rework the password subsystem
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 13:37:20 +0000 (05:37 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Wed, 13 Feb 1991 13:37:20 +0000 (05:37 -0800)
SCCS-vsn: usr.sbin/vipw/vipw.c 5.15
SCCS-vsn: usr.sbin/vipw/vipw.8 6.6
SCCS-vsn: usr.sbin/vipw/Makefile 5.4

usr/src/usr.sbin/vipw/Makefile
usr/src/usr.sbin/vipw/vipw.8
usr/src/usr.sbin/vipw/vipw.c

index e18c679..f2efc42 100644 (file)
@@ -1,6 +1,7 @@
-#      @(#)Makefile    5.3 (Berkeley) %G%
+#      @(#)Makefile    5.4 (Berkeley) %G%
 
 PROG=  vipw
 
 PROG=  vipw
+SRCS=  pw_util.c vipw.c
 MAN8=  vipw.0
 
 .include <bsd.prog.mk>
 MAN8=  vipw.0
 
 .include <bsd.prog.mk>
index 4a6b6f0..71728a1 100644 (file)
@@ -3,7 +3,7 @@
 .\"
 .\" %sccs.include.redist.man%
 .\"
 .\"
 .\" %sccs.include.redist.man%
 .\"
-.\"    @(#)vipw.8      6.5 (Berkeley) %G%
+.\"    @(#)vipw.8      6.6 (Berkeley) %G%
 .\"
 .TH VIPW 8 ""
 .UC 4
 .\"
 .TH VIPW 8 ""
 .UC 4
@@ -13,31 +13,43 @@ vipw \- edit the password file
 .B vipw
 .SH DESCRIPTION
 .I Vipw
 .B vipw
 .SH DESCRIPTION
 .I Vipw
-edits the password file while setting the appropriate locks,
-and does any necessary processing after the password file is unlocked.
-If the password file is already being edited, then you will be told
-to try again later.
-The 
-.I vi
-editor will be used unless the environment variable EDITOR indicates
-an alternate editor.  
+locks the password file and makes a temporary copy of it for editing.
+The user's editor (or by default, 
+.IR vi (1))
+is run on the copied file.
 .PP
 .PP
-.I Vipw
-performs a number of consistency checks on the password entries,
-and will not allow a password file with a ``mangled'' entry to be
-installed.
-If
+Once the file has been edited,
 .I vipw
 .I vipw
-rejects the new password file, the user is prompted to re-enter
-the edit session.
+runs the program
+.IR pwd_mkdb (8).
+.I Pwd_mkdb
+performs a number of consistency checks on the password entries, and will
+not allow a password file with a ``mangled'' entry to be installed.
+If
+.I pwd_mkdb
+rejects the new file, the user is prompted to re-enter the edit session.
+Once the file is found to be satisfactory,
+.I pwd_mkdb
+installs it as the new password file.
 .PP
 .PP
-Once the information has been verified,
-.I vipw
-uses
-.IR mkpasswd (8)
-to update the user database.  This is run in the background, and,
-at very large sites could take several minutes.  Until this update
-is completed, the password file is unavailable for other updates
-and the new information will not be available to programs.
+If the password file is already locked, you will be told to try again
+later.
+.SH FILES
+/var/db/pwd.db                 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
+.br
+/etc/vipw.XXXXXX               Temporary copy of the password file
+.SH ENVIRONMENT
+.TP
+EDITOR
+The editor used; the default is
+.IR vi (1).
+Any user specified editor is expected to take the file name it will
+edit as its first argument.
 .SH SEE ALSO
 .SH SEE ALSO
-chpass(1), passwd(1), passwd(5), adduser(8), mkpasswd(8)
+chpass(1), passwd(1), passwd(5), adduser(8), pwd_mkdb(8)
index 63812e1..98d8d4f 100644 (file)
@@ -12,264 +12,60 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)vipw.c     5.14 (Berkeley) %G%";
+static char sccsid[] = "@(#)vipw.c     5.15 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/param.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/signal.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <errno.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <pwd.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <string.h>
 
-char *passwd, *temp;
+char *progname = "vipw";
+char *tempname;
 
 main()
 {
 
 main()
 {
-       extern int errno;
-       register int n, fd_passwd, fd;
-       struct rlimit rlim;
-       struct stat s1, s2;
-       FILE *tfp;
-       char *fend, *tend;
-       char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
+       register int pfd, tfd;
+       struct stat begin, end;
 
 
-       (void)signal(SIGHUP, SIG_IGN);
-       (void)signal(SIGINT, SIG_IGN);
-       (void)signal(SIGQUIT, SIG_IGN);
-       (void)signal(SIGTSTP, SIG_IGN);
+       pw_init();
+       pfd = pw_lock();
+       tfd = pw_tmp();
+       copyfile(pfd, tfd);
+       (void)close(tfd);
 
 
-       rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
-       (void)setrlimit(RLIMIT_CPU, &rlim);
-       (void)setrlimit(RLIMIT_FSIZE, &rlim);
-
-       (void)umask(0);
-
-       temp = _PATH_PTMP;
-       if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
-               if (errno == EEXIST)
-                       (void)fprintf(stderr, "vipw: password file busy.\n");
-               else
-                       (void)fprintf(stderr,
-                           "vipw: %s: %s\n", temp, strerror(errno));
-               exit(1);
-       }
-       passwd = _PATH_MASTERPASSWD;
-       if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
-               (void)fprintf(stderr, "vipw: %s: %s\n", passwd,
-                   strerror(errno));
-               exit(1);
-       }
-       while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
-               if (write(fd, buf, n) != n)
-                       goto syserr;
-
-       if (n == -1 || close(fd_passwd)) {
-syserr:                (void)fprintf(stderr, "vipw: %s: %s; ",
-                   passwd, strerror(errno));
-               stop(1);
-       }
-
-       (void)fstat(fd, &s1);
-       (void)close(fd);
        for (;;) {
        for (;;) {
-               if (edit()) {
-                       (void)fprintf(stderr, "vipw: edit failed; ");
-                       stop(1);
-               }
-               /*
-                * close and re-open the file each time we edit it; some
-                * editors create a new physical file on each edit session.
-                */
-               if (!(tfp = fopen(temp, "r"))) {
-                       (void)fprintf(stderr, "vipw: %s: %s; ",
-                           temp, strerror(errno));
-                       stop(1);
+               if (stat(tempname, &begin))
+                       pw_error(tempname, 1, 1);
+               if (pw_edit(0)) {
+                       (void)fprintf(stderr, "vipw: edit failed\n");
+                       pw_error((char *)NULL, 0, 1);
                }
                }
-               (void)fstat(fileno(tfp), &s2);
-               if (s1.st_mtime == s2.st_mtime) {
-                       (void)fprintf(stderr, "vipw: no changes made; ");
-                       stop(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 (!check(tfp))
+               if (pw_mkdb())
                        break;
                        break;
-               if (prompt())
-                       stop(0);
-               (void)fstat(fileno(tfp), &s1);
-               (void)fclose(tfp);
-       }
-
-       switch(fork()) {
-       case 0:
-               break;
-       case -1:
-               (void)fprintf(stderr, "vipw: can't fork; ");
-               stop(1);
-               /* NOTREACHED */
-       default:
-               exit(0);
-               /* NOTREACHED */
+               pw_prompt();
        }
        }
-
-       if (makedb(temp)) {
-               (void)fprintf(stderr, "vipw: mkpasswd failed; ");
-               stop(1);
-       }
-
-       /*
-        * possible race; have to rename four files, and someone could slip
-        * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
-        * so that getpwent(3) can't slip in; the lock should never fail and
-        * it's unclear what to do if it does.  Rename ``ptmp'' last so that
-        * passwd/vipw/chpass can't slip in.
-        */
-       (void)setpriority(PRIO_PROCESS, 0, -20);
-       fend = strcpy(from, temp) + strlen(temp);
-       tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
-       bcopy(".dir", fend, 5);
-       bcopy(".dir", tend, 5);
-       if ((fd = open(from, O_RDONLY, 0)) >= 0)
-               (void)flock(fd, LOCK_EX);
-       /* here we go... */
-       (void)rename(from, to);
-       bcopy(".pag", fend, 5);
-       bcopy(".pag", tend, 5);
-       (void)rename(from, to);
-       bcopy(".orig", fend, 6);
-       (void)rename(from, _PATH_PASSWD);
-       (void)rename(temp, passwd);
-       /* done! */
        exit(0);
 }
 
        exit(0);
 }
 
-check(tfp)
-       FILE *tfp;
-{
-       register long id;
-       register int lcnt, root;
-       register char *p, *sh;
-       long atol();
-       char buf[1024], *bp, *getusershell();
-
-       for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) {
-               /* skip lines that are too big */
-               if (!(p = index(buf, '\n'))) {
-                       (void)fprintf(stderr, "vipw: line too long");
-                       goto bad;
-               }
-               *p = '\0';
-               bp = buf;
-               if (!(p = strsep(&bp, ":")))            /* login */
-                       goto general;
-               root = !strcmp(p, "root");
-               (void)strsep(&bp, ":"); /* passwd */
-               if (!(p = strsep(&bp, ":")))    /* uid */
-                       goto general;
-               id = atol(p);
-               if (root && id) {
-                       (void)fprintf(stderr, "vipw: root uid should be 0");
-                       goto bad;
-               }
-               if (id > USHRT_MAX) {
-                       (void)fprintf(stderr, "vipw: %s > max uid value (%d)",
-                           p, USHRT_MAX);
-                       goto bad;
-               }
-               if (!(p = strsep(&bp, ":")))    /* gid */
-                       goto general;
-               id = atol(p);
-               if (id > USHRT_MAX) {
-                       (void)fprintf(stderr, "vipw: %s > max gid value (%d)",
-                           p, USHRT_MAX);
-                       goto bad;
-               }
-               (void)strsep(&bp, ":"); /* class */
-               (void)strsep(&bp, ":"); /* change */
-               (void)strsep(&bp, ":"); /* expire */
-               (void)strsep(&bp, ":"); /* gecos */
-               (void)strsep(&bp, ":"); /* directory */
-               if (!(p = strsep(&bp, ":")))    /* shell */
-                       goto general;
-               if (root && *p)                         /* empty == /bin/sh */
-                       for (setusershell();;)
-                               if (!(sh = getusershell())) {
-                                       (void)fprintf(stderr,
-                                           "vipw: warning, unknown root shell.\n");
-                                       break;
-                               }
-                               else if (!strcmp(p, sh))
-                                       break;
-               if (p = strsep(&bp, ":")) {     /* too many */
-(void)fprintf(stderr, "got {%s}\n", p);
-general:               (void)fprintf(stderr, "vipw: corrupted entry");
-bad:                   (void)fprintf(stderr, "; line #%d.\n", lcnt);
-                       (void)fflush(stderr);
-                       return(1);
-               }
-       }
-       return(0);
-}
-
-makedb(file)
-       char *file;
-{
-       int status, pid, w;
-
-       if (!(pid = vfork())) {
-               execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
-               _exit(127);
-       }
-       while ((w = wait(&status)) != pid && w != -1);
-       return(w == -1 || status);
-}
-
-edit()
-{
-       extern int errno;
-       int status, pid, w;
-       char *p, *editor, *getenv(), *strerror();
-
-       if (editor = getenv("EDITOR")) {
-               if (p = rindex(editor, '/'))
-                       ++p;
-               else
-                       p = editor;
-       }
-       else
-               p = editor = "vi";
-       if (!(pid = vfork())) {
-               execlp(editor, p, temp, NULL);
-               (void)fprintf(stderr, "vipw: %s: %s\n", editor,
-                   strerror(errno));
-               _exit(127);
-       }
-       while ((w = wait(&status)) != pid && w != -1);
-       return(w == -1 || status);
-}
-
-prompt()
-{
-       register int c;
-
-       for (;;) {
-               (void)printf("re-edit the password file? [y]: ");
-               (void)fflush(stdout);
-               c = getchar();
-               if (c != EOF && c != (int)'\n')
-                       while (getchar() != (int)'\n');
-               return(c == (int)'n');
-       }
-       /* NOTREACHED */
-}
-
-stop(val)
-       int val;
+copyfile(from, to)
+       register int from, to;
 {
 {
-       (void)fprintf(stderr, "%s unchanged.\n", passwd);
-       (void)unlink(temp);
-       exit(val);
+       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);
 }
 }