Validate input of pw usermod -h and pwusermod -H

Push the code that set the password into a separate function to improve
readability

Add regression tests about pw usermod -h and pw usermod -H
This commit is contained in:
Baptiste Daroussin 2015-07-04 15:27:04 +00:00
parent ee5f66f820
commit 11621f9650
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285133
4 changed files with 132 additions and 60 deletions

View File

@ -137,6 +137,7 @@ main(int argc, char *argv[])
relocated = nis = false;
memset(&conf, 0, sizeof(conf));
strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
conf.fd = -1;
LIST_INIT(&arglist);
@ -280,6 +281,35 @@ main(int argc, char *argv[])
errx(EX_USAGE, "Bad id '%s': %s", optarg,
errstr);
break;
case 'H':
if (conf.fd != -1)
errx(EX_USAGE, "'-h' and '-H' are mutually "
"exclusive options");
conf.precrypted = true;
if (strspn(optarg, "0123456789") != strlen(optarg))
errx(EX_USAGE, "'-H' expects a file descriptor");
conf.fd = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL)
errx(EX_USAGE, "Bad file descriptor '%s': %s",
optarg, errstr);
break;
case 'h':
if (conf.fd != -1)
errx(EX_USAGE, "'-h' and '-H' are mutually "
"exclusive options");
if (strcmp(optarg, "-") == 0)
conf.fd = '-';
else if (strspn(optarg, "0123456789") == strlen(optarg)) {
conf.fd = strtonum(optarg, 0, INT_MAX, &errstr);
if (errstr != NULL)
errx(EX_USAGE, "'-h' expects a "
"file descriptor or '-'");
} else
errx(EX_USAGE, "'-h' expects a file "
"descriptor or '-'");
break;
case 'o':
conf.checkduplicate = true;
break;

View File

@ -86,6 +86,67 @@ create_and_populate_homedir(int mode, struct passwd *pwd)
pwd->pw_uid, pwd->pw_dir);
}
static int
set_passwd(struct passwd *pwd, struct carg *arg, bool update)
{
int b, istty;
struct termios t, n;
login_cap_t *lc;
char line[_PASSWORD_LEN+1];
char *p;
if (conf.fd == '-') {
if (!pwd->pw_passwd || *pwd->pw_passwd != '*') {
pwd->pw_passwd = "*"; /* No access */
return (1);
}
return (0);
}
if ((istty = isatty(conf.fd))) {
if (tcgetattr(conf.fd, &t) == -1)
istty = 0;
else {
n.c_lflag &= ~(ECHO);
tcsetattr(conf.fd, TCSANOW, &n);
printf("%s%spassword for user %s:",
update ? "new " : "",
conf.precrypted ? "encrypted " : "",
pwd->pw_name);
fflush(stdout);
}
}
b = read(conf.fd, line, sizeof(line) - 1);
if (istty) { /* Restore state */
tcsetattr(conf.fd, TCSANOW, &t);
fputc('\n', stdout);
fflush(stdout);
}
if (b < 0)
err(EX_IOERR, "-%c file descriptor",
conf.precrypted ? 'H' : 'h');
line[b] = '\0';
if ((p = strpbrk(line, "\r\n")) != NULL)
*p = '\0';
if (!*line)
errx(EX_DATAERR, "empty password read on file descriptor %d",
conf.fd);
if (conf.precrypted) {
if (strchr(line, ':') != NULL)
return EX_DATAERR;
pwd->pw_passwd = line;
} else {
lc = login_getpwclass(pwd);
if (lc == NULL ||
login_setcryptfmt(lc, "sha512", NULL) == NULL)
warn("setting crypt(3) format");
login_close(lc);
pwd->pw_passwd = pw_pwcrypt(line);
}
return (1);
}
/*-
* -C config configuration file
* -q quiet operation
@ -529,66 +590,8 @@ pw_user(int mode, char *name, long id, struct cargs * args)
}
}
if ((arg = getarg(args, 'h')) != NULL ||
(arg = getarg(args, 'H')) != NULL) {
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 precrypt = (arg->ch == 'H');
int b;
int istty = isatty(fd);
struct termios t;
login_cap_t *lc;
if (istty) {
if (tcgetattr(fd, &t) == -1)
istty = 0;
else {
struct termios n = t;
/* Disable echo */
n.c_lflag &= ~(ECHO);
tcsetattr(fd, TCSANOW, &n);
printf("%s%spassword for user %s:",
(mode == M_UPDATE) ? "new " : "",
precrypt ? "encrypted " : "",
pwd->pw_name);
fflush(stdout);
}
}
b = read(fd, line, sizeof(line) - 1);
if (istty) { /* Restore state */
tcsetattr(fd, TCSANOW, &t);
fputc('\n', stdout);
fflush(stdout);
}
if (b < 0)
err(EX_IOERR, "-%c file descriptor",
precrypt ? 'H' : 'h');
line[b] = '\0';
if ((p = strpbrk(line, "\r\n")) != NULL)
*p = '\0';
if (!*line)
errx(EX_DATAERR, "empty password read on file descriptor %d", fd);
if (precrypt) {
if (strchr(line, ':') != NULL)
return EX_DATAERR;
pwd->pw_passwd = line;
} else {
lc = login_getpwclass(pwd);
if (lc == NULL ||
login_setcryptfmt(lc, "sha512", NULL) == NULL)
warn("setting crypt(3) format");
login_close(lc);
pwd->pw_passwd = pw_pwcrypt(line);
}
edited = 1;
}
}
if (conf.fd != -1)
edited = set_passwd(pwd, arg, mode == M_UPDATE);
/*
* Special case: -N only displays & exits

View File

@ -85,10 +85,12 @@ struct pwconf {
char etcpath[MAXPATHLEN];
char *newname;
char *config;
int fd;
bool dryrun;
bool pretty;
bool v7;
bool checkduplicate;
bool precrypted;
struct userconf *userconf;
};

View File

@ -119,6 +119,41 @@ user_mod_rename_too_long_body() {
-l name_very_very_very_very_very_long
}
atf_test_case user_mod_h
user_mod_h_body() {
populate_etc_skel
atf_check -s exit:0 ${PW} useradd foo
atf_check -s exit:0 ${PW} usermod foo -h 0 <<- EOF
$(echo a)
EOF
atf_check -s exit:0 -o not-match:"^foo:\*:.*" \
grep "^foo" ${HOME}/master.passwd
atf_check -s exit:0 ${PW} usermod foo -h - <<- EOF
$(echo b)
EOF
atf_check -s exit:0 -o match:"^foo:\*:.*" \
grep "^foo" ${HOME}/master.passwd
atf_check -e inline:"pw: '-h' expects a file descriptor or '-'\n" \
-s exit:64 ${PW} usermod foo -h a <<- EOF
$(echo a)
EOF
}
atf_test_case user_mod_H
user_mod_H_body() {
populate_etc_skel
atf_check -s exit:0 ${PW} useradd foo
atf_check -s exit:0 ${PW} usermod foo -H 0 <<- EOF
$(echo a)
EOF
atf_check -s exit:0 -o match:"^foo:a:.*" \
grep "^foo" ${HOME}/master.passwd
atf_check -s exit:64 -e inline:"pw: '-H' expects a file descriptor\n" \
${PW} usermod foo -H -
}
atf_init_test_cases() {
atf_add_test_case user_mod
atf_add_test_case user_mod_noupdate
@ -130,4 +165,6 @@ atf_init_test_cases() {
atf_add_test_case user_mod_name_noupdate
atf_add_test_case user_mod_rename
atf_add_test_case user_mod_rename_too_long
atf_add_test_case user_mod_h
atf_add_test_case user_mod_H
}