pw_conf.c revision 50479
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: head/usr.sbin/pw/pw_conf.c 50479 1999-08-28 01:35:59Z peter $"; 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, 5020253Sjoerg _UC_SHELLPATH, 5120253Sjoerg _UC_SHELLS, 5220253Sjoerg _UC_DEFAULTSHELL, 5320253Sjoerg _UC_DEFAULTGROUP, 5420253Sjoerg _UC_EXTRAGROUPS, 5520253Sjoerg _UC_DEFAULTCLASS, 5620253Sjoerg _UC_MINUID, 5720253Sjoerg _UC_MAXUID, 5820253Sjoerg _UC_MINGID, 5920253Sjoerg _UC_MAXGID, 6020253Sjoerg _UC_EXPIRE, 6120253Sjoerg _UC_PASSWORD, 6220253Sjoerg _UC_FIELDS 6320253Sjoerg}; 6420253Sjoerg 6520253Sjoergstatic char bourne_shell[] = "sh"; 6620253Sjoerg 6720253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 6820253Sjoerg{ 6920253Sjoerg bourne_shell, 7020253Sjoerg "csh" 7120253Sjoerg}; 7220253Sjoerg 7320253Sjoergstatic char const *booltrue[] = 7420253Sjoerg{ 7520253Sjoerg "yes", "true", "1", "on", NULL 7620253Sjoerg}; 7720253Sjoergstatic char const *boolfalse[] = 7820253Sjoerg{ 7920253Sjoerg "no", "false", "0", "off", NULL 8020253Sjoerg}; 8120253Sjoerg 8220253Sjoergstatic struct userconf config = 8320253Sjoerg{ 8420253Sjoerg 0, /* Default password for new users? (nologin) */ 8520253Sjoerg 0, /* Reuse uids? */ 8620253Sjoerg 0, /* Reuse gids? */ 8721330Sdavidn NULL, /* NIS version of the passwd file */ 8820253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 8920253Sjoerg NULL, /* Mail to send to new accounts */ 9020253Sjoerg "/var/log/userlog", /* Where to log changes */ 9120253Sjoerg "/home", /* Where to create home directory */ 9220253Sjoerg "/bin", /* Where shells are located */ 9320253Sjoerg system_shells, /* List of shells (first is default) */ 9420253Sjoerg bourne_shell, /* Default shell */ 9520253Sjoerg NULL, /* Default group name */ 9620747Sdavidn NULL, /* Default (additional) groups */ 9720253Sjoerg NULL, /* Default login class */ 9820253Sjoerg 1000, 32000, /* Allowed range of uids */ 9920253Sjoerg 1000, 32000, /* Allowed range of gids */ 10020253Sjoerg 0, /* Days until account expires */ 10149171Sdavidn 0, /* Days until password expires */ 10249171Sdavidn 0 /* size of default_group array */ 10320253Sjoerg}; 10420253Sjoerg 10520253Sjoergstatic char const *comments[_UC_FIELDS] = 10620253Sjoerg{ 10720253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 10820253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 10920253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 11020253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11121330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 11220253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11320253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 11420253Sjoerg "\n# Log add/change/remove information in this file\n", 11520253Sjoerg "\n# Root directory in which $HOME directory is created\n", 11620253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 11720253Sjoerg "\n# Space separated list of available shells (without paths)\n", 11820253Sjoerg "\n# Default shell (without path)\n", 11920253Sjoerg "\n# Default group (leave blank for new group per user)\n", 12020253Sjoerg "\n# Extra groups for new users\n", 12120253Sjoerg "\n# Default login class for new users\n", 12220253Sjoerg "\n# Range of valid default user ids\n", 12320253Sjoerg NULL, 12420253Sjoerg "\n# Range of valid default group ids\n", 12520253Sjoerg NULL, 12620253Sjoerg "\n# Days after which account expires (0=disabled)\n", 12720253Sjoerg "\n# Days after which password expires (0=disabled)\n" 12820253Sjoerg}; 12920253Sjoerg 13020253Sjoergstatic char const *kwds[] = 13120253Sjoerg{ 13220253Sjoerg "", 13320253Sjoerg "defaultpasswd", 13420253Sjoerg "reuseuids", 13520253Sjoerg "reusegids", 13621330Sdavidn "nispasswd", 13720253Sjoerg "skeleton", 13820253Sjoerg "newmail", 13920253Sjoerg "logfile", 14020253Sjoerg "home", 14120253Sjoerg "shellpath", 14220253Sjoerg "shells", 14320253Sjoerg "defaultshell", 14420253Sjoerg "defaultgroup", 14520253Sjoerg "extragroups", 14620253Sjoerg "defaultclass", 14720253Sjoerg "minuid", 14820253Sjoerg "maxuid", 14920253Sjoerg "mingid", 15020253Sjoerg "maxgid", 15120253Sjoerg "expire_days", 15220253Sjoerg "password_days", 15320253Sjoerg NULL 15420253Sjoerg}; 15520253Sjoerg 15620253Sjoergstatic char * 15720253Sjoergunquote(char const * str) 15820253Sjoerg{ 15920253Sjoerg if (str && (*str == '"' || *str == '\'')) { 16020253Sjoerg char *p = strchr(str + 1, *str); 16120253Sjoerg 16220253Sjoerg if (p != NULL) 16320253Sjoerg *p = '\0'; 16420253Sjoerg return (char *) (*++str ? str : NULL); 16520253Sjoerg } 16620253Sjoerg return (char *) str; 16720253Sjoerg} 16820253Sjoerg 16920253Sjoergint 17020253Sjoergboolean_val(char const * str, int dflt) 17120253Sjoerg{ 17220253Sjoerg if ((str = unquote(str)) != NULL) { 17320253Sjoerg int i; 17420253Sjoerg 17520253Sjoerg for (i = 0; booltrue[i]; i++) 17620253Sjoerg if (strcmp(str, booltrue[i]) == 0) 17720253Sjoerg return 1; 17820253Sjoerg for (i = 0; boolfalse[i]; i++) 17920253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 18020253Sjoerg return 0; 18120253Sjoerg 18220253Sjoerg /* 18320253Sjoerg * Special cases for defaultpassword 18420253Sjoerg */ 18520253Sjoerg if (strcmp(str, "random") == 0) 18620253Sjoerg return -1; 18720253Sjoerg if (strcmp(str, "none") == 0) 18820253Sjoerg return -2; 18920253Sjoerg } 19020253Sjoerg return dflt; 19120253Sjoerg} 19220253Sjoerg 19320253Sjoergchar const * 19420253Sjoergboolean_str(int val) 19520253Sjoerg{ 19620253Sjoerg if (val == -1) 19720253Sjoerg return "random"; 19820253Sjoerg else if (val == -2) 19920253Sjoerg return "none"; 20020253Sjoerg else 20120253Sjoerg return val ? booltrue[0] : boolfalse[0]; 20220253Sjoerg} 20320253Sjoerg 20420253Sjoergchar * 20520253Sjoergnewstr(char const * p) 20620253Sjoerg{ 20720253Sjoerg char *q = NULL; 20820253Sjoerg 20920253Sjoerg if ((p = unquote(p)) != NULL) { 21020253Sjoerg int l = strlen(p) + 1; 21120253Sjoerg 21220253Sjoerg if ((q = malloc(l)) != NULL) 21320253Sjoerg memcpy(q, p, l); 21420253Sjoerg } 21520253Sjoerg return q; 21620253Sjoerg} 21720253Sjoerg 21820747Sdavidn#define LNBUFSZ 1024 21920253Sjoerg 22020747Sdavidn 22120253Sjoergstruct userconf * 22220253Sjoergread_userconfig(char const * file) 22320253Sjoerg{ 22420253Sjoerg FILE *fp; 22520253Sjoerg 22620747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 22720747Sdavidn memset(config.groups, 0, config.numgroups * sizeof(char *)); 22820253Sjoerg if (file == NULL) 22920253Sjoerg file = _PATH_PW_CONF; 23020253Sjoerg if ((fp = fopen(file, "r")) != NULL) { 23120747Sdavidn int buflen = LNBUFSZ; 23220747Sdavidn char *buf = malloc(buflen); 23320253Sjoerg 23420747Sdavidn nextline: 23520747Sdavidn while (fgets(buf, buflen, fp) != NULL) { 23620747Sdavidn char *p; 23720253Sjoerg 23820747Sdavidn while ((p = strchr(buf, '\n')) == NULL) { 23920747Sdavidn int l; 24020747Sdavidn if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) { 24120747Sdavidn int ch; 24220747Sdavidn while ((ch = fgetc(fp)) != '\n' && ch != EOF); 24320747Sdavidn goto nextline; /* Ignore it */ 24420747Sdavidn } 24520747Sdavidn l = strlen(buf); 24620747Sdavidn if (fgets(buf + l, buflen - l, fp) == NULL) 24720747Sdavidn break; /* Unterminated last line */ 24820747Sdavidn } 24920253Sjoerg 25020747Sdavidn if (p != NULL) 25120253Sjoerg *p = '\0'; 25220253Sjoerg 25320747Sdavidn if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 25420747Sdavidn static char const toks[] = " \t\r\n,="; 25520747Sdavidn char *q = strtok(NULL, toks); 25620747Sdavidn int i = 0; 25720747Sdavidn 25820747Sdavidn while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 25920747Sdavidn ++i; 26020253Sjoerg#if debugging 26120747Sdavidn if (i == _UC_FIELDS) 26220747Sdavidn printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 26320747Sdavidn else 26420747Sdavidn printf("Got kwd[%s]=%s\n", p, q); 26520253Sjoerg#endif 26620747Sdavidn switch (i) { 26720747Sdavidn case _UC_DEFAULTPWD: 26820747Sdavidn config.default_password = boolean_val(q, 1); 26920747Sdavidn break; 27020747Sdavidn case _UC_REUSEUID: 27120747Sdavidn config.reuse_uids = boolean_val(q, 0); 27220747Sdavidn break; 27320747Sdavidn case _UC_REUSEGID: 27420747Sdavidn config.reuse_gids = boolean_val(q, 0); 27520747Sdavidn break; 27621330Sdavidn case _UC_NISPASSWD: 27721330Sdavidn config.nispasswd = (q == NULL || !boolean_val(q, 1)) 27821330Sdavidn ? NULL : newstr(q); 27921330Sdavidn break; 28020747Sdavidn case _UC_DOTDIR: 28120747Sdavidn config.dotdir = (q == NULL || !boolean_val(q, 1)) 28220747Sdavidn ? NULL : newstr(q); 28320747Sdavidn break; 28420747Sdavidn case _UC_NEWMAIL: 28520747Sdavidn config.newmail = (q == NULL || !boolean_val(q, 1)) 28620747Sdavidn ? NULL : newstr(q); 28720747Sdavidn break; 28820747Sdavidn case _UC_LOGFILE: 28920747Sdavidn config.logfile = (q == NULL || !boolean_val(q, 1)) 29020747Sdavidn ? NULL : newstr(q); 29120747Sdavidn break; 29220747Sdavidn case _UC_HOMEROOT: 29320747Sdavidn config.home = (q == NULL || !boolean_val(q, 1)) 29420747Sdavidn ? "/home" : newstr(q); 29520747Sdavidn break; 29620747Sdavidn case _UC_SHELLPATH: 29720747Sdavidn config.shelldir = (q == NULL || !boolean_val(q, 1)) 29820747Sdavidn ? "/bin" : newstr(q); 29920747Sdavidn break; 30020747Sdavidn case _UC_SHELLS: 30120747Sdavidn for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 30220747Sdavidn system_shells[i] = newstr(q); 30320747Sdavidn if (i > 0) 30420747Sdavidn while (i < _UC_MAXSHELLS) 30520747Sdavidn system_shells[i++] = NULL; 30620747Sdavidn break; 30720747Sdavidn case _UC_DEFAULTSHELL: 30820747Sdavidn config.shell_default = (q == NULL || !boolean_val(q, 1)) 30920747Sdavidn ? (char *) bourne_shell : newstr(q); 31020747Sdavidn break; 31120747Sdavidn case _UC_DEFAULTGROUP: 31229002Sdavidn q = unquote(q); 31344229Sdavidn config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 31420747Sdavidn ? NULL : newstr(q); 31520747Sdavidn break; 31620747Sdavidn case _UC_EXTRAGROUPS: 31720747Sdavidn for (i = 0; q != NULL; q = strtok(NULL, toks)) { 31820747Sdavidn if (extendarray(&config.groups, &config.numgroups, i + 2) != -1) 31920747Sdavidn config.groups[i++] = newstr(q); 32020253Sjoerg } 32120747Sdavidn if (i > 0) 32220747Sdavidn while (i < config.numgroups) 32320747Sdavidn config.groups[i++] = NULL; 32420747Sdavidn break; 32520747Sdavidn case _UC_DEFAULTCLASS: 32620747Sdavidn config.default_class = (q == NULL || !boolean_val(q, 1)) 32720747Sdavidn ? NULL : newstr(q); 32820747Sdavidn break; 32920747Sdavidn case _UC_MINUID: 33020747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33120747Sdavidn config.min_uid = (uid_t) atol(q); 33220747Sdavidn break; 33320747Sdavidn case _UC_MAXUID: 33420747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33520747Sdavidn config.max_uid = (uid_t) atol(q); 33620747Sdavidn break; 33720747Sdavidn case _UC_MINGID: 33820747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33920747Sdavidn config.min_gid = (gid_t) atol(q); 34020747Sdavidn break; 34120747Sdavidn case _UC_MAXGID: 34220747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34320747Sdavidn config.max_gid = (gid_t) atol(q); 34420747Sdavidn break; 34520747Sdavidn case _UC_EXPIRE: 34620747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34720747Sdavidn config.expire_days = atoi(q); 34820747Sdavidn break; 34920747Sdavidn case _UC_PASSWORD: 35020747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 35120747Sdavidn config.password_days = atoi(q); 35220747Sdavidn break; 35320747Sdavidn case _UC_FIELDS: 35420747Sdavidn case _UC_NONE: 35520747Sdavidn break; 35620253Sjoerg } 35720253Sjoerg } 35820253Sjoerg } 35920747Sdavidn free(buf); 36020253Sjoerg fclose(fp); 36120253Sjoerg } 36220253Sjoerg return &config; 36320253Sjoerg} 36420253Sjoerg 36520253Sjoerg 36620253Sjoergint 36720253Sjoergwrite_userconfig(char const * file) 36820253Sjoerg{ 36920253Sjoerg int fd; 37020253Sjoerg 37120253Sjoerg if (file == NULL) 37220253Sjoerg file = _PATH_PW_CONF; 37320253Sjoerg 37420253Sjoerg if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { 37520253Sjoerg FILE *fp; 37620253Sjoerg 37720253Sjoerg if ((fp = fdopen(fd, "w")) == NULL) 37820253Sjoerg close(fd); 37920253Sjoerg else { 38020253Sjoerg int i, j, k; 38120747Sdavidn int len = LNBUFSZ; 38220747Sdavidn char *buf = malloc(len); 38320253Sjoerg 38420253Sjoerg for (i = _UC_NONE; i < _UC_FIELDS; i++) { 38520253Sjoerg int quote = 1; 38620253Sjoerg char const *val = buf; 38720253Sjoerg 38820253Sjoerg *buf = '\0'; 38920253Sjoerg switch (i) { 39020253Sjoerg case _UC_DEFAULTPWD: 39120253Sjoerg val = boolean_str(config.default_password); 39220253Sjoerg break; 39320253Sjoerg case _UC_REUSEUID: 39420253Sjoerg val = boolean_str(config.reuse_uids); 39520253Sjoerg break; 39620253Sjoerg case _UC_REUSEGID: 39720253Sjoerg val = boolean_str(config.reuse_gids); 39820253Sjoerg break; 39921330Sdavidn case _UC_NISPASSWD: 40021330Sdavidn val = config.nispasswd ? config.nispasswd : ""; 40121330Sdavidn quote = 0; 40221330Sdavidn break; 40320253Sjoerg case _UC_DOTDIR: 40420253Sjoerg val = config.dotdir ? config.dotdir : boolean_str(0); 40520253Sjoerg break; 40620253Sjoerg case _UC_NEWMAIL: 40720253Sjoerg val = config.newmail ? config.newmail : boolean_str(0); 40820253Sjoerg break; 40920253Sjoerg case _UC_LOGFILE: 41020253Sjoerg val = config.logfile ? config.logfile : boolean_str(0); 41120253Sjoerg break; 41220253Sjoerg case _UC_HOMEROOT: 41320253Sjoerg val = config.home; 41420253Sjoerg break; 41520253Sjoerg case _UC_SHELLPATH: 41620253Sjoerg val = config.shelldir; 41720253Sjoerg break; 41820253Sjoerg case _UC_SHELLS: 41920747Sdavidn for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) { 42020747Sdavidn char lbuf[64]; 42120747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]); 42220747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) { 42320747Sdavidn strcpy(buf + k, lbuf); 42420747Sdavidn k += l; 42520747Sdavidn } 42620747Sdavidn } 42720253Sjoerg quote = 0; 42820253Sjoerg break; 42920253Sjoerg case _UC_DEFAULTSHELL: 43020253Sjoerg val = config.shell_default ? config.shell_default : bourne_shell; 43120253Sjoerg break; 43220253Sjoerg case _UC_DEFAULTGROUP: 43320253Sjoerg val = config.default_group ? config.default_group : ""; 43420253Sjoerg break; 43520253Sjoerg case _UC_EXTRAGROUPS: 43620747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 43720747Sdavidn for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) { 43820747Sdavidn char lbuf[64]; 43920747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]); 44020747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) { 44120747Sdavidn strcpy(buf + k, lbuf); 44220747Sdavidn k += l; 44320747Sdavidn } 44420747Sdavidn } 44520253Sjoerg quote = 0; 44620253Sjoerg break; 44720253Sjoerg case _UC_DEFAULTCLASS: 44820253Sjoerg val = config.default_class ? config.default_class : ""; 44920253Sjoerg break; 45020253Sjoerg case _UC_MINUID: 45120253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_uid); 45220253Sjoerg quote = 0; 45320253Sjoerg break; 45420253Sjoerg case _UC_MAXUID: 45520253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_uid); 45620253Sjoerg quote = 0; 45720253Sjoerg break; 45820253Sjoerg case _UC_MINGID: 45920253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_gid); 46020253Sjoerg quote = 0; 46120253Sjoerg break; 46220253Sjoerg case _UC_MAXGID: 46320253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_gid); 46420253Sjoerg quote = 0; 46520253Sjoerg break; 46620253Sjoerg case _UC_EXPIRE: 46720253Sjoerg sprintf(buf, "%d", config.expire_days); 46820253Sjoerg quote = 0; 46920253Sjoerg break; 47020253Sjoerg case _UC_PASSWORD: 47120253Sjoerg sprintf(buf, "%d", config.password_days); 47220253Sjoerg quote = 0; 47320253Sjoerg break; 47420253Sjoerg case _UC_NONE: 47520253Sjoerg break; 47620253Sjoerg } 47720253Sjoerg 47820253Sjoerg if (comments[i]) 47920253Sjoerg fputs(comments[i], fp); 48020253Sjoerg 48120253Sjoerg if (*kwds[i]) { 48220253Sjoerg if (quote) 48320253Sjoerg fprintf(fp, "%s = \"%s\"\n", kwds[i], val); 48420253Sjoerg else 48520253Sjoerg fprintf(fp, "%s = %s\n", kwds[i], val); 48620253Sjoerg#if debugging 48720253Sjoerg printf("WROTE: %s = %s\n", kwds[i], val); 48820253Sjoerg#endif 48920253Sjoerg } 49020253Sjoerg } 49120747Sdavidn free(buf); 49220253Sjoerg return fclose(fp) != EOF; 49320253Sjoerg } 49420253Sjoerg } 49520253Sjoerg return 0; 49620253Sjoerg} 497