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