Back to index

glibc  2.9
nisplus-rpc.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1998, 2001, 2002, 2003, 2005, 2006, 2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <atomic.h>
00022 #include <ctype.h>
00023 #include <errno.h>
00024 #include <nss.h>
00025 #include <string.h>
00026 #include <rpc/netdb.h>
00027 #include <rpcsvc/nis.h>
00028 #include <bits/libc-lock.h>
00029 
00030 #include "nss-nisplus.h"
00031 
00032 __libc_lock_define_initialized (static, lock)
00033 
00034 static nis_result *result;
00035 static nis_name tablename_val;
00036 static u_long tablename_len;
00037 
00038 #define NISENTRYVAL(idx, col, res) \
00039         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
00040 
00041 #define NISENTRYLEN(idx, col, res) \
00042         (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
00043 
00044 
00045 static int
00046 _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
00047                         char *buffer, size_t buflen, int *errnop)
00048 {
00049   char *first_unused = buffer;
00050   size_t room_left = buflen;
00051   unsigned int i;
00052   char *line;
00053 
00054 
00055   if (result == NULL)
00056     return 0;
00057 
00058   if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
00059       || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
00060       || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0
00061       || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
00062     return 0;
00063 
00064   if (NISENTRYLEN (0, 0, result) >= room_left)
00065     {
00066     no_more_room:
00067       *errnop = ERANGE;
00068       return -1;
00069     }
00070   strncpy (first_unused, NISENTRYVAL (0, 0, result),
00071            NISENTRYLEN (0, 0, result));
00072   first_unused[NISENTRYLEN (0, 0, result)] = '\0';
00073   rpc->r_name = first_unused;
00074   size_t len = strlen (first_unused) + 1;
00075   room_left -= len;
00076   first_unused += len;
00077 
00078   rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
00079 
00080   /* XXX Rewrite at some point to allocate the array first and then
00081      copy the strings.  It wasteful to first concatenate the strings
00082      to just split them again later.  */
00083   line = first_unused;
00084   for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
00085     {
00086       if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
00087         {
00088           if (NISENTRYLEN (i, 1, result) + 2 > room_left)
00089            goto no_more_room;
00090          *first_unused++ = ' ';
00091           first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
00092                                 NISENTRYLEN (i, 1, result));
00093           room_left -= NISENTRYLEN (i, 1, result) + 1;
00094         }
00095     }
00096   *first_unused++ = '\0';
00097 
00098   /* Adjust the pointer so it is aligned for
00099      storing pointers.  */
00100   size_t adjust = ((__alignof__ (char *)
00101                   - (first_unused - (char *) 0) % __alignof__ (char *))
00102                  % __alignof__ (char *));
00103   if (room_left < adjust + sizeof (char *))
00104     goto no_more_room;
00105   first_unused += adjust;
00106   room_left -= adjust;
00107   rpc->r_aliases = (char **) first_unused;
00108 
00109   /* For the terminating NULL pointer.  */
00110   room_left -= sizeof (char *);
00111 
00112   i = 0;
00113   while (*line != '\0')
00114     {
00115       /* Skip leading blanks.  */
00116       while (isspace (*line))
00117         ++line;
00118 
00119       if (*line == '\0')
00120         break;
00121 
00122       if (room_left < sizeof (char *))
00123        goto no_more_room;
00124 
00125       room_left -= sizeof (char *);
00126       rpc->r_aliases[i++] = line;
00127 
00128       while (*line != '\0' && *line != ' ')
00129         ++line;
00130 
00131       if (*line == ' ')
00132        *line++ = '\0';
00133     }
00134   rpc->r_aliases[i] = NULL;
00135 
00136   return 1;
00137 }
00138 
00139 
00140 static enum nss_status
00141 _nss_create_tablename (int *errnop)
00142 {
00143   if (tablename_val == NULL)
00144     {
00145       const char *local_dir = nis_local_directory ();
00146       size_t local_dir_len = strlen (local_dir);
00147       static const char prefix[] = "rpc.org_dir.";
00148 
00149       char *p = malloc (sizeof (prefix) + local_dir_len);
00150       if (p == NULL)
00151        {
00152          *errnop = errno;
00153          return NSS_STATUS_TRYAGAIN;
00154        }
00155 
00156       memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
00157 
00158       tablename_len = sizeof (prefix) - 1 + local_dir_len;
00159 
00160       atomic_write_barrier ();
00161 
00162       tablename_val = p;
00163     }
00164 
00165   return NSS_STATUS_SUCCESS;
00166 }
00167 
00168 
00169 enum nss_status
00170 _nss_nisplus_setrpcent (int stayopen)
00171 {
00172   enum nss_status status = NSS_STATUS_SUCCESS;
00173 
00174   __libc_lock_lock (lock);
00175 
00176   if (result != NULL)
00177     {
00178       nis_freeresult (result);
00179       result = NULL;
00180     }
00181 
00182   if (tablename_val == NULL)
00183     {
00184       int err;
00185       status = _nss_create_tablename (&err);
00186     }
00187 
00188   __libc_lock_unlock (lock);
00189 
00190   return status;
00191 }
00192 
00193 enum nss_status
00194 _nss_nisplus_endrpcent (void)
00195 {
00196   __libc_lock_lock (lock);
00197 
00198   if (result != NULL)
00199     {
00200       nis_freeresult (result);
00201       result = NULL;
00202     }
00203 
00204   __libc_lock_unlock (lock);
00205 
00206   return NSS_STATUS_SUCCESS;
00207 }
00208 
00209 static enum nss_status
00210 internal_nisplus_getrpcent_r (struct rpcent *rpc, char *buffer,
00211                            size_t buflen, int *errnop)
00212 {
00213   int parse_res;
00214 
00215   /* Get the next entry until we found a correct one. */
00216   do
00217     {
00218       nis_result *saved_res;
00219 
00220       if (result == NULL)
00221        {
00222          saved_res = NULL;
00223           if (tablename_val == NULL)
00224            {
00225              enum nss_status status =  _nss_create_tablename (errnop);
00226 
00227              if (status != NSS_STATUS_SUCCESS)
00228               return status;
00229            }
00230 
00231          result = nis_first_entry (tablename_val);
00232          if (result == NULL)
00233            {
00234              *errnop = errno;
00235              return NSS_STATUS_TRYAGAIN;
00236            }
00237          if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
00238            return niserr2nss (result->status);
00239        }
00240       else
00241        {
00242          saved_res = result;
00243          result = nis_next_entry (tablename_val, &result->cookie);
00244          if (result == NULL)
00245            {
00246              *errnop = errno;
00247              return NSS_STATUS_TRYAGAIN;
00248            }
00249          if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
00250            {
00251              nis_freeresult (saved_res);
00252              return niserr2nss (result->status);
00253            }
00254        }
00255 
00256       parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer,
00257                                         buflen, errnop);
00258       if (parse_res == -1)
00259        {
00260          nis_freeresult (result);
00261          result = saved_res;
00262          *errnop = ERANGE;
00263          return NSS_STATUS_TRYAGAIN;
00264        }
00265       else
00266        {
00267          if (saved_res)
00268            nis_freeresult (saved_res);
00269        }
00270     }
00271   while (!parse_res);
00272 
00273   return NSS_STATUS_SUCCESS;
00274 }
00275 
00276 enum nss_status
00277 _nss_nisplus_getrpcent_r (struct rpcent *result, char *buffer,
00278                        size_t buflen, int *errnop)
00279 {
00280   int status;
00281 
00282   __libc_lock_lock (lock);
00283 
00284   status = internal_nisplus_getrpcent_r (result, buffer, buflen, errnop);
00285 
00286   __libc_lock_unlock (lock);
00287 
00288   return status;
00289 }
00290 
00291 enum nss_status
00292 _nss_nisplus_getrpcbyname_r (const char *name, struct rpcent *rpc,
00293                           char *buffer, size_t buflen, int *errnop)
00294 {
00295   int parse_res;
00296 
00297   if (tablename_val == NULL)
00298     {
00299       __libc_lock_lock (lock);
00300 
00301       enum nss_status status = _nss_create_tablename (errnop);
00302 
00303       __libc_lock_unlock (lock);
00304 
00305       if (status != NSS_STATUS_SUCCESS)
00306        return status;
00307     }
00308 
00309   if (name == NULL)
00310     return NSS_STATUS_NOTFOUND;
00311 
00312   char buf[strlen (name) + 10 + tablename_len];
00313   int olderr = errno;
00314 
00315   /* Search at first in the alias list, and use the correct name
00316      for the next search */
00317   snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
00318   nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
00319                              NULL, NULL);
00320 
00321   if (result != NULL)
00322     {
00323       char *bufptr = buf;
00324 
00325       /* If we did not find it, try it as original name. But if the
00326         database is correct, we should find it in the first case, too */
00327       if ((result->status != NIS_SUCCESS
00328           && result->status != NIS_S_SUCCESS)
00329          || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
00330          || strcmp (result->objects.objects_val->EN_data.en_type,
00331                    "rpc_tbl") != 0
00332          || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
00333        snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
00334       else
00335        {
00336          /* We need to allocate a new buffer since there is no
00337             guarantee the returned name has a length limit.  */
00338          const char *entryval = NISENTRYVAL (0, 0, result);
00339          size_t buflen = strlen (entryval) + 10 + tablename_len;
00340          bufptr = alloca (buflen);
00341          snprintf (bufptr, buflen, "[cname=%s],%s",
00342                   entryval, tablename_val);
00343        }
00344 
00345       nis_freeresult (result);
00346       result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
00347                       NULL, NULL);
00348     }
00349 
00350   if (result == NULL)
00351     {
00352       *errnop = ENOMEM;
00353       return NSS_STATUS_TRYAGAIN;
00354     }
00355 
00356   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
00357     {
00358       enum nss_status status = niserr2nss (result->status);
00359 
00360       __set_errno (olderr);
00361 
00362       nis_freeresult (result);
00363       return status;
00364     }
00365 
00366   parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
00367                                         errnop);
00368 
00369   nis_freeresult (result);
00370 
00371   if (parse_res < 1)
00372     {
00373       if (parse_res == -1)
00374        {
00375          *errnop = ERANGE;
00376          return NSS_STATUS_TRYAGAIN;
00377        }
00378 
00379       __set_errno (olderr);
00380       return NSS_STATUS_NOTFOUND;
00381     }
00382 
00383   return NSS_STATUS_SUCCESS;
00384 }
00385 
00386 enum nss_status
00387 _nss_nisplus_getrpcbynumber_r (const int number, struct rpcent *rpc,
00388                             char *buffer, size_t buflen, int *errnop)
00389 {
00390   if (tablename_val == NULL)
00391     {
00392       __libc_lock_lock (lock);
00393 
00394       enum nss_status status = _nss_create_tablename (errnop);
00395 
00396       __libc_lock_unlock (lock);
00397 
00398       if (status != NSS_STATUS_SUCCESS)
00399        return status;
00400     }
00401 
00402   char buf[12 + 3 * sizeof (number) + tablename_len];
00403   int olderr = errno;
00404 
00405   snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
00406 
00407   nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
00408                              NULL, NULL);
00409 
00410   if (result == NULL)
00411     {
00412       *errnop = ENOMEM;
00413       return NSS_STATUS_TRYAGAIN;
00414     }
00415 
00416   if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS,  0))
00417     {
00418       enum nss_status status = niserr2nss (result->status);
00419 
00420       __set_errno (olderr);
00421 
00422       nis_freeresult (result);
00423       return status;
00424     }
00425 
00426   int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
00427                                         errnop);
00428 
00429   nis_freeresult (result);
00430 
00431   if (parse_res < 1)
00432     {
00433       if (parse_res == -1)
00434        {
00435          *errnop = ERANGE;
00436          return NSS_STATUS_TRYAGAIN;
00437        }
00438       else
00439        {
00440          __set_errno (olderr);
00441          return NSS_STATUS_NOTFOUND;
00442        }
00443     }
00444 
00445   return NSS_STATUS_SUCCESS;
00446 }