pw_conf.c revision 283818
1183593Sjkoshy/*-
2183593Sjkoshy * Copyright (C) 1996
3183593Sjkoshy *	David L. Nugent.  All rights reserved.
4183593Sjkoshy *
5183593Sjkoshy * Redistribution and use in source and binary forms, with or without
6183593Sjkoshy * modification, are permitted provided that the following conditions
7183593Sjkoshy * are met:
8183593Sjkoshy * 1. Redistributions of source code must retain the above copyright
9183593Sjkoshy *    notice, this list of conditions and the following disclaimer.
10183593Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
11183593Sjkoshy *    notice, this list of conditions and the following disclaimer in the
12231871Sbrueffer *    documentation and/or other materials provided with the distribution.
13231871Sbrueffer *
14231871Sbrueffer * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15231871Sbrueffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16231871Sbrueffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17231871Sbrueffer * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18231871Sbrueffer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19231871Sbrueffer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20231871Sbrueffer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21231871Sbrueffer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22231871Sbrueffer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23183593Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24183593Sjkoshy * SUCH DAMAGE.
25183593Sjkoshy */
26184892Sjkoshy
27206622Suqs#ifndef lint
28183593Sjkoshystatic const char rcsid[] =
29183593Sjkoshy  "$FreeBSD: head/usr.sbin/pw/pw_conf.c 283818 2015-05-31 12:04:06Z bapt $";
30183593Sjkoshy#endif /* not lint */
31183593Sjkoshy
32183593Sjkoshy#include <sys/types.h>
33183593Sjkoshy#include <sys/sbuf.h>
34183593Sjkoshy#include <string.h>
35183593Sjkoshy#include <ctype.h>
36183593Sjkoshy#include <fcntl.h>
37183593Sjkoshy#include <err.h>
38183593Sjkoshy
39183593Sjkoshy#include "pw.h"
40183593Sjkoshy
41183593Sjkoshy#define debugging 0
42183593Sjkoshy
43183593Sjkoshyenum {
44183593Sjkoshy	_UC_NONE,
45183593Sjkoshy	_UC_DEFAULTPWD,
46183593Sjkoshy	_UC_REUSEUID,
47183593Sjkoshy	_UC_REUSEGID,
48183593Sjkoshy	_UC_NISPASSWD,
49183593Sjkoshy	_UC_DOTDIR,
50183593Sjkoshy	_UC_NEWMAIL,
51183593Sjkoshy	_UC_LOGFILE,
52208595Suqs	_UC_HOMEROOT,
53208595Suqs	_UC_HOMEMODE,
54208595Suqs	_UC_SHELLPATH,
55183593Sjkoshy	_UC_SHELLS,
56208595Suqs	_UC_DEFAULTSHELL,
57183593Sjkoshy	_UC_DEFAULTGROUP,
58183593Sjkoshy	_UC_EXTRAGROUPS,
59183593Sjkoshy	_UC_DEFAULTCLASS,
60183593Sjkoshy	_UC_MINUID,
61183593Sjkoshy	_UC_MAXUID,
62183593Sjkoshy	_UC_MINGID,
63183593Sjkoshy	_UC_MAXGID,
64183593Sjkoshy	_UC_EXPIRE,
65183593Sjkoshy	_UC_PASSWORD,
66183593Sjkoshy	_UC_FIELDS
67183593Sjkoshy};
68183593Sjkoshy
69183593Sjkoshystatic char     bourne_shell[] = "sh";
70183593Sjkoshy
71183593Sjkoshystatic char    *system_shells[_UC_MAXSHELLS] =
72183593Sjkoshy{
73183593Sjkoshy	bourne_shell,
74183593Sjkoshy	"csh",
75183593Sjkoshy	"tcsh"
76183593Sjkoshy};
77183593Sjkoshy
78183593Sjkoshystatic char const *booltrue[] =
79183593Sjkoshy{
80183593Sjkoshy	"yes", "true", "1", "on", NULL
81183593Sjkoshy};
82183593Sjkoshystatic char const *boolfalse[] =
83183593Sjkoshy{
84183593Sjkoshy	"no", "false", "0", "off", NULL
85183593Sjkoshy};
86183593Sjkoshy
87183593Sjkoshystatic struct userconf config =
88196449Sjkoshy{
89183593Sjkoshy	0,			/* Default password for new users? (nologin) */
90183593Sjkoshy	0,			/* Reuse uids? */
91183593Sjkoshy	0,			/* Reuse gids? */
92183593Sjkoshy	NULL,			/* NIS version of the passwd file */
93183593Sjkoshy	"/usr/share/skel",	/* Where to obtain skeleton files */
94196449Sjkoshy	NULL,			/* Mail to send to new accounts */
95183593Sjkoshy	"/var/log/userlog",	/* Where to log changes */
96183593Sjkoshy	"/home",		/* Where to create home directory */
97183593Sjkoshy	_DEF_DIRMODE,		/* Home directory perms, modified by umask */
98183593Sjkoshy	"/bin",			/* Where shells are located */
99183593Sjkoshy	system_shells,		/* List of shells (first is default) */
100183593Sjkoshy	bourne_shell,		/* Default shell */
101183593Sjkoshy	NULL,			/* Default group name */
102183593Sjkoshy	NULL,			/* Default (additional) groups */
103183593Sjkoshy	NULL,			/* Default login class */
104183593Sjkoshy	1000, 32000,		/* Allowed range of uids */
105183593Sjkoshy	1000, 32000,		/* Allowed range of gids */
106183593Sjkoshy	0,			/* Days until account expires */
107183593Sjkoshy	0,			/* Days until password expires */
108183593Sjkoshy	0			/* size of default_group array */
109183593Sjkoshy};
110183593Sjkoshy
111183593Sjkoshystatic char const *comments[_UC_FIELDS] =
112183593Sjkoshy{
113183593Sjkoshy	"#\n# pw.conf - user/group configuration defaults\n#\n",
114183593Sjkoshy	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
115183593Sjkoshy	"\n# Reuse gaps in uid sequence? (yes or no)\n",
116183593Sjkoshy	"\n# Reuse gaps in gid sequence? (yes or no)\n",
117183593Sjkoshy	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
118183593Sjkoshy	"\n# Obtain default dotfiles from this directory\n",
119183593Sjkoshy	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
120183593Sjkoshy	"\n# Log add/change/remove information in this file\n",
121183593Sjkoshy	"\n# Root directory in which $HOME directory is created\n",
122183593Sjkoshy	"\n# Mode for the new $HOME directory, will be modified by umask\n",
123183593Sjkoshy	"\n# Colon separated list of directories containing valid shells\n",
124183593Sjkoshy	"\n# Comma separated list of available shells (without paths)\n",
125183593Sjkoshy	"\n# Default shell (without path)\n",
126183593Sjkoshy	"\n# Default group (leave blank for new group per user)\n",
127183593Sjkoshy	"\n# Extra groups for new users\n",
128183593Sjkoshy	"\n# Default login class for new users\n",
129183593Sjkoshy	"\n# Range of valid default user ids\n",
130183593Sjkoshy	NULL,
131183593Sjkoshy	"\n# Range of valid default group ids\n",
132183593Sjkoshy	NULL,
133183593Sjkoshy	"\n# Days after which account expires (0=disabled)\n",
134183593Sjkoshy	"\n# Days after which password expires (0=disabled)\n"
135183593Sjkoshy};
136183593Sjkoshy
137183593Sjkoshystatic char const *kwds[] =
138183593Sjkoshy{
139183593Sjkoshy	"",
140183593Sjkoshy	"defaultpasswd",
141183593Sjkoshy	"reuseuids",
142183593Sjkoshy	"reusegids",
143183593Sjkoshy	"nispasswd",
144183593Sjkoshy	"skeleton",
145183593Sjkoshy	"newmail",
146183593Sjkoshy	"logfile",
147183593Sjkoshy	"home",
148183593Sjkoshy	"homemode",
149183593Sjkoshy	"shellpath",
150183593Sjkoshy	"shells",
151183593Sjkoshy	"defaultshell",
152183593Sjkoshy	"defaultgroup",
153183593Sjkoshy	"extragroups",
154183593Sjkoshy	"defaultclass",
155183593Sjkoshy	"minuid",
156183593Sjkoshy	"maxuid",
157183593Sjkoshy	"mingid",
158183593Sjkoshy	"maxgid",
159183593Sjkoshy	"expire_days",
160183593Sjkoshy	"password_days",
161183593Sjkoshy	NULL
162196449Sjkoshy};
163183593Sjkoshy
164183593Sjkoshystatic char    *
165183593Sjkoshyunquote(char const * str)
166183593Sjkoshy{
167183593Sjkoshy	if (str && (*str == '"' || *str == '\'')) {
168183593Sjkoshy		char           *p = strchr(str + 1, *str);
169183593Sjkoshy
170183593Sjkoshy		if (p != NULL)
171183593Sjkoshy			*p = '\0';
172183593Sjkoshy		return (char *) (*++str ? str : NULL);
173183593Sjkoshy	}
174183593Sjkoshy	return (char *) str;
175183593Sjkoshy}
176183593Sjkoshy
177183593Sjkoshyint
178183593Sjkoshyboolean_val(char const * str, int dflt)
179183593Sjkoshy{
180183593Sjkoshy	if ((str = unquote(str)) != NULL) {
181183593Sjkoshy		int             i;
182183593Sjkoshy
183233648Seadler		for (i = 0; booltrue[i]; i++)
184183593Sjkoshy			if (strcmp(str, booltrue[i]) == 0)
185183593Sjkoshy				return 1;
186183593Sjkoshy		for (i = 0; boolfalse[i]; i++)
187184917Sjkoshy			if (strcmp(str, boolfalse[i]) == 0)
188183593Sjkoshy				return 0;
189183593Sjkoshy
190184917Sjkoshy		/*
191183593Sjkoshy		 * Special cases for defaultpassword
192183593Sjkoshy		 */
193183593Sjkoshy		if (strcmp(str, "random") == 0)
194184917Sjkoshy			return -1;
195183593Sjkoshy		if (strcmp(str, "none") == 0)
196233648Seadler			return -2;
197183593Sjkoshy	}
198184917Sjkoshy	return dflt;
199183593Sjkoshy}
200183593Sjkoshy
201184917Sjkoshychar const     *
202183593Sjkoshyboolean_str(int val)
203183593Sjkoshy{
204183593Sjkoshy	if (val == -1)
205183593Sjkoshy		return "random";
206184917Sjkoshy	else if (val == -2)
207183593Sjkoshy		return "none";
208183593Sjkoshy	else
209183593Sjkoshy		return val ? booltrue[0] : boolfalse[0];
210183593Sjkoshy}
211184917Sjkoshy
212183593Sjkoshychar           *
213183593Sjkoshynewstr(char const * p)
214184917Sjkoshy{
215183593Sjkoshy	char	*q;
216183593Sjkoshy
217184917Sjkoshy	if ((p = unquote(p)) == NULL)
218183593Sjkoshy		return (NULL);
219183593Sjkoshy
220183593Sjkoshy	if ((q = strdup(p)) == NULL)
221183593Sjkoshy		err(1, "strdup()");
222184917Sjkoshy
223183593Sjkoshy	return (q);
224183593Sjkoshy}
225184917Sjkoshy
226183593Sjkoshystruct userconf *
227183593Sjkoshyread_userconfig(char const * file)
228184917Sjkoshy{
229183593Sjkoshy	FILE	*fp;
230183593Sjkoshy	char	*buf, *p;
231184917Sjkoshy	size_t	linecap;
232183593Sjkoshy	ssize_t	linelen;
233183593Sjkoshy
234184932Sjkoshy	buf = NULL;
235184892Sjkoshy	linecap = 0;
236183593Sjkoshy
237184892Sjkoshy	config.numgroups = 200;
238183593Sjkoshy	config.groups = calloc(config.numgroups, sizeof(char *));
239184932Sjkoshy	if (config.groups == NULL)
240184892Sjkoshy		err(1, "calloc()");
241183593Sjkoshy	if (file == NULL)
242184892Sjkoshy		file = _PATH_PW_CONF;
243183593Sjkoshy
244184917Sjkoshy	if ((fp = fopen(file, "r")) == NULL)
245183593Sjkoshy		return (&config);
246183593Sjkoshy
247184917Sjkoshy	while ((linelen = getline(&buf, &linecap, fp)) > 0) {
248183593Sjkoshy		if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
249183593Sjkoshy			static char const toks[] = " \t\r\n,=";
250183593Sjkoshy			char           *q = strtok(NULL, toks);
251184917Sjkoshy			int             i = 0;
252183593Sjkoshy			mode_t          *modeset;
253183593Sjkoshy
254183593Sjkoshy			while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
255184917Sjkoshy				++i;
256183593Sjkoshy#if debugging
257183593Sjkoshy			if (i == _UC_FIELDS)
258184917Sjkoshy				printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
259183593Sjkoshy			else
260183593Sjkoshy				printf("Got kwd[%s]=%s\n", p, q);
261184917Sjkoshy#endif
262183593Sjkoshy			switch (i) {
263183593Sjkoshy			case _UC_DEFAULTPWD:
264184917Sjkoshy				config.default_password = boolean_val(q, 1);
265183593Sjkoshy				break;
266183593Sjkoshy			case _UC_REUSEUID:
267184917Sjkoshy				config.reuse_uids = boolean_val(q, 0);
268183593Sjkoshy				break;
269183593Sjkoshy			case _UC_REUSEGID:
270184917Sjkoshy				config.reuse_gids = boolean_val(q, 0);
271183593Sjkoshy				break;
272183593Sjkoshy			case _UC_NISPASSWD:
273183593Sjkoshy				config.nispasswd = (q == NULL || !boolean_val(q, 1))
274183593Sjkoshy					? NULL : newstr(q);
275183593Sjkoshy				break;
276183593Sjkoshy			case _UC_DOTDIR:
277183593Sjkoshy				config.dotdir = (q == NULL || !boolean_val(q, 1))
278183593Sjkoshy					? NULL : newstr(q);
279183593Sjkoshy				break;
280183593Sjkoshy				case _UC_NEWMAIL:
281183593Sjkoshy				config.newmail = (q == NULL || !boolean_val(q, 1))
282183593Sjkoshy					? NULL : newstr(q);
283183593Sjkoshy				break;
284183593Sjkoshy			case _UC_LOGFILE:
285183593Sjkoshy				config.logfile = (q == NULL || !boolean_val(q, 1))
286183593Sjkoshy					? NULL : newstr(q);
287184917Sjkoshy				break;
288183593Sjkoshy			case _UC_HOMEROOT:
289183593Sjkoshy				config.home = (q == NULL || !boolean_val(q, 1))
290183593Sjkoshy					? "/home" : newstr(q);
291183593Sjkoshy				break;
292183593Sjkoshy			case _UC_HOMEMODE:
293183593Sjkoshy				modeset = setmode(q);
294183593Sjkoshy				config.homemode = (q == NULL || !boolean_val(q, 1))
295183593Sjkoshy					? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
296183593Sjkoshy				free(modeset);
297183593Sjkoshy				break;
298183593Sjkoshy			case _UC_SHELLPATH:
299183593Sjkoshy				config.shelldir = (q == NULL || !boolean_val(q, 1))
300183593Sjkoshy					? "/bin" : newstr(q);
301183593Sjkoshy				break;
302183593Sjkoshy			case _UC_SHELLS:
303183593Sjkoshy				for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
304183593Sjkoshy					system_shells[i] = newstr(q);
305183593Sjkoshy				if (i > 0)
306183593Sjkoshy					while (i < _UC_MAXSHELLS)
307183593Sjkoshy						system_shells[i++] = NULL;
308183593Sjkoshy				break;
309183593Sjkoshy			case _UC_DEFAULTSHELL:
310183593Sjkoshy				config.shell_default = (q == NULL || !boolean_val(q, 1))
311183593Sjkoshy					? (char *) bourne_shell : newstr(q);
312183593Sjkoshy				break;
313183593Sjkoshy			case _UC_DEFAULTGROUP:
314183593Sjkoshy				q = unquote(q);
315183593Sjkoshy				config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
316183593Sjkoshy					? NULL : newstr(q);
317183593Sjkoshy				break;
318183593Sjkoshy			case _UC_EXTRAGROUPS:
319183593Sjkoshy				for (i = 0; q != NULL; q = strtok(NULL, toks)) {
320183593Sjkoshy					if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
321183593Sjkoshy						config.groups[i++] = newstr(q);
322183593Sjkoshy				}
323183593Sjkoshy				if (i > 0)
324183593Sjkoshy					while (i < config.numgroups)
325183593Sjkoshy						config.groups[i++] = NULL;
326183593Sjkoshy				break;
327183593Sjkoshy			case _UC_DEFAULTCLASS:
328183593Sjkoshy				config.default_class = (q == NULL || !boolean_val(q, 1))
329183593Sjkoshy					? NULL : newstr(q);
330183593Sjkoshy				break;
331183593Sjkoshy			case _UC_MINUID:
332183593Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
333183593Sjkoshy					config.min_uid = (uid_t) atol(q);
334183593Sjkoshy				break;
335183593Sjkoshy			case _UC_MAXUID:
336183593Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
337183593Sjkoshy					config.max_uid = (uid_t) atol(q);
338183593Sjkoshy				break;
339183593Sjkoshy			case _UC_MINGID:
340183593Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
341183593Sjkoshy					config.min_gid = (gid_t) atol(q);
342183593Sjkoshy				break;
343183593Sjkoshy			case _UC_MAXGID:
344183593Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
345183593Sjkoshy					config.max_gid = (gid_t) atol(q);
346183593Sjkoshy				break;
347183593Sjkoshy			case _UC_EXPIRE:
348183593Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
349183593Sjkoshy					config.expire_days = atoi(q);
350183593Sjkoshy				break;
351196449Sjkoshy			case _UC_PASSWORD:
352196449Sjkoshy				if ((q = unquote(q)) != NULL && isdigit(*q))
353183593Sjkoshy					config.password_days = atoi(q);
354184917Sjkoshy				break;
355183593Sjkoshy			case _UC_FIELDS:
356185326Sjkoshy			case _UC_NONE:
357183593Sjkoshy				break;
358184917Sjkoshy			}
359183593Sjkoshy		}
360183593Sjkoshy	}
361184917Sjkoshy	free(buf);
362183593Sjkoshy	fclose(fp);
363183593Sjkoshy
364183593Sjkoshy	return (&config);
365183593Sjkoshy}
366183593Sjkoshy
367183593Sjkoshy
368183593Sjkoshyint
369183593Sjkoshywrite_userconfig(char const * file)
370183593Sjkoshy{
371183593Sjkoshy	int             fd;
372183593Sjkoshy	int             i, j;
373183593Sjkoshy	struct sbuf	*buf;
374183593Sjkoshy	FILE           *fp;
375183593Sjkoshy
376183593Sjkoshy	if (file == NULL)
377183593Sjkoshy		file = _PATH_PW_CONF;
378183593Sjkoshy
379184917Sjkoshy	if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
380183593Sjkoshy		return (0);
381183593Sjkoshy
382184917Sjkoshy	if ((fp = fdopen(fd, "w")) == NULL) {
383183593Sjkoshy		close(fd);
384183593Sjkoshy		return (0);
385184917Sjkoshy	}
386183593Sjkoshy
387183593Sjkoshy	buf = sbuf_new_auto();
388184917Sjkoshy	for (i = _UC_NONE; i < _UC_FIELDS; i++) {
389183593Sjkoshy		int             quote = 1;
390183593Sjkoshy
391184917Sjkoshy		sbuf_clear(buf);
392183593Sjkoshy		switch (i) {
393183593Sjkoshy		case _UC_DEFAULTPWD:
394184917Sjkoshy			sbuf_cat(buf, boolean_str(config.default_password));
395183593Sjkoshy			break;
396196449Sjkoshy		case _UC_REUSEUID:
397183593Sjkoshy			sbuf_cat(buf, boolean_str(config.reuse_uids));
398183593Sjkoshy			break;
399183593Sjkoshy		case _UC_REUSEGID:
400183593Sjkoshy			sbuf_cat(buf, boolean_str(config.reuse_gids));
401183593Sjkoshy			break;
402196449Sjkoshy		case _UC_NISPASSWD:
403183593Sjkoshy			sbuf_cat(buf, config.nispasswd ?  config.nispasswd :
404183593Sjkoshy			    "");
405184917Sjkoshy			quote = 0;
406183593Sjkoshy			break;
407183593Sjkoshy		case _UC_DOTDIR:
408183593Sjkoshy			sbuf_cat(buf, config.dotdir ?  config.dotdir :
409183593Sjkoshy			    boolean_str(0));
410184917Sjkoshy			break;
411183593Sjkoshy		case _UC_NEWMAIL:
412183593Sjkoshy			sbuf_cat(buf, config.newmail ?  config.newmail :
413184917Sjkoshy			    boolean_str(0));
414183593Sjkoshy			break;
415183593Sjkoshy		case _UC_LOGFILE:
416183593Sjkoshy			sbuf_cat(buf, config.logfile ?  config.logfile :
417183593Sjkoshy			    boolean_str(0));
418183593Sjkoshy			break;
419183593Sjkoshy		case _UC_HOMEROOT:
420183593Sjkoshy			sbuf_cat(buf, config.home);
421183593Sjkoshy			break;
422183593Sjkoshy		case _UC_HOMEMODE:
423183593Sjkoshy			sbuf_printf(buf, "%04o", config.homemode);
424183593Sjkoshy			quote = 0;
425183593Sjkoshy			break;
426183593Sjkoshy		case _UC_SHELLPATH:
427183593Sjkoshy			sbuf_cat(buf, config.shelldir);
428183593Sjkoshy			break;
429183593Sjkoshy		case _UC_SHELLS:
430184917Sjkoshy			for (j = 0; j < _UC_MAXSHELLS &&
431183593Sjkoshy			    system_shells[j] != NULL; j++)
432183593Sjkoshy				sbuf_printf(buf, "%s\"%s\"", j ?
433183593Sjkoshy				    "," : "", system_shells[j]);
434183593Sjkoshy			quote = 0;
435184917Sjkoshy			break;
436183593Sjkoshy		case _UC_DEFAULTSHELL:
437183593Sjkoshy			sbuf_cat(buf, config.shell_default ?
438183593Sjkoshy			    config.shell_default : bourne_shell);
439184917Sjkoshy			break;
440183593Sjkoshy		case _UC_DEFAULTGROUP:
441183593Sjkoshy			sbuf_cat(buf, config.default_group ?
442183593Sjkoshy			    config.default_group : "");
443183593Sjkoshy			break;
444183593Sjkoshy		case _UC_EXTRAGROUPS:
445183593Sjkoshy			for (j = 0; j < config.numgroups &&
446183593Sjkoshy			    config.groups[j] != NULL; j++)
447183593Sjkoshy				sbuf_printf(buf, "%s\"%s\"", j ?
448183593Sjkoshy				    "," : "", config.groups[j]);
449183593Sjkoshy			quote = 0;
450183593Sjkoshy			break;
451183593Sjkoshy		case _UC_DEFAULTCLASS:
452183593Sjkoshy			sbuf_cat(buf, config.default_class ?
453183593Sjkoshy			    config.default_class : "");
454184917Sjkoshy			break;
455183593Sjkoshy		case _UC_MINUID:
456183593Sjkoshy			sbuf_printf(buf, "%lu", (unsigned long) config.min_uid);
457184917Sjkoshy			quote = 0;
458183593Sjkoshy			break;
459183593Sjkoshy		case _UC_MAXUID:
460183593Sjkoshy			sbuf_printf(buf, "%lu", (unsigned long) config.max_uid);
461184917Sjkoshy			quote = 0;
462226436Seadler			break;
463196449Sjkoshy		case _UC_MINGID:
464183593Sjkoshy			sbuf_printf(buf, "%lu", (unsigned long) config.min_gid);
465184917Sjkoshy			quote = 0;
466183593Sjkoshy			break;
467183593Sjkoshy		case _UC_MAXGID:
468183593Sjkoshy			sbuf_printf(buf, "%lu", (unsigned long) config.max_gid);
469184917Sjkoshy			quote = 0;
470183593Sjkoshy			break;
471183593Sjkoshy		case _UC_EXPIRE:
472184917Sjkoshy			sbuf_printf(buf, "%d", config.expire_days);
473183593Sjkoshy			quote = 0;
474183593Sjkoshy			break;
475184917Sjkoshy		case _UC_PASSWORD:
476183593Sjkoshy			sbuf_printf(buf, "%d", config.password_days);
477183593Sjkoshy			quote = 0;
478184917Sjkoshy			break;
479184892Sjkoshy		case _UC_NONE:
480183593Sjkoshy			break;
481184892Sjkoshy		}
482183593Sjkoshy		sbuf_finish(buf);
483184917Sjkoshy
484183593Sjkoshy		if (comments[i])
485183593Sjkoshy			fputs(comments[i], fp);
486183593Sjkoshy
487183593Sjkoshy		if (*kwds[i]) {
488183593Sjkoshy			if (quote)
489183593Sjkoshy				fprintf(fp, "%s = \"%s\"\n", kwds[i],
490183593Sjkoshy				    sbuf_data(buf));
491183593Sjkoshy			else
492183593Sjkoshy				fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
493183593Sjkoshy#if debugging
494183593Sjkoshy			printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
495183593Sjkoshy#endif
496183593Sjkoshy		}
497183593Sjkoshy	}
498183593Sjkoshy	sbuf_delete(buf);
499183593Sjkoshy	return (fclose(fp) != EOF);
500183593Sjkoshy}
501183593Sjkoshy