diff options
author | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
commit | b137080f19736ee33fede2e88bb54438604cf86b (patch) | |
tree | 377ac0ac449528621eb192cd245adadb5fd53668 /usr.sbin/pw | |
parent | ab21a29eb607d4dfe389b965fbdee27558e791aa (diff) | |
parent | 4a8d07956d121238d006d34ffe7d6269744e8b1a (diff) | |
download | FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz |
Merge from head@274682
Diffstat (limited to 'usr.sbin/pw')
-rw-r--r-- | usr.sbin/pw/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/pw/pw.c | 8 | ||||
-rw-r--r-- | usr.sbin/pw/pw_group.c | 14 | ||||
-rw-r--r-- | usr.sbin/pw/pw_user.c | 27 | ||||
-rw-r--r-- | usr.sbin/pw/tests/Makefile | 24 | ||||
-rw-r--r-- | usr.sbin/pw/tests/group | 3 | ||||
-rwxr-xr-x | usr.sbin/pw/tests/helper_functions.shin | 15 | ||||
-rw-r--r-- | usr.sbin/pw/tests/master.passwd | 4 | ||||
-rwxr-xr-x | usr.sbin/pw/tests/pw_delete.sh | 47 | ||||
-rwxr-xr-x | usr.sbin/pw/tests/pw_etcdir.sh | 18 | ||||
-rwxr-xr-x | usr.sbin/pw/tests/pw_lock.sh | 22 | ||||
-rwxr-xr-x | usr.sbin/pw/tests/pw_modify.sh | 80 |
12 files changed, 262 insertions, 6 deletions
diff --git a/usr.sbin/pw/Makefile b/usr.sbin/pw/Makefile index eae0b87..8c5acf9 100644 --- a/usr.sbin/pw/Makefile +++ b/usr.sbin/pw/Makefile @@ -11,4 +11,10 @@ WARNS?= 2 DPADD= ${LIBCRYPT} ${LIBUTIL} LDADD= -lcrypt -lutil +.include <src.opts.mk> + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + .include <bsd.prog.mk> diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c index b0ac728..ff48db7 100644 --- a/usr.sbin/pw/pw.c +++ b/usr.sbin/pw/pw.c @@ -98,6 +98,7 @@ main(int argc, char *argv[]) int which = -1; char *config = NULL; struct userconf *cnf; + struct stat st; static const char *opts[W_NUM][M_NUM] = { @@ -143,6 +144,13 @@ main(int argc, char *argv[]) if (argv[1][1] == 'V') { optarg = &argv[1][2]; if (*optarg == '\0') { + if (stat(argv[2], &st) != 0) + errx(EX_OSFILE, \ + "no such directory `%s'", + argv[2]); + if (!S_ISDIR(st.st_mode)) + errx(EX_OSFILE, "`%s' not a " + "directory", argv[2]); optarg = argv[2]; ++argv; --argc; diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c index 391e477..b20ce88 100644 --- a/usr.sbin/pw/pw_group.c +++ b/usr.sbin/pw/pw_group.c @@ -51,6 +51,7 @@ int pw_group(struct userconf * cnf, int mode, struct cargs * args) { int rc; + struct carg *a_newname = getarg(args, 'l'); struct carg *a_name = getarg(args, 'n'); struct carg *a_gid = getarg(args, 'g'); struct carg *arg; @@ -66,6 +67,11 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args) NULL }; + if (a_gid != NULL) { + if (strspn(a_gid->val, "0123456789") != strlen(a_gid->val)) + errx(EX_USAGE, "-g expects a number"); + } + if (mode == M_LOCK || mode == M_UNLOCK) errx(EX_USAGE, "'lock' command is not available for groups"); @@ -140,8 +146,8 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args) if (a_gid) grp->gr_gid = (gid_t) atoi(a_gid->val); - if ((arg = getarg(args, 'l')) != NULL) - grp->gr_name = pw_checkname((u_char *)arg->val, 0); + if (a_newname != NULL) + grp->gr_name = pw_checkname((u_char *)a_newname->val, 0); } else { if (a_name == NULL) /* Required */ errx(EX_DATAERR, "group name required"); @@ -270,8 +276,10 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args) warn("group update"); return EX_IOERR; } + + arg = a_newname != NULL ? a_newname : a_name; /* grp may have been invalidated */ - if ((grp = GETGRNAM(a_name->val)) == NULL) + if ((grp = GETGRNAM(arg->val)) == NULL) errx(EX_SOFTWARE, "group disappeared during update"); pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid); diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c index 36c5d9d..483148a 100644 --- a/usr.sbin/pw/pw_user.c +++ b/usr.sbin/pw/pw_user.c @@ -321,6 +321,9 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) (a_uid = a_name)->ch = 'u'; a_name = NULL; } + } else { + if (strspn(a_uid->val, "0123456789") != strlen(a_uid->val)) + errx(EX_USAGE, "-u expects a number"); } /* @@ -615,7 +618,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * 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) + if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) warn("setting crypt(3) format"); login_close(lc); pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); @@ -690,7 +693,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) } else { lc = login_getpwclass(pwd); if (lc == NULL || - login_setcryptfmt(lc, "md5", NULL) == NULL) + login_setcryptfmt(lc, "sha512", NULL) == NULL) warn("setting crypt(3) format"); login_close(lc); pwd->pw_passwd = pw_pwcrypt(line); @@ -751,7 +754,25 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args) */ if (mode == M_ADD || getarg(args, 'G') != NULL) { - int i; + int i, j; + /* First remove the user from all group */ + SETGRENT(); + while ((grp = GETGRENT()) != NULL) { + char group[MAXLOGNAME]; + if (grp->gr_mem == NULL) + continue; + for (i = 0; grp->gr_mem[i] != NULL; i++) { + if (strcmp(grp->gr_mem[i] , pwd->pw_name) != 0) + continue; + for (j = i; grp->gr_mem[j] != NULL ; j++) + grp->gr_mem[j] = grp->gr_mem[j+1]; + strlcpy(group, grp->gr_name, MAXLOGNAME); + chggrent(group, grp); + } + } + ENDGRENT(); + + /* now add to group where needed */ for (i = 0; cnf->groups[i] != NULL; i++) { grp = GETGRNAM(cnf->groups[i]); grp = gr_add(grp, pwd->pw_name); diff --git a/usr.sbin/pw/tests/Makefile b/usr.sbin/pw/tests/Makefile new file mode 100644 index 0000000..6bc9433 --- /dev/null +++ b/usr.sbin/pw/tests/Makefile @@ -0,0 +1,24 @@ +# $FreeBSD$ + +TESTSRC= ${.CURDIR}/../../../contrib/netbsd-tests/usr.sbin/useradd +.PATH: ${TESTSRC} + +TESTSDIR= ${TESTSBASE}/usr.sbin/pw + +ATF_TESTS_SH= pw_delete pw_lock pw_modify pw_etcdir + +TEST_METADATA.pw_delete+= required_user="root" +TEST_METADATA.pw_modify+= required_user="root" + +FILES= group helper_functions.shin master.passwd +FILESDIR= ${TESTSDIR} + +ATF_TESTS_SH+= pw_test +# - user{add,del} does not exist on FreeBSD; use pw user{add,del} instead +# - The command passes on FreeBSD +ATF_TESTS_SH_SED_pw_test= -e 's/useradd /pw useradd /' +ATF_TESTS_SH_SED_pw_test+= -e 's/userdel /pw userdel /' +ATF_TESTS_SH_SED_pw_test+= -e '/atf_expect_fail "PR bin\/39546"/d' +ATF_TESTS_SH_SRC_pw_test= t_useradd.sh + +.include <bsd.test.mk> diff --git a/usr.sbin/pw/tests/group b/usr.sbin/pw/tests/group new file mode 100644 index 0000000..620c588 --- /dev/null +++ b/usr.sbin/pw/tests/group @@ -0,0 +1,3 @@ +# $FreeBSD$ +# +wheel:*:0:root diff --git a/usr.sbin/pw/tests/helper_functions.shin b/usr.sbin/pw/tests/helper_functions.shin new file mode 100755 index 0000000..f87b1e7 --- /dev/null +++ b/usr.sbin/pw/tests/helper_functions.shin @@ -0,0 +1,15 @@ +# $FreeBSD$ + +# Workdir to run tests in +TESTDIR=$(atf_get_srcdir) + +# Populate the files pw needs to use into $HOME/etc +populate_etc_skel() { + cp ${TESTDIR}/master.passwd ${HOME} || \ + atf_fail "Populating master.passwd in ${HOME}" + cp ${TESTDIR}/group ${HOME} || atf_fail "Populating group in ${HOME}" + + # Generate the passwd file + pwd_mkdb -p -d ${HOME} ${HOME}/master.passwd || \ + atf_fail "generate passwd from master.passwd" +} diff --git a/usr.sbin/pw/tests/master.passwd b/usr.sbin/pw/tests/master.passwd new file mode 100644 index 0000000..f7dc837 --- /dev/null +++ b/usr.sbin/pw/tests/master.passwd @@ -0,0 +1,4 @@ +# $FreeBSD$ +# +root:*:0:0::0:0:Charlie &:/root:/bin/csh +toor:*:0:0::0:0:Bourne-again Superuser:/root: diff --git a/usr.sbin/pw/tests/pw_delete.sh b/usr.sbin/pw/tests/pw_delete.sh new file mode 100755 index 0000000..02a9ade --- /dev/null +++ b/usr.sbin/pw/tests/pw_delete.sh @@ -0,0 +1,47 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + +# Test that a user can be deleted when another user is part of this +# user's default group and does not go into an infinate loop. +# PR: 191427 +atf_test_case rmuser_seperate_group cleanup +rmuser_seperate_group_head() { + atf_set "timeout" "30" +} +rmuser_seperate_group_body() { + populate_etc_skel + pw -V ${HOME} useradd test || atf_fail "Creating test user" + pw -V ${HOME} groupmod test -M 'test,root' || \ + atf_fail "Modifying the group" + pw -V ${HOME} userdel test || atf_fail "Delete the test user" +} + +atf_test_case group_do_not_delete_wheel_if_group_unknown +group_do_not_delete_wheel_if_group_unknown_head() { + atf_set "descr" "Make sure we do not consider gid 0 an unknown group" +} + +group_do_not_delete_wheel_if_group_unknown_body() { + populate_etc_skel + atf_check -s exit:0 -o inline:"wheel:*:0:root\n" -x pw -V ${HOME} groupshow wheel + atf_check -e inline:"pw: -g expects a number\n" -s exit:64 -x pw -V ${HOME} groupdel -g I_do_not_exist + atf_check -s exit:0 -o inline:"wheel:*:0:root\n" -x pw -V ${HOME} groupshow wheel +} + +atf_test_case user_do_not_try_to_delete_root_if_user_unknown +user_do_not_try_to_delete_root_if_user_unknown_head() { + atf_set "descr" "Make sure not to try to remove root if deleting an unknown user" +} + +user_do_not_try_to_delete_root_if_user_unknown_body() { + populate_etc_skel + atf_check -e inline:"pw: -u expects a number\n" -s exit:64 -x pw -V ${HOME} userdel -u plop +} + +atf_init_test_cases() { + atf_add_test_case rmuser_seperate_group + atf_add_test_case group_do_not_delete_wheel_if_group_unknown + atf_add_test_case user_do_not_try_to_delete_root_if_user_unknown +} diff --git a/usr.sbin/pw/tests/pw_etcdir.sh b/usr.sbin/pw/tests/pw_etcdir.sh new file mode 100755 index 0000000..b237789 --- /dev/null +++ b/usr.sbin/pw/tests/pw_etcdir.sh @@ -0,0 +1,18 @@ +# $FreeBSD$ + +# When the '-V directory' option is provided, the directory must exist +atf_test_case etcdir_must_exist +etcdir_must_exist_head() { + atf_set "descr" "When the '-V directory' option is provided, the directory must exist" +} + +etcdir_must_exist_body() { + local fakedir="/this_directory_does_not_exist" + atf_check -e inline:"pw: no such directory \`$fakedir'\n" \ + -s exit:72 -x pw -V ${fakedir} usershow root +} + +atf_init_test_cases() { + atf_add_test_case etcdir_must_exist +} + diff --git a/usr.sbin/pw/tests/pw_lock.sh b/usr.sbin/pw/tests/pw_lock.sh new file mode 100755 index 0000000..070a6f9 --- /dev/null +++ b/usr.sbin/pw/tests/pw_lock.sh @@ -0,0 +1,22 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + +# Test locking and unlocking a user account +atf_test_case user_locking cleanup +user_locking_body() { + populate_etc_skel + pw -V ${HOME} useradd test || atf_fail "Creating test user" + pw -V ${HOME} lock test || atf_fail "Locking the user" + atf_check -s exit:0 -o match:"^test:\*LOCKED\*\*:1001:" \ + grep "^test:\*LOCKED\*\*:1001:" $HOME/master.passwd + pw -V ${HOME} unlock test || atf_fail "Locking the user" + atf_check -s exit:0 -o match:"^test:\*:1001:" \ + grep "^test:\*:1001:" $HOME/master.passwd +} + + +atf_init_test_cases() { + atf_add_test_case user_locking +} diff --git a/usr.sbin/pw/tests/pw_modify.sh b/usr.sbin/pw/tests/pw_modify.sh new file mode 100755 index 0000000..b81f105 --- /dev/null +++ b/usr.sbin/pw/tests/pw_modify.sh @@ -0,0 +1,80 @@ +# $FreeBSD$ + +# Import helper functions +. $(atf_get_srcdir)/helper_functions.shin + + +# Test adding & removing a user from a group +atf_test_case groupmod_user +groupmod_user_body() { + populate_etc_skel + atf_check -s exit:0 pw -V ${HOME} addgroup test + atf_check -s exit:0 pw -V ${HOME} groupmod test -m root + atf_check -s exit:0 -o match:"^test:\*:1001:root$" \ + grep "^test:\*:.*:root$" $HOME/group + atf_check -s exit:0 pw -V ${HOME} groupmod test -d root + atf_check -s exit:0 -o match:"^test:\*:1001:$" \ + grep "^test:\*:.*:$" $HOME/group +} + + +# Test adding and removing a user that does not exist +atf_test_case groupmod_invalid_user +groupmod_invalid_user_body() { + populate_etc_skel + atf_check -s exit:0 pw -V ${HOME} addgroup test + atf_check -s exit:67 -e match:"does not exist" pw -V ${HOME} groupmod test -m foo + atf_check -s exit:0 pw -V ${HOME} groupmod test -d foo +} + +atf_test_case groupmod_bug_193704 +groupmod_bug_193704_head() { + atf_set "descr" "Regression test for the #193704 bug" +} +groupmod_bug_193704_body() { + populate_etc_skel + atf_check -s exit:0 -x pw -V ${HOME} groupadd test + atf_check -s exit:0 -x pw -V ${HOME} groupmod test -l newgroupname + atf_check -s exit:65 -e match:"^pw: unknown group" -x pw -V ${HOME} groupshow test +} + +atf_test_case usermod_bug_185666 +usermod_bug_185666_head() { + atf_set "descr" "Regression test for the #185666 bug" +} + +usermod_bug_185666_body() { + populate_etc_skel + atf_check -s exit:0 -x pw -V ${HOME} useradd testuser + atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup + atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup2 + atf_check -s exit:0 -x pw -V ${HOME} usermod testuser -G testgroup + atf_check -o inline:"testuser:*:1001:\n" -x pw -V${HOME} groupshow testuser + atf_check -o inline:"testgroup:*:1002:testuser\n" -x pw -V ${HOME} groupshow testgroup + atf_check -o inline:"testgroup2:*:1003:\n" -x pw -V${HOME} groupshow testgroup2 + atf_check -s exit:0 -x pw -V ${HOME} usermod testuser -G testgroup2 + atf_check -o inline:"testuser:*:1001:\n" -x pw -V ${HOME} groupshow testuser + atf_check -o inline:"testgroup:*:1002:\n" -x pw -V ${HOME} groupshow testgroup + atf_check -o inline:"testgroup2:*:1003:testuser\n" -x pw -V ${HOME} groupshow testgroup2 +} + +atf_test_case do_not_duplicate_group_on_gid_change +do_not_duplicate_group_on_gid_change_head() { + atf_set "descr" "Do not duplicate group on gid change" +} + +do_not_duplicate_group_on_gid_change_body() { + populate_etc_skel + atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup + atf_check -s exit:0 -x pw -V ${HOME} groupmod testgroup -g 12345 + # use grep to see if the entry has not be duplicated + atf_check -o inline:"testgroup:*:12345:\n" -s exit:0 -x grep "^testgroup" ${HOME}/group +} + +atf_init_test_cases() { + atf_add_test_case groupmod_user + atf_add_test_case groupmod_invalid_user + atf_add_test_case groupmod_bug_193704 + atf_add_test_case usermod_bug_185666 + atf_add_test_case do_not_duplicate_group_on_gid_change +} |