Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / chpass / field.c
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
35 static 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 */
55 int
56 p_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 */
84 int
85 p_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 */
101 int
102 p_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 */
129 int
130 p_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 */
162 int
163 p_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 */
179 int
180 p_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 */
192 int
193 p_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 */
205 int
206 p_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 */
221 int
222 p_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 */
239 int
240 p_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 }