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