pw_conf.c revision 44229
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[] = 2944229Sdavidn "$Id: pw_conf.c,v 1.7 1997/10/10 06:23:36 charnier Exp $"; 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 */ 10120253Sjoerg 0 /* Days until password expires */ 10220253Sjoerg}; 10320253Sjoerg 10420253Sjoergstatic char const *comments[_UC_FIELDS] = 10520253Sjoerg{ 10620253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 10720253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 10820253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 10920253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11021330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 11120253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11220253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 11320253Sjoerg "\n# Log add/change/remove information in this file\n", 11420253Sjoerg "\n# Root directory in which $HOME directory is created\n", 11520253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 11620253Sjoerg "\n# Space separated list of available shells (without paths)\n", 11720253Sjoerg "\n# Default shell (without path)\n", 11820253Sjoerg "\n# Default group (leave blank for new group per user)\n", 11920253Sjoerg "\n# Extra groups for new users\n", 12020253Sjoerg "\n# Default login class for new users\n", 12120253Sjoerg "\n# Range of valid default user ids\n", 12220253Sjoerg NULL, 12320253Sjoerg "\n# Range of valid default group ids\n", 12420253Sjoerg NULL, 12520253Sjoerg "\n# Days after which account expires (0=disabled)\n", 12620253Sjoerg "\n# Days after which password expires (0=disabled)\n" 12720253Sjoerg}; 12820253Sjoerg 12920253Sjoergstatic char const *kwds[] = 13020253Sjoerg{ 13120253Sjoerg "", 13220253Sjoerg "defaultpasswd", 13320253Sjoerg "reuseuids", 13420253Sjoerg "reusegids", 13521330Sdavidn "nispasswd", 13620253Sjoerg "skeleton", 13720253Sjoerg "newmail", 13820253Sjoerg "logfile", 13920253Sjoerg "home", 14020253Sjoerg "shellpath", 14120253Sjoerg "shells", 14220253Sjoerg "defaultshell", 14320253Sjoerg "defaultgroup", 14420253Sjoerg "extragroups", 14520253Sjoerg "defaultclass", 14620253Sjoerg "minuid", 14720253Sjoerg "maxuid", 14820253Sjoerg "mingid", 14920253Sjoerg "maxgid", 15020253Sjoerg "expire_days", 15120253Sjoerg "password_days", 15220253Sjoerg NULL 15320253Sjoerg}; 15420253Sjoerg 15520253Sjoergstatic char * 15620253Sjoergunquote(char const * str) 15720253Sjoerg{ 15820253Sjoerg if (str && (*str == '"' || *str == '\'')) { 15920253Sjoerg char *p = strchr(str + 1, *str); 16020253Sjoerg 16120253Sjoerg if (p != NULL) 16220253Sjoerg *p = '\0'; 16320253Sjoerg return (char *) (*++str ? str : NULL); 16420253Sjoerg } 16520253Sjoerg return (char *) str; 16620253Sjoerg} 16720253Sjoerg 16820253Sjoergint 16920253Sjoergboolean_val(char const * str, int dflt) 17020253Sjoerg{ 17120253Sjoerg if ((str = unquote(str)) != NULL) { 17220253Sjoerg int i; 17320253Sjoerg 17420253Sjoerg for (i = 0; booltrue[i]; i++) 17520253Sjoerg if (strcmp(str, booltrue[i]) == 0) 17620253Sjoerg return 1; 17720253Sjoerg for (i = 0; boolfalse[i]; i++) 17820253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 17920253Sjoerg return 0; 18020253Sjoerg 18120253Sjoerg /* 18220253Sjoerg * Special cases for defaultpassword 18320253Sjoerg */ 18420253Sjoerg if (strcmp(str, "random") == 0) 18520253Sjoerg return -1; 18620253Sjoerg if (strcmp(str, "none") == 0) 18720253Sjoerg return -2; 18820253Sjoerg } 18920253Sjoerg return dflt; 19020253Sjoerg} 19120253Sjoerg 19220253Sjoergchar const * 19320253Sjoergboolean_str(int val) 19420253Sjoerg{ 19520253Sjoerg if (val == -1) 19620253Sjoerg return "random"; 19720253Sjoerg else if (val == -2) 19820253Sjoerg return "none"; 19920253Sjoerg else 20020253Sjoerg return val ? booltrue[0] : boolfalse[0]; 20120253Sjoerg} 20220253Sjoerg 20320253Sjoergchar * 20420253Sjoergnewstr(char const * p) 20520253Sjoerg{ 20620253Sjoerg char *q = NULL; 20720253Sjoerg 20820253Sjoerg if ((p = unquote(p)) != NULL) { 20920253Sjoerg int l = strlen(p) + 1; 21020253Sjoerg 21120253Sjoerg if ((q = malloc(l)) != NULL) 21220253Sjoerg memcpy(q, p, l); 21320253Sjoerg } 21420253Sjoerg return q; 21520253Sjoerg} 21620253Sjoerg 21720747Sdavidn#define LNBUFSZ 1024 21820253Sjoerg 21920747Sdavidn 22020253Sjoergstruct userconf * 22120253Sjoergread_userconfig(char const * file) 22220253Sjoerg{ 22320253Sjoerg FILE *fp; 22420253Sjoerg 22520747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 22620747Sdavidn memset(config.groups, 0, config.numgroups * sizeof(char *)); 22720253Sjoerg if (file == NULL) 22820253Sjoerg file = _PATH_PW_CONF; 22920253Sjoerg if ((fp = fopen(file, "r")) != NULL) { 23020747Sdavidn int buflen = LNBUFSZ; 23120747Sdavidn char *buf = malloc(buflen); 23220253Sjoerg 23320747Sdavidn nextline: 23420747Sdavidn while (fgets(buf, buflen, fp) != NULL) { 23520747Sdavidn char *p; 23620253Sjoerg 23720747Sdavidn while ((p = strchr(buf, '\n')) == NULL) { 23820747Sdavidn int l; 23920747Sdavidn if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) { 24020747Sdavidn int ch; 24120747Sdavidn while ((ch = fgetc(fp)) != '\n' && ch != EOF); 24220747Sdavidn goto nextline; /* Ignore it */ 24320747Sdavidn } 24420747Sdavidn l = strlen(buf); 24520747Sdavidn if (fgets(buf + l, buflen - l, fp) == NULL) 24620747Sdavidn break; /* Unterminated last line */ 24720747Sdavidn } 24820253Sjoerg 24920747Sdavidn if (p != NULL) 25020253Sjoerg *p = '\0'; 25120253Sjoerg 25220747Sdavidn if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 25320747Sdavidn static char const toks[] = " \t\r\n,="; 25420747Sdavidn char *q = strtok(NULL, toks); 25520747Sdavidn int i = 0; 25620747Sdavidn 25720747Sdavidn while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 25820747Sdavidn ++i; 25920253Sjoerg#if debugging 26020747Sdavidn if (i == _UC_FIELDS) 26120747Sdavidn printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 26220747Sdavidn else 26320747Sdavidn printf("Got kwd[%s]=%s\n", p, q); 26420253Sjoerg#endif 26520747Sdavidn switch (i) { 26620747Sdavidn case _UC_DEFAULTPWD: 26720747Sdavidn config.default_password = boolean_val(q, 1); 26820747Sdavidn break; 26920747Sdavidn case _UC_REUSEUID: 27020747Sdavidn config.reuse_uids = boolean_val(q, 0); 27120747Sdavidn break; 27220747Sdavidn case _UC_REUSEGID: 27320747Sdavidn config.reuse_gids = boolean_val(q, 0); 27420747Sdavidn break; 27521330Sdavidn case _UC_NISPASSWD: 27621330Sdavidn config.nispasswd = (q == NULL || !boolean_val(q, 1)) 27721330Sdavidn ? NULL : newstr(q); 27821330Sdavidn break; 27920747Sdavidn case _UC_DOTDIR: 28020747Sdavidn config.dotdir = (q == NULL || !boolean_val(q, 1)) 28120747Sdavidn ? NULL : newstr(q); 28220747Sdavidn break; 28320747Sdavidn case _UC_NEWMAIL: 28420747Sdavidn config.newmail = (q == NULL || !boolean_val(q, 1)) 28520747Sdavidn ? NULL : newstr(q); 28620747Sdavidn break; 28720747Sdavidn case _UC_LOGFILE: 28820747Sdavidn config.logfile = (q == NULL || !boolean_val(q, 1)) 28920747Sdavidn ? NULL : newstr(q); 29020747Sdavidn break; 29120747Sdavidn case _UC_HOMEROOT: 29220747Sdavidn config.home = (q == NULL || !boolean_val(q, 1)) 29320747Sdavidn ? "/home" : newstr(q); 29420747Sdavidn break; 29520747Sdavidn case _UC_SHELLPATH: 29620747Sdavidn config.shelldir = (q == NULL || !boolean_val(q, 1)) 29720747Sdavidn ? "/bin" : newstr(q); 29820747Sdavidn break; 29920747Sdavidn case _UC_SHELLS: 30020747Sdavidn for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 30120747Sdavidn system_shells[i] = newstr(q); 30220747Sdavidn if (i > 0) 30320747Sdavidn while (i < _UC_MAXSHELLS) 30420747Sdavidn system_shells[i++] = NULL; 30520747Sdavidn break; 30620747Sdavidn case _UC_DEFAULTSHELL: 30720747Sdavidn config.shell_default = (q == NULL || !boolean_val(q, 1)) 30820747Sdavidn ? (char *) bourne_shell : newstr(q); 30920747Sdavidn break; 31020747Sdavidn case _UC_DEFAULTGROUP: 31129002Sdavidn q = unquote(q); 31244229Sdavidn config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 31320747Sdavidn ? NULL : newstr(q); 31420747Sdavidn break; 31520747Sdavidn case _UC_EXTRAGROUPS: 31620747Sdavidn for (i = 0; q != NULL; q = strtok(NULL, toks)) { 31720747Sdavidn if (extendarray(&config.groups, &config.numgroups, i + 2) != -1) 31820747Sdavidn config.groups[i++] = newstr(q); 31920253Sjoerg } 32020747Sdavidn if (i > 0) 32120747Sdavidn while (i < config.numgroups) 32220747Sdavidn config.groups[i++] = NULL; 32320747Sdavidn break; 32420747Sdavidn case _UC_DEFAULTCLASS: 32520747Sdavidn config.default_class = (q == NULL || !boolean_val(q, 1)) 32620747Sdavidn ? NULL : newstr(q); 32720747Sdavidn break; 32820747Sdavidn case _UC_MINUID: 32920747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33020747Sdavidn config.min_uid = (uid_t) atol(q); 33120747Sdavidn break; 33220747Sdavidn case _UC_MAXUID: 33320747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33420747Sdavidn config.max_uid = (uid_t) atol(q); 33520747Sdavidn break; 33620747Sdavidn case _UC_MINGID: 33720747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 33820747Sdavidn config.min_gid = (gid_t) atol(q); 33920747Sdavidn break; 34020747Sdavidn case _UC_MAXGID: 34120747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34220747Sdavidn config.max_gid = (gid_t) atol(q); 34320747Sdavidn break; 34420747Sdavidn case _UC_EXPIRE: 34520747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34620747Sdavidn config.expire_days = atoi(q); 34720747Sdavidn break; 34820747Sdavidn case _UC_PASSWORD: 34920747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 35020747Sdavidn config.password_days = atoi(q); 35120747Sdavidn break; 35220747Sdavidn case _UC_FIELDS: 35320747Sdavidn case _UC_NONE: 35420747Sdavidn break; 35520253Sjoerg } 35620253Sjoerg } 35720253Sjoerg } 35820747Sdavidn free(buf); 35920253Sjoerg fclose(fp); 36020253Sjoerg } 36120253Sjoerg return &config; 36220253Sjoerg} 36320253Sjoerg 36420253Sjoerg 36520253Sjoergint 36620253Sjoergwrite_userconfig(char const * file) 36720253Sjoerg{ 36820253Sjoerg int fd; 36920253Sjoerg 37020253Sjoerg if (file == NULL) 37120253Sjoerg file = _PATH_PW_CONF; 37220253Sjoerg 37320253Sjoerg if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { 37420253Sjoerg FILE *fp; 37520253Sjoerg 37620253Sjoerg if ((fp = fdopen(fd, "w")) == NULL) 37720253Sjoerg close(fd); 37820253Sjoerg else { 37920253Sjoerg int i, j, k; 38020747Sdavidn int len = LNBUFSZ; 38120747Sdavidn char *buf = malloc(len); 38220253Sjoerg 38320253Sjoerg for (i = _UC_NONE; i < _UC_FIELDS; i++) { 38420253Sjoerg int quote = 1; 38520253Sjoerg char const *val = buf; 38620253Sjoerg 38720253Sjoerg *buf = '\0'; 38820253Sjoerg switch (i) { 38920253Sjoerg case _UC_DEFAULTPWD: 39020253Sjoerg val = boolean_str(config.default_password); 39120253Sjoerg break; 39220253Sjoerg case _UC_REUSEUID: 39320253Sjoerg val = boolean_str(config.reuse_uids); 39420253Sjoerg break; 39520253Sjoerg case _UC_REUSEGID: 39620253Sjoerg val = boolean_str(config.reuse_gids); 39720253Sjoerg break; 39821330Sdavidn case _UC_NISPASSWD: 39921330Sdavidn val = config.nispasswd ? config.nispasswd : ""; 40021330Sdavidn quote = 0; 40121330Sdavidn break; 40220253Sjoerg case _UC_DOTDIR: 40320253Sjoerg val = config.dotdir ? config.dotdir : boolean_str(0); 40420253Sjoerg break; 40520253Sjoerg case _UC_NEWMAIL: 40620253Sjoerg val = config.newmail ? config.newmail : boolean_str(0); 40720253Sjoerg break; 40820253Sjoerg case _UC_LOGFILE: 40920253Sjoerg val = config.logfile ? config.logfile : boolean_str(0); 41020253Sjoerg break; 41120253Sjoerg case _UC_HOMEROOT: 41220253Sjoerg val = config.home; 41320253Sjoerg break; 41420253Sjoerg case _UC_SHELLPATH: 41520253Sjoerg val = config.shelldir; 41620253Sjoerg break; 41720253Sjoerg case _UC_SHELLS: 41820747Sdavidn for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) { 41920747Sdavidn char lbuf[64]; 42020747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]); 42120747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) { 42220747Sdavidn strcpy(buf + k, lbuf); 42320747Sdavidn k += l; 42420747Sdavidn } 42520747Sdavidn } 42620253Sjoerg quote = 0; 42720253Sjoerg break; 42820253Sjoerg case _UC_DEFAULTSHELL: 42920253Sjoerg val = config.shell_default ? config.shell_default : bourne_shell; 43020253Sjoerg break; 43120253Sjoerg case _UC_DEFAULTGROUP: 43220253Sjoerg val = config.default_group ? config.default_group : ""; 43320253Sjoerg break; 43420253Sjoerg case _UC_EXTRAGROUPS: 43520747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 43620747Sdavidn for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) { 43720747Sdavidn char lbuf[64]; 43820747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]); 43920747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) { 44020747Sdavidn strcpy(buf + k, lbuf); 44120747Sdavidn k += l; 44220747Sdavidn } 44320747Sdavidn } 44420253Sjoerg quote = 0; 44520253Sjoerg break; 44620253Sjoerg case _UC_DEFAULTCLASS: 44720253Sjoerg val = config.default_class ? config.default_class : ""; 44820253Sjoerg break; 44920253Sjoerg case _UC_MINUID: 45020253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_uid); 45120253Sjoerg quote = 0; 45220253Sjoerg break; 45320253Sjoerg case _UC_MAXUID: 45420253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_uid); 45520253Sjoerg quote = 0; 45620253Sjoerg break; 45720253Sjoerg case _UC_MINGID: 45820253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_gid); 45920253Sjoerg quote = 0; 46020253Sjoerg break; 46120253Sjoerg case _UC_MAXGID: 46220253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_gid); 46320253Sjoerg quote = 0; 46420253Sjoerg break; 46520253Sjoerg case _UC_EXPIRE: 46620253Sjoerg sprintf(buf, "%d", config.expire_days); 46720253Sjoerg quote = 0; 46820253Sjoerg break; 46920253Sjoerg case _UC_PASSWORD: 47020253Sjoerg sprintf(buf, "%d", config.password_days); 47120253Sjoerg quote = 0; 47220253Sjoerg break; 47320253Sjoerg case _UC_NONE: 47420253Sjoerg break; 47520253Sjoerg } 47620253Sjoerg 47720253Sjoerg if (comments[i]) 47820253Sjoerg fputs(comments[i], fp); 47920253Sjoerg 48020253Sjoerg if (*kwds[i]) { 48120253Sjoerg if (quote) 48220253Sjoerg fprintf(fp, "%s = \"%s\"\n", kwds[i], val); 48320253Sjoerg else 48420253Sjoerg fprintf(fp, "%s = %s\n", kwds[i], val); 48520253Sjoerg#if debugging 48620253Sjoerg printf("WROTE: %s = %s\n", kwds[i], val); 48720253Sjoerg#endif 48820253Sjoerg } 48920253Sjoerg } 49020747Sdavidn free(buf); 49120253Sjoerg return fclose(fp) != EOF; 49220253Sjoerg } 49320253Sjoerg } 49420253Sjoerg return 0; 49520253Sjoerg} 496