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