xref: /csrg-svn/usr.sbin/vipw/vipw.c (revision 39886)
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*39886Sbostic static char sccsid[] = "@(#)vipw.c	5.11 (Berkeley) 01/05/90";
2633502Sbostic #endif /* not lint */
2721186Sdist 
2836857Sbostic #include <sys/param.h>
2913736Ssam #include <sys/stat.h>
3032668Sbostic #include <sys/signal.h>
3113736Ssam #include <sys/file.h>
3236857Sbostic #include <sys/time.h>
3336857Sbostic #include <sys/resource.h>
3436857Sbostic #include <errno.h>
3536857Sbostic #include <pwd.h>
3613736Ssam #include <stdio.h>
3737133Sbostic #include <strings.h>
3813736Ssam 
3937133Sbostic char *passwd, *temp;
4037133Sbostic 
4131744Sbostic main()
4213736Ssam {
4336857Sbostic 	extern int errno;
4436857Sbostic 	register int n, fd_passwd, fd;
4536857Sbostic 	struct rlimit rlim;
4637197Sbostic 	struct stat s1, s2;
4737197Sbostic 	FILE *tfp;
4837133Sbostic 	char *fend, *tend;
4936857Sbostic 	char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
5013736Ssam 
5131744Sbostic 	(void)signal(SIGHUP, SIG_IGN);
5231744Sbostic 	(void)signal(SIGINT, SIG_IGN);
5331744Sbostic 	(void)signal(SIGQUIT, SIG_IGN);
5436857Sbostic 	(void)signal(SIGTSTP, SIG_IGN);
5531744Sbostic 
5636857Sbostic 	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
5736857Sbostic 	(void)setrlimit(RLIMIT_CPU, &rlim);
5836857Sbostic 	(void)setrlimit(RLIMIT_FSIZE, &rlim);
5936857Sbostic 
6032668Sbostic 	(void)umask(0);
6131744Sbostic 
6236857Sbostic 	temp = _PATH_PTMP;
6337468Sbostic 	if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
6436857Sbostic 		if (errno == EEXIST)
6537133Sbostic 			(void)fprintf(stderr, "vipw: password file busy.\n");
6636857Sbostic 		else
6737133Sbostic 			(void)fprintf(stderr,
6836857Sbostic 			    "vipw: %s: %s\n", temp, strerror(errno));
6931744Sbostic 		exit(1);
7031744Sbostic 	}
7136857Sbostic 	passwd = _PATH_MASTERPASSWD;
7236857Sbostic 	if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
7337133Sbostic 		(void)fprintf(stderr, "vipw: %s: %s\n", passwd,
7437133Sbostic 		    strerror(errno));
7513736Ssam 		exit(1);
7613736Ssam 	}
7731744Sbostic 	while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
7836857Sbostic 		if (write(fd, buf, n) != n)
7936857Sbostic 			goto syserr;
8036857Sbostic 
8137197Sbostic 	if (n == -1 || close(fd_passwd)) {
8237197Sbostic syserr:		(void)fprintf(stderr, "vipw: %s: %s; ",
8337197Sbostic 		    passwd, strerror(errno));
8437133Sbostic 		stop(1);
8513736Ssam 	}
8636857Sbostic 
8739127Sbostic 	(void)fstat(fd, &s1);
8839127Sbostic 	(void)close(fd);
8937133Sbostic 	for (;;) {
9037133Sbostic 		if (edit()) {
9137133Sbostic 			(void)fprintf(stderr, "vipw: edit failed; ");
9237133Sbostic 			stop(1);
9337133Sbostic 		}
9439127Sbostic 		/*
9539127Sbostic 		 * close and re-open the file each time we edit it; some
9639127Sbostic 		 * editors create a new physical file on each edit session.
9739127Sbostic 		 */
9839127Sbostic 		if (!(tfp = fopen(temp, "r"))) {
9939127Sbostic 			(void)fprintf(stderr, "vipw: %s: %s; ",
10039127Sbostic 			    temp, strerror(errno));
10139127Sbostic 			stop(1);
10239127Sbostic 		}
10339127Sbostic 		(void)fstat(fileno(tfp), &s2);
10437197Sbostic 		if (s1.st_mtime == s2.st_mtime) {
10537197Sbostic 			(void)fprintf(stderr, "vipw: no changes made; ");
10637197Sbostic 			stop(0);
10737197Sbostic 		}
10837197Sbostic 		if (!check(tfp))
10937133Sbostic 			break;
11037133Sbostic 		if (prompt())
11137133Sbostic 			stop(0);
11239127Sbostic 		(void)fstat(fileno(tfp), &s1);
11339127Sbostic 		(void)fclose(tfp);
11413736Ssam 	}
11531744Sbostic 
11636857Sbostic 	switch(fork()) {
11736857Sbostic 	case 0:
11836857Sbostic 		break;
11936857Sbostic 	case -1:
12037133Sbostic 		(void)fprintf(stderr, "vipw: can't fork; ");
12137133Sbostic 		stop(1);
12236857Sbostic 		/* NOTREACHED */
12336857Sbostic 	default:
12436857Sbostic 		exit(0);
12536857Sbostic 		/* NOTREACHED */
12631744Sbostic 	}
12731744Sbostic 
12836857Sbostic 	if (makedb(temp)) {
12937133Sbostic 		(void)fprintf(stderr, "vipw: mkpasswd failed; ");
13037133Sbostic 		stop(1);
13113736Ssam 	}
13236857Sbostic 
13336857Sbostic 	/*
13436857Sbostic 	 * possible race; have to rename four files, and someone could slip
13536857Sbostic 	 * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
13636857Sbostic 	 * so that getpwent(3) can't slip in; the lock should never fail and
13736857Sbostic 	 * it's unclear what to do if it does.  Rename ``ptmp'' last so that
13836857Sbostic 	 * passwd/vipw/chpass can't slip in.
13936857Sbostic 	 */
14036857Sbostic 	(void)setpriority(PRIO_PROCESS, 0, -20);
14136857Sbostic 	fend = strcpy(from, temp) + strlen(temp);
14237197Sbostic 	tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
14336857Sbostic 	bcopy(".dir", fend, 5);
14436857Sbostic 	bcopy(".dir", tend, 5);
14536857Sbostic 	if ((fd = open(from, O_RDONLY, 0)) >= 0)
14636857Sbostic 		(void)flock(fd, LOCK_EX);
14736857Sbostic 	/* here we go... */
14836857Sbostic 	(void)rename(from, to);
14936857Sbostic 	bcopy(".pag", fend, 5);
15036857Sbostic 	bcopy(".pag", tend, 5);
15136857Sbostic 	(void)rename(from, to);
15236857Sbostic 	bcopy(".orig", fend, 6);
15336857Sbostic 	(void)rename(from, _PATH_PASSWD);
15436857Sbostic 	(void)rename(temp, passwd);
15536857Sbostic 	/* done! */
15636857Sbostic 	exit(0);
15713736Ssam }
15815633Sralph 
15937197Sbostic check(tfp)
16037197Sbostic 	FILE *tfp;
16131744Sbostic {
16232668Sbostic 	register long id;
16336857Sbostic 	register int lcnt, root;
16436857Sbostic 	register char *p, *sh;
16532668Sbostic 	long atol();
16637133Sbostic 	char buf[1024], *getusershell();
16731744Sbostic 
16837133Sbostic 	for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) {
16936857Sbostic 		/* skip lines that are too big */
170*39886Sbostic 		if (!(p = index(buf, '\n'))) {
17137133Sbostic 			(void)fprintf(stderr, "vipw: line too long");
17236857Sbostic 			goto bad;
17332668Sbostic 		}
174*39886Sbostic 		*p = '\0';
175*39886Sbostic 		if (!(p = strsep(buf, ":")))		/* login */
17636857Sbostic 			goto general;
17736857Sbostic 		root = !strcmp(p, "root");
178*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* passwd */
179*39886Sbostic 		if (!(p = strsep((char *)NULL, ":")))	/* uid */
18036857Sbostic 			goto general;
18136857Sbostic 		id = atol(p);
18236857Sbostic 		if (root && id) {
18337133Sbostic 			(void)fprintf(stderr, "vipw: root uid should be 0");
18432668Sbostic 			goto bad;
18536857Sbostic 		}
18636857Sbostic 		if (id > USHRT_MAX) {
18737133Sbostic 			(void)fprintf(stderr, "vipw: %s > max uid value (%d)",
18836857Sbostic 			    p, USHRT_MAX);
18932668Sbostic 			goto bad;
19032668Sbostic 		}
191*39886Sbostic 		if (!(p = strsep((char *)NULL, ":")))	/* gid */
19236857Sbostic 			goto general;
19336857Sbostic 		id = atol(p);
19432668Sbostic 		if (id > USHRT_MAX) {
19537133Sbostic 			(void)fprintf(stderr, "vipw: %s > max gid value (%d)",
19636857Sbostic 			    p, USHRT_MAX);
19732668Sbostic 			goto bad;
19832668Sbostic 		}
199*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* class */
200*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* change */
201*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* expire */
202*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* gecos */
203*39886Sbostic 		(void)strsep((char *)NULL, ":");	/* directory */
204*39886Sbostic 		if (!(p = strsep((char *)NULL, ":")))	/* shell */
20536857Sbostic 			goto general;
20636857Sbostic 		if (root && *p)				/* empty == /bin/sh */
20737133Sbostic 			for (setusershell();;)
20832668Sbostic 				if (!(sh = getusershell())) {
20937133Sbostic 					(void)fprintf(stderr,
21037133Sbostic 					    "vipw: warning, unknown root shell.\n");
21136857Sbostic 					break;
21232668Sbostic 				}
21336857Sbostic 				else if (!strcmp(p, sh))
21432668Sbostic 					break;
215*39886Sbostic 		if (p = strsep((char *)NULL, ":")) {	/* too many */
216*39886Sbostic (void)fprintf(stderr, "got {%s}\n", p);
21737133Sbostic general:		(void)fprintf(stderr, "vipw: corrupted entry");
21837133Sbostic bad:			(void)fprintf(stderr, "; line #%d.\n", lcnt);
21937133Sbostic 			(void)fflush(stderr);
22037133Sbostic 			return(1);
22132668Sbostic 		}
22231744Sbostic 	}
22337133Sbostic 	return(0);
22431744Sbostic }
22531744Sbostic 
22615633Sralph makedb(file)
22732668Sbostic 	char *file;
22815633Sralph {
22932668Sbostic 	int status, pid, w;
23015633Sralph 
23131744Sbostic 	if (!(pid = vfork())) {
23236857Sbostic 		execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
23315633Sralph 		_exit(127);
23415633Sralph 	}
23531744Sbostic 	while ((w = wait(&status)) != pid && w != -1);
23636857Sbostic 	return(w == -1 || status);
23715633Sralph }
23832668Sbostic 
23937133Sbostic edit()
24032668Sbostic {
24137133Sbostic 	extern int errno;
24236857Sbostic 	int status, pid, w;
24337133Sbostic 	char *p, *editor, *getenv(), *strerror();
24432668Sbostic 
24536857Sbostic 	if (editor = getenv("EDITOR")) {
24636857Sbostic 		if (p = rindex(editor, '/'))
24736857Sbostic 			++p;
24836857Sbostic 		else
24936857Sbostic 			p = editor;
25036857Sbostic 	}
25136857Sbostic 	else
25236857Sbostic 		p = editor = "vi";
25336857Sbostic 	if (!(pid = vfork())) {
25437133Sbostic 		execlp(editor, p, temp, NULL);
25537133Sbostic 		(void)fprintf(stderr, "vipw: %s: %s\n", editor,
25637133Sbostic 		    strerror(errno));
25736857Sbostic 		_exit(127);
25836857Sbostic 	}
25936857Sbostic 	while ((w = wait(&status)) != pid && w != -1);
26036857Sbostic 	return(w == -1 || status);
26132668Sbostic }
26237133Sbostic 
26337133Sbostic prompt()
26437133Sbostic {
26537133Sbostic 	register int c;
26637133Sbostic 
26737133Sbostic 	for (;;) {
26837133Sbostic 		(void)printf("re-edit the password file? [y]: ");
26937133Sbostic 		(void)fflush(stdout);
27037133Sbostic 		c = getchar();
27137133Sbostic 		if (c != EOF && c != (int)'\n')
27237133Sbostic 			while (getchar() != (int)'\n');
27337133Sbostic 		return(c == (int)'n');
27437133Sbostic 	}
27537133Sbostic 	/* NOTREACHED */
27637133Sbostic }
27737133Sbostic 
27837133Sbostic stop(val)
27937133Sbostic 	int val;
28037133Sbostic {
28137133Sbostic 	(void)fprintf(stderr, "%s unchanged.\n", passwd);
28237133Sbostic 	(void)unlink(temp);
28337133Sbostic 	exit(val);
28437133Sbostic }
285