Back to index

glibc  2.9
nis-pwd.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-1998,2001,2002,2003,2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <ctype.h>
00022 #include <errno.h>
00023 #include <nss.h>
00024 #include <pwd.h>
00025 #include <string.h>
00026 #include <bits/libc-lock.h>
00027 #include <rpcsvc/yp.h>
00028 #include <rpcsvc/ypclnt.h>
00029 
00030 #include "nss-nis.h"
00031 #include <libnsl.h>
00032 
00033 /* Get the declaration of the parser function.  */
00034 #define ENTNAME pwent
00035 #define STRUCTURE passwd
00036 #define EXTERN_PARSER
00037 #include <nss/nss_files/files-parse.c>
00038 
00039 /* Protect global state against multiple changers */
00040 __libc_lock_define_initialized (static, lock)
00041 
00042 static bool_t new_start = 1;
00043 static char *oldkey;
00044 static int oldkeylen;
00045 static intern_t intern;
00046 
00047 
00048 int
00049 _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval,
00050             int invallen, char *indata)
00051 {
00052   intern_t *intern = (intern_t *) indata;
00053 
00054   if (instatus != YP_TRUE)
00055     return 1;
00056 
00057   if (inkey && inkeylen > 0 && inval && invallen > 0)
00058     {
00059       struct response_t *bucket = intern->next;
00060 
00061       if (__builtin_expect (bucket == NULL, 0))
00062        {
00063 #define MINSIZE 4096 - 4 * sizeof (void *)
00064          const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1));
00065          bucket = malloc (sizeof (struct response_t) + minsize);
00066          if (bucket == NULL)
00067            /* We have no error code for out of memory.  */
00068            return 1;
00069 
00070          bucket->next = NULL;
00071          bucket->size = minsize;
00072          intern->start = intern->next = bucket;
00073          intern->offset = 0;
00074        }
00075       else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset,
00076                              0))
00077        {
00078          /* We need a new (larger) buffer.  */
00079          const size_t newsize = 2 * MAX (bucket->size, invallen + 1);
00080          struct response_t *newp = malloc (sizeof (struct response_t)
00081                                        + newsize);
00082          if (newp == NULL)
00083            /* We have no error code for out of memory.  */
00084            return 1;
00085 
00086          /* Mark the old bucket as full.  */
00087          bucket->size = intern->offset;
00088 
00089          newp->next = NULL;
00090          newp->size = newsize;
00091          bucket = intern->next = bucket->next = newp;
00092          intern->offset = 0;
00093        }
00094 
00095       char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen);
00096       if (__builtin_expect (p[-1] != '\0', 0))
00097        {
00098          *p = '\0';
00099          ++invallen;
00100        }
00101       intern->offset += invallen;
00102     }
00103 
00104   return 0;
00105 }
00106 
00107 
00108 static void
00109 internal_nis_endpwent (void)
00110 {
00111   new_start = 1;
00112   if (oldkey != NULL)
00113     {
00114       free (oldkey);
00115       oldkey = NULL;
00116       oldkeylen = 0;
00117     }
00118 
00119   struct response_t *curr = intern.next;
00120 
00121   while (curr != NULL)
00122     {
00123       struct response_t *last = curr;
00124       curr = curr->next;
00125       free (last);
00126     }
00127 
00128   intern.next = intern.start = NULL;
00129 }
00130 
00131 
00132 enum nss_status
00133 _nss_nis_endpwent (void)
00134 {
00135   __libc_lock_lock (lock);
00136 
00137   internal_nis_endpwent ();
00138 
00139   __libc_lock_unlock (lock);
00140 
00141   return NSS_STATUS_SUCCESS;
00142 }
00143 
00144 
00145 enum nss_status
00146 internal_nis_setpwent (void)
00147 {
00148   /* We have to read all the data now.  */
00149   char *domain;
00150   if (__builtin_expect (yp_get_default_domain (&domain), 0))
00151     return NSS_STATUS_UNAVAIL;
00152 
00153   struct ypall_callback ypcb;
00154 
00155   ypcb.foreach = _nis_saveit;
00156   ypcb.data = (char *) &intern;
00157   enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb));
00158 
00159 
00160   /* Mark the last buffer as full.  */
00161   if (intern.next != NULL)
00162     intern.next->size = intern.offset;
00163 
00164   intern.next = intern.start;
00165   intern.offset = 0;
00166 
00167   return status;
00168 }
00169 
00170 
00171 enum nss_status
00172 _nss_nis_setpwent (int stayopen)
00173 {
00174   enum nss_status result = NSS_STATUS_SUCCESS;
00175 
00176   __libc_lock_lock (lock);
00177 
00178   internal_nis_endpwent ();
00179 
00180   if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
00181     result = internal_nis_setpwent ();
00182 
00183   __libc_lock_unlock (lock);
00184 
00185   return result;
00186 }
00187 
00188 
00189 static enum nss_status
00190 internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
00191                       int *errnop)
00192 {
00193   /* If we read the entire database at setpwent time we just iterate
00194      over the data we have in memory.  */
00195   bool batch_read = intern.start != NULL;
00196 
00197   char *domain = NULL;
00198   if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
00199     return NSS_STATUS_UNAVAIL;
00200 
00201   /* Get the next entry until we found a correct one. */
00202   int parse_res;
00203   do
00204     {
00205       char *result;
00206       char *outkey;
00207       int len;
00208       int keylen;
00209 
00210       if (batch_read)
00211        {
00212          struct response_t *bucket;
00213 
00214        handle_batch_read:
00215          bucket = intern.next;
00216 
00217          if (__builtin_expect (intern.offset >= bucket->size, 0))
00218            {
00219              if (bucket->next == NULL)
00220               return NSS_STATUS_NOTFOUND;
00221 
00222              /* We look at all the content in the current bucket.  Go on
00223                to the next.  */
00224              bucket = intern.next = bucket->next;
00225              intern.offset = 0;
00226            }
00227 
00228          for (result = &bucket->mem[intern.offset]; isspace (*result);
00229               ++result)
00230            ++intern.offset;
00231 
00232          len = strlen (result);
00233        }
00234       else
00235        {
00236          int yperr;
00237 
00238          if (new_start)
00239            {
00240              /* Maybe we should read the database in one piece.  */
00241              if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
00242                 && internal_nis_setpwent () == NSS_STATUS_SUCCESS
00243                 && intern.start != NULL)
00244               {
00245                 batch_read = true;
00246                 goto handle_batch_read;
00247               }
00248 
00249              yperr = yp_first (domain, "passwd.byname", &outkey, &keylen,
00250                             &result, &len);
00251            }
00252          else
00253            yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen,
00254                           &outkey, &keylen, &result, &len);
00255 
00256          if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00257            {
00258              enum nss_status retval = yperr2nss (yperr);
00259 
00260              if (retval == NSS_STATUS_TRYAGAIN)
00261               *errnop = errno;
00262              return retval;
00263            }
00264        }
00265 
00266       /* Check for adjunct style secret passwords.  They can be
00267         recognized by a password starting with "##".  */
00268       char *p = strchr (result, ':');
00269       size_t namelen;
00270       char *result2;
00271       int len2;
00272       if (p != NULL  /* This better should be true in all cases.  */
00273          && p[1] == '#' && p[2] == '#'
00274          && (namelen = p - result,
00275              yp_match (domain, "passwd.adjunct.byname", result, namelen,
00276                      &result2, &len2)) == YPERR_SUCCESS)
00277        {
00278          /* We found a passwd.adjunct entry.  Merge encrypted
00279             password therein into original result.  */
00280          char *encrypted = strchr (result2, ':');
00281          char *endp;
00282          size_t restlen;
00283 
00284          if (encrypted == NULL
00285              || (endp = strchr (++encrypted, ':')) == NULL
00286              || (p = strchr (p + 1, ':')) == NULL)
00287            {
00288              /* Invalid format of the entry.  This never should happen
00289                unless the data from which the NIS table is generated is
00290                wrong.  We simply ignore it.  */
00291              free (result2);
00292              goto non_adjunct;
00293            }
00294 
00295          restlen = len - (p - result);
00296          if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
00297                                      + restlen + 2) > buflen, 0))
00298            {
00299              free (result2);
00300              free (result);
00301              *errnop = ERANGE;
00302              return NSS_STATUS_TRYAGAIN;
00303            }
00304 
00305          mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen),
00306                                  ":", 1),
00307                          encrypted, endp - encrypted),
00308                  p, restlen + 1);
00309          p = buffer;
00310 
00311          free (result2);
00312        }
00313       else
00314        {
00315        non_adjunct:
00316          if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
00317            {
00318              free (result);
00319              *errnop = ERANGE;
00320              return NSS_STATUS_TRYAGAIN;
00321            }
00322 
00323          p = buffer;
00324          *((char *) mempcpy (buffer, result, len)) = '\0';
00325        }
00326 
00327       while (isspace (*p))
00328         ++p;
00329       if (!batch_read)
00330        free (result);
00331 
00332       parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
00333                                      errnop);
00334       if (__builtin_expect (parse_res == -1, 0))
00335        {
00336          if (!batch_read)
00337            free (outkey);
00338          *errnop = ERANGE;
00339          return NSS_STATUS_TRYAGAIN;
00340        }
00341 
00342       if (batch_read)
00343        intern.offset += len + 1;
00344       else
00345        {
00346          free (oldkey);
00347          oldkey = outkey;
00348          oldkeylen = keylen;
00349          new_start = 0;
00350        }
00351     }
00352   while (parse_res < 1);
00353 
00354   return NSS_STATUS_SUCCESS;
00355 }
00356 
00357 enum nss_status
00358 _nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
00359                    int *errnop)
00360 {
00361   int status;
00362 
00363   __libc_lock_lock (lock);
00364 
00365   status = internal_nis_getpwent_r (result, buffer, buflen, errnop);
00366 
00367   __libc_lock_unlock (lock);
00368 
00369   return status;
00370 }
00371 
00372 enum nss_status
00373 _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
00374                    char *buffer, size_t buflen, int *errnop)
00375 {
00376   if (name == NULL)
00377     {
00378       *errnop = EINVAL;
00379       return NSS_STATUS_UNAVAIL;
00380     }
00381 
00382   char *domain;
00383   if (__builtin_expect (yp_get_default_domain (&domain), 0))
00384     return NSS_STATUS_UNAVAIL;
00385 
00386   size_t namelen = strlen (name);
00387 
00388   char *result;
00389   int len;
00390   int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len);
00391 
00392   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00393     {
00394       enum nss_status retval = yperr2nss (yperr);
00395 
00396       if (retval == NSS_STATUS_TRYAGAIN)
00397        *errnop = errno;
00398       return retval;
00399     }
00400 
00401   /* Check for adjunct style secret passwords.  They can be recognized
00402      by a password starting with "##".  */
00403   char *result2;
00404   int len2;
00405   char *p = strchr (result, ':');
00406   if (p != NULL      /* This better should be true in all cases.  */
00407       && p[1] == '#' && p[2] == '#'
00408       && yp_match (domain, "passwd.adjunct.byname", name, namelen,
00409                  &result2, &len2) == YPERR_SUCCESS)
00410     {
00411       /* We found a passwd.adjunct entry.  Merge encrypted password
00412         therein into original result.  */
00413       char *encrypted = strchr (result2, ':');
00414       char *endp;
00415 
00416       if (encrypted == NULL
00417          || (endp = strchr (++encrypted, ':')) == NULL
00418          || (p = strchr (p + 1, ':')) == NULL)
00419        {
00420          /* Invalid format of the entry.  This never should happen
00421             unless the data from which the NIS table is generated is
00422             wrong.  We simply ignore it.  */
00423          free (result2);
00424          goto non_adjunct;
00425        }
00426 
00427       size_t restlen = len - (p - result);
00428       if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
00429                                   + restlen + 2) > buflen, 0))
00430        {
00431          free (result2);
00432          free (result);
00433          *errnop = ERANGE;
00434          return NSS_STATUS_TRYAGAIN;
00435        }
00436 
00437       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen),
00438                                    ":", 1),
00439                          encrypted, endp - encrypted),
00440                p, restlen + 1);
00441       p = buffer;
00442 
00443       free (result2);
00444     }
00445   else
00446     {
00447     non_adjunct:
00448       if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
00449        {
00450          free (result);
00451          *errnop = ERANGE;
00452          return NSS_STATUS_TRYAGAIN;
00453        }
00454 
00455       p = strncpy (buffer, result, len);
00456       buffer[len] = '\0';
00457     }
00458 
00459   while (isspace (*p))
00460     ++p;
00461   free (result);
00462 
00463   int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
00464                                      errnop);
00465   if (__builtin_expect (parse_res < 1, 0))
00466     {
00467       if (parse_res == -1)
00468         return NSS_STATUS_TRYAGAIN;
00469       else
00470        return NSS_STATUS_NOTFOUND;
00471     }
00472   else
00473     return NSS_STATUS_SUCCESS;
00474 }
00475 
00476 enum nss_status
00477 _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
00478                    char *buffer, size_t buflen, int *errnop)
00479 {
00480   char *domain;
00481   if (__builtin_expect (yp_get_default_domain (&domain), 0))
00482     return NSS_STATUS_UNAVAIL;
00483 
00484   char buf[32];
00485   int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid);
00486 
00487   char *result;
00488   int len;
00489   int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len);
00490 
00491   if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
00492     {
00493       enum nss_status retval = yperr2nss (yperr);
00494 
00495       if (retval == NSS_STATUS_TRYAGAIN)
00496        *errnop = errno;
00497       return retval;
00498     }
00499 
00500   /* Check for adjunct style secret passwords.  They can be recognized
00501      by a password starting with "##".  */
00502   char *result2;
00503   int len2;
00504   size_t namelen;
00505   char *p = strchr (result, ':');
00506   if (p != NULL      /* This better should be true in all cases.  */
00507       && p[1] == '#' && p[2] == '#'
00508       && (namelen = p - result,
00509          yp_match (domain, "passwd.adjunct.byname", result, namelen,
00510                   &result2, &len2)) == YPERR_SUCCESS)
00511     {
00512       /* We found a passwd.adjunct entry.  Merge encrypted password
00513         therein into original result.  */
00514       char *encrypted = strchr (result2, ':');
00515       char *endp;
00516       size_t restlen;
00517 
00518       if (encrypted == NULL
00519          || (endp = strchr (++encrypted, ':')) == NULL
00520          || (p = strchr (p + 1, ':')) == NULL)
00521        {
00522          /* Invalid format of the entry.  This never should happen
00523             unless the data from which the NIS table is generated is
00524             wrong.  We simply ignore it.  */
00525          free (result2);
00526          goto non_adjunct;
00527        }
00528 
00529       restlen = len - (p - result);
00530       if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
00531                                   + restlen + 2) > buflen, 0))
00532        {
00533          free (result2);
00534          free (result);
00535          *errnop = ERANGE;
00536          return NSS_STATUS_TRYAGAIN;
00537        }
00538 
00539       __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
00540                                    ":", 1),
00541                          encrypted, endp - encrypted),
00542                p, restlen + 1);
00543       p = buffer;
00544 
00545       free (result2);
00546     }
00547   else
00548     {
00549     non_adjunct:
00550       if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
00551        {
00552          free (result);
00553          *errnop = ERANGE;
00554          return NSS_STATUS_TRYAGAIN;
00555        }
00556 
00557       p = strncpy (buffer, result, len);
00558       buffer[len] = '\0';
00559     }
00560 
00561   while (isspace (*p))
00562     ++p;
00563   free (result);
00564 
00565   int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
00566                                      errnop);
00567   if (__builtin_expect (parse_res < 1, 0))
00568     {
00569       if (parse_res == -1)
00570         return NSS_STATUS_TRYAGAIN;
00571      else
00572        return NSS_STATUS_NOTFOUND;
00573     }
00574   else
00575     return NSS_STATUS_SUCCESS;
00576 }