xref: /csrg-svn/usr.sbin/vipw/vipw.c (revision 31744)
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