pw_conf.c revision 21330
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 *
2621330Sdavidn *	$Id: pw_conf.c,v 1.2 1996/12/21 15:35:42 davidn Exp $
2720253Sjoerg */
2820253Sjoerg
2920253Sjoerg#include <string.h>
3020253Sjoerg#include <ctype.h>
3120253Sjoerg#include <fcntl.h>
3220253Sjoerg
3320253Sjoerg#include "pw.h"
3420747Sdavidn#include "pwupd.h"
3520253Sjoerg
3620253Sjoerg#define debugging 0
3720253Sjoerg
3820253Sjoergenum {
3920253Sjoerg	_UC_NONE,
4020253Sjoerg	_UC_DEFAULTPWD,
4120253Sjoerg	_UC_REUSEUID,
4220253Sjoerg	_UC_REUSEGID,
4321330Sdavidn	_UC_NISPASSWD,
4420253Sjoerg	_UC_DOTDIR,
4520253Sjoerg	_UC_NEWMAIL,
4620253Sjoerg	_UC_LOGFILE,
4720253Sjoerg	_UC_HOMEROOT,
4820253Sjoerg	_UC_SHELLPATH,
4920253Sjoerg	_UC_SHELLS,
5020253Sjoerg	_UC_DEFAULTSHELL,
5120253Sjoerg	_UC_DEFAULTGROUP,
5220253Sjoerg	_UC_EXTRAGROUPS,
5320253Sjoerg	_UC_DEFAULTCLASS,
5420253Sjoerg	_UC_MINUID,
5520253Sjoerg	_UC_MAXUID,
5620253Sjoerg	_UC_MINGID,
5720253Sjoerg	_UC_MAXGID,
5820253Sjoerg	_UC_EXPIRE,
5920253Sjoerg	_UC_PASSWORD,
6020253Sjoerg	_UC_FIELDS
6120253Sjoerg};
6220253Sjoerg
6320253Sjoergstatic char     bourne_shell[] = "sh";
6420253Sjoerg
6520253Sjoergstatic char    *system_shells[_UC_MAXSHELLS] =
6620253Sjoerg{
6720253Sjoerg	bourne_shell,
6820253Sjoerg	"csh"
6920253Sjoerg};
7020253Sjoerg
7120253Sjoergstatic char const *booltrue[] =
7220253Sjoerg{
7320253Sjoerg	"yes", "true", "1", "on", NULL
7420253Sjoerg};
7520253Sjoergstatic char const *boolfalse[] =
7620253Sjoerg{
7720253Sjoerg	"no", "false", "0", "off", NULL
7820253Sjoerg};
7920253Sjoerg
8020253Sjoergstatic struct userconf config =
8120253Sjoerg{
8220253Sjoerg	0,			/* Default password for new users? (nologin) */
8320253Sjoerg	0,			/* Reuse uids? */
8420253Sjoerg	0,			/* Reuse gids? */
8521330Sdavidn	NULL,			/* NIS version of the passwd file */
8620253Sjoerg	"/usr/share/skel",	/* Where to obtain skeleton files */
8720253Sjoerg	NULL,			/* Mail to send to new accounts */
8820253Sjoerg	"/var/log/userlog",	/* Where to log changes */
8920253Sjoerg	"/home",		/* Where to create home directory */
9020253Sjoerg	"/bin",			/* Where shells are located */
9120253Sjoerg	system_shells,		/* List of shells (first is default) */
9220253Sjoerg	bourne_shell,		/* Default shell */
9320253Sjoerg	NULL,			/* Default group name */
9420747Sdavidn	NULL,			/* Default (additional) groups */
9520253Sjoerg	NULL,			/* Default login class */
9620253Sjoerg	1000, 32000,		/* Allowed range of uids */
9720253Sjoerg	1000, 32000,		/* Allowed range of gids */
9820253Sjoerg	0,			/* Days until account expires */
9920253Sjoerg	0			/* Days until password expires */
10020253Sjoerg};
10120253Sjoerg
10220253Sjoergstatic char const *comments[_UC_FIELDS] =
10320253Sjoerg{
10420253Sjoerg	"#\n# pw.conf - user/group configuration defaults\n#\n",
10520253Sjoerg	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
10620253Sjoerg	"\n# Reuse gaps in uid sequence? (yes or no)\n",
10720253Sjoerg	"\n# Reuse gaps in gid sequence? (yes or no)\n",
10821330Sdavidn	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
10920253Sjoerg	"\n# Obtain default dotfiles from this directory\n",
11020253Sjoerg	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
11120253Sjoerg	"\n# Log add/change/remove information in this file\n",
11220253Sjoerg	"\n# Root directory in which $HOME directory is created\n",
11320253Sjoerg	"\n# Colon separated list of directories containing valid shells\n",
11420253Sjoerg	"\n# Space separated list of available shells (without paths)\n",
11520253Sjoerg	"\n# Default shell (without path)\n",
11620253Sjoerg	"\n# Default group (leave blank for new group per user)\n",
11720253Sjoerg	"\n# Extra groups for new users\n",
11820253Sjoerg	"\n# Default login class for new users\n",
11920253Sjoerg	"\n# Range of valid default user ids\n",
12020253Sjoerg	NULL,
12120253Sjoerg	"\n# Range of valid default group ids\n",
12220253Sjoerg	NULL,
12320253Sjoerg	"\n# Days after which account expires (0=disabled)\n",
12420253Sjoerg	"\n# Days after which password expires (0=disabled)\n"
12520253Sjoerg};
12620253Sjoerg
12720253Sjoergstatic char const *kwds[] =
12820253Sjoerg{
12920253Sjoerg	"",
13020253Sjoerg	"defaultpasswd",
13120253Sjoerg	"reuseuids",
13220253Sjoerg	"reusegids",
13321330Sdavidn	"nispasswd",
13420253Sjoerg	"skeleton",
13520253Sjoerg	"newmail",
13620253Sjoerg	"logfile",
13720253Sjoerg	"home",
13820253Sjoerg	"shellpath",
13920253Sjoerg	"shells",
14020253Sjoerg	"defaultshell",
14120253Sjoerg	"defaultgroup",
14220253Sjoerg	"extragroups",
14320253Sjoerg	"defaultclass",
14420253Sjoerg	"minuid",
14520253Sjoerg	"maxuid",
14620253Sjoerg	"mingid",
14720253Sjoerg	"maxgid",
14820253Sjoerg	"expire_days",
14920253Sjoerg	"password_days",
15020253Sjoerg	NULL
15120253Sjoerg};
15220253Sjoerg
15320253Sjoergstatic char    *
15420253Sjoergunquote(char const * str)
15520253Sjoerg{
15620253Sjoerg	if (str && (*str == '"' || *str == '\'')) {
15720253Sjoerg		char           *p = strchr(str + 1, *str);
15820253Sjoerg
15920253Sjoerg		if (p != NULL)
16020253Sjoerg			*p = '\0';
16120253Sjoerg		return (char *) (*++str ? str : NULL);
16220253Sjoerg	}
16320253Sjoerg	return (char *) str;
16420253Sjoerg}
16520253Sjoerg
16620253Sjoergint
16720253Sjoergboolean_val(char const * str, int dflt)
16820253Sjoerg{
16920253Sjoerg	if ((str = unquote(str)) != NULL) {
17020253Sjoerg		int             i;
17120253Sjoerg
17220253Sjoerg		for (i = 0; booltrue[i]; i++)
17320253Sjoerg			if (strcmp(str, booltrue[i]) == 0)
17420253Sjoerg				return 1;
17520253Sjoerg		for (i = 0; boolfalse[i]; i++)
17620253Sjoerg			if (strcmp(str, boolfalse[i]) == 0)
17720253Sjoerg				return 0;
17820253Sjoerg
17920253Sjoerg		/*
18020253Sjoerg		 * Special cases for defaultpassword
18120253Sjoerg		 */
18220253Sjoerg		if (strcmp(str, "random") == 0)
18320253Sjoerg			return -1;
18420253Sjoerg		if (strcmp(str, "none") == 0)
18520253Sjoerg			return -2;
18620253Sjoerg	}
18720253Sjoerg	return dflt;
18820253Sjoerg}
18920253Sjoerg
19020253Sjoergchar const     *
19120253Sjoergboolean_str(int val)
19220253Sjoerg{
19320253Sjoerg	if (val == -1)
19420253Sjoerg		return "random";
19520253Sjoerg	else if (val == -2)
19620253Sjoerg		return "none";
19720253Sjoerg	else
19820253Sjoerg		return val ? booltrue[0] : boolfalse[0];
19920253Sjoerg}
20020253Sjoerg
20120253Sjoergchar           *
20220253Sjoergnewstr(char const * p)
20320253Sjoerg{
20420253Sjoerg	char           *q = NULL;
20520253Sjoerg
20620253Sjoerg	if ((p = unquote(p)) != NULL) {
20720253Sjoerg		int             l = strlen(p) + 1;
20820253Sjoerg
20920253Sjoerg		if ((q = malloc(l)) != NULL)
21020253Sjoerg			memcpy(q, p, l);
21120253Sjoerg	}
21220253Sjoerg	return q;
21320253Sjoerg}
21420253Sjoerg
21520747Sdavidn#define LNBUFSZ 1024
21620253Sjoerg
21720747Sdavidn
21820253Sjoergstruct userconf *
21920253Sjoergread_userconfig(char const * file)
22020253Sjoerg{
22120253Sjoerg	FILE           *fp;
22220253Sjoerg
22320747Sdavidn	extendarray(&config.groups, &config.numgroups, 200);
22420747Sdavidn	memset(config.groups, 0, config.numgroups * sizeof(char *));
22520253Sjoerg	if (file == NULL)
22620253Sjoerg		file = _PATH_PW_CONF;
22720253Sjoerg	if ((fp = fopen(file, "r")) != NULL) {
22820747Sdavidn		int	    buflen = LNBUFSZ;
22920747Sdavidn		char       *buf = malloc(buflen);
23020253Sjoerg
23120747Sdavidn	nextline:
23220747Sdavidn		while (fgets(buf, buflen, fp) != NULL) {
23320747Sdavidn			char           *p;
23420253Sjoerg
23520747Sdavidn			while ((p = strchr(buf, '\n')) == NULL) {
23620747Sdavidn				int	  l;
23720747Sdavidn				if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
23820747Sdavidn					int	ch;
23920747Sdavidn					while ((ch = fgetc(fp)) != '\n' && ch != EOF);
24020747Sdavidn					goto nextline;	/* Ignore it */
24120747Sdavidn				}
24220747Sdavidn				l = strlen(buf);
24320747Sdavidn				if (fgets(buf + l, buflen - l, fp) == NULL)
24420747Sdavidn					break;	/* Unterminated last line */
24520747Sdavidn			}
24620253Sjoerg
24720747Sdavidn			if (p != NULL)
24820253Sjoerg				*p = '\0';
24920253Sjoerg
25020747Sdavidn			if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
25120747Sdavidn				static char const toks[] = " \t\r\n,=";
25220747Sdavidn				char           *q = strtok(NULL, toks);
25320747Sdavidn				int             i = 0;
25420747Sdavidn
25520747Sdavidn				while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
25620747Sdavidn					++i;
25720253Sjoerg#if debugging
25820747Sdavidn				if (i == _UC_FIELDS)
25920747Sdavidn					printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
26020747Sdavidn				else
26120747Sdavidn					printf("Got kwd[%s]=%s\n", p, q);
26220253Sjoerg#endif
26320747Sdavidn				switch (i) {
26420747Sdavidn				case _UC_DEFAULTPWD:
26520747Sdavidn					config.default_password = boolean_val(q, 1);
26620747Sdavidn					break;
26720747Sdavidn				case _UC_REUSEUID:
26820747Sdavidn					config.reuse_uids = boolean_val(q, 0);
26920747Sdavidn					break;
27020747Sdavidn				case _UC_REUSEGID:
27120747Sdavidn					config.reuse_gids = boolean_val(q, 0);
27220747Sdavidn					break;
27321330Sdavidn				case _UC_NISPASSWD:
27421330Sdavidn					config.nispasswd = (q == NULL || !boolean_val(q, 1))
27521330Sdavidn						? NULL : newstr(q);
27621330Sdavidn					break;
27720747Sdavidn				case _UC_DOTDIR:
27820747Sdavidn					config.dotdir = (q == NULL || !boolean_val(q, 1))
27920747Sdavidn						? NULL : newstr(q);
28020747Sdavidn					break;
28120747Sdavidn				case _UC_NEWMAIL:
28220747Sdavidn					config.newmail = (q == NULL || !boolean_val(q, 1))
28320747Sdavidn						? NULL : newstr(q);
28420747Sdavidn					break;
28520747Sdavidn				case _UC_LOGFILE:
28620747Sdavidn					config.logfile = (q == NULL || !boolean_val(q, 1))
28720747Sdavidn						? NULL : newstr(q);
28820747Sdavidn					break;
28920747Sdavidn				case _UC_HOMEROOT:
29020747Sdavidn					config.home = (q == NULL || !boolean_val(q, 1))
29120747Sdavidn						? "/home" : newstr(q);
29220747Sdavidn					break;
29320747Sdavidn				case _UC_SHELLPATH:
29420747Sdavidn					config.shelldir = (q == NULL || !boolean_val(q, 1))
29520747Sdavidn						? "/bin" : newstr(q);
29620747Sdavidn					break;
29720747Sdavidn				case _UC_SHELLS:
29820747Sdavidn					for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
29920747Sdavidn						system_shells[i] = newstr(q);
30020747Sdavidn					if (i > 0)
30120747Sdavidn						while (i < _UC_MAXSHELLS)
30220747Sdavidn							system_shells[i++] = NULL;
30320747Sdavidn					break;
30420747Sdavidn				case _UC_DEFAULTSHELL:
30520747Sdavidn					config.shell_default = (q == NULL || !boolean_val(q, 1))
30620747Sdavidn						? (char *) bourne_shell : newstr(q);
30720747Sdavidn					break;
30820747Sdavidn				case _UC_DEFAULTGROUP:
30920747Sdavidn					config.default_group = (q == NULL || !boolean_val(q, 1) || getgrnam(q) == NULL)
31020747Sdavidn						? NULL : newstr(q);
31120747Sdavidn					break;
31220747Sdavidn				case _UC_EXTRAGROUPS:
31320747Sdavidn					for (i = 0; q != NULL; q = strtok(NULL, toks)) {
31420747Sdavidn						if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
31520747Sdavidn							config.groups[i++] = newstr(q);
31620253Sjoerg					}
31720747Sdavidn					if (i > 0)
31820747Sdavidn						while (i < config.numgroups)
31920747Sdavidn							config.groups[i++] = NULL;
32020747Sdavidn					break;
32120747Sdavidn				case _UC_DEFAULTCLASS:
32220747Sdavidn					config.default_class = (q == NULL || !boolean_val(q, 1))
32320747Sdavidn						? NULL : newstr(q);
32420747Sdavidn					break;
32520747Sdavidn				case _UC_MINUID:
32620747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
32720747Sdavidn						config.min_uid = (uid_t) atol(q);
32820747Sdavidn					break;
32920747Sdavidn				case _UC_MAXUID:
33020747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
33120747Sdavidn						config.max_uid = (uid_t) atol(q);
33220747Sdavidn					break;
33320747Sdavidn				case _UC_MINGID:
33420747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
33520747Sdavidn						config.min_gid = (gid_t) atol(q);
33620747Sdavidn					break;
33720747Sdavidn				case _UC_MAXGID:
33820747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
33920747Sdavidn						config.max_gid = (gid_t) atol(q);
34020747Sdavidn					break;
34120747Sdavidn				case _UC_EXPIRE:
34220747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
34320747Sdavidn						config.expire_days = atoi(q);
34420747Sdavidn					break;
34520747Sdavidn				case _UC_PASSWORD:
34620747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
34720747Sdavidn						config.password_days = atoi(q);
34820747Sdavidn					break;
34920747Sdavidn				case _UC_FIELDS:
35020747Sdavidn				case _UC_NONE:
35120747Sdavidn					break;
35220253Sjoerg				}
35320253Sjoerg			}
35420253Sjoerg		}
35520747Sdavidn		free(buf);
35620253Sjoerg		fclose(fp);
35720253Sjoerg	}
35820253Sjoerg	return &config;
35920253Sjoerg}
36020253Sjoerg
36120253Sjoerg
36220253Sjoergint
36320253Sjoergwrite_userconfig(char const * file)
36420253Sjoerg{
36520253Sjoerg	int             fd;
36620253Sjoerg
36720253Sjoerg	if (file == NULL)
36820253Sjoerg		file = _PATH_PW_CONF;
36920253Sjoerg
37020253Sjoerg	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
37120253Sjoerg		FILE           *fp;
37220253Sjoerg
37320253Sjoerg		if ((fp = fdopen(fd, "w")) == NULL)
37420253Sjoerg			close(fd);
37520253Sjoerg		else {
37620253Sjoerg			int             i, j, k;
37720747Sdavidn			int		len = LNBUFSZ;
37820747Sdavidn			char           *buf = malloc(len);
37920253Sjoerg
38020253Sjoerg			for (i = _UC_NONE; i < _UC_FIELDS; i++) {
38120253Sjoerg				int             quote = 1;
38220253Sjoerg				char const     *val = buf;
38320253Sjoerg
38420253Sjoerg				*buf = '\0';
38520253Sjoerg				switch (i) {
38620253Sjoerg				case _UC_DEFAULTPWD:
38720253Sjoerg					val = boolean_str(config.default_password);
38820253Sjoerg					break;
38920253Sjoerg				case _UC_REUSEUID:
39020253Sjoerg					val = boolean_str(config.reuse_uids);
39120253Sjoerg					break;
39220253Sjoerg				case _UC_REUSEGID:
39320253Sjoerg					val = boolean_str(config.reuse_gids);
39420253Sjoerg					break;
39521330Sdavidn				case _UC_NISPASSWD:
39621330Sdavidn					val = config.nispasswd ? config.nispasswd : "";
39721330Sdavidn					quote = 0;
39821330Sdavidn					break;
39920253Sjoerg				case _UC_DOTDIR:
40020253Sjoerg					val = config.dotdir ? config.dotdir : boolean_str(0);
40120253Sjoerg					break;
40220253Sjoerg				case _UC_NEWMAIL:
40320253Sjoerg					val = config.newmail ? config.newmail : boolean_str(0);
40420253Sjoerg					break;
40520253Sjoerg				case _UC_LOGFILE:
40620253Sjoerg					val = config.logfile ? config.logfile : boolean_str(0);
40720253Sjoerg					break;
40820253Sjoerg				case _UC_HOMEROOT:
40920253Sjoerg					val = config.home;
41020253Sjoerg					break;
41120253Sjoerg				case _UC_SHELLPATH:
41220253Sjoerg					val = config.shelldir;
41320253Sjoerg					break;
41420253Sjoerg				case _UC_SHELLS:
41520747Sdavidn					for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
41620747Sdavidn						char	lbuf[64];
41720747Sdavidn						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
41820747Sdavidn						if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
41920747Sdavidn							strcpy(buf + k, lbuf);
42020747Sdavidn							k += l;
42120747Sdavidn						}
42220747Sdavidn					}
42320253Sjoerg					quote = 0;
42420253Sjoerg					break;
42520253Sjoerg				case _UC_DEFAULTSHELL:
42620253Sjoerg					val = config.shell_default ? config.shell_default : bourne_shell;
42720253Sjoerg					break;
42820253Sjoerg				case _UC_DEFAULTGROUP:
42920253Sjoerg					val = config.default_group ? config.default_group : "";
43020253Sjoerg					break;
43120253Sjoerg				case _UC_EXTRAGROUPS:
43220747Sdavidn					extendarray(&config.groups, &config.numgroups, 200);
43320747Sdavidn					for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
43420747Sdavidn						char	lbuf[64];
43520747Sdavidn						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
43620747Sdavidn						if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
43720747Sdavidn							strcpy(buf + k, lbuf);
43820747Sdavidn							k +=  l;
43920747Sdavidn						}
44020747Sdavidn					}
44120253Sjoerg					quote = 0;
44220253Sjoerg					break;
44320253Sjoerg				case _UC_DEFAULTCLASS:
44420253Sjoerg					val = config.default_class ? config.default_class : "";
44520253Sjoerg					break;
44620253Sjoerg				case _UC_MINUID:
44720253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.min_uid);
44820253Sjoerg					quote = 0;
44920253Sjoerg					break;
45020253Sjoerg				case _UC_MAXUID:
45120253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.max_uid);
45220253Sjoerg					quote = 0;
45320253Sjoerg					break;
45420253Sjoerg				case _UC_MINGID:
45520253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.min_gid);
45620253Sjoerg					quote = 0;
45720253Sjoerg					break;
45820253Sjoerg				case _UC_MAXGID:
45920253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.max_gid);
46020253Sjoerg					quote = 0;
46120253Sjoerg					break;
46220253Sjoerg				case _UC_EXPIRE:
46320253Sjoerg					sprintf(buf, "%d", config.expire_days);
46420253Sjoerg					quote = 0;
46520253Sjoerg					break;
46620253Sjoerg				case _UC_PASSWORD:
46720253Sjoerg					sprintf(buf, "%d", config.password_days);
46820253Sjoerg					quote = 0;
46920253Sjoerg					break;
47020253Sjoerg				case _UC_NONE:
47120253Sjoerg					break;
47220253Sjoerg				}
47320253Sjoerg
47420253Sjoerg				if (comments[i])
47520253Sjoerg					fputs(comments[i], fp);
47620253Sjoerg
47720253Sjoerg				if (*kwds[i]) {
47820253Sjoerg					if (quote)
47920253Sjoerg						fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
48020253Sjoerg					else
48120253Sjoerg						fprintf(fp, "%s = %s\n", kwds[i], val);
48220253Sjoerg#if debugging
48320253Sjoerg					printf("WROTE: %s = %s\n", kwds[i], val);
48420253Sjoerg#endif
48520253Sjoerg				}
48620253Sjoerg			}
48720747Sdavidn			free(buf);
48820253Sjoerg			return fclose(fp) != EOF;
48920253Sjoerg		}
49020253Sjoerg	}
49120253Sjoerg	return 0;
49220253Sjoerg}
493