field.c revision 41568
1/*
2 * Copyright (c) 1988, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char sccsid[] = "@(#)field.c	8.4 (Berkeley) 4/2/94";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/stat.h>
40
41#include <ctype.h>
42#include <err.h>
43#include <errno.h>
44#include <grp.h>
45#include <pwd.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50
51#include "chpass.h"
52#include "pathnames.h"
53
54/* ARGSUSED */
55int
56p_login(p, pw, ep)
57	char *p;
58	struct passwd *pw;
59	ENTRY *ep;
60{
61	if (!*p) {
62		warnx("empty login field");
63		return (1);
64	}
65	if (*p == '-') {
66		warnx("login names may not begin with a hyphen");
67		return (1);
68	}
69	if (!(pw->pw_name = strdup(p))) {
70		warnx("can't save entry");
71		return (1);
72	}
73	if (strchr(p, '.'))
74		warnx("\'.\' is dangerous in a login name");
75	for (; *p; ++p)
76		if (isupper(*p)) {
77			warnx("upper-case letters are dangerous in a login name");
78			break;
79		}
80	return (0);
81}
82
83/* ARGSUSED */
84int
85p_passwd(p, pw, ep)
86	char *p;
87	struct passwd *pw;
88	ENTRY *ep;
89{
90	if (!*p)
91		pw->pw_passwd = "";	/* "NOLOGIN"; */
92	else if (!(pw->pw_passwd = strdup(p))) {
93		warnx("can't save password entry");
94		return (1);
95	}
96
97	return (0);
98}
99
100/* ARGSUSED */
101int
102p_uid(p, pw, ep)
103	char *p;
104	struct passwd *pw;
105	ENTRY *ep;
106{
107	uid_t id;
108	char *np;
109
110	if (!*p) {
111		warnx("empty uid field");
112		return (1);
113	}
114	if (!isdigit(*p)) {
115		warnx("illegal uid");
116		return (1);
117	}
118	errno = 0;
119	id = strtoul(p, &np, 10);
120	if (*np || (id == ULONG_MAX && errno == ERANGE)) {
121		warnx("illegal uid");
122		return (1);
123	}
124	pw->pw_uid = id;
125	return (0);
126}
127
128/* ARGSUSED */
129int
130p_gid(p, pw, ep)
131	char *p;
132	struct passwd *pw;
133	ENTRY *ep;
134{
135	struct group *gr;
136	gid_t id;
137	char *np;
138
139	if (!*p) {
140		warnx("empty gid field");
141		return (1);
142	}
143	if (!isdigit(*p)) {
144		if (!(gr = getgrnam(p))) {
145			warnx("unknown group %s", p);
146			return (1);
147		}
148		pw->pw_gid = gr->gr_gid;
149		return (0);
150	}
151	errno = 0;
152	id = strtoul(p, &np, 10);
153	if (*np || (id == ULONG_MAX && errno == ERANGE)) {
154		warnx("illegal gid");
155		return (1);
156	}
157	pw->pw_gid = id;
158	return (0);
159}
160
161/* ARGSUSED */
162int
163p_class(p, pw, ep)
164	char *p;
165	struct passwd *pw;
166	ENTRY *ep;
167{
168	if (!*p)
169		pw->pw_class = "";
170	else if (!(pw->pw_class = strdup(p))) {
171		warnx("can't save entry");
172		return (1);
173	}
174
175	return (0);
176}
177
178/* ARGSUSED */
179int
180p_change(p, pw, ep)
181	char *p;
182	struct passwd *pw;
183	ENTRY *ep;
184{
185	if (!atot(p, &pw->pw_change))
186		return (0);
187	warnx("illegal date for change field");
188	return (1);
189}
190
191/* ARGSUSED */
192int
193p_expire(p, pw, ep)
194	char *p;
195	struct passwd *pw;
196	ENTRY *ep;
197{
198	if (!atot(p, &pw->pw_expire))
199		return (0);
200	warnx("illegal date for expire field");
201	return (1);
202}
203
204/* ARGSUSED */
205int
206p_gecos(p, pw, ep)
207	char *p;
208	struct passwd *pw;
209	ENTRY *ep;
210{
211	if (!*p)
212		ep->save = "";
213	else if (!(ep->save = strdup(p))) {
214		warnx("can't save entry");
215		return (1);
216	}
217	return (0);
218}
219
220/* ARGSUSED */
221int
222p_hdir(p, pw, ep)
223	char *p;
224	struct passwd *pw;
225	ENTRY *ep;
226{
227	if (!*p) {
228		warnx("empty home directory field");
229		return (1);
230	}
231	if (!(pw->pw_dir = strdup(p))) {
232		warnx("can't save entry");
233		return (1);
234	}
235	return (0);
236}
237
238/* ARGSUSED */
239int
240p_shell(p, pw, ep)
241	char *p;
242	struct passwd *pw;
243	ENTRY *ep;
244{
245	char *t, *ok_shell();
246	struct stat sbuf;
247
248	if (!*p) {
249		pw->pw_shell = _PATH_BSHELL;
250		return (0);
251	}
252	/* only admin can change from or to "restricted" shells */
253	if (uid && pw->pw_shell && !ok_shell(pw->pw_shell)) {
254		warnx("%s: current shell non-standard", pw->pw_shell);
255		return (1);
256	}
257	if (!(t = ok_shell(p))) {
258		if (uid) {
259			warnx("%s: non-standard shell", p);
260			return (1);
261		}
262	}
263	else
264		p = t;
265	if (!(pw->pw_shell = strdup(p))) {
266		warnx("can't save entry");
267		return (1);
268	}
269	if (stat(pw->pw_shell, &sbuf) < 0) {
270		if (errno == ENOENT)
271			warnx("WARNING: shell '%s' does not exist",
272			    pw->pw_shell);
273		else
274			warn("WARNING: can't stat shell '%s'",  pw->pw_shell);
275		return (0);
276	}
277	if (!S_ISREG(sbuf.st_mode)) {
278		warnx("WARNING: shell '%s' is not a regular file",
279			pw->pw_shell);
280		return (0);
281	}
282	if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
283		warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
284		return (0);
285	}
286	return (0);
287}
288