pw_conf.c revision 282697
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 282697 2015-05-09 21:53:33Z bapt $"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 32282681Sbapt#include <sys/types.h> 33282681Sbapt#include <sys/sbuf.h> 3420253Sjoerg#include <string.h> 3520253Sjoerg#include <ctype.h> 3620253Sjoerg#include <fcntl.h> 3720253Sjoerg 3820253Sjoerg#include "pw.h" 3920253Sjoerg 4020253Sjoerg#define debugging 0 4120253Sjoerg 4220253Sjoergenum { 4320253Sjoerg _UC_NONE, 4420253Sjoerg _UC_DEFAULTPWD, 4520253Sjoerg _UC_REUSEUID, 4620253Sjoerg _UC_REUSEGID, 4721330Sdavidn _UC_NISPASSWD, 4820253Sjoerg _UC_DOTDIR, 4920253Sjoerg _UC_NEWMAIL, 5020253Sjoerg _UC_LOGFILE, 5120253Sjoerg _UC_HOMEROOT, 52168044Sle _UC_HOMEMODE, 5320253Sjoerg _UC_SHELLPATH, 5420253Sjoerg _UC_SHELLS, 5520253Sjoerg _UC_DEFAULTSHELL, 5620253Sjoerg _UC_DEFAULTGROUP, 5720253Sjoerg _UC_EXTRAGROUPS, 5820253Sjoerg _UC_DEFAULTCLASS, 5920253Sjoerg _UC_MINUID, 6020253Sjoerg _UC_MAXUID, 6120253Sjoerg _UC_MINGID, 6220253Sjoerg _UC_MAXGID, 6320253Sjoerg _UC_EXPIRE, 6420253Sjoerg _UC_PASSWORD, 6520253Sjoerg _UC_FIELDS 6620253Sjoerg}; 6720253Sjoerg 6820253Sjoergstatic char bourne_shell[] = "sh"; 6920253Sjoerg 7020253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 7120253Sjoerg{ 7220253Sjoerg bourne_shell, 7363239Sdavidn "csh", 7463239Sdavidn "tcsh" 7520253Sjoerg}; 7620253Sjoerg 7720253Sjoergstatic char const *booltrue[] = 7820253Sjoerg{ 7920253Sjoerg "yes", "true", "1", "on", NULL 8020253Sjoerg}; 8120253Sjoergstatic char const *boolfalse[] = 8220253Sjoerg{ 8320253Sjoerg "no", "false", "0", "off", NULL 8420253Sjoerg}; 8520253Sjoerg 8620253Sjoergstatic struct userconf config = 8720253Sjoerg{ 8820253Sjoerg 0, /* Default password for new users? (nologin) */ 8920253Sjoerg 0, /* Reuse uids? */ 9020253Sjoerg 0, /* Reuse gids? */ 9121330Sdavidn NULL, /* NIS version of the passwd file */ 9220253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 9320253Sjoerg NULL, /* Mail to send to new accounts */ 9420253Sjoerg "/var/log/userlog", /* Where to log changes */ 9520253Sjoerg "/home", /* Where to create home directory */ 96219408Sjkim _DEF_DIRMODE, /* Home directory perms, modified by umask */ 9720253Sjoerg "/bin", /* Where shells are located */ 9820253Sjoerg system_shells, /* List of shells (first is default) */ 9920253Sjoerg bourne_shell, /* Default shell */ 10020253Sjoerg NULL, /* Default group name */ 10120747Sdavidn NULL, /* Default (additional) groups */ 10220253Sjoerg NULL, /* Default login class */ 10320253Sjoerg 1000, 32000, /* Allowed range of uids */ 10420253Sjoerg 1000, 32000, /* Allowed range of gids */ 10520253Sjoerg 0, /* Days until account expires */ 10649171Sdavidn 0, /* Days until password expires */ 10749171Sdavidn 0 /* size of default_group array */ 10820253Sjoerg}; 10920253Sjoerg 11020253Sjoergstatic char const *comments[_UC_FIELDS] = 11120253Sjoerg{ 11220253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 11320253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 11420253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 11520253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11621330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 11720253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11820253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 11920253Sjoerg "\n# Log add/change/remove information in this file\n", 12020253Sjoerg "\n# Root directory in which $HOME directory is created\n", 121168044Sle "\n# Mode for the new $HOME directory, will be modified by umask\n", 12220253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 12370133Sdougb "\n# Comma separated list of available shells (without paths)\n", 12420253Sjoerg "\n# Default shell (without path)\n", 12520253Sjoerg "\n# Default group (leave blank for new group per user)\n", 12620253Sjoerg "\n# Extra groups for new users\n", 12720253Sjoerg "\n# Default login class for new users\n", 12820253Sjoerg "\n# Range of valid default user ids\n", 12920253Sjoerg NULL, 13020253Sjoerg "\n# Range of valid default group ids\n", 13120253Sjoerg NULL, 13220253Sjoerg "\n# Days after which account expires (0=disabled)\n", 13320253Sjoerg "\n# Days after which password expires (0=disabled)\n" 13420253Sjoerg}; 13520253Sjoerg 13620253Sjoergstatic char const *kwds[] = 13720253Sjoerg{ 13820253Sjoerg "", 13920253Sjoerg "defaultpasswd", 14020253Sjoerg "reuseuids", 14120253Sjoerg "reusegids", 14221330Sdavidn "nispasswd", 14320253Sjoerg "skeleton", 14420253Sjoerg "newmail", 14520253Sjoerg "logfile", 14620253Sjoerg "home", 147168044Sle "homemode", 14820253Sjoerg "shellpath", 14920253Sjoerg "shells", 15020253Sjoerg "defaultshell", 15120253Sjoerg "defaultgroup", 15220253Sjoerg "extragroups", 15320253Sjoerg "defaultclass", 15420253Sjoerg "minuid", 15520253Sjoerg "maxuid", 15620253Sjoerg "mingid", 15720253Sjoerg "maxgid", 15820253Sjoerg "expire_days", 15920253Sjoerg "password_days", 16020253Sjoerg NULL 16120253Sjoerg}; 16220253Sjoerg 16320253Sjoergstatic char * 16420253Sjoergunquote(char const * str) 16520253Sjoerg{ 16620253Sjoerg if (str && (*str == '"' || *str == '\'')) { 16720253Sjoerg char *p = strchr(str + 1, *str); 16820253Sjoerg 16920253Sjoerg if (p != NULL) 17020253Sjoerg *p = '\0'; 17120253Sjoerg return (char *) (*++str ? str : NULL); 17220253Sjoerg } 17320253Sjoerg return (char *) str; 17420253Sjoerg} 17520253Sjoerg 17620253Sjoergint 17720253Sjoergboolean_val(char const * str, int dflt) 17820253Sjoerg{ 17920253Sjoerg if ((str = unquote(str)) != NULL) { 18020253Sjoerg int i; 18120253Sjoerg 18220253Sjoerg for (i = 0; booltrue[i]; i++) 18320253Sjoerg if (strcmp(str, booltrue[i]) == 0) 18420253Sjoerg return 1; 18520253Sjoerg for (i = 0; boolfalse[i]; i++) 18620253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 18720253Sjoerg return 0; 18820253Sjoerg 18920253Sjoerg /* 19020253Sjoerg * Special cases for defaultpassword 19120253Sjoerg */ 19220253Sjoerg if (strcmp(str, "random") == 0) 19320253Sjoerg return -1; 19420253Sjoerg if (strcmp(str, "none") == 0) 19520253Sjoerg return -2; 19620253Sjoerg } 19720253Sjoerg return dflt; 19820253Sjoerg} 19920253Sjoerg 20020253Sjoergchar const * 20120253Sjoergboolean_str(int val) 20220253Sjoerg{ 20320253Sjoerg if (val == -1) 20420253Sjoerg return "random"; 20520253Sjoerg else if (val == -2) 20620253Sjoerg return "none"; 20720253Sjoerg else 20820253Sjoerg return val ? booltrue[0] : boolfalse[0]; 20920253Sjoerg} 21020253Sjoerg 21120253Sjoergchar * 21220253Sjoergnewstr(char const * p) 21320253Sjoerg{ 21420253Sjoerg char *q = NULL; 21520253Sjoerg 21620253Sjoerg if ((p = unquote(p)) != NULL) { 21720253Sjoerg int l = strlen(p) + 1; 21820253Sjoerg 21920253Sjoerg if ((q = malloc(l)) != NULL) 22020253Sjoerg memcpy(q, p, l); 22120253Sjoerg } 22220253Sjoerg return q; 22320253Sjoerg} 22420253Sjoerg 22520747Sdavidn#define LNBUFSZ 1024 22620253Sjoerg 22720747Sdavidn 22820253Sjoergstruct userconf * 22920253Sjoergread_userconfig(char const * file) 23020253Sjoerg{ 231264781Sbapt FILE *fp; 232264781Sbapt char *buf, *p; 233264781Sbapt size_t linecap; 234264781Sbapt ssize_t linelen; 23520253Sjoerg 236264781Sbapt buf = NULL; 237264781Sbapt linecap = 0; 238264781Sbapt 23920747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 24020747Sdavidn memset(config.groups, 0, config.numgroups * sizeof(char *)); 24120253Sjoerg if (file == NULL) 24220253Sjoerg file = _PATH_PW_CONF; 243264781Sbapt 24420253Sjoerg if ((fp = fopen(file, "r")) != NULL) { 245264781Sbapt while ((linelen = getline(&buf, &linecap, fp)) > 0) { 24620747Sdavidn if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 24720747Sdavidn static char const toks[] = " \t\r\n,="; 24820747Sdavidn char *q = strtok(NULL, toks); 24920747Sdavidn int i = 0; 250168044Sle mode_t *modeset; 25120747Sdavidn 25220747Sdavidn while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 25320747Sdavidn ++i; 25420253Sjoerg#if debugging 25520747Sdavidn if (i == _UC_FIELDS) 25620747Sdavidn printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 25720747Sdavidn else 25820747Sdavidn printf("Got kwd[%s]=%s\n", p, q); 25920253Sjoerg#endif 26020747Sdavidn switch (i) { 26120747Sdavidn case _UC_DEFAULTPWD: 26220747Sdavidn config.default_password = boolean_val(q, 1); 26320747Sdavidn break; 26420747Sdavidn case _UC_REUSEUID: 26520747Sdavidn config.reuse_uids = boolean_val(q, 0); 26620747Sdavidn break; 26720747Sdavidn case _UC_REUSEGID: 26820747Sdavidn config.reuse_gids = boolean_val(q, 0); 26920747Sdavidn break; 27021330Sdavidn case _UC_NISPASSWD: 27121330Sdavidn config.nispasswd = (q == NULL || !boolean_val(q, 1)) 27221330Sdavidn ? NULL : newstr(q); 27321330Sdavidn break; 27420747Sdavidn case _UC_DOTDIR: 27520747Sdavidn config.dotdir = (q == NULL || !boolean_val(q, 1)) 27620747Sdavidn ? NULL : newstr(q); 27720747Sdavidn break; 27820747Sdavidn case _UC_NEWMAIL: 27920747Sdavidn config.newmail = (q == NULL || !boolean_val(q, 1)) 28020747Sdavidn ? NULL : newstr(q); 28120747Sdavidn break; 28220747Sdavidn case _UC_LOGFILE: 28320747Sdavidn config.logfile = (q == NULL || !boolean_val(q, 1)) 28420747Sdavidn ? NULL : newstr(q); 28520747Sdavidn break; 28620747Sdavidn case _UC_HOMEROOT: 28720747Sdavidn config.home = (q == NULL || !boolean_val(q, 1)) 28820747Sdavidn ? "/home" : newstr(q); 28920747Sdavidn break; 290168044Sle case _UC_HOMEMODE: 291168044Sle modeset = setmode(q); 292168044Sle config.homemode = (q == NULL || !boolean_val(q, 1)) 293219408Sjkim ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE); 294168044Sle free(modeset); 295168044Sle 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 } 359264781Sbapt if (linecap > 0) 360264781Sbapt free(buf); 36120253Sjoerg fclose(fp); 36220253Sjoerg } 36320253Sjoerg return &config; 36420253Sjoerg} 36520253Sjoerg 36620253Sjoerg 36720253Sjoergint 36820253Sjoergwrite_userconfig(char const * file) 36920253Sjoerg{ 37020253Sjoerg int fd; 371282697Sbapt int i, j; 372282681Sbapt struct sbuf *buf; 373282697Sbapt FILE *fp; 37420253Sjoerg 37520253Sjoerg if (file == NULL) 37620253Sjoerg file = _PATH_PW_CONF; 37720253Sjoerg 378282697Sbapt if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1) 379282697Sbapt return (0); 38020253Sjoerg 381282697Sbapt if ((fp = fdopen(fd, "w")) == NULL) { 382282697Sbapt close(fd); 383282697Sbapt return (0); 384282697Sbapt } 385282681Sbapt 386282697Sbapt buf = sbuf_new_auto(); 387282697Sbapt for (i = _UC_NONE; i < _UC_FIELDS; i++) { 388282697Sbapt int quote = 1; 38920253Sjoerg 390282697Sbapt sbuf_clear(buf); 391282697Sbapt switch (i) { 392282697Sbapt case _UC_DEFAULTPWD: 393282697Sbapt sbuf_cat(buf, boolean_str(config.default_password)); 394282697Sbapt break; 395282697Sbapt case _UC_REUSEUID: 396282697Sbapt sbuf_cat(buf, boolean_str(config.reuse_uids)); 397282697Sbapt break; 398282697Sbapt case _UC_REUSEGID: 399282697Sbapt sbuf_cat(buf, boolean_str(config.reuse_gids)); 400282697Sbapt break; 401282697Sbapt case _UC_NISPASSWD: 402282697Sbapt sbuf_cat(buf, config.nispasswd ? config.nispasswd : 403282697Sbapt ""); 404282697Sbapt quote = 0; 405282697Sbapt break; 406282697Sbapt case _UC_DOTDIR: 407282697Sbapt sbuf_cat(buf, config.dotdir ? config.dotdir : 408282697Sbapt boolean_str(0)); 409282697Sbapt break; 410282697Sbapt case _UC_NEWMAIL: 411282697Sbapt sbuf_cat(buf, config.newmail ? config.newmail : 412282697Sbapt boolean_str(0)); 413282697Sbapt break; 414282697Sbapt case _UC_LOGFILE: 415282697Sbapt sbuf_cat(buf, config.logfile ? config.logfile : 416282697Sbapt boolean_str(0)); 417282697Sbapt break; 418282697Sbapt case _UC_HOMEROOT: 419282697Sbapt sbuf_cat(buf, config.home); 420282697Sbapt break; 421282697Sbapt case _UC_HOMEMODE: 422282697Sbapt sbuf_printf(buf, "%04o", config.homemode); 423282697Sbapt quote = 0; 424282697Sbapt break; 425282697Sbapt case _UC_SHELLPATH: 426282697Sbapt sbuf_cat(buf, config.shelldir); 427282697Sbapt break; 428282697Sbapt case _UC_SHELLS: 429282697Sbapt for (j = 0; j < _UC_MAXSHELLS && 430282697Sbapt system_shells[j] != NULL; j++) 431282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 432282697Sbapt "," : "", system_shells[j]); 433282697Sbapt quote = 0; 434282697Sbapt break; 435282697Sbapt case _UC_DEFAULTSHELL: 436282697Sbapt sbuf_cat(buf, config.shell_default ? 437282697Sbapt config.shell_default : bourne_shell); 438282697Sbapt break; 439282697Sbapt case _UC_DEFAULTGROUP: 440282697Sbapt sbuf_cat(buf, config.default_group ? 441282697Sbapt config.default_group : ""); 442282697Sbapt break; 443282697Sbapt case _UC_EXTRAGROUPS: 444282697Sbapt extendarray(&config.groups, &config.numgroups, 200); 445282697Sbapt for (j = 0; j < config.numgroups && 446282697Sbapt config.groups[j] != NULL; j++) 447282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 448282697Sbapt "," : "", config.groups[j]); 449282697Sbapt quote = 0; 450282697Sbapt break; 451282697Sbapt case _UC_DEFAULTCLASS: 452282697Sbapt sbuf_cat(buf, config.default_class ? 453282697Sbapt config.default_class : ""); 454282697Sbapt break; 455282697Sbapt case _UC_MINUID: 456282697Sbapt sbuf_printf(buf, "%lu", (unsigned long) config.min_uid); 457282697Sbapt quote = 0; 458282697Sbapt break; 459282697Sbapt case _UC_MAXUID: 460282697Sbapt sbuf_printf(buf, "%lu", (unsigned long) config.max_uid); 461282697Sbapt quote = 0; 462282697Sbapt break; 463282697Sbapt case _UC_MINGID: 464282697Sbapt sbuf_printf(buf, "%lu", (unsigned long) config.min_gid); 465282697Sbapt quote = 0; 466282697Sbapt break; 467282697Sbapt case _UC_MAXGID: 468282697Sbapt sbuf_printf(buf, "%lu", (unsigned long) config.max_gid); 469282697Sbapt quote = 0; 470282697Sbapt break; 471282697Sbapt case _UC_EXPIRE: 472282697Sbapt sbuf_printf(buf, "%d", config.expire_days); 473282697Sbapt quote = 0; 474282697Sbapt break; 475282697Sbapt case _UC_PASSWORD: 476282697Sbapt sbuf_printf(buf, "%d", config.password_days); 477282697Sbapt quote = 0; 478282697Sbapt break; 479282697Sbapt case _UC_NONE: 480282697Sbapt break; 481282697Sbapt } 482282697Sbapt sbuf_finish(buf); 48320253Sjoerg 484282697Sbapt if (comments[i]) 485282697Sbapt fputs(comments[i], fp); 48620253Sjoerg 487282697Sbapt if (*kwds[i]) { 488282697Sbapt if (quote) 489282697Sbapt fprintf(fp, "%s = \"%s\"\n", kwds[i], 490282697Sbapt sbuf_data(buf)); 491282697Sbapt else 492282697Sbapt fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf)); 49320253Sjoerg#if debugging 494282697Sbapt printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf)); 49520253Sjoerg#endif 49620253Sjoerg } 49720253Sjoerg } 498282697Sbapt sbuf_delete(buf); 499282697Sbapt return (fclose(fp) != EOF); 50020253Sjoerg} 501