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