4.4BSD snapshot (revision 8.1); add 1993 to copyright
[unix-history] / usr / src / usr.sbin / vipw / vipw.c
index 9cddf08..c30bbd6 100644 (file)
 /*
 /*
- * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1987, 1993
+ *     The 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.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1987 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)vipw.c     5.5 (Berkeley) %G%";
+static char sccsid[] = "@(#)vipw.c     8.1 (Berkeley) %G%";
 #endif /* not lint */
 
 #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 <pwd.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
 
 
-/*
- * Password file editor with locking.
- */
-static char    *passwd = "/etc/passwd", buf[BUFSIZ];
+char *progname = "vipw";
+char *tempname;
 
 main()
 {
 
 main()
 {
-       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) {
-                       fputs("vipw: password file busy.\n", stderr);
-                       exit(1);
-               }
-               fputs("vipw: ", stderr);
-               perror(temp);
-               exit(1);
-       }
-       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;
-       }
-       if (fstat(fd_temp, &s1)) {
-               perror("vipw: fstat");
-               goto bad;
-       }
-       (void)close(fd_temp);
-
-       if (!(editor = getenv("EDITOR")))
-               editor = "vi";
-       (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 (!(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;
-               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);
-               }
-               if (!(cp = token(CHN)) || !*cp)         /* gid */
-                       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);
-               }
-               (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);
+       register int pfd, tfd;
+       struct stat begin, end;
+
+       pw_init();
+       pfd = pw_lock();
+       tfd = pw_tmp();
+       copyfile(pfd, tfd);
+       (void)close(tfd);
+
+       for (;;) {
+               if (stat(tempname, &begin))
+                       pw_error(tempname, 1, 1);
+               pw_edit(0);
+               if (stat(tempname, &end))
+                       pw_error(tempname, 1, 1);
+               if (begin.st_mtime == end.st_mtime) {
+                       (void)fprintf(stderr, "vipw: no changes made\n");
+                       pw_error((char *)NULL, 0, 0);
                }
                }
+               if (pw_mkdb())
+                       break;
+               pw_prompt();
        }
        }
-       return(1);
-}
-
-static
-makedb(file)
-       char *file;
-{
-       int status, pid, w;
-
-       if (!(pid = vfork())) {
-               execl("/etc/mkpasswd", "mkpasswd", file, 0);
-               _exit(127);
-       }
-       while ((w = wait(&status)) != pid && w != -1);
-       if (w == -1 || status)
-               return(-1);
-       return(0);
+       exit(0);
 }
 
 }
 
-static char *
-token(bfr)
-       char *bfr;
+copyfile(from, to)
+       register int from, to;
 {
 {
-       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 */
+       register int nr, nw, off;
+       char buf[8*1024];
+       
+       while ((nr = read(from, buf, sizeof(buf))) > 0)
+               for (off = 0; off < nr; nr -= nw, off += nw)
+                       if ((nw = write(to, buf + off, nr)) < 0)
+                               pw_error(tempname, 1, 1);
+       if (nr < 0)
+               pw_error(_PATH_MASTERPASSWD, 1, 1);
 }
 }