121186Sdist /* 231744Sbostic * Copyright (c) 1987 Regents of the University of California. 333502Sbostic * All rights reserved. 433502Sbostic * 5*42713Sbostic * %sccs.include.redist.c% 621186Sdist */ 721186Sdist 813736Ssam #ifndef lint 921186Sdist char copyright[] = 1031744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1121186Sdist All rights reserved.\n"; 1233502Sbostic #endif /* not lint */ 1313736Ssam 1421186Sdist #ifndef lint 15*42713Sbostic static char sccsid[] = "@(#)vipw.c 5.14 (Berkeley) 06/01/90"; 1633502Sbostic #endif /* not lint */ 1721186Sdist 1836857Sbostic #include <sys/param.h> 1913736Ssam #include <sys/stat.h> 2032668Sbostic #include <sys/signal.h> 2113736Ssam #include <sys/file.h> 2236857Sbostic #include <sys/time.h> 2336857Sbostic #include <sys/resource.h> 2436857Sbostic #include <errno.h> 2536857Sbostic #include <pwd.h> 2613736Ssam #include <stdio.h> 2742039Sbostic #include <string.h> 2813736Ssam 2937133Sbostic char *passwd, *temp; 3037133Sbostic 3131744Sbostic main() 3213736Ssam { 3336857Sbostic extern int errno; 3436857Sbostic register int n, fd_passwd, fd; 3536857Sbostic struct rlimit rlim; 3637197Sbostic struct stat s1, s2; 3737197Sbostic FILE *tfp; 3837133Sbostic char *fend, *tend; 3936857Sbostic char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN]; 4013736Ssam 4131744Sbostic (void)signal(SIGHUP, SIG_IGN); 4231744Sbostic (void)signal(SIGINT, SIG_IGN); 4331744Sbostic (void)signal(SIGQUIT, SIG_IGN); 4436857Sbostic (void)signal(SIGTSTP, SIG_IGN); 4531744Sbostic 4636857Sbostic rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 4736857Sbostic (void)setrlimit(RLIMIT_CPU, &rlim); 4836857Sbostic (void)setrlimit(RLIMIT_FSIZE, &rlim); 4936857Sbostic 5032668Sbostic (void)umask(0); 5131744Sbostic 5236857Sbostic temp = _PATH_PTMP; 5337468Sbostic if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) { 5436857Sbostic if (errno == EEXIST) 5537133Sbostic (void)fprintf(stderr, "vipw: password file busy.\n"); 5636857Sbostic else 5737133Sbostic (void)fprintf(stderr, 5836857Sbostic "vipw: %s: %s\n", temp, strerror(errno)); 5931744Sbostic exit(1); 6031744Sbostic } 6136857Sbostic passwd = _PATH_MASTERPASSWD; 6236857Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 6337133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", passwd, 6437133Sbostic strerror(errno)); 6513736Ssam exit(1); 6613736Ssam } 6731744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 6836857Sbostic if (write(fd, buf, n) != n) 6936857Sbostic goto syserr; 7036857Sbostic 7137197Sbostic if (n == -1 || close(fd_passwd)) { 7237197Sbostic syserr: (void)fprintf(stderr, "vipw: %s: %s; ", 7337197Sbostic passwd, strerror(errno)); 7437133Sbostic stop(1); 7513736Ssam } 7636857Sbostic 7739127Sbostic (void)fstat(fd, &s1); 7839127Sbostic (void)close(fd); 7937133Sbostic for (;;) { 8037133Sbostic if (edit()) { 8137133Sbostic (void)fprintf(stderr, "vipw: edit failed; "); 8237133Sbostic stop(1); 8337133Sbostic } 8439127Sbostic /* 8539127Sbostic * close and re-open the file each time we edit it; some 8639127Sbostic * editors create a new physical file on each edit session. 8739127Sbostic */ 8839127Sbostic if (!(tfp = fopen(temp, "r"))) { 8939127Sbostic (void)fprintf(stderr, "vipw: %s: %s; ", 9039127Sbostic temp, strerror(errno)); 9139127Sbostic stop(1); 9239127Sbostic } 9339127Sbostic (void)fstat(fileno(tfp), &s2); 9437197Sbostic if (s1.st_mtime == s2.st_mtime) { 9537197Sbostic (void)fprintf(stderr, "vipw: no changes made; "); 9637197Sbostic stop(0); 9737197Sbostic } 9837197Sbostic if (!check(tfp)) 9937133Sbostic break; 10037133Sbostic if (prompt()) 10137133Sbostic stop(0); 10239127Sbostic (void)fstat(fileno(tfp), &s1); 10339127Sbostic (void)fclose(tfp); 10413736Ssam } 10531744Sbostic 10636857Sbostic switch(fork()) { 10736857Sbostic case 0: 10836857Sbostic break; 10936857Sbostic case -1: 11037133Sbostic (void)fprintf(stderr, "vipw: can't fork; "); 11137133Sbostic stop(1); 11236857Sbostic /* NOTREACHED */ 11336857Sbostic default: 11436857Sbostic exit(0); 11536857Sbostic /* NOTREACHED */ 11631744Sbostic } 11731744Sbostic 11836857Sbostic if (makedb(temp)) { 11937133Sbostic (void)fprintf(stderr, "vipw: mkpasswd failed; "); 12037133Sbostic stop(1); 12113736Ssam } 12236857Sbostic 12336857Sbostic /* 12436857Sbostic * possible race; have to rename four files, and someone could slip 12536857Sbostic * in between them. LOCK_EX and rename the ``passwd.dir'' file first 12636857Sbostic * so that getpwent(3) can't slip in; the lock should never fail and 12736857Sbostic * it's unclear what to do if it does. Rename ``ptmp'' last so that 12836857Sbostic * passwd/vipw/chpass can't slip in. 12936857Sbostic */ 13036857Sbostic (void)setpriority(PRIO_PROCESS, 0, -20); 13136857Sbostic fend = strcpy(from, temp) + strlen(temp); 13237197Sbostic tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); 13336857Sbostic bcopy(".dir", fend, 5); 13436857Sbostic bcopy(".dir", tend, 5); 13536857Sbostic if ((fd = open(from, O_RDONLY, 0)) >= 0) 13636857Sbostic (void)flock(fd, LOCK_EX); 13736857Sbostic /* here we go... */ 13836857Sbostic (void)rename(from, to); 13936857Sbostic bcopy(".pag", fend, 5); 14036857Sbostic bcopy(".pag", tend, 5); 14136857Sbostic (void)rename(from, to); 14236857Sbostic bcopy(".orig", fend, 6); 14336857Sbostic (void)rename(from, _PATH_PASSWD); 14436857Sbostic (void)rename(temp, passwd); 14536857Sbostic /* done! */ 14636857Sbostic exit(0); 14713736Ssam } 14815633Sralph 14937197Sbostic check(tfp) 15037197Sbostic FILE *tfp; 15131744Sbostic { 15232668Sbostic register long id; 15336857Sbostic register int lcnt, root; 15436857Sbostic register char *p, *sh; 15532668Sbostic long atol(); 15641570Smarc char buf[1024], *bp, *getusershell(); 15731744Sbostic 15837133Sbostic for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { 15936857Sbostic /* skip lines that are too big */ 16039886Sbostic if (!(p = index(buf, '\n'))) { 16137133Sbostic (void)fprintf(stderr, "vipw: line too long"); 16236857Sbostic goto bad; 16332668Sbostic } 16439886Sbostic *p = '\0'; 16541570Smarc bp = buf; 16641570Smarc if (!(p = strsep(&bp, ":"))) /* login */ 16736857Sbostic goto general; 16836857Sbostic root = !strcmp(p, "root"); 16941570Smarc (void)strsep(&bp, ":"); /* passwd */ 17041570Smarc if (!(p = strsep(&bp, ":"))) /* uid */ 17136857Sbostic goto general; 17236857Sbostic id = atol(p); 17336857Sbostic if (root && id) { 17437133Sbostic (void)fprintf(stderr, "vipw: root uid should be 0"); 17532668Sbostic goto bad; 17636857Sbostic } 17736857Sbostic if (id > USHRT_MAX) { 17837133Sbostic (void)fprintf(stderr, "vipw: %s > max uid value (%d)", 17936857Sbostic p, USHRT_MAX); 18032668Sbostic goto bad; 18132668Sbostic } 18241570Smarc if (!(p = strsep(&bp, ":"))) /* gid */ 18336857Sbostic goto general; 18436857Sbostic id = atol(p); 18532668Sbostic if (id > USHRT_MAX) { 18637133Sbostic (void)fprintf(stderr, "vipw: %s > max gid value (%d)", 18736857Sbostic p, USHRT_MAX); 18832668Sbostic goto bad; 18932668Sbostic } 19041570Smarc (void)strsep(&bp, ":"); /* class */ 19141570Smarc (void)strsep(&bp, ":"); /* change */ 19241570Smarc (void)strsep(&bp, ":"); /* expire */ 19341570Smarc (void)strsep(&bp, ":"); /* gecos */ 19441570Smarc (void)strsep(&bp, ":"); /* directory */ 19541570Smarc if (!(p = strsep(&bp, ":"))) /* shell */ 19636857Sbostic goto general; 19736857Sbostic if (root && *p) /* empty == /bin/sh */ 19837133Sbostic for (setusershell();;) 19932668Sbostic if (!(sh = getusershell())) { 20037133Sbostic (void)fprintf(stderr, 20137133Sbostic "vipw: warning, unknown root shell.\n"); 20236857Sbostic break; 20332668Sbostic } 20436857Sbostic else if (!strcmp(p, sh)) 20532668Sbostic break; 20641570Smarc if (p = strsep(&bp, ":")) { /* too many */ 20739886Sbostic (void)fprintf(stderr, "got {%s}\n", p); 20837133Sbostic general: (void)fprintf(stderr, "vipw: corrupted entry"); 20937133Sbostic bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); 21037133Sbostic (void)fflush(stderr); 21137133Sbostic return(1); 21232668Sbostic } 21331744Sbostic } 21437133Sbostic return(0); 21531744Sbostic } 21631744Sbostic 21715633Sralph makedb(file) 21832668Sbostic char *file; 21915633Sralph { 22032668Sbostic int status, pid, w; 22115633Sralph 22231744Sbostic if (!(pid = vfork())) { 22336857Sbostic execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 22415633Sralph _exit(127); 22515633Sralph } 22631744Sbostic while ((w = wait(&status)) != pid && w != -1); 22736857Sbostic return(w == -1 || status); 22815633Sralph } 22932668Sbostic 23037133Sbostic edit() 23132668Sbostic { 23237133Sbostic extern int errno; 23336857Sbostic int status, pid, w; 23437133Sbostic char *p, *editor, *getenv(), *strerror(); 23532668Sbostic 23636857Sbostic if (editor = getenv("EDITOR")) { 23736857Sbostic if (p = rindex(editor, '/')) 23836857Sbostic ++p; 23936857Sbostic else 24036857Sbostic p = editor; 24136857Sbostic } 24236857Sbostic else 24336857Sbostic p = editor = "vi"; 24436857Sbostic if (!(pid = vfork())) { 24537133Sbostic execlp(editor, p, temp, NULL); 24637133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", editor, 24737133Sbostic strerror(errno)); 24836857Sbostic _exit(127); 24936857Sbostic } 25036857Sbostic while ((w = wait(&status)) != pid && w != -1); 25136857Sbostic return(w == -1 || status); 25232668Sbostic } 25337133Sbostic 25437133Sbostic prompt() 25537133Sbostic { 25637133Sbostic register int c; 25737133Sbostic 25837133Sbostic for (;;) { 25937133Sbostic (void)printf("re-edit the password file? [y]: "); 26037133Sbostic (void)fflush(stdout); 26137133Sbostic c = getchar(); 26237133Sbostic if (c != EOF && c != (int)'\n') 26337133Sbostic while (getchar() != (int)'\n'); 26437133Sbostic return(c == (int)'n'); 26537133Sbostic } 26637133Sbostic /* NOTREACHED */ 26737133Sbostic } 26837133Sbostic 26937133Sbostic stop(val) 27037133Sbostic int val; 27137133Sbostic { 27237133Sbostic (void)fprintf(stderr, "%s unchanged.\n", passwd); 27337133Sbostic (void)unlink(temp); 27437133Sbostic exit(val); 27537133Sbostic } 276