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
26 * $FreeBSD: src/usr.sbin/pw/pw_conf.c,v 1.10.2.2 2001/01/14 08:41:19 dougb Exp $
27 * $DragonFly: src/usr.sbin/pw/pw_conf.c,v 1.2 2003/06/17 04:30:02 dillon Exp $
63 static char bourne_shell[] = "sh";
65 static char *system_shells[_UC_MAXSHELLS] =
72 static char const *booltrue[] =
74 "yes", "true", "1", "on", NULL
76 static char const *boolfalse[] =
78 "no", "false", "0", "off", NULL
81 static struct userconf config =
83 0, /* Default password for new users? (nologin) */
86 NULL, /* NIS version of the passwd file */
87 "/usr/share/skel", /* Where to obtain skeleton files */
88 NULL, /* Mail to send to new accounts */
89 "/var/log/userlog", /* Where to log changes */
90 "/home", /* Where to create home directory */
91 "/bin", /* Where shells are located */
92 system_shells, /* List of shells (first is default) */
93 bourne_shell, /* Default shell */
94 NULL, /* Default group name */
95 NULL, /* Default (additional) groups */
96 NULL, /* Default login class */
97 1000, 32000, /* Allowed range of uids */
98 1000, 32000, /* Allowed range of gids */
99 0, /* Days until account expires */
100 0, /* Days until password expires */
101 0 /* size of default_group array */
104 static char const *comments[_UC_FIELDS] =
106 "#\n# pw.conf - user/group configuration defaults\n#\n",
107 "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
108 "\n# Reuse gaps in uid sequence? (yes or no)\n",
109 "\n# Reuse gaps in gid sequence? (yes or no)\n",
110 "\n# Path to the NIS passwd file (blank or 'no' for none)\n",
111 "\n# Obtain default dotfiles from this directory\n",
112 "\n# Mail this file to new user (/etc/newuser.msg or no)\n",
113 "\n# Log add/change/remove information in this file\n",
114 "\n# Root directory in which $HOME directory is created\n",
115 "\n# Colon separated list of directories containing valid shells\n",
116 "\n# Comma separated list of available shells (without paths)\n",
117 "\n# Default shell (without path)\n",
118 "\n# Default group (leave blank for new group per user)\n",
119 "\n# Extra groups for new users\n",
120 "\n# Default login class for new users\n",
121 "\n# Range of valid default user ids\n",
123 "\n# Range of valid default group ids\n",
125 "\n# Days after which account expires (0=disabled)\n",
126 "\n# Days after which password expires (0=disabled)\n"
129 static char const *kwds[] =
156 unquote(char const * str)
158 if (str && (*str == '"' || *str == '\'')) {
159 char *p = strchr(str + 1, *str);
163 return (char *) (*++str ? str : NULL);
169 boolean_val(char const * str, int dflt)
171 if ((str = unquote(str)) != NULL) {
174 for (i = 0; booltrue[i]; i++)
175 if (strcmp(str, booltrue[i]) == 0)
177 for (i = 0; boolfalse[i]; i++)
178 if (strcmp(str, boolfalse[i]) == 0)
182 * Special cases for defaultpassword
184 if (strcmp(str, "random") == 0)
186 if (strcmp(str, "none") == 0)
200 return val ? booltrue[0] : boolfalse[0];
204 newstr(char const * p)
208 if ((p = unquote(p)) != NULL) {
209 int l = strlen(p) + 1;
211 if ((q = malloc(l)) != NULL)
221 read_userconfig(char const * file)
225 extendarray(&config.groups, &config.numgroups, 200);
226 memset(config.groups, 0, config.numgroups * sizeof(char *));
228 file = _PATH_PW_CONF;
229 if ((fp = fopen(file, "r")) != NULL) {
230 int buflen = LNBUFSZ;
231 char *buf = malloc(buflen);
234 while (fgets(buf, buflen, fp) != NULL) {
237 while ((p = strchr(buf, '\n')) == NULL) {
239 if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
241 while ((ch = fgetc(fp)) != '\n' && ch != EOF);
242 goto nextline; /* Ignore it */
245 if (fgets(buf + l, buflen - l, fp) == NULL)
246 break; /* Unterminated last line */
252 if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
253 static char const toks[] = " \t\r\n,=";
254 char *q = strtok(NULL, toks);
257 while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
261 printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
263 printf("Got kwd[%s]=%s\n", p, q);
267 config.default_password = boolean_val(q, 1);
270 config.reuse_uids = boolean_val(q, 0);
273 config.reuse_gids = boolean_val(q, 0);
276 config.nispasswd = (q == NULL || !boolean_val(q, 1))
280 config.dotdir = (q == NULL || !boolean_val(q, 1))
284 config.newmail = (q == NULL || !boolean_val(q, 1))
288 config.logfile = (q == NULL || !boolean_val(q, 1))
292 config.home = (q == NULL || !boolean_val(q, 1))
293 ? "/home" : newstr(q);
296 config.shelldir = (q == NULL || !boolean_val(q, 1))
297 ? "/bin" : newstr(q);
300 for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
301 system_shells[i] = newstr(q);
303 while (i < _UC_MAXSHELLS)
304 system_shells[i++] = NULL;
306 case _UC_DEFAULTSHELL:
307 config.shell_default = (q == NULL || !boolean_val(q, 1))
308 ? (char *) bourne_shell : newstr(q);
310 case _UC_DEFAULTGROUP:
312 config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
315 case _UC_EXTRAGROUPS:
316 for (i = 0; q != NULL; q = strtok(NULL, toks)) {
317 if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
318 config.groups[i++] = newstr(q);
321 while (i < config.numgroups)
322 config.groups[i++] = NULL;
324 case _UC_DEFAULTCLASS:
325 config.default_class = (q == NULL || !boolean_val(q, 1))
329 if ((q = unquote(q)) != NULL && isdigit(*q))
330 config.min_uid = (uid_t) atol(q);
333 if ((q = unquote(q)) != NULL && isdigit(*q))
334 config.max_uid = (uid_t) atol(q);
337 if ((q = unquote(q)) != NULL && isdigit(*q))
338 config.min_gid = (gid_t) atol(q);
341 if ((q = unquote(q)) != NULL && isdigit(*q))
342 config.max_gid = (gid_t) atol(q);
345 if ((q = unquote(q)) != NULL && isdigit(*q))
346 config.expire_days = atoi(q);
349 if ((q = unquote(q)) != NULL && isdigit(*q))
350 config.password_days = atoi(q);
366 write_userconfig(char const * file)
371 file = _PATH_PW_CONF;
373 if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
376 if ((fp = fdopen(fd, "w")) == NULL)
381 char *buf = malloc(len);
383 for (i = _UC_NONE; i < _UC_FIELDS; i++) {
385 char const *val = buf;
390 val = boolean_str(config.default_password);
393 val = boolean_str(config.reuse_uids);
396 val = boolean_str(config.reuse_gids);
399 val = config.nispasswd ? config.nispasswd : "";
403 val = config.dotdir ? config.dotdir : boolean_str(0);
406 val = config.newmail ? config.newmail : boolean_str(0);
409 val = config.logfile ? config.logfile : boolean_str(0);
415 val = config.shelldir;
418 for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
420 int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
421 if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
422 strcpy(buf + k, lbuf);
428 case _UC_DEFAULTSHELL:
429 val = config.shell_default ? config.shell_default : bourne_shell;
431 case _UC_DEFAULTGROUP:
432 val = config.default_group ? config.default_group : "";
434 case _UC_EXTRAGROUPS:
435 extendarray(&config.groups, &config.numgroups, 200);
436 for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
438 int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
439 if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
440 strcpy(buf + k, lbuf);
446 case _UC_DEFAULTCLASS:
447 val = config.default_class ? config.default_class : "";
450 sprintf(buf, "%lu", (unsigned long) config.min_uid);
454 sprintf(buf, "%lu", (unsigned long) config.max_uid);
458 sprintf(buf, "%lu", (unsigned long) config.min_gid);
462 sprintf(buf, "%lu", (unsigned long) config.max_gid);
466 sprintf(buf, "%d", config.expire_days);
470 sprintf(buf, "%d", config.password_days);
478 fputs(comments[i], fp);
482 fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
484 fprintf(fp, "%s = %s\n", kwds[i], val);
486 printf("WROTE: %s = %s\n", kwds[i], val);
491 return fclose(fp) != EOF;