121186Sdist /* 231744Sbostic * Copyright (c) 1987 Regents of the University of California. 321186Sdist * All rights reserved. The Berkeley software License Agreement 421186Sdist * specifies the terms and conditions for redistribution. 521186Sdist */ 621186Sdist 713736Ssam #ifndef lint 821186Sdist char copyright[] = 931744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1021186Sdist All rights reserved.\n"; 11*32668Sbostic #endif /* !lint */ 1213736Ssam 1321186Sdist #ifndef lint 14*32668Sbostic static char sccsid[] = "@(#)vipw.c 5.3 (Berkeley) 11/23/87"; 15*32668Sbostic #endif /* !lint */ 1621186Sdist 17*32668Sbostic #include <machine/machparam.h> 1813736Ssam #include <sys/types.h> 1913736Ssam #include <sys/stat.h> 20*32668Sbostic #include <sys/signal.h> 2113736Ssam #include <sys/file.h> 2213736Ssam #include <stdio.h> 2313736Ssam #include <errno.h> 2413736Ssam 2513736Ssam /* 2613736Ssam * Password file editor with locking. 2713736Ssam */ 28*32668Sbostic static char *passwd = "/etc/passwd", buf[BUFSIZ]; 2913736Ssam 3031744Sbostic main() 3113736Ssam { 32*32668Sbostic register int n, fd_passwd, fd_temp; 33*32668Sbostic static char *temp = "/etc/ptmp"; 34*32668Sbostic struct stat s1, s2; 35*32668Sbostic char *editor, *getenv(); 3613736Ssam 3731744Sbostic (void)signal(SIGHUP, SIG_IGN); 3831744Sbostic (void)signal(SIGINT, SIG_IGN); 3931744Sbostic (void)signal(SIGQUIT, SIG_IGN); 4031744Sbostic 4131744Sbostic setbuf(stderr, (char *)NULL); 42*32668Sbostic (void)umask(0); 4331744Sbostic 4431744Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 45*32668Sbostic fputs("vipw: ", stderr); 4631744Sbostic perror(passwd); 4731744Sbostic exit(1); 4831744Sbostic } 4931744Sbostic if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { 5031744Sbostic extern int errno; 5131744Sbostic 5213736Ssam if (errno == EEXIST) { 53*32668Sbostic fputs("vipw: password file busy.\n", stderr); 5413736Ssam exit(1); 5513736Ssam } 56*32668Sbostic fputs("vipw: ", stderr); 5731744Sbostic perror(temp); 5813736Ssam exit(1); 5913736Ssam } 6031744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 6131744Sbostic if (write(fd_temp, buf, n) != n) { 6231744Sbostic perror("vipw: write"); 6331744Sbostic goto bad; 6431744Sbostic } 6531744Sbostic if (n == -1) { 6631744Sbostic perror("vipw: read"); 6713736Ssam goto bad; 6813736Ssam } 6931744Sbostic (void)close(fd_passwd); 7031744Sbostic if (fsync(fd_temp)) { 7131744Sbostic perror("vipw: fsync"); 7213736Ssam goto bad; 7313736Ssam } 7431744Sbostic if (fstat(fd_temp, &s1)) { 7531744Sbostic perror("vipw: fstat"); 7631744Sbostic goto bad; 7731744Sbostic } 7831744Sbostic (void)close(fd_temp); 7931744Sbostic 8031744Sbostic if (!(editor = getenv("EDITOR"))) 8113736Ssam editor = "vi"; 8231744Sbostic (void)sprintf(buf, "%s %s", editor, temp); 8331744Sbostic if (system(buf)) { 8431744Sbostic perror("vipw: system"); 8531744Sbostic goto bad; 8631744Sbostic } 8713736Ssam 8831744Sbostic if (!freopen(temp, "r", stdin)) { 89*32668Sbostic fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd); 9031744Sbostic goto bad; 9131744Sbostic } 9231744Sbostic if (fstat(fileno(stdin), &s2)) { 93*32668Sbostic fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd); 9431744Sbostic goto bad; 9531744Sbostic } 9631744Sbostic if (s1.st_mtime == s2.st_mtime) { 97*32668Sbostic fprintf(stderr, "vipw: %s unchanged.\n", passwd); 9831744Sbostic goto bad; 9931744Sbostic } 10031744Sbostic if (!s2.st_size) { 101*32668Sbostic fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd); 10231744Sbostic goto bad; 10331744Sbostic } 104*32668Sbostic if (check()) { 10531744Sbostic static char *temp_pag = "/etc/ptmp.pag", 10631744Sbostic *temp_dir = "/etc/ptmp.dir", 10731744Sbostic *passwd_pag = "/etc/passwd.pag", 10831744Sbostic *passwd_dir = "/etc/passwd.dir"; 10931744Sbostic 11031744Sbostic if (makedb(temp) < 0) 11131744Sbostic fputs("vipw: mkpasswd failed.\n", stderr); 11231744Sbostic else if (rename(temp_pag, passwd_pag) < 0) { 11331744Sbostic fprintf(stderr, "vipw: "); 11431744Sbostic perror(temp_pag); 11513736Ssam } 11631744Sbostic else if (rename(temp_dir, passwd_dir) < 0) { 11731744Sbostic fprintf(stderr, "vipw: "); 11831744Sbostic perror(temp_dir); 11913736Ssam } 12031744Sbostic else if (rename(temp, passwd) < 0) { 12131744Sbostic fprintf(stderr, "vipw: "); 12231744Sbostic perror("rename"); 12313736Ssam } 12431744Sbostic else 12531744Sbostic exit(0); 12631744Sbostic (void)unlink(temp_pag); 12731744Sbostic (void)unlink(temp_dir); 12813736Ssam } 12931744Sbostic bad: (void)unlink(temp); 13015166Sralph exit(1); 13113736Ssam } 13215633Sralph 133*32668Sbostic #define CHN ((char *)NULL) 13431744Sbostic static 135*32668Sbostic check() 13631744Sbostic { 137*32668Sbostic register char *cp, *sh; 138*32668Sbostic register long id; 139*32668Sbostic register int root; 140*32668Sbostic long atol(); 141*32668Sbostic char *token(), *getusershell(); 14231744Sbostic 143*32668Sbostic for (root = 0; gets(buf); root = 0) { 144*32668Sbostic if (!*buf) { 145*32668Sbostic fputs("vipw: empty line.\n", stderr); 14631744Sbostic continue; 147*32668Sbostic } 148*32668Sbostic if (!(cp = token(buf)) || !*cp) /* login */ 149*32668Sbostic goto bad; 150*32668Sbostic if (!strcmp(cp, "root")) 151*32668Sbostic root = 1; 152*32668Sbostic (void)token(CHN); /* passwd */ 153*32668Sbostic if (!(cp = token(CHN)) || !*cp) /* uid */ 154*32668Sbostic goto bad; 155*32668Sbostic id = atol(cp); 156*32668Sbostic if (root && id) { 157*32668Sbostic fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd); 158*32668Sbostic return(0); 159*32668Sbostic } 160*32668Sbostic if (id > USHRT_MAX) { 161*32668Sbostic fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 162*32668Sbostic return(0); 163*32668Sbostic } 164*32668Sbostic if (!(cp = token(CHN)) || !*cp) /* gid */ 165*32668Sbostic goto bad; 166*32668Sbostic id = atol(cp); 167*32668Sbostic if (id > USHRT_MAX) { 168*32668Sbostic fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 169*32668Sbostic return(0); 170*32668Sbostic } 171*32668Sbostic (void)token(CHN); /* gcos */ 172*32668Sbostic if (!token(CHN)) /* home directory */ 173*32668Sbostic goto bad; 174*32668Sbostic if (!(cp = token(CHN))) /* shell */ 175*32668Sbostic goto bad; 176*32668Sbostic if (root && *cp) /* empty == /bin/sh */ 177*32668Sbostic for (;;) 178*32668Sbostic if (!(sh = getusershell())) { 179*32668Sbostic fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd); 180*32668Sbostic return(0); 181*32668Sbostic } 182*32668Sbostic else if (!strcmp(cp, sh)) 183*32668Sbostic break; 184*32668Sbostic if (token(CHN)) { /* too many fields */ 185*32668Sbostic bad: fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd); 186*32668Sbostic return(0); 187*32668Sbostic } 18831744Sbostic } 189*32668Sbostic return(1); 19031744Sbostic } 19131744Sbostic 19231744Sbostic static 19315633Sralph makedb(file) 194*32668Sbostic char *file; 19515633Sralph { 196*32668Sbostic int status, pid, w; 19715633Sralph 19831744Sbostic if (!(pid = vfork())) { 19915633Sralph execl("/etc/mkpasswd", "mkpasswd", file, 0); 20015633Sralph _exit(127); 20115633Sralph } 20231744Sbostic while ((w = wait(&status)) != pid && w != -1); 20331744Sbostic if (w == -1 || status) 20431744Sbostic return(-1); 20531744Sbostic return(0); 20615633Sralph } 207*32668Sbostic 208*32668Sbostic static char * 209*32668Sbostic token(bfr) 210*32668Sbostic char *bfr; 211*32668Sbostic { 212*32668Sbostic static char *cp; 213*32668Sbostic char *start; 214*32668Sbostic 215*32668Sbostic if (bfr) /* re-init string */ 216*32668Sbostic cp = bfr; 217*32668Sbostic else if (!cp) /* check if hit EOS last time */ 218*32668Sbostic return(CHN); 219*32668Sbostic else if (!bfr) /* start at next char after ':' */ 220*32668Sbostic ++cp; 221*32668Sbostic for (start = cp;; ++cp) 222*32668Sbostic if (!*cp) { /* found EOS; mark it for next time */ 223*32668Sbostic cp = CHN; 224*32668Sbostic break; 225*32668Sbostic } 226*32668Sbostic else if (*cp == ':') { /* found ':'; end token */ 227*32668Sbostic *cp = '\0'; 228*32668Sbostic break; 229*32668Sbostic } 230*32668Sbostic return(start); /* return token */ 231*32668Sbostic } 232