minor cleanups for cray
[unix-history] / usr / src / usr.sbin / vipw / vipw.c
index 850be7b..9cddf08 100644 (file)
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-static char sccsid[] = "@(#)vipw.c     4.5 (Berkeley) %G%";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1987 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
 
 
+#ifndef lint
+static char sccsid[] = "@(#)vipw.c     5.5 (Berkeley) %G%";
+#endif /* not lint */
+
+#include <machine/machparam.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/signal.h>
 #include <sys/file.h>
 #include <sys/file.h>
-
 #include <stdio.h>
 #include <errno.h>
 #include <stdio.h>
 #include <errno.h>
-#include <signal.h>
 
 /*
  * Password file editor with locking.
  */
 
 /*
  * Password file editor with locking.
  */
-char   temp[] = "/etc/ptmp";
-char   temp_pag[] = "/etc/ptmp.pag";
-char   temp_dir[] = "/etc/ptmp.dir";
-char   passwd[] = "/etc/passwd";
-char   passwd_pag[] = "/etc/passwd.pag";
-char   passwd_dir[] = "/etc/passwd.dir";
-char   buf[BUFSIZ];
-char   *getenv();
-char   *index();
-extern int errno;
-
-main(argc, argv)
-       char *argv[];
+static char    *passwd = "/etc/passwd", buf[BUFSIZ];
+
+main()
 {
 {
-       int fd;
-       FILE *ft, *fp;
-       char *editor;
-
-       signal(SIGHUP, SIG_IGN);
-       signal(SIGINT, SIG_IGN);
-       signal(SIGQUIT, SIG_IGN);
-       signal(SIGTSTP, SIG_IGN);
-       setbuf(stderr, NULL);
-       umask(0);
-       fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644);
-       if (fd < 0) {
+       register int n, fd_passwd, fd_temp;
+       static char *temp = "/etc/ptmp";
+       struct stat s1, s2;
+       char *editor, *getenv();
+
+       (void)signal(SIGHUP, SIG_IGN);
+       (void)signal(SIGINT, SIG_IGN);
+       (void)signal(SIGQUIT, SIG_IGN);
+
+       setbuf(stderr, (char *)NULL);
+       (void)umask(0);
+
+       if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
+               fputs("vipw: ", stderr);
+               perror(passwd);
+               exit(1);
+       }
+       if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
+               extern int errno;
+
                if (errno == EEXIST) {
                if (errno == EEXIST) {
-                       fprintf(stderr, "vipw: password file busy\n");
+                       fputs("vipw: password file busy.\n", stderr);
                        exit(1);
                }
                        exit(1);
                }
-               fprintf(stderr, "vipw: "); perror(temp);
+               fputs("vipw: ", stderr);
+               perror(temp);
                exit(1);
        }
                exit(1);
        }
-       ft = fdopen(fd, "w");
-       if (ft == NULL) {
-               fprintf(stderr, "vipw: "); perror(temp);
+       while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
+               if (write(fd_temp, buf, n) != n) {
+                       perror("vipw: write");
+                       goto bad;
+               }
+       if (n == -1) {
+               perror("vipw: read");
+               goto bad;
+       }
+       (void)close(fd_passwd);
+       if (fsync(fd_temp)) {
+               perror("vipw: fsync");
                goto bad;
        }
                goto bad;
        }
-       fp = fopen(passwd, "r");
-       if (fp == NULL) {
-               fprintf(stderr, "vipw: "); perror(passwd);
+       if (fstat(fd_temp, &s1)) {
+               perror("vipw: fstat");
                goto bad;
        }
                goto bad;
        }
-       while (fgets(buf, sizeof (buf) - 1, fp) != NULL)
-               fputs(buf, ft);
-       fclose(ft); fclose(fp);
-       editor = getenv("EDITOR");
-       if (editor == 0)
+       (void)close(fd_temp);
+
+       if (!(editor = getenv("EDITOR")))
                editor = "vi";
                editor = "vi";
-       sprintf(buf, "%s %s", editor, temp);
-       if (system(buf) == 0) {
-               struct stat sbuf;
-               int ok;
-
-               /* sanity checks */
-               if (stat(temp, &sbuf) < 0) {
-                       fprintf(stderr,
-                           "vipw: can't stat temp file, %s unchanged\n",
-                           passwd);
-                       goto bad;
+       (void)sprintf(buf, "%s %s", editor, temp);
+       if (system(buf)) {
+               perror("vipw: system");
+               goto bad;
+       }
+
+       if (!freopen(temp, "r", stdin)) {
+               fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd);
+               goto bad;
+       }
+       if (fstat(fileno(stdin), &s2)) {
+               fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd);
+               goto bad;
+       }
+       if (s1.st_mtime == s2.st_mtime) {
+               fprintf(stderr, "vipw: %s unchanged.\n", passwd);
+               goto bad;
+       }
+       if (!s2.st_size) {
+               fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd);
+               goto bad;
+       }
+       if (check()) {
+               static char     *temp_pag = "/etc/ptmp.pag",
+                               *temp_dir = "/etc/ptmp.dir",
+                               *passwd_pag = "/etc/passwd.pag",
+                               *passwd_dir = "/etc/passwd.dir";
+
+               if (makedb(temp) < 0)
+                       fputs("vipw: mkpasswd failed.\n", stderr);
+               else if (rename(temp_pag, passwd_pag) < 0) {
+                       fprintf(stderr, "vipw: ");
+                       perror(temp_pag);
+               }
+               else if (rename(temp_dir, passwd_dir) < 0) {
+                       fprintf(stderr, "vipw: ");
+                       perror(temp_dir);
+               }
+               else if (rename(temp, passwd) < 0) {
+                       fprintf(stderr, "vipw: ");
+                       perror("rename");
+               }
+               else
+                       exit(0);
+               (void)unlink(temp_pag);
+               (void)unlink(temp_dir);
+       }
+bad:   (void)unlink(temp);
+       exit(1);
+}
+
+#define        CHN     ((char *)NULL)
+static
+check()
+{
+       register char *cp, *sh;
+       register long id;
+       register int root;
+       long atol();
+       char *token(), *getusershell();
+
+       for (root = 0; gets(buf); root = 0) {
+               if (!*buf) {
+                       fputs("vipw: empty line.\n", stderr);
+                       continue;
                }
                }
-               if (sbuf.st_size == 0) {
-                       fprintf(stderr, "vipw: bad temp file, %s unchanged\n",
-                           passwd);
+               if (!(cp = token(buf)) || !*cp)         /* login */
+                       goto bad;
+               if (!strcmp(cp, "root"))
+                       root = 1;
+               (void)token(CHN);                       /* passwd */
+               if (!(cp = token(CHN)) || !*cp)         /* uid */
                        goto bad;
                        goto bad;
+               id = atol(cp);
+               if (root && id) {
+                       fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd);
+                       return(0);
+               }
+               if (id > USHRT_MAX) {
+                       fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd);
+                       return(0);
                }
                }
-               ft = fopen(temp, "r");
-               if (ft == NULL) {
-                       fprintf(stderr,
-                           "vipw: can't reopen temp file, %s unchanged\n",
-                           passwd);
+               if (!(cp = token(CHN)) || !*cp)         /* gid */
                        goto bad;
                        goto bad;
+               id = atol(cp);
+               if (id > USHRT_MAX) {
+                       fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd);
+                       return(0);
                }
                }
-               ok = 0;
-               while (fgets(buf, sizeof (buf) - 1, ft) != NULL) {
-                       register char *cp;
-
-                       cp = index(buf, '\n');
-                       if (cp == 0)
-                               continue;
-                       *cp = '\0';
-                       cp = index(buf, ':');
-                       if (cp == 0)
-                               continue;
-                       *cp = '\0';
-                       if (strcmp(buf, "root"))
-                               continue;
-                       /* password */
-                       cp = index(cp + 1, ':');
-                       if (cp == 0)
-                               break;
-                       /* uid */
-                       if (atoi(cp + 1) != 0)
-                               break;
-                       cp = index(cp + 1, ':');
-                       if (cp == 0)
-                               break;
-                       /* gid */
-                       cp = index(cp + 1, ':');
-                       if (cp == 0)
-                               break;
-                       /* gecos */
-                       cp = index(cp + 1, ':');
-                       if (cp == 0)
-                               break;
-                       /* login directory */
-                       if (strncmp(++cp, "/:"))
-                               break;
-                       cp += 2;
-                       if (*cp && strcmp(cp, "/bin/sh") &&
-                           strcmp(cp, "/bin/csh"))
-                               break;
-                       ok++;
+               (void)token(CHN);                       /* gcos */
+               if (!token(CHN))                        /* home directory */
+                       goto bad;
+               if (!(cp = token(CHN)))                 /* shell */
+                       goto bad;
+               if (root && *cp)                        /* empty == /bin/sh */
+                       for (;;)
+                               if (!(sh = getusershell())) {
+                                       fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd);
+                                       return(0);
+                               }
+                               else if (!strcmp(cp, sh))
+                                       break;
+               if (token(CHN)) {                       /* too many fields */
+bad:                   fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd);
+                       return(0);
                }
                }
-               fclose(ft);
-               if (ok) {
-                       if (makedb(temp) < 0)
-                               fprintf(stderr, "vipw: mkpasswd failed\n");
-                       else if (rename(temp_pag, passwd_pag) < 0)
-                               fprintf(stderr, "vipw: "), perror(temp_pag);
-                       else if (rename(temp_dir, passwd_dir) < 0)
-                               fprintf(stderr, "vipw: "), perror(temp_dir);
-                       else if (rename(temp, passwd) < 0)
-                               fprintf(stderr, "vipw: "), perror("rename");
-                       else
-                               exit(0);
-               } else
-                       fprintf(stderr,
-                           "vipw: you mangled the temp file, %s unchanged\n",
-                           passwd);
        }
        }
-bad:
-       unlink(temp_pag);
-       unlink(temp_dir);
-       unlink(temp);
-       exit(1);
+       return(1);
 }
 
 }
 
+static
 makedb(file)
        char *file;
 {
        int status, pid, w;
 
 makedb(file)
        char *file;
 {
        int status, pid, w;
 
-       if ((pid = vfork()) == 0) {
+       if (!(pid = vfork())) {
                execl("/etc/mkpasswd", "mkpasswd", file, 0);
                _exit(127);
        }
                execl("/etc/mkpasswd", "mkpasswd", file, 0);
                _exit(127);
        }
-       while ((w = wait(&status)) != pid && w != -1)
-               ;
-       if (w == -1 || status != 0)
-               status = -1;
-       return(status);
+       while ((w = wait(&status)) != pid && w != -1);
+       if (w == -1 || status)
+               return(-1);
+       return(0);
+}
+
+static char *
+token(bfr)
+       char *bfr;
+{
+       static char *cp;
+       char *start;
+
+       if (bfr)                        /* re-init string */
+               cp = bfr;
+       else if (!cp)                   /* check if hit EOS last time */
+               return(CHN);
+       else if (!bfr)                  /* start at next char after ':' */
+               ++cp;
+       for (start = cp;; ++cp)
+               if (!*cp) {             /* found EOS; mark it for next time */
+                       cp = CHN;
+                       break;
+               }
+               else if (*cp == ':') {  /* found ':'; end token */
+                       *cp = '\0';
+                       break;
+               }
+       return(start);                  /* return token */
 }
 }