xref: /csrg-svn/usr.sbin/vipw/vipw.c (revision 36857)
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
634778Sbostic  * provided that the above copyright notice and this paragraph are
734778Sbostic  * duplicated in all such forms and that any documentation,
834778Sbostic  * advertising materials, and other materials related to such
934778Sbostic  * distribution and use acknowledge that the software was developed
1034778Sbostic  * by the University of California, Berkeley.  The name of the
1134778Sbostic  * University may not be used to endorse or promote products derived
1234778Sbostic  * from this software without specific prior written permission.
1334778Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434778Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534778Sbostic  * 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*36857Sbostic static char sccsid[] = "@(#)vipw.c	5.6 (Berkeley) 02/22/89";
2633502Sbostic #endif /* not lint */
2721186Sdist 
28*36857Sbostic #include <sys/param.h>
2913736Ssam #include <sys/stat.h>
3032668Sbostic #include <sys/signal.h>
3113736Ssam #include <sys/file.h>
32*36857Sbostic #include <sys/time.h>
33*36857Sbostic #include <sys/resource.h>
34*36857Sbostic #include <errno.h>
35*36857Sbostic #include <pwd.h>
3613736Ssam #include <stdio.h>
3713736Ssam 
3831744Sbostic main()
3913736Ssam {
40*36857Sbostic 	extern int errno;
41*36857Sbostic 	register int n, fd_passwd, fd;
42*36857Sbostic 	struct rlimit rlim;
4332668Sbostic 	struct stat s1, s2;
44*36857Sbostic 	char *fend, *passwd, *temp, *tend;
45*36857Sbostic 	char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
46*36857Sbostic 	char *strerror(), *strcpy();
4713736Ssam 
4831744Sbostic 	(void)signal(SIGHUP, SIG_IGN);
4931744Sbostic 	(void)signal(SIGINT, SIG_IGN);
5031744Sbostic 	(void)signal(SIGQUIT, SIG_IGN);
51*36857Sbostic 	(void)signal(SIGTSTP, SIG_IGN);
5231744Sbostic 
53*36857Sbostic 	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
54*36857Sbostic 	(void)setrlimit(RLIMIT_CPU, &rlim);
55*36857Sbostic 	(void)setrlimit(RLIMIT_FSIZE, &rlim);
56*36857Sbostic 
5732668Sbostic 	(void)umask(0);
5831744Sbostic 
59*36857Sbostic 	temp = _PATH_PTMP;
60*36857Sbostic 	if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
61*36857Sbostic 		if (errno == EEXIST)
62*36857Sbostic 			fprintf(stderr, "vipw: password file busy.\n");
63*36857Sbostic 		else
64*36857Sbostic 			fprintf(stderr,
65*36857Sbostic 			    "vipw: %s: %s\n", temp, strerror(errno));
6631744Sbostic 		exit(1);
6731744Sbostic 	}
68*36857Sbostic 	passwd = _PATH_MASTERPASSWD;
69*36857Sbostic 	if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
70*36857Sbostic 		fprintf(stderr, "vipw: %s: %s\n", passwd, strerror(errno));
7113736Ssam 		exit(1);
7213736Ssam 	}
7331744Sbostic 	while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
74*36857Sbostic 		if (write(fd, buf, n) != n)
75*36857Sbostic 			goto syserr;
76*36857Sbostic 
77*36857Sbostic 	if (n == -1 || close(fd_passwd) || fsync(fd) ||
78*36857Sbostic 	    fstat(fd, &s1) || close(fd)) {
79*36857Sbostic syserr:		fprintf(stderr, "vipw: %s", strerror(errno));
8013736Ssam 		goto bad;
8113736Ssam 	}
82*36857Sbostic 
83*36857Sbostic 	if (edit(temp)) {
84*36857Sbostic 		fprintf(stderr, "vipw: edit failed");
8513736Ssam 		goto bad;
8613736Ssam 	}
8731744Sbostic 
88*36857Sbostic 	if (!freopen(temp, "r", stdin) || fstat(fileno(stdin), &s2) ||
89*36857Sbostic 	    !s2.st_size) {
90*36857Sbostic 		fprintf(stderr, "vipw: can't read temp file");
9131744Sbostic 		goto bad;
9231744Sbostic 	}
9313736Ssam 
9431744Sbostic 	if (s1.st_mtime == s2.st_mtime) {
9532668Sbostic 		fprintf(stderr, "vipw: %s unchanged.\n", passwd);
96*36857Sbostic 		(void)unlink(temp);
97*36857Sbostic 		exit(0);
9831744Sbostic 	}
99*36857Sbostic 
100*36857Sbostic 	if (!check())
10131744Sbostic 		goto bad;
102*36857Sbostic 
103*36857Sbostic 	switch(fork()) {
104*36857Sbostic 	case 0:
105*36857Sbostic 		break;
106*36857Sbostic 	case -1:
107*36857Sbostic 		fprintf(stderr, "vipw: can't fork");
108*36857Sbostic 		goto bad;
109*36857Sbostic 		/* NOTREACHED */
110*36857Sbostic 	default:
111*36857Sbostic 		exit(0);
112*36857Sbostic 		/* NOTREACHED */
11331744Sbostic 	}
11431744Sbostic 
115*36857Sbostic 	if (makedb(temp)) {
116*36857Sbostic 		fprintf(stderr, "vipw: mkpasswd failed");
117*36857Sbostic bad:		fprintf(stderr, "; %s unchanged.\n", passwd);
118*36857Sbostic 		(void)unlink(temp);
119*36857Sbostic 		exit(1);
12013736Ssam 	}
121*36857Sbostic 
122*36857Sbostic 	/*
123*36857Sbostic 	 * possible race; have to rename four files, and someone could slip
124*36857Sbostic 	 * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
125*36857Sbostic 	 * so that getpwent(3) can't slip in; the lock should never fail and
126*36857Sbostic 	 * it's unclear what to do if it does.  Rename ``ptmp'' last so that
127*36857Sbostic 	 * passwd/vipw/chpass can't slip in.
128*36857Sbostic 	 */
129*36857Sbostic 	(void)setpriority(PRIO_PROCESS, 0, -20);
130*36857Sbostic 	fend = strcpy(from, temp) + strlen(temp);
131*36857Sbostic 	tend = strcpy(to, passwd) + strlen(passwd);
132*36857Sbostic 	bcopy(".dir", fend, 5);
133*36857Sbostic 	bcopy(".dir", tend, 5);
134*36857Sbostic 	if ((fd = open(from, O_RDONLY, 0)) >= 0)
135*36857Sbostic 		(void)flock(fd, LOCK_EX);
136*36857Sbostic 	/* here we go... */
137*36857Sbostic 	(void)rename(from, to);
138*36857Sbostic 	bcopy(".pag", fend, 5);
139*36857Sbostic 	bcopy(".pag", tend, 5);
140*36857Sbostic 	(void)rename(from, to);
141*36857Sbostic 	bcopy(".orig", fend, 6);
142*36857Sbostic 	(void)rename(from, _PATH_PASSWD);
143*36857Sbostic 	(void)rename(temp, passwd);
144*36857Sbostic 	/* done! */
145*36857Sbostic 	exit(0);
14613736Ssam }
14715633Sralph 
14832668Sbostic check()
14931744Sbostic {
15032668Sbostic 	register long id;
151*36857Sbostic 	register int lcnt, root;
152*36857Sbostic 	register char *p, *sh;
15332668Sbostic 	long atol();
154*36857Sbostic 	char buf[1024], *getusershell(), *strsep();
15531744Sbostic 
156*36857Sbostic 	for (lcnt = 1; fgets(buf, sizeof(buf), stdin); ++lcnt) {
157*36857Sbostic 		/* skip lines that are too big */
158*36857Sbostic 		if (!index(buf, '\n')) {
159*36857Sbostic 			fprintf(stderr, "vipw: line too long");
160*36857Sbostic 			goto bad;
16132668Sbostic 		}
162*36857Sbostic 		if (!(p = strsep(buf, ":\n")))		/* login */
163*36857Sbostic 			goto general;
164*36857Sbostic 		root = !strcmp(p, "root");
165*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* passwd */
166*36857Sbostic 		if (!(p = strsep((char *)NULL, ":\n")))	/* uid */
167*36857Sbostic 			goto general;
168*36857Sbostic 		id = atol(p);
169*36857Sbostic 		if (root && id) {
170*36857Sbostic 			fprintf(stderr, "vipw: root uid should be 0");
17132668Sbostic 			goto bad;
172*36857Sbostic 		}
173*36857Sbostic 		if (id > USHRT_MAX) {
174*36857Sbostic 			fprintf(stderr, "vipw: %s > max uid value (%d)",
175*36857Sbostic 			    p, USHRT_MAX);
17632668Sbostic 			goto bad;
17732668Sbostic 		}
178*36857Sbostic 		if (!(p = strsep((char *)NULL, ":\n")))	/* gid */
179*36857Sbostic 			goto general;
180*36857Sbostic 		id = atol(p);
18132668Sbostic 		if (id > USHRT_MAX) {
182*36857Sbostic 			fprintf(stderr, "vipw: %s > max gid value (%d)",
183*36857Sbostic 			    p, USHRT_MAX);
18432668Sbostic 			goto bad;
18532668Sbostic 		}
186*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* class */
187*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* change */
188*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* expire */
189*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* gecos */
190*36857Sbostic 		(void)strsep((char *)NULL, ":\n");	/* directory */
191*36857Sbostic 		if (!(p = strsep((char *)NULL, ":\n")))	/* shell */
192*36857Sbostic 			goto general;
193*36857Sbostic 		if (root && *p)				/* empty == /bin/sh */
19432668Sbostic 			for (;;)
19532668Sbostic 				if (!(sh = getusershell())) {
196*36857Sbostic 					fprintf(stderr,
197*36857Sbostic 					    "vipw: warning, unknown root shell.");
198*36857Sbostic 					break;
19932668Sbostic 				}
200*36857Sbostic 				else if (!strcmp(p, sh))
20132668Sbostic 					break;
202*36857Sbostic 		if (strsep((char *)NULL, ":\n")) {	/* too many */
203*36857Sbostic general:		fprintf(stderr, "vipw: corrupted entry");
204*36857Sbostic bad:			fprintf(stderr, "; line #%d", lcnt);
20532668Sbostic 			return(0);
20632668Sbostic 		}
20731744Sbostic 	}
20832668Sbostic 	return(1);
20931744Sbostic }
21031744Sbostic 
21115633Sralph makedb(file)
21232668Sbostic 	char *file;
21315633Sralph {
21432668Sbostic 	int status, pid, w;
21515633Sralph 
21631744Sbostic 	if (!(pid = vfork())) {
217*36857Sbostic 		execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
21815633Sralph 		_exit(127);
21915633Sralph 	}
22031744Sbostic 	while ((w = wait(&status)) != pid && w != -1);
221*36857Sbostic 	return(w == -1 || status);
22215633Sralph }
22332668Sbostic 
224*36857Sbostic edit(file)
225*36857Sbostic 	char *file;
22632668Sbostic {
227*36857Sbostic 	int status, pid, w;
228*36857Sbostic 	char *p, *editor, *getenv(), *rindex();
22932668Sbostic 
230*36857Sbostic 	if (editor = getenv("EDITOR")) {
231*36857Sbostic 		if (p = rindex(editor, '/'))
232*36857Sbostic 			++p;
233*36857Sbostic 		else
234*36857Sbostic 			p = editor;
235*36857Sbostic 	}
236*36857Sbostic 	else
237*36857Sbostic 		p = editor = "vi";
238*36857Sbostic 	if (!(pid = vfork())) {
239*36857Sbostic 		execlp(editor, p, file, NULL);
240*36857Sbostic 		_exit(127);
241*36857Sbostic 	}
242*36857Sbostic 	while ((w = wait(&status)) != pid && w != -1);
243*36857Sbostic 	return(w == -1 || status);
24432668Sbostic }
245