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