]> git.cameronkatri.com Git - pw-darwin.git/blob - pw/pw_conf.c
Cleanup includes
[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 #include <err.h>
38
39 #include "pw.h"
40
41 #define debugging 0
42
43 enum {
44 _UC_NONE,
45 _UC_DEFAULTPWD,
46 _UC_REUSEUID,
47 _UC_REUSEGID,
48 _UC_NISPASSWD,
49 _UC_DOTDIR,
50 _UC_NEWMAIL,
51 _UC_LOGFILE,
52 _UC_HOMEROOT,
53 _UC_HOMEMODE,
54 _UC_SHELLPATH,
55 _UC_SHELLS,
56 _UC_DEFAULTSHELL,
57 _UC_DEFAULTGROUP,
58 _UC_EXTRAGROUPS,
59 _UC_DEFAULTCLASS,
60 _UC_MINUID,
61 _UC_MAXUID,
62 _UC_MINGID,
63 _UC_MAXGID,
64 _UC_EXPIRE,
65 _UC_PASSWORD,
66 _UC_FIELDS
67 };
68
69 static char bourne_shell[] = "sh";
70
71 static char *system_shells[_UC_MAXSHELLS] =
72 {
73 bourne_shell,
74 "csh",
75 "tcsh"
76 };
77
78 static char const *booltrue[] =
79 {
80 "yes", "true", "1", "on", NULL
81 };
82 static char const *boolfalse[] =
83 {
84 "no", "false", "0", "off", NULL
85 };
86
87 static struct userconf config =
88 {
89 0, /* Default password for new users? (nologin) */
90 0, /* Reuse uids? */
91 0, /* Reuse gids? */
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 };
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;
215
216 if ((p = unquote(p)) == NULL)
217 return (NULL);
218
219 if ((q = strdup(p)) == NULL)
220 err(1, "strdup()");
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 config.groups = sl_init();
237 if (config.groups == NULL)
238 err(1, "sl_init()");
239 if (file == NULL)
240 file = _PATH_PW_CONF;
241
242 if ((fp = fopen(file, "r")) == NULL)
243 return (&config);
244
245 while ((linelen = getline(&buf, &linecap, fp)) > 0) {
246 if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
247 static char const toks[] = " \t\r\n,=";
248 char *q = strtok(NULL, toks);
249 int i = 0;
250 mode_t *modeset;
251
252 while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
253 ++i;
254 #if debugging
255 if (i == _UC_FIELDS)
256 printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
257 else
258 printf("Got kwd[%s]=%s\n", p, q);
259 #endif
260 switch (i) {
261 case _UC_DEFAULTPWD:
262 config.default_password = boolean_val(q, 1);
263 break;
264 case _UC_REUSEUID:
265 config.reuse_uids = boolean_val(q, 0);
266 break;
267 case _UC_REUSEGID:
268 config.reuse_gids = boolean_val(q, 0);
269 break;
270 case _UC_NISPASSWD:
271 config.nispasswd = (q == NULL || !boolean_val(q, 1))
272 ? NULL : newstr(q);
273 break;
274 case _UC_DOTDIR:
275 config.dotdir = (q == NULL || !boolean_val(q, 1))
276 ? NULL : newstr(q);
277 break;
278 case _UC_NEWMAIL:
279 config.newmail = (q == NULL || !boolean_val(q, 1))
280 ? NULL : newstr(q);
281 break;
282 case _UC_LOGFILE:
283 config.logfile = (q == NULL || !boolean_val(q, 1))
284 ? NULL : newstr(q);
285 break;
286 case _UC_HOMEROOT:
287 config.home = (q == NULL || !boolean_val(q, 1))
288 ? "/home" : newstr(q);
289 break;
290 case _UC_HOMEMODE:
291 modeset = setmode(q);
292 config.homemode = (q == NULL || !boolean_val(q, 1))
293 ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
294 free(modeset);
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 sl_add(config.groups, newstr(q));
319 break;
320 case _UC_DEFAULTCLASS:
321 config.default_class = (q == NULL || !boolean_val(q, 1))
322 ? NULL : newstr(q);
323 break;
324 case _UC_MINUID:
325 if ((q = unquote(q)) != NULL && isdigit(*q))
326 config.min_uid = (uid_t) atol(q);
327 break;
328 case _UC_MAXUID:
329 if ((q = unquote(q)) != NULL && isdigit(*q))
330 config.max_uid = (uid_t) atol(q);
331 break;
332 case _UC_MINGID:
333 if ((q = unquote(q)) != NULL && isdigit(*q))
334 config.min_gid = (gid_t) atol(q);
335 break;
336 case _UC_MAXGID:
337 if ((q = unquote(q)) != NULL && isdigit(*q))
338 config.max_gid = (gid_t) atol(q);
339 break;
340 case _UC_EXPIRE:
341 if ((q = unquote(q)) != NULL && isdigit(*q))
342 config.expire_days = atoi(q);
343 break;
344 case _UC_PASSWORD:
345 if ((q = unquote(q)) != NULL && isdigit(*q))
346 config.password_days = atoi(q);
347 break;
348 case _UC_FIELDS:
349 case _UC_NONE:
350 break;
351 }
352 }
353 }
354 free(buf);
355 fclose(fp);
356
357 return (&config);
358 }
359
360
361 int
362 write_userconfig(char const * file)
363 {
364 int fd;
365 int i, j;
366 struct sbuf *buf;
367 FILE *fp;
368
369 if (file == NULL)
370 file = _PATH_PW_CONF;
371
372 if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
373 return (0);
374
375 if ((fp = fdopen(fd, "w")) == NULL) {
376 close(fd);
377 return (0);
378 }
379
380 buf = sbuf_new_auto();
381 for (i = _UC_NONE; i < _UC_FIELDS; i++) {
382 int quote = 1;
383
384 sbuf_clear(buf);
385 switch (i) {
386 case _UC_DEFAULTPWD:
387 sbuf_cat(buf, boolean_str(config.default_password));
388 break;
389 case _UC_REUSEUID:
390 sbuf_cat(buf, boolean_str(config.reuse_uids));
391 break;
392 case _UC_REUSEGID:
393 sbuf_cat(buf, boolean_str(config.reuse_gids));
394 break;
395 case _UC_NISPASSWD:
396 sbuf_cat(buf, config.nispasswd ? config.nispasswd :
397 "");
398 quote = 0;
399 break;
400 case _UC_DOTDIR:
401 sbuf_cat(buf, config.dotdir ? config.dotdir :
402 boolean_str(0));
403 break;
404 case _UC_NEWMAIL:
405 sbuf_cat(buf, config.newmail ? config.newmail :
406 boolean_str(0));
407 break;
408 case _UC_LOGFILE:
409 sbuf_cat(buf, config.logfile ? config.logfile :
410 boolean_str(0));
411 break;
412 case _UC_HOMEROOT:
413 sbuf_cat(buf, config.home);
414 break;
415 case _UC_HOMEMODE:
416 sbuf_printf(buf, "%04o", config.homemode);
417 quote = 0;
418 break;
419 case _UC_SHELLPATH:
420 sbuf_cat(buf, config.shelldir);
421 break;
422 case _UC_SHELLS:
423 for (j = 0; j < _UC_MAXSHELLS &&
424 system_shells[j] != NULL; j++)
425 sbuf_printf(buf, "%s\"%s\"", j ?
426 "," : "", system_shells[j]);
427 quote = 0;
428 break;
429 case _UC_DEFAULTSHELL:
430 sbuf_cat(buf, config.shell_default ?
431 config.shell_default : bourne_shell);
432 break;
433 case _UC_DEFAULTGROUP:
434 sbuf_cat(buf, config.default_group ?
435 config.default_group : "");
436 break;
437 case _UC_EXTRAGROUPS:
438 for (j = 0; config.groups != NULL &&
439 j < (int)config.groups->sl_cur; j++)
440 sbuf_printf(buf, "%s\"%s\"", j ?
441 "," : "", config.groups->sl_str[j]);
442 quote = 0;
443 break;
444 case _UC_DEFAULTCLASS:
445 sbuf_cat(buf, config.default_class ?
446 config.default_class : "");
447 break;
448 case _UC_MINUID:
449 sbuf_printf(buf, "%u", config.min_uid);
450 quote = 0;
451 break;
452 case _UC_MAXUID:
453 sbuf_printf(buf, "%u", config.max_uid);
454 quote = 0;
455 break;
456 case _UC_MINGID:
457 sbuf_printf(buf, "%u", config.min_gid);
458 quote = 0;
459 break;
460 case _UC_MAXGID:
461 sbuf_printf(buf, "%u", config.max_gid);
462 quote = 0;
463 break;
464 case _UC_EXPIRE:
465 sbuf_printf(buf, "%d", config.expire_days);
466 quote = 0;
467 break;
468 case _UC_PASSWORD:
469 sbuf_printf(buf, "%d", config.password_days);
470 quote = 0;
471 break;
472 case _UC_NONE:
473 break;
474 }
475 sbuf_finish(buf);
476
477 if (comments[i])
478 fputs(comments[i], fp);
479
480 if (*kwds[i]) {
481 if (quote)
482 fprintf(fp, "%s = \"%s\"\n", kwds[i],
483 sbuf_data(buf));
484 else
485 fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
486 #if debugging
487 printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
488 #endif
489 }
490 }
491 sbuf_delete(buf);
492 return (fclose(fp) != EOF);
493 }