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$";
3030259Scharnier#endif /* not lint */
3130259Scharnier
3220253Sjoerg#include <string.h>
3320253Sjoerg#include <ctype.h>
3420253Sjoerg#include <fcntl.h>
3520253Sjoerg
3620253Sjoerg#include "pw.h"
3720253Sjoerg
3820253Sjoerg#define debugging 0
3920253Sjoerg
4020253Sjoergenum {
4120253Sjoerg	_UC_NONE,
4220253Sjoerg	_UC_DEFAULTPWD,
4320253Sjoerg	_UC_REUSEUID,
4420253Sjoerg	_UC_REUSEGID,
4521330Sdavidn	_UC_NISPASSWD,
4620253Sjoerg	_UC_DOTDIR,
4720253Sjoerg	_UC_NEWMAIL,
4820253Sjoerg	_UC_LOGFILE,
4920253Sjoerg	_UC_HOMEROOT,
50168044Sle	_UC_HOMEMODE,
5120253Sjoerg	_UC_SHELLPATH,
5220253Sjoerg	_UC_SHELLS,
5320253Sjoerg	_UC_DEFAULTSHELL,
5420253Sjoerg	_UC_DEFAULTGROUP,
5520253Sjoerg	_UC_EXTRAGROUPS,
5620253Sjoerg	_UC_DEFAULTCLASS,
5720253Sjoerg	_UC_MINUID,
5820253Sjoerg	_UC_MAXUID,
5920253Sjoerg	_UC_MINGID,
6020253Sjoerg	_UC_MAXGID,
6120253Sjoerg	_UC_EXPIRE,
6220253Sjoerg	_UC_PASSWORD,
6320253Sjoerg	_UC_FIELDS
6420253Sjoerg};
6520253Sjoerg
6620253Sjoergstatic char     bourne_shell[] = "sh";
6720253Sjoerg
6820253Sjoergstatic char    *system_shells[_UC_MAXSHELLS] =
6920253Sjoerg{
7020253Sjoerg	bourne_shell,
7163239Sdavidn	"csh",
7263239Sdavidn	"tcsh"
7320253Sjoerg};
7420253Sjoerg
7520253Sjoergstatic char const *booltrue[] =
7620253Sjoerg{
7720253Sjoerg	"yes", "true", "1", "on", NULL
7820253Sjoerg};
7920253Sjoergstatic char const *boolfalse[] =
8020253Sjoerg{
8120253Sjoerg	"no", "false", "0", "off", NULL
8220253Sjoerg};
8320253Sjoerg
8420253Sjoergstatic struct userconf config =
8520253Sjoerg{
8620253Sjoerg	0,			/* Default password for new users? (nologin) */
8720253Sjoerg	0,			/* Reuse uids? */
8820253Sjoerg	0,			/* Reuse gids? */
8921330Sdavidn	NULL,			/* NIS version of the passwd file */
9020253Sjoerg	"/usr/share/skel",	/* Where to obtain skeleton files */
9120253Sjoerg	NULL,			/* Mail to send to new accounts */
9220253Sjoerg	"/var/log/userlog",	/* Where to log changes */
9320253Sjoerg	"/home",		/* Where to create home directory */
94219408Sjkim	_DEF_DIRMODE,		/* Home directory perms, modified by umask */
9520253Sjoerg	"/bin",			/* Where shells are located */
9620253Sjoerg	system_shells,		/* List of shells (first is default) */
9720253Sjoerg	bourne_shell,		/* Default shell */
9820253Sjoerg	NULL,			/* Default group name */
9920747Sdavidn	NULL,			/* Default (additional) groups */
10020253Sjoerg	NULL,			/* Default login class */
10120253Sjoerg	1000, 32000,		/* Allowed range of uids */
10220253Sjoerg	1000, 32000,		/* Allowed range of gids */
10320253Sjoerg	0,			/* Days until account expires */
10449171Sdavidn	0,			/* Days until password expires */
10549171Sdavidn	0			/* size of default_group array */
10620253Sjoerg};
10720253Sjoerg
10820253Sjoergstatic char const *comments[_UC_FIELDS] =
10920253Sjoerg{
11020253Sjoerg	"#\n# pw.conf - user/group configuration defaults\n#\n",
11120253Sjoerg	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
11220253Sjoerg	"\n# Reuse gaps in uid sequence? (yes or no)\n",
11320253Sjoerg	"\n# Reuse gaps in gid sequence? (yes or no)\n",
11421330Sdavidn	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
11520253Sjoerg	"\n# Obtain default dotfiles from this directory\n",
11620253Sjoerg	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
11720253Sjoerg	"\n# Log add/change/remove information in this file\n",
11820253Sjoerg	"\n# Root directory in which $HOME directory is created\n",
119168044Sle	"\n# Mode for the new $HOME directory, will be modified by umask\n",
12020253Sjoerg	"\n# Colon separated list of directories containing valid shells\n",
12170133Sdougb	"\n# Comma separated list of available shells (without paths)\n",
12220253Sjoerg	"\n# Default shell (without path)\n",
12320253Sjoerg	"\n# Default group (leave blank for new group per user)\n",
12420253Sjoerg	"\n# Extra groups for new users\n",
12520253Sjoerg	"\n# Default login class for new users\n",
12620253Sjoerg	"\n# Range of valid default user ids\n",
12720253Sjoerg	NULL,
12820253Sjoerg	"\n# Range of valid default group ids\n",
12920253Sjoerg	NULL,
13020253Sjoerg	"\n# Days after which account expires (0=disabled)\n",
13120253Sjoerg	"\n# Days after which password expires (0=disabled)\n"
13220253Sjoerg};
13320253Sjoerg
13420253Sjoergstatic char const *kwds[] =
13520253Sjoerg{
13620253Sjoerg	"",
13720253Sjoerg	"defaultpasswd",
13820253Sjoerg	"reuseuids",
13920253Sjoerg	"reusegids",
14021330Sdavidn	"nispasswd",
14120253Sjoerg	"skeleton",
14220253Sjoerg	"newmail",
14320253Sjoerg	"logfile",
14420253Sjoerg	"home",
145168044Sle	"homemode",
14620253Sjoerg	"shellpath",
14720253Sjoerg	"shells",
14820253Sjoerg	"defaultshell",
14920253Sjoerg	"defaultgroup",
15020253Sjoerg	"extragroups",
15120253Sjoerg	"defaultclass",
15220253Sjoerg	"minuid",
15320253Sjoerg	"maxuid",
15420253Sjoerg	"mingid",
15520253Sjoerg	"maxgid",
15620253Sjoerg	"expire_days",
15720253Sjoerg	"password_days",
15820253Sjoerg	NULL
15920253Sjoerg};
16020253Sjoerg
16120253Sjoergstatic char    *
16220253Sjoergunquote(char const * str)
16320253Sjoerg{
16420253Sjoerg	if (str && (*str == '"' || *str == '\'')) {
16520253Sjoerg		char           *p = strchr(str + 1, *str);
16620253Sjoerg
16720253Sjoerg		if (p != NULL)
16820253Sjoerg			*p = '\0';
16920253Sjoerg		return (char *) (*++str ? str : NULL);
17020253Sjoerg	}
17120253Sjoerg	return (char *) str;
17220253Sjoerg}
17320253Sjoerg
17420253Sjoergint
17520253Sjoergboolean_val(char const * str, int dflt)
17620253Sjoerg{
17720253Sjoerg	if ((str = unquote(str)) != NULL) {
17820253Sjoerg		int             i;
17920253Sjoerg
18020253Sjoerg		for (i = 0; booltrue[i]; i++)
18120253Sjoerg			if (strcmp(str, booltrue[i]) == 0)
18220253Sjoerg				return 1;
18320253Sjoerg		for (i = 0; boolfalse[i]; i++)
18420253Sjoerg			if (strcmp(str, boolfalse[i]) == 0)
18520253Sjoerg				return 0;
18620253Sjoerg
18720253Sjoerg		/*
18820253Sjoerg		 * Special cases for defaultpassword
18920253Sjoerg		 */
19020253Sjoerg		if (strcmp(str, "random") == 0)
19120253Sjoerg			return -1;
19220253Sjoerg		if (strcmp(str, "none") == 0)
19320253Sjoerg			return -2;
19420253Sjoerg	}
19520253Sjoerg	return dflt;
19620253Sjoerg}
19720253Sjoerg
19820253Sjoergchar const     *
19920253Sjoergboolean_str(int val)
20020253Sjoerg{
20120253Sjoerg	if (val == -1)
20220253Sjoerg		return "random";
20320253Sjoerg	else if (val == -2)
20420253Sjoerg		return "none";
20520253Sjoerg	else
20620253Sjoerg		return val ? booltrue[0] : boolfalse[0];
20720253Sjoerg}
20820253Sjoerg
20920253Sjoergchar           *
21020253Sjoergnewstr(char const * p)
21120253Sjoerg{
21220253Sjoerg	char           *q = NULL;
21320253Sjoerg
21420253Sjoerg	if ((p = unquote(p)) != NULL) {
21520253Sjoerg		int             l = strlen(p) + 1;
21620253Sjoerg
21720253Sjoerg		if ((q = malloc(l)) != NULL)
21820253Sjoerg			memcpy(q, p, l);
21920253Sjoerg	}
22020253Sjoerg	return q;
22120253Sjoerg}
22220253Sjoerg
22320747Sdavidn#define LNBUFSZ 1024
22420253Sjoerg
22520747Sdavidn
22620253Sjoergstruct userconf *
22720253Sjoergread_userconfig(char const * file)
22820253Sjoerg{
22920253Sjoerg	FILE           *fp;
23020253Sjoerg
23120747Sdavidn	extendarray(&config.groups, &config.numgroups, 200);
23220747Sdavidn	memset(config.groups, 0, config.numgroups * sizeof(char *));
23320253Sjoerg	if (file == NULL)
23420253Sjoerg		file = _PATH_PW_CONF;
23520253Sjoerg	if ((fp = fopen(file, "r")) != NULL) {
23620747Sdavidn		int	    buflen = LNBUFSZ;
23720747Sdavidn		char       *buf = malloc(buflen);
23820253Sjoerg
23920747Sdavidn	nextline:
24020747Sdavidn		while (fgets(buf, buflen, fp) != NULL) {
24120747Sdavidn			char           *p;
24220253Sjoerg
24320747Sdavidn			while ((p = strchr(buf, '\n')) == NULL) {
24420747Sdavidn				int	  l;
24520747Sdavidn				if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
24620747Sdavidn					int	ch;
24720747Sdavidn					while ((ch = fgetc(fp)) != '\n' && ch != EOF);
24820747Sdavidn					goto nextline;	/* Ignore it */
24920747Sdavidn				}
25020747Sdavidn				l = strlen(buf);
25120747Sdavidn				if (fgets(buf + l, buflen - l, fp) == NULL)
25220747Sdavidn					break;	/* Unterminated last line */
25320747Sdavidn			}
25420253Sjoerg
25520747Sdavidn			if (p != NULL)
25620253Sjoerg				*p = '\0';
25720253Sjoerg
25820747Sdavidn			if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
25920747Sdavidn				static char const toks[] = " \t\r\n,=";
26020747Sdavidn				char           *q = strtok(NULL, toks);
26120747Sdavidn				int             i = 0;
262168044Sle				mode_t          *modeset;
26320747Sdavidn
26420747Sdavidn				while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
26520747Sdavidn					++i;
26620253Sjoerg#if debugging
26720747Sdavidn				if (i == _UC_FIELDS)
26820747Sdavidn					printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
26920747Sdavidn				else
27020747Sdavidn					printf("Got kwd[%s]=%s\n", p, q);
27120253Sjoerg#endif
27220747Sdavidn				switch (i) {
27320747Sdavidn				case _UC_DEFAULTPWD:
27420747Sdavidn					config.default_password = boolean_val(q, 1);
27520747Sdavidn					break;
27620747Sdavidn				case _UC_REUSEUID:
27720747Sdavidn					config.reuse_uids = boolean_val(q, 0);
27820747Sdavidn					break;
27920747Sdavidn				case _UC_REUSEGID:
28020747Sdavidn					config.reuse_gids = boolean_val(q, 0);
28120747Sdavidn					break;
28221330Sdavidn				case _UC_NISPASSWD:
28321330Sdavidn					config.nispasswd = (q == NULL || !boolean_val(q, 1))
28421330Sdavidn						? NULL : newstr(q);
28521330Sdavidn					break;
28620747Sdavidn				case _UC_DOTDIR:
28720747Sdavidn					config.dotdir = (q == NULL || !boolean_val(q, 1))
28820747Sdavidn						? NULL : newstr(q);
28920747Sdavidn					break;
29020747Sdavidn				case _UC_NEWMAIL:
29120747Sdavidn					config.newmail = (q == NULL || !boolean_val(q, 1))
29220747Sdavidn						? NULL : newstr(q);
29320747Sdavidn					break;
29420747Sdavidn				case _UC_LOGFILE:
29520747Sdavidn					config.logfile = (q == NULL || !boolean_val(q, 1))
29620747Sdavidn						? NULL : newstr(q);
29720747Sdavidn					break;
29820747Sdavidn				case _UC_HOMEROOT:
29920747Sdavidn					config.home = (q == NULL || !boolean_val(q, 1))
30020747Sdavidn						? "/home" : newstr(q);
30120747Sdavidn					break;
302168044Sle				case _UC_HOMEMODE:
303168044Sle					modeset = setmode(q);
304168044Sle					config.homemode = (q == NULL || !boolean_val(q, 1))
305219408Sjkim						? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
306168044Sle					free(modeset);
307168044Sle					break;
30820747Sdavidn				case _UC_SHELLPATH:
30920747Sdavidn					config.shelldir = (q == NULL || !boolean_val(q, 1))
31020747Sdavidn						? "/bin" : newstr(q);
31120747Sdavidn					break;
31220747Sdavidn				case _UC_SHELLS:
31320747Sdavidn					for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
31420747Sdavidn						system_shells[i] = newstr(q);
31520747Sdavidn					if (i > 0)
31620747Sdavidn						while (i < _UC_MAXSHELLS)
31720747Sdavidn							system_shells[i++] = NULL;
31820747Sdavidn					break;
31920747Sdavidn				case _UC_DEFAULTSHELL:
32020747Sdavidn					config.shell_default = (q == NULL || !boolean_val(q, 1))
32120747Sdavidn						? (char *) bourne_shell : newstr(q);
32220747Sdavidn					break;
32320747Sdavidn				case _UC_DEFAULTGROUP:
32429002Sdavidn					q = unquote(q);
32544229Sdavidn					config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
32620747Sdavidn						? NULL : newstr(q);
32720747Sdavidn					break;
32820747Sdavidn				case _UC_EXTRAGROUPS:
32920747Sdavidn					for (i = 0; q != NULL; q = strtok(NULL, toks)) {
33020747Sdavidn						if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
33120747Sdavidn							config.groups[i++] = newstr(q);
33220253Sjoerg					}
33320747Sdavidn					if (i > 0)
33420747Sdavidn						while (i < config.numgroups)
33520747Sdavidn							config.groups[i++] = NULL;
33620747Sdavidn					break;
33720747Sdavidn				case _UC_DEFAULTCLASS:
33820747Sdavidn					config.default_class = (q == NULL || !boolean_val(q, 1))
33920747Sdavidn						? NULL : newstr(q);
34020747Sdavidn					break;
34120747Sdavidn				case _UC_MINUID:
34220747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
34320747Sdavidn						config.min_uid = (uid_t) atol(q);
34420747Sdavidn					break;
34520747Sdavidn				case _UC_MAXUID:
34620747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
34720747Sdavidn						config.max_uid = (uid_t) atol(q);
34820747Sdavidn					break;
34920747Sdavidn				case _UC_MINGID:
35020747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
35120747Sdavidn						config.min_gid = (gid_t) atol(q);
35220747Sdavidn					break;
35320747Sdavidn				case _UC_MAXGID:
35420747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
35520747Sdavidn						config.max_gid = (gid_t) atol(q);
35620747Sdavidn					break;
35720747Sdavidn				case _UC_EXPIRE:
35820747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
35920747Sdavidn						config.expire_days = atoi(q);
36020747Sdavidn					break;
36120747Sdavidn				case _UC_PASSWORD:
36220747Sdavidn					if ((q = unquote(q)) != NULL && isdigit(*q))
36320747Sdavidn						config.password_days = atoi(q);
36420747Sdavidn					break;
36520747Sdavidn				case _UC_FIELDS:
36620747Sdavidn				case _UC_NONE:
36720747Sdavidn					break;
36820253Sjoerg				}
36920253Sjoerg			}
37020253Sjoerg		}
37120747Sdavidn		free(buf);
37220253Sjoerg		fclose(fp);
37320253Sjoerg	}
37420253Sjoerg	return &config;
37520253Sjoerg}
37620253Sjoerg
37720253Sjoerg
37820253Sjoergint
37920253Sjoergwrite_userconfig(char const * file)
38020253Sjoerg{
38120253Sjoerg	int             fd;
38220253Sjoerg
38320253Sjoerg	if (file == NULL)
38420253Sjoerg		file = _PATH_PW_CONF;
38520253Sjoerg
38620253Sjoerg	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
38720253Sjoerg		FILE           *fp;
38820253Sjoerg
38920253Sjoerg		if ((fp = fdopen(fd, "w")) == NULL)
39020253Sjoerg			close(fd);
39120253Sjoerg		else {
39220253Sjoerg			int             i, j, k;
39320747Sdavidn			int		len = LNBUFSZ;
39420747Sdavidn			char           *buf = malloc(len);
39520253Sjoerg
39620253Sjoerg			for (i = _UC_NONE; i < _UC_FIELDS; i++) {
39720253Sjoerg				int             quote = 1;
39820253Sjoerg				char const     *val = buf;
39920253Sjoerg
40020253Sjoerg				*buf = '\0';
40120253Sjoerg				switch (i) {
40220253Sjoerg				case _UC_DEFAULTPWD:
40320253Sjoerg					val = boolean_str(config.default_password);
40420253Sjoerg					break;
40520253Sjoerg				case _UC_REUSEUID:
40620253Sjoerg					val = boolean_str(config.reuse_uids);
40720253Sjoerg					break;
40820253Sjoerg				case _UC_REUSEGID:
40920253Sjoerg					val = boolean_str(config.reuse_gids);
41020253Sjoerg					break;
41121330Sdavidn				case _UC_NISPASSWD:
41221330Sdavidn					val = config.nispasswd ? config.nispasswd : "";
41321330Sdavidn					quote = 0;
41421330Sdavidn					break;
41520253Sjoerg				case _UC_DOTDIR:
41620253Sjoerg					val = config.dotdir ? config.dotdir : boolean_str(0);
41720253Sjoerg					break;
41820253Sjoerg				case _UC_NEWMAIL:
41920253Sjoerg					val = config.newmail ? config.newmail : boolean_str(0);
42020253Sjoerg					break;
42120253Sjoerg				case _UC_LOGFILE:
42220253Sjoerg					val = config.logfile ? config.logfile : boolean_str(0);
42320253Sjoerg					break;
42420253Sjoerg				case _UC_HOMEROOT:
42520253Sjoerg					val = config.home;
42620253Sjoerg					break;
427168044Sle				case _UC_HOMEMODE:
428168044Sle					sprintf(buf, "%04o", config.homemode);
429168044Sle					quote = 0;
430168044Sle					break;
43120253Sjoerg				case _UC_SHELLPATH:
43220253Sjoerg					val = config.shelldir;
43320253Sjoerg					break;
43420253Sjoerg				case _UC_SHELLS:
43520747Sdavidn					for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
43620747Sdavidn						char	lbuf[64];
43720747Sdavidn						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
43881982Sbrian						if (l < 0)
43981977Sbrian							l = 0;
44020747Sdavidn						if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
44120747Sdavidn							strcpy(buf + k, lbuf);
44220747Sdavidn							k += l;
44320747Sdavidn						}
44420747Sdavidn					}
44520253Sjoerg					quote = 0;
44620253Sjoerg					break;
44720253Sjoerg				case _UC_DEFAULTSHELL:
44820253Sjoerg					val = config.shell_default ? config.shell_default : bourne_shell;
44920253Sjoerg					break;
45020253Sjoerg				case _UC_DEFAULTGROUP:
45120253Sjoerg					val = config.default_group ? config.default_group : "";
45220253Sjoerg					break;
45320253Sjoerg				case _UC_EXTRAGROUPS:
45420747Sdavidn					extendarray(&config.groups, &config.numgroups, 200);
45520747Sdavidn					for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
45620747Sdavidn						char	lbuf[64];
45720747Sdavidn						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
45881982Sbrian						if (l < 0)
45981977Sbrian							l = 0;
46020747Sdavidn						if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
46120747Sdavidn							strcpy(buf + k, lbuf);
46220747Sdavidn							k +=  l;
46320747Sdavidn						}
46420747Sdavidn					}
46520253Sjoerg					quote = 0;
46620253Sjoerg					break;
46720253Sjoerg				case _UC_DEFAULTCLASS:
46820253Sjoerg					val = config.default_class ? config.default_class : "";
46920253Sjoerg					break;
47020253Sjoerg				case _UC_MINUID:
47120253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.min_uid);
47220253Sjoerg					quote = 0;
47320253Sjoerg					break;
47420253Sjoerg				case _UC_MAXUID:
47520253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.max_uid);
47620253Sjoerg					quote = 0;
47720253Sjoerg					break;
47820253Sjoerg				case _UC_MINGID:
47920253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.min_gid);
48020253Sjoerg					quote = 0;
48120253Sjoerg					break;
48220253Sjoerg				case _UC_MAXGID:
48320253Sjoerg					sprintf(buf, "%lu", (unsigned long) config.max_gid);
48420253Sjoerg					quote = 0;
48520253Sjoerg					break;
48620253Sjoerg				case _UC_EXPIRE:
48720253Sjoerg					sprintf(buf, "%d", config.expire_days);
48820253Sjoerg					quote = 0;
48920253Sjoerg					break;
49020253Sjoerg				case _UC_PASSWORD:
49120253Sjoerg					sprintf(buf, "%d", config.password_days);
49220253Sjoerg					quote = 0;
49320253Sjoerg					break;
49420253Sjoerg				case _UC_NONE:
49520253Sjoerg					break;
49620253Sjoerg				}
49720253Sjoerg
49820253Sjoerg				if (comments[i])
49920253Sjoerg					fputs(comments[i], fp);
50020253Sjoerg
50120253Sjoerg				if (*kwds[i]) {
50220253Sjoerg					if (quote)
50320253Sjoerg						fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
50420253Sjoerg					else
50520253Sjoerg						fprintf(fp, "%s = %s\n", kwds[i], val);
50620253Sjoerg#if debugging
50720253Sjoerg					printf("WROTE: %s = %s\n", kwds[i], val);
50820253Sjoerg#endif
50920253Sjoerg				}
51020253Sjoerg			}
51120747Sdavidn			free(buf);
51220253Sjoerg			return fclose(fp) != EOF;
51320253Sjoerg		}
51420253Sjoerg	}
51520253Sjoerg	return 0;
51620253Sjoerg}
517