120253Sjoerg/*-
220302Sjoerg * Copyright (C) 1996
320302Sjoerg *	David L. Nugent.  All rights reserved.
420253Sjoerg *
520253Sjoerg * Redistribution and use in source and binary forms, with or without
620253Sjoerg * modification, are permitted provided that the following conditions
720253Sjoerg * are met:
820253Sjoerg * 1. Redistributions of source code must retain the above copyright
920302Sjoerg *    notice, this list of conditions and the following disclaimer.
1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1120253Sjoerg *    notice, this list of conditions and the following disclaimer in the
1220253Sjoerg *    documentation and/or other materials provided with the distribution.
1320253Sjoerg *
1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1720302Sjoerg * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2420253Sjoerg * SUCH DAMAGE.
2520253Sjoerg */
2620253Sjoerg
2730259Scharnier#ifndef lint
2830259Scharnierstatic const char rcsid[] =
2950479Speter  "$FreeBSD: stable/10/usr.sbin/pw/pw_conf.c 326849 2017-12-14 13:10:22Z eugen $";
3030259Scharnier#endif /* not lint */
3130259Scharnier
32285092Sbapt#include <sys/types.h>
33285092Sbapt#include <sys/sbuf.h>
34287084Sbapt
35287084Sbapt#include <err.h>
36287084Sbapt#include <fcntl.h>
3720253Sjoerg#include <string.h>
38287084Sbapt#include <unistd.h>
3920253Sjoerg
4020253Sjoerg#include "pw.h"
4120253Sjoerg
4220253Sjoerg#define debugging 0
4320253Sjoerg
4420253Sjoergenum {
4520253Sjoerg	_UC_NONE,
4620253Sjoerg	_UC_DEFAULTPWD,
4720253Sjoerg	_UC_REUSEUID,
4820253Sjoerg	_UC_REUSEGID,
4921330Sdavidn	_UC_NISPASSWD,
5020253Sjoerg	_UC_DOTDIR,
5120253Sjoerg	_UC_NEWMAIL,
5220253Sjoerg	_UC_LOGFILE,
5320253Sjoerg	_UC_HOMEROOT,
54168044Sle	_UC_HOMEMODE,
5520253Sjoerg	_UC_SHELLPATH,
5620253Sjoerg	_UC_SHELLS,
5720253Sjoerg	_UC_DEFAULTSHELL,
5820253Sjoerg	_UC_DEFAULTGROUP,
5920253Sjoerg	_UC_EXTRAGROUPS,
6020253Sjoerg	_UC_DEFAULTCLASS,
6120253Sjoerg	_UC_MINUID,
6220253Sjoerg	_UC_MAXUID,
6320253Sjoerg	_UC_MINGID,
6420253Sjoerg	_UC_MAXGID,
6520253Sjoerg	_UC_EXPIRE,
6620253Sjoerg	_UC_PASSWORD,
6720253Sjoerg	_UC_FIELDS
6820253Sjoerg};
6920253Sjoerg
7020253Sjoergstatic char     bourne_shell[] = "sh";
7120253Sjoerg
7220253Sjoergstatic char    *system_shells[_UC_MAXSHELLS] =
7320253Sjoerg{
7420253Sjoerg	bourne_shell,
7563239Sdavidn	"csh",
7663239Sdavidn	"tcsh"
7720253Sjoerg};
7820253Sjoerg
7920253Sjoergstatic char const *booltrue[] =
8020253Sjoerg{
8120253Sjoerg	"yes", "true", "1", "on", NULL
8220253Sjoerg};
8320253Sjoergstatic char const *boolfalse[] =
8420253Sjoerg{
8520253Sjoerg	"no", "false", "0", "off", NULL
8620253Sjoerg};
8720253Sjoerg
8820253Sjoergstatic struct userconf config =
8920253Sjoerg{
9020253Sjoerg	0,			/* Default password for new users? (nologin) */
9120253Sjoerg	0,			/* Reuse uids? */
9220253Sjoerg	0,			/* Reuse gids? */
9321330Sdavidn	NULL,			/* NIS version of the passwd file */
9420253Sjoerg	"/usr/share/skel",	/* Where to obtain skeleton files */
9520253Sjoerg	NULL,			/* Mail to send to new accounts */
9620253Sjoerg	"/var/log/userlog",	/* Where to log changes */
9720253Sjoerg	"/home",		/* Where to create home directory */
98219408Sjkim	_DEF_DIRMODE,		/* Home directory perms, modified by umask */
9920253Sjoerg	"/bin",			/* Where shells are located */
10020253Sjoerg	system_shells,		/* List of shells (first is default) */
10120253Sjoerg	bourne_shell,		/* Default shell */
10220253Sjoerg	NULL,			/* Default group name */
10320747Sdavidn	NULL,			/* Default (additional) groups */
10420253Sjoerg	NULL,			/* Default login class */
10520253Sjoerg	1000, 32000,		/* Allowed range of uids */
10620253Sjoerg	1000, 32000,		/* Allowed range of gids */
10720253Sjoerg	0,			/* Days until account expires */
108287084Sbapt	0			/* Days until password expires */
10920253Sjoerg};
11020253Sjoerg
11120253Sjoergstatic char const *comments[_UC_FIELDS] =
11220253Sjoerg{
11320253Sjoerg	"#\n# pw.conf - user/group configuration defaults\n#\n",
11420253Sjoerg	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
11520253Sjoerg	"\n# Reuse gaps in uid sequence? (yes or no)\n",
11620253Sjoerg	"\n# Reuse gaps in gid sequence? (yes or no)\n",
11721330Sdavidn	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
11820253Sjoerg	"\n# Obtain default dotfiles from this directory\n",
11920253Sjoerg	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
12020253Sjoerg	"\n# Log add/change/remove information in this file\n",
12120253Sjoerg	"\n# Root directory in which $HOME directory is created\n",
122168044Sle	"\n# Mode for the new $HOME directory, will be modified by umask\n",
12320253Sjoerg	"\n# Colon separated list of directories containing valid shells\n",
12470133Sdougb	"\n# Comma separated list of available shells (without paths)\n",
12520253Sjoerg	"\n# Default shell (without path)\n",
12620253Sjoerg	"\n# Default group (leave blank for new group per user)\n",
12720253Sjoerg	"\n# Extra groups for new users\n",
12820253Sjoerg	"\n# Default login class for new users\n",
12920253Sjoerg	"\n# Range of valid default user ids\n",
13020253Sjoerg	NULL,
13120253Sjoerg	"\n# Range of valid default group ids\n",
13220253Sjoerg	NULL,
13320253Sjoerg	"\n# Days after which account expires (0=disabled)\n",
13420253Sjoerg	"\n# Days after which password expires (0=disabled)\n"
13520253Sjoerg};
13620253Sjoerg
13720253Sjoergstatic char const *kwds[] =
13820253Sjoerg{
13920253Sjoerg	"",
14020253Sjoerg	"defaultpasswd",
14120253Sjoerg	"reuseuids",
14220253Sjoerg	"reusegids",
14321330Sdavidn	"nispasswd",
14420253Sjoerg	"skeleton",
14520253Sjoerg	"newmail",
14620253Sjoerg	"logfile",
14720253Sjoerg	"home",
148168044Sle	"homemode",
14920253Sjoerg	"shellpath",
15020253Sjoerg	"shells",
15120253Sjoerg	"defaultshell",
15220253Sjoerg	"defaultgroup",
15320253Sjoerg	"extragroups",
15420253Sjoerg	"defaultclass",
15520253Sjoerg	"minuid",
15620253Sjoerg	"maxuid",
15720253Sjoerg	"mingid",
15820253Sjoerg	"maxgid",
15920253Sjoerg	"expire_days",
16020253Sjoerg	"password_days",
16120253Sjoerg	NULL
16220253Sjoerg};
16320253Sjoerg
16420253Sjoergstatic char    *
16520253Sjoergunquote(char const * str)
16620253Sjoerg{
16720253Sjoerg	if (str && (*str == '"' || *str == '\'')) {
16820253Sjoerg		char           *p = strchr(str + 1, *str);
16920253Sjoerg
17020253Sjoerg		if (p != NULL)
17120253Sjoerg			*p = '\0';
17220253Sjoerg		return (char *) (*++str ? str : NULL);
17320253Sjoerg	}
17420253Sjoerg	return (char *) str;
17520253Sjoerg}
17620253Sjoerg
17720253Sjoergint
17820253Sjoergboolean_val(char const * str, int dflt)
17920253Sjoerg{
18020253Sjoerg	if ((str = unquote(str)) != NULL) {
18120253Sjoerg		int             i;
18220253Sjoerg
18320253Sjoerg		for (i = 0; booltrue[i]; i++)
18420253Sjoerg			if (strcmp(str, booltrue[i]) == 0)
18520253Sjoerg				return 1;
18620253Sjoerg		for (i = 0; boolfalse[i]; i++)
18720253Sjoerg			if (strcmp(str, boolfalse[i]) == 0)
18820253Sjoerg				return 0;
189305750Sasomers	}
190305750Sasomers	return dflt;
191305750Sasomers}
19220253Sjoerg
193305750Sasomersint
194305750Sasomerspasswd_val(char const * str, int dflt)
195305750Sasomers{
196305750Sasomers	if ((str = unquote(str)) != NULL) {
197305750Sasomers		int             i;
198305750Sasomers
199305750Sasomers		for (i = 0; booltrue[i]; i++)
200305750Sasomers			if (strcmp(str, booltrue[i]) == 0)
201326849Seugen				return P_YES;
202305750Sasomers		for (i = 0; boolfalse[i]; i++)
203305750Sasomers			if (strcmp(str, boolfalse[i]) == 0)
204326849Seugen				return P_NO;
205305750Sasomers
20620253Sjoerg		/*
20720253Sjoerg		 * Special cases for defaultpassword
20820253Sjoerg		 */
20920253Sjoerg		if (strcmp(str, "random") == 0)
210326849Seugen			return P_RANDOM;
21120253Sjoerg		if (strcmp(str, "none") == 0)
212326849Seugen			return P_NONE;
213305750Sasomers
214305750Sasomers		errx(1, "Invalid value for default password");
21520253Sjoerg	}
21620253Sjoerg	return dflt;
21720253Sjoerg}
21820253Sjoerg
21920253Sjoergchar const     *
22020253Sjoergboolean_str(int val)
22120253Sjoerg{
22220253Sjoerg	if (val == -1)
22320253Sjoerg		return "random";
22420253Sjoerg	else if (val == -2)
22520253Sjoerg		return "none";
22620253Sjoerg	else
22720253Sjoerg		return val ? booltrue[0] : boolfalse[0];
22820253Sjoerg}
22920253Sjoerg
23020253Sjoergchar           *
23120253Sjoergnewstr(char const * p)
23220253Sjoerg{
233285092Sbapt	char	*q;
23420253Sjoerg
235285092Sbapt	if ((p = unquote(p)) == NULL)
236285092Sbapt		return (NULL);
23720253Sjoerg
238285092Sbapt	if ((q = strdup(p)) == NULL)
239285092Sbapt		err(1, "strdup()");
240285092Sbapt
241285092Sbapt	return (q);
24220253Sjoerg}
24320253Sjoerg
24420253Sjoergstruct userconf *
24520253Sjoergread_userconfig(char const * file)
24620253Sjoerg{
247268346Sbapt	FILE	*fp;
248268346Sbapt	char	*buf, *p;
249287084Sbapt	const char *errstr;
250268346Sbapt	size_t	linecap;
251268346Sbapt	ssize_t	linelen;
25220253Sjoerg
253268346Sbapt	buf = NULL;
254268346Sbapt	linecap = 0;
255268346Sbapt
25620253Sjoerg	if (file == NULL)
25720253Sjoerg		file = _PATH_PW_CONF;
258268346Sbapt
259285092Sbapt	if ((fp = fopen(file, "r")) == NULL)
260285092Sbapt		return (&config);
26120747Sdavidn
262285092Sbapt	while ((linelen = getline(&buf, &linecap, fp)) > 0) {
263285092Sbapt		if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
264285092Sbapt			static char const toks[] = " \t\r\n,=";
265285092Sbapt			char           *q = strtok(NULL, toks);
266285092Sbapt			int             i = 0;
267285092Sbapt			mode_t          *modeset;
268285092Sbapt
269285092Sbapt			while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
270285092Sbapt				++i;
27120253Sjoerg#if debugging
272285092Sbapt			if (i == _UC_FIELDS)
273285092Sbapt				printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
274285092Sbapt			else
275285092Sbapt				printf("Got kwd[%s]=%s\n", p, q);
27620253Sjoerg#endif
277285092Sbapt			switch (i) {
278285092Sbapt			case _UC_DEFAULTPWD:
279305750Sasomers				config.default_password = passwd_val(q, 1);
280285092Sbapt				break;
281285092Sbapt			case _UC_REUSEUID:
282285092Sbapt				config.reuse_uids = boolean_val(q, 0);
283285092Sbapt				break;
284285092Sbapt			case _UC_REUSEGID:
285285092Sbapt				config.reuse_gids = boolean_val(q, 0);
286285092Sbapt				break;
287285092Sbapt			case _UC_NISPASSWD:
288285092Sbapt				config.nispasswd = (q == NULL || !boolean_val(q, 1))
289285092Sbapt					? NULL : newstr(q);
290285092Sbapt				break;
291285092Sbapt			case _UC_DOTDIR:
292285092Sbapt				config.dotdir = (q == NULL || !boolean_val(q, 1))
293285092Sbapt					? NULL : newstr(q);
294285092Sbapt				break;
29520747Sdavidn				case _UC_NEWMAIL:
296285092Sbapt				config.newmail = (q == NULL || !boolean_val(q, 1))
297285092Sbapt					? NULL : newstr(q);
298285092Sbapt				break;
299285092Sbapt			case _UC_LOGFILE:
300285092Sbapt				config.logfile = (q == NULL || !boolean_val(q, 1))
301285092Sbapt					? NULL : newstr(q);
302285092Sbapt				break;
303285092Sbapt			case _UC_HOMEROOT:
304285092Sbapt				config.home = (q == NULL || !boolean_val(q, 1))
305285092Sbapt					? "/home" : newstr(q);
306285092Sbapt				break;
307285092Sbapt			case _UC_HOMEMODE:
308285092Sbapt				modeset = setmode(q);
309285092Sbapt				config.homemode = (q == NULL || !boolean_val(q, 1))
310285092Sbapt					? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
311285092Sbapt				free(modeset);
312285092Sbapt				break;
313285092Sbapt			case _UC_SHELLPATH:
314285092Sbapt				config.shelldir = (q == NULL || !boolean_val(q, 1))
315285092Sbapt					? "/bin" : newstr(q);
316285092Sbapt				break;
317285092Sbapt			case _UC_SHELLS:
318285092Sbapt				for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
319285092Sbapt					system_shells[i] = newstr(q);
320285092Sbapt				if (i > 0)
321285092Sbapt					while (i < _UC_MAXSHELLS)
322285092Sbapt						system_shells[i++] = NULL;
323285092Sbapt				break;
324285092Sbapt			case _UC_DEFAULTSHELL:
325285092Sbapt				config.shell_default = (q == NULL || !boolean_val(q, 1))
326285092Sbapt					? (char *) bourne_shell : newstr(q);
327285092Sbapt				break;
328285092Sbapt			case _UC_DEFAULTGROUP:
329285092Sbapt				q = unquote(q);
330285092Sbapt				config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
331285092Sbapt					? NULL : newstr(q);
332285092Sbapt				break;
333285092Sbapt			case _UC_EXTRAGROUPS:
334292965Sbapt				while ((q = strtok(NULL, toks)) != NULL) {
335287084Sbapt					if (config.groups == NULL)
336287084Sbapt						config.groups = sl_init();
337287084Sbapt					sl_add(config.groups, newstr(q));
33820253Sjoerg				}
339285092Sbapt				break;
340285092Sbapt			case _UC_DEFAULTCLASS:
341285092Sbapt				config.default_class = (q == NULL || !boolean_val(q, 1))
342285092Sbapt					? NULL : newstr(q);
343285092Sbapt				break;
344285092Sbapt			case _UC_MINUID:
345287084Sbapt				if ((q = unquote(q)) != NULL) {
346287084Sbapt					config.min_uid = strtounum(q, 0,
347287084Sbapt					    UID_MAX, &errstr);
348287084Sbapt					if (errstr)
349287084Sbapt						warnx("Invalid min_uid: '%s';"
350287084Sbapt						    " ignoring", q);
351287084Sbapt				}
352285092Sbapt				break;
353285092Sbapt			case _UC_MAXUID:
354287084Sbapt				if ((q = unquote(q)) != NULL) {
355287084Sbapt					config.max_uid = strtounum(q, 0,
356287084Sbapt					    UID_MAX, &errstr);
357287084Sbapt					if (errstr)
358287084Sbapt						warnx("Invalid max_uid: '%s';"
359287084Sbapt						    " ignoring", q);
360287084Sbapt				}
361285092Sbapt				break;
362285092Sbapt			case _UC_MINGID:
363287084Sbapt				if ((q = unquote(q)) != NULL) {
364287084Sbapt					config.min_gid = strtounum(q, 0,
365287084Sbapt					    GID_MAX, &errstr);
366287084Sbapt					if (errstr)
367287084Sbapt						warnx("Invalid min_gid: '%s';"
368287084Sbapt						    " ignoring", q);
369287084Sbapt				}
370285092Sbapt				break;
371285092Sbapt			case _UC_MAXGID:
372287084Sbapt				if ((q = unquote(q)) != NULL) {
373287084Sbapt					config.max_gid = strtounum(q, 0,
374287084Sbapt					    GID_MAX, &errstr);
375287084Sbapt					if (errstr)
376287084Sbapt						warnx("Invalid max_gid: '%s';"
377287084Sbapt						    " ignoring", q);
378287084Sbapt				}
379285092Sbapt				break;
380285092Sbapt			case _UC_EXPIRE:
381287084Sbapt				if ((q = unquote(q)) != NULL) {
382287084Sbapt					config.expire_days = strtonum(q, 0,
383287084Sbapt					    INT_MAX, &errstr);
384287084Sbapt					if (errstr)
385287084Sbapt						warnx("Invalid expire days:"
386287084Sbapt						    " '%s'; ignoring", q);
387287084Sbapt				}
388285092Sbapt				break;
389285092Sbapt			case _UC_PASSWORD:
390287084Sbapt				if ((q = unquote(q)) != NULL) {
391287084Sbapt					config.password_days = strtonum(q, 0,
392287084Sbapt					    INT_MAX, &errstr);
393287084Sbapt					if (errstr)
394287084Sbapt						warnx("Invalid password days:"
395287084Sbapt						    " '%s'; ignoring", q);
396287084Sbapt				}
397285092Sbapt				break;
398285092Sbapt			case _UC_FIELDS:
399285092Sbapt			case _UC_NONE:
400285092Sbapt				break;
40120253Sjoerg			}
40220253Sjoerg		}
40320253Sjoerg	}
404285092Sbapt	free(buf);
405285092Sbapt	fclose(fp);
406285092Sbapt
407285092Sbapt	return (&config);
40820253Sjoerg}
40920253Sjoerg
41020253Sjoerg
41120253Sjoergint
412287084Sbaptwrite_userconfig(struct userconf *cnf, const char *file)
41320253Sjoerg{
41420253Sjoerg	int             fd;
415285092Sbapt	int             i, j;
416285092Sbapt	struct sbuf	*buf;
417285092Sbapt	FILE           *fp;
41820253Sjoerg
41920253Sjoerg	if (file == NULL)
42020253Sjoerg		file = _PATH_PW_CONF;
42120253Sjoerg
422285092Sbapt	if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
423285092Sbapt		return (0);
42420253Sjoerg
425285092Sbapt	if ((fp = fdopen(fd, "w")) == NULL) {
426285092Sbapt		close(fd);
427285092Sbapt		return (0);
428285092Sbapt	}
429285092Sbapt
430285092Sbapt	buf = sbuf_new_auto();
431285092Sbapt	for (i = _UC_NONE; i < _UC_FIELDS; i++) {
432285092Sbapt		int             quote = 1;
43320253Sjoerg
434285092Sbapt		sbuf_clear(buf);
435285092Sbapt		switch (i) {
436285092Sbapt		case _UC_DEFAULTPWD:
437287084Sbapt			sbuf_cat(buf, boolean_str(cnf->default_password));
438285092Sbapt			break;
439285092Sbapt		case _UC_REUSEUID:
440287084Sbapt			sbuf_cat(buf, boolean_str(cnf->reuse_uids));
441285092Sbapt			break;
442285092Sbapt		case _UC_REUSEGID:
443287084Sbapt			sbuf_cat(buf, boolean_str(cnf->reuse_gids));
444285092Sbapt			break;
445285092Sbapt		case _UC_NISPASSWD:
446287084Sbapt			sbuf_cat(buf, cnf->nispasswd ?  cnf->nispasswd : "");
447285092Sbapt			quote = 0;
448285092Sbapt			break;
449285092Sbapt		case _UC_DOTDIR:
450287084Sbapt			sbuf_cat(buf, cnf->dotdir ?  cnf->dotdir :
451285092Sbapt			    boolean_str(0));
452285092Sbapt			break;
453285092Sbapt		case _UC_NEWMAIL:
454287084Sbapt			sbuf_cat(buf, cnf->newmail ?  cnf->newmail :
455285092Sbapt			    boolean_str(0));
456285092Sbapt			break;
457285092Sbapt		case _UC_LOGFILE:
458287084Sbapt			sbuf_cat(buf, cnf->logfile ?  cnf->logfile :
459285092Sbapt			    boolean_str(0));
460285092Sbapt			break;
461285092Sbapt		case _UC_HOMEROOT:
462287084Sbapt			sbuf_cat(buf, cnf->home);
463285092Sbapt			break;
464285092Sbapt		case _UC_HOMEMODE:
465287084Sbapt			sbuf_printf(buf, "%04o", cnf->homemode);
466285092Sbapt			quote = 0;
467285092Sbapt			break;
468285092Sbapt		case _UC_SHELLPATH:
469287084Sbapt			sbuf_cat(buf, cnf->shelldir);
470285092Sbapt			break;
471285092Sbapt		case _UC_SHELLS:
472285092Sbapt			for (j = 0; j < _UC_MAXSHELLS &&
473285092Sbapt			    system_shells[j] != NULL; j++)
474285092Sbapt				sbuf_printf(buf, "%s\"%s\"", j ?
475285092Sbapt				    "," : "", system_shells[j]);
476285092Sbapt			quote = 0;
477285092Sbapt			break;
478285092Sbapt		case _UC_DEFAULTSHELL:
479287084Sbapt			sbuf_cat(buf, cnf->shell_default ?
480287084Sbapt			    cnf->shell_default : bourne_shell);
481285092Sbapt			break;
482285092Sbapt		case _UC_DEFAULTGROUP:
483287084Sbapt			sbuf_cat(buf, cnf->default_group ?
484287084Sbapt			    cnf->default_group : "");
485285092Sbapt			break;
486285092Sbapt		case _UC_EXTRAGROUPS:
487287084Sbapt			for (j = 0; cnf->groups != NULL &&
488287084Sbapt			    j < (int)cnf->groups->sl_cur; j++)
489285092Sbapt				sbuf_printf(buf, "%s\"%s\"", j ?
490287084Sbapt				    "," : "", cnf->groups->sl_str[j]);
491285092Sbapt			quote = 0;
492285092Sbapt			break;
493285092Sbapt		case _UC_DEFAULTCLASS:
494287084Sbapt			sbuf_cat(buf, cnf->default_class ?
495287084Sbapt			    cnf->default_class : "");
496285092Sbapt			break;
497285092Sbapt		case _UC_MINUID:
498287084Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_uid);
499285092Sbapt			quote = 0;
500285092Sbapt			break;
501285092Sbapt		case _UC_MAXUID:
502287084Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_uid);
503285092Sbapt			quote = 0;
504285092Sbapt			break;
505285092Sbapt		case _UC_MINGID:
506287084Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_gid);
507285092Sbapt			quote = 0;
508285092Sbapt			break;
509285092Sbapt		case _UC_MAXGID:
510287084Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_gid);
511285092Sbapt			quote = 0;
512285092Sbapt			break;
513285092Sbapt		case _UC_EXPIRE:
514287084Sbapt			sbuf_printf(buf, "%jd", (intmax_t)cnf->expire_days);
515285092Sbapt			quote = 0;
516285092Sbapt			break;
517285092Sbapt		case _UC_PASSWORD:
518287084Sbapt			sbuf_printf(buf, "%jd", (intmax_t)cnf->password_days);
519285092Sbapt			quote = 0;
520285092Sbapt			break;
521285092Sbapt		case _UC_NONE:
522285092Sbapt			break;
523285092Sbapt		}
524285092Sbapt		sbuf_finish(buf);
52520253Sjoerg
526285092Sbapt		if (comments[i])
527285092Sbapt			fputs(comments[i], fp);
52820253Sjoerg
529285092Sbapt		if (*kwds[i]) {
530285092Sbapt			if (quote)
531285092Sbapt				fprintf(fp, "%s = \"%s\"\n", kwds[i],
532285092Sbapt				    sbuf_data(buf));
533285092Sbapt			else
534285092Sbapt				fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
53520253Sjoerg#if debugging
536285092Sbapt			printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
53720253Sjoerg#endif
53820253Sjoerg		}
53920253Sjoerg	}
540285092Sbapt	sbuf_delete(buf);
541285092Sbapt	return (fclose(fp) != EOF);
54220253Sjoerg}
543