120253Sjoerg/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 420302Sjoerg * Copyright (C) 1996 520302Sjoerg * David L. Nugent. All rights reserved. 620253Sjoerg * 720253Sjoerg * Redistribution and use in source and binary forms, with or without 820253Sjoerg * modification, are permitted provided that the following conditions 920253Sjoerg * are met: 1020253Sjoerg * 1. Redistributions of source code must retain the above copyright 1120302Sjoerg * notice, this list of conditions and the following disclaimer. 1220253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1320253Sjoerg * notice, this list of conditions and the following disclaimer in the 1420253Sjoerg * documentation and/or other materials provided with the distribution. 1520253Sjoerg * 1620302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND 1720253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1820253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1920302Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE 2020253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2120253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2220253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2320253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2420253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2520253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2620253Sjoerg * SUCH DAMAGE. 2720253Sjoerg */ 2820253Sjoerg 2930259Scharnier#ifndef lint 3030259Scharnierstatic const char rcsid[] = 3150479Speter "$FreeBSD: stable/11/usr.sbin/pw/pw_conf.c 330449 2018-03-05 07:26:05Z eadler $"; 3230259Scharnier#endif /* not lint */ 3330259Scharnier 34282681Sbapt#include <sys/types.h> 35282681Sbapt#include <sys/sbuf.h> 36286201Sbapt 37286201Sbapt#include <err.h> 38286201Sbapt#include <fcntl.h> 3920253Sjoerg#include <string.h> 40286201Sbapt#include <unistd.h> 4120253Sjoerg 4220253Sjoerg#include "pw.h" 4320253Sjoerg 4420253Sjoerg#define debugging 0 4520253Sjoerg 4620253Sjoergenum { 4720253Sjoerg _UC_NONE, 4820253Sjoerg _UC_DEFAULTPWD, 4920253Sjoerg _UC_REUSEUID, 5020253Sjoerg _UC_REUSEGID, 5121330Sdavidn _UC_NISPASSWD, 5220253Sjoerg _UC_DOTDIR, 5320253Sjoerg _UC_NEWMAIL, 5420253Sjoerg _UC_LOGFILE, 5520253Sjoerg _UC_HOMEROOT, 56168044Sle _UC_HOMEMODE, 5720253Sjoerg _UC_SHELLPATH, 5820253Sjoerg _UC_SHELLS, 5920253Sjoerg _UC_DEFAULTSHELL, 6020253Sjoerg _UC_DEFAULTGROUP, 6120253Sjoerg _UC_EXTRAGROUPS, 6220253Sjoerg _UC_DEFAULTCLASS, 6320253Sjoerg _UC_MINUID, 6420253Sjoerg _UC_MAXUID, 6520253Sjoerg _UC_MINGID, 6620253Sjoerg _UC_MAXGID, 6720253Sjoerg _UC_EXPIRE, 6820253Sjoerg _UC_PASSWORD, 6920253Sjoerg _UC_FIELDS 7020253Sjoerg}; 7120253Sjoerg 7220253Sjoergstatic char bourne_shell[] = "sh"; 7320253Sjoerg 7420253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 7520253Sjoerg{ 7620253Sjoerg bourne_shell, 7763239Sdavidn "csh", 7863239Sdavidn "tcsh" 7920253Sjoerg}; 8020253Sjoerg 8120253Sjoergstatic char const *booltrue[] = 8220253Sjoerg{ 8320253Sjoerg "yes", "true", "1", "on", NULL 8420253Sjoerg}; 8520253Sjoergstatic char const *boolfalse[] = 8620253Sjoerg{ 8720253Sjoerg "no", "false", "0", "off", NULL 8820253Sjoerg}; 8920253Sjoerg 9020253Sjoergstatic struct userconf config = 9120253Sjoerg{ 9220253Sjoerg 0, /* Default password for new users? (nologin) */ 9320253Sjoerg 0, /* Reuse uids? */ 9420253Sjoerg 0, /* Reuse gids? */ 9521330Sdavidn NULL, /* NIS version of the passwd file */ 9620253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 9720253Sjoerg NULL, /* Mail to send to new accounts */ 9820253Sjoerg "/var/log/userlog", /* Where to log changes */ 9920253Sjoerg "/home", /* Where to create home directory */ 100219408Sjkim _DEF_DIRMODE, /* Home directory perms, modified by umask */ 10120253Sjoerg "/bin", /* Where shells are located */ 10220253Sjoerg system_shells, /* List of shells (first is default) */ 10320253Sjoerg bourne_shell, /* Default shell */ 10420253Sjoerg NULL, /* Default group name */ 10520747Sdavidn NULL, /* Default (additional) groups */ 10620253Sjoerg NULL, /* Default login class */ 10720253Sjoerg 1000, 32000, /* Allowed range of uids */ 10820253Sjoerg 1000, 32000, /* Allowed range of gids */ 10920253Sjoerg 0, /* Days until account expires */ 110285412Sbapt 0 /* Days until password expires */ 11120253Sjoerg}; 11220253Sjoerg 11320253Sjoergstatic char const *comments[_UC_FIELDS] = 11420253Sjoerg{ 11520253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 11620253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 11720253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 11820253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11921330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 12020253Sjoerg "\n# Obtain default dotfiles from this directory\n", 12120253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 12220253Sjoerg "\n# Log add/change/remove information in this file\n", 12320253Sjoerg "\n# Root directory in which $HOME directory is created\n", 124168044Sle "\n# Mode for the new $HOME directory, will be modified by umask\n", 12520253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 12670133Sdougb "\n# Comma separated list of available shells (without paths)\n", 12720253Sjoerg "\n# Default shell (without path)\n", 12820253Sjoerg "\n# Default group (leave blank for new group per user)\n", 12920253Sjoerg "\n# Extra groups for new users\n", 13020253Sjoerg "\n# Default login class for new users\n", 13120253Sjoerg "\n# Range of valid default user ids\n", 13220253Sjoerg NULL, 13320253Sjoerg "\n# Range of valid default group ids\n", 13420253Sjoerg NULL, 13520253Sjoerg "\n# Days after which account expires (0=disabled)\n", 13620253Sjoerg "\n# Days after which password expires (0=disabled)\n" 13720253Sjoerg}; 13820253Sjoerg 13920253Sjoergstatic char const *kwds[] = 14020253Sjoerg{ 14120253Sjoerg "", 14220253Sjoerg "defaultpasswd", 14320253Sjoerg "reuseuids", 14420253Sjoerg "reusegids", 14521330Sdavidn "nispasswd", 14620253Sjoerg "skeleton", 14720253Sjoerg "newmail", 14820253Sjoerg "logfile", 14920253Sjoerg "home", 150168044Sle "homemode", 15120253Sjoerg "shellpath", 15220253Sjoerg "shells", 15320253Sjoerg "defaultshell", 15420253Sjoerg "defaultgroup", 15520253Sjoerg "extragroups", 15620253Sjoerg "defaultclass", 15720253Sjoerg "minuid", 15820253Sjoerg "maxuid", 15920253Sjoerg "mingid", 16020253Sjoerg "maxgid", 16120253Sjoerg "expire_days", 16220253Sjoerg "password_days", 16320253Sjoerg NULL 16420253Sjoerg}; 16520253Sjoerg 16620253Sjoergstatic char * 16720253Sjoergunquote(char const * str) 16820253Sjoerg{ 16920253Sjoerg if (str && (*str == '"' || *str == '\'')) { 17020253Sjoerg char *p = strchr(str + 1, *str); 17120253Sjoerg 17220253Sjoerg if (p != NULL) 17320253Sjoerg *p = '\0'; 17420253Sjoerg return (char *) (*++str ? str : NULL); 17520253Sjoerg } 17620253Sjoerg return (char *) str; 17720253Sjoerg} 17820253Sjoerg 17920253Sjoergint 18020253Sjoergboolean_val(char const * str, int dflt) 18120253Sjoerg{ 18220253Sjoerg if ((str = unquote(str)) != NULL) { 18320253Sjoerg int i; 18420253Sjoerg 18520253Sjoerg for (i = 0; booltrue[i]; i++) 18620253Sjoerg if (strcmp(str, booltrue[i]) == 0) 18720253Sjoerg return 1; 18820253Sjoerg for (i = 0; boolfalse[i]; i++) 18920253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 19020253Sjoerg return 0; 191305741Sasomers } 192305741Sasomers return dflt; 193305741Sasomers} 19420253Sjoerg 195305741Sasomersint 196305741Sasomerspasswd_val(char const * str, int dflt) 197305741Sasomers{ 198305741Sasomers if ((str = unquote(str)) != NULL) { 199305741Sasomers int i; 200305741Sasomers 201305741Sasomers for (i = 0; booltrue[i]; i++) 202305741Sasomers if (strcmp(str, booltrue[i]) == 0) 203326848Seugen return P_YES; 204305741Sasomers for (i = 0; boolfalse[i]; i++) 205305741Sasomers if (strcmp(str, boolfalse[i]) == 0) 206326848Seugen return P_NO; 207305741Sasomers 20820253Sjoerg /* 20920253Sjoerg * Special cases for defaultpassword 21020253Sjoerg */ 21120253Sjoerg if (strcmp(str, "random") == 0) 212326848Seugen return P_RANDOM; 21320253Sjoerg if (strcmp(str, "none") == 0) 214326848Seugen return P_NONE; 215305741Sasomers 216305741Sasomers errx(1, "Invalid value for default password"); 21720253Sjoerg } 21820253Sjoerg return dflt; 21920253Sjoerg} 22020253Sjoerg 22120253Sjoergchar const * 22220253Sjoergboolean_str(int val) 22320253Sjoerg{ 22420253Sjoerg if (val == -1) 22520253Sjoerg return "random"; 22620253Sjoerg else if (val == -2) 22720253Sjoerg return "none"; 22820253Sjoerg else 22920253Sjoerg return val ? booltrue[0] : boolfalse[0]; 23020253Sjoerg} 23120253Sjoerg 23220253Sjoergchar * 23320253Sjoergnewstr(char const * p) 23420253Sjoerg{ 235282718Sbapt char *q; 23620253Sjoerg 237282718Sbapt if ((p = unquote(p)) == NULL) 238282718Sbapt return (NULL); 23920253Sjoerg 240282719Sbapt if ((q = strdup(p)) == NULL) 241282719Sbapt err(1, "strdup()"); 242282718Sbapt 243282718Sbapt return (q); 24420253Sjoerg} 24520253Sjoerg 24620253Sjoergstruct userconf * 24720253Sjoergread_userconfig(char const * file) 24820253Sjoerg{ 249264781Sbapt FILE *fp; 250264781Sbapt char *buf, *p; 251286154Sbapt const char *errstr; 252264781Sbapt size_t linecap; 253264781Sbapt ssize_t linelen; 25420253Sjoerg 255264781Sbapt buf = NULL; 256264781Sbapt linecap = 0; 257264781Sbapt 25820253Sjoerg if (file == NULL) 25920253Sjoerg file = _PATH_PW_CONF; 260264781Sbapt 261283815Sbapt if ((fp = fopen(file, "r")) == NULL) 262283815Sbapt return (&config); 26320747Sdavidn 264283815Sbapt while ((linelen = getline(&buf, &linecap, fp)) > 0) { 265283815Sbapt if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 266283815Sbapt static char const toks[] = " \t\r\n,="; 267283815Sbapt char *q = strtok(NULL, toks); 268283815Sbapt int i = 0; 269283815Sbapt mode_t *modeset; 270283815Sbapt 271283815Sbapt while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 272283815Sbapt ++i; 27320253Sjoerg#if debugging 274283815Sbapt if (i == _UC_FIELDS) 275283815Sbapt printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 276283815Sbapt else 277283815Sbapt printf("Got kwd[%s]=%s\n", p, q); 27820253Sjoerg#endif 279283815Sbapt switch (i) { 280283815Sbapt case _UC_DEFAULTPWD: 281305741Sasomers config.default_password = passwd_val(q, 1); 282283815Sbapt break; 283283815Sbapt case _UC_REUSEUID: 284283815Sbapt config.reuse_uids = boolean_val(q, 0); 285283815Sbapt break; 286283815Sbapt case _UC_REUSEGID: 287283815Sbapt config.reuse_gids = boolean_val(q, 0); 288283815Sbapt break; 289283815Sbapt case _UC_NISPASSWD: 290283815Sbapt config.nispasswd = (q == NULL || !boolean_val(q, 1)) 291283815Sbapt ? NULL : newstr(q); 292283815Sbapt break; 293283815Sbapt case _UC_DOTDIR: 294283815Sbapt config.dotdir = (q == NULL || !boolean_val(q, 1)) 295283815Sbapt ? NULL : newstr(q); 296283815Sbapt break; 29720747Sdavidn case _UC_NEWMAIL: 298283815Sbapt config.newmail = (q == NULL || !boolean_val(q, 1)) 299283815Sbapt ? NULL : newstr(q); 300283815Sbapt break; 301283815Sbapt case _UC_LOGFILE: 302283815Sbapt config.logfile = (q == NULL || !boolean_val(q, 1)) 303283815Sbapt ? NULL : newstr(q); 304283815Sbapt break; 305283815Sbapt case _UC_HOMEROOT: 306283815Sbapt config.home = (q == NULL || !boolean_val(q, 1)) 307283815Sbapt ? "/home" : newstr(q); 308283815Sbapt break; 309283815Sbapt case _UC_HOMEMODE: 310283815Sbapt modeset = setmode(q); 311283815Sbapt config.homemode = (q == NULL || !boolean_val(q, 1)) 312283815Sbapt ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE); 313283815Sbapt free(modeset); 314283815Sbapt break; 315283815Sbapt case _UC_SHELLPATH: 316283815Sbapt config.shelldir = (q == NULL || !boolean_val(q, 1)) 317283815Sbapt ? "/bin" : newstr(q); 318283815Sbapt break; 319283815Sbapt case _UC_SHELLS: 320283815Sbapt for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 321283815Sbapt system_shells[i] = newstr(q); 322283815Sbapt if (i > 0) 323283815Sbapt while (i < _UC_MAXSHELLS) 324283815Sbapt system_shells[i++] = NULL; 325283815Sbapt break; 326283815Sbapt case _UC_DEFAULTSHELL: 327283815Sbapt config.shell_default = (q == NULL || !boolean_val(q, 1)) 328283815Sbapt ? (char *) bourne_shell : newstr(q); 329283815Sbapt break; 330283815Sbapt case _UC_DEFAULTGROUP: 331283815Sbapt q = unquote(q); 332283815Sbapt config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 333283815Sbapt ? NULL : newstr(q); 334283815Sbapt break; 335283815Sbapt case _UC_EXTRAGROUPS: 336292849Sbapt while ((q = strtok(NULL, toks)) != NULL) { 337286196Sbapt if (config.groups == NULL) 338286196Sbapt config.groups = sl_init(); 339285412Sbapt sl_add(config.groups, newstr(q)); 340286196Sbapt } 341283815Sbapt break; 342283815Sbapt case _UC_DEFAULTCLASS: 343283815Sbapt config.default_class = (q == NULL || !boolean_val(q, 1)) 344283815Sbapt ? NULL : newstr(q); 345283815Sbapt break; 346283815Sbapt case _UC_MINUID: 347286151Sbapt if ((q = unquote(q)) != NULL) { 348286154Sbapt config.min_uid = strtounum(q, 0, 349286154Sbapt UID_MAX, &errstr); 350286151Sbapt if (errstr) 351286154Sbapt warnx("Invalid min_uid: '%s';" 352286154Sbapt " ignoring", q); 353286151Sbapt } 354283815Sbapt break; 355283815Sbapt case _UC_MAXUID: 356286151Sbapt if ((q = unquote(q)) != NULL) { 357286154Sbapt config.max_uid = strtounum(q, 0, 358286154Sbapt UID_MAX, &errstr); 359286151Sbapt if (errstr) 360286154Sbapt warnx("Invalid max_uid: '%s';" 361286154Sbapt " ignoring", q); 362286151Sbapt } 363283815Sbapt break; 364283815Sbapt case _UC_MINGID: 365286154Sbapt if ((q = unquote(q)) != NULL) { 366286154Sbapt config.min_gid = strtounum(q, 0, 367286154Sbapt GID_MAX, &errstr); 368286151Sbapt if (errstr) 369286154Sbapt warnx("Invalid min_gid: '%s';" 370286154Sbapt " ignoring", q); 371286155Sbapt } 372283815Sbapt break; 373283815Sbapt case _UC_MAXGID: 374286151Sbapt if ((q = unquote(q)) != NULL) { 375286154Sbapt config.max_gid = strtounum(q, 0, 376286154Sbapt GID_MAX, &errstr); 377286151Sbapt if (errstr) 378286154Sbapt warnx("Invalid max_gid: '%s';" 379286154Sbapt " ignoring", q); 380286151Sbapt } 381283815Sbapt break; 382283815Sbapt case _UC_EXPIRE: 383286152Sbapt if ((q = unquote(q)) != NULL) { 384286154Sbapt config.expire_days = strtonum(q, 0, 385286154Sbapt INT_MAX, &errstr); 386286152Sbapt if (errstr) 387286154Sbapt warnx("Invalid expire days:" 388286154Sbapt " '%s'; ignoring", q); 389286152Sbapt } 390283815Sbapt break; 391283815Sbapt case _UC_PASSWORD: 392286152Sbapt if ((q = unquote(q)) != NULL) { 393286154Sbapt config.password_days = strtonum(q, 0, 394286154Sbapt INT_MAX, &errstr); 395286152Sbapt if (errstr) 396286154Sbapt warnx("Invalid password days:" 397286154Sbapt " '%s'; ignoring", q); 398286152Sbapt } 399283815Sbapt break; 400283815Sbapt case _UC_FIELDS: 401283815Sbapt case _UC_NONE: 402283815Sbapt break; 40320253Sjoerg } 40420253Sjoerg } 40520253Sjoerg } 406283818Sbapt free(buf); 407283818Sbapt fclose(fp); 408283818Sbapt 409283815Sbapt return (&config); 41020253Sjoerg} 41120253Sjoerg 41220253Sjoerg 41320253Sjoergint 414286196Sbaptwrite_userconfig(struct userconf *cnf, const char *file) 41520253Sjoerg{ 41620253Sjoerg int fd; 417282697Sbapt int i, j; 418282681Sbapt struct sbuf *buf; 419282697Sbapt FILE *fp; 42020253Sjoerg 42120253Sjoerg if (file == NULL) 42220253Sjoerg file = _PATH_PW_CONF; 42320253Sjoerg 424282697Sbapt if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1) 425282697Sbapt return (0); 42620253Sjoerg 427282697Sbapt if ((fp = fdopen(fd, "w")) == NULL) { 428282697Sbapt close(fd); 429282697Sbapt return (0); 430282697Sbapt } 431282681Sbapt 432282697Sbapt buf = sbuf_new_auto(); 433282697Sbapt for (i = _UC_NONE; i < _UC_FIELDS; i++) { 434282697Sbapt int quote = 1; 43520253Sjoerg 436282697Sbapt sbuf_clear(buf); 437282697Sbapt switch (i) { 438282697Sbapt case _UC_DEFAULTPWD: 439286196Sbapt sbuf_cat(buf, boolean_str(cnf->default_password)); 440282697Sbapt break; 441282697Sbapt case _UC_REUSEUID: 442286196Sbapt sbuf_cat(buf, boolean_str(cnf->reuse_uids)); 443282697Sbapt break; 444282697Sbapt case _UC_REUSEGID: 445286196Sbapt sbuf_cat(buf, boolean_str(cnf->reuse_gids)); 446282697Sbapt break; 447282697Sbapt case _UC_NISPASSWD: 448286196Sbapt sbuf_cat(buf, cnf->nispasswd ? cnf->nispasswd : ""); 449282697Sbapt quote = 0; 450282697Sbapt break; 451282697Sbapt case _UC_DOTDIR: 452286196Sbapt sbuf_cat(buf, cnf->dotdir ? cnf->dotdir : 453282697Sbapt boolean_str(0)); 454282697Sbapt break; 455282697Sbapt case _UC_NEWMAIL: 456286196Sbapt sbuf_cat(buf, cnf->newmail ? cnf->newmail : 457282697Sbapt boolean_str(0)); 458282697Sbapt break; 459282697Sbapt case _UC_LOGFILE: 460286196Sbapt sbuf_cat(buf, cnf->logfile ? cnf->logfile : 461282697Sbapt boolean_str(0)); 462282697Sbapt break; 463282697Sbapt case _UC_HOMEROOT: 464286196Sbapt sbuf_cat(buf, cnf->home); 465282697Sbapt break; 466282697Sbapt case _UC_HOMEMODE: 467286196Sbapt sbuf_printf(buf, "%04o", cnf->homemode); 468282697Sbapt quote = 0; 469282697Sbapt break; 470282697Sbapt case _UC_SHELLPATH: 471286196Sbapt sbuf_cat(buf, cnf->shelldir); 472282697Sbapt break; 473282697Sbapt case _UC_SHELLS: 474282697Sbapt for (j = 0; j < _UC_MAXSHELLS && 475282697Sbapt system_shells[j] != NULL; j++) 476282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 477282697Sbapt "," : "", system_shells[j]); 478282697Sbapt quote = 0; 479282697Sbapt break; 480282697Sbapt case _UC_DEFAULTSHELL: 481286196Sbapt sbuf_cat(buf, cnf->shell_default ? 482286196Sbapt cnf->shell_default : bourne_shell); 483282697Sbapt break; 484282697Sbapt case _UC_DEFAULTGROUP: 485286196Sbapt sbuf_cat(buf, cnf->default_group ? 486286196Sbapt cnf->default_group : ""); 487282697Sbapt break; 488282697Sbapt case _UC_EXTRAGROUPS: 489286196Sbapt for (j = 0; cnf->groups != NULL && 490286196Sbapt j < (int)cnf->groups->sl_cur; j++) 491282697Sbapt sbuf_printf(buf, "%s\"%s\"", j ? 492286196Sbapt "," : "", cnf->groups->sl_str[j]); 493282697Sbapt quote = 0; 494282697Sbapt break; 495282697Sbapt case _UC_DEFAULTCLASS: 496286196Sbapt sbuf_cat(buf, cnf->default_class ? 497286196Sbapt cnf->default_class : ""); 498282697Sbapt break; 499282697Sbapt case _UC_MINUID: 500286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_uid); 501282697Sbapt quote = 0; 502282697Sbapt break; 503282697Sbapt case _UC_MAXUID: 504286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_uid); 505282697Sbapt quote = 0; 506282697Sbapt break; 507282697Sbapt case _UC_MINGID: 508286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_gid); 509282697Sbapt quote = 0; 510282697Sbapt break; 511282697Sbapt case _UC_MAXGID: 512286196Sbapt sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_gid); 513282697Sbapt quote = 0; 514282697Sbapt break; 515282697Sbapt case _UC_EXPIRE: 516286211Sbapt sbuf_printf(buf, "%jd", (intmax_t)cnf->expire_days); 517282697Sbapt quote = 0; 518282697Sbapt break; 519282697Sbapt case _UC_PASSWORD: 520286211Sbapt sbuf_printf(buf, "%jd", (intmax_t)cnf->password_days); 521282697Sbapt quote = 0; 522282697Sbapt break; 523282697Sbapt case _UC_NONE: 524282697Sbapt break; 525282697Sbapt } 526282697Sbapt sbuf_finish(buf); 52720253Sjoerg 528282697Sbapt if (comments[i]) 529282697Sbapt fputs(comments[i], fp); 53020253Sjoerg 531282697Sbapt if (*kwds[i]) { 532282697Sbapt if (quote) 533282697Sbapt fprintf(fp, "%s = \"%s\"\n", kwds[i], 534282697Sbapt sbuf_data(buf)); 535282697Sbapt else 536282697Sbapt fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf)); 53720253Sjoerg#if debugging 538282697Sbapt printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf)); 53920253Sjoerg#endif 54020253Sjoerg } 54120253Sjoerg } 542282697Sbapt sbuf_delete(buf); 543282697Sbapt return (fclose(fp) != EOF); 54420253Sjoerg} 545