field.c revision 93086
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/cdefs.h>
39__FBSDID("$FreeBSD: head/usr.bin/chpass/field.c 93086 2002-03-24 10:21:22Z markm $");
40
41#include <sys/param.h>
42#include <sys/stat.h>
43
44#include <ctype.h>
45#include <err.h>
46#include <errno.h>
47#include <grp.h>
48#include <pwd.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53
54#include "chpass.h"
55#include "pathnames.h"
56
57static char blank[] = "";
58
59/* ARGSUSED */
60int
61p_login(char *p, struct passwd *pw, ENTRY *ep __unused)
62{
63	if (!*p) {
64		warnx("empty login field");
65		return (1);
66	}
67	if (*p == '-') {
68		warnx("login names may not begin with a hyphen");
69		return (1);
70	}
71	if (!(pw->pw_name = strdup(p))) {
72		warnx("can't save entry");
73		return (1);
74	}
75	if (strchr(p, '.'))
76		warnx("\'.\' is dangerous in a login name");
77	for (; *p; ++p)
78		if (isupper(*p)) {
79			warnx("upper-case letters are dangerous in a login name");
80			break;
81		}
82	return (0);
83}
84
85/* ARGSUSED */
86int
87p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused)
88{
89	if (!*p)
90		pw->pw_passwd = blank;	/* "NOLOGIN"; */
91	else if (!(pw->pw_passwd = strdup(p))) {
92		warnx("can't save password entry");
93		return (1);
94	}
95
96	return (0);
97}
98
99/* ARGSUSED */
100int
101p_uid(char *p, struct passwd *pw, ENTRY *ep __unused)
102{
103	uid_t id;
104	char *np;
105
106	if (!*p) {
107		warnx("empty uid field");
108		return (1);
109	}
110	if (!isdigit(*p)) {
111		warnx("illegal uid");
112		return (1);
113	}
114	errno = 0;
115	id = strtoul(p, &np, 10);
116	if (*np || (id == ULONG_MAX && errno == ERANGE)) {
117		warnx("illegal uid");
118		return (1);
119	}
120	pw->pw_uid = id;
121	return (0);
122}
123
124/* ARGSUSED */
125int
126p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
127{
128	struct group *gr;
129	gid_t id;
130	char *np;
131
132	if (!*p) {
133		warnx("empty gid field");
134		return (1);
135	}
136	if (!isdigit(*p)) {
137		if (!(gr = getgrnam(p))) {
138			warnx("unknown group %s", p);
139			return (1);
140		}
141		pw->pw_gid = gr->gr_gid;
142		return (0);
143	}
144	errno = 0;
145	id = strtoul(p, &np, 10);
146	if (*np || (id == ULONG_MAX && errno == ERANGE)) {
147		warnx("illegal gid");
148		return (1);
149	}
150	pw->pw_gid = id;
151	return (0);
152}
153
154/* ARGSUSED */
155int
156p_class(char *p, struct passwd *pw, ENTRY *ep __unused)
157{
158	if (!*p)
159		pw->pw_class = blank;
160	else if (!(pw->pw_class = strdup(p))) {
161		warnx("can't save entry");
162		return (1);
163	}
164
165	return (0);
166}
167
168/* ARGSUSED */
169int
170p_change(char *p, struct passwd *pw, ENTRY *ep __unused)
171{
172	if (!atot(p, &pw->pw_change))
173		return (0);
174	warnx("illegal date for change field");
175	return (1);
176}
177
178/* ARGSUSED */
179int
180p_expire(char *p, struct passwd *pw, ENTRY *ep __unused)
181{
182	if (!atot(p, &pw->pw_expire))
183		return (0);
184	warnx("illegal date for expire field");
185	return (1);
186}
187
188/* ARGSUSED */
189int
190p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep __unused)
191{
192	if (!*p)
193		ep->save = blank;
194	else if (!(ep->save = strdup(p))) {
195		warnx("can't save entry");
196		return (1);
197	}
198	return (0);
199}
200
201/* ARGSUSED */
202int
203p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused)
204{
205	if (!*p) {
206		warnx("empty home directory field");
207		return (1);
208	}
209	if (!(pw->pw_dir = strdup(p))) {
210		warnx("can't save entry");
211		return (1);
212	}
213	return (0);
214}
215
216/* ARGSUSED */
217int
218p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
219{
220	char *t;
221	struct stat sbuf;
222
223	if (!*p) {
224		pw->pw_shell = strdup(_PATH_BSHELL);
225		return (0);
226	}
227	/* only admin can change from or to "restricted" shells */
228	if (uid && pw->pw_shell && !ok_shell(pw->pw_shell)) {
229		warnx("%s: current shell non-standard", pw->pw_shell);
230		return (1);
231	}
232	if (!(t = ok_shell(p))) {
233		if (uid) {
234			warnx("%s: non-standard shell", p);
235			return (1);
236		}
237	}
238	else
239		p = t;
240	if (!(pw->pw_shell = strdup(p))) {
241		warnx("can't save entry");
242		return (1);
243	}
244	if (stat(pw->pw_shell, &sbuf) < 0) {
245		if (errno == ENOENT)
246			warnx("WARNING: shell '%s' does not exist",
247			    pw->pw_shell);
248		else
249			warn("WARNING: can't stat shell '%s'",  pw->pw_shell);
250		return (0);
251	}
252	if (!S_ISREG(sbuf.st_mode)) {
253		warnx("WARNING: shell '%s' is not a regular file",
254			pw->pw_shell);
255		return (0);
256	}
257	if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
258		warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
259		return (0);
260	}
261	return (0);
262}
263