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