From netch@sivka.carrier.kiev.ua Thu Jun  3 07:44:09 1999
Return-Path: <netch@sivka.carrier.kiev.ua>
Received: from sivka.carrier.kiev.ua (zirafe.carrier.kiev.ua [193.193.193.119])
	by hub.freebsd.org (Postfix) with ESMTP id B6F18153D2
	for <FreeBSD-gnats-submit@freebsd.org>; Thu,  3 Jun 1999 07:44:06 -0700 (PDT)
	(envelope-from netch@sivka.carrier.kiev.ua)
Received: (from netch@localhost)
        by sivka.carrier.kiev.ua (8.Who.Cares/Kilkenny_is_better) id RAA84607;
        Thu, 3 Jun 1999 17:44:04 +0300 (EEST)
        (envelope-from netch)
Message-Id: <199906031444.RAA84607@sivka.carrier.kiev.ua>
Date: Thu, 3 Jun 1999 17:44:04 +0300 (EEST)
From: netch@lucky.net (Valentin Nechayev)
Sender: netch@sivka.carrier.kiev.ua
Reply-To: netch@lucky.net
To: FreeBSD-gnats-submit@freebsd.org
Subject: getpwent() YP bug
X-Send-Pr-Version: 3.2

>Number:         12008
>Category:       bin
>Synopsis:       getpwent() YP bug
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jun  3 07:50:01 PDT 1999
>Closed-Date:    Thu Jun 3 19:32:54 PDT 1999
>Last-Modified:  Thu Jun  3 19:34:28 PDT 1999
>Originator:     Valentin Nechayev
>Release:        FreeBSD 3.2-STABLE i386
>Organization:
Lucky Net Ltd
>Environment:

FreeBSD 3.2-STABLE

>Description:

With YP/NIS or pseudo YP/NIS entries in password database, multiple
setpwent() - getpwent() - endpwent() cycles result in null pointer usage with
successive segmentation fault.

YP support in getpwxxx() function group uses variable _yp_enabled to make
decision in YP using policy. Its initial value (-1) causes getpwxxx()
functions ( getpwnam, getpwuid, getpwent ) to call _ypinitdb(). _ypinitdb()
creates cache DB in memory pointed by _ypcache pointer and changes _yp_enabled
value to non-negative. When endpwent() called,
it clears some variables and destruct the database, then _ypcache points to
null, but _yp_enabled keeps its old state. When getpwent() is called after
endpwent(), the following code is executed:

==== cut src/lib/libc/gen/getpwent.c line 122 ===
#ifdef YP
        if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
                if (_yp_enabled == -1)
                        _ypinitdb();
                bzero((char *)&_ypnam, sizeof(_ypnam));
                bcopy(_pw_passwd.pw_name, _ypnam,
                        strlen(_pw_passwd.pw_name));
                _pw_copy = _pw_passwd;
                if (unwind((char *)&_ypnam) == 0)
                        goto tryagain;
                else
                        return(&_pw_passwd);
        }
#else
=== end cut ===

In this code, _yp_enabled is not equal to -1, therefore _ypinitdb() is not
called; when getpwent() calls unwind(), unwind calls store(), store tries
to write data to cache database, but cache database does not exist and
_ypcache is equal to NULL. SEGV.

>How-To-Repeat:

Add the following comment line to /etc/master.passwd:

---:-:8:8::0:0:------------ SLIRP pseudo-users ------------:/no.such/dir:/dev/null

but really line content is IMHO insensitive, when it matches /^+/ or /^-/.

Rebuild password databases using pwd_mkdb program or vipw editing interface.

Compile and run the following program:

=== cut here ===
#include <stdio.h>
#include <stddef.h>
#include <pwd.h>

int main() {
   int i;
   for( i = 1; i <= 2; i++ ) {
      struct passwd* pwp;
      setpwent();
      while( ( pwp = getpwent() ) != NULL )
         ;
      endpwent();
   }
   printf( "I am alive!\n" );
}
=== end cut ===

At second iteration of for(i), a segmentation fault occurs:

=== cut gdb output ===
Starting program: /usr/staff/netch/tmp/getpwbug/test2/test2

Program received signal SIGSEGV, Segmentation fault.
0x8049d43 in store (key=0x804ba25 "-") at getpwent.c:386
386             (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
(gdb) print _ypcache
$1 = (DB *) 0x0
=== end cut ===

>Fix:
	
Clear the variable _yp_enabled to default value (-1) when endpwent() clears
_ypcache database:

*** src/lib/libc/gen/getpwent.c.orig	Thu Dec 17 18:31:02 1998
--- src/lib/libc/gen/getpwent.c	Thu Jun  3 16:28:13 1999
***************
*** 255,260 ****
--- 255,261 ----
  		_ypcache = (DB *)NULL;
  		_yp_exclusions = 0;
  	}
+ 	_yp_enabled = -1;
  #endif
  }
  

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: wpaul 
State-Changed-When: Thu Jun 3 19:32:54 PDT 1999 
State-Changed-Why:  
I have applied your patch to both the -current and -stable branches. 
Thanks for submitting the bug report and the fix. 

-Bill 
>Unformatted:
