xref: /csrg-svn/usr.bin/chpass/edit.c (revision 66651)
146391Sbostic /*-
2*66651Spendry  * Copyright (c) 1990, 1993, 1994
361940Sbostic  *	The Regents of the University of California.  All rights reserved.
446391Sbostic  *
546391Sbostic  * %sccs.include.redist.c%
646391Sbostic  */
746391Sbostic 
846391Sbostic #ifndef lint
9*66651Spendry static char sccsid[] = "@(#)edit.c	8.3 (Berkeley) 04/02/94";
1046391Sbostic #endif /* not lint */
1146391Sbostic 
1246391Sbostic #include <sys/param.h>
1346391Sbostic #include <sys/stat.h>
1466621Spendry 
1566621Spendry #include <ctype.h>
1666621Spendry #include <err.h>
1766621Spendry #include <errno.h>
1866621Spendry #include <paths.h>
1946391Sbostic #include <pwd.h>
2046391Sbostic #include <stdio.h>
2146391Sbostic #include <stdlib.h>
2246391Sbostic #include <string.h>
2366621Spendry #include <unistd.h>
2466621Spendry 
2566621Spendry #include <pw_scan.h>
2666621Spendry #include <pw_util.h>
2766621Spendry 
2846391Sbostic #include "chpass.h"
2946391Sbostic 
3046391Sbostic extern char *tempname;
3146391Sbostic 
3246952Sbostic void
edit(pw)3346952Sbostic edit(pw)
3446391Sbostic 	struct passwd *pw;
3546391Sbostic {
3646391Sbostic 	struct stat begin, end;
3746391Sbostic 
3846391Sbostic 	for (;;) {
3946391Sbostic 		if (stat(tempname, &begin))
4046391Sbostic 			pw_error(tempname, 1, 1);
4146952Sbostic 		pw_edit(1);
4246391Sbostic 		if (stat(tempname, &end))
4346391Sbostic 			pw_error(tempname, 1, 1);
4451372Sbostic 		if (begin.st_mtime == end.st_mtime) {
4566621Spendry 			warnx("no changes made");
4651371Sbostic 			pw_error(NULL, 0, 0);
4746391Sbostic 		}
4846391Sbostic 		if (verify(pw))
4946391Sbostic 			break;
5046391Sbostic 		pw_prompt();
5146391Sbostic 	}
5246391Sbostic }
5346391Sbostic 
5446391Sbostic /*
5546391Sbostic  * display --
5646391Sbostic  *	print out the file for the user to edit; strange side-effect:
5746391Sbostic  *	set conditional flag if the user gets to edit the shell.
5846391Sbostic  */
5966621Spendry void
display(fd,pw)6046391Sbostic display(fd, pw)
6146391Sbostic 	int fd;
6246391Sbostic 	struct passwd *pw;
6346391Sbostic {
6446391Sbostic 	FILE *fp;
6566621Spendry 	char *bp, *p, *ttoa();
6646391Sbostic 
6746391Sbostic 	if (!(fp = fdopen(fd, "w")))
6846391Sbostic 		pw_error(tempname, 1, 1);
6946391Sbostic 
7046391Sbostic 	(void)fprintf(fp,
7146391Sbostic 	    "#Changing user database information for %s.\n", pw->pw_name);
7246391Sbostic 	if (!uid) {
7346391Sbostic 		(void)fprintf(fp, "Login: %s\n", pw->pw_name);
7446391Sbostic 		(void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
7546391Sbostic 		(void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid);
7646391Sbostic 		(void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid);
7746391Sbostic 		(void)fprintf(fp, "Change [month day year]: %s\n",
7846391Sbostic 		    ttoa(pw->pw_change));
7946391Sbostic 		(void)fprintf(fp, "Expire [month day year]: %s\n",
8046391Sbostic 		    ttoa(pw->pw_expire));
8146391Sbostic 		(void)fprintf(fp, "Class: %s\n", pw->pw_class);
8246391Sbostic 		(void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
8346391Sbostic 		(void)fprintf(fp, "Shell: %s\n",
8446391Sbostic 		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
8546391Sbostic 	}
8646391Sbostic 	/* Only admin can change "restricted" shells. */
8746391Sbostic 	else if (ok_shell(pw->pw_shell))
8846391Sbostic 		/*
8946391Sbostic 		 * Make shell a restricted field.  Ugly with a
9046391Sbostic 		 * necklace, but there's not much else to do.
9146391Sbostic 		 */
9246391Sbostic 		(void)fprintf(fp, "Shell: %s\n",
9346391Sbostic 		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
9446391Sbostic 	else
9546391Sbostic 		list[E_SHELL].restricted = 1;
9646391Sbostic 	bp = pw->pw_gecos;
9746391Sbostic 	p = strsep(&bp, ",");
9846391Sbostic 	(void)fprintf(fp, "Full Name: %s\n", p ? p : "");
9946391Sbostic 	p = strsep(&bp, ",");
10046391Sbostic 	(void)fprintf(fp, "Location: %s\n", p ? p : "");
10146391Sbostic 	p = strsep(&bp, ",");
10246391Sbostic 	(void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
10346391Sbostic 	p = strsep(&bp, ",");
10446391Sbostic 	(void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
10546391Sbostic 
10646952Sbostic 	(void)fchown(fd, getuid(), getgid());
10746391Sbostic 	(void)fclose(fp);
10846391Sbostic }
10946391Sbostic 
11066621Spendry int
verify(pw)11146391Sbostic verify(pw)
11246391Sbostic 	struct passwd *pw;
11346391Sbostic {
11466621Spendry 	ENTRY *ep;
11566621Spendry 	char *p;
11651372Sbostic 	struct stat sb;
11746391Sbostic 	FILE *fp;
11846391Sbostic 	int len;
11946391Sbostic 	char buf[LINE_MAX];
12046391Sbostic 
12146391Sbostic 	if (!(fp = fopen(tempname, "r")))
12246391Sbostic 		pw_error(tempname, 1, 1);
12351372Sbostic 	if (fstat(fileno(fp), &sb))
12451372Sbostic 		pw_error(tempname, 1, 1);
12551372Sbostic 	if (sb.st_size == 0) {
12666621Spendry 		warnx("corrupted temporary file");
12751372Sbostic 		goto bad;
12851372Sbostic 	}
12946391Sbostic 	while (fgets(buf, sizeof(buf), fp)) {
13046391Sbostic 		if (!buf[0] || buf[0] == '#')
13146391Sbostic 			continue;
13266621Spendry 		if (!(p = strchr(buf, '\n'))) {
13366621Spendry 			warnx("line too long");
13446391Sbostic 			goto bad;
13546391Sbostic 		}
13646391Sbostic 		*p = '\0';
13746391Sbostic 		for (ep = list;; ++ep) {
13846391Sbostic 			if (!ep->prompt) {
13966621Spendry 				warnx("unrecognized field");
14046391Sbostic 				goto bad;
14146391Sbostic 			}
14246391Sbostic 			if (!strncasecmp(buf, ep->prompt, ep->len)) {
14346391Sbostic 				if (ep->restricted && uid) {
14466621Spendry 					warnx(
14566621Spendry 					    "you may not change the %s field",
14666621Spendry 						ep->prompt);
14746391Sbostic 					goto bad;
14846391Sbostic 				}
14966621Spendry 				if (!(p = strchr(buf, ':'))) {
15066621Spendry 					warnx("line corrupted");
15146391Sbostic 					goto bad;
15246391Sbostic 				}
15346391Sbostic 				while (isspace(*++p));
15446391Sbostic 				if (ep->except && strpbrk(p, ep->except)) {
15566621Spendry 					warnx(
15666621Spendry 				   "illegal character in the \"%s\" field",
15746391Sbostic 					    ep->prompt);
15846391Sbostic 					goto bad;
15946391Sbostic 				}
16046391Sbostic 				if ((ep->func)(p, pw, ep)) {
16146391Sbostic bad:					(void)fclose(fp);
16266621Spendry 					return (0);
16346391Sbostic 				}
16446391Sbostic 				break;
16546391Sbostic 			}
16646391Sbostic 		}
16746391Sbostic 	}
16846391Sbostic 	(void)fclose(fp);
16946391Sbostic 
17046391Sbostic 	/* Build the gecos field. */
17146391Sbostic 	len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
17246391Sbostic 	    strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4;
17366621Spendry 	if (!(p = malloc(len)))
17466621Spendry 		err(1, NULL);
17546391Sbostic 	(void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save,
17646391Sbostic 	    list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save);
17746391Sbostic 
17846391Sbostic 	if (snprintf(buf, sizeof(buf),
17946391Sbostic 	    "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
18046391Sbostic 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
18146391Sbostic 	    pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir,
18246391Sbostic 	    pw->pw_shell) >= sizeof(buf)) {
18366621Spendry 		warnx("entries too long");
18466621Spendry 		return (0);
18546391Sbostic 	}
18666621Spendry 	return (pw_scan(buf, pw));
18746391Sbostic }
188