3 * David L. Nugent. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 static const char rcsid[] =
32 #include <sys/types.h>
69 static char bourne_shell[] = "sh";
71 static char *system_shells[_UC_MAXSHELLS] =
78 static char const *booltrue[] =
80 "yes", "true", "1", "on", NULL
82 static char const *boolfalse[] =
84 "no", "false", "0", "off", NULL
87 static struct userconf config =
89 0, /* Default password for new users? (nologin) */
92 NULL, /* NIS version of the passwd file */
93 "/usr/share/skel", /* Where to obtain skeleton files */
94 NULL, /* Mail to send to new accounts */
95 "/var/log/userlog", /* Where to log changes */
96 "/home", /* Where to create home directory */
97 _DEF_DIRMODE, /* Home directory perms, modified by umask */
98 "/bin", /* Where shells are located */
99 system_shells, /* List of shells (first is default) */
100 bourne_shell, /* Default shell */
101 NULL, /* Default group name */
102 NULL, /* Default (additional) groups */
103 NULL, /* Default login class */
104 1000, 32000, /* Allowed range of uids */
105 1000, 32000, /* Allowed range of gids */
106 0, /* Days until account expires */
107 0, /* Days until password expires */
108 0 /* size of default_group array */
111 static char const *comments[_UC_FIELDS] =
113 "#\n# pw.conf - user/group configuration defaults\n#\n",
114 "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
115 "\n# Reuse gaps in uid sequence? (yes or no)\n",
116 "\n# Reuse gaps in gid sequence? (yes or no)\n",
117 "\n# Path to the NIS passwd file (blank or 'no' for none)\n",
118 "\n# Obtain default dotfiles from this directory\n",
119 "\n# Mail this file to new user (/etc/newuser.msg or no)\n",
120 "\n# Log add/change/remove information in this file\n",
121 "\n# Root directory in which $HOME directory is created\n",
122 "\n# Mode for the new $HOME directory, will be modified by umask\n",
123 "\n# Colon separated list of directories containing valid shells\n",
124 "\n# Comma separated list of available shells (without paths)\n",
125 "\n# Default shell (without path)\n",
126 "\n# Default group (leave blank for new group per user)\n",
127 "\n# Extra groups for new users\n",
128 "\n# Default login class for new users\n",
129 "\n# Range of valid default user ids\n",
131 "\n# Range of valid default group ids\n",
133 "\n# Days after which account expires (0=disabled)\n",
134 "\n# Days after which password expires (0=disabled)\n"
137 static char const *kwds[] =
165 unquote(char const * str)
167 if (str && (*str == '"' || *str == '\'')) {
168 char *p = strchr(str + 1, *str);
172 return (char *) (*++str ? str : NULL);
178 boolean_val(char const * str, int dflt)
180 if ((str = unquote(str)) != NULL) {
183 for (i = 0; booltrue[i]; i++)
184 if (strcmp(str, booltrue[i]) == 0)
186 for (i = 0; boolfalse[i]; i++)
187 if (strcmp(str, boolfalse[i]) == 0)
191 * Special cases for defaultpassword
193 if (strcmp(str, "random") == 0)
195 if (strcmp(str, "none") == 0)
209 return val ? booltrue[0] : boolfalse[0];
213 newstr(char const * p)
217 if ((p = unquote(p)) == NULL)
220 if ((q = strdup(p)) == NULL)
227 read_userconfig(char const * file)
237 config.numgroups = 200;
238 config.groups = calloc(config.numgroups, sizeof(char *));
239 if (config.groups == NULL)
242 file = _PATH_PW_CONF;
244 if ((fp = fopen(file, "r")) == NULL)
247 while ((linelen = getline(&buf, &linecap, fp)) > 0) {
248 if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
249 static char const toks[] = " \t\r\n,=";
250 char *q = strtok(NULL, toks);
254 while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
258 printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
260 printf("Got kwd[%s]=%s\n", p, q);
264 config.default_password = boolean_val(q, 1);
267 config.reuse_uids = boolean_val(q, 0);
270 config.reuse_gids = boolean_val(q, 0);
273 config.nispasswd = (q == NULL || !boolean_val(q, 1))
277 config.dotdir = (q == NULL || !boolean_val(q, 1))
281 config.newmail = (q == NULL || !boolean_val(q, 1))
285 config.logfile = (q == NULL || !boolean_val(q, 1))
289 config.home = (q == NULL || !boolean_val(q, 1))
290 ? "/home" : newstr(q);
293 modeset = setmode(q);
294 config.homemode = (q == NULL || !boolean_val(q, 1))
295 ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
299 config.shelldir = (q == NULL || !boolean_val(q, 1))
300 ? "/bin" : newstr(q);
303 for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
304 system_shells[i] = newstr(q);
306 while (i < _UC_MAXSHELLS)
307 system_shells[i++] = NULL;
309 case _UC_DEFAULTSHELL:
310 config.shell_default = (q == NULL || !boolean_val(q, 1))
311 ? (char *) bourne_shell : newstr(q);
313 case _UC_DEFAULTGROUP:
315 config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
318 case _UC_EXTRAGROUPS:
319 for (i = 0; q != NULL; q = strtok(NULL, toks)) {
320 if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
321 config.groups[i++] = newstr(q);
324 while (i < config.numgroups)
325 config.groups[i++] = NULL;
327 case _UC_DEFAULTCLASS:
328 config.default_class = (q == NULL || !boolean_val(q, 1))
332 if ((q = unquote(q)) != NULL && isdigit(*q))
333 config.min_uid = (uid_t) atol(q);
336 if ((q = unquote(q)) != NULL && isdigit(*q))
337 config.max_uid = (uid_t) atol(q);
340 if ((q = unquote(q)) != NULL && isdigit(*q))
341 config.min_gid = (gid_t) atol(q);
344 if ((q = unquote(q)) != NULL && isdigit(*q))
345 config.max_gid = (gid_t) atol(q);
348 if ((q = unquote(q)) != NULL && isdigit(*q))
349 config.expire_days = atoi(q);
352 if ((q = unquote(q)) != NULL && isdigit(*q))
353 config.password_days = atoi(q);
369 write_userconfig(char const * file)
377 file = _PATH_PW_CONF;
379 if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
382 if ((fp = fdopen(fd, "w")) == NULL) {
387 buf = sbuf_new_auto();
388 for (i = _UC_NONE; i < _UC_FIELDS; i++) {
394 sbuf_cat(buf, boolean_str(config.default_password));
397 sbuf_cat(buf, boolean_str(config.reuse_uids));
400 sbuf_cat(buf, boolean_str(config.reuse_gids));
403 sbuf_cat(buf, config.nispasswd ? config.nispasswd :
408 sbuf_cat(buf, config.dotdir ? config.dotdir :
412 sbuf_cat(buf, config.newmail ? config.newmail :
416 sbuf_cat(buf, config.logfile ? config.logfile :
420 sbuf_cat(buf, config.home);
423 sbuf_printf(buf, "%04o", config.homemode);
427 sbuf_cat(buf, config.shelldir);
430 for (j = 0; j < _UC_MAXSHELLS &&
431 system_shells[j] != NULL; j++)
432 sbuf_printf(buf, "%s\"%s\"", j ?
433 "," : "", system_shells[j]);
436 case _UC_DEFAULTSHELL:
437 sbuf_cat(buf, config.shell_default ?
438 config.shell_default : bourne_shell);
440 case _UC_DEFAULTGROUP:
441 sbuf_cat(buf, config.default_group ?
442 config.default_group : "");
444 case _UC_EXTRAGROUPS:
445 for (j = 0; j < config.numgroups &&
446 config.groups[j] != NULL; j++)
447 sbuf_printf(buf, "%s\"%s\"", j ?
448 "," : "", config.groups[j]);
451 case _UC_DEFAULTCLASS:
452 sbuf_cat(buf, config.default_class ?
453 config.default_class : "");
456 sbuf_printf(buf, "%u", config.min_uid);
460 sbuf_printf(buf, "%u", config.max_uid);
464 sbuf_printf(buf, "%u", config.min_gid);
468 sbuf_printf(buf, "%u", config.max_gid);
472 sbuf_printf(buf, "%d", config.expire_days);
476 sbuf_printf(buf, "%d", config.password_days);
485 fputs(comments[i], fp);
489 fprintf(fp, "%s = \"%s\"\n", kwds[i],
492 fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
494 printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
499 return (fclose(fp) != EOF);