prettyness police
[unix-history] / usr / src / usr.bin / chpass / edit.c
... / ...
CommitLineData
1/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9static char sccsid[] = "@(#)edit.c 8.2 (Berkeley) %G%";
10#endif /* not lint */
11
12#include <sys/param.h>
13#include <sys/stat.h>
14
15#include <ctype.h>
16#include <err.h>
17#include <errno.h>
18#include <paths.h>
19#include <pwd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include <pw_scan.h>
26#include <pw_util.h>
27
28#include "chpass.h"
29
30extern char *tempname;
31
32void
33edit(pw)
34 struct passwd *pw;
35{
36 struct stat begin, end;
37
38 for (;;) {
39 if (stat(tempname, &begin))
40 pw_error(tempname, 1, 1);
41 pw_edit(1);
42 if (stat(tempname, &end))
43 pw_error(tempname, 1, 1);
44 if (begin.st_mtime == end.st_mtime) {
45 warnx("no changes made");
46 pw_error(NULL, 0, 0);
47 }
48 if (verify(pw))
49 break;
50 pw_prompt();
51 }
52}
53
54/*
55 * display --
56 * print out the file for the user to edit; strange side-effect:
57 * set conditional flag if the user gets to edit the shell.
58 */
59void
60display(fd, pw)
61 int fd;
62 struct passwd *pw;
63{
64 FILE *fp;
65 char *bp, *p, *ttoa();
66
67 if (!(fp = fdopen(fd, "w")))
68 pw_error(tempname, 1, 1);
69
70 (void)fprintf(fp,
71 "#Changing user database information for %s.\n", pw->pw_name);
72 if (!uid) {
73 (void)fprintf(fp, "Login: %s\n", pw->pw_name);
74 (void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
75 (void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid);
76 (void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid);
77 (void)fprintf(fp, "Change [month day year]: %s\n",
78 ttoa(pw->pw_change));
79 (void)fprintf(fp, "Expire [month day year]: %s\n",
80 ttoa(pw->pw_expire));
81 (void)fprintf(fp, "Class: %s\n", pw->pw_class);
82 (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
83 (void)fprintf(fp, "Shell: %s\n",
84 *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
85 }
86 /* Only admin can change "restricted" shells. */
87 else if (ok_shell(pw->pw_shell))
88 /*
89 * Make shell a restricted field. Ugly with a
90 * necklace, but there's not much else to do.
91 */
92 (void)fprintf(fp, "Shell: %s\n",
93 *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
94 else
95 list[E_SHELL].restricted = 1;
96 bp = pw->pw_gecos;
97 p = strsep(&bp, ",");
98 (void)fprintf(fp, "Full Name: %s\n", p ? p : "");
99 p = strsep(&bp, ",");
100 (void)fprintf(fp, "Location: %s\n", p ? p : "");
101 p = strsep(&bp, ",");
102 (void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
103 p = strsep(&bp, ",");
104 (void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
105
106 (void)fchown(fd, getuid(), getgid());
107 (void)fclose(fp);
108}
109
110int
111verify(pw)
112 struct passwd *pw;
113{
114 ENTRY *ep;
115 char *p;
116 struct stat sb;
117 FILE *fp;
118 int len;
119 char buf[LINE_MAX];
120
121 if (!(fp = fopen(tempname, "r")))
122 pw_error(tempname, 1, 1);
123 if (fstat(fileno(fp), &sb))
124 pw_error(tempname, 1, 1);
125 if (sb.st_size == 0) {
126 warnx("corrupted temporary file");
127 goto bad;
128 }
129 while (fgets(buf, sizeof(buf), fp)) {
130 if (!buf[0] || buf[0] == '#')
131 continue;
132 if (!(p = strchr(buf, '\n'))) {
133 warnx("line too long");
134 goto bad;
135 }
136 *p = '\0';
137 for (ep = list;; ++ep) {
138 if (!ep->prompt) {
139 warnx("unrecognized field");
140 goto bad;
141 }
142 if (!strncasecmp(buf, ep->prompt, ep->len)) {
143 if (ep->restricted && uid) {
144 warnx(
145 "you may not change the %s field",
146 ep->prompt);
147 goto bad;
148 }
149 if (!(p = strchr(buf, ':'))) {
150 warnx("line corrupted");
151 goto bad;
152 }
153 while (isspace(*++p));
154 if (ep->except && strpbrk(p, ep->except)) {
155 warnx(
156 "illegal character in the \"%s\" field",
157 ep->prompt);
158 goto bad;
159 }
160 if ((ep->func)(p, pw, ep)) {
161bad: (void)fclose(fp);
162 return (0);
163 }
164 break;
165 }
166 }
167 }
168 (void)fclose(fp);
169
170 /* Build the gecos field. */
171 len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
172 strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4;
173 if (!(p = malloc(len)))
174 err(1, NULL);
175 (void)sprintf(pw->pw_gecos = p, "%s,%s,%s,%s", list[E_NAME].save,
176 list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save);
177
178 if (snprintf(buf, sizeof(buf),
179 "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s",
180 pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
181 pw->pw_change, pw->pw_expire, pw->pw_gecos, pw->pw_dir,
182 pw->pw_shell) >= sizeof(buf)) {
183 warnx("entries too long");
184 return (0);
185 }
186 return (pw_scan(buf, pw));
187}