(_nss_nis_getpwent_r): Correct test for invalid password.
[kopensolaris-gnu/glibc.git] / nis / nss_nis / nis-pwd.c
index b273332..0a337bb 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
 
@@ -22,7 +22,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <string.h>
-#include <libc-lock.h>
+#include <bits/libc-lock.h>
 #include <rpcsvc/yp.h>
 #include <rpcsvc/ypclnt.h>
 
@@ -78,11 +78,12 @@ _nss_nis_endpwent (void)
 }
 
 static enum nss_status
-internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
+internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
+                        int *errnop)
 {
   struct parser_data *data = (void *) buffer;
-  char *domain, *result, *outkey;
-  int len, keylen, parse_res;
+  char *domain;
+  int parse_res;
 
   if (yp_get_default_domain (&domain))
     return NSS_STATUS_UNAVAIL;
@@ -91,7 +92,9 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
   do
     {
       enum nss_status retval;
-      char *p;
+      char *result, *outkey, *result2, *p;
+      int len, keylen, len2;
+      size_t namelen;
 
       if (new_start)
         retval = yperr2nss (yp_first (domain, "passwd.byname",
@@ -103,46 +106,101 @@ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
 
       if (retval != NSS_STATUS_SUCCESS)
         {
-          if (retval == NSS_STATUS_TRYAGAIN)
-            __set_errno (EAGAIN);
+         if (retval == NSS_STATUS_NOTFOUND)
+           *errnop = ENOENT;
+          else if (retval == NSS_STATUS_TRYAGAIN)
+            *errnop = errno;
           return retval;
         }
 
-      if ((size_t) (len + 1) > buflen)
-        {
-          free (result);
-          __set_errno (ERANGE);
-          return NSS_STATUS_TRYAGAIN;
-        }
+      /* Check for adjunct style secret passwords.  They can be
+        recognized by a password starting with "##".  */
+      p = strchr (result, ':');
+      if (p != NULL    /* This better should be true in all cases.  */
+         && p[1] == '#' && p[2] == '#'
+         && (namelen = p - result,
+             yp_match (domain, "passwd.adjunct.byname", result, namelen,
+                       &result2, &len2)) == YPERR_SUCCESS)
+       {
+         /* We found a passwd.adjunct entry.  Merge encrypted
+            password therein into original result.  */
+         char *encrypted = strchr (result2, ':');
+         char *endp;
+         size_t restlen;
+
+         if (encrypted == NULL
+             || (endp = strchr (++encrypted, ':')) == NULL
+             || (p = strchr (p + 1, ':')) == NULL)
+           {
+             /* Invalid format of the entry.  This never should happen
+                unless the data from which the NIS table is generated is
+                wrong.  We simply ignore it.  */
+             free (result2);
+             goto non_adjunct;
+           }
+
+         restlen = len - (p - result);
+         if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+           {
+             free (result2);
+             free (result);
+             *errnop = ERANGE;
+             return NSS_STATUS_TRYAGAIN;
+           }
+
+         __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
+                                          ":", 1),
+                               encrypted, endp - encrypted),
+                    p, restlen + 1);
+         p = buffer;
+
+         free (result2);
+       }
+      else
+       {
+       non_adjunct:
+         if ((size_t) (len + 1) > buflen)
+           {
+             free (result);
+             *errnop = ERANGE;
+             return NSS_STATUS_TRYAGAIN;
+           }
+
+         p = strncpy (buffer, result, len);
+         buffer[len] = '\0';
+       }
 
-      p = strncpy (buffer, result, len);
-      buffer[len] = '\0';
       while (isspace (*p))
         ++p;
       free (result);
 
-      parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
-      if (!parse_res && errno == ERANGE)
-        return NSS_STATUS_TRYAGAIN;
+      parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+      if (parse_res == -1)
+       {
+         free (outkey);
+         *errnop = ERANGE;
+         return NSS_STATUS_TRYAGAIN;
+       }
 
       free (oldkey);
       oldkey = outkey;
       oldkeylen = keylen;
       new_start = 0;
     }
-  while (!parse_res);
+  while (parse_res < 1);
 
   return NSS_STATUS_SUCCESS;
 }
 
 enum nss_status
-_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen)
+_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
+                    int *errnop)
 {
   int status;
 
   __libc_lock_lock (lock);
 
-  status = internal_nis_getpwent_r (result, buffer, buflen);
+  status = internal_nis_getpwent_r (result, buffer, buflen, errnop);
 
   __libc_lock_unlock (lock);
 
@@ -151,53 +209,107 @@ _nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen)
 
 enum nss_status
 _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
-                    char *buffer, size_t buflen)
+                    char *buffer, size_t buflen, int *errnop)
 {
   struct parser_data *data = (void *) buffer;
   enum nss_status retval;
-  char *domain, *result, *p;
-  int len, parse_res;
+  char *domain, *result, *result2, *p;
+  int len, len2, parse_res;
+  size_t namelen;
 
   if (name == NULL)
     {
-      __set_errno (EINVAL);
+      *errnop = EINVAL;
       return NSS_STATUS_UNAVAIL;
     }
 
   if (yp_get_default_domain (&domain))
     return NSS_STATUS_UNAVAIL;
 
+  namelen = strlen (name);
+
   retval = yperr2nss (yp_match (domain, "passwd.byname", name,
-                               strlen (name), &result, &len));
+                               namelen, &result, &len));
 
   if (retval != NSS_STATUS_SUCCESS)
     {
-      if (retval == NSS_STATUS_TRYAGAIN)
-        __set_errno (EAGAIN);
+      if (retval == NSS_STATUS_NOTFOUND)
+       *errnop = ENOENT;
+      else if (retval == NSS_STATUS_TRYAGAIN)
+       *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  /* Check for adjunct style secret passwords.  They can be recognized
+     by a password starting with "##".  */
+  p = strchr (result, ':');
+  if (p != NULL        /* This better should be true in all cases.  */
+      && p[1] == '#' && p[2] == '#'
+      && yp_match (domain, "passwd.adjunct.byname", name, namelen,
+                  &result2, &len2) == YPERR_SUCCESS)
     {
-      free (result);
-      __set_errno (ERANGE);
-      return NSS_STATUS_TRYAGAIN;
+      /* We found a passwd.adjunct entry.  Merge encrypted password
+        therein into original result.  */
+      char *encrypted = strchr (result2, ':');
+      char *endp;
+      size_t restlen;
+
+      if (encrypted == NULL
+         || (endp = strchr (++encrypted, ':')) == NULL
+         || (p = strchr (p + 1, ':')) == NULL)
+       {
+         /* Invalid format of the entry.  This never should happen
+            unless the data from which the NIS table is generated is
+            wrong.  We simply ignore it.  */
+         free (result2);
+         goto non_adjunct;
+       }
+
+      restlen = len - (p - result);
+      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+       {
+         free (result2);
+         free (result);
+         *errnop = ERANGE;
+         return NSS_STATUS_TRYAGAIN;
+       }
+
+      __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen),
+                                      ":", 1),
+                           encrypted, endp - encrypted),
+                p, restlen + 1);
+      p = buffer;
+
+      free (result2);
+    }
+  else
+    {
+    non_adjunct:
+      if ((size_t) (len + 1) > buflen)
+       {
+         free (result);
+         *errnop = ERANGE;
+         return NSS_STATUS_TRYAGAIN;
+       }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
     }
 
-  p = strncpy (buffer, result, len);
-  buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
-
-  if (!parse_res)
+  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+  if (parse_res < 1)
     {
-      if (errno == ERANGE)
+      if (parse_res == -1)
         return NSS_STATUS_TRYAGAIN;
       else
-        return NSS_STATUS_NOTFOUND;
+       {
+         *errnop = ENOENT;
+         return NSS_STATUS_NOTFOUND;
+       }
     }
   else
     return NSS_STATUS_SUCCESS;
@@ -205,13 +317,14 @@ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
 
 enum nss_status
 _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
-                    char *buffer, size_t buflen)
+                    char *buffer, size_t buflen, int *errnop)
 {
   struct parser_data *data = (void *) buffer;
   enum nss_status retval;
-  char *domain, *result, *p;
-  int len, nlen, parse_res;
+  char *domain, *result, *p, *result2;
+  int len, nlen, parse_res, len2;
   char buf[32];
+  size_t namelen;
 
   if (yp_get_default_domain (&domain))
     return NSS_STATUS_UNAVAIL;
@@ -223,32 +336,84 @@ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
 
   if (retval != NSS_STATUS_SUCCESS)
     {
-      if (retval == NSS_STATUS_TRYAGAIN)
-        __set_errno (EAGAIN);
+      if (retval == NSS_STATUS_NOTFOUND)
+       *errnop = ENOENT;
+      else if (retval == NSS_STATUS_TRYAGAIN)
+       *errnop = errno;
       return retval;
     }
 
-  if ((size_t) (len + 1) > buflen)
+  /* Check for adjunct style secret passwords.  They can be recognized
+     by a password starting with "##".  */
+  p = strchr (result, ':');
+  if (p != NULL        /* This better should be true in all cases.  */
+      && p[1] == '#' && p[2] == '#'
+      && (namelen = p - result,
+         yp_match (domain, "passwd.adjunct.byname", result, namelen,
+                   &result2, &len2)) == YPERR_SUCCESS)
     {
-      free (result);
-      __set_errno (ERANGE);
-      return NSS_STATUS_TRYAGAIN;
+      /* We found a passwd.adjunct entry.  Merge encrypted password
+        therein into original result.  */
+      char *encrypted = strchr (result2, ':');
+      char *endp;
+      size_t restlen;
+
+      if (encrypted == NULL
+         || (endp = strchr (++encrypted, ':')) == NULL
+         || (p = strchr (p + 1, ':')) == NULL)
+       {
+         /* Invalid format of the entry.  This never should happen
+            unless the data from which the NIS table is generated is
+            wrong.  We simply ignore it.  */
+         free (result2);
+         goto non_adjunct;
+       }
+
+      restlen = len - (p - result);
+      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+       {
+         free (result2);
+         free (result);
+         *errnop = ERANGE;
+         return NSS_STATUS_TRYAGAIN;
+       }
+
+      __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
+                                      ":", 1),
+                           encrypted, endp - encrypted),
+                p, restlen + 1);
+      p = buffer;
+
+      free (result2);
+    }
+  else
+    {
+    non_adjunct:
+      if ((size_t) (len + 1) > buflen)
+       {
+         free (result);
+         *errnop = ERANGE;
+         return NSS_STATUS_TRYAGAIN;
+       }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
     }
 
-  p = strncpy (buffer, result, len);
-  buffer[len] = '\0';
   while (isspace (*p))
     ++p;
   free (result);
 
-  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
-
-  if (!parse_res)
+  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+  if (parse_res < 1)
     {
-      if (errno == ERANGE)
+      if (parse_res == -1)
         return NSS_STATUS_TRYAGAIN;
-      else
-        return NSS_STATUS_NOTFOUND;
+     else
+       {
+        *errnop = ENOENT;
+        return NSS_STATUS_NOTFOUND;
+       }
     }
   else
     return NSS_STATUS_SUCCESS;