pw_conf.c revision 168044
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 168044 2007-03-30 11:23:10Z le $"; 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, 50168044Sle _UC_HOMEMODE, 5120253Sjoerg _UC_SHELLPATH, 5220253Sjoerg _UC_SHELLS, 5320253Sjoerg _UC_DEFAULTSHELL, 5420253Sjoerg _UC_DEFAULTGROUP, 5520253Sjoerg _UC_EXTRAGROUPS, 5620253Sjoerg _UC_DEFAULTCLASS, 5720253Sjoerg _UC_MINUID, 5820253Sjoerg _UC_MAXUID, 5920253Sjoerg _UC_MINGID, 6020253Sjoerg _UC_MAXGID, 6120253Sjoerg _UC_EXPIRE, 6220253Sjoerg _UC_PASSWORD, 6320253Sjoerg _UC_FIELDS 6420253Sjoerg}; 6520253Sjoerg 6620253Sjoergstatic char bourne_shell[] = "sh"; 6720253Sjoerg 6820253Sjoergstatic char *system_shells[_UC_MAXSHELLS] = 6920253Sjoerg{ 7020253Sjoerg bourne_shell, 7163239Sdavidn "csh", 7263239Sdavidn "tcsh" 7320253Sjoerg}; 7420253Sjoerg 7520253Sjoergstatic char const *booltrue[] = 7620253Sjoerg{ 7720253Sjoerg "yes", "true", "1", "on", NULL 7820253Sjoerg}; 7920253Sjoergstatic char const *boolfalse[] = 8020253Sjoerg{ 8120253Sjoerg "no", "false", "0", "off", NULL 8220253Sjoerg}; 8320253Sjoerg 8420253Sjoergstatic struct userconf config = 8520253Sjoerg{ 8620253Sjoerg 0, /* Default password for new users? (nologin) */ 8720253Sjoerg 0, /* Reuse uids? */ 8820253Sjoerg 0, /* Reuse gids? */ 8921330Sdavidn NULL, /* NIS version of the passwd file */ 9020253Sjoerg "/usr/share/skel", /* Where to obtain skeleton files */ 9120253Sjoerg NULL, /* Mail to send to new accounts */ 9220253Sjoerg "/var/log/userlog", /* Where to log changes */ 9320253Sjoerg "/home", /* Where to create home directory */ 94168044Sle 0777, /* Home directory perms, modified by umask */ 9520253Sjoerg "/bin", /* Where shells are located */ 9620253Sjoerg system_shells, /* List of shells (first is default) */ 9720253Sjoerg bourne_shell, /* Default shell */ 9820253Sjoerg NULL, /* Default group name */ 9920747Sdavidn NULL, /* Default (additional) groups */ 10020253Sjoerg NULL, /* Default login class */ 10120253Sjoerg 1000, 32000, /* Allowed range of uids */ 10220253Sjoerg 1000, 32000, /* Allowed range of gids */ 10320253Sjoerg 0, /* Days until account expires */ 10449171Sdavidn 0, /* Days until password expires */ 10549171Sdavidn 0 /* size of default_group array */ 10620253Sjoerg}; 10720253Sjoerg 10820253Sjoergstatic char const *comments[_UC_FIELDS] = 10920253Sjoerg{ 11020253Sjoerg "#\n# pw.conf - user/group configuration defaults\n#\n", 11120253Sjoerg "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", 11220253Sjoerg "\n# Reuse gaps in uid sequence? (yes or no)\n", 11320253Sjoerg "\n# Reuse gaps in gid sequence? (yes or no)\n", 11421330Sdavidn "\n# Path to the NIS passwd file (blank or 'no' for none)\n", 11520253Sjoerg "\n# Obtain default dotfiles from this directory\n", 11620253Sjoerg "\n# Mail this file to new user (/etc/newuser.msg or no)\n", 11720253Sjoerg "\n# Log add/change/remove information in this file\n", 11820253Sjoerg "\n# Root directory in which $HOME directory is created\n", 119168044Sle "\n# Mode for the new $HOME directory, will be modified by umask\n", 12020253Sjoerg "\n# Colon separated list of directories containing valid shells\n", 12170133Sdougb "\n# Comma separated list of available shells (without paths)\n", 12220253Sjoerg "\n# Default shell (without path)\n", 12320253Sjoerg "\n# Default group (leave blank for new group per user)\n", 12420253Sjoerg "\n# Extra groups for new users\n", 12520253Sjoerg "\n# Default login class for new users\n", 12620253Sjoerg "\n# Range of valid default user ids\n", 12720253Sjoerg NULL, 12820253Sjoerg "\n# Range of valid default group ids\n", 12920253Sjoerg NULL, 13020253Sjoerg "\n# Days after which account expires (0=disabled)\n", 13120253Sjoerg "\n# Days after which password expires (0=disabled)\n" 13220253Sjoerg}; 13320253Sjoerg 13420253Sjoergstatic char const *kwds[] = 13520253Sjoerg{ 13620253Sjoerg "", 13720253Sjoerg "defaultpasswd", 13820253Sjoerg "reuseuids", 13920253Sjoerg "reusegids", 14021330Sdavidn "nispasswd", 14120253Sjoerg "skeleton", 14220253Sjoerg "newmail", 14320253Sjoerg "logfile", 14420253Sjoerg "home", 145168044Sle "homemode", 14620253Sjoerg "shellpath", 14720253Sjoerg "shells", 14820253Sjoerg "defaultshell", 14920253Sjoerg "defaultgroup", 15020253Sjoerg "extragroups", 15120253Sjoerg "defaultclass", 15220253Sjoerg "minuid", 15320253Sjoerg "maxuid", 15420253Sjoerg "mingid", 15520253Sjoerg "maxgid", 15620253Sjoerg "expire_days", 15720253Sjoerg "password_days", 15820253Sjoerg NULL 15920253Sjoerg}; 16020253Sjoerg 16120253Sjoergstatic char * 16220253Sjoergunquote(char const * str) 16320253Sjoerg{ 16420253Sjoerg if (str && (*str == '"' || *str == '\'')) { 16520253Sjoerg char *p = strchr(str + 1, *str); 16620253Sjoerg 16720253Sjoerg if (p != NULL) 16820253Sjoerg *p = '\0'; 16920253Sjoerg return (char *) (*++str ? str : NULL); 17020253Sjoerg } 17120253Sjoerg return (char *) str; 17220253Sjoerg} 17320253Sjoerg 17420253Sjoergint 17520253Sjoergboolean_val(char const * str, int dflt) 17620253Sjoerg{ 17720253Sjoerg if ((str = unquote(str)) != NULL) { 17820253Sjoerg int i; 17920253Sjoerg 18020253Sjoerg for (i = 0; booltrue[i]; i++) 18120253Sjoerg if (strcmp(str, booltrue[i]) == 0) 18220253Sjoerg return 1; 18320253Sjoerg for (i = 0; boolfalse[i]; i++) 18420253Sjoerg if (strcmp(str, boolfalse[i]) == 0) 18520253Sjoerg return 0; 18620253Sjoerg 18720253Sjoerg /* 18820253Sjoerg * Special cases for defaultpassword 18920253Sjoerg */ 19020253Sjoerg if (strcmp(str, "random") == 0) 19120253Sjoerg return -1; 19220253Sjoerg if (strcmp(str, "none") == 0) 19320253Sjoerg return -2; 19420253Sjoerg } 19520253Sjoerg return dflt; 19620253Sjoerg} 19720253Sjoerg 19820253Sjoergchar const * 19920253Sjoergboolean_str(int val) 20020253Sjoerg{ 20120253Sjoerg if (val == -1) 20220253Sjoerg return "random"; 20320253Sjoerg else if (val == -2) 20420253Sjoerg return "none"; 20520253Sjoerg else 20620253Sjoerg return val ? booltrue[0] : boolfalse[0]; 20720253Sjoerg} 20820253Sjoerg 20920253Sjoergchar * 21020253Sjoergnewstr(char const * p) 21120253Sjoerg{ 21220253Sjoerg char *q = NULL; 21320253Sjoerg 21420253Sjoerg if ((p = unquote(p)) != NULL) { 21520253Sjoerg int l = strlen(p) + 1; 21620253Sjoerg 21720253Sjoerg if ((q = malloc(l)) != NULL) 21820253Sjoerg memcpy(q, p, l); 21920253Sjoerg } 22020253Sjoerg return q; 22120253Sjoerg} 22220253Sjoerg 22320747Sdavidn#define LNBUFSZ 1024 22420253Sjoerg 22520747Sdavidn 22620253Sjoergstruct userconf * 22720253Sjoergread_userconfig(char const * file) 22820253Sjoerg{ 22920253Sjoerg FILE *fp; 23020253Sjoerg 23120747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 23220747Sdavidn memset(config.groups, 0, config.numgroups * sizeof(char *)); 23320253Sjoerg if (file == NULL) 23420253Sjoerg file = _PATH_PW_CONF; 23520253Sjoerg if ((fp = fopen(file, "r")) != NULL) { 23620747Sdavidn int buflen = LNBUFSZ; 23720747Sdavidn char *buf = malloc(buflen); 23820253Sjoerg 23920747Sdavidn nextline: 24020747Sdavidn while (fgets(buf, buflen, fp) != NULL) { 24120747Sdavidn char *p; 24220253Sjoerg 24320747Sdavidn while ((p = strchr(buf, '\n')) == NULL) { 24420747Sdavidn int l; 24520747Sdavidn if (extendline(&buf, &buflen, buflen + LNBUFSZ) == -1) { 24620747Sdavidn int ch; 24720747Sdavidn while ((ch = fgetc(fp)) != '\n' && ch != EOF); 24820747Sdavidn goto nextline; /* Ignore it */ 24920747Sdavidn } 25020747Sdavidn l = strlen(buf); 25120747Sdavidn if (fgets(buf + l, buflen - l, fp) == NULL) 25220747Sdavidn break; /* Unterminated last line */ 25320747Sdavidn } 25420253Sjoerg 25520747Sdavidn if (p != NULL) 25620253Sjoerg *p = '\0'; 25720253Sjoerg 25820747Sdavidn if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { 25920747Sdavidn static char const toks[] = " \t\r\n,="; 26020747Sdavidn char *q = strtok(NULL, toks); 26120747Sdavidn int i = 0; 262168044Sle mode_t *modeset; 26320747Sdavidn 26420747Sdavidn while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) 26520747Sdavidn ++i; 26620253Sjoerg#if debugging 26720747Sdavidn if (i == _UC_FIELDS) 26820747Sdavidn printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); 26920747Sdavidn else 27020747Sdavidn printf("Got kwd[%s]=%s\n", p, q); 27120253Sjoerg#endif 27220747Sdavidn switch (i) { 27320747Sdavidn case _UC_DEFAULTPWD: 27420747Sdavidn config.default_password = boolean_val(q, 1); 27520747Sdavidn break; 27620747Sdavidn case _UC_REUSEUID: 27720747Sdavidn config.reuse_uids = boolean_val(q, 0); 27820747Sdavidn break; 27920747Sdavidn case _UC_REUSEGID: 28020747Sdavidn config.reuse_gids = boolean_val(q, 0); 28120747Sdavidn break; 28221330Sdavidn case _UC_NISPASSWD: 28321330Sdavidn config.nispasswd = (q == NULL || !boolean_val(q, 1)) 28421330Sdavidn ? NULL : newstr(q); 28521330Sdavidn break; 28620747Sdavidn case _UC_DOTDIR: 28720747Sdavidn config.dotdir = (q == NULL || !boolean_val(q, 1)) 28820747Sdavidn ? NULL : newstr(q); 28920747Sdavidn break; 29020747Sdavidn case _UC_NEWMAIL: 29120747Sdavidn config.newmail = (q == NULL || !boolean_val(q, 1)) 29220747Sdavidn ? NULL : newstr(q); 29320747Sdavidn break; 29420747Sdavidn case _UC_LOGFILE: 29520747Sdavidn config.logfile = (q == NULL || !boolean_val(q, 1)) 29620747Sdavidn ? NULL : newstr(q); 29720747Sdavidn break; 29820747Sdavidn case _UC_HOMEROOT: 29920747Sdavidn config.home = (q == NULL || !boolean_val(q, 1)) 30020747Sdavidn ? "/home" : newstr(q); 30120747Sdavidn break; 302168044Sle case _UC_HOMEMODE: 303168044Sle modeset = setmode(q); 304168044Sle config.homemode = (q == NULL || !boolean_val(q, 1)) 305168044Sle ? 0777 : getmode(modeset, 0777); 306168044Sle free(modeset); 307168044Sle break; 30820747Sdavidn case _UC_SHELLPATH: 30920747Sdavidn config.shelldir = (q == NULL || !boolean_val(q, 1)) 31020747Sdavidn ? "/bin" : newstr(q); 31120747Sdavidn break; 31220747Sdavidn case _UC_SHELLS: 31320747Sdavidn for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) 31420747Sdavidn system_shells[i] = newstr(q); 31520747Sdavidn if (i > 0) 31620747Sdavidn while (i < _UC_MAXSHELLS) 31720747Sdavidn system_shells[i++] = NULL; 31820747Sdavidn break; 31920747Sdavidn case _UC_DEFAULTSHELL: 32020747Sdavidn config.shell_default = (q == NULL || !boolean_val(q, 1)) 32120747Sdavidn ? (char *) bourne_shell : newstr(q); 32220747Sdavidn break; 32320747Sdavidn case _UC_DEFAULTGROUP: 32429002Sdavidn q = unquote(q); 32544229Sdavidn config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) 32620747Sdavidn ? NULL : newstr(q); 32720747Sdavidn break; 32820747Sdavidn case _UC_EXTRAGROUPS: 32920747Sdavidn for (i = 0; q != NULL; q = strtok(NULL, toks)) { 33020747Sdavidn if (extendarray(&config.groups, &config.numgroups, i + 2) != -1) 33120747Sdavidn config.groups[i++] = newstr(q); 33220253Sjoerg } 33320747Sdavidn if (i > 0) 33420747Sdavidn while (i < config.numgroups) 33520747Sdavidn config.groups[i++] = NULL; 33620747Sdavidn break; 33720747Sdavidn case _UC_DEFAULTCLASS: 33820747Sdavidn config.default_class = (q == NULL || !boolean_val(q, 1)) 33920747Sdavidn ? NULL : newstr(q); 34020747Sdavidn break; 34120747Sdavidn case _UC_MINUID: 34220747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34320747Sdavidn config.min_uid = (uid_t) atol(q); 34420747Sdavidn break; 34520747Sdavidn case _UC_MAXUID: 34620747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 34720747Sdavidn config.max_uid = (uid_t) atol(q); 34820747Sdavidn break; 34920747Sdavidn case _UC_MINGID: 35020747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 35120747Sdavidn config.min_gid = (gid_t) atol(q); 35220747Sdavidn break; 35320747Sdavidn case _UC_MAXGID: 35420747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 35520747Sdavidn config.max_gid = (gid_t) atol(q); 35620747Sdavidn break; 35720747Sdavidn case _UC_EXPIRE: 35820747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 35920747Sdavidn config.expire_days = atoi(q); 36020747Sdavidn break; 36120747Sdavidn case _UC_PASSWORD: 36220747Sdavidn if ((q = unquote(q)) != NULL && isdigit(*q)) 36320747Sdavidn config.password_days = atoi(q); 36420747Sdavidn break; 36520747Sdavidn case _UC_FIELDS: 36620747Sdavidn case _UC_NONE: 36720747Sdavidn break; 36820253Sjoerg } 36920253Sjoerg } 37020253Sjoerg } 37120747Sdavidn free(buf); 37220253Sjoerg fclose(fp); 37320253Sjoerg } 37420253Sjoerg return &config; 37520253Sjoerg} 37620253Sjoerg 37720253Sjoerg 37820253Sjoergint 37920253Sjoergwrite_userconfig(char const * file) 38020253Sjoerg{ 38120253Sjoerg int fd; 38220253Sjoerg 38320253Sjoerg if (file == NULL) 38420253Sjoerg file = _PATH_PW_CONF; 38520253Sjoerg 38620253Sjoerg if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { 38720253Sjoerg FILE *fp; 38820253Sjoerg 38920253Sjoerg if ((fp = fdopen(fd, "w")) == NULL) 39020253Sjoerg close(fd); 39120253Sjoerg else { 39220253Sjoerg int i, j, k; 39320747Sdavidn int len = LNBUFSZ; 39420747Sdavidn char *buf = malloc(len); 39520253Sjoerg 39620253Sjoerg for (i = _UC_NONE; i < _UC_FIELDS; i++) { 39720253Sjoerg int quote = 1; 39820253Sjoerg char const *val = buf; 39920253Sjoerg 40020253Sjoerg *buf = '\0'; 40120253Sjoerg switch (i) { 40220253Sjoerg case _UC_DEFAULTPWD: 40320253Sjoerg val = boolean_str(config.default_password); 40420253Sjoerg break; 40520253Sjoerg case _UC_REUSEUID: 40620253Sjoerg val = boolean_str(config.reuse_uids); 40720253Sjoerg break; 40820253Sjoerg case _UC_REUSEGID: 40920253Sjoerg val = boolean_str(config.reuse_gids); 41020253Sjoerg break; 41121330Sdavidn case _UC_NISPASSWD: 41221330Sdavidn val = config.nispasswd ? config.nispasswd : ""; 41321330Sdavidn quote = 0; 41421330Sdavidn break; 41520253Sjoerg case _UC_DOTDIR: 41620253Sjoerg val = config.dotdir ? config.dotdir : boolean_str(0); 41720253Sjoerg break; 41820253Sjoerg case _UC_NEWMAIL: 41920253Sjoerg val = config.newmail ? config.newmail : boolean_str(0); 42020253Sjoerg break; 42120253Sjoerg case _UC_LOGFILE: 42220253Sjoerg val = config.logfile ? config.logfile : boolean_str(0); 42320253Sjoerg break; 42420253Sjoerg case _UC_HOMEROOT: 42520253Sjoerg val = config.home; 42620253Sjoerg break; 427168044Sle case _UC_HOMEMODE: 428168044Sle sprintf(buf, "%04o", config.homemode); 429168044Sle quote = 0; 430168044Sle break; 43120253Sjoerg case _UC_SHELLPATH: 43220253Sjoerg val = config.shelldir; 43320253Sjoerg break; 43420253Sjoerg case _UC_SHELLS: 43520747Sdavidn for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) { 43620747Sdavidn char lbuf[64]; 43720747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", system_shells[j]); 43881982Sbrian if (l < 0) 43981977Sbrian l = 0; 44020747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + LNBUFSZ) != -1) { 44120747Sdavidn strcpy(buf + k, lbuf); 44220747Sdavidn k += l; 44320747Sdavidn } 44420747Sdavidn } 44520253Sjoerg quote = 0; 44620253Sjoerg break; 44720253Sjoerg case _UC_DEFAULTSHELL: 44820253Sjoerg val = config.shell_default ? config.shell_default : bourne_shell; 44920253Sjoerg break; 45020253Sjoerg case _UC_DEFAULTGROUP: 45120253Sjoerg val = config.default_group ? config.default_group : ""; 45220253Sjoerg break; 45320253Sjoerg case _UC_EXTRAGROUPS: 45420747Sdavidn extendarray(&config.groups, &config.numgroups, 200); 45520747Sdavidn for (j = k = 0; j < config.numgroups && config.groups[j] != NULL; j++) { 45620747Sdavidn char lbuf[64]; 45720747Sdavidn int l = snprintf(lbuf, sizeof lbuf, "%s\"%s\"", k ? "," : "", config.groups[j]); 45881982Sbrian if (l < 0) 45981977Sbrian l = 0; 46020747Sdavidn if (l + k + 1 < len || extendline(&buf, &len, len + 1024) != -1) { 46120747Sdavidn strcpy(buf + k, lbuf); 46220747Sdavidn k += l; 46320747Sdavidn } 46420747Sdavidn } 46520253Sjoerg quote = 0; 46620253Sjoerg break; 46720253Sjoerg case _UC_DEFAULTCLASS: 46820253Sjoerg val = config.default_class ? config.default_class : ""; 46920253Sjoerg break; 47020253Sjoerg case _UC_MINUID: 47120253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_uid); 47220253Sjoerg quote = 0; 47320253Sjoerg break; 47420253Sjoerg case _UC_MAXUID: 47520253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_uid); 47620253Sjoerg quote = 0; 47720253Sjoerg break; 47820253Sjoerg case _UC_MINGID: 47920253Sjoerg sprintf(buf, "%lu", (unsigned long) config.min_gid); 48020253Sjoerg quote = 0; 48120253Sjoerg break; 48220253Sjoerg case _UC_MAXGID: 48320253Sjoerg sprintf(buf, "%lu", (unsigned long) config.max_gid); 48420253Sjoerg quote = 0; 48520253Sjoerg break; 48620253Sjoerg case _UC_EXPIRE: 48720253Sjoerg sprintf(buf, "%d", config.expire_days); 48820253Sjoerg quote = 0; 48920253Sjoerg break; 49020253Sjoerg case _UC_PASSWORD: 49120253Sjoerg sprintf(buf, "%d", config.password_days); 49220253Sjoerg quote = 0; 49320253Sjoerg break; 49420253Sjoerg case _UC_NONE: 49520253Sjoerg break; 49620253Sjoerg } 49720253Sjoerg 49820253Sjoerg if (comments[i]) 49920253Sjoerg fputs(comments[i], fp); 50020253Sjoerg 50120253Sjoerg if (*kwds[i]) { 50220253Sjoerg if (quote) 50320253Sjoerg fprintf(fp, "%s = \"%s\"\n", kwds[i], val); 50420253Sjoerg else 50520253Sjoerg fprintf(fp, "%s = %s\n", kwds[i], val); 50620253Sjoerg#if debugging 50720253Sjoerg printf("WROTE: %s = %s\n", kwds[i], val); 50820253Sjoerg#endif 50920253Sjoerg } 51020253Sjoerg } 51120747Sdavidn free(buf); 51220253Sjoerg return fclose(fp) != EOF; 51320253Sjoerg } 51420253Sjoerg } 51520253Sjoerg return 0; 51620253Sjoerg} 517