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*39127Sbostic static char sccsid[] = "@(#)vipw.c 5.10 (Berkeley) 09/12/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; 4637197Sbostic struct stat s1, s2; 4737197Sbostic 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; 6337468Sbostic if ((fd = open(temp, O_RDWR|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 8137197Sbostic if (n == -1 || close(fd_passwd)) { 8237197Sbostic syserr: (void)fprintf(stderr, "vipw: %s: %s; ", 8337197Sbostic passwd, strerror(errno)); 8437133Sbostic stop(1); 8513736Ssam } 8636857Sbostic 87*39127Sbostic (void)fstat(fd, &s1); 88*39127Sbostic (void)close(fd); 8937133Sbostic for (;;) { 9037133Sbostic if (edit()) { 9137133Sbostic (void)fprintf(stderr, "vipw: edit failed; "); 9237133Sbostic stop(1); 9337133Sbostic } 94*39127Sbostic /* 95*39127Sbostic * close and re-open the file each time we edit it; some 96*39127Sbostic * editors create a new physical file on each edit session. 97*39127Sbostic */ 98*39127Sbostic if (!(tfp = fopen(temp, "r"))) { 99*39127Sbostic (void)fprintf(stderr, "vipw: %s: %s; ", 100*39127Sbostic temp, strerror(errno)); 101*39127Sbostic stop(1); 102*39127Sbostic } 103*39127Sbostic (void)fstat(fileno(tfp), &s2); 10437197Sbostic if (s1.st_mtime == s2.st_mtime) { 10537197Sbostic (void)fprintf(stderr, "vipw: no changes made; "); 10637197Sbostic stop(0); 10737197Sbostic } 10837197Sbostic if (!check(tfp)) 10937133Sbostic break; 11037133Sbostic if (prompt()) 11137133Sbostic stop(0); 112*39127Sbostic (void)fstat(fileno(tfp), &s1); 113*39127Sbostic (void)fclose(tfp); 11413736Ssam } 11531744Sbostic 11636857Sbostic switch(fork()) { 11736857Sbostic case 0: 11836857Sbostic break; 11936857Sbostic case -1: 12037133Sbostic (void)fprintf(stderr, "vipw: can't fork; "); 12137133Sbostic stop(1); 12236857Sbostic /* NOTREACHED */ 12336857Sbostic default: 12436857Sbostic exit(0); 12536857Sbostic /* NOTREACHED */ 12631744Sbostic } 12731744Sbostic 12836857Sbostic if (makedb(temp)) { 12937133Sbostic (void)fprintf(stderr, "vipw: mkpasswd failed; "); 13037133Sbostic stop(1); 13113736Ssam } 13236857Sbostic 13336857Sbostic /* 13436857Sbostic * possible race; have to rename four files, and someone could slip 13536857Sbostic * in between them. LOCK_EX and rename the ``passwd.dir'' file first 13636857Sbostic * so that getpwent(3) can't slip in; the lock should never fail and 13736857Sbostic * it's unclear what to do if it does. Rename ``ptmp'' last so that 13836857Sbostic * passwd/vipw/chpass can't slip in. 13936857Sbostic */ 14036857Sbostic (void)setpriority(PRIO_PROCESS, 0, -20); 14136857Sbostic fend = strcpy(from, temp) + strlen(temp); 14237197Sbostic tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD); 14336857Sbostic bcopy(".dir", fend, 5); 14436857Sbostic bcopy(".dir", tend, 5); 14536857Sbostic if ((fd = open(from, O_RDONLY, 0)) >= 0) 14636857Sbostic (void)flock(fd, LOCK_EX); 14736857Sbostic /* here we go... */ 14836857Sbostic (void)rename(from, to); 14936857Sbostic bcopy(".pag", fend, 5); 15036857Sbostic bcopy(".pag", tend, 5); 15136857Sbostic (void)rename(from, to); 15236857Sbostic bcopy(".orig", fend, 6); 15336857Sbostic (void)rename(from, _PATH_PASSWD); 15436857Sbostic (void)rename(temp, passwd); 15536857Sbostic /* done! */ 15636857Sbostic exit(0); 15713736Ssam } 15815633Sralph 15937197Sbostic check(tfp) 16037197Sbostic FILE *tfp; 16131744Sbostic { 16232668Sbostic register long id; 16336857Sbostic register int lcnt, root; 16436857Sbostic register char *p, *sh; 16532668Sbostic long atol(); 16637133Sbostic char buf[1024], *getusershell(); 16731744Sbostic 16837133Sbostic for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { 16936857Sbostic /* skip lines that are too big */ 17036857Sbostic if (!index(buf, '\n')) { 17137133Sbostic (void)fprintf(stderr, "vipw: line too long"); 17236857Sbostic goto bad; 17332668Sbostic } 17436857Sbostic if (!(p = strsep(buf, ":\n"))) /* login */ 17536857Sbostic goto general; 17636857Sbostic root = !strcmp(p, "root"); 17736857Sbostic (void)strsep((char *)NULL, ":\n"); /* passwd */ 17836857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* uid */ 17936857Sbostic goto general; 18036857Sbostic id = atol(p); 18136857Sbostic if (root && id) { 18237133Sbostic (void)fprintf(stderr, "vipw: root uid should be 0"); 18332668Sbostic goto bad; 18436857Sbostic } 18536857Sbostic if (id > USHRT_MAX) { 18637133Sbostic (void)fprintf(stderr, "vipw: %s > max uid value (%d)", 18736857Sbostic p, USHRT_MAX); 18832668Sbostic goto bad; 18932668Sbostic } 19036857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* gid */ 19136857Sbostic goto general; 19236857Sbostic id = atol(p); 19332668Sbostic if (id > USHRT_MAX) { 19437133Sbostic (void)fprintf(stderr, "vipw: %s > max gid value (%d)", 19536857Sbostic p, USHRT_MAX); 19632668Sbostic goto bad; 19732668Sbostic } 19836857Sbostic (void)strsep((char *)NULL, ":\n"); /* class */ 19936857Sbostic (void)strsep((char *)NULL, ":\n"); /* change */ 20036857Sbostic (void)strsep((char *)NULL, ":\n"); /* expire */ 20136857Sbostic (void)strsep((char *)NULL, ":\n"); /* gecos */ 20236857Sbostic (void)strsep((char *)NULL, ":\n"); /* directory */ 20336857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* shell */ 20436857Sbostic goto general; 20536857Sbostic if (root && *p) /* empty == /bin/sh */ 20637133Sbostic for (setusershell();;) 20732668Sbostic if (!(sh = getusershell())) { 20837133Sbostic (void)fprintf(stderr, 20937133Sbostic "vipw: warning, unknown root shell.\n"); 21036857Sbostic break; 21132668Sbostic } 21236857Sbostic else if (!strcmp(p, sh)) 21332668Sbostic break; 21436857Sbostic if (strsep((char *)NULL, ":\n")) { /* too many */ 21537133Sbostic general: (void)fprintf(stderr, "vipw: corrupted entry"); 21637133Sbostic bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); 21737133Sbostic (void)fflush(stderr); 21837133Sbostic return(1); 21932668Sbostic } 22031744Sbostic } 22137133Sbostic return(0); 22231744Sbostic } 22331744Sbostic 22415633Sralph makedb(file) 22532668Sbostic char *file; 22615633Sralph { 22732668Sbostic int status, pid, w; 22815633Sralph 22931744Sbostic if (!(pid = vfork())) { 23036857Sbostic execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 23115633Sralph _exit(127); 23215633Sralph } 23331744Sbostic while ((w = wait(&status)) != pid && w != -1); 23436857Sbostic return(w == -1 || status); 23515633Sralph } 23632668Sbostic 23737133Sbostic edit() 23832668Sbostic { 23937133Sbostic extern int errno; 24036857Sbostic int status, pid, w; 24137133Sbostic char *p, *editor, *getenv(), *strerror(); 24232668Sbostic 24336857Sbostic if (editor = getenv("EDITOR")) { 24436857Sbostic if (p = rindex(editor, '/')) 24536857Sbostic ++p; 24636857Sbostic else 24736857Sbostic p = editor; 24836857Sbostic } 24936857Sbostic else 25036857Sbostic p = editor = "vi"; 25136857Sbostic if (!(pid = vfork())) { 25237133Sbostic execlp(editor, p, temp, NULL); 25337133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", editor, 25437133Sbostic strerror(errno)); 25536857Sbostic _exit(127); 25636857Sbostic } 25736857Sbostic while ((w = wait(&status)) != pid && w != -1); 25836857Sbostic return(w == -1 || status); 25932668Sbostic } 26037133Sbostic 26137133Sbostic prompt() 26237133Sbostic { 26337133Sbostic register int c; 26437133Sbostic 26537133Sbostic for (;;) { 26637133Sbostic (void)printf("re-edit the password file? [y]: "); 26737133Sbostic (void)fflush(stdout); 26837133Sbostic c = getchar(); 26937133Sbostic if (c != EOF && c != (int)'\n') 27037133Sbostic while (getchar() != (int)'\n'); 27137133Sbostic return(c == (int)'n'); 27237133Sbostic } 27337133Sbostic /* NOTREACHED */ 27437133Sbostic } 27537133Sbostic 27637133Sbostic stop(val) 27737133Sbostic int val; 27837133Sbostic { 27937133Sbostic (void)fprintf(stderr, "%s unchanged.\n", passwd); 28037133Sbostic (void)unlink(temp); 28137133Sbostic exit(val); 28237133Sbostic } 283