/etc/passwd bug, loophole

Wolfgang Rupprecht wsr at lmi-angel.UUCP
Thu May 22 09:32:25 AEST 1986


[]

	Has anyone else noticed how /etc/passwd often gets lines of
the form:

--
joe::100:100:joe shmoe:/usr/joe:/bin/csh
foo:xyz:101:100:bar foo:/usr/foo:/bin/ksh
				<----- blank line 
::0:0:::			<----- empty templates
::0:0:::
::0:0:::
--

	Well, I finally got motivated to look into what causes this.
It turns out that both "passwd (1)" and "chsh (1)" behave badly if ANY
invalid lines are found in /etc/passwd. Infact, a *blank line* will
produce a 'struct passwd' that has all pointers to null length strings
for the char pointer fields, and 0's for the integer fields.  These
struct passwds are then written to the new passwd file via a
printf().  This causes the NULL and zero fields. This happens, for
example, whenever you have a *blank line* as the last line of
/etc/passwd.

	The problem is that "getpwent (2)" is less than generous with 
blank lines. Below is a set of diffs for bullet-proofing getpwent().

	Oh yes, these blank entries *are* security loopholes, *big
ones*. If you don't believe me, put a blank line in /etc/passwd, then
generate a blank entry or two via a 'chsh' or two. Then try a:

su ''

*poof* you are root (the nameless one).  I am very surprised that ATT
and Berkley haven't fixed this yet. (If you don't have lib sources;
you can't fix getpwent. Complain to Ma Belle and/or Bezerkly. :-) In
the mean time just KEEP the BLANK lines out of /etc/passwd. You'll be
perfectly safe then.)

--
Wolfgang Rupprecht	{harvard|decvax!cca|mit-eddie}!lmi-angel!wsr


*** getpwent.c~	Mon Jun 27 18:07:08 1983
--- getpwent.c	Wed May 21 18:10:24 1986
***************
*** 34,41
  	return(p);
  }
  
! struct passwd *
! getpwent()
  {
  	register char *p;
  

--- 34,42 -----
  	return(p);
  }
  
! static char *
! npwskip(p)
! register char *p;
  {
  	while( *p && *p != ':' )
  		++p;
***************
*** 37,43
  struct passwd *
  getpwent()
  {
! 	register char *p;
  
  	if (pwf == NULL) {
  		if( (pwf = fopen( PASSWD, "r" )) == NULL )

--- 38,49 -----
  npwskip(p)
  register char *p;
  {
! 	while( *p && *p != ':' )
! 		++p;
!         if (*p != ':')
! 	  return 0;
! 	if( *p ) *p++ = 0;
! 	return (p);
  
  
  }
***************
*** 39,51
  {
  	register char *p;
  
! 	if (pwf == NULL) {
! 		if( (pwf = fopen( PASSWD, "r" )) == NULL )
! 			return(0);
! 	}
! 	p = fgets(line, BUFSIZ, pwf);
! 	if (p==NULL)
! 		return(0);
  	passwd.pw_name = p;
  	p = pwskip(p);
  	passwd.pw_passwd = p;

--- 45,67 -----
  	if( *p ) *p++ = 0;
  	return (p);
  
! 
! }
! 
! struct passwd  *
! getpwent ()
! {
!     register char  *p;
! 
!     if (pwf == NULL)
!     {
! 	if ((pwf = fopen (PASSWD, "r")) == NULL)
! 	    return (0);
!     }
!     while (p = fgets (line, BUFSIZ, pwf))
!     {
! 	if ((*p == NULL) || (*p == ':')) /* get rid of old trash */
! 	    continue;
  	passwd.pw_name = p;
  	p = npwskip (p);
  	if (p == NULL)
***************
*** 47,53
  	if (p==NULL)
  		return(0);
  	passwd.pw_name = p;
! 	p = pwskip(p);
  	passwd.pw_passwd = p;
  	p = pwskip(p);
  	passwd.pw_uid = atoi(p);

--- 63,71 -----
  	if ((*p == NULL) || (*p == ':')) /* get rid of old trash */
  	    continue;
  	passwd.pw_name = p;
! 	p = npwskip (p);
! 	if (p == NULL)
! 	    continue;
  	passwd.pw_passwd = p;
  	p = npwskip (p);
  	if (p == NULL)
***************
*** 49,58
  	passwd.pw_name = p;
  	p = pwskip(p);
  	passwd.pw_passwd = p;
! 	p = pwskip(p);
! 	passwd.pw_uid = atoi(p);
! 	p = pwskip(p);
! 	passwd.pw_gid = atoi(p);
  	passwd.pw_quota = 0;
  	passwd.pw_comment = EMPTY;
  	p = pwskip(p);

--- 67,80 -----
  	if (p == NULL)
  	    continue;
  	passwd.pw_passwd = p;
! 	p = npwskip (p);
! 	if (p == NULL)
! 	    continue;
! 	passwd.pw_uid = atoi (p);
! 	p = npwskip (p);
! 	if (p == NULL)
! 	    continue;
! 	passwd.pw_gid = atoi (p);
  	passwd.pw_quota = 0;
  	passwd.pw_comment = EMPTY;
  	p = npwskip (p);
***************
*** 55,61
  	passwd.pw_gid = atoi(p);
  	passwd.pw_quota = 0;
  	passwd.pw_comment = EMPTY;
! 	p = pwskip(p);
  	passwd.pw_gecos = p;
  	p = pwskip(p);
  	passwd.pw_dir = p;

--- 77,85 -----
  	passwd.pw_gid = atoi (p);
  	passwd.pw_quota = 0;
  	passwd.pw_comment = EMPTY;
! 	p = npwskip (p);
! 	if (p == NULL)
! 	    continue;
  	passwd.pw_gecos = p;
  	p = npwskip (p);
  	if (p == NULL)
***************
*** 57,63
  	passwd.pw_comment = EMPTY;
  	p = pwskip(p);
  	passwd.pw_gecos = p;
! 	p = pwskip(p);
  	passwd.pw_dir = p;
  	p = pwskip(p);
  	passwd.pw_shell = p;

--- 81,89 -----
  	if (p == NULL)
  	    continue;
  	passwd.pw_gecos = p;
! 	p = npwskip (p);
! 	if (p == NULL)
! 	    continue;
  	passwd.pw_dir = p;
  	p = pwskip (p);
  	passwd.pw_shell = p;
***************
*** 59,65
  	passwd.pw_gecos = p;
  	p = pwskip(p);
  	passwd.pw_dir = p;
! 	p = pwskip(p);
  	passwd.pw_shell = p;
  	while(*p && *p != '\n') p++;
  	*p = '\0';

--- 85,91 -----
  	if (p == NULL)
  	    continue;
  	passwd.pw_dir = p;
! 	p = pwskip (p);
  	passwd.pw_shell = p;
  	while (*p && *p != '\n')
  	    p++;
***************
*** 61,67
  	passwd.pw_dir = p;
  	p = pwskip(p);
  	passwd.pw_shell = p;
! 	while(*p && *p != '\n') p++;
  	*p = '\0';
  	return(&passwd);
  }

--- 87,94 -----
  	passwd.pw_dir = p;
  	p = pwskip (p);
  	passwd.pw_shell = p;
! 	while (*p && *p != '\n')
! 	    p++;
  	*p = '\0';
  	return (&passwd);
      }
***************
*** 63,67
  	passwd.pw_shell = p;
  	while(*p && *p != '\n') p++;
  	*p = '\0';
! 	return(&passwd);
  }

--- 90,96 -----
  	while (*p && *p != '\n')
  	    p++;
  	*p = '\0';
! 	return (&passwd);
!     }
!     return (0);
  }

-- 
Wolfgang Rupprecht	{harvard|decvax!cca|mit-eddie}!lmi-angel!wsr



More information about the Comp.unix.wizards mailing list