pw_conf.c revision 305741
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/11/usr.sbin/pw/pw_conf.c 305741 2016-09-12 16:28:32Z asomers $";
3030259Scharnier#endif /* not lint */
3130259Scharnier
32282681Sbapt#include <sys/types.h>
33282681Sbapt#include <sys/sbuf.h>
34286201Sbapt
35286201Sbapt#include <err.h>
36286201Sbapt#include <fcntl.h>
3720253Sjoerg#include <string.h>
38286201Sbapt#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 */
108285412Sbapt	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;
189305741Sasomers	}
190305741Sasomers	return dflt;
191305741Sasomers}
19220253Sjoerg
193305741Sasomersint
194305741Sasomerspasswd_val(char const * str, int dflt)
195305741Sasomers{
196305741Sasomers	if ((str = unquote(str)) != NULL) {
197305741Sasomers		int             i;
198305741Sasomers
199305741Sasomers		for (i = 0; booltrue[i]; i++)
200305741Sasomers			if (strcmp(str, booltrue[i]) == 0)
201305741Sasomers				return 1;
202305741Sasomers		for (i = 0; boolfalse[i]; i++)
203305741Sasomers			if (strcmp(str, boolfalse[i]) == 0)
204305741Sasomers				return 0;
205305741Sasomers
20620253Sjoerg		/*
20720253Sjoerg		 * Special cases for defaultpassword
20820253Sjoerg		 */
20920253Sjoerg		if (strcmp(str, "random") == 0)
21020253Sjoerg			return -1;
21120253Sjoerg		if (strcmp(str, "none") == 0)
21220253Sjoerg			return -2;
213305741Sasomers
214305741Sasomers		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{
233282718Sbapt	char	*q;
23420253Sjoerg
235282718Sbapt	if ((p = unquote(p)) == NULL)
236282718Sbapt		return (NULL);
23720253Sjoerg
238282719Sbapt	if ((q = strdup(p)) == NULL)
239282719Sbapt		err(1, "strdup()");
240282718Sbapt
241282718Sbapt	return (q);
24220253Sjoerg}
24320253Sjoerg
24420253Sjoergstruct userconf *
24520253Sjoergread_userconfig(char const * file)
24620253Sjoerg{
247264781Sbapt	FILE	*fp;
248264781Sbapt	char	*buf, *p;
249286154Sbapt	const char *errstr;
250264781Sbapt	size_t	linecap;
251264781Sbapt	ssize_t	linelen;
25220253Sjoerg
253264781Sbapt	buf = NULL;
254264781Sbapt	linecap = 0;
255264781Sbapt
25620253Sjoerg	if (file == NULL)
25720253Sjoerg		file = _PATH_PW_CONF;
258264781Sbapt
259283815Sbapt	if ((fp = fopen(file, "r")) == NULL)
260283815Sbapt		return (&config);
26120747Sdavidn
262283815Sbapt	while ((linelen = getline(&buf, &linecap, fp)) > 0) {
263283815Sbapt		if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
264283815Sbapt			static char const toks[] = " \t\r\n,=";
265283815Sbapt			char           *q = strtok(NULL, toks);
266283815Sbapt			int             i = 0;
267283815Sbapt			mode_t          *modeset;
268283815Sbapt
269283815Sbapt			while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
270283815Sbapt				++i;
27120253Sjoerg#if debugging
272283815Sbapt			if (i == _UC_FIELDS)
273283815Sbapt				printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
274283815Sbapt			else
275283815Sbapt				printf("Got kwd[%s]=%s\n", p, q);
27620253Sjoerg#endif
277283815Sbapt			switch (i) {
278283815Sbapt			case _UC_DEFAULTPWD:
279305741Sasomers				config.default_password = passwd_val(q, 1);
280283815Sbapt				break;
281283815Sbapt			case _UC_REUSEUID:
282283815Sbapt				config.reuse_uids = boolean_val(q, 0);
283283815Sbapt				break;
284283815Sbapt			case _UC_REUSEGID:
285283815Sbapt				config.reuse_gids = boolean_val(q, 0);
286283815Sbapt				break;
287283815Sbapt			case _UC_NISPASSWD:
288283815Sbapt				config.nispasswd = (q == NULL || !boolean_val(q, 1))
289283815Sbapt					? NULL : newstr(q);
290283815Sbapt				break;
291283815Sbapt			case _UC_DOTDIR:
292283815Sbapt				config.dotdir = (q == NULL || !boolean_val(q, 1))
293283815Sbapt					? NULL : newstr(q);
294283815Sbapt				break;
29520747Sdavidn				case _UC_NEWMAIL:
296283815Sbapt				config.newmail = (q == NULL || !boolean_val(q, 1))
297283815Sbapt					? NULL : newstr(q);
298283815Sbapt				break;
299283815Sbapt			case _UC_LOGFILE:
300283815Sbapt				config.logfile = (q == NULL || !boolean_val(q, 1))
301283815Sbapt					? NULL : newstr(q);
302283815Sbapt				break;
303283815Sbapt			case _UC_HOMEROOT:
304283815Sbapt				config.home = (q == NULL || !boolean_val(q, 1))
305283815Sbapt					? "/home" : newstr(q);
306283815Sbapt				break;
307283815Sbapt			case _UC_HOMEMODE:
308283815Sbapt				modeset = setmode(q);
309283815Sbapt				config.homemode = (q == NULL || !boolean_val(q, 1))
310283815Sbapt					? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
311283815Sbapt				free(modeset);
312283815Sbapt				break;
313283815Sbapt			case _UC_SHELLPATH:
314283815Sbapt				config.shelldir = (q == NULL || !boolean_val(q, 1))
315283815Sbapt					? "/bin" : newstr(q);
316283815Sbapt				break;
317283815Sbapt			case _UC_SHELLS:
318283815Sbapt				for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
319283815Sbapt					system_shells[i] = newstr(q);
320283815Sbapt				if (i > 0)
321283815Sbapt					while (i < _UC_MAXSHELLS)
322283815Sbapt						system_shells[i++] = NULL;
323283815Sbapt				break;
324283815Sbapt			case _UC_DEFAULTSHELL:
325283815Sbapt				config.shell_default = (q == NULL || !boolean_val(q, 1))
326283815Sbapt					? (char *) bourne_shell : newstr(q);
327283815Sbapt				break;
328283815Sbapt			case _UC_DEFAULTGROUP:
329283815Sbapt				q = unquote(q);
330283815Sbapt				config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
331283815Sbapt					? NULL : newstr(q);
332283815Sbapt				break;
333283815Sbapt			case _UC_EXTRAGROUPS:
334292849Sbapt				while ((q = strtok(NULL, toks)) != NULL) {
335286196Sbapt					if (config.groups == NULL)
336286196Sbapt						config.groups = sl_init();
337285412Sbapt					sl_add(config.groups, newstr(q));
338286196Sbapt				}
339283815Sbapt				break;
340283815Sbapt			case _UC_DEFAULTCLASS:
341283815Sbapt				config.default_class = (q == NULL || !boolean_val(q, 1))
342283815Sbapt					? NULL : newstr(q);
343283815Sbapt				break;
344283815Sbapt			case _UC_MINUID:
345286151Sbapt				if ((q = unquote(q)) != NULL) {
346286154Sbapt					config.min_uid = strtounum(q, 0,
347286154Sbapt					    UID_MAX, &errstr);
348286151Sbapt					if (errstr)
349286154Sbapt						warnx("Invalid min_uid: '%s';"
350286154Sbapt						    " ignoring", q);
351286151Sbapt				}
352283815Sbapt				break;
353283815Sbapt			case _UC_MAXUID:
354286151Sbapt				if ((q = unquote(q)) != NULL) {
355286154Sbapt					config.max_uid = strtounum(q, 0,
356286154Sbapt					    UID_MAX, &errstr);
357286151Sbapt					if (errstr)
358286154Sbapt						warnx("Invalid max_uid: '%s';"
359286154Sbapt						    " ignoring", q);
360286151Sbapt				}
361283815Sbapt				break;
362283815Sbapt			case _UC_MINGID:
363286154Sbapt				if ((q = unquote(q)) != NULL) {
364286154Sbapt					config.min_gid = strtounum(q, 0,
365286154Sbapt					    GID_MAX, &errstr);
366286151Sbapt					if (errstr)
367286154Sbapt						warnx("Invalid min_gid: '%s';"
368286154Sbapt						    " ignoring", q);
369286155Sbapt				}
370283815Sbapt				break;
371283815Sbapt			case _UC_MAXGID:
372286151Sbapt				if ((q = unquote(q)) != NULL) {
373286154Sbapt					config.max_gid = strtounum(q, 0,
374286154Sbapt					    GID_MAX, &errstr);
375286151Sbapt					if (errstr)
376286154Sbapt						warnx("Invalid max_gid: '%s';"
377286154Sbapt						    " ignoring", q);
378286151Sbapt				}
379283815Sbapt				break;
380283815Sbapt			case _UC_EXPIRE:
381286152Sbapt				if ((q = unquote(q)) != NULL) {
382286154Sbapt					config.expire_days = strtonum(q, 0,
383286154Sbapt					    INT_MAX, &errstr);
384286152Sbapt					if (errstr)
385286154Sbapt						warnx("Invalid expire days:"
386286154Sbapt						    " '%s'; ignoring", q);
387286152Sbapt				}
388283815Sbapt				break;
389283815Sbapt			case _UC_PASSWORD:
390286152Sbapt				if ((q = unquote(q)) != NULL) {
391286154Sbapt					config.password_days = strtonum(q, 0,
392286154Sbapt					    INT_MAX, &errstr);
393286152Sbapt					if (errstr)
394286154Sbapt						warnx("Invalid password days:"
395286154Sbapt						    " '%s'; ignoring", q);
396286152Sbapt				}
397283815Sbapt				break;
398283815Sbapt			case _UC_FIELDS:
399283815Sbapt			case _UC_NONE:
400283815Sbapt				break;
40120253Sjoerg			}
40220253Sjoerg		}
40320253Sjoerg	}
404283818Sbapt	free(buf);
405283818Sbapt	fclose(fp);
406283818Sbapt
407283815Sbapt	return (&config);
40820253Sjoerg}
40920253Sjoerg
41020253Sjoerg
41120253Sjoergint
412286196Sbaptwrite_userconfig(struct userconf *cnf, const char *file)
41320253Sjoerg{
41420253Sjoerg	int             fd;
415282697Sbapt	int             i, j;
416282681Sbapt	struct sbuf	*buf;
417282697Sbapt	FILE           *fp;
41820253Sjoerg
41920253Sjoerg	if (file == NULL)
42020253Sjoerg		file = _PATH_PW_CONF;
42120253Sjoerg
422282697Sbapt	if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
423282697Sbapt		return (0);
42420253Sjoerg
425282697Sbapt	if ((fp = fdopen(fd, "w")) == NULL) {
426282697Sbapt		close(fd);
427282697Sbapt		return (0);
428282697Sbapt	}
429282681Sbapt
430282697Sbapt	buf = sbuf_new_auto();
431282697Sbapt	for (i = _UC_NONE; i < _UC_FIELDS; i++) {
432282697Sbapt		int             quote = 1;
43320253Sjoerg
434282697Sbapt		sbuf_clear(buf);
435282697Sbapt		switch (i) {
436282697Sbapt		case _UC_DEFAULTPWD:
437286196Sbapt			sbuf_cat(buf, boolean_str(cnf->default_password));
438282697Sbapt			break;
439282697Sbapt		case _UC_REUSEUID:
440286196Sbapt			sbuf_cat(buf, boolean_str(cnf->reuse_uids));
441282697Sbapt			break;
442282697Sbapt		case _UC_REUSEGID:
443286196Sbapt			sbuf_cat(buf, boolean_str(cnf->reuse_gids));
444282697Sbapt			break;
445282697Sbapt		case _UC_NISPASSWD:
446286196Sbapt			sbuf_cat(buf, cnf->nispasswd ?  cnf->nispasswd : "");
447282697Sbapt			quote = 0;
448282697Sbapt			break;
449282697Sbapt		case _UC_DOTDIR:
450286196Sbapt			sbuf_cat(buf, cnf->dotdir ?  cnf->dotdir :
451282697Sbapt			    boolean_str(0));
452282697Sbapt			break;
453282697Sbapt		case _UC_NEWMAIL:
454286196Sbapt			sbuf_cat(buf, cnf->newmail ?  cnf->newmail :
455282697Sbapt			    boolean_str(0));
456282697Sbapt			break;
457282697Sbapt		case _UC_LOGFILE:
458286196Sbapt			sbuf_cat(buf, cnf->logfile ?  cnf->logfile :
459282697Sbapt			    boolean_str(0));
460282697Sbapt			break;
461282697Sbapt		case _UC_HOMEROOT:
462286196Sbapt			sbuf_cat(buf, cnf->home);
463282697Sbapt			break;
464282697Sbapt		case _UC_HOMEMODE:
465286196Sbapt			sbuf_printf(buf, "%04o", cnf->homemode);
466282697Sbapt			quote = 0;
467282697Sbapt			break;
468282697Sbapt		case _UC_SHELLPATH:
469286196Sbapt			sbuf_cat(buf, cnf->shelldir);
470282697Sbapt			break;
471282697Sbapt		case _UC_SHELLS:
472282697Sbapt			for (j = 0; j < _UC_MAXSHELLS &&
473282697Sbapt			    system_shells[j] != NULL; j++)
474282697Sbapt				sbuf_printf(buf, "%s\"%s\"", j ?
475282697Sbapt				    "," : "", system_shells[j]);
476282697Sbapt			quote = 0;
477282697Sbapt			break;
478282697Sbapt		case _UC_DEFAULTSHELL:
479286196Sbapt			sbuf_cat(buf, cnf->shell_default ?
480286196Sbapt			    cnf->shell_default : bourne_shell);
481282697Sbapt			break;
482282697Sbapt		case _UC_DEFAULTGROUP:
483286196Sbapt			sbuf_cat(buf, cnf->default_group ?
484286196Sbapt			    cnf->default_group : "");
485282697Sbapt			break;
486282697Sbapt		case _UC_EXTRAGROUPS:
487286196Sbapt			for (j = 0; cnf->groups != NULL &&
488286196Sbapt			    j < (int)cnf->groups->sl_cur; j++)
489282697Sbapt				sbuf_printf(buf, "%s\"%s\"", j ?
490286196Sbapt				    "," : "", cnf->groups->sl_str[j]);
491282697Sbapt			quote = 0;
492282697Sbapt			break;
493282697Sbapt		case _UC_DEFAULTCLASS:
494286196Sbapt			sbuf_cat(buf, cnf->default_class ?
495286196Sbapt			    cnf->default_class : "");
496282697Sbapt			break;
497282697Sbapt		case _UC_MINUID:
498286196Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_uid);
499282697Sbapt			quote = 0;
500282697Sbapt			break;
501282697Sbapt		case _UC_MAXUID:
502286196Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_uid);
503282697Sbapt			quote = 0;
504282697Sbapt			break;
505282697Sbapt		case _UC_MINGID:
506286196Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_gid);
507282697Sbapt			quote = 0;
508282697Sbapt			break;
509282697Sbapt		case _UC_MAXGID:
510286196Sbapt			sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_gid);
511282697Sbapt			quote = 0;
512282697Sbapt			break;
513282697Sbapt		case _UC_EXPIRE:
514286211Sbapt			sbuf_printf(buf, "%jd", (intmax_t)cnf->expire_days);
515282697Sbapt			quote = 0;
516282697Sbapt			break;
517282697Sbapt		case _UC_PASSWORD:
518286211Sbapt			sbuf_printf(buf, "%jd", (intmax_t)cnf->password_days);
519282697Sbapt			quote = 0;
520282697Sbapt			break;
521282697Sbapt		case _UC_NONE:
522282697Sbapt			break;
523282697Sbapt		}
524282697Sbapt		sbuf_finish(buf);
52520253Sjoerg
526282697Sbapt		if (comments[i])
527282697Sbapt			fputs(comments[i], fp);
52820253Sjoerg
529282697Sbapt		if (*kwds[i]) {
530282697Sbapt			if (quote)
531282697Sbapt				fprintf(fp, "%s = \"%s\"\n", kwds[i],
532282697Sbapt				    sbuf_data(buf));
533282697Sbapt			else
534282697Sbapt				fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
53520253Sjoerg#if debugging
536282697Sbapt			printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
53720253Sjoerg#endif
53820253Sjoerg		}
53920253Sjoerg	}
540282697Sbapt	sbuf_delete(buf);
541282697Sbapt	return (fclose(fp) != EOF);
54220253Sjoerg}
543