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 6*34778Sbostic * provided that the above copyright notice and this paragraph are 7*34778Sbostic * duplicated in all such forms and that any documentation, 8*34778Sbostic * advertising materials, and other materials related to such 9*34778Sbostic * distribution and use acknowledge that the software was developed 10*34778Sbostic * by the University of California, Berkeley. The name of the 11*34778Sbostic * University may not be used to endorse or promote products derived 12*34778Sbostic * from this software without specific prior written permission. 13*34778Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34778Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34778Sbostic * 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*34778Sbostic static char sccsid[] = "@(#)vipw.c 5.5 (Berkeley) 06/18/88"; 2633502Sbostic #endif /* not lint */ 2721186Sdist 2832668Sbostic #include <machine/machparam.h> 2913736Ssam #include <sys/types.h> 3013736Ssam #include <sys/stat.h> 3132668Sbostic #include <sys/signal.h> 3213736Ssam #include <sys/file.h> 3313736Ssam #include <stdio.h> 3413736Ssam #include <errno.h> 3513736Ssam 3613736Ssam /* 3713736Ssam * Password file editor with locking. 3813736Ssam */ 3932668Sbostic static char *passwd = "/etc/passwd", buf[BUFSIZ]; 4013736Ssam 4131744Sbostic main() 4213736Ssam { 4332668Sbostic register int n, fd_passwd, fd_temp; 4432668Sbostic static char *temp = "/etc/ptmp"; 4532668Sbostic struct stat s1, s2; 4633502Sbostic char *editor, *getenv(); 4713736Ssam 4831744Sbostic (void)signal(SIGHUP, SIG_IGN); 4931744Sbostic (void)signal(SIGINT, SIG_IGN); 5031744Sbostic (void)signal(SIGQUIT, SIG_IGN); 5131744Sbostic 5231744Sbostic setbuf(stderr, (char *)NULL); 5332668Sbostic (void)umask(0); 5431744Sbostic 5531744Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 5632668Sbostic fputs("vipw: ", stderr); 5731744Sbostic perror(passwd); 5831744Sbostic exit(1); 5931744Sbostic } 6031744Sbostic if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { 6131744Sbostic extern int errno; 6231744Sbostic 6313736Ssam if (errno == EEXIST) { 6432668Sbostic fputs("vipw: password file busy.\n", stderr); 6513736Ssam exit(1); 6613736Ssam } 6732668Sbostic fputs("vipw: ", stderr); 6831744Sbostic perror(temp); 6913736Ssam exit(1); 7013736Ssam } 7131744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 7231744Sbostic if (write(fd_temp, buf, n) != n) { 7331744Sbostic perror("vipw: write"); 7431744Sbostic goto bad; 7531744Sbostic } 7631744Sbostic if (n == -1) { 7731744Sbostic perror("vipw: read"); 7813736Ssam goto bad; 7913736Ssam } 8031744Sbostic (void)close(fd_passwd); 8131744Sbostic if (fsync(fd_temp)) { 8231744Sbostic perror("vipw: fsync"); 8313736Ssam goto bad; 8413736Ssam } 8531744Sbostic if (fstat(fd_temp, &s1)) { 8631744Sbostic perror("vipw: fstat"); 8731744Sbostic goto bad; 8831744Sbostic } 8931744Sbostic (void)close(fd_temp); 9031744Sbostic 9131744Sbostic if (!(editor = getenv("EDITOR"))) 9213736Ssam editor = "vi"; 9331744Sbostic (void)sprintf(buf, "%s %s", editor, temp); 9431744Sbostic if (system(buf)) { 9531744Sbostic perror("vipw: system"); 9631744Sbostic goto bad; 9731744Sbostic } 9813736Ssam 9931744Sbostic if (!freopen(temp, "r", stdin)) { 10032668Sbostic fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd); 10131744Sbostic goto bad; 10231744Sbostic } 10331744Sbostic if (fstat(fileno(stdin), &s2)) { 10432668Sbostic fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd); 10531744Sbostic goto bad; 10631744Sbostic } 10731744Sbostic if (s1.st_mtime == s2.st_mtime) { 10832668Sbostic fprintf(stderr, "vipw: %s unchanged.\n", passwd); 10931744Sbostic goto bad; 11031744Sbostic } 11131744Sbostic if (!s2.st_size) { 11232668Sbostic fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd); 11331744Sbostic goto bad; 11431744Sbostic } 11532668Sbostic if (check()) { 11631744Sbostic static char *temp_pag = "/etc/ptmp.pag", 11731744Sbostic *temp_dir = "/etc/ptmp.dir", 11831744Sbostic *passwd_pag = "/etc/passwd.pag", 11931744Sbostic *passwd_dir = "/etc/passwd.dir"; 12031744Sbostic 12131744Sbostic if (makedb(temp) < 0) 12231744Sbostic fputs("vipw: mkpasswd failed.\n", stderr); 12331744Sbostic else if (rename(temp_pag, passwd_pag) < 0) { 12431744Sbostic fprintf(stderr, "vipw: "); 12531744Sbostic perror(temp_pag); 12613736Ssam } 12731744Sbostic else if (rename(temp_dir, passwd_dir) < 0) { 12831744Sbostic fprintf(stderr, "vipw: "); 12931744Sbostic perror(temp_dir); 13013736Ssam } 13131744Sbostic else if (rename(temp, passwd) < 0) { 13231744Sbostic fprintf(stderr, "vipw: "); 13331744Sbostic perror("rename"); 13413736Ssam } 13531744Sbostic else 13631744Sbostic exit(0); 13731744Sbostic (void)unlink(temp_pag); 13831744Sbostic (void)unlink(temp_dir); 13913736Ssam } 14031744Sbostic bad: (void)unlink(temp); 14115166Sralph exit(1); 14213736Ssam } 14315633Sralph 14432668Sbostic #define CHN ((char *)NULL) 14531744Sbostic static 14632668Sbostic check() 14731744Sbostic { 14832668Sbostic register char *cp, *sh; 14932668Sbostic register long id; 15032668Sbostic register int root; 15132668Sbostic long atol(); 15232668Sbostic char *token(), *getusershell(); 15331744Sbostic 15432668Sbostic for (root = 0; gets(buf); root = 0) { 15532668Sbostic if (!*buf) { 15632668Sbostic fputs("vipw: empty line.\n", stderr); 15731744Sbostic continue; 15832668Sbostic } 15932668Sbostic if (!(cp = token(buf)) || !*cp) /* login */ 16032668Sbostic goto bad; 16132668Sbostic if (!strcmp(cp, "root")) 16232668Sbostic root = 1; 16332668Sbostic (void)token(CHN); /* passwd */ 16432668Sbostic if (!(cp = token(CHN)) || !*cp) /* uid */ 16532668Sbostic goto bad; 16632668Sbostic id = atol(cp); 16732668Sbostic if (root && id) { 16832668Sbostic fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd); 16932668Sbostic return(0); 17032668Sbostic } 17132668Sbostic if (id > USHRT_MAX) { 17232668Sbostic fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 17332668Sbostic return(0); 17432668Sbostic } 17532668Sbostic if (!(cp = token(CHN)) || !*cp) /* gid */ 17632668Sbostic goto bad; 17732668Sbostic id = atol(cp); 17832668Sbostic if (id > USHRT_MAX) { 17932668Sbostic fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd); 18032668Sbostic return(0); 18132668Sbostic } 18232668Sbostic (void)token(CHN); /* gcos */ 18332668Sbostic if (!token(CHN)) /* home directory */ 18432668Sbostic goto bad; 18532668Sbostic if (!(cp = token(CHN))) /* shell */ 18632668Sbostic goto bad; 18732668Sbostic if (root && *cp) /* empty == /bin/sh */ 18832668Sbostic for (;;) 18932668Sbostic if (!(sh = getusershell())) { 19032668Sbostic fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd); 19132668Sbostic return(0); 19232668Sbostic } 19332668Sbostic else if (!strcmp(cp, sh)) 19432668Sbostic break; 19532668Sbostic if (token(CHN)) { /* too many fields */ 19632668Sbostic bad: fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd); 19732668Sbostic return(0); 19832668Sbostic } 19931744Sbostic } 20032668Sbostic return(1); 20131744Sbostic } 20231744Sbostic 20331744Sbostic static 20415633Sralph makedb(file) 20532668Sbostic char *file; 20615633Sralph { 20732668Sbostic int status, pid, w; 20815633Sralph 20931744Sbostic if (!(pid = vfork())) { 21015633Sralph execl("/etc/mkpasswd", "mkpasswd", file, 0); 21115633Sralph _exit(127); 21215633Sralph } 21331744Sbostic while ((w = wait(&status)) != pid && w != -1); 21431744Sbostic if (w == -1 || status) 21531744Sbostic return(-1); 21631744Sbostic return(0); 21715633Sralph } 21832668Sbostic 21932668Sbostic static char * 22032668Sbostic token(bfr) 22132668Sbostic char *bfr; 22232668Sbostic { 22332668Sbostic static char *cp; 22432668Sbostic char *start; 22532668Sbostic 22632668Sbostic if (bfr) /* re-init string */ 22732668Sbostic cp = bfr; 22832668Sbostic else if (!cp) /* check if hit EOS last time */ 22932668Sbostic return(CHN); 23032668Sbostic else if (!bfr) /* start at next char after ':' */ 23132668Sbostic ++cp; 23232668Sbostic for (start = cp;; ++cp) 23332668Sbostic if (!*cp) { /* found EOS; mark it for next time */ 23432668Sbostic cp = CHN; 23532668Sbostic break; 23632668Sbostic } 23732668Sbostic else if (*cp == ':') { /* found ':'; end token */ 23832668Sbostic *cp = '\0'; 23932668Sbostic break; 24032668Sbostic } 24132668Sbostic return(start); /* return token */ 24232668Sbostic } 243