121186Sdist /* 2*31744Sbostic * 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[] = 9*31744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1021186Sdist All rights reserved.\n"; 1121186Sdist #endif not lint 1213736Ssam 1321186Sdist #ifndef lint 14*31744Sbostic static char sccsid[] = "@(#)vipw.c 5.2 (Berkeley) 07/01/87"; 1521186Sdist #endif not lint 1621186Sdist 1713736Ssam #include <sys/types.h> 1813736Ssam #include <sys/stat.h> 1913736Ssam #include <sys/file.h> 2013736Ssam #include <stdio.h> 2113736Ssam #include <errno.h> 2213736Ssam #include <signal.h> 2313736Ssam 2413736Ssam /* 2513736Ssam * Password file editor with locking. 2613736Ssam */ 27*31744Sbostic static char *passwd = "/etc/passwd", 28*31744Sbostic buf[BUFSIZ]; 2913736Ssam 30*31744Sbostic main() 3113736Ssam { 32*31744Sbostic register int n, fd_passwd, fd_temp; 33*31744Sbostic static char *temp = "/etc/ptmp"; 34*31744Sbostic struct stat s1, s2; 35*31744Sbostic char *editor, 36*31744Sbostic *getenv(); 3713736Ssam 38*31744Sbostic (void)signal(SIGHUP, SIG_IGN); 39*31744Sbostic (void)signal(SIGINT, SIG_IGN); 40*31744Sbostic (void)signal(SIGQUIT, SIG_IGN); 41*31744Sbostic 42*31744Sbostic setbuf(stderr, (char *)NULL); 4314911Sralph umask(0); 44*31744Sbostic 45*31744Sbostic if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) { 46*31744Sbostic fprintf(stderr, "vipw: "); 47*31744Sbostic perror(passwd); 48*31744Sbostic exit(1); 49*31744Sbostic } 50*31744Sbostic if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) { 51*31744Sbostic extern int errno; 52*31744Sbostic 5313736Ssam if (errno == EEXIST) { 54*31744Sbostic fputs("vipw: password file busy\n", stderr); 5513736Ssam exit(1); 5613736Ssam } 57*31744Sbostic fprintf(stderr, "vipw: "); 58*31744Sbostic perror(temp); 5913736Ssam exit(1); 6013736Ssam } 61*31744Sbostic while ((n = read(fd_passwd, buf, sizeof(buf))) > 0) 62*31744Sbostic if (write(fd_temp, buf, n) != n) { 63*31744Sbostic perror("vipw: write"); 64*31744Sbostic goto bad; 65*31744Sbostic } 66*31744Sbostic if (n == -1) { 67*31744Sbostic perror("vipw: read"); 6813736Ssam goto bad; 6913736Ssam } 70*31744Sbostic (void)close(fd_passwd); 71*31744Sbostic if (fsync(fd_temp)) { 72*31744Sbostic perror("vipw: fsync"); 7313736Ssam goto bad; 7413736Ssam } 75*31744Sbostic if (fstat(fd_temp, &s1)) { 76*31744Sbostic perror("vipw: fstat"); 77*31744Sbostic goto bad; 78*31744Sbostic } 79*31744Sbostic (void)close(fd_temp); 80*31744Sbostic 81*31744Sbostic if (!(editor = getenv("EDITOR"))) 8213736Ssam editor = "vi"; 83*31744Sbostic (void)sprintf(buf, "%s %s", editor, temp); 84*31744Sbostic if (system(buf)) { 85*31744Sbostic perror("vipw: system"); 86*31744Sbostic goto bad; 87*31744Sbostic } 8813736Ssam 89*31744Sbostic if (!freopen(temp, "r", stdin)) { 90*31744Sbostic fprintf(stderr, "vipw: can't reopen temp file, %s unchanged\n", passwd); 91*31744Sbostic goto bad; 92*31744Sbostic } 93*31744Sbostic if (fstat(fileno(stdin), &s2)) { 94*31744Sbostic fprintf(stderr, "vipw: can't stat temp file, %s unchanged\n", passwd); 95*31744Sbostic goto bad; 96*31744Sbostic } 97*31744Sbostic if (s1.st_mtime == s2.st_mtime) { 98*31744Sbostic fprintf(stderr, "vipw: %s unchanged\n", passwd); 99*31744Sbostic goto bad; 100*31744Sbostic } 101*31744Sbostic if (!s2.st_size) { 102*31744Sbostic fprintf(stderr, "vipw: bad temp file, %s unchanged\n", passwd); 103*31744Sbostic goto bad; 104*31744Sbostic } 105*31744Sbostic if (checkroot()) { 106*31744Sbostic static char *temp_pag = "/etc/ptmp.pag", 107*31744Sbostic *temp_dir = "/etc/ptmp.dir", 108*31744Sbostic *passwd_pag = "/etc/passwd.pag", 109*31744Sbostic *passwd_dir = "/etc/passwd.dir"; 110*31744Sbostic 111*31744Sbostic if (makedb(temp) < 0) 112*31744Sbostic fputs("vipw: mkpasswd failed.\n", stderr); 113*31744Sbostic else if (rename(temp_pag, passwd_pag) < 0) { 114*31744Sbostic fprintf(stderr, "vipw: "); 115*31744Sbostic perror(temp_pag); 11613736Ssam } 117*31744Sbostic else if (rename(temp_dir, passwd_dir) < 0) { 118*31744Sbostic fprintf(stderr, "vipw: "); 119*31744Sbostic perror(temp_dir); 12013736Ssam } 121*31744Sbostic else if (rename(temp, passwd) < 0) { 122*31744Sbostic fprintf(stderr, "vipw: "); 123*31744Sbostic perror("rename"); 12413736Ssam } 125*31744Sbostic else 126*31744Sbostic exit(0); 127*31744Sbostic (void)unlink(temp_pag); 128*31744Sbostic (void)unlink(temp_dir); 12913736Ssam } 130*31744Sbostic bad: (void)unlink(temp); 13115166Sralph exit(1); 13213736Ssam } 13315633Sralph 134*31744Sbostic static 135*31744Sbostic checkroot() 136*31744Sbostic { 137*31744Sbostic register int cnt; 138*31744Sbostic register char *cp, *sh; 139*31744Sbostic char *getusershell(); 140*31744Sbostic 141*31744Sbostic while (gets(buf)) { 142*31744Sbostic if (strncmp(buf, "root:", sizeof("root:") - 1)) 143*31744Sbostic continue; 144*31744Sbostic /* skip password */ 145*31744Sbostic for (cp = buf + sizeof("root:") - 1; *cp && *cp != ':'; ++cp); 146*31744Sbostic if (!*cp || atoi(++cp)) /* uid exists && uid == 0 */ 147*31744Sbostic break; /* skip uid, gid, gcos, dir */ 148*31744Sbostic for (cnt = 0; *cp && cnt < 4; ++cp) 149*31744Sbostic if (*cp == ':') 150*31744Sbostic ++cnt; 151*31744Sbostic if (!*cp) 152*31744Sbostic break; 153*31744Sbostic while (sh = getusershell()) 154*31744Sbostic if (!strcmp(cp, sh)) 155*31744Sbostic return(1); 156*31744Sbostic fprintf(stderr, "vipw: illegal shell (%s) for root login, %s unchanged.\n", cp, passwd); 157*31744Sbostic return(0); 158*31744Sbostic } 159*31744Sbostic fprintf(stderr, "vipw: root login corrupted, %s unchanged.\n", passwd); 160*31744Sbostic return(0); 161*31744Sbostic } 162*31744Sbostic 163*31744Sbostic static 16415633Sralph makedb(file) 165*31744Sbostic char *file; 16615633Sralph { 167*31744Sbostic int status, pid, w; 16815633Sralph 169*31744Sbostic if (!(pid = vfork())) { 17015633Sralph execl("/etc/mkpasswd", "mkpasswd", file, 0); 17115633Sralph _exit(127); 17215633Sralph } 173*31744Sbostic while ((w = wait(&status)) != pid && w != -1); 174*31744Sbostic if (w == -1 || status) 175*31744Sbostic return(-1); 176*31744Sbostic return(0); 17715633Sralph } 178