121186Sdist /* 231744Sbostic * Copyright (c) 1987 Regents of the University of California. 3*33502Sbostic * All rights reserved. 4*33502Sbostic * 5*33502Sbostic * Redistribution and use in source and binary forms are permitted 6*33502Sbostic * provided that this notice is preserved and that due credit is given 7*33502Sbostic * to the University of California at Berkeley. The name of the University 8*33502Sbostic * may not be used to endorse or promote products derived from this 9*33502Sbostic * software without specific prior written permission. This software 10*33502Sbostic * is provided ``as is'' without express or implied warranty. 1121186Sdist */ 1221186Sdist 1313736Ssam #ifndef lint 1421186Sdist char copyright[] = 1531744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1621186Sdist All rights reserved.\n"; 17*33502Sbostic #endif /* not lint */ 1813736Ssam 1921186Sdist #ifndef lint 20*33502Sbostic static char sccsid[] = "@(#)vipw.c 5.4 (Berkeley) 02/19/88"; 21*33502Sbostic #endif /* not lint */ 2221186Sdist 2332668Sbostic #include <machine/machparam.h> 2413736Ssam #include <sys/types.h> 2513736Ssam #include <sys/stat.h> 2632668Sbostic #include <sys/signal.h> 2713736Ssam #include <sys/file.h> 2813736Ssam #include <stdio.h> 2913736Ssam #include <errno.h> 3013736Ssam 3113736Ssam /* 3213736Ssam * Password file editor with locking. 3313736Ssam */ 3432668Sbostic static char *passwd = "/etc/passwd", buf[BUFSIZ]; 3513736Ssam 3631744Sbostic main() 3713736Ssam { 3832668Sbostic register int n, fd_passwd, fd_temp; 3932668Sbostic static char *temp = "/etc/ptmp"; 4032668Sbostic struct stat s1, s2; 41*33502Sbostic char *editor, *getenv(); 4213736Ssam 4331744Sbostic (void)signal(SIGHUP, SIG_IGN); 4431744Sbostic (void)signal(SIGINT, SIG_IGN); 4531744Sbostic (void)signal(SIGQUIT, SIG_IGN); 4631744Sbostic 4731744Sbostic setbuf(stderr, (char *)NULL); 4832668Sbostic (void)umask(0); 4931744Sbostic 5031744Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 5132668Sbostic fputs("vipw: ", stderr); 5231744Sbostic perror(passwd); 5331744Sbostic exit(1); 5431744Sbostic } 5531744Sbostic if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { 5631744Sbostic extern int errno; 5731744Sbostic 5813736Ssam if (errno == EEXIST) { 5932668Sbostic fputs("vipw: password file busy.\n", stderr); 6013736Ssam exit(1); 6113736Ssam } 6232668Sbostic fputs("vipw: ", stderr); 6331744Sbostic perror(temp); 6413736Ssam exit(1); 6513736Ssam } 6631744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 6731744Sbostic if (write(fd_temp, buf, n) != n) { 6831744Sbostic perror("vipw: write"); 6931744Sbostic goto bad; 7031744Sbostic } 7131744Sbostic if (n == -1) { 7231744Sbostic perror("vipw: read"); 7313736Ssam goto bad; 7413736Ssam } 7531744Sbostic (void)close(fd_passwd); 7631744Sbostic if (fsync(fd_temp)) { 7731744Sbostic perror("vipw: fsync"); 7813736Ssam goto bad; 7913736Ssam } 8031744Sbostic if (fstat(fd_temp, &s1)) { 8131744Sbostic perror("vipw: fstat"); 8231744Sbostic goto bad; 8331744Sbostic } 8431744Sbostic (void)close(fd_temp); 8531744Sbostic 8631744Sbostic if (!(editor = getenv("EDITOR"))) 8713736Ssam editor = "vi"; 8831744Sbostic (void)sprintf(buf, "%s %s", editor, temp); 8931744Sbostic if (system(buf)) { 9031744Sbostic perror("vipw: system"); 9131744Sbostic goto bad; 9231744Sbostic } 9313736Ssam 9431744Sbostic if (!freopen(temp, "r", stdin)) { 9532668Sbostic fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd); 9631744Sbostic goto bad; 9731744Sbostic } 9831744Sbostic if (fstat(fileno(stdin), &s2)) { 9932668Sbostic fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd); 10031744Sbostic goto bad; 10131744Sbostic } 10231744Sbostic if (s1.st_mtime == s2.st_mtime) { 10332668Sbostic fprintf(stderr, "vipw: %s unchanged.\n", passwd); 10431744Sbostic goto bad; 10531744Sbostic } 10631744Sbostic if (!s2.st_size) { 10732668Sbostic fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd); 10831744Sbostic goto bad; 10931744Sbostic } 11032668Sbostic if (check()) { 11131744Sbostic static char *temp_pag = "/etc/ptmp.pag", 11231744Sbostic *temp_dir = "/etc/ptmp.dir", 11331744Sbostic *passwd_pag = "/etc/passwd.pag", 11431744Sbostic *passwd_dir = "/etc/passwd.dir"; 11531744Sbostic 11631744Sbostic if (makedb(temp) < 0) 11731744Sbostic fputs("vipw: mkpasswd failed.\n", stderr); 11831744Sbostic else if (rename(temp_pag, passwd_pag) < 0) { 11931744Sbostic fprintf(stderr, "vipw: "); 12031744Sbostic perror(temp_pag); 12113736Ssam } 12231744Sbostic else if (rename(temp_dir, passwd_dir) < 0) { 12331744Sbostic fprintf(stderr, "vipw: "); 12431744Sbostic perror(temp_dir); 12513736Ssam } 12631744Sbostic else if (rename(temp, passwd) < 0) { 12731744Sbostic fprintf(stderr, "vipw: "); 12831744Sbostic perror("rename"); 12913736Ssam } 13031744Sbostic else 13131744Sbostic exit(0); 13231744Sbostic (void)unlink(temp_pag); 13331744Sbostic (void)unlink(temp_dir); 13413736Ssam } 13531744Sbostic bad: (void)unlink(temp); 13615166Sralph exit(1); 13713736Ssam } 13815633Sralph 13932668Sbostic #define CHN ((char *)NULL) 14031744Sbostic static 14132668Sbostic check() 14231744Sbostic { 14332668Sbostic register char *cp, *sh; 14432668Sbostic register long id; 14532668Sbostic register int root; 14632668Sbostic long atol(); 14732668Sbostic char *token(), *getusershell(); 14831744Sbostic 14932668Sbostic for (root = 0; gets(buf); root = 0) { 15032668Sbostic if (!*buf) { 15132668Sbostic fputs("vipw: empty line.\n", stderr); 15231744Sbostic continue; 15332668Sbostic } 15432668Sbostic if (!(cp = token(buf)) || !*cp) /* login */ 15532668Sbostic goto bad; 15632668Sbostic if (!strcmp(cp, "root")) 15732668Sbostic root = 1; 15832668Sbostic (void)token(CHN); /* passwd */ 15932668Sbostic if (!(cp = token(CHN)) || !*cp) /* uid */ 16032668Sbostic goto bad; 16132668Sbostic id = atol(cp); 16232668Sbostic if (root && id) { 16332668Sbostic fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd); 16432668Sbostic return(0); 16532668Sbostic } 16632668Sbostic if (id > USHRT_MAX) { 16732668Sbostic fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 16832668Sbostic return(0); 16932668Sbostic } 17032668Sbostic if (!(cp = token(CHN)) || !*cp) /* gid */ 17132668Sbostic goto bad; 17232668Sbostic id = atol(cp); 17332668Sbostic if (id > USHRT_MAX) { 17432668Sbostic fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 17532668Sbostic return(0); 17632668Sbostic } 17732668Sbostic (void)token(CHN); /* gcos */ 17832668Sbostic if (!token(CHN)) /* home directory */ 17932668Sbostic goto bad; 18032668Sbostic if (!(cp = token(CHN))) /* shell */ 18132668Sbostic goto bad; 18232668Sbostic if (root && *cp) /* empty == /bin/sh */ 18332668Sbostic for (;;) 18432668Sbostic if (!(sh = getusershell())) { 18532668Sbostic fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd); 18632668Sbostic return(0); 18732668Sbostic } 18832668Sbostic else if (!strcmp(cp, sh)) 18932668Sbostic break; 19032668Sbostic if (token(CHN)) { /* too many fields */ 19132668Sbostic bad: fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd); 19232668Sbostic return(0); 19332668Sbostic } 19431744Sbostic } 19532668Sbostic return(1); 19631744Sbostic } 19731744Sbostic 19831744Sbostic static 19915633Sralph makedb(file) 20032668Sbostic char *file; 20115633Sralph { 20232668Sbostic int status, pid, w; 20315633Sralph 20431744Sbostic if (!(pid = vfork())) { 20515633Sralph execl("/etc/mkpasswd", "mkpasswd", file, 0); 20615633Sralph _exit(127); 20715633Sralph } 20831744Sbostic while ((w = wait(&status)) != pid && w != -1); 20931744Sbostic if (w == -1 || status) 21031744Sbostic return(-1); 21131744Sbostic return(0); 21215633Sralph } 21332668Sbostic 21432668Sbostic static char * 21532668Sbostic token(bfr) 21632668Sbostic char *bfr; 21732668Sbostic { 21832668Sbostic static char *cp; 21932668Sbostic char *start; 22032668Sbostic 22132668Sbostic if (bfr) /* re-init string */ 22232668Sbostic cp = bfr; 22332668Sbostic else if (!cp) /* check if hit EOS last time */ 22432668Sbostic return(CHN); 22532668Sbostic else if (!bfr) /* start at next char after ':' */ 22632668Sbostic ++cp; 22732668Sbostic for (start = cp;; ++cp) 22832668Sbostic if (!*cp) { /* found EOS; mark it for next time */ 22932668Sbostic cp = CHN; 23032668Sbostic break; 23132668Sbostic } 23232668Sbostic else if (*cp == ':') { /* found ':'; end token */ 23332668Sbostic *cp = '\0'; 23432668Sbostic break; 23532668Sbostic } 23632668Sbostic return(start); /* return token */ 23732668Sbostic } 238