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