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 *
@@ -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
Hello, adjunct. byname" . These two maps are mangled together in some calls
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.
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 adjunct. byname map into the password field
passwd.
of passwd map, instead mangle an 'x' into the field
* In nis-spwd.c, look for key in passwd. adjunct. byname if shadow.byname adjunct. byname
does not exist and add the two missing fields (passwd.
has two fields less than shadow)
diff -Naurp glibc-2. 7.original/ nis/nss_ nis/nis- pwd.c 7/nis/nss_ nis/nis- pwd.c 7.original/ nis/nss_ nis/nis- pwd.c 2006-05-02 00:31:15.000000000 7/nis/nss_ nis/nis- pwd.c 2009-12-22 09:04:46.000000000 +0100 nis_getpwent_ r (struct passwd * adjunct. byname" , result, namelen, nis_getpwent_ r (struct passwd *
glibc-2.
--- glibc-2.
+0200
+++ glibc-2.
@@ -275,8 +275,8 @@ internal_
yp_match (domain, "passwd.
&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_
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 adjunct. byname" , name, namelen,
&& yp_match (domain, "passwd.
&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 adjunct. byname" , result, namelen,
yp_match (domain, "passwd.
&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 7/nis/nss_ nis/nis- spwd.c 7.original/ nis/nss_ nis/nis- spwd.c 2006-04-29 03:09:49.000000000 7/nis/nss_ nis/nis- spwd.c 2009-12-22 10:02:25.000000000 +0100 nis_getspent_ r (struct spwd *sp
glibc-2.
--- glibc-2.
+0200
+++ glibc-2.
@@ -78,17 +78,42 @@ internal_
{
char *result;
char *outkey;
+ char *p;
int len;
int keylen;
int yperr;
+ int adjunct_used = 0;
- if (new_start) adjunct. byname" , &outkey, &keylen,
+ 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.
&result,
+ &len);
+
+ adjunct_used = 1;
+ }
+ }
+
+ else {
yperr = yp_next (domain, "shadow.byname", oldkey, oldkeylen, &outkey,
&keylen, &result, &len);
+ if (yperr == YPERR_MAP) { adjunct. byname" , oldkey, oldkeylen, nis_getspent_ r (struct spwd *sp
+ if (result != NULL)
+ free result;
+
+ yperr = yp_next (domain, "passwd.
&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_
return retval;
}
- if (__builtin_expect ((size_t) (len + 1) > buflen, 0)) TRYAGAIN; TRYAGAIN; TRYAGAIN;
- {
- free (result);
- *errnop = ERANGE;
- return NSS_STATUS_
- }
+ if (! adjunct_used)
+ {
+ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_
+ }
+
+ 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_
+ }
+
+ p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ p = strcat (buffer, "::");
+ }
- char *p = strncpy (buffer, result, len); getspnam_ r (const char *name, struct spwd *sp,
- buffer[len] = '\0';
while (isspace (*p))
++p;
free (result);
@@ -149,6 +191,9 @@ enum nss_status
_nss_nis_
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) { adjunct. byname" , name, strlen (name),
+ if (result != NULL)
+ free result;
+
+ yperr = yp_match (domain, "passwd.
&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)) TRYAGAIN; TRYAGAIN; TRYAGAIN;
+ if (! adjunct_used)
{
- free (result);
- *errnop = ERANGE;
- return NSS_STATUS_
+ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_
+ }
+
+ 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_
+ }
- 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