pw_conf.c revision 81977
1256056Sgrehan/*-
2256056Sgrehan * Copyright (C) 1996
3256056Sgrehan *	David L. Nugent.  All rights reserved.
4256056Sgrehan *
5256056Sgrehan * Redistribution and use in source and binary forms, with or without
6256056Sgrehan * modification, are permitted provided that the following conditions
7256056Sgrehan * are met:
8256056Sgrehan * 1. Redistributions of source code must retain the above copyright
9256056Sgrehan *    notice, this list of conditions and the following disclaimer.
10256056Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
11256056Sgrehan *    notice, this list of conditions and the following disclaimer in the
12256056Sgrehan *    documentation and/or other materials provided with the distribution.
13256056Sgrehan *
14256056Sgrehan * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15256056Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16256056Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17256056Sgrehan * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18256056Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19256056Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20256056Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21256056Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22256056Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23256056Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24256056Sgrehan * SUCH DAMAGE.
25256056Sgrehan */
26256056Sgrehan
27256056Sgrehan#ifndef lint
28256056Sgrehanstatic const char rcsid[] =
29256056Sgrehan  "$FreeBSD: head/usr.sbin/pw/pw_conf.c 81977 2001-08-20 13:24:39Z brian $";
30256056Sgrehan#endif /* not lint */
31256056Sgrehan
32256056Sgrehan#include <string.h>
33256056Sgrehan#include <ctype.h>
34256056Sgrehan#include <fcntl.h>
35256056Sgrehan
36256056Sgrehan#include "pw.h"
37256056Sgrehan
38256056Sgrehan#define debugging 0
39256056Sgrehan
40256056Sgrehanenum {
41256056Sgrehan	_UC_NONE,
42256056Sgrehan	_UC_DEFAULTPWD,
43256056Sgrehan	_UC_REUSEUID,
44256056Sgrehan	_UC_REUSEGID,
45256056Sgrehan	_UC_NISPASSWD,
46256056Sgrehan	_UC_DOTDIR,
47256056Sgrehan	_UC_NEWMAIL,
48256056Sgrehan	_UC_LOGFILE,
49256056Sgrehan	_UC_HOMEROOT,
50256056Sgrehan	_UC_SHELLPATH,
51276349Sneel	_UC_SHELLS,
52256056Sgrehan	_UC_DEFAULTSHELL,
53280745Smav	_UC_DEFAULTGROUP,
54256056Sgrehan	_UC_EXTRAGROUPS,
55256056Sgrehan	_UC_DEFAULTCLASS,
56256056Sgrehan	_UC_MINUID,
57256056Sgrehan	_UC_MAXUID,
58256056Sgrehan	_UC_MINGID,
59256056Sgrehan	_UC_MAXGID,
60256056Sgrehan	_UC_EXPIRE,
61256056Sgrehan	_UC_PASSWORD,
62256056Sgrehan	_UC_FIELDS
63256056Sgrehan};
64256056Sgrehan
65256056Sgrehanstatic char     bourne_shell[] = "sh";
66256056Sgrehan
67256056Sgrehanstatic char    *system_shells[_UC_MAXSHELLS] =
68256056Sgrehan{
69256056Sgrehan	bourne_shell,
70256056Sgrehan	"csh",
71256056Sgrehan	"tcsh"
72256056Sgrehan};
73256056Sgrehan
74256056Sgrehanstatic char const *booltrue[] =
75256056Sgrehan{
76256056Sgrehan	"yes", "true", "1", "on", NULL
77256056Sgrehan};
78256056Sgrehanstatic char const *boolfalse[] =
79256056Sgrehan{
80256056Sgrehan	"no", "false", "0", "off", NULL
81256056Sgrehan};
82256056Sgrehan
83256056Sgrehanstatic struct userconf config =
84256056Sgrehan{
85256056Sgrehan	0,			/* Default password for new users? (nologin) */
86256056Sgrehan	0,			/* Reuse uids? */
87256056Sgrehan	0,			/* Reuse gids? */
88256056Sgrehan	NULL,			/* NIS version of the passwd file */
89256056Sgrehan	"/usr/share/skel",	/* Where to obtain skeleton files */
90280740Smav	NULL,			/* Mail to send to new accounts */
91256056Sgrehan	"/var/log/userlog",	/* Where to log changes */
92256056Sgrehan	"/home",		/* Where to create home directory */
93256056Sgrehan	"/bin",			/* Where shells are located */
94256056Sgrehan	system_shells,		/* List of shells (first is default) */
95256056Sgrehan	bourne_shell,		/* Default shell */
96256056Sgrehan	NULL,			/* Default group name */
97256056Sgrehan	NULL,			/* Default (additional) groups */
98256056Sgrehan	NULL,			/* Default login class */
99256056Sgrehan	1000, 32000,		/* Allowed range of uids */
100256056Sgrehan	1000, 32000,		/* Allowed range of gids */
101267339Sjhb	0,			/* Days until account expires */
102267339Sjhb	0,			/* Days until password expires */
103267339Sjhb	0			/* size of default_group array */
104267339Sjhb};
105267339Sjhb
106267339Sjhbstatic char const *comments[_UC_FIELDS] =
107267339Sjhb{
108256056Sgrehan	"#\n# pw.conf - user/group configuration defaults\n#\n",
109256056Sgrehan	"\n# Password for new users? no=nologin yes=loginid none=blank random=random\n",
110256056Sgrehan	"\n# Reuse gaps in uid sequence? (yes or no)\n",
111256056Sgrehan	"\n# Reuse gaps in gid sequence? (yes or no)\n",
112256056Sgrehan	"\n# Path to the NIS passwd file (blank or 'no' for none)\n",
113256056Sgrehan	"\n# Obtain default dotfiles from this directory\n",
114256056Sgrehan	"\n# Mail this file to new user (/etc/newuser.msg or no)\n",
115256056Sgrehan	"\n# Log add/change/remove information in this file\n",
116256056Sgrehan	"\n# Root directory in which $HOME directory is created\n",
117256056Sgrehan	"\n# Colon separated list of directories containing valid shells\n",
118256056Sgrehan	"\n# Comma separated list of available shells (without paths)\n",
119256056Sgrehan	"\n# Default shell (without path)\n",
120256056Sgrehan	"\n# Default group (leave blank for new group per user)\n",
121276349Sneel	"\n# Extra groups for new users\n",
122276349Sneel	"\n# Default login class for new users\n",
123256056Sgrehan	"\n# Range of valid default user ids\n",
124256056Sgrehan	NULL,
125256056Sgrehan	"\n# Range of valid default group ids\n",
126256056Sgrehan	NULL,
127282306Smav	"\n# Days after which account expires (0=disabled)\n",
128256056Sgrehan	"\n# Days after which password expires (0=disabled)\n"
129256056Sgrehan};
130256056Sgrehan
131256056Sgrehanstatic char const *kwds[] =
132256056Sgrehan{
133256164Sdim	"",
134256164Sdim	"defaultpasswd",
135280745Smav	"reuseuids",
136256056Sgrehan	"reusegids",
137256056Sgrehan	"nispasswd",
138282846Smav	"skeleton",
139256056Sgrehan	"newmail",
140256056Sgrehan	"logfile",
141280736Smav	"home",
142256056Sgrehan	"shellpath",
143256056Sgrehan	"shells",
144282846Smav	"defaultshell",
145267339Sjhb	"defaultgroup",
146256056Sgrehan	"extragroups",
147256056Sgrehan	"defaultclass",
148256056Sgrehan	"minuid",
149256056Sgrehan	"maxuid",
150256056Sgrehan	"mingid",
151256056Sgrehan	"maxgid",
152256056Sgrehan	"expire_days",
153256056Sgrehan	"password_days",
154256056Sgrehan	NULL
155256056Sgrehan};
156256056Sgrehan
157256056Sgrehanstatic char    *
158256056Sgrehanunquote(char const * str)
159256056Sgrehan{
160256056Sgrehan	if (str && (*str == '"' || *str == '\'')) {
161256056Sgrehan		char           *p = strchr(str + 1, *str);
162256056Sgrehan
163256056Sgrehan		if (p != NULL)
164256056Sgrehan			*p = '\0';
165256056Sgrehan		return (char *) (*++str ? str : NULL);
166256056Sgrehan	}
167256056Sgrehan	return (char *) str;
168256056Sgrehan}
169256056Sgrehan
170256056Sgrehanint
171276349Sneelboolean_val(char const * str, int dflt)
172256056Sgrehan{
173256056Sgrehan	if ((str = unquote(str)) != NULL) {
174256056Sgrehan		int             i;
175256056Sgrehan
176256056Sgrehan		for (i = 0; booltrue[i]; i++)
177256056Sgrehan			if (strcmp(str, booltrue[i]) == 0)
178256056Sgrehan				return 1;
179256056Sgrehan		for (i = 0; boolfalse[i]; i++)
180256056Sgrehan			if (strcmp(str, boolfalse[i]) == 0)
181256056Sgrehan				return 0;
182256056Sgrehan
183256056Sgrehan		/*
184256056Sgrehan		 * Special cases for defaultpassword
185259301Sgrehan		 */
186256056Sgrehan		if (strcmp(str, "random") == 0)
187256056Sgrehan			return -1;
188256056Sgrehan		if (strcmp(str, "none") == 0)
189256056Sgrehan			return -2;
190256056Sgrehan	}
191256056Sgrehan	return dflt;
192256056Sgrehan}
193256056Sgrehan
194256056Sgrehanchar const     *
195256056Sgrehanboolean_str(int val)
196256056Sgrehan{
197256056Sgrehan	if (val == -1)
198256056Sgrehan		return "random";
199256056Sgrehan	else if (val == -2)
200256056Sgrehan		return "none";
201256056Sgrehan	else
202256056Sgrehan		return val ? booltrue[0] : boolfalse[0];
203256056Sgrehan}
204267393Sjhb
205256056Sgrehanchar           *
206256056Sgrehannewstr(char const * p)
207256056Sgrehan{
208256056Sgrehan	char           *q = NULL;
209282846Smav
210282846Smav	if ((p = unquote(p)) != NULL) {
211256056Sgrehan		int             l = strlen(p) + 1;
212256056Sgrehan
213256056Sgrehan		if ((q = malloc(l)) != NULL)
214256056Sgrehan			memcpy(q, p, l);
215256056Sgrehan	}
216256056Sgrehan	return q;
217256056Sgrehan}
218256056Sgrehan
219256056Sgrehan#define LNBUFSZ 1024
220256056Sgrehan
221256056Sgrehan
222256056Sgrehanstruct userconf *
223256056Sgrehanread_userconfig(char const * file)
224256056Sgrehan{
225256056Sgrehan	FILE           *fp;
226267393Sjhb
227256056Sgrehan	extendarray(&config.groups, &config.numgroups, 200);
228256056Sgrehan	memset(config.groups, 0, config.numgroups * sizeof(char *));
229267393Sjhb	if (file == NULL)
230267393Sjhb		file = _PATH_PW_CONF;
231256056Sgrehan	if ((fp = fopen(file, "r")) != NULL) {
232256056Sgrehan		int	    buflen = LNBUFSZ;
233256056Sgrehan		char       *buf = malloc(buflen);
234256056Sgrehan
235256056Sgrehan	nextline:
236256056Sgrehan		while (fgets(buf, buflen, fp) != NULL) {
237256056Sgrehan			char           *p;
238256056Sgrehan
239256056Sgrehan			while ((p = strchr(buf, '\n')) == NULL) {
240267393Sjhb				int	  l;
241267393Sjhb				if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) {
242267393Sjhb					int	ch;
243267393Sjhb					while ((ch = fgetc(fp)) != '\n' && ch != EOF);
244267393Sjhb					goto nextline;	/* Ignore it */
245267393Sjhb				}
246267393Sjhb				l = strlen(buf);
247267393Sjhb				if (fgets(buf + l, buflen - l, fp) == NULL)
248267393Sjhb					break;	/* Unterminated last line */
249267393Sjhb			}
250267393Sjhb
251267393Sjhb			if (p != NULL)
252267393Sjhb				*p = '\0';
253267393Sjhb
254267393Sjhb			if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
255267393Sjhb				static char const toks[] = " \t\r\n,=";
256267393Sjhb				char           *q = strtok(NULL, toks);
257267393Sjhb				int             i = 0;
258267393Sjhb
259267393Sjhb				while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
260267393Sjhb					++i;
261267393Sjhb#if debugging
262256056Sgrehan				if (i == _UC_FIELDS)
263256056Sgrehan					printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
264256056Sgrehan				else
265256056Sgrehan					printf("Got kwd[%s]=%s\n", p, q);
266256056Sgrehan#endif
267256056Sgrehan				switch (i) {
268256056Sgrehan				case _UC_DEFAULTPWD:
269256164Sdim					config.default_password = boolean_val(q, 1);
270256056Sgrehan					break;
271256056Sgrehan				case _UC_REUSEUID:
272256056Sgrehan					config.reuse_uids = boolean_val(q, 0);
273256056Sgrehan					break;
274256056Sgrehan				case _UC_REUSEGID:
275256056Sgrehan					config.reuse_gids = boolean_val(q, 0);
276282846Smav					break;
277256056Sgrehan				case _UC_NISPASSWD:
278256056Sgrehan					config.nispasswd = (q == NULL || !boolean_val(q, 1))
279256056Sgrehan						? NULL : newstr(q);
280256056Sgrehan					break;
281282846Smav				case _UC_DOTDIR:
282256056Sgrehan					config.dotdir = (q == NULL || !boolean_val(q, 1))
283256056Sgrehan						? NULL : newstr(q);
284256056Sgrehan					break;
285256056Sgrehan				case _UC_NEWMAIL:
286282846Smav					config.newmail = (q == NULL || !boolean_val(q, 1))
287256056Sgrehan						? NULL : newstr(q);
288256056Sgrehan					break;
289256056Sgrehan				case _UC_LOGFILE:
290256056Sgrehan					config.logfile = (q == NULL || !boolean_val(q, 1))
291256056Sgrehan						? NULL : newstr(q);
292282846Smav					break;
293282846Smav				case _UC_HOMEROOT:
294282846Smav					config.home = (q == NULL || !boolean_val(q, 1))
295282846Smav						? "/home" : newstr(q);
296256056Sgrehan					break;
297256056Sgrehan				case _UC_SHELLPATH:
298256056Sgrehan					config.shelldir = (q == NULL || !boolean_val(q, 1))
299256056Sgrehan						? "/bin" : newstr(q);
300256056Sgrehan					break;
301256056Sgrehan				case _UC_SHELLS:
302256056Sgrehan					for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
303256056Sgrehan						system_shells[i] = newstr(q);
304267339Sjhb					if (i > 0)
305267339Sjhb						while (i < _UC_MAXSHELLS)
306267339Sjhb							system_shells[i++] = NULL;
307267339Sjhb					break;
308267339Sjhb				case _UC_DEFAULTSHELL:
309267339Sjhb					config.shell_default = (q == NULL || !boolean_val(q, 1))
310267339Sjhb						? (char *) bourne_shell : newstr(q);
311267339Sjhb					break;
312267339Sjhb				case _UC_DEFAULTGROUP:
313267339Sjhb					q = unquote(q);
314280736Smav					config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
315256056Sgrehan						? NULL : newstr(q);
316256056Sgrehan					break;
317256056Sgrehan				case _UC_EXTRAGROUPS:
318256056Sgrehan					for (i = 0; q != NULL; q = strtok(NULL, toks)) {
319256056Sgrehan						if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
320282846Smav							config.groups[i++] = newstr(q);
321256056Sgrehan					}
322280736Smav					if (i > 0)
323280736Smav						while (i < config.numgroups)
324282846Smav							config.groups[i++] = NULL;
325280736Smav					break;
326280736Smav				case _UC_DEFAULTCLASS:
327280736Smav					config.default_class = (q == NULL || !boolean_val(q, 1))
328282846Smav						? NULL : newstr(q);
329280736Smav					break;
330280736Smav				case _UC_MINUID:
331280736Smav					if ((q = unquote(q)) != NULL && isdigit(*q))
332280736Smav						config.min_uid = (uid_t) atol(q);
333280736Smav					break;
334280736Smav				case _UC_MAXUID:
335282846Smav					if ((q = unquote(q)) != NULL && isdigit(*q))
336282846Smav						config.max_uid = (uid_t) atol(q);
337256056Sgrehan					break;
338256056Sgrehan				case _UC_MINGID:
339256056Sgrehan					if ((q = unquote(q)) != NULL && isdigit(*q))
340256056Sgrehan						config.min_gid = (gid_t) atol(q);
341256056Sgrehan					break;
342256056Sgrehan				case _UC_MAXGID:
343256056Sgrehan					if ((q = unquote(q)) != NULL && isdigit(*q))
344256056Sgrehan						config.max_gid = (gid_t) atol(q);
345256056Sgrehan					break;
346256056Sgrehan				case _UC_EXPIRE:
347256056Sgrehan					if ((q = unquote(q)) != NULL && isdigit(*q))
348256056Sgrehan						config.expire_days = atoi(q);
349256056Sgrehan					break;
350256056Sgrehan				case _UC_PASSWORD:
351256056Sgrehan					if ((q = unquote(q)) != NULL && isdigit(*q))
352256056Sgrehan						config.password_days = atoi(q);
353256056Sgrehan					break;
354256056Sgrehan				case _UC_FIELDS:
355256056Sgrehan				case _UC_NONE:
356256056Sgrehan					break;
357256056Sgrehan				}
358256056Sgrehan			}
359256056Sgrehan		}
360256056Sgrehan		free(buf);
361256056Sgrehan		fclose(fp);
362280736Smav	}
363280736Smav	return &config;
364280736Smav}
365280736Smav
366280736Smav
367280736Smavint
368270159Sgrehanwrite_userconfig(char const * file)
369256056Sgrehan{
370256056Sgrehan	int             fd;
371256056Sgrehan
372256056Sgrehan	if (file == NULL)
373256056Sgrehan		file = _PATH_PW_CONF;
374282846Smav
375282846Smav	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
376282846Smav		FILE           *fp;
377282846Smav
378282846Smav		if ((fp = fdopen(fd, "w")) == NULL)
379282846Smav			close(fd);
380282846Smav		else {
381282846Smav			int             i, j, k;
382282846Smav			int		len = LNBUFSZ;
383282846Smav			char           *buf = malloc(len);
384282846Smav
385282846Smav			for (i = _UC_NONE; i < _UC_FIELDS; i++) {
386282846Smav				int             quote = 1;
387282846Smav				char const     *val = buf;
388282846Smav
389256056Sgrehan				*buf = '\0';
390256056Sgrehan				switch (i) {
391256056Sgrehan				case _UC_DEFAULTPWD:
392256056Sgrehan					val = boolean_str(config.default_password);
393256056Sgrehan					break;
394256056Sgrehan				case _UC_REUSEUID:
395256056Sgrehan					val = boolean_str(config.reuse_uids);
396256056Sgrehan					break;
397256056Sgrehan				case _UC_REUSEGID:
398256056Sgrehan					val = boolean_str(config.reuse_gids);
399256056Sgrehan					break;
400256056Sgrehan				case _UC_NISPASSWD:
401256056Sgrehan					val = config.nispasswd ? config.nispasswd : "";
402256056Sgrehan					quote = 0;
403256056Sgrehan					break;
404256056Sgrehan				case _UC_DOTDIR:
405256056Sgrehan					val = config.dotdir ? config.dotdir : boolean_str(0);
406276349Sneel					break;
407276349Sneel				case _UC_NEWMAIL:
408276349Sneel					val = config.newmail ? config.newmail : boolean_str(0);
409276349Sneel					break;
410276429Sneel				case _UC_LOGFILE:
411276429Sneel					val = config.logfile ? config.logfile : boolean_str(0);
412276349Sneel					break;
413276349Sneel				case _UC_HOMEROOT:
414276429Sneel					val = config.home;
415282846Smav					break;
416276349Sneel				case _UC_SHELLPATH:
417276429Sneel					val = config.shelldir;
418276429Sneel					break;
419282846Smav				case _UC_SHELLS:
420276429Sneel					for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) {
421276349Sneel						char	lbuf[64];
422276349Sneel						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]);
423276349Sneel						if (l == -1)
424276349Sneel							l = 0;
425276349Sneel						if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) {
426276349Sneel							strcpy(buf + k, lbuf);
427276349Sneel							k += l;
428276349Sneel						}
429276349Sneel					}
430276349Sneel					quote = 0;
431276349Sneel					break;
432276349Sneel				case _UC_DEFAULTSHELL:
433276349Sneel					val = config.shell_default ? config.shell_default : bourne_shell;
434276349Sneel					break;
435276349Sneel				case _UC_DEFAULTGROUP:
436276349Sneel					val = config.default_group ? config.default_group : "";
437276349Sneel					break;
438276349Sneel				case _UC_EXTRAGROUPS:
439276349Sneel					extendarray(&config.groups, &config.numgroups, 200);
440276349Sneel					for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) {
441276349Sneel						char	lbuf[64];
442276349Sneel						int	l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]);
443276349Sneel						if (l == -1)
444276349Sneel							l = 0;
445276349Sneel						if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) {
446282844Smav							strcpy(buf + k, lbuf);
447282844Smav							k +=  l;
448276349Sneel						}
449276349Sneel					}
450276349Sneel					quote = 0;
451276349Sneel					break;
452276349Sneel				case _UC_DEFAULTCLASS:
453276349Sneel					val = config.default_class ? config.default_class : "";
454276349Sneel					break;
455276349Sneel				case _UC_MINUID:
456276349Sneel					sprintf(buf, "%lu", (unsigned long) config.min_uid);
457276349Sneel					quote = 0;
458276349Sneel					break;
459276349Sneel				case _UC_MAXUID:
460276349Sneel					sprintf(buf, "%lu", (unsigned long) config.max_uid);
461276349Sneel					quote = 0;
462276349Sneel					break;
463276349Sneel				case _UC_MINGID:
464276349Sneel					sprintf(buf, "%lu", (unsigned long) config.min_gid);
465276349Sneel					quote = 0;
466276349Sneel					break;
467276349Sneel				case _UC_MAXGID:
468276349Sneel					sprintf(buf, "%lu", (unsigned long) config.max_gid);
469276349Sneel					quote = 0;
470276349Sneel					break;
471276349Sneel				case _UC_EXPIRE:
472276349Sneel					sprintf(buf, "%d", config.expire_days);
473276349Sneel					quote = 0;
474276349Sneel					break;
475256056Sgrehan				case _UC_PASSWORD:
476256056Sgrehan					sprintf(buf, "%d", config.password_days);
477256056Sgrehan					quote = 0;
478256056Sgrehan					break;
479256056Sgrehan				case _UC_NONE:
480256056Sgrehan					break;
481256056Sgrehan				}
482256056Sgrehan
483256056Sgrehan				if (comments[i])
484256056Sgrehan					fputs(comments[i], fp);
485256056Sgrehan
486256056Sgrehan				if (*kwds[i]) {
487256056Sgrehan					if (quote)
488280733Smav						fprintf(fp, "%s = \"%s\"\n", kwds[i], val);
489280733Smav					else
490280733Smav						fprintf(fp, "%s = %s\n", kwds[i], val);
491280733Smav#if debugging
492280733Smav					printf("WROTE: %s = %s\n", kwds[i], val);
493256056Sgrehan#endif
494256056Sgrehan				}
495256056Sgrehan			}
496256056Sgrehan			free(buf);
497256056Sgrehan			return fclose(fp) != EOF;
498256056Sgrehan		}
499256056Sgrehan	}
500256056Sgrehan	return 0;
501256056Sgrehan}
502256056Sgrehan