xref: /csrg-svn/usr.sbin/vipw/vipw.c (revision 33502)
121186Sdist /*
231744Sbostic  * Copyright (c) 1987 Regents of the University of California.
3*33502Sbostic  * All rights reserved.
4*33502Sbostic  *
5*33502Sbostic  * Redistribution and use in source and binary forms are permitted
6*33502Sbostic  * provided that this notice is preserved and that due credit is given
7*33502Sbostic  * to the University of California at Berkeley. The name of the University
8*33502Sbostic  * may not be used to endorse or promote products derived from this
9*33502Sbostic  * software without specific prior written permission. This software
10*33502Sbostic  * is provided ``as is'' without express or implied warranty.
1121186Sdist  */
1221186Sdist 
1313736Ssam #ifndef lint
1421186Sdist char copyright[] =
1531744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
1621186Sdist  All rights reserved.\n";
17*33502Sbostic #endif /* not lint */
1813736Ssam 
1921186Sdist #ifndef lint
20*33502Sbostic static char sccsid[] = "@(#)vipw.c	5.4 (Berkeley) 02/19/88";
21*33502Sbostic #endif /* not lint */
2221186Sdist 
2332668Sbostic #include <machine/machparam.h>
2413736Ssam #include <sys/types.h>
2513736Ssam #include <sys/stat.h>
2632668Sbostic #include <sys/signal.h>
2713736Ssam #include <sys/file.h>
2813736Ssam #include <stdio.h>
2913736Ssam #include <errno.h>
3013736Ssam 
3113736Ssam /*
3213736Ssam  * Password file editor with locking.
3313736Ssam  */
3432668Sbostic static char	*passwd = "/etc/passwd", buf[BUFSIZ];
3513736Ssam 
3631744Sbostic main()
3713736Ssam {
3832668Sbostic 	register int n, fd_passwd, fd_temp;
3932668Sbostic 	static char *temp = "/etc/ptmp";
4032668Sbostic 	struct stat s1, s2;
41*33502Sbostic 	char *editor, *getenv();
4213736Ssam 
4331744Sbostic 	(void)signal(SIGHUP, SIG_IGN);
4431744Sbostic 	(void)signal(SIGINT, SIG_IGN);
4531744Sbostic 	(void)signal(SIGQUIT, SIG_IGN);
4631744Sbostic 
4731744Sbostic 	setbuf(stderr, (char *)NULL);
4832668Sbostic 	(void)umask(0);
4931744Sbostic 
5031744Sbostic 	if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
5132668Sbostic 		fputs("vipw: ", stderr);
5231744Sbostic 		perror(passwd);
5331744Sbostic 		exit(1);
5431744Sbostic 	}
5531744Sbostic 	if ((fd_temp = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
5631744Sbostic 		extern int errno;
5731744Sbostic 
5813736Ssam 		if (errno == EEXIST) {
5932668Sbostic 			fputs("vipw: password file busy.\n", stderr);
6013736Ssam 			exit(1);
6113736Ssam 		}
6232668Sbostic 		fputs("vipw: ", stderr);
6331744Sbostic 		perror(temp);
6413736Ssam 		exit(1);
6513736Ssam 	}
6631744Sbostic 	while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
6731744Sbostic 		if (write(fd_temp, buf, n) != n) {
6831744Sbostic 			perror("vipw: write");
6931744Sbostic 			goto bad;
7031744Sbostic 		}
7131744Sbostic 	if (n == -1) {
7231744Sbostic 		perror("vipw: read");
7313736Ssam 		goto bad;
7413736Ssam 	}
7531744Sbostic 	(void)close(fd_passwd);
7631744Sbostic 	if (fsync(fd_temp)) {
7731744Sbostic 		perror("vipw: fsync");
7813736Ssam 		goto bad;
7913736Ssam 	}
8031744Sbostic 	if (fstat(fd_temp, &s1)) {
8131744Sbostic 		perror("vipw: fstat");
8231744Sbostic 		goto bad;
8331744Sbostic 	}
8431744Sbostic 	(void)close(fd_temp);
8531744Sbostic 
8631744Sbostic 	if (!(editor = getenv("EDITOR")))
8713736Ssam 		editor = "vi";
8831744Sbostic 	(void)sprintf(buf, "%s %s", editor, temp);
8931744Sbostic 	if (system(buf)) {
9031744Sbostic 		perror("vipw: system");
9131744Sbostic 		goto bad;
9231744Sbostic 	}
9313736Ssam 
9431744Sbostic 	if (!freopen(temp, "r", stdin)) {
9532668Sbostic 		fprintf(stderr, "vipw: can't reopen temp file; %s unchanged.\n", passwd);
9631744Sbostic 		goto bad;
9731744Sbostic 	}
9831744Sbostic 	if (fstat(fileno(stdin), &s2)) {
9932668Sbostic 		fprintf(stderr, "vipw: can't stat temp file; %s unchanged.\n", passwd);
10031744Sbostic 		goto bad;
10131744Sbostic 	}
10231744Sbostic 	if (s1.st_mtime == s2.st_mtime) {
10332668Sbostic 		fprintf(stderr, "vipw: %s unchanged.\n", passwd);
10431744Sbostic 		goto bad;
10531744Sbostic 	}
10631744Sbostic 	if (!s2.st_size) {
10732668Sbostic 		fprintf(stderr, "vipw: bad temp file; %s unchanged.\n", passwd);
10831744Sbostic 		goto bad;
10931744Sbostic 	}
11032668Sbostic 	if (check()) {
11131744Sbostic 		static char	*temp_pag = "/etc/ptmp.pag",
11231744Sbostic 				*temp_dir = "/etc/ptmp.dir",
11331744Sbostic 				*passwd_pag = "/etc/passwd.pag",
11431744Sbostic 				*passwd_dir = "/etc/passwd.dir";
11531744Sbostic 
11631744Sbostic 		if (makedb(temp) < 0)
11731744Sbostic 			fputs("vipw: mkpasswd failed.\n", stderr);
11831744Sbostic 		else if (rename(temp_pag, passwd_pag) < 0) {
11931744Sbostic 			fprintf(stderr, "vipw: ");
12031744Sbostic 			perror(temp_pag);
12113736Ssam 		}
12231744Sbostic 		else if (rename(temp_dir, passwd_dir) < 0) {
12331744Sbostic 			fprintf(stderr, "vipw: ");
12431744Sbostic 			perror(temp_dir);
12513736Ssam 		}
12631744Sbostic 		else if (rename(temp, passwd) < 0) {
12731744Sbostic 			fprintf(stderr, "vipw: ");
12831744Sbostic 			perror("rename");
12913736Ssam 		}
13031744Sbostic 		else
13131744Sbostic 			exit(0);
13231744Sbostic 		(void)unlink(temp_pag);
13331744Sbostic 		(void)unlink(temp_dir);
13413736Ssam 	}
13531744Sbostic bad:	(void)unlink(temp);
13615166Sralph 	exit(1);
13713736Ssam }
13815633Sralph 
13932668Sbostic #define	CHN	((char *)NULL)
14031744Sbostic static
14132668Sbostic check()
14231744Sbostic {
14332668Sbostic 	register char *cp, *sh;
14432668Sbostic 	register long id;
14532668Sbostic 	register int root;
14632668Sbostic 	long atol();
14732668Sbostic 	char *token(), *getusershell();
14831744Sbostic 
14932668Sbostic 	for (root = 0; gets(buf); root = 0) {
15032668Sbostic 		if (!*buf) {
15132668Sbostic 			fputs("vipw: empty line.\n", stderr);
15231744Sbostic 			continue;
15332668Sbostic 		}
15432668Sbostic 		if (!(cp = token(buf)) || !*cp)		/* login */
15532668Sbostic 			goto bad;
15632668Sbostic 		if (!strcmp(cp, "root"))
15732668Sbostic 			root = 1;
15832668Sbostic 		(void)token(CHN);			/* passwd */
15932668Sbostic 		if (!(cp = token(CHN)) || !*cp)		/* uid */
16032668Sbostic 			goto bad;
16132668Sbostic 		id = atol(cp);
16232668Sbostic 		if (root && id) {
16332668Sbostic 			fprintf(stderr, "vipw: root uid should be 0; %s unchanged.\n", passwd);
16432668Sbostic 			return(0);
16532668Sbostic 		}
16632668Sbostic 		if (id > USHRT_MAX) {
16732668Sbostic 			fprintf(stderr, "vipw: %s > max uid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd);
16832668Sbostic 			return(0);
16932668Sbostic 		}
17032668Sbostic 		if (!(cp = token(CHN)) || !*cp)		/* gid */
17132668Sbostic 			goto bad;
17232668Sbostic 		id = atol(cp);
17332668Sbostic 		if (id > USHRT_MAX) {
17432668Sbostic 			fprintf(stderr, "vipw: %s > max gid value (%u); %s unchanged.\n", cp, USHRT_MAX, passwd);
17532668Sbostic 			return(0);
17632668Sbostic 		}
17732668Sbostic 		(void)token(CHN);			/* gcos */
17832668Sbostic 		if (!token(CHN))			/* home directory */
17932668Sbostic 			goto bad;
18032668Sbostic 		if (!(cp = token(CHN)))			/* shell */
18132668Sbostic 			goto bad;
18232668Sbostic 		if (root && *cp)			/* empty == /bin/sh */
18332668Sbostic 			for (;;)
18432668Sbostic 				if (!(sh = getusershell())) {
18532668Sbostic 					fprintf(stderr, "vipw: illegal shell (%s) for root; %s unchanged.\n", cp, passwd);
18632668Sbostic 					return(0);
18732668Sbostic 				}
18832668Sbostic 				else if (!strcmp(cp, sh))
18932668Sbostic 					break;
19032668Sbostic 		if (token(CHN)) {			/* too many fields */
19132668Sbostic bad:			fprintf(stderr, "vipw: corrupted entry; %s unchanged.\n", passwd);
19232668Sbostic 			return(0);
19332668Sbostic 		}
19431744Sbostic 	}
19532668Sbostic 	return(1);
19631744Sbostic }
19731744Sbostic 
19831744Sbostic static
19915633Sralph makedb(file)
20032668Sbostic 	char *file;
20115633Sralph {
20232668Sbostic 	int status, pid, w;
20315633Sralph 
20431744Sbostic 	if (!(pid = vfork())) {
20515633Sralph 		execl("/etc/mkpasswd", "mkpasswd", file, 0);
20615633Sralph 		_exit(127);
20715633Sralph 	}
20831744Sbostic 	while ((w = wait(&status)) != pid && w != -1);
20931744Sbostic 	if (w == -1 || status)
21031744Sbostic 		return(-1);
21131744Sbostic 	return(0);
21215633Sralph }
21332668Sbostic 
21432668Sbostic static char *
21532668Sbostic token(bfr)
21632668Sbostic 	char *bfr;
21732668Sbostic {
21832668Sbostic 	static char *cp;
21932668Sbostic 	char *start;
22032668Sbostic 
22132668Sbostic 	if (bfr)			/* re-init string */
22232668Sbostic 		cp = bfr;
22332668Sbostic 	else if (!cp)			/* check if hit EOS last time */
22432668Sbostic 		return(CHN);
22532668Sbostic 	else if (!bfr)			/* start at next char after ':' */
22632668Sbostic 		++cp;
22732668Sbostic 	for (start = cp;; ++cp)
22832668Sbostic 		if (!*cp) {		/* found EOS; mark it for next time */
22932668Sbostic 			cp = CHN;
23032668Sbostic 			break;
23132668Sbostic 		}
23232668Sbostic 		else if (*cp == ':') {	/* found ':'; end token */
23332668Sbostic 			*cp = '\0';
23432668Sbostic 			break;
23532668Sbostic 		}
23632668Sbostic 	return(start);			/* return token */
23732668Sbostic }
238