#705577 nis: rpc.yppasswdd check for shadow password inconsistent with yppasswd's check

Package:
ypserv
Source:
ypserv
Description:
Server daemon for working with Network Information System (NIS)
Submitter:
Vincent McIntyre
Date:
2021-01-24 15:45:05 UTC
Severity:
normal
Tags:
#705577#5
Date:
2013-04-17 03:33:48 UTC
From:
To:
*** Please type your report below this line ***

Hi

I was experimenting with the following setup:
 - debian NIS master (squeeze/amd64)
 - separate passwd and shadow maps
 - passwd and shadow files distinct from master's /etc/{passwd,shadow}
 - passwd.adjunct for solaris clients, generated from shadow

To make the solaris clients check passwd.adjunct.byname I needed to have
the special '##username' string in field 2 of the passwd map, instead
of the usual 'x' that tells debian clients to check the shadow.byname map.

But I found to get password changes to work from debian hosts I had to
have 'x' in field 2 of the master file for the NIS passwd map; just
mangling the map with ypserv.conf was insufficient.
When I looked at the code to see why '##username' would not work,
I found that yppasswd and rpc.yppasswdd do the check-for-shadow differently:

yppasswd.c:
      hashpass = alloca (strlen (pwd->pw_name) + 3);
      cp = stpcpy (hashpass, "##");
      strcpy (cp, pwd->pw_name);

      if (strncmp(pwd->pw_passwd, "$1$", 3) == 0)
        has_md5_passwd = 1;

      /* We can't check the password with shadow passwords enabled. We
       * leave the checking to yppasswdd */
      if (uid != 0 && strcmp (pwd->pw_passwd, "x") != 0 &&
          strcmp (pwd->pw_passwd, hashpass ) != 0)

rpc.yppasswdd, update.c:
          /* Check the password. At first check for a shadow password. */
          if (oldsf != NULL &&
              pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0')
            {
#ifdef HAVE_GETSPNAM /* shadow password */
              /* Search for the shadow entry of this user */

The patch below changes the rpc.yppasswdd check regarding shadow passwords
to be consistent with yppasswd. I've tested changing passwords from a client
machine using yppasswd and passwd (the latter with the pam_unix2 module)
and it seems to work ok.
It has another nice side effect - when I run yppasswd on the NIS master,
it now updates the entry in the master file for the _shadow_ map, not the
entry in the master file for the _passwd_ map.

Please consider applying this patch.

Kind regards
Vince
--- nis-3.17/ypserv-2.19/rpc.yppasswdd/update.c.orig    2013-04-17 01:19:31.0000 00000 +0000
+++ nis-3.17/ypserv-2.19/rpc.yppasswdd/update.c 2013-04-17 02:20:12.000000000 +0000
@@ -365,6 +365,8 @@
   FILE *oldpf = NULL, *newpf = NULL, *oldsf = NULL, *newsf = NULL;
   struct stat passwd_stat, shadow_stat;
   char *rootpass = "x";
+  char *hashpass, *cp;
+

 #if CHECKROOT
   if ((pw = getpwnam ("root")) != NULL)
@@ -473,9 +475,16 @@
        {
          ++gotit;

+         /* We will also check for passwd.adjunct-style shadow passwords */
+         hashpass = alloca (strlen (pw->pw_name) + 3);
+         cp = stpcpy (hashpass, "##");
+         strcpy (cp, pw->pw_name);
+
          /* Check the password. At first check for a shadow password. */
+         /* This check should match the semantics of the one yppasswd makes. */
          if (oldsf != NULL &&
-             pw->pw_passwd[0] == 'x' && pw->pw_passwd[1] == '\0')
+             (strcmp (pw->pw_passwd, "x") == 0 ||
+              strcmp (pw->pw_passwd, hashpass ) == 0))
            {
 #ifdef HAVE_GETSPNAM /* shadow password */
              /* Search for the shadow entry of this user */