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*39886Sbostic static char sccsid[] = "@(#)vipw.c 5.11 (Berkeley) 01/05/90"; 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 8739127Sbostic (void)fstat(fd, &s1); 8839127Sbostic (void)close(fd); 8937133Sbostic for (;;) { 9037133Sbostic if (edit()) { 9137133Sbostic (void)fprintf(stderr, "vipw: edit failed; "); 9237133Sbostic stop(1); 9337133Sbostic } 9439127Sbostic /* 9539127Sbostic * close and re-open the file each time we edit it; some 9639127Sbostic * editors create a new physical file on each edit session. 9739127Sbostic */ 9839127Sbostic if (!(tfp = fopen(temp, "r"))) { 9939127Sbostic (void)fprintf(stderr, "vipw: %s: %s; ", 10039127Sbostic temp, strerror(errno)); 10139127Sbostic stop(1); 10239127Sbostic } 10339127Sbostic (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); 11239127Sbostic (void)fstat(fileno(tfp), &s1); 11339127Sbostic (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 */ 170*39886Sbostic if (!(p = index(buf, '\n'))) { 17137133Sbostic (void)fprintf(stderr, "vipw: line too long"); 17236857Sbostic goto bad; 17332668Sbostic } 174*39886Sbostic *p = '\0'; 175*39886Sbostic if (!(p = strsep(buf, ":"))) /* login */ 17636857Sbostic goto general; 17736857Sbostic root = !strcmp(p, "root"); 178*39886Sbostic (void)strsep((char *)NULL, ":"); /* passwd */ 179*39886Sbostic if (!(p = strsep((char *)NULL, ":"))) /* uid */ 18036857Sbostic goto general; 18136857Sbostic id = atol(p); 18236857Sbostic if (root && id) { 18337133Sbostic (void)fprintf(stderr, "vipw: root uid should be 0"); 18432668Sbostic goto bad; 18536857Sbostic } 18636857Sbostic if (id > USHRT_MAX) { 18737133Sbostic (void)fprintf(stderr, "vipw: %s > max uid value (%d)", 18836857Sbostic p, USHRT_MAX); 18932668Sbostic goto bad; 19032668Sbostic } 191*39886Sbostic if (!(p = strsep((char *)NULL, ":"))) /* gid */ 19236857Sbostic goto general; 19336857Sbostic id = atol(p); 19432668Sbostic if (id > USHRT_MAX) { 19537133Sbostic (void)fprintf(stderr, "vipw: %s > max gid value (%d)", 19636857Sbostic p, USHRT_MAX); 19732668Sbostic goto bad; 19832668Sbostic } 199*39886Sbostic (void)strsep((char *)NULL, ":"); /* class */ 200*39886Sbostic (void)strsep((char *)NULL, ":"); /* change */ 201*39886Sbostic (void)strsep((char *)NULL, ":"); /* expire */ 202*39886Sbostic (void)strsep((char *)NULL, ":"); /* gecos */ 203*39886Sbostic (void)strsep((char *)NULL, ":"); /* directory */ 204*39886Sbostic if (!(p = strsep((char *)NULL, ":"))) /* shell */ 20536857Sbostic goto general; 20636857Sbostic if (root && *p) /* empty == /bin/sh */ 20737133Sbostic for (setusershell();;) 20832668Sbostic if (!(sh = getusershell())) { 20937133Sbostic (void)fprintf(stderr, 21037133Sbostic "vipw: warning, unknown root shell.\n"); 21136857Sbostic break; 21232668Sbostic } 21336857Sbostic else if (!strcmp(p, sh)) 21432668Sbostic break; 215*39886Sbostic if (p = strsep((char *)NULL, ":")) { /* too many */ 216*39886Sbostic (void)fprintf(stderr, "got {%s}\n", p); 21737133Sbostic general: (void)fprintf(stderr, "vipw: corrupted entry"); 21837133Sbostic bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); 21937133Sbostic (void)fflush(stderr); 22037133Sbostic return(1); 22132668Sbostic } 22231744Sbostic } 22337133Sbostic return(0); 22431744Sbostic } 22531744Sbostic 22615633Sralph makedb(file) 22732668Sbostic char *file; 22815633Sralph { 22932668Sbostic int status, pid, w; 23015633Sralph 23131744Sbostic if (!(pid = vfork())) { 23236857Sbostic execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 23315633Sralph _exit(127); 23415633Sralph } 23531744Sbostic while ((w = wait(&status)) != pid && w != -1); 23636857Sbostic return(w == -1 || status); 23715633Sralph } 23832668Sbostic 23937133Sbostic edit() 24032668Sbostic { 24137133Sbostic extern int errno; 24236857Sbostic int status, pid, w; 24337133Sbostic char *p, *editor, *getenv(), *strerror(); 24432668Sbostic 24536857Sbostic if (editor = getenv("EDITOR")) { 24636857Sbostic if (p = rindex(editor, '/')) 24736857Sbostic ++p; 24836857Sbostic else 24936857Sbostic p = editor; 25036857Sbostic } 25136857Sbostic else 25236857Sbostic p = editor = "vi"; 25336857Sbostic if (!(pid = vfork())) { 25437133Sbostic execlp(editor, p, temp, NULL); 25537133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", editor, 25637133Sbostic strerror(errno)); 25736857Sbostic _exit(127); 25836857Sbostic } 25936857Sbostic while ((w = wait(&status)) != pid && w != -1); 26036857Sbostic return(w == -1 || status); 26132668Sbostic } 26237133Sbostic 26337133Sbostic prompt() 26437133Sbostic { 26537133Sbostic register int c; 26637133Sbostic 26737133Sbostic for (;;) { 26837133Sbostic (void)printf("re-edit the password file? [y]: "); 26937133Sbostic (void)fflush(stdout); 27037133Sbostic c = getchar(); 27137133Sbostic if (c != EOF && c != (int)'\n') 27237133Sbostic while (getchar() != (int)'\n'); 27337133Sbostic return(c == (int)'n'); 27437133Sbostic } 27537133Sbostic /* NOTREACHED */ 27637133Sbostic } 27737133Sbostic 27837133Sbostic stop(val) 27937133Sbostic int val; 28037133Sbostic { 28137133Sbostic (void)fprintf(stderr, "%s unchanged.\n", passwd); 28237133Sbostic (void)unlink(temp); 28337133Sbostic exit(val); 28437133Sbostic } 285