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*36857Sbostic static char sccsid[] = "@(#)vipw.c 5.6 (Berkeley) 02/22/89"; 2633502Sbostic #endif /* not lint */ 2721186Sdist 28*36857Sbostic #include <sys/param.h> 2913736Ssam #include <sys/stat.h> 3032668Sbostic #include <sys/signal.h> 3113736Ssam #include <sys/file.h> 32*36857Sbostic #include <sys/time.h> 33*36857Sbostic #include <sys/resource.h> 34*36857Sbostic #include <errno.h> 35*36857Sbostic #include <pwd.h> 3613736Ssam #include <stdio.h> 3713736Ssam 3831744Sbostic main() 3913736Ssam { 40*36857Sbostic extern int errno; 41*36857Sbostic register int n, fd_passwd, fd; 42*36857Sbostic struct rlimit rlim; 4332668Sbostic struct stat s1, s2; 44*36857Sbostic char *fend, *passwd, *temp, *tend; 45*36857Sbostic char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN]; 46*36857Sbostic char *strerror(), *strcpy(); 4713736Ssam 4831744Sbostic (void)signal(SIGHUP, SIG_IGN); 4931744Sbostic (void)signal(SIGINT, SIG_IGN); 5031744Sbostic (void)signal(SIGQUIT, SIG_IGN); 51*36857Sbostic (void)signal(SIGTSTP, SIG_IGN); 5231744Sbostic 53*36857Sbostic rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; 54*36857Sbostic (void)setrlimit(RLIMIT_CPU, &rlim); 55*36857Sbostic (void)setrlimit(RLIMIT_FSIZE, &rlim); 56*36857Sbostic 5732668Sbostic (void)umask(0); 5831744Sbostic 59*36857Sbostic temp = _PATH_PTMP; 60*36857Sbostic if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) { 61*36857Sbostic if (errno == EEXIST) 62*36857Sbostic fprintf(stderr, "vipw: password file busy.\n"); 63*36857Sbostic else 64*36857Sbostic fprintf(stderr, 65*36857Sbostic "vipw: %s: %s\n", temp, strerror(errno)); 6631744Sbostic exit(1); 6731744Sbostic } 68*36857Sbostic passwd = _PATH_MASTERPASSWD; 69*36857Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 70*36857Sbostic fprintf(stderr, "vipw: %s: %s\n", passwd, strerror(errno)); 7113736Ssam exit(1); 7213736Ssam } 7331744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 74*36857Sbostic if (write(fd, buf, n) != n) 75*36857Sbostic goto syserr; 76*36857Sbostic 77*36857Sbostic if (n == -1 || close(fd_passwd) || fsync(fd) || 78*36857Sbostic fstat(fd, &s1) || close(fd)) { 79*36857Sbostic syserr: fprintf(stderr, "vipw: %s", strerror(errno)); 8013736Ssam goto bad; 8113736Ssam } 82*36857Sbostic 83*36857Sbostic if (edit(temp)) { 84*36857Sbostic fprintf(stderr, "vipw: edit failed"); 8513736Ssam goto bad; 8613736Ssam } 8731744Sbostic 88*36857Sbostic if (!freopen(temp, "r", stdin) || fstat(fileno(stdin), &s2) || 89*36857Sbostic !s2.st_size) { 90*36857Sbostic fprintf(stderr, "vipw: can't read temp file"); 9131744Sbostic goto bad; 9231744Sbostic } 9313736Ssam 9431744Sbostic if (s1.st_mtime == s2.st_mtime) { 9532668Sbostic fprintf(stderr, "vipw: %s unchanged.\n", passwd); 96*36857Sbostic (void)unlink(temp); 97*36857Sbostic exit(0); 9831744Sbostic } 99*36857Sbostic 100*36857Sbostic if (!check()) 10131744Sbostic goto bad; 102*36857Sbostic 103*36857Sbostic switch(fork()) { 104*36857Sbostic case 0: 105*36857Sbostic break; 106*36857Sbostic case -1: 107*36857Sbostic fprintf(stderr, "vipw: can't fork"); 108*36857Sbostic goto bad; 109*36857Sbostic /* NOTREACHED */ 110*36857Sbostic default: 111*36857Sbostic exit(0); 112*36857Sbostic /* NOTREACHED */ 11331744Sbostic } 11431744Sbostic 115*36857Sbostic if (makedb(temp)) { 116*36857Sbostic fprintf(stderr, "vipw: mkpasswd failed"); 117*36857Sbostic bad: fprintf(stderr, "; %s unchanged.\n", passwd); 118*36857Sbostic (void)unlink(temp); 119*36857Sbostic exit(1); 12013736Ssam } 121*36857Sbostic 122*36857Sbostic /* 123*36857Sbostic * possible race; have to rename four files, and someone could slip 124*36857Sbostic * in between them. LOCK_EX and rename the ``passwd.dir'' file first 125*36857Sbostic * so that getpwent(3) can't slip in; the lock should never fail and 126*36857Sbostic * it's unclear what to do if it does. Rename ``ptmp'' last so that 127*36857Sbostic * passwd/vipw/chpass can't slip in. 128*36857Sbostic */ 129*36857Sbostic (void)setpriority(PRIO_PROCESS, 0, -20); 130*36857Sbostic fend = strcpy(from, temp) + strlen(temp); 131*36857Sbostic tend = strcpy(to, passwd) + strlen(passwd); 132*36857Sbostic bcopy(".dir", fend, 5); 133*36857Sbostic bcopy(".dir", tend, 5); 134*36857Sbostic if ((fd = open(from, O_RDONLY, 0)) >= 0) 135*36857Sbostic (void)flock(fd, LOCK_EX); 136*36857Sbostic /* here we go... */ 137*36857Sbostic (void)rename(from, to); 138*36857Sbostic bcopy(".pag", fend, 5); 139*36857Sbostic bcopy(".pag", tend, 5); 140*36857Sbostic (void)rename(from, to); 141*36857Sbostic bcopy(".orig", fend, 6); 142*36857Sbostic (void)rename(from, _PATH_PASSWD); 143*36857Sbostic (void)rename(temp, passwd); 144*36857Sbostic /* done! */ 145*36857Sbostic exit(0); 14613736Ssam } 14715633Sralph 14832668Sbostic check() 14931744Sbostic { 15032668Sbostic register long id; 151*36857Sbostic register int lcnt, root; 152*36857Sbostic register char *p, *sh; 15332668Sbostic long atol(); 154*36857Sbostic char buf[1024], *getusershell(), *strsep(); 15531744Sbostic 156*36857Sbostic for (lcnt = 1; fgets(buf, sizeof(buf), stdin); ++lcnt) { 157*36857Sbostic /* skip lines that are too big */ 158*36857Sbostic if (!index(buf, '\n')) { 159*36857Sbostic fprintf(stderr, "vipw: line too long"); 160*36857Sbostic goto bad; 16132668Sbostic } 162*36857Sbostic if (!(p = strsep(buf, ":\n"))) /* login */ 163*36857Sbostic goto general; 164*36857Sbostic root = !strcmp(p, "root"); 165*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* passwd */ 166*36857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* uid */ 167*36857Sbostic goto general; 168*36857Sbostic id = atol(p); 169*36857Sbostic if (root && id) { 170*36857Sbostic fprintf(stderr, "vipw: root uid should be 0"); 17132668Sbostic goto bad; 172*36857Sbostic } 173*36857Sbostic if (id > USHRT_MAX) { 174*36857Sbostic fprintf(stderr, "vipw: %s > max uid value (%d)", 175*36857Sbostic p, USHRT_MAX); 17632668Sbostic goto bad; 17732668Sbostic } 178*36857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* gid */ 179*36857Sbostic goto general; 180*36857Sbostic id = atol(p); 18132668Sbostic if (id > USHRT_MAX) { 182*36857Sbostic fprintf(stderr, "vipw: %s > max gid value (%d)", 183*36857Sbostic p, USHRT_MAX); 18432668Sbostic goto bad; 18532668Sbostic } 186*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* class */ 187*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* change */ 188*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* expire */ 189*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* gecos */ 190*36857Sbostic (void)strsep((char *)NULL, ":\n"); /* directory */ 191*36857Sbostic if (!(p = strsep((char *)NULL, ":\n"))) /* shell */ 192*36857Sbostic goto general; 193*36857Sbostic if (root && *p) /* empty == /bin/sh */ 19432668Sbostic for (;;) 19532668Sbostic if (!(sh = getusershell())) { 196*36857Sbostic fprintf(stderr, 197*36857Sbostic "vipw: warning, unknown root shell."); 198*36857Sbostic break; 19932668Sbostic } 200*36857Sbostic else if (!strcmp(p, sh)) 20132668Sbostic break; 202*36857Sbostic if (strsep((char *)NULL, ":\n")) { /* too many */ 203*36857Sbostic general: fprintf(stderr, "vipw: corrupted entry"); 204*36857Sbostic bad: fprintf(stderr, "; line #%d", lcnt); 20532668Sbostic return(0); 20632668Sbostic } 20731744Sbostic } 20832668Sbostic return(1); 20931744Sbostic } 21031744Sbostic 21115633Sralph makedb(file) 21232668Sbostic char *file; 21315633Sralph { 21432668Sbostic int status, pid, w; 21515633Sralph 21631744Sbostic if (!(pid = vfork())) { 217*36857Sbostic execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL); 21815633Sralph _exit(127); 21915633Sralph } 22031744Sbostic while ((w = wait(&status)) != pid && w != -1); 221*36857Sbostic return(w == -1 || status); 22215633Sralph } 22332668Sbostic 224*36857Sbostic edit(file) 225*36857Sbostic char *file; 22632668Sbostic { 227*36857Sbostic int status, pid, w; 228*36857Sbostic char *p, *editor, *getenv(), *rindex(); 22932668Sbostic 230*36857Sbostic if (editor = getenv("EDITOR")) { 231*36857Sbostic if (p = rindex(editor, '/')) 232*36857Sbostic ++p; 233*36857Sbostic else 234*36857Sbostic p = editor; 235*36857Sbostic } 236*36857Sbostic else 237*36857Sbostic p = editor = "vi"; 238*36857Sbostic if (!(pid = vfork())) { 239*36857Sbostic execlp(editor, p, file, NULL); 240*36857Sbostic _exit(127); 241*36857Sbostic } 242*36857Sbostic while ((w = wait(&status)) != pid && w != -1); 243*36857Sbostic return(w == -1 || status); 24432668Sbostic } 245