xref: /minix3/usr.bin/chpass/edit.c (revision 5c00743626989a611dd2966296c00a8cc4abca6f)
1*5c007436SBen Gras /*	$NetBSD: edit.c,v 1.20 2009/04/11 12:10:02 lukem Exp $	*/
2*5c007436SBen Gras 
3*5c007436SBen Gras /*-
4*5c007436SBen Gras  * Copyright (c) 1990, 1993, 1994
5*5c007436SBen Gras  *	The Regents of the University of California.  All rights reserved.
6*5c007436SBen Gras  *
7*5c007436SBen Gras  * Redistribution and use in source and binary forms, with or without
8*5c007436SBen Gras  * modification, are permitted provided that the following conditions
9*5c007436SBen Gras  * are met:
10*5c007436SBen Gras  * 1. Redistributions of source code must retain the above copyright
11*5c007436SBen Gras  *    notice, this list of conditions and the following disclaimer.
12*5c007436SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
13*5c007436SBen Gras  *    notice, this list of conditions and the following disclaimer in the
14*5c007436SBen Gras  *    documentation and/or other materials provided with the distribution.
15*5c007436SBen Gras  * 3. Neither the name of the University nor the names of its contributors
16*5c007436SBen Gras  *    may be used to endorse or promote products derived from this software
17*5c007436SBen Gras  *    without specific prior written permission.
18*5c007436SBen Gras  *
19*5c007436SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*5c007436SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*5c007436SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*5c007436SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*5c007436SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*5c007436SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*5c007436SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*5c007436SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*5c007436SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*5c007436SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*5c007436SBen Gras  * SUCH DAMAGE.
30*5c007436SBen Gras  */
31*5c007436SBen Gras 
32*5c007436SBen Gras #include <sys/cdefs.h>
33*5c007436SBen Gras #ifndef lint
34*5c007436SBen Gras #if 0
35*5c007436SBen Gras static char sccsid[] = "@(#)edit.c	8.3 (Berkeley) 4/2/94";
36*5c007436SBen Gras #else
37*5c007436SBen Gras __RCSID("$NetBSD: edit.c,v 1.20 2009/04/11 12:10:02 lukem Exp $");
38*5c007436SBen Gras #endif
39*5c007436SBen Gras #endif /* not lint */
40*5c007436SBen Gras 
41*5c007436SBen Gras #include <sys/param.h>
42*5c007436SBen Gras #include <sys/stat.h>
43*5c007436SBen Gras 
44*5c007436SBen Gras #include <ctype.h>
45*5c007436SBen Gras #include <err.h>
46*5c007436SBen Gras #include <errno.h>
47*5c007436SBen Gras #include <paths.h>
48*5c007436SBen Gras #include <pwd.h>
49*5c007436SBen Gras #include <stdio.h>
50*5c007436SBen Gras #include <stdlib.h>
51*5c007436SBen Gras #include <string.h>
52*5c007436SBen Gras #include <unistd.h>
53*5c007436SBen Gras #include <fcntl.h>
54*5c007436SBen Gras #include <util.h>
55*5c007436SBen Gras 
56*5c007436SBen Gras #include "chpass.h"
57*5c007436SBen Gras 
58*5c007436SBen Gras void
59*5c007436SBen Gras edit(char *tempname, struct passwd *pw)
60*5c007436SBen Gras {
61*5c007436SBen Gras 	struct stat begin, end;
62*5c007436SBen Gras 
63*5c007436SBen Gras 	for (;;) {
64*5c007436SBen Gras 		if (stat(tempname, &begin))
65*5c007436SBen Gras 			(*Pw_error)(tempname, 1, 1);
66*5c007436SBen Gras 		pw_edit(1, tempname);
67*5c007436SBen Gras 		if (stat(tempname, &end))
68*5c007436SBen Gras 			(*Pw_error)(tempname, 1, 1);
69*5c007436SBen Gras 		if (begin.st_mtime == end.st_mtime) {
70*5c007436SBen Gras 			warnx("no changes made");
71*5c007436SBen Gras 			(*Pw_error)(NULL, 0, 0);
72*5c007436SBen Gras 		}
73*5c007436SBen Gras 		if (verify(tempname, pw))
74*5c007436SBen Gras 			break;
75*5c007436SBen Gras #ifdef YP
76*5c007436SBen Gras 		if (use_yp)
77*5c007436SBen Gras 			yppw_prompt();
78*5c007436SBen Gras 		else
79*5c007436SBen Gras #endif
80*5c007436SBen Gras 			pw_prompt();
81*5c007436SBen Gras 	}
82*5c007436SBen Gras }
83*5c007436SBen Gras 
84*5c007436SBen Gras /*
85*5c007436SBen Gras  * display --
86*5c007436SBen Gras  *	print out the file for the user to edit; strange side-effect:
87*5c007436SBen Gras  *	set conditional flag if the user gets to edit the shell.
88*5c007436SBen Gras  */
89*5c007436SBen Gras void
90*5c007436SBen Gras display(char *tempname, int fd, struct passwd *pw)
91*5c007436SBen Gras {
92*5c007436SBen Gras 	FILE *fp;
93*5c007436SBen Gras 	char *bp, *p;
94*5c007436SBen Gras 	char chgstr[256], expstr[256];
95*5c007436SBen Gras 
96*5c007436SBen Gras 	if (!(fp = fdopen(fd, "w")))
97*5c007436SBen Gras 		(*Pw_error)(tempname, 1, 1);
98*5c007436SBen Gras 
99*5c007436SBen Gras 	(void)fprintf(fp,
100*5c007436SBen Gras 	    "#Changing user %sdatabase information for %s.\n",
101*5c007436SBen Gras 	    use_yp ? "YP " : "", pw->pw_name);
102*5c007436SBen Gras 	if (!uid) {
103*5c007436SBen Gras 		(void)fprintf(fp, "Login: %s\n", pw->pw_name);
104*5c007436SBen Gras 		(void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
105*5c007436SBen Gras 		(void)fprintf(fp, "Uid [#]: %d\n", pw->pw_uid);
106*5c007436SBen Gras 		(void)fprintf(fp, "Gid [# or name]: %d\n", pw->pw_gid);
107*5c007436SBen Gras 		(void)fprintf(fp, "Change [month day year]: %s\n",
108*5c007436SBen Gras 		    ttoa(chgstr, sizeof chgstr, pw->pw_change));
109*5c007436SBen Gras 		(void)fprintf(fp, "Expire [month day year]: %s\n",
110*5c007436SBen Gras 		    ttoa(expstr, sizeof expstr, pw->pw_expire));
111*5c007436SBen Gras 		(void)fprintf(fp, "Class: %s\n", pw->pw_class);
112*5c007436SBen Gras 		(void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
113*5c007436SBen Gras 		(void)fprintf(fp, "Shell: %s\n",
114*5c007436SBen Gras 		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
115*5c007436SBen Gras 	}
116*5c007436SBen Gras 	/* Only admin can change "restricted" shells. */
117*5c007436SBen Gras 	else if (ok_shell(pw->pw_shell))
118*5c007436SBen Gras 		/*
119*5c007436SBen Gras 		 * Make shell a restricted field.  Ugly with a
120*5c007436SBen Gras 		 * necklace, but there's not much else to do.
121*5c007436SBen Gras 		 */
122*5c007436SBen Gras 		(void)fprintf(fp, "Shell: %s\n",
123*5c007436SBen Gras 		    *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
124*5c007436SBen Gras 	else
125*5c007436SBen Gras 		list[E_SHELL].restricted = 1;
126*5c007436SBen Gras 	bp = strdup(pw->pw_gecos);
127*5c007436SBen Gras 	if (!bp) {
128*5c007436SBen Gras 		err(1, "strdup");
129*5c007436SBen Gras 		/*NOTREACHED*/
130*5c007436SBen Gras 	}
131*5c007436SBen Gras 	p = strsep(&bp, ",");
132*5c007436SBen Gras 	(void)fprintf(fp, "Full Name: %s\n", p ? p : "");
133*5c007436SBen Gras 	p = strsep(&bp, ",");
134*5c007436SBen Gras 	(void)fprintf(fp, "Location: %s\n", p ? p : "");
135*5c007436SBen Gras 	p = strsep(&bp, ",");
136*5c007436SBen Gras 	(void)fprintf(fp, "Office Phone: %s\n", p ? p : "");
137*5c007436SBen Gras 	p = strsep(&bp, ",");
138*5c007436SBen Gras 	(void)fprintf(fp, "Home Phone: %s\n", p ? p : "");
139*5c007436SBen Gras 
140*5c007436SBen Gras 	(void)fchown(fd, getuid(), getgid());
141*5c007436SBen Gras 	(void)fclose(fp);
142*5c007436SBen Gras }
143*5c007436SBen Gras 
144*5c007436SBen Gras int
145*5c007436SBen Gras verify(char *tempname, struct passwd *pw)
146*5c007436SBen Gras {
147*5c007436SBen Gras 	ENTRY *ep;
148*5c007436SBen Gras 	char *p;
149*5c007436SBen Gras 	struct stat sb;
150*5c007436SBen Gras 	FILE *fp = NULL;
151*5c007436SBen Gras 	int len, fd;
152*5c007436SBen Gras 	static char buf[LINE_MAX];
153*5c007436SBen Gras 
154*5c007436SBen Gras #ifdef __minix
155*5c007436SBen Gras 	if ((fd = open(tempname, O_RDONLY)) == -1 ||
156*5c007436SBen Gras 	    (fp = fdopen(fd, "r")) == NULL)
157*5c007436SBen Gras #else
158*5c007436SBen Gras 	if ((fd = open(tempname, O_RDONLY|O_NOFOLLOW)) == -1 ||
159*5c007436SBen Gras 	    (fp = fdopen(fd, "r")) == NULL)
160*5c007436SBen Gras #endif
161*5c007436SBen Gras 		(*Pw_error)(tempname, 1, 1);
162*5c007436SBen Gras 	if (fstat(fd, &sb))
163*5c007436SBen Gras 		(*Pw_error)(tempname, 1, 1);
164*5c007436SBen Gras 	if (sb.st_size == 0 || sb.st_nlink != 1) {
165*5c007436SBen Gras 		warnx("corrupted temporary file");
166*5c007436SBen Gras 		goto bad;
167*5c007436SBen Gras 	}
168*5c007436SBen Gras 	while (fgets(buf, sizeof(buf), fp)) {
169*5c007436SBen Gras 		if (!buf[0] || buf[0] == '#')
170*5c007436SBen Gras 			continue;
171*5c007436SBen Gras 		if (!(p = strchr(buf, '\n'))) {
172*5c007436SBen Gras 			warnx("line too long");
173*5c007436SBen Gras 			goto bad;
174*5c007436SBen Gras 		}
175*5c007436SBen Gras 		*p = '\0';
176*5c007436SBen Gras 		for (ep = list;; ++ep) {
177*5c007436SBen Gras 			if (!ep->prompt) {
178*5c007436SBen Gras 				warnx("unrecognized field");
179*5c007436SBen Gras 				goto bad;
180*5c007436SBen Gras 			}
181*5c007436SBen Gras 			if (!strncasecmp(buf, ep->prompt, ep->len)) {
182*5c007436SBen Gras 				if (ep->restricted && uid) {
183*5c007436SBen Gras 					warnx(
184*5c007436SBen Gras 					    "you may not change the %s field",
185*5c007436SBen Gras 						ep->prompt);
186*5c007436SBen Gras 					goto bad;
187*5c007436SBen Gras 				}
188*5c007436SBen Gras 				if (!(p = strchr(buf, ':'))) {
189*5c007436SBen Gras 					warnx("line corrupted");
190*5c007436SBen Gras 					goto bad;
191*5c007436SBen Gras 				}
192*5c007436SBen Gras 				while (isspace((unsigned char)*++p));
193*5c007436SBen Gras 				if (ep->except && strpbrk(p, ep->except)) {
194*5c007436SBen Gras 					warnx(
195*5c007436SBen Gras 				   "illegal character in the \"%s\" field",
196*5c007436SBen Gras 					    ep->prompt);
197*5c007436SBen Gras 					goto bad;
198*5c007436SBen Gras 				}
199*5c007436SBen Gras 				if ((ep->func)(p, pw, ep)) {
200*5c007436SBen Gras bad:					(void)fclose(fp);
201*5c007436SBen Gras 					return (0);
202*5c007436SBen Gras 				}
203*5c007436SBen Gras 				break;
204*5c007436SBen Gras 			}
205*5c007436SBen Gras 		}
206*5c007436SBen Gras 	}
207*5c007436SBen Gras 	(void)fclose(fp);
208*5c007436SBen Gras 
209*5c007436SBen Gras 	/* Build the gecos field. */
210*5c007436SBen Gras 	len = strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
211*5c007436SBen Gras 	    strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save) + 4;
212*5c007436SBen Gras 	if (!(p = malloc(len)))
213*5c007436SBen Gras 		err(1, "malloc");
214*5c007436SBen Gras 	(void)snprintf(p, len, "%s,%s,%s,%s", list[E_NAME].save,
215*5c007436SBen Gras 	    list[E_LOCATE].save, list[E_BPHONE].save, list[E_HPHONE].save);
216*5c007436SBen Gras 	pw->pw_gecos = p;
217*5c007436SBen Gras 
218*5c007436SBen Gras 	if (snprintf(buf, sizeof(buf),
219*5c007436SBen Gras 	    "%s:%s:%d:%d:%s:%lu:%lu:%s:%s:%s",
220*5c007436SBen Gras 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
221*5c007436SBen Gras 	    (u_long)pw->pw_change, (u_long)pw->pw_expire, pw->pw_gecos,
222*5c007436SBen Gras 	    pw->pw_dir, pw->pw_shell) >= (int)sizeof(buf)) {
223*5c007436SBen Gras 		warnx("entries too long");
224*5c007436SBen Gras 		return (0);
225*5c007436SBen Gras 	}
226*5c007436SBen Gras 	return (pw_scan(buf, pw, (int *)NULL));
227*5c007436SBen Gras }
228