X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/b1da672b1218212f3151eff39f55f65f6f1bbac0..22e3ea3a26032d00c12a5fc2814d3b78966018b9:/pw/pw_conf.c diff --git a/pw/pw_conf.c b/pw/pw_conf.c index 77778f3..f7b98f1 100644 --- a/pw/pw_conf.c +++ b/pw/pw_conf.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 1996 * David L. Nugent. All rights reserved. * @@ -22,13 +24,20 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $Id: pw_conf.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $ */ -#include -#include +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include +#include + +#include #include +#include +#include #include "pw.h" @@ -39,10 +48,12 @@ enum { _UC_DEFAULTPWD, _UC_REUSEUID, _UC_REUSEGID, + _UC_NISPASSWD, _UC_DOTDIR, _UC_NEWMAIL, _UC_LOGFILE, _UC_HOMEROOT, + _UC_HOMEMODE, _UC_SHELLPATH, _UC_SHELLS, _UC_DEFAULTSHELL, @@ -63,12 +74,8 @@ static char bourne_shell[] = "sh"; static char *system_shells[_UC_MAXSHELLS] = { bourne_shell, - "csh" -}; - -static char *default_groups[_UC_MAXGROUPS] = -{ - NULL + "csh", + "tcsh" }; static char const *booltrue[] = @@ -85,15 +92,17 @@ static struct userconf config = 0, /* Default password for new users? (nologin) */ 0, /* Reuse uids? */ 0, /* Reuse gids? */ + NULL, /* NIS version of the passwd file */ "/usr/share/skel", /* Where to obtain skeleton files */ NULL, /* Mail to send to new accounts */ "/var/log/userlog", /* Where to log changes */ "/home", /* Where to create home directory */ + _DEF_DIRMODE, /* Home directory perms, modified by umask */ "/bin", /* Where shells are located */ system_shells, /* List of shells (first is default) */ bourne_shell, /* Default shell */ NULL, /* Default group name */ - default_groups, /* Default (additional) groups */ + NULL, /* Default (additional) groups */ NULL, /* Default login class */ 1000, 32000, /* Allowed range of uids */ 1000, 32000, /* Allowed range of gids */ @@ -107,12 +116,14 @@ static char const *comments[_UC_FIELDS] = "\n# Password for new users? no=nologin yes=loginid none=blank random=random\n", "\n# Reuse gaps in uid sequence? (yes or no)\n", "\n# Reuse gaps in gid sequence? (yes or no)\n", + "\n# Path to the NIS passwd file (blank or 'no' for none)\n", "\n# Obtain default dotfiles from this directory\n", "\n# Mail this file to new user (/etc/newuser.msg or no)\n", "\n# Log add/change/remove information in this file\n", "\n# Root directory in which $HOME directory is created\n", + "\n# Mode for the new $HOME directory, will be modified by umask\n", "\n# Colon separated list of directories containing valid shells\n", - "\n# Space separated list of available shells (without paths)\n", + "\n# Comma separated list of available shells (without paths)\n", "\n# Default shell (without path)\n", "\n# Default group (leave blank for new group per user)\n", "\n# Extra groups for new users\n", @@ -131,10 +142,12 @@ static char const *kwds[] = "defaultpasswd", "reuseuids", "reusegids", + "nispasswd", "skeleton", "newmail", "logfile", "home", + "homemode", "shellpath", "shells", "defaultshell", @@ -175,14 +188,32 @@ boolean_val(char const * str, int dflt) for (i = 0; boolfalse[i]; i++) if (strcmp(str, boolfalse[i]) == 0) return 0; + } + return dflt; +} + +int +passwd_val(char const * str, int dflt) +{ + if ((str = unquote(str)) != NULL) { + int i; + + for (i = 0; booltrue[i]; i++) + if (strcmp(str, booltrue[i]) == 0) + return P_YES; + for (i = 0; boolfalse[i]; i++) + if (strcmp(str, boolfalse[i]) == 0) + return P_NO; /* * Special cases for defaultpassword */ if (strcmp(str, "random") == 0) - return -1; + return P_RANDOM; if (strcmp(str, "none") == 0) - return -2; + return P_NONE; + + errx(1, "Invalid value for default password"); } return dflt; } @@ -201,252 +232,317 @@ boolean_str(int val) char * newstr(char const * p) { - char *q = NULL; + char *q; - if ((p = unquote(p)) != NULL) { - int l = strlen(p) + 1; + if ((p = unquote(p)) == NULL) + return (NULL); - if ((q = malloc(l)) != NULL) - memcpy(q, p, l); - } - return q; -} + if ((q = strdup(p)) == NULL) + err(1, "strdup()"); + return (q); +} struct userconf * read_userconfig(char const * file) { - FILE *fp; + FILE *fp; + char *buf, *p; + const char *errstr; + size_t linecap; + ssize_t linelen; + + buf = NULL; + linecap = 0; if (file == NULL) file = _PATH_PW_CONF; - if ((fp = fopen(file, "r")) != NULL) { - char buf[_UC_MAXLINE]; - - while (fgets(buf, sizeof buf, fp) != NULL) { - char *p = strchr(buf, '\n'); - if (p == NULL) { /* Line too long */ - int ch; + if ((fp = fopen(file, "r")) == NULL) + return (&config); - while ((ch = fgetc(fp)) != '\n' && ch != EOF); - } else { - *p = '\0'; - if (*buf && *buf != '\n' && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { - static char const toks[] = " \t\r\n,="; - char *q = strtok(NULL, toks); - int i = 0; + while ((linelen = getline(&buf, &linecap, fp)) > 0) { + if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') { + static char const toks[] = " \t\r\n,="; + char *q = strtok(NULL, toks); + int i = 0; + mode_t *modeset; - while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) - ++i; + while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0) + ++i; #if debugging - if (i == _UC_FIELDS) - printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); - else - printf("Got kwd[%s]=%s\n", p, q); + if (i == _UC_FIELDS) + printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : ""); + else + printf("Got kwd[%s]=%s\n", p, q); #endif - switch (i) { - case _UC_DEFAULTPWD: - config.default_password = boolean_val(q, 1); - break; - case _UC_REUSEUID: - config.reuse_uids = boolean_val(q, 0); - break; - case _UC_REUSEGID: - config.reuse_gids = boolean_val(q, 0); - break; - case _UC_DOTDIR: - config.dotdir = (q == NULL || !boolean_val(q, 1)) - ? NULL : newstr(q); - break; - case _UC_NEWMAIL: - config.newmail = (q == NULL || !boolean_val(q, 1)) - ? NULL : newstr(q); - break; - case _UC_LOGFILE: - config.logfile = (q == NULL || !boolean_val(q, 1)) - ? NULL : newstr(q); - break; - case _UC_HOMEROOT: - config.home = (q == NULL || !boolean_val(q, 1)) - ? "/home" : newstr(q); - break; - case _UC_SHELLPATH: - config.shelldir = (q == NULL || !boolean_val(q, 1)) - ? "/bin" : newstr(q); - break; - case _UC_SHELLS: - for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) - system_shells[i] = newstr(q); - if (i > 0) - while (i < _UC_MAXSHELLS) - system_shells[i++] = NULL; - break; - case _UC_DEFAULTSHELL: - config.shell_default = (q == NULL || !boolean_val(q, 1)) - ? (char *) bourne_shell : newstr(q); - break; - case _UC_DEFAULTGROUP: - config.default_group = (q == NULL || !boolean_val(q, 1) || getgrnam(q) == NULL) - ? NULL : newstr(q); - break; - case _UC_EXTRAGROUPS: - for (i = 0; i < _UC_MAXGROUPS && q != NULL; i++, q = strtok(NULL, toks)) - default_groups[i] = newstr(q); - if (i > 0) - while (i < _UC_MAXGROUPS) - default_groups[i++] = NULL; - break; - case _UC_DEFAULTCLASS: - config.default_class = (q == NULL || !boolean_val(q, 1)) - ? NULL : newstr(q); - break; - case _UC_MINUID: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.min_uid = (uid_t) atol(q); - break; - case _UC_MAXUID: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.max_uid = (uid_t) atol(q); - break; - case _UC_MINGID: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.min_gid = (gid_t) atol(q); - break; - case _UC_MAXGID: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.max_gid = (gid_t) atol(q); - break; - case _UC_EXPIRE: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.expire_days = atoi(q); - break; - case _UC_PASSWORD: - if ((q = unquote(q)) != NULL && isdigit(*q)) - config.password_days = atoi(q); - break; - case _UC_FIELDS: - case _UC_NONE: - break; - } + switch (i) { + case _UC_DEFAULTPWD: + config.default_password = passwd_val(q, 1); + break; + case _UC_REUSEUID: + config.reuse_uids = boolean_val(q, 0); + break; + case _UC_REUSEGID: + config.reuse_gids = boolean_val(q, 0); + break; + case _UC_NISPASSWD: + config.nispasswd = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_DOTDIR: + config.dotdir = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_NEWMAIL: + config.newmail = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_LOGFILE: + config.logfile = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_HOMEROOT: + config.home = (q == NULL || !boolean_val(q, 1)) + ? "/home" : newstr(q); + break; + case _UC_HOMEMODE: + modeset = setmode(q); + config.homemode = (q == NULL || !boolean_val(q, 1)) + ? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE); + free(modeset); + break; + case _UC_SHELLPATH: + config.shelldir = (q == NULL || !boolean_val(q, 1)) + ? "/bin" : newstr(q); + break; + case _UC_SHELLS: + for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks)) + system_shells[i] = newstr(q); + if (i > 0) + while (i < _UC_MAXSHELLS) + system_shells[i++] = NULL; + break; + case _UC_DEFAULTSHELL: + config.shell_default = (q == NULL || !boolean_val(q, 1)) + ? (char *) bourne_shell : newstr(q); + break; + case _UC_DEFAULTGROUP: + q = unquote(q); + config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL) + ? NULL : newstr(q); + break; + case _UC_EXTRAGROUPS: + while ((q = strtok(NULL, toks)) != NULL) { + if (config.groups == NULL) + config.groups = sl_init(); + sl_add(config.groups, newstr(q)); + } + break; + case _UC_DEFAULTCLASS: + config.default_class = (q == NULL || !boolean_val(q, 1)) + ? NULL : newstr(q); + break; + case _UC_MINUID: + if ((q = unquote(q)) != NULL) { + config.min_uid = strtounum(q, 0, + UID_MAX, &errstr); + if (errstr) + warnx("Invalid min_uid: '%s';" + " ignoring", q); + } + break; + case _UC_MAXUID: + if ((q = unquote(q)) != NULL) { + config.max_uid = strtounum(q, 0, + UID_MAX, &errstr); + if (errstr) + warnx("Invalid max_uid: '%s';" + " ignoring", q); + } + break; + case _UC_MINGID: + if ((q = unquote(q)) != NULL) { + config.min_gid = strtounum(q, 0, + GID_MAX, &errstr); + if (errstr) + warnx("Invalid min_gid: '%s';" + " ignoring", q); + } + break; + case _UC_MAXGID: + if ((q = unquote(q)) != NULL) { + config.max_gid = strtounum(q, 0, + GID_MAX, &errstr); + if (errstr) + warnx("Invalid max_gid: '%s';" + " ignoring", q); + } + break; + case _UC_EXPIRE: + if ((q = unquote(q)) != NULL) { + config.expire_days = strtonum(q, 0, + INT_MAX, &errstr); + if (errstr) + warnx("Invalid expire days:" + " '%s'; ignoring", q); + } + break; + case _UC_PASSWORD: + if ((q = unquote(q)) != NULL) { + config.password_days = strtonum(q, 0, + INT_MAX, &errstr); + if (errstr) + warnx("Invalid password days:" + " '%s'; ignoring", q); } + break; + case _UC_FIELDS: + case _UC_NONE: + break; } } - fclose(fp); } - return &config; + free(buf); + fclose(fp); + + return (&config); } int -write_userconfig(char const * file) +write_userconfig(struct userconf *cnf, const char *file) { int fd; + int i, j; + struct sbuf *buf; + FILE *fp; + char cfgfile[MAXPATHLEN]; - if (file == NULL) - file = _PATH_PW_CONF; + if (file == NULL) { + snprintf(cfgfile, sizeof(cfgfile), "%s/" _PW_CONF, + conf.etcpath); + file = cfgfile; + } - if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) { - FILE *fp; - - if ((fp = fdopen(fd, "w")) == NULL) - close(fd); - else { - int i, j, k; - char buf[_UC_MAXLINE]; - - for (i = _UC_NONE; i < _UC_FIELDS; i++) { - int quote = 1; - char const *val = buf; - - *buf = '\0'; - switch (i) { - case _UC_DEFAULTPWD: - val = boolean_str(config.default_password); - break; - case _UC_REUSEUID: - val = boolean_str(config.reuse_uids); - break; - case _UC_REUSEGID: - val = boolean_str(config.reuse_gids); - break; - case _UC_DOTDIR: - val = config.dotdir ? config.dotdir : boolean_str(0); - break; - case _UC_NEWMAIL: - val = config.newmail ? config.newmail : boolean_str(0); - break; - case _UC_LOGFILE: - val = config.logfile ? config.logfile : boolean_str(0); - break; - case _UC_HOMEROOT: - val = config.home; - break; - case _UC_SHELLPATH: - val = config.shelldir; - break; - case _UC_SHELLS: - for (j = k = 0; j < _UC_MAXSHELLS && system_shells[j] != NULL; j++) - k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", system_shells[j]); - quote = 0; - break; - case _UC_DEFAULTSHELL: - val = config.shell_default ? config.shell_default : bourne_shell; - break; - case _UC_DEFAULTGROUP: - val = config.default_group ? config.default_group : ""; - break; - case _UC_EXTRAGROUPS: - for (j = k = 0; j < _UC_MAXGROUPS && default_groups[j] != NULL; j++) - k += sprintf(buf + k, "%s\"%s\"", k ? "," : "", default_groups[j]); - quote = 0; - break; - case _UC_DEFAULTCLASS: - val = config.default_class ? config.default_class : ""; - break; - case _UC_MINUID: - sprintf(buf, "%lu", (unsigned long) config.min_uid); - quote = 0; - break; - case _UC_MAXUID: - sprintf(buf, "%lu", (unsigned long) config.max_uid); - quote = 0; - break; - case _UC_MINGID: - sprintf(buf, "%lu", (unsigned long) config.min_gid); - quote = 0; - break; - case _UC_MAXGID: - sprintf(buf, "%lu", (unsigned long) config.max_gid); - quote = 0; - break; - case _UC_EXPIRE: - sprintf(buf, "%d", config.expire_days); - quote = 0; - break; - case _UC_PASSWORD: - sprintf(buf, "%d", config.password_days); - quote = 0; - break; - case _UC_NONE: - break; - } + if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1) + return (0); + + if ((fp = fdopen(fd, "w")) == NULL) { + close(fd); + return (0); + } + + buf = sbuf_new_auto(); + for (i = _UC_NONE; i < _UC_FIELDS; i++) { + int quote = 1; + + sbuf_clear(buf); + switch (i) { + case _UC_DEFAULTPWD: + sbuf_cat(buf, boolean_str(cnf->default_password)); + break; + case _UC_REUSEUID: + sbuf_cat(buf, boolean_str(cnf->reuse_uids)); + break; + case _UC_REUSEGID: + sbuf_cat(buf, boolean_str(cnf->reuse_gids)); + break; + case _UC_NISPASSWD: + sbuf_cat(buf, cnf->nispasswd ? cnf->nispasswd : ""); + quote = 0; + break; + case _UC_DOTDIR: + sbuf_cat(buf, cnf->dotdir ? cnf->dotdir : + boolean_str(0)); + break; + case _UC_NEWMAIL: + sbuf_cat(buf, cnf->newmail ? cnf->newmail : + boolean_str(0)); + break; + case _UC_LOGFILE: + sbuf_cat(buf, cnf->logfile ? cnf->logfile : + boolean_str(0)); + break; + case _UC_HOMEROOT: + sbuf_cat(buf, cnf->home); + break; + case _UC_HOMEMODE: + sbuf_printf(buf, "%04o", cnf->homemode); + quote = 0; + break; + case _UC_SHELLPATH: + sbuf_cat(buf, cnf->shelldir); + break; + case _UC_SHELLS: + for (j = 0; j < _UC_MAXSHELLS && + system_shells[j] != NULL; j++) + sbuf_printf(buf, "%s\"%s\"", j ? + "," : "", system_shells[j]); + quote = 0; + break; + case _UC_DEFAULTSHELL: + sbuf_cat(buf, cnf->shell_default ? + cnf->shell_default : bourne_shell); + break; + case _UC_DEFAULTGROUP: + sbuf_cat(buf, cnf->default_group ? + cnf->default_group : ""); + break; + case _UC_EXTRAGROUPS: + for (j = 0; cnf->groups != NULL && + j < (int)cnf->groups->sl_cur; j++) + sbuf_printf(buf, "%s\"%s\"", j ? + "," : "", cnf->groups->sl_str[j]); + quote = 0; + break; + case _UC_DEFAULTCLASS: + sbuf_cat(buf, cnf->default_class ? + cnf->default_class : ""); + break; + case _UC_MINUID: + sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_uid); + quote = 0; + break; + case _UC_MAXUID: + sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_uid); + quote = 0; + break; + case _UC_MINGID: + sbuf_printf(buf, "%ju", (uintmax_t)cnf->min_gid); + quote = 0; + break; + case _UC_MAXGID: + sbuf_printf(buf, "%ju", (uintmax_t)cnf->max_gid); + quote = 0; + break; + case _UC_EXPIRE: + sbuf_printf(buf, "%jd", (intmax_t)cnf->expire_days); + quote = 0; + break; + case _UC_PASSWORD: + sbuf_printf(buf, "%jd", (intmax_t)cnf->password_days); + quote = 0; + break; + case _UC_NONE: + break; + } + sbuf_finish(buf); - if (comments[i]) - fputs(comments[i], fp); + if (comments[i]) + fputs(comments[i], fp); - if (*kwds[i]) { - if (quote) - fprintf(fp, "%s = \"%s\"\n", kwds[i], val); - else - fprintf(fp, "%s = %s\n", kwds[i], val); + if (*kwds[i]) { + if (quote) + fprintf(fp, "%s = \"%s\"\n", kwds[i], + sbuf_data(buf)); + else + fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf)); #if debugging - printf("WROTE: %s = %s\n", kwds[i], val); + printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf)); #endif - } - } - return fclose(fp) != EOF; } } - return 0; + sbuf_delete(buf); + return (fclose(fp) != EOF); }