]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pw/pw_conf.c
This commit was generated by cvs2svn to compensate for changes in r54359,
[FreeBSD/FreeBSD.git] / usr.sbin / pw / pw_conf.c
1 /*-
2  * Copyright (C) 1996
3  *      David L. Nugent.  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  *
14  * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #ifndef lint
28 static const char rcsid[] =
29   "$FreeBSD$";
30 #endif /* not lint */
31
32 #include <string.h>
33 #include <ctype.h>
34 #include <fcntl.h>
35
36 #include "pw.h"
37
38 #define debugging 0
39
40 enum {
41         _UC_NONE,
42         _UC_DEFAULTPWD,
43         _UC_REUSEUID,
44         _UC_REUSEGID,
45         _UC_NISPASSWD,
46         _UC_DOTDIR,
47         _UC_NEWMAIL,
48         _UC_LOGFILE,
49         _UC_HOMEROOT,
50         _UC_SHELLPATH,
51         _UC_SHELLS,
52         _UC_DEFAULTSHELL,
53         _UC_DEFAULTGROUP,
54         _UC_EXTRAGROUPS,
55         _UC_DEFAULTCLASS,
56         _UC_MINUID,
57         _UC_MAXUID,
58         _UC_MINGID,
59         _UC_MAXGID,
60         _UC_EXPIRE,
61         _UC_PASSWORD,
62         _UC_FIELDS
63 };
64
65 static char     bourne_shell[] = "sh";
66
67 static char    *system_shells[_UC_MAXSHELLS] =
68 {
69         bourne_shell,
70         "csh"
71 };
72
73 static char const *booltrue[] =
74 {
75         "yes", "true", "1", "on", NULL
76 };
77 static char const *boolfalse[] =
78 {
79         "no", "false", "0", "off", NULL
80 };
81
82 static struct userconf config =
83 {
84         0,                      /* Default password for new users? (nologin) */
85         0,                      /* Reuse uids? */
86         0,                      /* Reuse gids? */
87         NULL,                   /* NIS version of the passwd file */
88         "/usr/share/skel",      /* Where to obtain skeleton files */
89         NULL,                   /* Mail to send to new accounts */
90         "/var/log/userlog",     /* Where to log changes */
91         "/home",                /* Where to create home directory */
92         "/bin",                 /* Where shells are located */
93         system_shells,          /* List of shells (first is default) */
94         bourne_shell,           /* Default shell */
95         NULL,                   /* Default group name */
96         NULL,                   /* Default (additional) groups */
97         NULL,                   /* Default login class */
98         1000, 32000,            /* Allowed range of uids */
99         1000, 32000,            /* Allowed range of gids */
100         0,                      /* Days until account expires */
101         0,                      /* Days until password expires */
102         0                       /* size of default_group array */
103 };
104
105 static char const *comments[_UC_FIELDS] =
106 {
107         "#\n# pw.conf - user/group configuration defaults\n#\n",
108         "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
109         "\n# Reuse gaps in uid sequence? (yes or no)\n",
110         "\n# Reuse gaps in gid sequence? (yes or no)\n",
111         "\n# Path to the NIS passwd file (blank or 'no' for none)\n",
112         "\n# Obtain default dotfiles from this directory\n",
113         "\n# Mail this file to new user (/etc/newuser.msg or no)\n",
114         "\n# Log add/change/remove information in this file\n",
115         "\n# Root directory in which $HOME directory is created\n",
116         "\n# Colon separated list of directories containing valid shells\n",
117         "\n# Space separated list of available shells (without paths)\n",
118         "\n# Default shell (without path)\n",
119         "\n# Default group (leave blank for new group per user)\n",
120         "\n# Extra groups for new users\n",
121         "\n# Default login class for new users\n",
122         "\n# Range of valid default user ids\n",
123         NULL,
124         "\n# Range of valid default group ids\n",
125         NULL,
126         "\n# Days after which account expires (0=disabled)\n",
127         "\n# Days after which password expires (0=disabled)\n"
128 };
129
130 static char const *kwds[] =
131 {
132         "",
133         "defaultpasswd",
134         "reuseuids",
135         "reusegids",
136         "nispasswd",
137         "skeleton",
138         "newmail",
139         "logfile",
140         "home",
141         "shellpath",
142         "shells",
143         "defaultshell",
144         "defaultgroup",
145         "extragroups",
146         "defaultclass",
147         "minuid",
148         "maxuid",
149         "mingid",
150         "maxgid",
151         "expire_days",
152         "password_days",
153         NULL
154 };
155
156 static char    *
157 unquote(char const * str)
158 {
159         if (str && (*str == '"' || *str == '\'')) {
160                 char           *p = strchr(str + 1, *str);
161
162                 if (p != NULL)
163                         *p = '\0';
164                 return (char *) (*++str ? str : NULL);
165         }
166         return (char *) str;
167 }
168
169 int
170 boolean_val(char const * str, int dflt)
171 {
172         if ((str = unquote(str)) != NULL) {
173                 int             i;
174
175                 for (i = 0; booltrue[i]; i++)
176                         if (strcmp(str, booltrue[i]) == 0)
177                                 return 1;
178                 for (i = 0; boolfalse[i]; i++)
179                         if (strcmp(str, boolfalse[i]) == 0)
180                                 return 0;
181
182                 /*
183                  * Special cases for defaultpassword
184                  */
185                 if (strcmp(str, "random") == 0)
186                         return -1;
187                 if (strcmp(str, "none") == 0)
188                         return -2;
189         }
190         return dflt;
191 }
192
193 char const     *
194 boolean_str(int val)
195 {
196         if (val == -1)
197                 return "random";
198         else if (val == -2)
199                 return "none";
200         else
201                 return val ? booltrue[0] : boolfalse[0];
202 }
203
204 char           *
205 newstr(char const * p)
206 {
207         char           *q = NULL;
208
209         if ((p = unquote(p)) != NULL) {
210                 int             l = strlen(p) + 1;
211
212                 if ((q = malloc(l)) != NULL)
213                         memcpy(q, p, l);
214         }
215         return q;
216 }
217
218 #define LNBUFSZ 1024
219
220
221 struct userconf *
222 read_userconfig(char const * file)
223 {
224         FILE           *fp;
225
226         extendarray(&config.groups, &config.numgroups, 200);
227         memset(config.groups, 0, config.numgroups * sizeof(char *));
228         if (file == NULL)
229                 file = _PATH_PW_CONF;
230         if ((fp = fopen(file, "r")) != NULL) {
231                 int         buflen = LNBUFSZ;
232                 char       *buf = malloc(buflen);
233
234         nextline:
235                 while (fgets(buf, buflen, fp) != NULL) {
236                         char           *p;
237
238                         while ((p = strchr(buf, '\n')) == NULL) {
239                                 int       l;
240                                 if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
241                                         int     ch;
242                                         while ((ch = fgetc(fp)) != '\n' && ch != EOF);
243                                         goto nextline;  /* Ignore it */
244                                 }
245                                 l = strlen(buf);
246                                 if (fgets(buf + l, buflen - l, fp) == NULL)
247                                         break;  /* Unterminated last line */
248                         }
249
250                         if (p != NULL)
251                                 *p = '\0';
252
253                         if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
254                                 static char const toks[] = " \t\r\n,=";
255                                 char           *q = strtok(NULL, toks);
256                                 int             i = 0;
257
258                                 while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
259                                         ++i;
260 #if debugging
261                                 if (i == _UC_FIELDS)
262                                         printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
263                                 else
264                                         printf("Got kwd[%s]=%s\n", p, q);
265 #endif
266                                 switch (i) {
267                                 case _UC_DEFAULTPWD:
268                                         config.default_password = boolean_val(q, 1);
269                                         break;
270                                 case _UC_REUSEUID:
271                                         config.reuse_uids = boolean_val(q, 0);
272                                         break;
273                                 case _UC_REUSEGID:
274                                         config.reuse_gids = boolean_val(q, 0);
275                                         break;
276                                 case _UC_NISPASSWD:
277                                         config.nispasswd = (q == NULL || !boolean_val(q, 1))
278                                                 ? NULL : newstr(q);
279                                         break;
280                                 case _UC_DOTDIR:
281                                         config.dotdir = (q == NULL || !boolean_val(q, 1))
282                                                 ? NULL : newstr(q);
283                                         break;
284                                 case _UC_NEWMAIL:
285                                         config.newmail = (q == NULL || !boolean_val(q, 1))
286                                                 ? NULL : newstr(q);
287                                         break;
288                                 case _UC_LOGFILE:
289                                         config.logfile = (q == NULL || !boolean_val(q, 1))
290                                                 ? NULL : newstr(q);
291                                         break;
292                                 case _UC_HOMEROOT:
293                                         config.home = (q == NULL || !boolean_val(q, 1))
294                                                 ? "/home" : newstr(q);
295                                         break;
296                                 case _UC_SHELLPATH:
297                                         config.shelldir = (q == NULL || !boolean_val(q, 1))
298                                                 ? "/bin" : newstr(q);
299                                         break;
300                                 case _UC_SHELLS:
301                                         for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
302                                                 system_shells[i] = newstr(q);
303                                         if (i > 0)
304                                                 while (i < _UC_MAXSHELLS)
305                                                         system_shells[i++] = NULL;
306                                         break;
307                                 case _UC_DEFAULTSHELL:
308                                         config.shell_default = (q == NULL || !boolean_val(q, 1))
309                                                 ? (char *) bourne_shell : newstr(q);
310                                         break;
311                                 case _UC_DEFAULTGROUP:
312                                         q = unquote(q);
313                                         config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
314                                                 ? NULL : newstr(q);
315                                         break;
316                                 case _UC_EXTRAGROUPS:
317                                         for (i = 0; q != NULL; q = strtok(NULL, toks)) {
318                                                 if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
319                                                         config.groups[i++] = newstr(q);
320                                         }
321                                         if (i > 0)
322                                                 while (i < config.numgroups)
323                                                         config.groups[i++] = NULL;
324                                         break;
325                                 case _UC_DEFAULTCLASS:
326                                         config.default_class = (q == NULL || !boolean_val(q, 1))
327                                                 ? NULL : newstr(q);
328                                         break;
329                                 case _UC_MINUID:
330                                         if ((q = unquote(q)) != NULL && isdigit(*q))
331                                                 config.min_uid = (uid_t) atol(q);
332                                         break;
333                                 case _UC_MAXUID:
334                                         if ((q = unquote(q)) != NULL && isdigit(*q))
335                                                 config.max_uid = (uid_t) atol(q);
336                                         break;
337                                 case _UC_MINGID:
338                                         if ((q = unquote(q)) != NULL && isdigit(*q))
339                                                 config.min_gid = (gid_t) atol(q);
340                                         break;
341                                 case _UC_MAXGID:
342                                         if ((q = unquote(q)) != NULL && isdigit(*q))
343                                                 config.max_gid = (gid_t) atol(q);
344                                         break;
345                                 case _UC_EXPIRE:
346                                         if ((q = unquote(q)) != NULL && isdigit(*q))
347                                                 config.expire_days = atoi(q);
348                                         break;
349                                 case _UC_PASSWORD:
350                                         if ((q = unquote(q)) != NULL && isdigit(*q))
351                                                 config.password_days = atoi(q);
352                                         break;
353                                 case _UC_FIELDS:
354                                 case _UC_NONE:
355                                         break;
356                                 }
357                         }
358                 }
359                 free(buf);
360                 fclose(fp);
361         }
362         return &config;
363 }
364
365
366 int
367 write_userconfig(char const * file)
368 {
369         int             fd;
370
371         if (file == NULL)
372                 file = _PATH_PW_CONF;
373
374         if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
375                 FILE           *fp;
376
377                 if ((fp = fdopen(fd, "w")) == NULL)
378                         close(fd);
379                 else {
380                         int             i, j, k;
381                         int             len = LNBUFSZ;
382                         char           *buf = malloc(len);
383
384                         for (i = _UC_NONE; i < _UC_FIELDS; i++) {
385                                 int             quote = 1;
386                                 char const     *val = buf;
387
388                                 *buf = '\0';
389                                 switch (i) {
390                                 case _UC_DEFAULTPWD:
391                                         val = boolean_str(config.default_password);
392                                         break;
393                                 case _UC_REUSEUID:
394                                         val = boolean_str(config.reuse_uids);
395                                         break;
396                                 case _UC_REUSEGID:
397                                         val = boolean_str(config.reuse_gids);
398                                         break;
399                                 case _UC_NISPASSWD:
400                                         val = config.nispasswd ? config.nispasswd : "";
401                                         quote = 0;
402                                         break;
403                                 case _UC_DOTDIR:
404                                         val = config.dotdir ? config.dotdir : boolean_str(0);
405                                         break;
406                                 case _UC_NEWMAIL:
407                                         val = config.newmail ? config.newmail : boolean_str(0);
408                                         break;
409                                 case _UC_LOGFILE:
410                                         val = config.logfile ? config.logfile : boolean_str(0);
411                                         break;
412                                 case _UC_HOMEROOT:
413                                         val = config.home;
414                                         break;
415                                 case _UC_SHELLPATH:
416                                         val = config.shelldir;
417                                         break;
418                                 case _UC_SHELLS:
419                                         for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
420                                                 char    lbuf[64];
421                                                 int     l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
422                                                 if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
423                                                         strcpy(buf + k, lbuf);
424                                                         k += l;
425                                                 }
426                                         }
427                                         quote = 0;
428                                         break;
429                                 case _UC_DEFAULTSHELL:
430                                         val = config.shell_default ? config.shell_default : bourne_shell;
431                                         break;
432                                 case _UC_DEFAULTGROUP:
433                                         val = config.default_group ? config.default_group : "";
434                                         break;
435                                 case _UC_EXTRAGROUPS:
436                                         extendarray(&config.groups, &config.numgroups, 200);
437                                         for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
438                                                 char    lbuf[64];
439                                                 int     l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
440                                                 if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
441                                                         strcpy(buf + k, lbuf);
442                                                         k +=  l;
443                                                 }
444                                         }
445                                         quote = 0;
446                                         break;
447                                 case _UC_DEFAULTCLASS:
448                                         val = config.default_class ? config.default_class : "";
449                                         break;
450                                 case _UC_MINUID:
451                                         sprintf(buf, "%lu", (unsigned long) config.min_uid);
452                                         quote = 0;
453                                         break;
454                                 case _UC_MAXUID:
455                                         sprintf(buf, "%lu", (unsigned long) config.max_uid);
456                                         quote = 0;
457                                         break;
458                                 case _UC_MINGID:
459                                         sprintf(buf, "%lu", (unsigned long) config.min_gid);
460                                         quote = 0;
461                                         break;
462                                 case _UC_MAXGID:
463                                         sprintf(buf, "%lu", (unsigned long) config.max_gid);
464                                         quote = 0;
465                                         break;
466                                 case _UC_EXPIRE:
467                                         sprintf(buf, "%d", config.expire_days);
468                                         quote = 0;
469                                         break;
470                                 case _UC_PASSWORD:
471                                         sprintf(buf, "%d", config.password_days);
472                                         quote = 0;
473                                         break;
474                                 case _UC_NONE:
475                                         break;
476                                 }
477
478                                 if (comments[i])
479                                         fputs(comments[i], fp);
480
481                                 if (*kwds[i]) {
482                                         if (quote)
483                                                 fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
484                                         else
485                                                 fprintf(fp, "%s = %s\n", kwds[i], val);
486 #if debugging
487                                         printf("WROTE: %s = %s\n", kwds[i], val);
488 #endif
489                                 }
490                         }
491                         free(buf);
492                         return fclose(fp) != EOF;
493                 }
494         }
495         return 0;
496 }