xref: /csrg-svn/usr.sbin/vipw/vipw.c (revision 42713)
121186Sdist /*
231744Sbostic  * Copyright (c) 1987 Regents of the University of California.
333502Sbostic  * All rights reserved.
433502Sbostic  *
5*42713Sbostic  * %sccs.include.redist.c%
621186Sdist  */
721186Sdist 
813736Ssam #ifndef lint
921186Sdist char copyright[] =
1031744Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
1121186Sdist  All rights reserved.\n";
1233502Sbostic #endif /* not lint */
1313736Ssam 
1421186Sdist #ifndef lint
15*42713Sbostic static char sccsid[] = "@(#)vipw.c	5.14 (Berkeley) 06/01/90";
1633502Sbostic #endif /* not lint */
1721186Sdist 
1836857Sbostic #include <sys/param.h>
1913736Ssam #include <sys/stat.h>
2032668Sbostic #include <sys/signal.h>
2113736Ssam #include <sys/file.h>
2236857Sbostic #include <sys/time.h>
2336857Sbostic #include <sys/resource.h>
2436857Sbostic #include <errno.h>
2536857Sbostic #include <pwd.h>
2613736Ssam #include <stdio.h>
2742039Sbostic #include <string.h>
2813736Ssam 
2937133Sbostic char *passwd, *temp;
3037133Sbostic 
3131744Sbostic main()
3213736Ssam {
3336857Sbostic 	extern int errno;
3436857Sbostic 	register int n, fd_passwd, fd;
3536857Sbostic 	struct rlimit rlim;
3637197Sbostic 	struct stat s1, s2;
3737197Sbostic 	FILE *tfp;
3837133Sbostic 	char *fend, *tend;
3936857Sbostic 	char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
4013736Ssam 
4131744Sbostic 	(void)signal(SIGHUP, SIG_IGN);
4231744Sbostic 	(void)signal(SIGINT, SIG_IGN);
4331744Sbostic 	(void)signal(SIGQUIT, SIG_IGN);
4436857Sbostic 	(void)signal(SIGTSTP, SIG_IGN);
4531744Sbostic 
4636857Sbostic 	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
4736857Sbostic 	(void)setrlimit(RLIMIT_CPU, &rlim);
4836857Sbostic 	(void)setrlimit(RLIMIT_FSIZE, &rlim);
4936857Sbostic 
5032668Sbostic 	(void)umask(0);
5131744Sbostic 
5236857Sbostic 	temp = _PATH_PTMP;
5337468Sbostic 	if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
5436857Sbostic 		if (errno == EEXIST)
5537133Sbostic 			(void)fprintf(stderr, "vipw: password file busy.\n");
5636857Sbostic 		else
5737133Sbostic 			(void)fprintf(stderr,
5836857Sbostic 			    "vipw: %s: %s\n", temp, strerror(errno));
5931744Sbostic 		exit(1);
6031744Sbostic 	}
6136857Sbostic 	passwd = _PATH_MASTERPASSWD;
6236857Sbostic 	if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
6337133Sbostic 		(void)fprintf(stderr, "vipw: %s: %s\n", passwd,
6437133Sbostic 		    strerror(errno));
6513736Ssam 		exit(1);
6613736Ssam 	}
6731744Sbostic 	while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
6836857Sbostic 		if (write(fd, buf, n) != n)
6936857Sbostic 			goto syserr;
7036857Sbostic 
7137197Sbostic 	if (n == -1 || close(fd_passwd)) {
7237197Sbostic syserr:		(void)fprintf(stderr, "vipw: %s: %s; ",
7337197Sbostic 		    passwd, strerror(errno));
7437133Sbostic 		stop(1);
7513736Ssam 	}
7636857Sbostic 
7739127Sbostic 	(void)fstat(fd, &s1);
7839127Sbostic 	(void)close(fd);
7937133Sbostic 	for (;;) {
8037133Sbostic 		if (edit()) {
8137133Sbostic 			(void)fprintf(stderr, "vipw: edit failed; ");
8237133Sbostic 			stop(1);
8337133Sbostic 		}
8439127Sbostic 		/*
8539127Sbostic 		 * close and re-open the file each time we edit it; some
8639127Sbostic 		 * editors create a new physical file on each edit session.
8739127Sbostic 		 */
8839127Sbostic 		if (!(tfp = fopen(temp, "r"))) {
8939127Sbostic 			(void)fprintf(stderr, "vipw: %s: %s; ",
9039127Sbostic 			    temp, strerror(errno));
9139127Sbostic 			stop(1);
9239127Sbostic 		}
9339127Sbostic 		(void)fstat(fileno(tfp), &s2);
9437197Sbostic 		if (s1.st_mtime == s2.st_mtime) {
9537197Sbostic 			(void)fprintf(stderr, "vipw: no changes made; ");
9637197Sbostic 			stop(0);
9737197Sbostic 		}
9837197Sbostic 		if (!check(tfp))
9937133Sbostic 			break;
10037133Sbostic 		if (prompt())
10137133Sbostic 			stop(0);
10239127Sbostic 		(void)fstat(fileno(tfp), &s1);
10339127Sbostic 		(void)fclose(tfp);
10413736Ssam 	}
10531744Sbostic 
10636857Sbostic 	switch(fork()) {
10736857Sbostic 	case 0:
10836857Sbostic 		break;
10936857Sbostic 	case -1:
11037133Sbostic 		(void)fprintf(stderr, "vipw: can't fork; ");
11137133Sbostic 		stop(1);
11236857Sbostic 		/* NOTREACHED */
11336857Sbostic 	default:
11436857Sbostic 		exit(0);
11536857Sbostic 		/* NOTREACHED */
11631744Sbostic 	}
11731744Sbostic 
11836857Sbostic 	if (makedb(temp)) {
11937133Sbostic 		(void)fprintf(stderr, "vipw: mkpasswd failed; ");
12037133Sbostic 		stop(1);
12113736Ssam 	}
12236857Sbostic 
12336857Sbostic 	/*
12436857Sbostic 	 * possible race; have to rename four files, and someone could slip
12536857Sbostic 	 * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
12636857Sbostic 	 * so that getpwent(3) can't slip in; the lock should never fail and
12736857Sbostic 	 * it's unclear what to do if it does.  Rename ``ptmp'' last so that
12836857Sbostic 	 * passwd/vipw/chpass can't slip in.
12936857Sbostic 	 */
13036857Sbostic 	(void)setpriority(PRIO_PROCESS, 0, -20);
13136857Sbostic 	fend = strcpy(from, temp) + strlen(temp);
13237197Sbostic 	tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
13336857Sbostic 	bcopy(".dir", fend, 5);
13436857Sbostic 	bcopy(".dir", tend, 5);
13536857Sbostic 	if ((fd = open(from, O_RDONLY, 0)) >= 0)
13636857Sbostic 		(void)flock(fd, LOCK_EX);
13736857Sbostic 	/* here we go... */
13836857Sbostic 	(void)rename(from, to);
13936857Sbostic 	bcopy(".pag", fend, 5);
14036857Sbostic 	bcopy(".pag", tend, 5);
14136857Sbostic 	(void)rename(from, to);
14236857Sbostic 	bcopy(".orig", fend, 6);
14336857Sbostic 	(void)rename(from, _PATH_PASSWD);
14436857Sbostic 	(void)rename(temp, passwd);
14536857Sbostic 	/* done! */
14636857Sbostic 	exit(0);
14713736Ssam }
14815633Sralph 
14937197Sbostic check(tfp)
15037197Sbostic 	FILE *tfp;
15131744Sbostic {
15232668Sbostic 	register long id;
15336857Sbostic 	register int lcnt, root;
15436857Sbostic 	register char *p, *sh;
15532668Sbostic 	long atol();
15641570Smarc 	char buf[1024], *bp, *getusershell();
15731744Sbostic 
15837133Sbostic 	for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) {
15936857Sbostic 		/* skip lines that are too big */
16039886Sbostic 		if (!(p = index(buf, '\n'))) {
16137133Sbostic 			(void)fprintf(stderr, "vipw: line too long");
16236857Sbostic 			goto bad;
16332668Sbostic 		}
16439886Sbostic 		*p = '\0';
16541570Smarc 		bp = buf;
16641570Smarc 		if (!(p = strsep(&bp, ":")))		/* login */
16736857Sbostic 			goto general;
16836857Sbostic 		root = !strcmp(p, "root");
16941570Smarc 		(void)strsep(&bp, ":");	/* passwd */
17041570Smarc 		if (!(p = strsep(&bp, ":")))	/* uid */
17136857Sbostic 			goto general;
17236857Sbostic 		id = atol(p);
17336857Sbostic 		if (root && id) {
17437133Sbostic 			(void)fprintf(stderr, "vipw: root uid should be 0");
17532668Sbostic 			goto bad;
17636857Sbostic 		}
17736857Sbostic 		if (id > USHRT_MAX) {
17837133Sbostic 			(void)fprintf(stderr, "vipw: %s > max uid value (%d)",
17936857Sbostic 			    p, USHRT_MAX);
18032668Sbostic 			goto bad;
18132668Sbostic 		}
18241570Smarc 		if (!(p = strsep(&bp, ":")))	/* gid */
18336857Sbostic 			goto general;
18436857Sbostic 		id = atol(p);
18532668Sbostic 		if (id > USHRT_MAX) {
18637133Sbostic 			(void)fprintf(stderr, "vipw: %s > max gid value (%d)",
18736857Sbostic 			    p, USHRT_MAX);
18832668Sbostic 			goto bad;
18932668Sbostic 		}
19041570Smarc 		(void)strsep(&bp, ":");	/* class */
19141570Smarc 		(void)strsep(&bp, ":");	/* change */
19241570Smarc 		(void)strsep(&bp, ":");	/* expire */
19341570Smarc 		(void)strsep(&bp, ":");	/* gecos */
19441570Smarc 		(void)strsep(&bp, ":");	/* directory */
19541570Smarc 		if (!(p = strsep(&bp, ":")))	/* shell */
19636857Sbostic 			goto general;
19736857Sbostic 		if (root && *p)				/* empty == /bin/sh */
19837133Sbostic 			for (setusershell();;)
19932668Sbostic 				if (!(sh = getusershell())) {
20037133Sbostic 					(void)fprintf(stderr,
20137133Sbostic 					    "vipw: warning, unknown root shell.\n");
20236857Sbostic 					break;
20332668Sbostic 				}
20436857Sbostic 				else if (!strcmp(p, sh))
20532668Sbostic 					break;
20641570Smarc 		if (p = strsep(&bp, ":")) {	/* too many */
20739886Sbostic (void)fprintf(stderr, "got {%s}\n", p);
20837133Sbostic general:		(void)fprintf(stderr, "vipw: corrupted entry");
20937133Sbostic bad:			(void)fprintf(stderr, "; line #%d.\n", lcnt);
21037133Sbostic 			(void)fflush(stderr);
21137133Sbostic 			return(1);
21232668Sbostic 		}
21331744Sbostic 	}
21437133Sbostic 	return(0);
21531744Sbostic }
21631744Sbostic 
21715633Sralph makedb(file)
21832668Sbostic 	char *file;
21915633Sralph {
22032668Sbostic 	int status, pid, w;
22115633Sralph 
22231744Sbostic 	if (!(pid = vfork())) {
22336857Sbostic 		execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
22415633Sralph 		_exit(127);
22515633Sralph 	}
22631744Sbostic 	while ((w = wait(&status)) != pid && w != -1);
22736857Sbostic 	return(w == -1 || status);
22815633Sralph }
22932668Sbostic 
23037133Sbostic edit()
23132668Sbostic {
23237133Sbostic 	extern int errno;
23336857Sbostic 	int status, pid, w;
23437133Sbostic 	char *p, *editor, *getenv(), *strerror();
23532668Sbostic 
23636857Sbostic 	if (editor = getenv("EDITOR")) {
23736857Sbostic 		if (p = rindex(editor, '/'))
23836857Sbostic 			++p;
23936857Sbostic 		else
24036857Sbostic 			p = editor;
24136857Sbostic 	}
24236857Sbostic 	else
24336857Sbostic 		p = editor = "vi";
24436857Sbostic 	if (!(pid = vfork())) {
24537133Sbostic 		execlp(editor, p, temp, NULL);
24637133Sbostic 		(void)fprintf(stderr, "vipw: %s: %s\n", editor,
24737133Sbostic 		    strerror(errno));
24836857Sbostic 		_exit(127);
24936857Sbostic 	}
25036857Sbostic 	while ((w = wait(&status)) != pid && w != -1);
25136857Sbostic 	return(w == -1 || status);
25232668Sbostic }
25337133Sbostic 
25437133Sbostic prompt()
25537133Sbostic {
25637133Sbostic 	register int c;
25737133Sbostic 
25837133Sbostic 	for (;;) {
25937133Sbostic 		(void)printf("re-edit the password file? [y]: ");
26037133Sbostic 		(void)fflush(stdout);
26137133Sbostic 		c = getchar();
26237133Sbostic 		if (c != EOF && c != (int)'\n')
26337133Sbostic 			while (getchar() != (int)'\n');
26437133Sbostic 		return(c == (int)'n');
26537133Sbostic 	}
26637133Sbostic 	/* NOTREACHED */
26737133Sbostic }
26837133Sbostic 
26937133Sbostic stop(val)
27037133Sbostic 	int val;
27137133Sbostic {
27237133Sbostic 	(void)fprintf(stderr, "%s unchanged.\n", passwd);
27337133Sbostic 	(void)unlink(temp);
27437133Sbostic 	exit(val);
27537133Sbostic }
276