pw_conf.c revision 286196
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 286196 2015-08-02 12:47:50Z bapt $"; 3030259Scharnier#endif /* not lint */ 3130259Scharnier 32282681Sbapt#include <sys/types.h> 33282681Sbapt#include <sys/sbuf.h> 34286150Sbapt#include <inttypes.h> 3520253Sjoerg#include <string.h> 3620253Sjoerg#include <ctype.h> 3720253Sjoerg#include <fcntl.h> 38282718Sbapt#include <err.h> 3920253Sjoerg 4020253Sjoerg#include "pw.h" 4120253Sjoerg 4220253Sjoerg#define debugging 0 4320253Sjoerg 4420253Sjoergenum { 4520253Sjoerg _UC_NONE, 4620253Sjoerg _UC_DEFAULTPWD, 4720253Sjoerg _UC_REUSEUID, 4820253Sjoerg _UC_REUSEGID, 4921330Sdavidn _UC_NISPASSWD, 5020253Sjoerg _UC_DOTDIR, 5120253Sjoerg _UC_NEWMAIL, 5220253Sjoerg _UC_LOGFILE, 5320253Sjoerg _UC_HOMEROOT, 54168044Sle _UC_HOMEMODE, 5520253Sjoerg _UC_SHELLPATH, 5620253Sjoerg _UC_SHELLS, 5720253Sjoerg _UC_DEFAULTSHELL, 5820253Sjoerg _UC_DEFAULTGROUP, 5920253Sjoerg _UC_EXTRAGROUPS, 6020253Sjoerg _UC_DEFAULTCLASS, 6120253Sjoerg _UC_MINUID, 6220253Sjoerg _UC_MAXUID, 6320253Sjoerg _UC_MINGID, 6420253Sjoerg _UC_MAXGID, 6520253Sjoerg _UC_EXPIRE, 6620253Sjoerg _UC_PASSWORD, 6720253Sjoerg _UC_FIELDS 6820253Sjoerg}; 6920253Sjoerg 7020253Sjoergstatic char bourne_shell[] = "sh"; 7120253Sjoerg 7220253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 7320253Sjoerg{ 7420253Sjoerg bourne_shell, 7563239Sdavidn "csh", 7663239Sdavidn "tcsh" 7720253Sjoerg}; 7820253Sjoerg 7920253Sjoergstatic char const *booltrue[] = 8020253Sjoerg{ 8120253Sjoerg "yes", "true", "1", "on", NULL 8220253Sjoerg}; 8320253Sjoergstatic char const *boolfalse[] = 8420253Sjoerg{ 8520253Sjoerg "no", "false", "0", "off", NULL 8620253Sjoerg}; 8720253Sjoerg 8820253Sjoergstatic struct userconf config = 8920253Sjoerg{ 9020253Sjoerg 0, /* Default password for new users? (nologin) */ 9120253Sjoerg 0, /* Reuse uids? */ 9220253Sjoerg 0, /* Reuse gids? */ 9321330Sdavidn NULL, /* NIS version of the passwd file */ 9420253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 9520253Sjoerg NULL, /* Mail to send to new accounts */ 9620253Sjoerg "/var/log/userlog", /* Where to log changes */ 9720253Sjoerg "/home", /* Where to create home directory */ 98219408Sjkim _DEF_DIRMODE, /* Home directory perms, modified by umask */ 9920253Sjoerg "/bin", /* Where shells are located */ 10020253Sjoerg system_shells, /* List of shells (first is default) */ 10120253Sjoerg bourne_shell, /* Default shell */ 10220253Sjoerg NULL, /* Default group name */ 10320747Sdavidn NULL, /* Default (additional) groups */ 10420253Sjoerg NULL, /* Default login class */ 10520253Sjoerg 1000, 32000, /* Allowed range of uids */ 10620253Sjoerg 1000, 32000, /* Allowed range of gids */ 10720253Sjoerg 0, /* Days until account expires */ 108285412Sbapt 0 /* Days until password expires */ 10920253Sjoerg}; 11020253Sjoerg 11120253Sjoergstatic char const *comments[_UC_FIELDS] = 11220253Sjoerg{ 11320253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 11420253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 11520253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 11620253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11721330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 11820253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11920253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 12020253Sjoerg "\n# Log add/change/remove information in this file\n", 12120253Sjoerg "\n# Root directory in which $HOME directory is created\n", 122168044Sle "\n# Mode for the new $HOME directory, will be modified by umask\n", 12320253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 12470133Sdougb "\n# Comma separated list of available shells (without paths)\n", 12520253Sjoerg "\n# Default shell (without path)\n", 12620253Sjoerg "\n# Default group (leave blank for new group per user)\n", 12720253Sjoerg "\n# Extra groups for new users\n", 12820253Sjoerg "\n# Default login class for new users\n", 12920253Sjoerg "\n# Range of valid default user ids\n", 13020253Sjoerg NULL, 13120253Sjoerg "\n# Range of valid default group ids\n", 13220253Sjoerg NULL, 13320253Sjoerg "\n# Days after which account expires (0=disabled)\n", 13420253Sjoerg "\n# Days after which password expires (0=disabled)\n" 13520253Sjoerg}; 13620253Sjoerg 13720253Sjoergstatic char const *kwds[] = 13820253Sjoerg{ 13920253Sjoerg "", 14020253Sjoerg "defaultpasswd", 14120253Sjoerg "reuseuids", 14220253Sjoerg "reusegids", 14321330Sdavidn "nispasswd", 14420253Sjoerg "skeleton", 14520253Sjoerg "newmail", 14620253Sjoerg "logfile", 14720253Sjoerg "home", 148168044Sle "homemode", 14920253Sjoerg "shellpath", 15020253Sjoerg "shells", 15120253Sjoerg "defaultshell", 15220253Sjoerg "defaultgroup", 15320253Sjoerg "extragroups", 15420253Sjoerg "defaultclass", 15520253Sjoerg "minuid", 15620253Sjoerg "maxuid", 15720253Sjoerg "mingid", 15820253Sjoerg "maxgid", 15920253Sjoerg "expire_days", 16020253Sjoerg "password_days", 16120253Sjoerg NULL 16220253Sjoerg}; 16320253Sjoerg 16420253Sjoergstatic char * 16520253Sjoergunquote(char const * str) 16620253Sjoerg{ 16720253Sjoerg if (str && (*str == '"' || *str == '\'')) { 16820253Sjoerg char *p = strchr(str + 1, *str); 16920253Sjoerg 17020253Sjoerg if (p != NULL) 17120253Sjoerg *p = '\0'; 17220253Sjoerg return (char *) (*++str ? str : NULL); 17320253Sjoerg } 17420253Sjoerg return (char *) str; 17520253Sjoerg} 17620253Sjoerg 17720253Sjoergint 17820253Sjoergboolean_val(char const * str, int dflt) 17920253Sjoerg{ 18020253Sjoerg if ((str = unquote(str)) != NULL) { 18120253Sjoerg int i; 18220253Sjoerg 18320253Sjoerg for (i = 0; booltrue[i]; i++) 18420253Sjoerg if (strcmp(str, booltrue[i]) == 0) 18520253Sjoerg return 1; 18620253Sjoerg for (i = 0; boolfalse[i]; i++) 18720253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 18820253Sjoerg return 0; 18920253Sjoerg 19020253Sjoerg /* 19120253Sjoerg * Special cases for defaultpassword 19220253Sjoerg */ 19320253Sjoerg if (strcmp(str, "random") == 0) 19420253Sjoerg return -1; 19520253Sjoerg if (strcmp(str, "none") == 0) 19620253Sjoerg return -2; 19720253Sjoerg } 19820253Sjoerg return dflt; 19920253Sjoerg} 20020253Sjoerg 20120253Sjoergchar const * 20220253Sjoergboolean_str(int val) 20320253Sjoerg{ 20420253Sjoerg if (val == -1) 20520253Sjoerg return "random"; 20620253Sjoerg else if (val == -2) 20720253Sjoerg return "none"; 20820253Sjoerg else 20920253Sjoerg return val ? booltrue[0] : boolfalse[0]; 21020253Sjoerg} 21120253Sjoerg 21220253Sjoergchar * 21320253Sjoergnewstr(char const * p) 21420253Sjoerg{ 215282718Sbapt char *q; 21620253Sjoerg 217282718Sbapt if ((p = unquote(p)) == NULL) 218282718Sbapt return (NULL); 21920253Sjoerg 220282719Sbapt if ((q = strdup(p)) == NULL) 221282719Sbapt err(1, "strdup()"); 222282718Sbapt 223282718Sbapt return (q); 22420253Sjoerg} 22520253Sjoerg 22620253Sjoergstruct userconf * 22720253Sjoergread_userconfig(char const * file) 22820253Sjoerg{ 229264781Sbapt FILE *fp; 230264781Sbapt char *buf, *p; 231286154Sbapt const char *errstr; 232264781Sbapt size_t linecap; 233264781Sbapt ssize_t linelen; 23420253Sjoerg 235264781Sbapt buf = NULL; 236264781Sbapt linecap = 0; 237264781Sbapt 23820253Sjoerg if (file == NULL) 23920253Sjoerg file = _PATH_PW_CONF; 240264781Sbapt 241283815Sbapt if ((fp = fopen(file, "r")) == NULL) 242283815Sbapt return (&config); 24320747Sdavidn 244283815Sbapt while ((linelen = getline(&buf, &linecap, fp)) > 0) { 245283815Sbapt if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 246283815Sbapt static char const toks[] = " \t\r\n,="; 247283815Sbapt char *q = strtok(NULL, toks); 248283815Sbapt int i = 0; 249283815Sbapt mode_t *modeset; 250283815Sbapt 251283815Sbapt while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 252283815Sbapt ++i; 25320253Sjoerg#if debugging 254283815Sbapt if (i == _UC_FIELDS) 255283815Sbapt printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 256283815Sbapt else 257283815Sbapt printf("Got kwd[%s]=%s\n", p, q); 25820253Sjoerg#endif 259283815Sbapt switch (i) { 260283815Sbapt case _UC_DEFAULTPWD: 261283815Sbapt config.default_password = boolean_val(q, 1); 262283815Sbapt break; 263283815Sbapt case _UC_REUSEUID: 264283815Sbapt config.reuse_uids = boolean_val(q, 0); 265283815Sbapt break; 266283815Sbapt case _UC_REUSEGID: 267283815Sbapt config.reuse_gids = boolean_val(q, 0); 268283815Sbapt break; 269283815Sbapt case _UC_NISPASSWD: 270283815Sbapt config.nispasswd = (q == NULL || !boolean_val(q, 1)) 271283815Sbapt ? NULL : newstr(q); 272283815Sbapt break; 273283815Sbapt case _UC_DOTDIR: 274283815Sbapt config.dotdir = (q == NULL || !boolean_val(q, 1)) 275283815Sbapt ? NULL : newstr(q); 276283815Sbapt break; 27720747Sdavidn case _UC_NEWMAIL: 278283815Sbapt config.newmail = (q == NULL || !boolean_val(q, 1)) 279283815Sbapt ? NULL : newstr(q); 280283815Sbapt break; 281283815Sbapt case _UC_LOGFILE: 282283815Sbapt config.logfile = (q == NULL || !boolean_val(q, 1)) 283283815Sbapt ? NULL : newstr(q); 284283815Sbapt break; 285283815Sbapt case _UC_HOMEROOT: 286283815Sbapt config.home = (q == NULL || !boolean_val(q, 1)) 287283815Sbapt ? "/home" : newstr(q); 288283815Sbapt break; 289283815Sbapt case _UC_HOMEMODE: 290283815Sbapt modeset = setmode(q); 291283815Sbapt config.homemode = (q == NULL || !boolean_val(q, 1)) 292283815Sbapt ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE); 293283815Sbapt free(modeset); 294283815Sbapt break; 295283815Sbapt case _UC_SHELLPATH: 296283815Sbapt config.shelldir = (q == NULL || !boolean_val(q, 1)) 297283815Sbapt ? "/bin" : newstr(q); 298283815Sbapt break; 299283815Sbapt case _UC_SHELLS: 300283815Sbapt for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 301283815Sbapt system_shells[i] = newstr(q); 302283815Sbapt if (i > 0) 303283815Sbapt while (i < _UC_MAXSHELLS) 304283815Sbapt system_shells[i++] = NULL; 305283815Sbapt break; 306283815Sbapt case _UC_DEFAULTSHELL: 307283815Sbapt config.shell_default = (q == NULL || !boolean_val(q, 1)) 308283815Sbapt ? (char *) bourne_shell : newstr(q); 309283815Sbapt break; 310283815Sbapt case _UC_DEFAULTGROUP: 311283815Sbapt q = unquote(q); 312283815Sbapt config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 313283815Sbapt ? NULL : newstr(q); 314283815Sbapt break; 315283815Sbapt case _UC_EXTRAGROUPS: 316286196Sbapt for (i = 0; q != NULL; q = strtok(NULL, toks)) { 317286196Sbapt if (config.groups == NULL) 318286196Sbapt config.groups = sl_init(); 319285412Sbapt sl_add(config.groups, newstr(q)); 320286196Sbapt } 321283815Sbapt break; 322283815Sbapt case _UC_DEFAULTCLASS: 323283815Sbapt config.default_class = (q == NULL || !boolean_val(q, 1)) 324283815Sbapt ? NULL : newstr(q); 325283815Sbapt break; 326283815Sbapt case _UC_MINUID: 327286151Sbapt if ((q = unquote(q)) != NULL) { 328286154Sbapt config.min_uid = strtounum(q, 0, 329286154Sbapt UID_MAX, &errstr); 330286151Sbapt if (errstr) 331286154Sbapt warnx("Invalid min_uid: '%s';" 332286154Sbapt " ignoring", q); 333286151Sbapt } 334283815Sbapt break; 335283815Sbapt case _UC_MAXUID: 336286151Sbapt if ((q = unquote(q)) != NULL) { 337286154Sbapt config.max_uid = strtounum(q, 0, 338286154Sbapt UID_MAX, &errstr); 339286151Sbapt if (errstr) 340286154Sbapt warnx("Invalid max_uid: '%s';" 341286154Sbapt " ignoring", q); 342286151Sbapt } 343283815Sbapt break; 344283815Sbapt case _UC_MINGID: 345286154Sbapt if ((q = unquote(q)) != NULL) { 346286154Sbapt config.min_gid = strtounum(q, 0, 347286154Sbapt GID_MAX, &errstr); 348286151Sbapt if (errstr) 349286154Sbapt warnx("Invalid min_gid: '%s';" 350286154Sbapt " ignoring", q); 351286155Sbapt } 352283815Sbapt break; 353283815Sbapt case _UC_MAXGID: 354286151Sbapt if ((q = unquote(q)) != NULL) { 355286154Sbapt config.max_gid = strtounum(q, 0, 356286154Sbapt GID_MAX, &errstr); 357286151Sbapt if (errstr) 358286154Sbapt warnx("Invalid max_gid: '%s';" 359286154Sbapt " ignoring", q); 360286151Sbapt } 361283815Sbapt break; 362283815Sbapt case _UC_EXPIRE: 363286152Sbapt if ((q = unquote(q)) != NULL) { 364286154Sbapt config.expire_days = strtonum(q, 0, 365286154Sbapt INT_MAX, &errstr); 366286152Sbapt if (errstr) 367286154Sbapt warnx("Invalid expire days:" 368286154Sbapt " '%s'; ignoring", q); 369286152Sbapt } 370283815Sbapt break; 371283815Sbapt case _UC_PASSWORD: 372286152Sbapt if ((q = unquote(q)) != NULL) { 373286154Sbapt config.password_days = strtonum(q, 0, 374286154Sbapt INT_MAX, &errstr); 375286152Sbapt if (errstr) 376286154Sbapt warnx("Invalid password days:" 377286154Sbapt " '%s'; ignoring", q); 378286152Sbapt } 379283815Sbapt break; 380283815Sbapt case _UC_FIELDS: 381283815Sbapt case _UC_NONE: 382283815Sbapt break; 38320253Sjoerg } 38420253Sjoerg } 38520253Sjoerg } 386283818Sbapt free(buf); 387283818Sbapt fclose(fp); 388283818Sbapt 389283815Sbapt return (&config); 39020253Sjoerg} 39120253Sjoerg 39220253Sjoerg 39320253Sjoergint 394286196Sbaptwrite_userconfig(struct userconf *cnf, const char *file) 39520253Sjoerg{ 39620253Sjoerg int fd; 397282697Sbapt int i, j; 398282681Sbapt struct sbuf *buf; 399282697Sbapt FILE *fp; 40020253Sjoerg 40120253Sjoerg if (file == NULL) 40220253Sjoerg file = _PATH_PW_CONF; 40320253Sjoerg 404282697Sbapt if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1) 405282697Sbapt return (0); 40620253Sjoerg 407282697Sbapt if ((fp = fdopen(fd, "w")) == NULL) { 408282697Sbapt close(fd); 409282697Sbapt return (0); 410282697Sbapt } 411282681Sbapt 412282697Sbapt buf = sbuf_new_auto(); 413282697Sbapt for (i = _UC_NONE; i < _UC_FIELDS; i++) { 414282697Sbapt int quote = 1; 41520253Sjoerg 416282697Sbapt sbuf_clear(buf); 417282697Sbapt switch (i) { 418282697Sbapt case _UC_DEFAULTPWD: 419286196Sbapt sbuf_cat(buf, boolean_str(cnf->default_password)); 420282697Sbapt break; 421282697Sbapt case _UC_REUSEUID: 422286196Sbapt sbuf_cat(buf, boolean_str(cnf->reuse_uids)); 423282697Sbapt break; 424282697Sbapt case _UC_REUSEGID: 425286196Sbapt sbuf_cat(buf, boolean_str(cnf->reuse_gids)); 426282697Sbapt break; 427282697Sbapt case _UC_NISPASSWD: 428286196Sbapt sbuf_cat(buf, cnf->nispasswd ? cnf->nispasswd : ""); 429282697Sbapt quote = 0; 430282697Sbapt break; 431282697Sbapt case _UC_DOTDIR: 432286196Sbapt sbuf_cat(buf, cnf->dotdir ? cnf->dotdir : 433282697Sbapt boolean_str(0)); 434282697Sbapt break; 435282697Sbapt case _UC_NEWMAIL: 436286196Sbapt sbuf_cat(buf, cnf->newmail ? cnf->newmail : 437282697Sbapt boolean_str(0)); 438282697Sbapt break; 439282697Sbapt case _UC_LOGFILE: 440286196Sbapt sbuf_cat(buf, cnf->logfile ? cnf->logfile : 441282697Sbapt boolean_str(0)); 442282697Sbapt break; 443282697Sbapt case _UC_HOMEROOT: 444286196Sbapt sbuf_cat(buf, cnf->home); 445282697Sbapt break; 446282697Sbapt case _UC_HOMEMODE: 447286196Sbapt sbuf_printf(buf, "%04o", cnf->homemode); 448282697Sbapt quote = 0; 449282697Sbapt break; 450282697Sbapt case _UC_SHELLPATH: 451286196Sbapt sbuf_cat(buf, cnf->shelldir); 452282697Sbapt break; 453282697Sbapt case _UC_SHELLS: 454282697Sbapt for (j = 0; j < _UC_MAXSHELLS && 455282697Sbapt system_shells[j] != NULL; j++) 456282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 457282697Sbapt "," : "", system_shells[j]); 458282697Sbapt quote = 0; 459282697Sbapt break; 460282697Sbapt case _UC_DEFAULTSHELL: 461286196Sbapt sbuf_cat(buf, cnf->shell_default ? 462286196Sbapt cnf->shell_default : bourne_shell); 463282697Sbapt break; 464282697Sbapt case _UC_DEFAULTGROUP: 465286196Sbapt sbuf_cat(buf, cnf->default_group ? 466286196Sbapt cnf->default_group : ""); 467282697Sbapt break; 468282697Sbapt case _UC_EXTRAGROUPS: 469286196Sbapt for (j = 0; cnf->groups != NULL && 470286196Sbapt j < (int)cnf->groups->sl_cur; j++) 471282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 472286196Sbapt "," : "", cnf->groups->sl_str[j]); 473282697Sbapt quote = 0; 474282697Sbapt break; 475282697Sbapt case _UC_DEFAULTCLASS: 476286196Sbapt sbuf_cat(buf, cnf->default_class ? 477286196Sbapt cnf->default_class : ""); 478282697Sbapt break; 479282697Sbapt case _UC_MINUID: 480286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_uid); 481282697Sbapt quote = 0; 482282697Sbapt break; 483282697Sbapt case _UC_MAXUID: 484286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_uid); 485282697Sbapt quote = 0; 486282697Sbapt break; 487282697Sbapt case _UC_MINGID: 488286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_gid); 489282697Sbapt quote = 0; 490282697Sbapt break; 491282697Sbapt case _UC_MAXGID: 492286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_gid); 493282697Sbapt quote = 0; 494282697Sbapt break; 495282697Sbapt case _UC_EXPIRE: 496286196Sbapt sbuf_printf(buf, "%ld", cnf->expire_days); 497282697Sbapt quote = 0; 498282697Sbapt break; 499282697Sbapt case _UC_PASSWORD: 500286196Sbapt sbuf_printf(buf, "%ld", cnf->password_days); 501282697Sbapt quote = 0; 502282697Sbapt break; 503282697Sbapt case _UC_NONE: 504282697Sbapt break; 505282697Sbapt } 506282697Sbapt sbuf_finish(buf); 50720253Sjoerg 508282697Sbapt if (comments[i]) 509282697Sbapt fputs(comments[i], fp); 51020253Sjoerg 511282697Sbapt if (*kwds[i]) { 512282697Sbapt if (quote) 513282697Sbapt fprintf(fp, "%s = \"%s\"\n", kwds[i], 514282697Sbapt sbuf_data(buf)); 515282697Sbapt else 516282697Sbapt fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf)); 51720253Sjoerg#if debugging 518282697Sbapt printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf)); 51920253Sjoerg#endif 52020253Sjoerg } 52120253Sjoerg } 522282697Sbapt sbuf_delete(buf); 523282697Sbapt return (fclose(fp) != EOF); 52420253Sjoerg} 525