#include <sys/resource.h>
#include <unistd.h>
#include <utmp.h>
+#include <login_cap.h>
#if defined(USE_MD5RAND)
#include <md5.h>
#endif
#define LOGNAMESIZE (MAXLOGNAME-1)
#endif
-static int randinit;
static char locked_str[] = "*LOCKED*";
static int print_user(struct passwd * pwd, int pretty, int v7);
static char *pw_password(struct userconf * cnf, struct cargs * args, char const * user);
static char *shell_path(char const * path, char *shells[], char *sh);
static void rmat(uid_t uid);
-static void rmskey(char const * name);
+static void rmopie(char const * name);
/*-
* -C config configuration file
struct group *grp;
struct stat st;
char line[_PASSWORD_LEN+1];
+ FILE *fp;
static struct passwd fakeuser =
{
cnf->password_days = atoi(arg->val);
if ((arg = getarg(args, 'g')) != NULL) {
- p = arg->val;
- if ((grp = GETGRNAM(p)) == NULL) {
- if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL)
- errx(EX_NOUSER, "group `%s' does not exist", p);
+ if (!*(p = arg->val)) /* Handle empty group list specially */
+ cnf->default_group = "";
+ else {
+ if ((grp = GETGRNAM(p)) == NULL) {
+ if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL)
+ errx(EX_NOUSER, "group `%s' does not exist", p);
+ }
+ cnf->default_group = newstr(grp->gr_name);
}
- cnf->default_group = newstr(grp->gr_name);
}
if ((arg = getarg(args, 'L')) != NULL)
cnf->default_class = pw_checkname((u_char *)arg->val, 0);
if ((arg = getarg(args, 's')) != NULL)
cnf->shell_default = arg->val;
+ if ((arg = getarg(args, 'w')) != NULL)
+ cnf->default_password = boolean_val(arg->val, cnf->default_password);
if (mode == M_ADD && getarg(args, 'D')) {
if (getarg(args, 'n') != NULL)
errx(EX_DATAERR, "can't combine `-D' with `-n name'");
if ((p = strtok(NULL, " ,\t")) == NULL || (cnf->max_gid = (gid_t) atoi(p)) < cnf->min_gid)
cnf->max_gid = 32000;
}
- if ((arg = getarg(args, 'w')) != NULL)
- cnf->default_password = boolean_val(arg->val, cnf->default_password);
arg = getarg(args, 'C');
if (write_userconfig(arg ? arg->val : NULL))
if (!PWALTDIR()) {
/*
- * Remove skey record from /etc/skeykeys
+ * Remove opie record from /etc/opiekeys
*/
- rmskey(pwd->pw_name);
+ rmopie(pwd->pw_name);
/*
* Remove crontabs
}
if ((arg = getarg(args, 'd')) != NULL) {
+ edited = strcmp(pwd->pw_dir, arg->val) != 0;
if (stat(pwd->pw_dir = arg->val, &st) == -1) {
if (getarg(args, 'm') == NULL && strcmp(pwd->pw_dir, "/nonexistent") != 0)
warnx("WARNING: home `%s' does not exist", pwd->pw_dir);
}
if ((arg = getarg(args, 'w')) != NULL && getarg(args, 'h') == NULL) {
+ login_cap_t *lc;
+
+ lc = login_getpwclass(pwd);
+ if (lc == NULL ||
+ login_setcryptfmt(lc, "md5", NULL) == NULL)
+ warn("setting crypt(3) format");
+ login_close(lc);
pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
edited = 1;
}
} else {
+ login_cap_t *lc;
/*
* Add code
pwd = &fakeuser;
pwd->pw_name = a_name->val;
pwd->pw_class = cnf->default_class ? cnf->default_class : "";
- pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
pwd->pw_uid = pw_uidpolicy(cnf, args);
pwd->pw_gid = pw_gidpolicy(cnf, args, pwd->pw_name, (gid_t) pwd->pw_uid);
pwd->pw_change = pw_pwdpolicy(cnf, args);
pwd->pw_expire = pw_exppolicy(cnf, args);
pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
+ lc = login_getpwclass(pwd);
+ if (lc == NULL || login_setcryptfmt(lc, "md5", NULL) == NULL)
+ warn("setting crypt(3) format");
+ login_close(lc);
+ pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
edited = 1;
if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0)
}
if ((arg = getarg(args, 'h')) != NULL) {
- if (strcmp(arg->val, "-") == 0)
- pwd->pw_passwd = "*"; /* No access */
- else {
+ if (strcmp(arg->val, "-") == 0) {
+ if (!pwd->pw_passwd || *pwd->pw_passwd != '*') {
+ pwd->pw_passwd = "*"; /* No access */
+ edited = 1;
+ }
+ } else {
int fd = atoi(arg->val);
int b;
int istty = isatty(fd);
struct termios t;
+ login_cap_t *lc;
if (istty) {
if (tcgetattr(fd, &t) == -1)
*p = '\0';
if (!*line)
errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
+ lc = login_getpwclass(pwd);
+ if (lc == NULL ||
+ login_setcryptfmt(lc, "md5", NULL) == NULL)
+ warn("setting crypt(3) format");
+ login_close(lc);
pwd->pw_passwd = pw_pwcrypt(line);
edited = 1;
}
errx(EX_NOUSER, "user '%s' disappeared during update", a_name->val);
grp = GETGRGID(pwd->pw_gid);
- pw_log(cnf, mode, W_USER, "%s(%ld):%s(%d):%s:%s:%s",
+ pw_log(cnf, mode, W_USER, "%s(%ld):%s(%ld):%s:%s:%s",
pwd->pw_name, (long) pwd->pw_uid,
grp ? grp->gr_name : "unknown", (long) (grp ? grp->gr_gid : -1),
pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
* doesn't hurt anything to create the empty mailfile
*/
if (mode == M_ADD) {
- FILE *fp;
-
if (!PWALTDIR()) {
sprintf(line, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
close(open(line, O_RDWR | O_CREAT, 0600)); /* Preserve contents &
* mtime */
chown(line, pwd->pw_uid, pwd->pw_gid);
-
- /*
- * Send mail to the new user as well, if we are asked to
- */
- if (cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) {
- FILE *pfp = popen(_PATH_SENDMAIL " -t", "w");
-
- if (pfp == NULL)
- warn("sendmail");
- else {
- fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name);
- while (fgets(line, sizeof(line), fp) != NULL) {
- /* Do substitutions? */
- fputs(line, pfp);
- }
- pclose(pfp);
- pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent",
- pwd->pw_name, (long) pwd->pw_uid);
- }
- fclose(fp);
- }
}
}
/*
- * Finally, let's create and populate the user's home directory. Note
+ * Let's create and populate the user's home directory. Note
* that this also `works' for editing users if -m is used, but
* existing files will *not* be overwritten.
*/
pwd->pw_name, (long) pwd->pw_uid, pwd->pw_dir);
}
+
+ /*
+ * Finally, send mail to the new user as well, if we are asked to
+ */
+ if (mode == M_ADD && !PWALTDIR() && cnf->newmail && *cnf->newmail && (fp = fopen(cnf->newmail, "r")) != NULL) {
+ FILE *pfp = popen(_PATH_SENDMAIL " -t", "w");
+
+ if (pfp == NULL)
+ warn("sendmail");
+ else {
+ fprintf(pfp, "From: root\n" "To: %s\n" "Subject: Welcome!\n\n", pwd->pw_name);
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ /* Do substitutions? */
+ fputs(line, pfp);
+ }
+ pclose(pfp);
+ pw_log(cnf, mode, W_USER, "%s(%ld) new user mail sent",
+ pwd->pw_name, (long) pwd->pw_uid);
+ }
+ fclose(fp);
+ }
+
return EXIT_SUCCESS;
}
if ((grp = GETGRNAM(nam)) != NULL)
gid = grp->gr_gid;
}
- a_gid = grpargs.lh_first;
+ a_gid = LIST_FIRST(&grpargs);
while (a_gid != NULL) {
- struct carg *t = a_gid->list.le_next;
+ struct carg *t = LIST_NEXT(a_gid, list);
LIST_REMOVE(a_gid, list);
a_gid = t;
}
/*
* Calculate a salt value
*/
- if (!randinit) {
- randinit = 1;
-#ifdef __FreeBSD__
- srandomdev();
-#else
- srandom((unsigned long) (time(NULL) ^ getpid()));
-#endif
- }
for (i = 0; i < 8; i++)
- salt[i] = chars[random() % 63];
+ salt[i] = chars[arc4random() % 63];
salt[i] = '\0';
return strcpy(buf, crypt(password, salt));
MD5Update (&md5_ctx, (u_char*)&tv, sizeof tv);
} while (n++<20 || tv.tv_usec-tvo.tv_usec<100*1000);
MD5Final (ubuf, &md5_ctx);
- memcpy(buf+i, ubuf, MIN(16, len-n));
+ memcpy(buf+i, ubuf, MIN(16, len-i));
}
return buf;
}
{
int i;
+ srandomdev();
for (i = 0; i < len; i++) {
unsigned long val = random();
/* Use all bits in the random value */
switch (cnf->default_password) {
case -1: /* Random password */
- if (!randinit) {
- randinit = 1;
-#ifdef __FreeBSD__
- srandomdev();
-#else
- srandom((unsigned long) (time(NULL) ^ getpid()));
-#endif
- }
- l = (random() % 8 + 8); /* 8 - 16 chars */
+ l = (arc4random() % 8 + 8); /* 8 - 16 chars */
pw_getrand(rndbuf, l);
for (i = 0; i < l; i++)
pwbuf[i] = chars[rndbuf[i] % (sizeof(chars)-1)];
*p = (char) toupper((unsigned char)*p);
}
if (pwd->pw_expire > (time_t)0 && (tptr = localtime(&pwd->pw_expire)) != NULL)
- strftime(acexpire, sizeof acexpire, "%a %Ef %Y %X", tptr);
+ strftime(acexpire, sizeof acexpire, "%c", tptr);
if (pwd->pw_change > (time_t)0 && (tptr = localtime(&pwd->pw_change)) != NULL)
- strftime(pwexpire, sizeof pwexpire, "%a %Ef %Y %X", tptr);
+ strftime(pwexpire, sizeof pwexpire, "%c", tptr);
printf("Login Name: %-15s #%-12ld Group: %-15s #%ld\n"
" Full Name: %s\n"
" Home: %-26.26s Class: %s\n"
char *
pw_checkname(u_char *name, int gecos)
{
- int l = 0;
- char const *notch = gecos ? ":!@" : " ,\t:+&#%$^()!@~*?<>=|\\/\"";
-
- while (name[l]) {
- if (strchr(notch, name[l]) != NULL || name[l] < ' ' || name[l] == 127 ||
- (!gecos && l==0 && name[l] == '-') || /* leading '-' */
- (!gecos && name[l] & 0x80)) /* 8-bit */
- errx(EX_DATAERR, (name[l] >= ' ' && name[l] < 127)
- ? "invalid character `%c' in field"
- : "invalid character 0x%02x in field",
- name[l]);
- ++l;
+ char showch[8];
+ u_char const *badchars, *ch, *showtype;
+ int reject;
+
+ ch = name;
+ reject = 0;
+ if (gecos) {
+ /* See if the name is valid as a gecos (comment) field. */
+ badchars = ":!@";
+ showtype = "gecos field";
+ } else {
+ /* See if the name is valid as a userid or group. */
+ badchars = " ,\t:+&#%$^()!@~*?<>=|\\/\"";
+ showtype = "userid/group name";
+ /* Userids and groups can not have a leading '-'. */
+ if (*ch == '-')
+ reject = 1;
+ }
+ if (!reject) {
+ while (*ch) {
+ if (strchr(badchars, *ch) != NULL || *ch < ' ' ||
+ *ch == 127) {
+ reject = 1;
+ break;
+ }
+ /* 8-bit characters are only allowed in GECOS fields */
+ if (!gecos && (*ch & 0x80)) {
+ reject = 1;
+ break;
+ }
+ ch++;
+ }
+ }
+ /*
+ * A `$' is allowed as the final character for userids and groups,
+ * mainly for the benefit of samba.
+ */
+ if (reject && !gecos) {
+ if (*ch == '$' && *(ch + 1) == '\0') {
+ reject = 0;
+ ch++;
+ }
+ }
+ if (reject) {
+ snprintf(showch, sizeof(showch), (*ch >= ' ' && *ch < 127)
+ ? "`%c'" : "0x%02x", *ch);
+ errx(EX_DATAERR, "invalid character %s at position %d in %s",
+ showch, (ch - name), showtype);
}
- if (!gecos && l > LOGNAMESIZE)
- errx(EX_DATAERR, "name too long `%s'", name);
+ if (!gecos && (ch - name) > LOGNAMESIZE)
+ errx(EX_DATAERR, "name too long `%s' (max is %d)", name,
+ LOGNAMESIZE);
return (char *)name;
}
}
static void
-rmskey(char const * name)
+rmopie(char const * name)
{
- static const char etcskey[] = "/etc/skeykeys";
- FILE *fp = fopen(etcskey, "r+");
+ static const char etcopie[] = "/etc/opiekeys";
+ FILE *fp = fopen(etcopie, "r+");
if (fp != NULL) {
char tmp[1024];