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*37133Sbostic static char sccsid[] = "@(#)vipw.c 5.7 (Berkeley) 03/11/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> 37*37133Sbostic #include <strings.h> 3813736Ssam 39*37133Sbostic char *passwd, *temp; 40*37133Sbostic 4131744Sbostic main() 4213736Ssam { 4336857Sbostic extern int errno; 4436857Sbostic register int n, fd_passwd, fd; 4536857Sbostic struct rlimit rlim; 46*37133Sbostic struct stat s1; 47*37133Sbostic char *fend, *tend; 4836857Sbostic char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN]; 4913736Ssam 5031744Sbostic (void)signal(SIGHUP, SIG_IGN); 5131744Sbostic (void)signal(SIGINT, SIG_IGN); 5231744Sbostic (void)signal(SIGQUIT, SIG_IGN); 5336857Sbostic (void)signal(SIGTSTP, SIG_IGN); 5431744Sbostic 5536857Sbostic rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 5636857Sbostic (void)setrlimit(RLIMIT_CPU, &rlim); 5736857Sbostic (void)setrlimit(RLIMIT_FSIZE, &rlim); 5836857Sbostic 5932668Sbostic (void)umask(0); 6031744Sbostic 6136857Sbostic temp = _PATH_PTMP; 6236857Sbostic if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 6336857Sbostic if (errno == EEXIST) 64*37133Sbostic (void)fprintf(stderr, "vipw: password file busy.\n"); 6536857Sbostic else 66*37133Sbostic (void)fprintf(stderr, 6736857Sbostic "vipw: %s: %s\n", temp, strerror(errno)); 6831744Sbostic exit(1); 6931744Sbostic } 7036857Sbostic passwd = _PATH_MASTERPASSWD; 7136857Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 72*37133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", passwd, 73*37133Sbostic strerror(errno)); 7413736Ssam exit(1); 7513736Ssam } 7631744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 7736857Sbostic if (write(fd, buf, n) != n) 7836857Sbostic goto syserr; 7936857Sbostic 8036857Sbostic if (n == -1 || close(fd_passwd) || fsync(fd) || 8136857Sbostic fstat(fd, &s1) || close(fd)) { 82*37133Sbostic syserr: (void)fprintf(stderr, "vipw: %s; ", strerror(errno)); 83*37133Sbostic stop(1); 8413736Ssam } 8536857Sbostic 86*37133Sbostic for (;;) { 87*37133Sbostic if (edit()) { 88*37133Sbostic (void)fprintf(stderr, "vipw: edit failed; "); 89*37133Sbostic stop(1); 90*37133Sbostic } 91*37133Sbostic if (!check(&s1)) 92*37133Sbostic break; 93*37133Sbostic if (prompt()) 94*37133Sbostic stop(0); 9513736Ssam } 9631744Sbostic 9736857Sbostic switch(fork()) { 9836857Sbostic case 0: 9936857Sbostic break; 10036857Sbostic case -1: 101*37133Sbostic (void)fprintf(stderr, "vipw: can't fork; "); 102*37133Sbostic stop(1); 10336857Sbostic /* NOTREACHED */ 10436857Sbostic default: 10536857Sbostic exit(0); 10636857Sbostic /* NOTREACHED */ 10731744Sbostic } 10831744Sbostic 10936857Sbostic if (makedb(temp)) { 110*37133Sbostic (void)fprintf(stderr, "vipw: mkpasswd failed; "); 111*37133Sbostic stop(1); 11213736Ssam } 11336857Sbostic 11436857Sbostic /* 11536857Sbostic * possible race; have to rename four files, and someone could slip 11636857Sbostic * in between them. LOCK_EX and rename the ``passwd.dir'' file first 11736857Sbostic * so that getpwent(3) can't slip in; the lock should never fail and 11836857Sbostic * it's unclear what to do if it does. Rename ``ptmp'' last so that 11936857Sbostic * passwd/vipw/chpass can't slip in. 12036857Sbostic */ 12136857Sbostic (void)setpriority(PRIO_PROCESS, 0, -20); 12236857Sbostic fend = strcpy(from, temp) + strlen(temp); 12336857Sbostic tend = strcpy(to, passwd) + strlen(passwd); 12436857Sbostic bcopy(".dir", fend, 5); 12536857Sbostic bcopy(".dir", tend, 5); 12636857Sbostic if ((fd = open(from, O_RDONLY, 0)) >= 0) 12736857Sbostic (void)flock(fd, LOCK_EX); 12836857Sbostic /* here we go... */ 12936857Sbostic (void)rename(from, to); 13036857Sbostic bcopy(".pag", fend, 5); 13136857Sbostic bcopy(".pag", tend, 5); 13236857Sbostic (void)rename(from, to); 13336857Sbostic bcopy(".orig", fend, 6); 13436857Sbostic (void)rename(from, _PATH_PASSWD); 13536857Sbostic (void)rename(temp, passwd); 13636857Sbostic /* done! */ 13736857Sbostic exit(0); 13813736Ssam } 13915633Sralph 140*37133Sbostic check(s1) 141*37133Sbostic struct stat *s1; 14231744Sbostic { 14332668Sbostic register long id; 14436857Sbostic register int lcnt, root; 14536857Sbostic register char *p, *sh; 146*37133Sbostic struct stat s2; 147*37133Sbostic FILE *tfp; 14832668Sbostic long atol(); 149*37133Sbostic char buf[1024], *getusershell(); 15031744Sbostic 151*37133Sbostic if (!(tfp = fopen(temp, "r")) || fstat(fileno(tfp), &s2) || 152*37133Sbostic !s2.st_size) { 153*37133Sbostic (void)fprintf(stderr, "vipw: can't read temp file; "); 154*37133Sbostic stop(1); 155*37133Sbostic } 156*37133Sbostic 157*37133Sbostic if (s1->st_mtime == s2.st_mtime) { 158*37133Sbostic (void)fprintf(stderr, "vipw: "); 159*37133Sbostic stop(0); 160*37133Sbostic } 161*37133Sbostic 162*37133Sbostic for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) { 16336857Sbostic /* skip lines that are too big */ 16436857Sbostic if (!index(buf, '\n')) { 165*37133Sbostic (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) { 176*37133Sbostic (void)fprintf(stderr, "vipw: root uid should be 0"); 17732668Sbostic goto bad; 17836857Sbostic } 17936857Sbostic if (id > USHRT_MAX) { 180*37133Sbostic (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) { 188*37133Sbostic (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 */ 200*37133Sbostic for (setusershell();;) 20132668Sbostic if (!(sh = getusershell())) { 202*37133Sbostic (void)fprintf(stderr, 203*37133Sbostic "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 */ 209*37133Sbostic general: (void)fprintf(stderr, "vipw: corrupted entry"); 210*37133Sbostic bad: (void)fprintf(stderr, "; line #%d.\n", lcnt); 211*37133Sbostic (void)fflush(stderr); 212*37133Sbostic return(1); 21332668Sbostic } 21431744Sbostic } 215*37133Sbostic 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 231*37133Sbostic edit() 23232668Sbostic { 233*37133Sbostic extern int errno; 23436857Sbostic int status, pid, w; 235*37133Sbostic 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())) { 246*37133Sbostic execlp(editor, p, temp, NULL); 247*37133Sbostic (void)fprintf(stderr, "vipw: %s: %s\n", editor, 248*37133Sbostic strerror(errno)); 24936857Sbostic _exit(127); 25036857Sbostic } 25136857Sbostic while ((w = wait(&status)) != pid && w != -1); 25236857Sbostic return(w == -1 || status); 25332668Sbostic } 254*37133Sbostic 255*37133Sbostic prompt() 256*37133Sbostic { 257*37133Sbostic register int c; 258*37133Sbostic 259*37133Sbostic for (;;) { 260*37133Sbostic (void)printf("re-edit the password file? [y]: "); 261*37133Sbostic (void)fflush(stdout); 262*37133Sbostic c = getchar(); 263*37133Sbostic if (c != EOF && c != (int)'\n') 264*37133Sbostic while (getchar() != (int)'\n'); 265*37133Sbostic return(c == (int)'n'); 266*37133Sbostic } 267*37133Sbostic /* NOTREACHED */ 268*37133Sbostic } 269*37133Sbostic 270*37133Sbostic stop(val) 271*37133Sbostic int val; 272*37133Sbostic { 273*37133Sbostic (void)fprintf(stderr, "%s unchanged.\n", passwd); 274*37133Sbostic (void)unlink(temp); 275*37133Sbostic exit(val); 276*37133Sbostic } 277