]> git.cameronkatri.com Git - pw-darwin.git/blobdiff - libc/gen/pw_scan.c
Set the pw_class field to NULL when scanning the non-master passwd file.
[pw-darwin.git] / libc / gen / pw_scan.c
index 9d280f7ded8b3323a9f68f70b3e24ed24a793807..01146e9111d102670774dd2f3a3181599ddcb665 100644 (file)
@@ -1,4 +1,6 @@
 /*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
  * Copyright (c) 1990, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
  * 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
+ * 3. 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.
  *
@@ -31,9 +29,9 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static char sccsid[] = "@(#)pw_scan.c  8.3 (Berkeley) 4/2/94";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__SCCSID("@(#)pw_scan.c        8.3 (Berkeley) 4/2/94");
+__FBSDID("$FreeBSD$");
 
 /*
  * This module is used to "verify" password entries by chpass(1) and
@@ -43,98 +41,170 @@ static char sccsid[] = "@(#)pw_scan.c      8.3 (Berkeley) 4/2/94";
 #include <sys/param.h>
 
 #include <err.h>
-#include <fcntl.h>
-#include <pwd.h>
 #include <errno.h>
-#include <stdio.h>
+#include <pwd.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "pw_scan.h"
 
+/*
+ * Some software assumes that IDs are short.  We should emit warnings
+ * for id's which cannot be stored in a short, but we are more liberal
+ * by default, warning for IDs greater than USHRT_MAX.
+ *
+ * If pw_big_ids_warning is -1 on entry to pw_scan(), it will be set based
+ * on the existence of PW_SCAN_BIG_IDS in the environment.
+ *
+ * It is believed all baseline system software that can not handle the
+ * normal ID sizes is now gone so pw_big_ids_warning is disabled for now.
+ * But the code has been left in place in case end-users want to re-enable
+ * it and/or for the next time the ID sizes get bigger but pieces of the
+ * system lag behind.
+ */
+static int     pw_big_ids_warning = 0;
+
 int
-pw_scan(bp, pw)
-       char *bp;
-       struct passwd *pw;
+__pw_scan(char *bp, struct passwd *pw, int flags)
 {
-       long id;
+       uid_t id;
        int root;
-       char *p, *sh;
+       char *ep, *p, *sh;
+       unsigned long temp;
+
+       if (pw_big_ids_warning == -1)
+               pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0;
 
        pw->pw_fields = 0;
        if (!(pw->pw_name = strsep(&bp, ":")))          /* login */
                goto fmt;
        root = !strcmp(pw->pw_name, "root");
-       if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
+       if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
                pw->pw_fields |= _PWF_NAME;
 
        if (!(pw->pw_passwd = strsep(&bp, ":")))        /* passwd */
                goto fmt;
-       if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD;
+       if (pw->pw_passwd[0])
+               pw->pw_fields |= _PWF_PASSWD;
 
        if (!(p = strsep(&bp, ":")))                    /* uid */
                goto fmt;
-       if(p[0]) pw->pw_fields |= _PWF_UID;
-       id = atol(p);
-       if (root && id) {
-               warnx("root uid should be 0");
+       if (p[0])
+               pw->pw_fields |= _PWF_UID;
+       else {
+               if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+                       if (flags & _PWSCAN_WARN)
+                               warnx("no uid for user %s", pw->pw_name);
+                       return (0);
+               }
+       }
+       errno = 0;
+       temp = strtoul(p, &ep, 10);
+       if ((temp == ULONG_MAX && errno == ERANGE) || temp > UID_MAX) {
+               if (flags & _PWSCAN_WARN)
+                       warnx("%s > max uid value (%u)", p, UID_MAX);
                return (0);
        }
-       if (id > USHRT_MAX) {
-               warnx("%s > max uid value (%d)", p, USHRT_MAX);
+       id = temp;
+       if (*ep != '\0') {
+               if (flags & _PWSCAN_WARN)
+                       warnx("%s uid is incorrect", p);
                return (0);
        }
+       if (root && id) {
+               if (flags & _PWSCAN_WARN)
+                       warnx("root uid should be 0");
+               return (0);
+       }
+       if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+               warnx("%s > recommended max uid value (%u)", p, USHRT_MAX);
+               /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */
+       }
        pw->pw_uid = id;
 
        if (!(p = strsep(&bp, ":")))                    /* gid */
                goto fmt;
-       if(p[0]) pw->pw_fields |= _PWF_GID;
-       id = atol(p);
-       if (id > USHRT_MAX) {
-               warnx("%s > max gid value (%d)", p, USHRT_MAX);
+       if (p[0])
+               pw->pw_fields |= _PWF_GID;
+       else {
+               if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') {
+                       if (flags & _PWSCAN_WARN)
+                               warnx("no gid for user %s", pw->pw_name);
+                       return (0);
+               }
+       }
+       errno = 0;
+       temp = strtoul(p, &ep, 10);
+       if ((temp == ULONG_MAX && errno == ERANGE) || temp > GID_MAX) {
+               if (flags & _PWSCAN_WARN)
+                       warnx("%s > max gid value (%u)", p, GID_MAX);
                return (0);
        }
+       id = temp;
+       if (*ep != '\0') {
+               if (flags & _PWSCAN_WARN)
+                       warnx("%s gid is incorrect", p);
+               return (0);
+       }
+       if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) {
+               warnx("%s > recommended max gid value (%u)", p, USHRT_MAX);
+               /* return (0); This should not be fatal! */
+       }
        pw->pw_gid = id;
 
-       pw->pw_class = strsep(&bp, ":");                /* class */
-       if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
-
-       if (!(p = strsep(&bp, ":")))                    /* change */
-               goto fmt;
-       if(p[0]) pw->pw_fields |= _PWF_CHANGE;
-       pw->pw_change = atol(p);
-
-       if (!(p = strsep(&bp, ":")))                    /* expire */
-               goto fmt;
-       if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
-       pw->pw_expire = atol(p);
-
+       if (flags & _PWSCAN_MASTER ) {
+               if (!(pw->pw_class = strsep(&bp, ":"))) /* class */
+                       goto fmt;
+               if (pw->pw_class[0])
+                       pw->pw_fields |= _PWF_CLASS;
+               
+               if (!(p = strsep(&bp, ":")))            /* change */
+                       goto fmt;
+               if (p[0])
+                       pw->pw_fields |= _PWF_CHANGE;
+               pw->pw_change = atol(p);
+               
+               if (!(p = strsep(&bp, ":")))            /* expire */
+                       goto fmt;
+               if (p[0])
+                       pw->pw_fields |= _PWF_EXPIRE;
+               pw->pw_expire = atol(p);
+       } else
+               pw->pw_class = NULL;
        if (!(pw->pw_gecos = strsep(&bp, ":")))         /* gecos */
                goto fmt;
-       if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS;
+       if (pw->pw_gecos[0])
+               pw->pw_fields |= _PWF_GECOS;
 
-       if (!(pw->pw_dir = strsep(&bp, ":")))                   /* directory */
+       if (!(pw->pw_dir = strsep(&bp, ":")))           /* directory */
                goto fmt;
-       if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR;
+       if (pw->pw_dir[0])
+               pw->pw_fields |= _PWF_DIR;
 
        if (!(pw->pw_shell = strsep(&bp, ":")))         /* shell */
                goto fmt;
 
        p = pw->pw_shell;
-       if (root && *p)                                 /* empty == /bin/sh */
+       if (root && *p) {                               /* empty == /bin/sh */
                for (setusershell();;) {
                        if (!(sh = getusershell())) {
-                               warnx("warning, unknown root shell");
+                               if (flags & _PWSCAN_WARN)
+                                       warnx("warning, unknown root shell");
                                break;
                        }
                        if (!strcmp(p, sh))
                                break;
                }
-       if(p[0]) pw->pw_fields |= _PWF_SHELL;
+               endusershell();
+       }
+       if (p[0])
+               pw->pw_fields |= _PWF_SHELL;
 
-       if (p = strsep(&bp, ":")) {                     /* too many */
-fmt:           warnx("corrupted entry");
+       if ((p = strsep(&bp, ":"))) {                   /* too many */
+fmt:           
+               if (flags & _PWSCAN_WARN)
+                       warnx("corrupted entry");
                return (0);
        }
        return (1);