When run without root privileges, getpwent(), getpwnam() and friends
always set errno, even if they succeed. Because of this, it is
impossible to distinguish between true errors (for which errno should be
set) and conditions like "end of database" and "no such user" (for which
errno should not be set).

The problem is caused by __initdb() in lib/libc/gen/getpwent.c. It first
tries to open /etc/spwd.db. If that fails, it tries /etc/pwd.db. Opening
/etc/spwd.db always fails for non-root users and this causes errno to be
set.

The simplest solution is to save the original errno value before
attempting to open the password databases and then restore it when
either database has been opened successfully.

Regards,
Tim

Index: getpwent.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/getpwent.c,v
retrieving revision 1.42
diff -p -u -r1.42 getpwent.c
--- getpwent.c  21 Nov 2009 10:24:59 -0000      1.42
+++ getpwent.c  12 Aug 2011 23:30:07 -0000
@@ -844,14 +844,18 @@ static int
 __initdb(void)
 {
        static int warned;
+       int oerrno;
 
 #ifdef YP
        __ypmode = YPMODE_NONE;
        __getpwent_has_yppw = -1;
 #endif
+       oerrno = errno;
        if ((_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) ||
-           (_pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL)))
+           (_pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL))) {
+               errno = oerrno;
                return (1);
+       }
        if (!warned)
                syslog(LOG_ERR, "%s: %m", _PATH_MP_DB);
        warned = 1;

Reply via email to