rework the password subsystem
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 12:43:09 +0000 (04:43 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 12:43:09 +0000 (04:43 -0800)
SCCS-vsn: lib/libc/gen/getpwent.3 6.7
SCCS-vsn: lib/libc/gen/getpwent.c 5.15

usr/src/lib/libc/gen/getpwent.3
usr/src/lib/libc/gen/getpwent.c

index e83d3bb..e4ef707 100644 (file)
@@ -3,35 +3,26 @@
 .\"
 .\" %sccs.include.redist.man%
 .\"
 .\"
 .\" %sccs.include.redist.man%
 .\"
-.\"    @(#)getpwent.3  6.6 (Berkeley) %G%
+.\"    @(#)getpwent.3  6.7 (Berkeley) %G%
 .\"
 .TH GETPWENT 3  ""
 .AT 3
 .SH NAME
 .\"
 .TH GETPWENT 3  ""
 .AT 3
 .SH NAME
-getpwent, getpwnam, getpwuid, setpassent,
-setpwfile, setpwent, endpwent \- get password file entries
+getpwent, getpwnam, getpwuid, setpassent, setpwent,
+endpwent \- get password file entries
 .SH SYNOPSIS
 .nf
 .SH SYNOPSIS
 .nf
-.B #include <sys/types.h>
-.B #include <pwd.h>
-.PP
-.B struct passwd *getpwent()
-.PP
-.B struct passwd *getpwnam(login)
-.B char *login;
-.PP
-.B struct passwd *getpwuid(uid)
-.B uid_t uid;
-.PP
-.B int setpassent(stayopen)
-.B int stayopen;
-.PP
-.B void setpwfile(file)
-.B char *file;
-.PP
-.B int setpwent()
-.PP
-.B void endpwent()
+.ft B
+#include <sys/types.h>
+#include <pwd.h>
+
+struct passwd *getpwent(void);
+struct passwd *getpwnam(char *login);
+struct passwd *getpwuid(uid_t uid);
+int setpassent(int stayopen);
+int setpwent(void);
+void endpwent(void);
+.ft R
 .fi
 .SH DESCRIPTION
 .IR Getpwent ,
 .fi
 .SH DESCRIPTION
 .IR Getpwent ,
@@ -68,34 +59,28 @@ These fields are more completely described in
 and
 .I getpwuid
 search the password database for a matching user name or user uid,
 and
 .I getpwuid
 search the password database for a matching user name or user uid,
-respectively, returning the first one encountered.  Identical
-user names or user uids may result in undefined behavior.
+respectively, always returning the first one encountered.
 .PP
 .I Getpwent
 sequentially reads the password database and is intended for programs
 .PP
 .I Getpwent
 sequentially reads the password database and is intended for programs
-that wish to step through the complete list of users.
-.PP
-All three routines will open the password file for reading, if
-necessary.
-.PP
-.I Setpwfile
-changes the default password file to
-.IR file ,
-thus allowing the use of alternate password files.
+that wish to process the complete list of users.
 .PP
 .I Setpassent
 .PP
 .I Setpassent
-opens the file or rewinds it if it is already open.  If
+accomplishes two purposes.
+First, it causes
+.I getpwent
+to ``rewind'' to the beginning of the database.
+Additionally, if
 .I stayopen
 is non-zero, file descriptors are left open, significantly speeding
 .I stayopen
 is non-zero, file descriptors are left open, significantly speeding
-up subsequent calls.  This functionality is unnecessary for
+up subsequent accesses for all of the routines.
+(This latter functionality is unnecessary for
 .I getpwent
 .I getpwent
-as it doesn't close its file descriptors by default.  It should also
-be noted that it is dangerous for long-running programs to use this
-functionality as the password file may be updated by
-.IR chpass (1),
-.IR passwd (1),
-or
-.IR vipw (8).
+as it doesn't close its file descriptors by default.)
+.PP
+It is dangerous for long-running programs to keep the file descriptors
+open the database will become out of date if it is updated while the
+program is running.
 .PP
 .I Setpwent
 is identical to
 .PP
 .I Setpwent
 is identical to
@@ -107,30 +92,19 @@ closes any open files.
 .PP
 These routines have been written to ``shadow'' the password file, e.g.
 allow only certain programs to have access to the encrypted password.
 .PP
 These routines have been written to ``shadow'' the password file, e.g.
 allow only certain programs to have access to the encrypted password.
-This is done by using the
-.IR mkpasswd (8)
-program, which creates
-.IR ndbm (3)
-databases that correspond to the password file, with the single exception
-that, rather than storing the encrypted password in the database, it stores
-the offset in the password file where the encrypted password may be found.
-.IR Getpwent ,
-.IR getpwnam ,
-and
-.I getpwuid
-will use the
-.I ndbm
-files in preference to the ``real'' password files, only reading the
-password file itself, to obtain the encrypted password, if the process
-is running with an effective user id equivalent to super-user.
-If the password file itself is protected, and the
-.I ndbm
-files are not, this makes the password available only to programs
-running with super-user privileges.
+If the process which calls them has an effective uid of 0, the encrypted
+password will be returned, otherwise, the password field of the retuned
+structure will point to the string ``*''.
 .SH FILES
 .SH FILES
-/etc/passwd
+/var/db/pwd.db                 The insecure password database file
+.br
+/var/db/spwd.db                The secure password database file
+.br
+/etc/master.passwd             The current password file
+.br
+/etc/passwd                    A Version 7 format password file
 .SH "SEE ALSO"
 .SH "SEE ALSO"
-getlogin(3), getgrent(3), ndbm(3), passwd(5)
+getlogin(3), getgrent(3), passwd(5), pwd_mkdb(8), vipw(8)
 .SH DIAGNOSTICS
 The routines
 .IR getpwent ,
 .SH DIAGNOSTICS
 The routines
 .IR getpwent ,
@@ -143,27 +117,11 @@ and
 .I setpwent
 return 0 on failure and 1 on success.
 .I Endpwent
 .I setpwent
 return 0 on failure and 1 on success.
 .I Endpwent
-and
-.I setpwfile
-have no return value.
+has no return value.
 .SH BUGS
 All information is contained in a static buffer which is overwritten
 .SH BUGS
 All information is contained in a static buffer which is overwritten
-by each new call.  It must be copied elsewhere to be retained.
-.PP
-Intermixing calls to
-.IR getpwent
-with calls to
-.I getpwnam
-or
-.IR getpwuid ,
-or intermixing calls to
-.I getpwnam
-and
-.IR getpwuid ,
-after using
-.I setpassent
-to require that file descriptors be left open, may result
-in undefined behavior.
+by each new call.
+It must be copied elsewhere to be retained.
 .PP
 The routines
 .IR getpwent ,
 .PP
 The routines
 .IR getpwent ,
@@ -173,3 +131,8 @@ and
 .IR setpwent
 are fairly useless in a networked environment and should be
 avoided, if possible.
 .IR setpwent
 are fairly useless in a networked environment and should be
 avoided, if possible.
+.SH COMPATIBILITY
+The historic function
+.IR setpwfile ,
+which allowed the specification of alternate password databases,
+has been deprecated and is no longer available.
index 15cea4b..797ea77 100644 (file)
@@ -6,60 +6,73 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getpwent.c 5.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)getpwent.c 5.15 (Berkeley) %G%";
 #endif /* LIBC_SCCS and not lint */
 
 #endif /* LIBC_SCCS and not lint */
 
-#include <sys/types.h>
-#include <sys/file.h>
-#include <stdio.h>
+#include <sys/param.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <ndbm.h>
 #include <pwd.h>
 #include <ndbm.h>
-
-static DBM *_pw_db;
-static FILE *_pw_fp;
-static struct passwd _pw_passwd;
-static int _pw_getfirstkey, _pw_stayopen;
-static char _pw_flag, *_pw_file = _PATH_PASSWD, _pw_master;
-
-#define        MAXLINELENGTH   1024
-static char line[MAXLINELENGTH];
+#include <unistd.h>
+#include <syslog.h>
+#include <utmp.h>
+#include <limits.h>
+
+static struct passwd _pw_passwd;       /* password structure */
+static DBM *_pw_db;                    /* password database */
+static int _pw_keynum;                 /* key counter */
+static int _pw_stayopen;               /* keep fd's open */
+static int _pw_euid;
+static __hashpw(), __initdb();
 
 struct passwd *
 getpwent()
 {
 
 struct passwd *
 getpwent()
 {
+       datum key;
+       int rval;
+       char bf[sizeof(_pw_keynum) + 1];
 
 
-       if (!_pw_fp && !start_pw(1))
+       if (!_pw_db && !__initdb())
                return((struct passwd *)NULL);
                return((struct passwd *)NULL);
-       if (!scanpw())
-               return((struct passwd *)NULL);
-       getpw();
-       return(&_pw_passwd);
+
+       ++_pw_keynum;
+       bf[0] = _PW_KEYBYNUM;
+       bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
+       key.dptr = bf;
+       key.dsize = sizeof(_pw_keynum) + 1;
+       rval = __hashpw(key);
+
+       /* Can't leave secure database open. */
+       if (!_pw_euid) {
+               (void)dbm_close(_pw_db);
+               _pw_db = (DBM *)NULL;
+       }
+       return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 struct passwd *
 }
 
 struct passwd *
-getpwnam(nam)
-       char *nam;
+getpwnam(name)
+       char *name;
 {
 {
-       int rval;
+       datum key;
+       int len, rval;
+       char bf[UT_NAMESIZE + 1];
 
 
-       if (!start_pw(0))
+       if (!_pw_db && !__initdb())
                return((struct passwd *)NULL);
                return((struct passwd *)NULL);
-       if (_pw_db) {
-               datum key;
 
 
-               key.dptr = nam;
-               key.dsize = strlen(nam);
-               rval = fetch_pw(key);
-       } else /* _pw_fp */
-               for (rval = 0; scanpw();)
-                       if (!strcmp(nam, _pw_passwd.pw_name)) {
-                               rval = 1;
-                               break;
-                       }
-       if (!_pw_stayopen)
-               endpwent();
-       if (rval)
-               getpw();
+       bf[0] = _PW_KEYBYNAME;
+       len = strlen(name);
+       bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
+       key.dptr = bf;
+       key.dsize = len + 1;
+       rval = __hashpw(key);
+
+       /* Can't leave secure database open. */
+       if (!_pw_stayopen || !_pw_euid) {
+               (void)dbm_close(_pw_db);
+               _pw_db = (DBM *)NULL;
+       }
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
@@ -67,173 +80,85 @@ struct passwd *
 getpwuid(uid)
        int uid;
 {
 getpwuid(uid)
        int uid;
 {
+       datum key;
        int rval;
        int rval;
+       char bf[sizeof(uid) + 1];
 
 
-       if (!start_pw(0))
+       if (!_pw_db && !__initdb())
                return((struct passwd *)NULL);
                return((struct passwd *)NULL);
-       if (_pw_db) {
-               datum key;
-
-               key.dptr = (char *)&uid;
-               key.dsize = sizeof(uid);
-               rval = fetch_pw(key);
-       } else /* _pw_fp */
-               for (rval = 0; scanpw();)
-                       if (_pw_passwd.pw_uid == uid) {
-                               rval = 1;
-                               break;
-                       }
-       if (!_pw_stayopen)
-               endpwent();
-       if (rval)
-               getpw();
-       return(rval ? &_pw_passwd : (struct passwd *)NULL);
-}
 
 
-static
-start_pw(want_fp)
-       char want_fp;           /* open _pw_fp also */
-{
-       char *p;
+       bf[0] = _PW_KEYBYUID;
+       bcopy(&uid, bf + 1, sizeof(uid));
+       key.dptr = bf;
+       key.dsize = sizeof(uid) + 1;
+       rval = __hashpw(key);
 
 
-       if (_pw_db) {
-               _pw_getfirstkey = 1;
-               if (!want_fp)
-                       return(1);
-       }
-       if (_pw_fp) {
-               rewind(_pw_fp);
-               return(1);
-       }
-       if (!_pw_db && (_pw_db = dbm_open(_pw_file, O_RDONLY, 0))) {
-               _pw_getfirstkey = 1;
-               if (!want_fp)
-                       return(1);
-       }
-       /*
-        * special case; if it's the official password file, look in
-        * the master password file, otherwise, look in the file itself.
-        */
-       p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
-       if (_pw_fp = fopen(p, "r")) {
-               _pw_master = 1;
-               return(1);
-       }
-       /*
-        * If we really want to set up _pw_fp, then try again
-        * with the old file.
-        */
-       if (want_fp && p != _pw_file && (_pw_fp = fopen(_pw_file, "r"))) {
-               _pw_master = 0;
-               return(1);
+       /* Can't leave secure database open. */
+       if (!_pw_stayopen || !_pw_euid) {
+               (void)dbm_close(_pw_db);
+               _pw_db = (DBM *)NULL;
        }
        }
-       return(0);
-}
-
-setpwent()
-{
-       return(setpassent(0));
+       return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 setpassent(stayopen)
        int stayopen;
 {
 }
 
 setpassent(stayopen)
        int stayopen;
 {
-       if (!start_pw(0))
-               return(0);
+       _pw_keynum = 0;
        _pw_stayopen = stayopen;
        return(1);
 }
 
        _pw_stayopen = stayopen;
        return(1);
 }
 
+setpwent()
+{
+       _pw_keynum = 0;
+       _pw_stayopen = 0;
+       return(1);
+}
+
 void
 endpwent()
 {
 void
 endpwent()
 {
+       _pw_keynum = 0;
        if (_pw_db) {
        if (_pw_db) {
-               dbm_close(_pw_db);
+               (void)dbm_close(_pw_db);
                _pw_db = (DBM *)NULL;
        }
                _pw_db = (DBM *)NULL;
        }
-       if (_pw_fp) {
-               (void)fclose(_pw_fp);
-               _pw_fp = (FILE *)NULL;
-       }
-}
-
-void
-setpwfile(file)
-       char *file;
-{
-       _pw_file = file;
 }
 
 static
 }
 
 static
-scanpw()
+__initdb()
 {
 {
-       register char *cp;
-       long atol();
-       char *bp;
-       char *fgets(), *strsep(), *index();
-
-       for (;;) {
-               if (!(fgets(line, sizeof(line), _pw_fp)))
-                       return(0);
-               bp = line;
-               /* skip lines that are too big */
-               if (!index(line, '\n')) {
-                       int ch;
+       static int warned;
+       char *p;
 
 
-                       while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
-                               ;
-                       continue;
-               }
-               _pw_passwd.pw_name = strsep(&bp, ":\n");
-               _pw_passwd.pw_passwd = strsep(&bp, ":\n");
-               if (!(cp = strsep(&bp, ":\n")))
-                       continue;
-               _pw_passwd.pw_uid = atoi(cp);
-               if (!(cp = strsep(&bp, ":\n")))
-                       continue;
-               _pw_passwd.pw_gid = atoi(cp);
-               if (_pw_master) {
-                       _pw_passwd.pw_class = strsep(&bp, ":\n");
-                       if (!(cp = strsep(&bp, ":\n")))
-                               continue;
-                       _pw_passwd.pw_change = atol(cp);
-                       if (!(cp = strsep(&bp, ":\n")))
-                               continue;
-                       _pw_passwd.pw_expire = atol(cp);
-               }
-               _pw_passwd.pw_gecos = strsep(&bp, ":\n");
-               _pw_passwd.pw_dir = strsep(&bp, ":\n");
-               _pw_passwd.pw_shell = strsep(&bp, ":\n");
-               if (!_pw_passwd.pw_shell)
-                       continue;
+       p = (_pw_euid = geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
+       if (_pw_db = dbm_open(p, O_RDONLY, 0))
                return(1);
                return(1);
+       if (!warned) {
+               openlog("getpwent", LOG_CONS|LOG_PERROR);
+               syslog(LOG_ALERT, "%s: %m", p);
+               closelog();
+               warned = 1;
        }
        }
-       /* NOTREACHED */
+       return(0);
 }
 
 static
 }
 
 static
-fetch_pw(key)
+__hashpw(key)
        datum key;
 {
        register char *p, *t;
        datum key;
 {
        register char *p, *t;
+       static u_int max;
+       static char *line;
+       datum dp;
 
 
-       /*
-        * the .dir file is LOCK_EX locked by programs that are
-        * renaming the various password files.
-        */
-       if (flock(dbm_dirfno(_pw_db), LOCK_SH))
+       dp = dbm_fetch(_pw_db, key);
+       if (!(p = dp.dptr))
                return(0);
                return(0);
-       if (!key.dptr)
-               if (_pw_getfirstkey) {
-                       _pw_getfirstkey = 0;
-                       key = dbm_firstkey(_pw_db);
-               } else
-                       key = dbm_nextkey(_pw_db);
-       if (key.dptr)
-               key = dbm_fetch(_pw_db, key);
-       (void)flock(dbm_dirfno(_pw_db), LOCK_UN);
-       if (!(p = key.dptr))
+       if (dp.dsize > max && !(line = (char *)realloc(line, max += 1024)))
                return(0);
                return(0);
+
        t = line;
 #define        EXPAND(e)       e = t; while (*t++ = *p++);
        EXPAND(_pw_passwd.pw_name);
        t = line;
 #define        EXPAND(e)       e = t; while (*t++ = *p++);
        EXPAND(_pw_passwd.pw_name);
@@ -250,41 +175,5 @@ fetch_pw(key)
        EXPAND(_pw_passwd.pw_shell);
        bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
        p += sizeof(time_t);
        EXPAND(_pw_passwd.pw_shell);
        bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
        p += sizeof(time_t);
-       _pw_flag = *p;
        return(1);
 }
        return(1);
 }
-
-#define        _MAX_PASSWD_SIZE        50
-static char pwbuf[_MAX_PASSWD_SIZE];
-
-static
-getpw()
-{
-       long pos, atol();
-       int fd, n;
-       char *p;
-       off_t lseek();
-
-       if (geteuid())
-               return;
-       /*
-        * special case; if it's the official password file, look in
-        * the master password file, otherwise, look in the file itself.
-        */
-       p = strcmp(_pw_file, _PATH_PASSWD) ? _pw_file : _PATH_MASTERPASSWD;
-       if ((fd = open(p, O_RDONLY, 0)) < 0)
-               return;
-       pos = atol(_pw_passwd.pw_passwd);
-       if (lseek(fd, pos, L_SET) != pos)
-               goto bad;
-       if ((n = read(fd, pwbuf, sizeof(pwbuf) - 1)) < 0)
-               goto bad;
-       pwbuf[n] = '\0';
-       for (p = pwbuf; *p; ++p)
-               if (*p == ':') {
-                       *p = '\0';
-                       _pw_passwd.pw_passwd = pwbuf;
-                       break;
-               }
-bad:   (void)close(fd);
-}