/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
* Copyright (C) 1996
* David L. Nugent. All rights reserved.
*
"$FreeBSD$";
#endif /* not lint */
-#include <sys/types.h>
-#include <sys/sbuf.h>
-#include <string.h>
-#include <ctype.h>
+#include <err.h>
#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
#include "pw.h"
"/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 */
+ "/var", /* 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) */
1000, 32000, /* Allowed range of uids */
1000, 32000, /* Allowed range of gids */
0, /* Days until account expires */
- 0, /* Days until password expires */
- 0 /* size of default_group array */
+ 0 /* Days until password expires */
};
static char const *comments[_UC_FIELDS] =
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;
}
char const *
boolean_str(int val)
{
- if (val == -1)
- return "random";
- else if (val == -2)
- return "none";
+ if (val == P_NO)
+ return (boolfalse[0]);
+ else if (val == P_RANDOM)
+ return ("random");
+ else if (val == P_NONE)
+ return ("none");
else
- return val ? booltrue[0] : boolfalse[0];
+ return (booltrue[0]);
}
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 *
{
FILE *fp;
char *buf, *p;
+ const char *errstr;
size_t linecap;
ssize_t linelen;
buf = NULL;
linecap = 0;
- extendarray(&config.groups, &config.numgroups, 200);
- memset(config.groups, 0, config.numgroups * sizeof(char *));
- if (file == NULL)
- file = _PATH_PW_CONF;
-
- if ((fp = fopen(file, "r")) != NULL) {
- 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;
+ if ((fp = fopen(file, "r")) == NULL)
+ return (&config);
+
+ 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;
#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_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;
+ 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:
- for (i = 0; q != NULL; q = strtok(NULL, toks)) {
- if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
- config.groups[i++] = newstr(q);
- }
- if (i > 0)
- while (i < config.numgroups)
- config.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;
+ 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))
+ ? "/var" : 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;
}
}
- if (linecap > 0)
- free(buf);
- 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 *buffp;
FILE *fp;
-
- if (file == NULL)
- file = _PATH_PW_CONF;
+ char cfgfile[MAXPATHLEN];
+ char *buf;
+ size_t sz;
+
+ 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)
return (0);
close(fd);
return (0);
}
-
- buf = sbuf_new_auto();
+
+ sz = 0;
+ buf = NULL;
+ buffp = open_memstream(&buf, &sz);
+ if (buffp == NULL)
+ err(EXIT_FAILURE, "open_memstream()");
+
for (i = _UC_NONE; i < _UC_FIELDS; i++) {
int quote = 1;
- sbuf_clear(buf);
+ if (buf != NULL)
+ memset(buf, 0, sz);
+ rewind(buffp);
switch (i) {
case _UC_DEFAULTPWD:
- sbuf_cat(buf, boolean_str(config.default_password));
+ fputs(boolean_str(cnf->default_password), buffp);
break;
case _UC_REUSEUID:
- sbuf_cat(buf, boolean_str(config.reuse_uids));
+ fputs(boolean_str(cnf->reuse_uids), buffp);
break;
case _UC_REUSEGID:
- sbuf_cat(buf, boolean_str(config.reuse_gids));
+ fputs(boolean_str(cnf->reuse_gids), buffp);
break;
case _UC_NISPASSWD:
- sbuf_cat(buf, config.nispasswd ? config.nispasswd :
- "");
+ fputs(cnf->nispasswd ? cnf->nispasswd : "", buffp);
quote = 0;
break;
case _UC_DOTDIR:
- sbuf_cat(buf, config.dotdir ? config.dotdir :
- boolean_str(0));
+ fputs(cnf->dotdir ? cnf->dotdir : boolean_str(0),
+ buffp);
break;
case _UC_NEWMAIL:
- sbuf_cat(buf, config.newmail ? config.newmail :
- boolean_str(0));
+ fputs(cnf->newmail ? cnf->newmail : boolean_str(0),
+ buffp);
break;
case _UC_LOGFILE:
- sbuf_cat(buf, config.logfile ? config.logfile :
- boolean_str(0));
+ fputs(cnf->logfile ? cnf->logfile : boolean_str(0),
+ buffp);
break;
case _UC_HOMEROOT:
- sbuf_cat(buf, config.home);
+ fputs(cnf->home, buffp);
break;
case _UC_HOMEMODE:
- sbuf_printf(buf, "%04o", config.homemode);
+ fprintf(buffp, "%04o", cnf->homemode);
quote = 0;
break;
case _UC_SHELLPATH:
- sbuf_cat(buf, config.shelldir);
+ fputs(cnf->shelldir, buffp);
break;
case _UC_SHELLS:
for (j = 0; j < _UC_MAXSHELLS &&
system_shells[j] != NULL; j++)
- sbuf_printf(buf, "%s\"%s\"", j ?
+ fprintf(buffp, "%s\"%s\"", j ?
"," : "", system_shells[j]);
quote = 0;
break;
case _UC_DEFAULTSHELL:
- sbuf_cat(buf, config.shell_default ?
- config.shell_default : bourne_shell);
+ fputs(cnf->shell_default ? cnf->shell_default :
+ bourne_shell, buffp);
break;
case _UC_DEFAULTGROUP:
- sbuf_cat(buf, config.default_group ?
- config.default_group : "");
+ fputs(cnf->default_group ? cnf->default_group : "",
+ buffp);
break;
case _UC_EXTRAGROUPS:
- extendarray(&config.groups, &config.numgroups, 200);
- for (j = 0; j < config.numgroups &&
- config.groups[j] != NULL; j++)
- sbuf_printf(buf, "%s\"%s\"", j ?
- "," : "", config.groups[j]);
+ for (j = 0; cnf->groups != NULL &&
+ j < (int)cnf->groups->sl_cur; j++)
+ fprintf(buffp, "%s\"%s\"", j ?
+ "," : "", cnf->groups->sl_str[j]);
quote = 0;
break;
case _UC_DEFAULTCLASS:
- sbuf_cat(buf, config.default_class ?
- config.default_class : "");
+ fputs(cnf->default_class ? cnf->default_class : "",
+ buffp);
break;
case _UC_MINUID:
- sbuf_printf(buf, "%lu", (unsigned long) config.min_uid);
+ fprintf(buffp, "%ju", (uintmax_t)cnf->min_uid);
quote = 0;
break;
case _UC_MAXUID:
- sbuf_printf(buf, "%lu", (unsigned long) config.max_uid);
+ fprintf(buffp, "%ju", (uintmax_t)cnf->max_uid);
quote = 0;
break;
case _UC_MINGID:
- sbuf_printf(buf, "%lu", (unsigned long) config.min_gid);
+ fprintf(buffp, "%ju", (uintmax_t)cnf->min_gid);
quote = 0;
break;
case _UC_MAXGID:
- sbuf_printf(buf, "%lu", (unsigned long) config.max_gid);
+ fprintf(buffp, "%ju", (uintmax_t)cnf->max_gid);
quote = 0;
break;
case _UC_EXPIRE:
- sbuf_printf(buf, "%d", config.expire_days);
+ fprintf(buffp, "%jd", (intmax_t)cnf->expire_days);
quote = 0;
break;
case _UC_PASSWORD:
- sbuf_printf(buf, "%d", config.password_days);
+ fprintf(buffp, "%jd", (intmax_t)cnf->password_days);
quote = 0;
break;
case _UC_NONE:
break;
}
- sbuf_finish(buf);
+ fflush(buffp);
if (comments[i])
fputs(comments[i], fp);
if (*kwds[i]) {
if (quote)
- fprintf(fp, "%s = \"%s\"\n", kwds[i],
- sbuf_data(buf));
+ fprintf(fp, "%s = \"%s\"\n", kwds[i], buf);
else
- fprintf(fp, "%s = %s\n", kwds[i], sbuf_data(buf));
+ fprintf(fp, "%s = %s\n", kwds[i], buf);
#if debugging
- printf("WROTE: %s = %s\n", kwds[i], sbuf_data(buf));
+ printf("WROTE: %s = %s\n", kwds[i], buf);
#endif
}
}
- sbuf_delete(buf);
+ fclose(buffp);
+ free(buf);
return (fclose(fp) != EOF);
}