121186Sdist /* 231744Sbostic * Copyright (c) 1987 Regents of the University of California. 333502Sbostic * All rights reserved. 433502Sbostic * 533502Sbostic * Redistribution and use in source and binary forms are permitted 634778Sbostic * provided that the above copyright notice and this paragraph are 734778Sbostic * duplicated in all such forms and that any documentation, 834778Sbostic * advertising materials, and other materials related to such 934778Sbostic * distribution and use acknowledge that the software was developed 1034778Sbostic * by the University of California, Berkeley. The name of the 1134778Sbostic * University may not be used to endorse or promote products derived 1234778Sbostic * from this software without specific prior written permission. 1334778Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434778Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534778Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621186Sdist */ 1721186Sdist 1813736Ssam #ifndef lint 1921186Sdist char copyright[] = 2031744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 2121186Sdist All rights reserved.\n"; 2233502Sbostic #endif /* not lint */ 2313736Ssam 2421186Sdist #ifndef lint 25*37197Sbostic static char sccsid[] = "@(#)vipw.c 5.8 (Berkeley) 03/16/89"; 2633502Sbostic #endif /* not lint */ 2721186Sdist 2836857Sbostic #include <sys/param.h> 2913736Ssam #include <sys/stat.h> 3032668Sbostic #include <sys/signal.h> 3113736Ssam #include <sys/file.h> 3236857Sbostic #include <sys/time.h> 3336857Sbostic #include <sys/resource.h> 3436857Sbostic #include <errno.h> 3536857Sbostic #include <pwd.h> 3613736Ssam #include <stdio.h> 3737133Sbostic #include <strings.h> 3813736Ssam 3937133Sbostic char *passwd, *temp; 4037133Sbostic 4131744Sbostic main() 4213736Ssam { 4336857Sbostic extern int errno; 4436857Sbostic register int n, fd_passwd, fd; 4536857Sbostic struct rlimit rlim; 46*37197Sbostic struct stat s1, s2; 47*37197Sbostic FILE *tfp; 4837133Sbostic char *fend, *tend; 4936857Sbostic char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN]; 5013736Ssam 5131744Sbostic (void)signal(SIGHUP, SIG_IGN); 5231744Sbostic (void)signal(SIGINT, SIG_IGN); 5331744Sbostic (void)signal(SIGQUIT, SIG_IGN); 5436857Sbostic (void)signal(SIGTSTP, SIG_IGN); 5531744Sbostic 5636857Sbostic rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 5736857Sbostic (void)setrlimit(RLIMIT_CPU, &rlim); 5836857Sbostic (void)setrlimit(RLIMIT_FSIZE, &rlim); 5936857Sbostic 6032668Sbostic (void)umask(0); 6131744Sbostic 6236857Sbostic temp = _PATH_PTMP; 6336857Sbostic if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 6436857Sbostic if (errno == EEXIST) 6537133Sbostic (void)fprintf(stderr, "vipw: password file busy.\n"); 6636857Sbostic else 6737133Sbostic (void)fprintf(stderr, 6836857Sbostic "vipw: %s: %s\n", temp, strerror(errno)); 6931744Sbostic exit(1); 7031744Sbostic } 7136857Sbostic passwd = _PATH_MASTERPASSWD; 7236857Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 7337133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", passwd, 7437133Sbostic strerror(errno)); 7513736Ssam exit(1); 7613736Ssam } 7731744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 7836857Sbostic if (write(fd, buf, n) != n) 7936857Sbostic goto syserr; 8036857Sbostic 81*37197Sbostic if (n == -1 || close(fd_passwd)) { 82*37197Sbostic syserr: (void)fprintf(stderr, "vipw: %s: %s; ", 83*37197Sbostic passwd, strerror(errno)); 8437133Sbostic stop(1); 8513736Ssam } 86*37197Sbostic if (fsync(fd) || !(tfp = fdopen(fd, "r"))) { 87*37197Sbostic (void)fprintf(stderr, "vipw: %s: %s; ", 88*37197Sbostic temp, strerror(errno)); 89*37197Sbostic stop(1); 90*37197Sbostic } 9136857Sbostic 9237133Sbostic for (;;) { 93*37197Sbostic (void)fstat(fd, &s1); 9437133Sbostic if (edit()) { 9537133Sbostic (void)fprintf(stderr, "vipw: edit failed; "); 9637133Sbostic stop(1); 9737133Sbostic } 98*37197Sbostic (void)fstat(fd, &s2); 99*37197Sbostic if (s1.st_mtime == s2.st_mtime) { 100*37197Sbostic (void)fprintf(stderr, "vipw: no changes made; "); 101*37197Sbostic stop(0); 102*37197Sbostic } 103*37197Sbostic rewind(tfp); 104*37197Sbostic if (!check(tfp)) 10537133Sbostic break; 10637133Sbostic if (prompt()) 10737133Sbostic stop(0); 10813736Ssam } 10931744Sbostic 11036857Sbostic switch(fork()) { 11136857Sbostic case 0: 11236857Sbostic break; 11336857Sbostic case -1: 11437133Sbostic (void)fprintf(stderr, "vipw: can't fork; "); 11537133Sbostic stop(1); 11636857Sbostic /* NOTREACHED */ 11736857Sbostic default: 11836857Sbostic exit(0); 11936857Sbostic /* NOTREACHED */ 12031744Sbostic } 12131744Sbostic 12236857Sbostic if (makedb(temp)) { 12337133Sbostic (void)fprintf(stderr, "vipw: mkpasswd failed; "); 12437133Sbostic stop(1); 12513736Ssam } 12636857Sbostic 12736857Sbostic /* 12836857Sbostic * possible race; have to rename four files, and someone could slip 12936857Sbostic * in between them. LOCK_EX and rename the ``passwd.dir'' file first 13036857Sbostic * so that getpwent(3) can't slip in; the lock should never fail and 13136857Sbostic * it's unclear what to do if it does. Rename ``ptmp'' last so that 13236857Sbostic * passwd/vipw/chpass can't slip in. 13336857Sbostic */ 13436857Sbostic (void)setpriority(PRIO_PROCESS, 0, -20); 13536857Sbostic fend = strcpy(from, temp) + strlen(temp); 136*37197Sbostic tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); 13736857Sbostic bcopy(".dir", fend, 5); 13836857Sbostic bcopy(".dir", tend, 5); 13936857Sbostic if ((fd = open(from, O_RDONLY, 0)) >= 0) 14036857Sbostic (void)flock(fd, LOCK_EX); 14136857Sbostic /* here we go... */ 14236857Sbostic (void)rename(from, to); 14336857Sbostic bcopy(".pag", fend, 5); 14436857Sbostic bcopy(".pag", tend, 5); 14536857Sbostic (void)rename(from, to); 14636857Sbostic bcopy(".orig", fend, 6); 14736857Sbostic (void)rename(from, _PATH_PASSWD); 14836857Sbostic (void)rename(temp, passwd); 14936857Sbostic /* done! */ 15036857Sbostic exit(0); 15113736Ssam } 15215633Sralph 153*37197Sbostic check(tfp) 154*37197Sbostic FILE *tfp; 15531744Sbostic { 15632668Sbostic register long id; 15736857Sbostic register int lcnt, root; 15836857Sbostic register char *p, *sh; 15932668Sbostic long atol(); 16037133Sbostic char buf[1024], *getusershell(); 16131744Sbostic 16237133Sbostic for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { 16336857Sbostic /* skip lines that are too big */ 16436857Sbostic if (!index(buf, '\n')) { 16537133Sbostic (void)fprintf(stderr, "vipw: line too long"); 16636857Sbostic goto bad; 16732668Sbostic } 16836857Sbostic if (!(p = strsep(buf, ":\n"))) /* login */ 16936857Sbostic goto general; 17036857Sbostic root = !strcmp(p, "root"); 17136857Sbostic (void)strsep((char *)NULL, ":\n"); /* passwd */ 17236857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* uid */ 17336857Sbostic goto general; 17436857Sbostic id = atol(p); 17536857Sbostic if (root && id) { 17637133Sbostic (void)fprintf(stderr, "vipw: root uid should be 0"); 17732668Sbostic goto bad; 17836857Sbostic } 17936857Sbostic if (id > USHRT_MAX) { 18037133Sbostic (void)fprintf(stderr, "vipw: %s > max uid value (%d)", 18136857Sbostic p, USHRT_MAX); 18232668Sbostic goto bad; 18332668Sbostic } 18436857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* gid */ 18536857Sbostic goto general; 18636857Sbostic id = atol(p); 18732668Sbostic if (id > USHRT_MAX) { 18837133Sbostic (void)fprintf(stderr, "vipw: %s > max gid value (%d)", 18936857Sbostic p, USHRT_MAX); 19032668Sbostic goto bad; 19132668Sbostic } 19236857Sbostic (void)strsep((char *)NULL, ":\n"); /* class */ 19336857Sbostic (void)strsep((char *)NULL, ":\n"); /* change */ 19436857Sbostic (void)strsep((char *)NULL, ":\n"); /* expire */ 19536857Sbostic (void)strsep((char *)NULL, ":\n"); /* gecos */ 19636857Sbostic (void)strsep((char *)NULL, ":\n"); /* directory */ 19736857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* shell */ 19836857Sbostic goto general; 19936857Sbostic if (root && *p) /* empty == /bin/sh */ 20037133Sbostic for (setusershell();;) 20132668Sbostic if (!(sh = getusershell())) { 20237133Sbostic (void)fprintf(stderr, 20337133Sbostic "vipw: warning, unknown root shell.\n"); 20436857Sbostic break; 20532668Sbostic } 20636857Sbostic else if (!strcmp(p, sh)) 20732668Sbostic break; 20836857Sbostic if (strsep((char *)NULL, ":\n")) { /* too many */ 20937133Sbostic general: (void)fprintf(stderr, "vipw: corrupted entry"); 21037133Sbostic bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); 21137133Sbostic (void)fflush(stderr); 21237133Sbostic return(1); 21332668Sbostic } 21431744Sbostic } 21537133Sbostic return(0); 21631744Sbostic } 21731744Sbostic 21815633Sralph makedb(file) 21932668Sbostic char *file; 22015633Sralph { 22132668Sbostic int status, pid, w; 22215633Sralph 22331744Sbostic if (!(pid = vfork())) { 22436857Sbostic execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 22515633Sralph _exit(127); 22615633Sralph } 22731744Sbostic while ((w = wait(&status)) != pid && w != -1); 22836857Sbostic return(w == -1 || status); 22915633Sralph } 23032668Sbostic 23137133Sbostic edit() 23232668Sbostic { 23337133Sbostic extern int errno; 23436857Sbostic int status, pid, w; 23537133Sbostic char *p, *editor, *getenv(), *strerror(); 23632668Sbostic 23736857Sbostic if (editor = getenv("EDITOR")) { 23836857Sbostic if (p = rindex(editor, '/')) 23936857Sbostic ++p; 24036857Sbostic else 24136857Sbostic p = editor; 24236857Sbostic } 24336857Sbostic else 24436857Sbostic p = editor = "vi"; 24536857Sbostic if (!(pid = vfork())) { 24637133Sbostic execlp(editor, p, temp, NULL); 24737133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", editor, 24837133Sbostic strerror(errno)); 24936857Sbostic _exit(127); 25036857Sbostic } 25136857Sbostic while ((w = wait(&status)) != pid && w != -1); 25236857Sbostic return(w == -1 || status); 25332668Sbostic } 25437133Sbostic 25537133Sbostic prompt() 25637133Sbostic { 25737133Sbostic register int c; 25837133Sbostic 25937133Sbostic for (;;) { 26037133Sbostic (void)printf("re-edit the password file? [y]: "); 26137133Sbostic (void)fflush(stdout); 26237133Sbostic c = getchar(); 26337133Sbostic if (c != EOF && c != (int)'\n') 26437133Sbostic while (getchar() != (int)'\n'); 26537133Sbostic return(c == (int)'n'); 26637133Sbostic } 26737133Sbostic /* NOTREACHED */ 26837133Sbostic } 26937133Sbostic 27037133Sbostic stop(val) 27137133Sbostic int val; 27237133Sbostic { 27337133Sbostic (void)fprintf(stderr, "%s unchanged.\n", passwd); 27437133Sbostic (void)unlink(temp); 27537133Sbostic exit(val); 27637133Sbostic } 277