BSD 4_3_Net_2 release
[unix-history] / usr / src / lib / libc / gen / getpwent.c
index acdd908..4d65063 100644 (file)
  * Copyright (c) 1988 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1988 The Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement:  ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getpwent.c 5.14 (Berkeley) 6/1/90";
+static char sccsid[] = "@(#)getpwent.c 5.21 (Berkeley) 3/14/91";
 #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 <db.h>
+#include <syslog.h>
 #include <pwd.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 <utmp.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+static struct passwd _pw_passwd;       /* password structure */
+static DB *_pw_db;                     /* password database */
+static int _pw_keynum;                 /* key counter */
+static int _pw_stayopen;               /* keep fd's open */
+static int __hashpw(), __initdb();
 
 struct passwd *
 getpwent()
 {
 
 struct passwd *
 getpwent()
 {
+       DBT key;
+       char bf[sizeof(_pw_keynum) + 1];
 
 
-       if (!_pw_fp && !start_pw(1))
-               return((struct passwd *)NULL);
-       if (!scanpw())
+       if (!_pw_db && !__initdb())
                return((struct passwd *)NULL);
                return((struct passwd *)NULL);
-       getpw();
-       return(&_pw_passwd);
+
+       ++_pw_keynum;
+       bf[0] = _PW_KEYBYNUM;
+       bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
+       key.data = (u_char *)bf;
+       key.size = sizeof(_pw_keynum) + 1;
+       return(__hashpw(&key) ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 struct passwd *
 }
 
 struct passwd *
-getpwnam(nam)
-       char *nam;
+getpwnam(name)
+       const char *name;
 {
 {
-       int rval;
+       DBT 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.data = (u_char *)bf;
+       key.size = len + 1;
+       rval = __hashpw(&key);
+
+       if (!_pw_stayopen) {
+               (void)(_pw_db->close)(_pw_db);
+               _pw_db = (DB *)NULL;
+       }
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 struct passwd *
        return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 struct passwd *
+#ifdef __STDC__
+getpwuid(uid_t uid)
+#else
 getpwuid(uid)
        int uid;
 getpwuid(uid)
        int uid;
+#endif
 {
 {
-       int rval;
+       DBT key;
+       int keyuid, rval;
+       char bf[sizeof(keyuid) + 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;
+       keyuid = uid;
+       bcopy(&keyuid, bf + 1, sizeof(keyuid));
+       key.data = (u_char *)bf;
+       key.size = sizeof(keyuid) + 1;
+       rval = __hashpw(&key);
 
 
-       if (_pw_db) {
-               _pw_getfirstkey = 1;
-               if (!want_fp)
-                       return(1);
+       if (!_pw_stayopen) {
+               (void)(_pw_db->close)(_pw_db);
+               _pw_db = (DB *)NULL;
        }
        }
-       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);
-       }
-       return(0);
-}
-
-setpwent()
-{
-       return(setpassent(0));
+       return(rval ? &_pw_passwd : (struct passwd *)NULL);
 }
 
 }
 
+int
 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);
 }
 
-void
-endpwent()
+int
+setpwent()
 {
 {
-       if (_pw_db) {
-               dbm_close(_pw_db);
-               _pw_db = (DBM *)NULL;
-       }
-       if (_pw_fp) {
-               (void)fclose(_pw_fp);
-               _pw_fp = (FILE *)NULL;
-       }
+       _pw_keynum = 0;
+       _pw_stayopen = 0;
+       return(1);
 }
 
 void
 }
 
 void
-setpwfile(file)
-       char *file;
+endpwent()
 {
 {
-       _pw_file = file;
+       _pw_keynum = 0;
+       if (_pw_db) {
+               (void)(_pw_db->close)(_pw_db);
+               _pw_db = (DB *)NULL;
+       }
 }
 
 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 = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
+       _pw_db = hash_open(p, O_RDONLY, 0, NULL);
+       if (_pw_db)
                return(1);
                return(1);
-       }
-       /* NOTREACHED */
+       if (!warned)
+               syslog(LOG_ERR, "%s: %m", p);
+       return(0);
 }
 
 static
 }
 
 static
-fetch_pw(key)
-       datum key;
+__hashpw(key)
+       DBT *key;
 {
        register char *p, *t;
 {
        register char *p, *t;
+       static u_int max;
+       static char *line;
+       DBT data;
 
 
-       /*
-        * the .dir file is LOCK_EX locked by programs that are
-        * renaming the various password files.
-        */
-       if (flock(dbm_dirfno(_pw_db), LOCK_SH))
+       if ((_pw_db->get)(_pw_db, key, &data, 0))
                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))
+       p = (char *)data.data;
+       if (data.size > max && !(line = 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);
@@ -262,41 +197,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);
-}