Bug 14201

Summary: setpassent() in libc does not function properly
Product: Base System Reporter: robertw <robertw>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 3.3-RELEASE   
Hardware: Any   
OS: Any   

Description robertw 1999-10-08 07:00:00 UTC
(This was taken from another post, just reposting this bug on 3.3-RELEASE)

The manual page for the setpassent(int stayopen) function says :

"The setpassent() function accomplishes two purposes.  First, it
causes getpwent() to ``rewind'' to the beginning of the database.
Additionally, if stayopen is non-zero, file descriptors are left open,
significantly speeding up subsequent accesses for all of the routines.
(This latter functionality is unnecessary for getpwent() as it doesn't
close its file descriptors by default.)"

The problem is that in the file getpwent.c which implements the
setpassent() function in the libc, the stayopen variable seems not
used. And then, code like setpassent(1) doesn't work as expected.

This problem is particularly annoying with ProFTPD
(/usr/ports/net/proftpd) which uses a such code.

Fix: 

(Again taken from the previous post.  It's a quick one line fix!!)

A patch has been proposed by Adam Mackler
(mackler@barter.dewline.com). It adds a "if" to check the value of
"_pw_stayopen" BEFORE calling "endpwent()".

	
Adam Mackler writes:
 > > Date: Thu, 6 Aug 1998 17:50:08 -0400
 > > From: Floody <flood@evcom.net>
 > > Reply-To: proftpd-l@evcom.net
 > > To: Karl Pielorz <kpielorz@tdx.co.uk>
 > > Cc: proftpd-l@evcom.net
 > > Subject: Re: [proftpd-l] New ProFTPd user - Security, Incoming and pwd.db?
 > > 
 > > Ok.  I put up a test FreeBSD 2.2.7 system.  There appears to be a libc
 > > problem with the setpassent() function, which doesn't work on FreeBSD as
 > > documented in the man pages (or on any other BSD).  This is the heart of
 > > the problem.  There is no workaround until libc is fixed.
 > 
 > Hi:
 > 
 > I think the following patch may fix the problem, but I'm afraid
 > I don't know how to rebuild my c library.  If you find out if this
 > works can you let me know?  Thanks.
 > 
 > 
 > *** getpwent.c  Wed Aug 19 02:00:13 1998
 > --- getpwent.c.dist     Wed Aug 19 01:58:33 1998
 > ***************
 > *** 194,201 ****
 >         if (rval && (_pw_passwd.pw_name[0] == '+'||
 >                         _pw_passwd.pw_name[0] == '-')) rval = 0;
 >   
 > !       if (!_pw_stayopen)
 > !         endpwent();
 >         return(rval ? &_pw_passwd : (struct passwd *)NULL);
 >   }
 >   
 > --- 194,200 ----
 >         if (rval && (_pw_passwd.pw_name[0] == '+'||
 >                         _pw_passwd.pw_name[0] == '-')) rval = 0;
 >   
 > !       endpwent();
 >         return(rval ? &_pw_passwd : (struct passwd *)NULL);
 >   }
 >   
 > 
 > -- 
 > Adam Mackler
 > Dewline Communications, LLC
 > 212-505-9149
 >
How-To-Repeat: The problem is visible using ProFTPD (latest at the time of this bug report is 1.2.0pre8).
Comment 1 robertw 1999-10-08 07:56:48 UTC
The patch in this bug report does not work fully.  I patched the endpwent()
function, and it works correctly now:

244,246d243
<     if (_pw_stayopen)
<       return;
<

It will keep the fd open when setpassent(int stayopen) is passed 1.  It's
now behaving the way it should ;)

Thanks,

Robert S. Wojciechowski Jr.
robertw@wojo.com

PGP: 0xF2CA68F2 - http://www.wojo.com/pgpkeys/robertw.asc
Comment 2 Ruslan Ermilov 1999-10-08 08:20:06 UTC
On Fri, Oct 08, 1999 at 12:00:01AM -0700, Robert Wojciechowski Jr. wrote:
> 
>  The patch in this bug report does not work fully.  I patched the endpwent()
>  function, and it works correctly now:
>  
>  244,246d243
>  <     if (_pw_stayopen)
>  <       return;
>  <
>  
>  It will keep the fd open when setpassent(int stayopen) is passed 1.  It's
>  now behaving the way it should ;)
>  
And endpwent() will never close the file :-(

-- 
Ruslan Ermilov		Sysadmin and DBA of the
ru@ucb.crimea.ua	United Commercial Bank,
ru@FreeBSD.org		FreeBSD committer,
+380.652.247.647	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age
Comment 3 stephane.legrand 1999-10-08 09:11:15 UTC
robertw@wojo.com writes:
 > 
 > >Number:         14201
 > >Category:       kern
 > >Synopsis:       setpassent() in libc does not function properly
 > >Confidential:   no
 > >Severity:       serious
 > >Priority:       high
 > >Responsible:    freebsd-bugs
 > >State:          open
 > >Quarter:        
 > >Keywords:       
 > >Date-Required:
 > >Class:          sw-bug
 > >Submitter-Id:   current-users
 > >Arrival-Date:   Thu Oct  7 23:00:00 PDT 1999
 > >Closed-Date:
 > >Last-Modified:
 > >Originator:     Robert S. Wojciechowski Jr.
 > >Release:        FreeBSD 3.3-RELEASE i386
 > >Organization:
 > >Environment:
 > FreeBSD max.millenniumworks.com 3.3-RELEASE FreeBSD 3.3-RELEASE #9:
 > Sun Oct 3 02:40:16 EDT 1999
 > root@max.millenniumworks.com:/usr/src/sys/compile/MYKERNEL i386
 > >Description:
 > (This was taken from another post, just reposting this bug on 3.3-RELEASE)
 > 

Yes, indeed :) . This is the same bug report than the kern/7781.


 > The manual page for the setpassent(int stayopen) function says :
 > 
 > "The setpassent() function accomplishes two purposes.  First, it
 > causes getpwent() to ``rewind'' to the beginning of the database.
 > Additionally, if stayopen is non-zero, file descriptors are left open,
 > significantly speeding up subsequent accesses for all of the routines.
 > (This latter functionality is unnecessary for getpwent() as it doesn't
 > close its file descriptors by default.)"
 > 
 > The problem is that in the file getpwent.c which implements the
 > setpassent() function in the libc, the stayopen variable seems not
 > used. And then, code like setpassent(1) doesn't work as expected.
 > 
 > This problem is particularly annoying with ProFTPD
 > (/usr/ports/net/proftpd) which uses a such code.
 > 
 > >How-To-Repeat:
 > The problem is visible using ProFTPD (latest at the time of this bug report is 1.2.0pre8).
 > >Fix:
 > (Again taken from the previous post.  It's a quick one line fix!!)
 > 
 > A patch has been proposed by Adam Mackler
 > (mackler@barter.dewline.com). It adds a "if" to check the value of
 > "_pw_stayopen" BEFORE calling "endpwent()".
 > 
 > 	
 > Adam Mackler writes:
 >  > > Date: Thu, 6 Aug 1998 17:50:08 -0400
 >  > > From: Floody <flood@evcom.net>
 >  > > Reply-To: proftpd-l@evcom.net
 >  > > To: Karl Pielorz <kpielorz@tdx.co.uk>
 >  > > Cc: proftpd-l@evcom.net
 >  > > Subject: Re: [proftpd-l] New ProFTPd user - Security, Incoming and pwd.db?
 >  > > 
 >  > > Ok.  I put up a test FreeBSD 2.2.7 system.  There appears to be a libc
 >  > > problem with the setpassent() function, which doesn't work on FreeBSD as
 >  > > documented in the man pages (or on any other BSD).  This is the heart of
 >  > > the problem.  There is no workaround until libc is fixed.
 >  > 
 >  > Hi:
 >  > 
 >  > I think the following patch may fix the problem, but I'm afraid
 >  > I don't know how to rebuild my c library.  If you find out if this
 >  > works can you let me know?  Thanks.
 >  > 
 >  > 
 >  > *** getpwent.c  Wed Aug 19 02:00:13 1998
 >  > --- getpwent.c.dist     Wed Aug 19 01:58:33 1998
 >  > ***************
 >  > *** 194,201 ****
 >  >         if (rval && (_pw_passwd.pw_name[0] == '+'||
 >  >                         _pw_passwd.pw_name[0] == '-')) rval = 0;
 >  >   
 >  > !       if (!_pw_stayopen)
 >  > !         endpwent();
 >  >         return(rval ? &_pw_passwd : (struct passwd *)NULL);
 >  >   }
 >  >   
 >  > --- 194,200 ----
 >  >         if (rval && (_pw_passwd.pw_name[0] == '+'||
 >  >                         _pw_passwd.pw_name[0] == '-')) rval = 0;
 >  >   
 >  > !       endpwent();
 >  >         return(rval ? &_pw_passwd : (struct passwd *)NULL);
 >  >   }
 >  >   
 >  > 
 >  > -- 
 >  > Adam Mackler
 >  > Dewline Communications, LLC
 >  > 212-505-9149
 >  > 
 > 

-- 
Stephane.Legrand@bigfoot.com
FreeBSD Francophone : http://www.freebsd-fr.org/
Comment 4 robertw 1999-10-08 22:43:59 UTC
A test for this bug is:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>

int main()
{
  setpassent(1);
  getpwent();

  chroot("/usr");
  chdir("/");
  if(!getpwuid(0)) {
    printf("setpassent doesn't appear to work\n");
  } else {
    if(!getpwuid(0))
      printf("second getpwuid(0) didn't work\n");
    else
      printf("setpassent works\n");
  }
  return 0;
}

Right now, the second getpwuid(0) call fails.  Adding the if (!_pw_stayopen)
before the endpwent() in both getpwnam() and getpwuid() lets this test pass,
but is it a sufficient fix?

Is a closing call to endpwent() necessary for a program to correctly close
the database?

Robert S. Wojciechowski Jr.
robertw@wojo.com

PGP: 0xF2CA68F2 - http://www.wojo.com/pgpkeys/robertw.asc
Comment 5 robertw 1999-10-09 03:31:04 UTC
Ruslan, 

Looks like the original patch works the best.  It works well too.  If you
look in getgrent.c, it contains the right code to handle the stayopen flag:

       /* correct, from getgrent.c */
       if (!_gr_stayopen)
                endgrent();
        return(rval ? &_gr_group : NULL);

instead of

        /* incorrect */
        endgrent();
        return(rval ? &_gr_group : NULL);

The incorrect code is what getpwent.c contains.  A test for this
functionality is the following program:

--SNIP--
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pwd.h>

int main()
{
  setpassent(1);
  getpwent();

  chroot("/usr");
  chdir("/");
  if(!getpwuid(0)) {
    printf("setpassent doesn't appear to work\n");
  } else {
    if(!getpwuid(0))
      printf("second getpwuid(0) didn't work\n");
    else
      printf("setpassent works\n");
  }
  return 0;
}
--SNIP--

It passes with flying colors after the fix.  

Best regards,

Robert S. Wojciechowski Jr.
robertw@wojo.com

PGP: 0xF2CA68F2 - http://www.wojo.com/pgpkeys/robertw.asc

-----Original Message-----
From: Ruslan Ermilov [mailto:ru@ucb.crimea.ua]
Sent: Friday, October 08, 1999 3:20 AM
To: Robert Wojciechowski Jr.
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/14201: setpassent() in libc does not function properly

On Fri, Oct 08, 1999 at 12:00:01AM -0700, Robert Wojciechowski Jr. wrote:
>
>  The patch in this bug report does not work fully.  I patched the
endpwent()
>  function, and it works correctly now:
> 
>  244,246d243
>  <     if (_pw_stayopen)
>  <       return;
>  <
> 
>  It will keep the fd open when setpassent(int stayopen) is passed 1.  It's
>  now behaving the way it should ;)
> 
And endpwent() will never close the file :-(

--
Ruslan Ermilov          Sysadmin and DBA of the
ru@ucb.crimea.ua        United Commercial Bank,
ru@FreeBSD.org          FreeBSD committer,
+380.652.247.647        Simferopol, Ukraine

http://www.FreeBSD.org  The Power To Serve
http://www.oracle.com   Enabling The Information Age
Comment 6 robertw 1999-10-09 07:02:42 UTC
Problem crept in on this update (1.11):

http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/gen/getpwent.c.diff?r1=1.
10&r2=1.11

Robert S. Wojciechowski Jr.
robertw@wojo.com

PGP: 0xF2CA68F2 - http://www.wojo.com/pgpkeys/robertw.asc
Comment 7 robertw 1999-10-11 20:56:43 UTC
Working and tested patch (adopted from OpenBSD and NetBSD):


-- BEGIN PATCH --
--- getpwent.c.orig     Mon Oct 11 15:34:56 1999
+++ getpwent.c  Mon Oct 11 14:59:42 1999
@@ -176,7 +176,10 @@
        if (rval && (_pw_passwd.pw_name[0] == '+'||
                        _pw_passwd.pw_name[0] == '-')) rval = 0;

-       endpwent();
+       if (!_pw_stayopen) {
+         (void)(_pw_db->close)(_pw_db);
+         _pw_db = (DB *)NULL;
+       }
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }

@@ -216,7 +219,10 @@
        if (rval && (_pw_passwd.pw_name[0] == '+'||
                        _pw_passwd.pw_name[0] == '-')) rval = 0;

-       endpwent();
+       if (!_pw_stayopen) {
+         (void)(_pw_db->close)(_pw_db);
+         _pw_db = (DB *)NULL;
+        }
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
-- END PATCH --


Robert S. Wojciechowski Jr.
robertw@wojo.com

PGP: 0xF2CA68F2 - http://www.wojo.com/pgpkeys/robertw.asc
Comment 8 Andrey A. Chernov freebsd_committer freebsd_triage 1999-10-16 12:53:39 UTC
State Changed
From-To: open->closed

Just fixed