From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23401 invoked by alias); 5 Jan 2010 09:26:47 -0000 Received: (qmail 23350 invoked by uid 48); 5 Jan 2010 09:26:33 -0000 Date: Tue, 05 Jan 2010 09:26:00 -0000 From: "Christoph dot Pleger at cs dot tu-dortmund dot de" To: glibc-bugs@sources.redhat.com Message-ID: <20100105092632.11134.Christoph.Pleger@cs.tu-dortmund.de> Reply-To: sourceware-bugzilla@sourceware.org Subject: [Bug libc/11134] New: getpwnam shows shadow passwords of NIS users X-Bugzilla-Reason: CC Mailing-List: contact glibc-bugs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: glibc-bugs-owner@sourceware.org X-SW-Source: 2010-01/txt/msg00005.txt.bz2 Hello, I have several machines where almost all user accounts come by NIS. The NIS server is running on a Solaris machine. As usual, the Solaris NIS server exports the passwd data in the map "passwd" and the shadow data in the map "passwd.adjunct.byname". These two maps are mangled together in some calls of libc6, for example in getpwnam. This makes it possible for every user who has an account on the NIS client machine to see the encrypted passwords of all NIS users. This is a grave security bug. Furthermore, getspnam returns a NULL pointer for all NIS users, even if getspnam is called by root. I wrote a patch nis_shadow.diff that solves these problems. It makes the following changes: * In nis-pwd.c, do not mangle encrypted password from passwd.adjunct.byname map into the password field of passwd map, instead mangle an 'x' into the field * In nis-spwd.c, look for key in passwd.adjunct.byname if shadow.byname does not exist and add the two missing fields (passwd.adjunct.byname has two fields less than shadow) diff -Naurp glibc-2.7.original/nis/nss_nis/nis-pwd.c glibc-2.7/nis/nss_nis/nis-pwd.c --- glibc-2.7.original/nis/nss_nis/nis-pwd.c 2006-05-02 00:31:15.000000000 +0200 +++ glibc-2.7/nis/nss_nis/nis-pwd.c 2009-12-22 09:04:46.000000000 +0100 @@ -275,8 +275,8 @@ internal_nis_getpwent_r (struct passwd * 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. */ + /* We found a passwd.adjunct entry. Merge "x" + into original result. */ char *encrypted = strchr (result2, ':'); char *endp; size_t restlen; @@ -304,7 +304,7 @@ internal_nis_getpwent_r (struct passwd * mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen), ":", 1), - encrypted, endp - encrypted), + "x", 1), p, restlen + 1); p = buffer; @@ -408,8 +408,8 @@ _nss_nis_getpwnam_r (const char *name, s && yp_match (domain, "passwd.adjunct.byname", name, namelen, &result2, &len2) == YPERR_SUCCESS) { - /* We found a passwd.adjunct entry. Merge encrypted password - therein into original result. */ + /* We found a passwd.adjunct entry. Merge "x" + into original result. */ char *encrypted = strchr (result2, ':'); char *endp; @@ -436,7 +436,7 @@ _nss_nis_getpwnam_r (const char *name, s __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, name, namelen), ":", 1), - encrypted, endp - encrypted), + "x", 1), p, restlen + 1); p = buffer; @@ -509,8 +509,8 @@ _nss_nis_getpwuid_r (uid_t uid, struct p 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. */ + /* We found a passwd.adjunct entry. Merge "x" + into original result. */ char *encrypted = strchr (result2, ':'); char *endp; size_t restlen; @@ -538,7 +538,7 @@ _nss_nis_getpwuid_r (uid_t uid, struct p __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen), ":", 1), - encrypted, endp - encrypted), + "x", 1), p, restlen + 1); p = buffer; diff -Naurp glibc-2.7.original/nis/nss_nis/nis-spwd.c glibc-2.7/nis/nss_nis/nis-spwd.c --- glibc-2.7.original/nis/nss_nis/nis-spwd.c 2006-04-29 03:09:49.000000000 +0200 +++ glibc-2.7/nis/nss_nis/nis-spwd.c 2009-12-22 10:02:25.000000000 +0100 @@ -78,17 +78,42 @@ internal_nis_getspent_r (struct spwd *sp { char *result; char *outkey; + char *p; int len; int keylen; int yperr; + int adjunct_used = 0; - if (new_start) + if (new_start) { yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result, &len); - else + + if (yperr == YPERR_MAP) { + if (result != NULL) + free result; + + yperr = yp_first (domain, "passwd.adjunct.byname", &outkey, &keylen, &result, + &len); + + adjunct_used = 1; + } + } + + else { yperr = yp_next (domain, "shadow.byname", oldkey, oldkeylen, &outkey, &keylen, &result, &len); + if (yperr == YPERR_MAP) { + if (result != NULL) + free result; + + yperr = yp_next (domain, "passwd.adjunct.byname", oldkey, oldkeylen, &outkey, + &keylen, &result, &len); + + adjunct_used = 1; + } + } + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { enum nss_status retval = yperr2nss (yperr); @@ -98,15 +123,32 @@ internal_nis_getspent_r (struct spwd *sp return retval; } - if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) - { - free (result); - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } + if (! adjunct_used) + { + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + } + else + { + if (__builtin_expect ((size_t) (len + 3) > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + p = strcat (buffer, "::"); + } - char *p = strncpy (buffer, result, len); - buffer[len] = '\0'; while (isspace (*p)) ++p; free (result); @@ -149,6 +191,9 @@ enum nss_status _nss_nis_getspnam_r (const char *name, struct spwd *sp, char *buffer, size_t buflen, int *errnop) { + int adjunct_used = 0; + char *p; + if (name == NULL) { *errnop = EINVAL; @@ -164,6 +209,15 @@ _nss_nis_getspnam_r (const char *name, s int yperr = yp_match (domain, "shadow.byname", name, strlen (name), &result, &len); + if (yperr == YPERR_MAP) { + if (result != NULL) + free result; + + yperr = yp_match (domain, "passwd.adjunct.byname", name, strlen (name), &result, + &len); + adjunct_used = 1; + } + if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) { enum nss_status retval = yperr2nss (yperr); @@ -173,15 +227,32 @@ _nss_nis_getspnam_r (const char *name, s return retval; } - if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) + if (! adjunct_used) { - free (result); - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; + if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } + + p = strncpy (buffer, result, len); + buffer[len] = '\0'; } + else + { + if (__builtin_expect ((size_t) (len + 3) > buflen, 0)) + { + free (result); + *errnop = ERANGE; + return NSS_STATUS_TRYAGAIN; + } - char *p = strncpy (buffer, result, len); - buffer[len] = '\0'; + p = strncpy (buffer, result, len); + buffer[len] = '\0'; + p = strcat (buffer, "::"); + } + while (isspace (*p)) ++p; free (result); Regards Christoph -- Summary: getpwnam shows shadow passwords of NIS users Product: glibc Version: unspecified Status: NEW Severity: critical Priority: P1 Component: libc AssignedTo: drepper at redhat dot com ReportedBy: Christoph dot Pleger at cs dot tu-dortmund dot de CC: glibc-bugs at sources dot redhat dot com http://sourceware.org/bugzilla/show_bug.cgi?id=11134 ------- You are receiving this mail because: ------- You are on the CC list for the bug, or are watching someone who is.