pw_conf.c revision 81982
1264269Ssbruno/*-
2264269Ssbruno * Copyright (C) 1996
3264269Ssbruno *	David L. Nugent.  All rights reserved.
4264269Ssbruno *
5264269Ssbruno * Redistribution and use in source and binary forms, with or without
6264269Ssbruno * modification, are permitted provided that the following conditions
7264269Ssbruno * are met:
8264269Ssbruno * 1. Redistributions of source code must retain the above copyright
9264269Ssbruno *    notice, this list of conditions and the following disclaimer.
10264269Ssbruno * 2. Redistributions in binary form must reproduce the above copyright
11264269Ssbruno *    notice, this list of conditions and the following disclaimer in the
12264269Ssbruno *    documentation and/or other materials provided with the distribution.
13264269Ssbruno *
14264269Ssbruno * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15264269Ssbruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16264269Ssbruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17264269Ssbruno * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18264269Ssbruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19264269Ssbruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20264269Ssbruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21264269Ssbruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22264269Ssbruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23264269Ssbruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24264269Ssbruno * SUCH DAMAGE.
25264269Ssbruno */
26264269Ssbruno
27264269Ssbruno#ifndef lint
28264269Ssbrunostatic const char rcsid[] =
29264269Ssbruno  "$FreeBSD: head/usr.sbin/pw/pw_conf.c 81982 2001-08-20 15:09:34Z brian $";
30264269Ssbruno#endif /* not lint */
31264269Ssbruno
32264269Ssbruno#include <string.h>
33264269Ssbruno#include <ctype.h>
34264269Ssbruno#include <fcntl.h>
35264269Ssbruno
36264269Ssbruno#include "pw.h"
37264269Ssbruno
38264269Ssbruno#define debugging 0
39264269Ssbruno
40264269Ssbrunoenum {
41264269Ssbruno	_UC_NONE,
42264269Ssbruno	_UC_DEFAULTPWD,
43264269Ssbruno	_UC_REUSEUID,
44264269Ssbruno	_UC_REUSEGID,
45264269Ssbruno	_UC_NISPASSWD,
46264269Ssbruno	_UC_DOTDIR,
47264269Ssbruno	_UC_NEWMAIL,
48264269Ssbruno	_UC_LOGFILE,
49264269Ssbruno	_UC_HOMEROOT,
50264269Ssbruno	_UC_SHELLPATH,
51264269Ssbruno	_UC_SHELLS,
52264269Ssbruno	_UC_DEFAULTSHELL,
53264269Ssbruno	_UC_DEFAULTGROUP,
54264269Ssbruno	_UC_EXTRAGROUPS,
55264269Ssbruno	_UC_DEFAULTCLASS,
56264269Ssbruno	_UC_MINUID,
57264269Ssbruno	_UC_MAXUID,
58264269Ssbruno	_UC_MINGID,
59264269Ssbruno	_UC_MAXGID,
60264269Ssbruno	_UC_EXPIRE,
61264269Ssbruno	_UC_PASSWORD,
62264269Ssbruno	_UC_FIELDS
63264269Ssbruno};
64264269Ssbruno
65264269Ssbrunostatic char     bourne_shell[] = "sh";
66264269Ssbruno
67264269Ssbrunostatic char    *system_shells[_UC_MAXSHELLS] =
68264269Ssbruno{
69264269Ssbruno	bourne_shell,
70264269Ssbruno	"csh",
71264269Ssbruno	"tcsh"
72264269Ssbruno};
73264269Ssbruno
74264269Ssbrunostatic char const *booltrue[] =
75264269Ssbruno{
76264269Ssbruno	"yes", "true", "1", "on", NULL
77264269Ssbruno};
78264269Ssbrunostatic char const *boolfalse[] =
79264269Ssbruno{
80264269Ssbruno	"no", "false", "0", "off", NULL
81264269Ssbruno};
82264269Ssbruno
83264269Ssbrunostatic struct userconf config =
84264269Ssbruno{
85264269Ssbruno	0,			/* Default password for new users? (nologin) */
86264269Ssbruno	0,			/* Reuse uids? */
87264269Ssbruno	0,			/* Reuse gids? */
88264269Ssbruno	NULL,			/* NIS version of the passwd file */
89264269Ssbruno	"/usr/share/skel",	/* Where to obtain skeleton files */
90264269Ssbruno	NULL,			/* Mail to send to new accounts */
91264269Ssbruno	"/var/log/userlog",	/* Where to log changes */
92264269Ssbruno	"/home",		/* Where to create home directory */
93264269Ssbruno	"/bin",			/* Where shells are located */
94264269Ssbruno	system_shells,		/* List of shells (first is default) */
95264269Ssbruno	bourne_shell,		/* Default shell */
96264269Ssbruno	NULL,			/* Default group name */
97264269Ssbruno	NULL,			/* Default (additional) groups */
98264269Ssbruno	NULL,			/* Default login class */
99264269Ssbruno	1000, 32000,		/* Allowed range of uids */
100264269Ssbruno	1000, 32000,		/* Allowed range of gids */
101264269Ssbruno	0,			/* Days until account expires */
102264269Ssbruno	0,			/* Days until password expires */
103264269Ssbruno	0			/* size of default_group array */
104264269Ssbruno};
105264269Ssbruno
106264269Ssbrunostatic char const *comments[_UC_FIELDS] =
107264269Ssbruno{
108264269Ssbruno	"#\n# pw.conf - user/group configuration defaults\n#\n",
109264269Ssbruno	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
110264269Ssbruno	"\n# Reuse gaps in uid sequence? (yes or no)\n",
111264269Ssbruno	"\n# Reuse gaps in gid sequence? (yes or no)\n",
112264269Ssbruno	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
113264269Ssbruno	"\n# Obtain default dotfiles from this directory\n",
114264269Ssbruno	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
115264269Ssbruno	"\n# Log add/change/remove information in this file\n",
116264269Ssbruno	"\n# Root directory in which $HOME directory is created\n",
117264269Ssbruno	"\n# Colon separated list of directories containing valid shells\n",
118264269Ssbruno	"\n# Comma separated list of available shells (without paths)\n",
119264269Ssbruno	"\n# Default shell (without path)\n",
120264269Ssbruno	"\n# Default group (leave blank for new group per user)\n",
121264269Ssbruno	"\n# Extra groups for new users\n",
122264269Ssbruno	"\n# Default login class for new users\n",
123264269Ssbruno	"\n# Range of valid default user ids\n",
124264269Ssbruno	NULL,
125264269Ssbruno	"\n# Range of valid default group ids\n",
126264269Ssbruno	NULL,
127264269Ssbruno	"\n# Days after which account expires (0=disabled)\n",
128264269Ssbruno	"\n# Days after which password expires (0=disabled)\n"
129264269Ssbruno};
130264269Ssbruno
131264269Ssbrunostatic char const *kwds[] =
132264269Ssbruno{
133264269Ssbruno	"",
134264269Ssbruno	"defaultpasswd",
135264269Ssbruno	"reuseuids",
136264269Ssbruno	"reusegids",
137264269Ssbruno	"nispasswd",
138264269Ssbruno	"skeleton",
139264269Ssbruno	"newmail",
140264269Ssbruno	"logfile",
141264269Ssbruno	"home",
142264269Ssbruno	"shellpath",
143264269Ssbruno	"shells",
144264269Ssbruno	"defaultshell",
145264269Ssbruno	"defaultgroup",
146264269Ssbruno	"extragroups",
147264269Ssbruno	"defaultclass",
148264269Ssbruno	"minuid",
149264269Ssbruno	"maxuid",
150264269Ssbruno	"mingid",
151264269Ssbruno	"maxgid",
152264269Ssbruno	"expire_days",
153264269Ssbruno	"password_days",
154264269Ssbruno	NULL
155264269Ssbruno};
156264269Ssbruno
157264269Ssbrunostatic char    *
158264269Ssbrunounquote(char const * str)
159264269Ssbruno{
160264269Ssbruno	if (str && (*str == '"' || *str == '\'')) {
161264269Ssbruno		char           *p = strchr(str + 1, *str);
162264269Ssbruno
163264269Ssbruno		if (p != NULL)
164264269Ssbruno			*p = '\0';
165264269Ssbruno		return (char *) (*++str ? str : NULL);
166264269Ssbruno	}
167264269Ssbruno	return (char *) str;
168264269Ssbruno}
169264269Ssbruno
170264269Ssbrunoint
171264269Ssbrunoboolean_val(char const * str, int dflt)
172264269Ssbruno{
173264269Ssbruno	if ((str = unquote(str)) != NULL) {
174264269Ssbruno		int             i;
175264269Ssbruno
176264269Ssbruno		for (i = 0; booltrue[i]; i++)
177264269Ssbruno			if (strcmp(str, booltrue[i]) == 0)
178264269Ssbruno				return 1;
179264269Ssbruno		for (i = 0; boolfalse[i]; i++)
180264269Ssbruno			if (strcmp(str, boolfalse[i]) == 0)
181264269Ssbruno				return 0;
182264269Ssbruno
183264269Ssbruno		/*
184264269Ssbruno		 * Special cases for defaultpassword
185264269Ssbruno		 */
186264269Ssbruno		if (strcmp(str, "random") == 0)
187264269Ssbruno			return -1;
188264269Ssbruno		if (strcmp(str, "none") == 0)
189264269Ssbruno			return -2;
190264269Ssbruno	}
191264269Ssbruno	return dflt;
192264269Ssbruno}
193264269Ssbruno
194264269Ssbrunochar const     *
195264269Ssbrunoboolean_str(int val)
196264269Ssbruno{
197264269Ssbruno	if (val == -1)
198264269Ssbruno		return "random";
199264269Ssbruno	else if (val == -2)
200264269Ssbruno		return "none";
201264269Ssbruno	else
202264269Ssbruno		return val ? booltrue[0] : boolfalse[0];
203264269Ssbruno}
204264269Ssbruno
205264269Ssbrunochar           *
206264269Ssbrunonewstr(char const * p)
207264269Ssbruno{
208264269Ssbruno	char           *q = NULL;
209264269Ssbruno
210264269Ssbruno	if ((p = unquote(p)) != NULL) {
211264269Ssbruno		int             l = strlen(p) + 1;
212264269Ssbruno
213264269Ssbruno		if ((q = malloc(l)) != NULL)
214264269Ssbruno			memcpy(q, p, l);
215264269Ssbruno	}
216264269Ssbruno	return q;
217264269Ssbruno}
218264269Ssbruno
219264269Ssbruno#define LNBUFSZ 1024
220264269Ssbruno
221264269Ssbruno
222264269Ssbrunostruct userconf *
223264269Ssbrunoread_userconfig(char const * file)
224264269Ssbruno{
225264269Ssbruno	FILE           *fp;
226264269Ssbruno
227264269Ssbruno	extendarray(&config.groups, &config.numgroups, 200);
228264269Ssbruno	memset(config.groups, 0, config.numgroups * sizeof(char *));
229264269Ssbruno	if (file == NULL)
230264269Ssbruno		file = _PATH_PW_CONF;
231264269Ssbruno	if ((fp = fopen(file, "r")) != NULL) {
232264269Ssbruno		int	    buflen = LNBUFSZ;
233264269Ssbruno		char       *buf = malloc(buflen);
234264269Ssbruno
235264269Ssbruno	nextline:
236264269Ssbruno		while (fgets(buf, buflen, fp) != NULL) {
237264269Ssbruno			char           *p;
238264269Ssbruno
239264269Ssbruno			while ((p = strchr(buf, '\n')) == NULL) {
240264269Ssbruno				int	  l;
241264269Ssbruno				if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
242264269Ssbruno					int	ch;
243264269Ssbruno					while ((ch = fgetc(fp)) != '\n' && ch != EOF);
244264269Ssbruno					goto nextline;	/* Ignore it */
245264269Ssbruno				}
246264269Ssbruno				l = strlen(buf);
247264269Ssbruno				if (fgets(buf + l, buflen - l, fp) == NULL)
248264269Ssbruno					break;	/* Unterminated last line */
249264269Ssbruno			}
250264269Ssbruno
251264269Ssbruno			if (p != NULL)
252264269Ssbruno				*p = '\0';
253264269Ssbruno
254264269Ssbruno			if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
255264269Ssbruno				static char const toks[] = " \t\r\n,=";
256264269Ssbruno				char           *q = strtok(NULL, toks);
257264269Ssbruno				int             i = 0;
258264269Ssbruno
259264269Ssbruno				while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
260264269Ssbruno					++i;
261264269Ssbruno#if debugging
262264269Ssbruno				if (i == _UC_FIELDS)
263264269Ssbruno					printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
264264269Ssbruno				else
265264269Ssbruno					printf("Got kwd[%s]=%s\n", p, q);
266264269Ssbruno#endif
267264269Ssbruno				switch (i) {
268264269Ssbruno				case _UC_DEFAULTPWD:
269264269Ssbruno					config.default_password = boolean_val(q, 1);
270264269Ssbruno					break;
271264269Ssbruno				case _UC_REUSEUID:
272264269Ssbruno					config.reuse_uids = boolean_val(q, 0);
273264269Ssbruno					break;
274264269Ssbruno				case _UC_REUSEGID:
275264269Ssbruno					config.reuse_gids = boolean_val(q, 0);
276264269Ssbruno					break;
277264269Ssbruno				case _UC_NISPASSWD:
278264269Ssbruno					config.nispasswd = (q == NULL || !boolean_val(q, 1))
279264269Ssbruno						? NULL : newstr(q);
280264269Ssbruno					break;
281264269Ssbruno				case _UC_DOTDIR:
282264269Ssbruno					config.dotdir = (q == NULL || !boolean_val(q, 1))
283264269Ssbruno						? NULL : newstr(q);
284264269Ssbruno					break;
285264269Ssbruno				case _UC_NEWMAIL:
286264269Ssbruno					config.newmail = (q == NULL || !boolean_val(q, 1))
287264269Ssbruno						? NULL : newstr(q);
288264269Ssbruno					break;
289264269Ssbruno				case _UC_LOGFILE:
290264269Ssbruno					config.logfile = (q == NULL || !boolean_val(q, 1))
291264269Ssbruno						? NULL : newstr(q);
292264269Ssbruno					break;
293264269Ssbruno				case _UC_HOMEROOT:
294264269Ssbruno					config.home = (q == NULL || !boolean_val(q, 1))
295264269Ssbruno						? "/home" : newstr(q);
296264269Ssbruno					break;
297264269Ssbruno				case _UC_SHELLPATH:
298264269Ssbruno					config.shelldir = (q == NULL || !boolean_val(q, 1))
299264269Ssbruno						? "/bin" : newstr(q);
300264269Ssbruno					break;
301264269Ssbruno				case _UC_SHELLS:
302264269Ssbruno					for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
303264269Ssbruno						system_shells[i] = newstr(q);
304264269Ssbruno					if (i > 0)
305264269Ssbruno						while (i < _UC_MAXSHELLS)
306264269Ssbruno							system_shells[i++] = NULL;
307264269Ssbruno					break;
308264269Ssbruno				case _UC_DEFAULTSHELL:
309264269Ssbruno					config.shell_default = (q == NULL || !boolean_val(q, 1))
310264269Ssbruno						? (char *) bourne_shell : newstr(q);
311264269Ssbruno					break;
312264269Ssbruno				case _UC_DEFAULTGROUP:
313264269Ssbruno					q = unquote(q);
314264269Ssbruno					config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
315264269Ssbruno						? NULL : newstr(q);
316264269Ssbruno					break;
317264269Ssbruno				case _UC_EXTRAGROUPS:
318264269Ssbruno					for (i = 0; q != NULL; q = strtok(NULL, toks)) {
319264269Ssbruno						if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
320264269Ssbruno							config.groups[i++] = newstr(q);
321264269Ssbruno					}
322264269Ssbruno					if (i > 0)
323264269Ssbruno						while (i < config.numgroups)
324264269Ssbruno							config.groups[i++] = NULL;
325264269Ssbruno					break;
326264269Ssbruno				case _UC_DEFAULTCLASS:
327264269Ssbruno					config.default_class = (q == NULL || !boolean_val(q, 1))
328264269Ssbruno						? NULL : newstr(q);
329264269Ssbruno					break;
330264269Ssbruno				case _UC_MINUID:
331264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
332264269Ssbruno						config.min_uid = (uid_t) atol(q);
333264269Ssbruno					break;
334264269Ssbruno				case _UC_MAXUID:
335264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
336264269Ssbruno						config.max_uid = (uid_t) atol(q);
337264269Ssbruno					break;
338264269Ssbruno				case _UC_MINGID:
339264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
340264269Ssbruno						config.min_gid = (gid_t) atol(q);
341264269Ssbruno					break;
342264269Ssbruno				case _UC_MAXGID:
343264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
344264269Ssbruno						config.max_gid = (gid_t) atol(q);
345264269Ssbruno					break;
346264269Ssbruno				case _UC_EXPIRE:
347264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
348264269Ssbruno						config.expire_days = atoi(q);
349264269Ssbruno					break;
350264269Ssbruno				case _UC_PASSWORD:
351264269Ssbruno					if ((q = unquote(q)) != NULL && isdigit(*q))
352264269Ssbruno						config.password_days = atoi(q);
353264269Ssbruno					break;
354264269Ssbruno				case _UC_FIELDS:
355264269Ssbruno				case _UC_NONE:
356264269Ssbruno					break;
357264269Ssbruno				}
358264269Ssbruno			}
359264269Ssbruno		}
360264269Ssbruno		free(buf);
361264269Ssbruno		fclose(fp);
362264269Ssbruno	}
363264269Ssbruno	return &config;
364264269Ssbruno}
365264269Ssbruno
366287463Ssbruno
367264269Ssbrunoint
368264269Ssbrunowrite_userconfig(char const * file)
369264269Ssbruno{
370264269Ssbruno	int             fd;
371264269Ssbruno
372264269Ssbruno	if (file == NULL)
373264269Ssbruno		file = _PATH_PW_CONF;
374278961Ssbruno
375264269Ssbruno	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
376278961Ssbruno		FILE           *fp;
377278961Ssbruno
378264269Ssbruno		if ((fp = fdopen(fd, "w")) == NULL)
379264269Ssbruno			close(fd);
380264269Ssbruno		else {
381264269Ssbruno			int             i, j, k;
382264269Ssbruno			int		len = LNBUFSZ;
383264269Ssbruno			char           *buf = malloc(len);
384264269Ssbruno
385264269Ssbruno			for (i = _UC_NONE; i < _UC_FIELDS; i++) {
386264269Ssbruno				int             quote = 1;
387264269Ssbruno				char const     *val = buf;
388264269Ssbruno
389264269Ssbruno				*buf = '\0';
390264269Ssbruno				switch (i) {
391264269Ssbruno				case _UC_DEFAULTPWD:
392264269Ssbruno					val = boolean_str(config.default_password);
393264269Ssbruno					break;
394264269Ssbruno				case _UC_REUSEUID:
395264269Ssbruno					val = boolean_str(config.reuse_uids);
396264269Ssbruno					break;
397264269Ssbruno				case _UC_REUSEGID:
398264269Ssbruno					val = boolean_str(config.reuse_gids);
399264269Ssbruno					break;
400264269Ssbruno				case _UC_NISPASSWD:
401264269Ssbruno					val = config.nispasswd ? config.nispasswd : "";
402264269Ssbruno					quote = 0;
403264269Ssbruno					break;
404264269Ssbruno				case _UC_DOTDIR:
405264269Ssbruno					val = config.dotdir ? config.dotdir : boolean_str(0);
406264269Ssbruno					break;
407264269Ssbruno				case _UC_NEWMAIL:
408264269Ssbruno					val = config.newmail ? config.newmail : boolean_str(0);
409264269Ssbruno					break;
410264269Ssbruno				case _UC_LOGFILE:
411264269Ssbruno					val = config.logfile ? config.logfile : boolean_str(0);
412264269Ssbruno					break;
413264269Ssbruno				case _UC_HOMEROOT:
414264269Ssbruno					val = config.home;
415264269Ssbruno					break;
416264269Ssbruno				case _UC_SHELLPATH:
417264269Ssbruno					val = config.shelldir;
418264269Ssbruno					break;
419264269Ssbruno				case _UC_SHELLS:
420264269Ssbruno					for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
421264269Ssbruno						char	lbuf[64];
422264269Ssbruno						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
423264269Ssbruno						if (l < 0)
424264269Ssbruno							l = 0;
425264269Ssbruno						if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
426264269Ssbruno							strcpy(buf + k, lbuf);
427264269Ssbruno							k += l;
428264269Ssbruno						}
429264269Ssbruno					}
430264269Ssbruno					quote = 0;
431264269Ssbruno					break;
432264269Ssbruno				case _UC_DEFAULTSHELL:
433264269Ssbruno					val = config.shell_default ? config.shell_default : bourne_shell;
434264269Ssbruno					break;
435264269Ssbruno				case _UC_DEFAULTGROUP:
436264269Ssbruno					val = config.default_group ? config.default_group : "";
437264269Ssbruno					break;
438264269Ssbruno				case _UC_EXTRAGROUPS:
439264269Ssbruno					extendarray(&config.groups, &config.numgroups, 200);
440264269Ssbruno					for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
441264269Ssbruno						char	lbuf[64];
442264269Ssbruno						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
443264269Ssbruno						if (l < 0)
444264269Ssbruno							l = 0;
445264269Ssbruno						if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
446264269Ssbruno							strcpy(buf + k, lbuf);
447264269Ssbruno							k +=  l;
448264269Ssbruno						}
449264269Ssbruno					}
450264269Ssbruno					quote = 0;
451264269Ssbruno					break;
452264269Ssbruno				case _UC_DEFAULTCLASS:
453264269Ssbruno					val = config.default_class ? config.default_class : "";
454264269Ssbruno					break;
455264269Ssbruno				case _UC_MINUID:
456264269Ssbruno					sprintf(buf, "%lu", (unsigned long) config.min_uid);
457264269Ssbruno					quote = 0;
458264269Ssbruno					break;
459264269Ssbruno				case _UC_MAXUID:
460264269Ssbruno					sprintf(buf, "%lu", (unsigned long) config.max_uid);
461264269Ssbruno					quote = 0;
462264269Ssbruno					break;
463264269Ssbruno				case _UC_MINGID:
464264269Ssbruno					sprintf(buf, "%lu", (unsigned long) config.min_gid);
465264269Ssbruno					quote = 0;
466264269Ssbruno					break;
467264269Ssbruno				case _UC_MAXGID:
468264269Ssbruno					sprintf(buf, "%lu", (unsigned long) config.max_gid);
469264269Ssbruno					quote = 0;
470264269Ssbruno					break;
471264269Ssbruno				case _UC_EXPIRE:
472264269Ssbruno					sprintf(buf, "%d", config.expire_days);
473264269Ssbruno					quote = 0;
474264269Ssbruno					break;
475264269Ssbruno				case _UC_PASSWORD:
476264269Ssbruno					sprintf(buf, "%d", config.password_days);
477264269Ssbruno					quote = 0;
478264269Ssbruno					break;
479264269Ssbruno				case _UC_NONE:
480264269Ssbruno					break;
481264269Ssbruno				}
482264269Ssbruno
483264269Ssbruno				if (comments[i])
484264269Ssbruno					fputs(comments[i], fp);
485264269Ssbruno
486264269Ssbruno				if (*kwds[i]) {
487264269Ssbruno					if (quote)
488264269Ssbruno						fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
489264269Ssbruno					else
490264269Ssbruno						fprintf(fp, "%s = %s\n", kwds[i], val);
491264269Ssbruno#if debugging
492264269Ssbruno					printf("WROTE: %s = %s\n", kwds[i], val);
493264269Ssbruno#endif
494264269Ssbruno				}
495264269Ssbruno			}
496264269Ssbruno			free(buf);
497264269Ssbruno			return fclose(fp) != EOF;
498264269Ssbruno		}
499264269Ssbruno	}
500264269Ssbruno	return 0;
501264269Ssbruno}
502264269Ssbruno