🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by Wolfgang Rupprecht Wed, 21 May 1986 23:32
/etc/passwd bug, loophole
#553
Author: Wolfgang Rupprecht
Date: Wed, 21 May 1986 23:32
273 lines
6470 bytes
[]

	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
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads