NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bin/37863: yp_passwd command may destroy NIS database entries when used on a server that includes users via netgroups



>Number:         37863
>Category:       bin
>Synopsis:       yp_passwd command may destroy NIS database entries when used 
>on a server that includes users via netgroups
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jan 24 14:25:01 +0000 2008
>Originator:     Wolfgang Stukenbrock
>Release:        NetBSD 4.0
>Organization:
Dr. Nagler & Company GmbH
        
>Environment:
        
        
System: NetBSD s012 2.1 NetBSD 2.1 (NSW-S012) #10: Mon Dec 12 12:03:54 CET 2005 
wgstuken@s011:/export/netbsd-2.1/usr/src/sys/arch/i386/compile/NSW-S012 i386
Architecture: i386
Machine: i386
>Description:
        If users are added to a system using NIS comparbility mode and netgroups
        and if some parts of the password entry will be overwritten by the 
netgroup-entry
        in the password file. (e.g. "+@NNN:*:0:0::/usr/common-home/:" - this 
will overwrite
        the home directory for every user in netgroup NNN)
        If yppasswd (or passwd -y or ...) is called the home-directory of the 
calling user is
        also changed to the value from the netgroup-line.
        This is not the intendet behaviour of a password change and can lead to 
user lockouts
        on some systems, if login is rejected without e.g. home directory.
>How-To-Repeat:
        Setup a netgroup and replace e.g. the home-directory or the login-shell 
and perform
        a password change from that machine. The home-directory or login-shell 
will also be
        changed by this call in the NIS-master.
>Fix:
        As already stated in the source code at line 264, it is no good idea to 
rely on getpwnam
        of the local machine if we are gooing to change te whole entry in the 
NIS database.
        The following fix will change that. The original entries retrieved from 
the NIS server
        are used in the password change request.
        The affected file is /usr/src/usr.bin/passwd/yp_passwd.c.

*** /export/NetBSD-4.0/src/usr.bin/passwd/yp_passwd.c   Sat Feb 26 08:19:25 2005
--- ./src/usr.bin/passwd/yp_passwd.c    Wed Jan  9 09:14:19 2008
***************
*** 149,155 ****
  }
  
  static int
! ypgetpwnam(const char *nam)
  {
        char *val;
        int reason, vallen;
--- 149,155 ----
  }
  
  static int
! ypgetpwnam(const char *nam, struct passwd *pwd)
  {
        char *val;
        int reason, vallen;
***************
*** 159,168 ****
                          &val, &vallen);
        if (reason != 0) {
                if (val != NULL)
!                       free(val);
                return 0;
        }
!       free(val);
        return 1;
  }
  
--- 159,181 ----
                          &val, &vallen);
        if (reason != 0) {
                if (val != NULL)
!                       { parse_error: free(val); }
                return 0;
        }
!       pwd->pw_name = val;
!       while (*val != ':' && *val != '\0') val++; if (*val != ':') goto 
parse_error; *val++ = '\0';
!       pwd->pw_passwd = val;
!       while (*val != ':' && *val != '\0') val++; if (*val != ':') goto 
parse_error; *val++ = '\0';
!       for (pwd->pw_uid = 0; *val >= '0' && *val <= '9'; pwd->pw_uid = 
pwd->pw_uid * 10 + (*val++ - '0'));
!       if (*val != ':') goto parse_error; *val++ = '\0';
!       for (pwd->pw_gid = 0; *val >= '0' && *val <= '9'; pwd->pw_gid = 
pwd->pw_gid * 10 + (*val++ - '0'));
!       if (*val != ':') goto parse_error; *val++ = '\0';
!       pwd->pw_gecos = val;
!       while (*val != ':' && *val != '\0') val++; if (*val != ':') goto 
parse_error; *val++ = '\0';
!       pwd->pw_dir = val;
!       while (*val != ':' && *val != '\0') val++; if (*val != ':') goto 
parse_error; *val++ = '\0';
!       pwd->pw_shell = val;
!       while (*val != ':' && *val != '\0') val++; if (*val == ':') goto 
parse_error;
        return 1;
  }
  
***************
*** 190,196 ****
        char *master;
        int ch, r, rpcport, status;
        struct yppasswd yppasswd;
!       struct passwd *pw;
        struct timeval tv;
        CLIENT *client;
  
--- 203,209 ----
        char *master;
        int ch, r, rpcport, status;
        struct yppasswd yppasswd;
!       struct passwd pw;
        struct timeval tv;
        CLIENT *client;
  
***************
*** 261,297 ****
  
        /* Bail out if this is a local (non-yp) user, */
        /* then get user's login identity */
!       /* XXX This should always fetch from NIS, not rely on getpwnam()! */
!       if (!ypgetpwnam(username) ||
!           !(pw = getpwnam(username)))
                errx(1, "NIS unknown user %s", username);
  
!       if (uid && uid != pw->pw_uid)
                errx(1, "you may only change your own password: %s",
                    strerror(EACCES));
  
        /* prompt for new password */
!       yppasswd.newpw.pw_passwd = getnewpasswd(pw, &yppasswd.oldpass);
  
        /* tell rpc.yppasswdd */
!       yppasswd.newpw.pw_name  = strdup(pw->pw_name);
        if (!yppasswd.newpw.pw_name) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_uid   = pw->pw_uid;
!       yppasswd.newpw.pw_gid   = pw->pw_gid;
!       yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
        if (!yppasswd.newpw.pw_gecos) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_dir   = strdup(pw->pw_dir);
        if (!yppasswd.newpw.pw_dir) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
        if (!yppasswd.newpw.pw_shell) {
                err(1, "strdup");
                /*NOTREACHED*/
--- 274,309 ----
  
        /* Bail out if this is a local (non-yp) user, */
        /* then get user's login identity */
!       if (!ypgetpwnam(username, &pw) ||
!           !getpwnam(username))
                errx(1, "NIS unknown user %s", username);
  
!       if (uid && uid != pw.pw_uid)
                errx(1, "you may only change your own password: %s",
                    strerror(EACCES));
  
        /* prompt for new password */
!       yppasswd.newpw.pw_passwd = getnewpasswd(&pw, &yppasswd.oldpass);
  
        /* tell rpc.yppasswdd */
!       yppasswd.newpw.pw_name  = strdup(pw.pw_name);
        if (!yppasswd.newpw.pw_name) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_uid   = pw.pw_uid;
!       yppasswd.newpw.pw_gid   = pw.pw_gid;
!       yppasswd.newpw.pw_gecos = strdup(pw.pw_gecos);
        if (!yppasswd.newpw.pw_gecos) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_dir   = strdup(pw.pw_dir);
        if (!yppasswd.newpw.pw_dir) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_shell = strdup(pw.pw_shell);
        if (!yppasswd.newpw.pw_shell) {
                err(1, "strdup");
                /*NOTREACHED*/
***************
*** 376,382 ****
        char *master;
        int r, rpcport, status;
        struct yppasswd yppasswd;
!       struct passwd *pw;
        struct timeval tv;
        CLIENT *client;
  
--- 388,394 ----
        char *master;
        int r, rpcport, status;
        struct yppasswd yppasswd;
!       struct passwd pw;
        struct timeval tv;
        CLIENT *client;
  
***************
*** 419,457 ****
  
        /* Bail out if this is a local (non-yp) user, */
        /* then get user's login identity */
!       if (!ypgetpwnam(username) ||
!           !(pw = getpwnam(username))) {
                warnx("NIS unknown user %s", username);
                /* continuation */
                return(-1);
        }
  
!       if (uid && uid != pw->pw_uid)
                errx(1, "you may only change your own password: %s",
                    strerror(EACCES));
  
        /* prompt for new password */
!       yppasswd.newpw.pw_passwd = getnewpasswd(pw, &yppasswd.oldpass);
  
        /* tell rpc.yppasswdd */
!       yppasswd.newpw.pw_name  = strdup(pw->pw_name);
        if (!yppasswd.newpw.pw_name) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_uid   = pw->pw_uid;
!       yppasswd.newpw.pw_gid   = pw->pw_gid;
!       yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
        if (!yppasswd.newpw.pw_gecos) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_dir   = strdup(pw->pw_dir);
        if (!yppasswd.newpw.pw_dir) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
        if (!yppasswd.newpw.pw_shell) {
                err(1, "strdup");
                /*NOTREACHED*/
--- 431,469 ----
  
        /* Bail out if this is a local (non-yp) user, */
        /* then get user's login identity */
!       if (!ypgetpwnam(username, &pw) ||
!           !getpwnam(username)) {
                warnx("NIS unknown user %s", username);
                /* continuation */
                return(-1);
        }
  
!       if (uid && uid != pw.pw_uid)
                errx(1, "you may only change your own password: %s",
                    strerror(EACCES));
  
        /* prompt for new password */
!       yppasswd.newpw.pw_passwd = getnewpasswd(&pw, &yppasswd.oldpass);
  
        /* tell rpc.yppasswdd */
!       yppasswd.newpw.pw_name  = strdup(pw.pw_name);
        if (!yppasswd.newpw.pw_name) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_uid   = pw.pw_uid;
!       yppasswd.newpw.pw_gid   = pw.pw_gid;
!       yppasswd.newpw.pw_gecos = strdup(pw.pw_gecos);
        if (!yppasswd.newpw.pw_gecos) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_dir   = strdup(pw.pw_dir);
        if (!yppasswd.newpw.pw_dir) {
                err(1, "strdup");
                /*NOTREACHED*/
        }
!       yppasswd.newpw.pw_shell = strdup(pw.pw_shell);
        if (!yppasswd.newpw.pw_shell) {
                err(1, "strdup");
                /*NOTREACHED*/

>Unformatted:
        
        



Home | Main Index | Thread Index | Old Index