#include <sys/capsicum.h>
#include <sys/nv.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libcasper.h>
#include <casper/cap_pwd.h>
static int ntest = 1;
#define CHECK(expr) do { \
if ((expr)) \
printf("ok %d # %s:%u\n", ntest, __FILE__, __LINE__); \
else \
printf("not ok %d # %s:%u\n", ntest, __FILE__, __LINE__); \
fflush(stdout); \
ntest++; \
} while (0)
#define CHECKX(expr) do { \
if ((expr)) { \
printf("ok %d # %s:%u\n", ntest, __FILE__, __LINE__); \
} else { \
printf("not ok %d # %s:%u\n", ntest, __FILE__, __LINE__); \
exit(1); \
} \
fflush(stdout); \
ntest++; \
} while (0)
#define UID_ROOT 0
#define UID_OPERATOR 2
#define GETPWENT0 0x0001
#define GETPWENT1 0x0002
#define GETPWENT2 0x0004
#define GETPWENT (GETPWENT0 | GETPWENT1 | GETPWENT2)
#define GETPWENT_R0 0x0008
#define GETPWENT_R1 0x0010
#define GETPWENT_R2 0x0020
#define GETPWENT_R (GETPWENT_R0 | GETPWENT_R1 | GETPWENT_R2)
#define GETPWNAM 0x0040
#define GETPWNAM_R 0x0080
#define GETPWUID 0x0100
#define GETPWUID_R 0x0200
static bool
passwd_compare(const struct passwd *pwd0, const struct passwd *pwd1)
{
if (pwd0 == NULL && pwd1 == NULL)
return (true);
if (pwd0 == NULL || pwd1 == NULL)
return (false);
if (strcmp(pwd0->pw_name, pwd1->pw_name) != 0)
return (false);
if (pwd0->pw_passwd != NULL || pwd1->pw_passwd != NULL) {
if (pwd0->pw_passwd == NULL || pwd1->pw_passwd == NULL)
return (false);
if (strcmp(pwd0->pw_passwd, pwd1->pw_passwd) != 0)
return (false);
}
if (pwd0->pw_uid != pwd1->pw_uid)
return (false);
if (pwd0->pw_gid != pwd1->pw_gid)
return (false);
if (pwd0->pw_change != pwd1->pw_change)
return (false);
if (pwd0->pw_class != NULL || pwd1->pw_class != NULL) {
if (pwd0->pw_class == NULL || pwd1->pw_class == NULL)
return (false);
if (strcmp(pwd0->pw_class, pwd1->pw_class) != 0)
return (false);
}
if (pwd0->pw_gecos != NULL || pwd1->pw_gecos != NULL) {
if (pwd0->pw_gecos == NULL || pwd1->pw_gecos == NULL)
return (false);
if (strcmp(pwd0->pw_gecos, pwd1->pw_gecos) != 0)
return (false);
}
if (pwd0->pw_dir != NULL || pwd1->pw_dir != NULL) {
if (pwd0->pw_dir == NULL || pwd1->pw_dir == NULL)
return (false);
if (strcmp(pwd0->pw_dir, pwd1->pw_dir) != 0)
return (false);
}
if (pwd0->pw_shell != NULL || pwd1->pw_shell != NULL) {
if (pwd0->pw_shell == NULL || pwd1->pw_shell == NULL)
return (false);
if (strcmp(pwd0->pw_shell, pwd1->pw_shell) != 0)
return (false);
}
if (pwd0->pw_expire != pwd1->pw_expire)
return (false);
if (pwd0->pw_fields != pwd1->pw_fields)
return (false);
return (true);
}
static unsigned int
runtest_cmds(cap_channel_t *cappwd)
{
char bufs[1024], bufc[1024];
unsigned int result;
struct passwd *pwds, *pwdc;
struct passwd sts, stc;
result = 0;
setpwent();
cap_setpwent(cappwd);
pwds = getpwent();
pwdc = cap_getpwent(cappwd);
if (passwd_compare(pwds, pwdc)) {
result |= GETPWENT0;
pwds = getpwent();
pwdc = cap_getpwent(cappwd);
if (passwd_compare(pwds, pwdc))
result |= GETPWENT1;
}
getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
if (passwd_compare(pwds, pwdc)) {
result |= GETPWENT_R0;
getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
if (passwd_compare(pwds, pwdc))
result |= GETPWENT_R1;
}
setpwent();
cap_setpwent(cappwd);
getpwent_r(&sts, bufs, sizeof(bufs), &pwds);
cap_getpwent_r(cappwd, &stc, bufc, sizeof(bufc), &pwdc);
if (passwd_compare(pwds, pwdc))
result |= GETPWENT_R2;
pwds = getpwent();
pwdc = cap_getpwent(cappwd);
if (passwd_compare(pwds, pwdc))
result |= GETPWENT2;
pwds = getpwnam("root");
pwdc = cap_getpwnam(cappwd, "root");
if (passwd_compare(pwds, pwdc)) {
pwds = getpwnam("operator");
pwdc = cap_getpwnam(cappwd, "operator");
if (passwd_compare(pwds, pwdc))
result |= GETPWNAM;
}
getpwnam_r("root", &sts, bufs, sizeof(bufs), &pwds);
cap_getpwnam_r(cappwd, "root", &stc, bufc, sizeof(bufc), &pwdc);
if (passwd_compare(pwds, pwdc)) {
getpwnam_r("operator", &sts, bufs, sizeof(bufs), &pwds);
cap_getpwnam_r(cappwd, "operator", &stc, bufc, sizeof(bufc),
&pwdc);
if (passwd_compare(pwds, pwdc))
result |= GETPWNAM_R;
}
pwds = getpwuid(UID_ROOT);
pwdc = cap_getpwuid(cappwd, UID_ROOT);
if (passwd_compare(pwds, pwdc)) {
pwds = getpwuid(UID_OPERATOR);
pwdc = cap_getpwuid(cappwd, UID_OPERATOR);
if (passwd_compare(pwds, pwdc))
result |= GETPWUID;
}
getpwuid_r(UID_ROOT, &sts, bufs, sizeof(bufs), &pwds);
cap_getpwuid_r(cappwd, UID_ROOT, &stc, bufc, sizeof(bufc), &pwdc);
if (passwd_compare(pwds, pwdc)) {
getpwuid_r(UID_OPERATOR, &sts, bufs, sizeof(bufs), &pwds);
cap_getpwuid_r(cappwd, UID_OPERATOR, &stc, bufc, sizeof(bufc),
&pwdc);
if (passwd_compare(pwds, pwdc))
result |= GETPWUID_R;
}
return (result);
}
static void
test_cmds(cap_channel_t *origcappwd)
{
cap_channel_t *cappwd;
const char *cmds[7], *fields[10], *names[6];
uid_t uids[5];
fields[0] = "pw_name";
fields[1] = "pw_passwd";
fields[2] = "pw_uid";
fields[3] = "pw_gid";
fields[4] = "pw_change";
fields[5] = "pw_class";
fields[6] = "pw_gecos";
fields[7] = "pw_dir";
fields[8] = "pw_shell";
fields[9] = "pw_expire";
names[0] = "root";
names[1] = "toor";
names[2] = "daemon";
names[3] = "operator";
names[4] = "bin";
names[5] = "kmem";
uids[0] = 0;
uids[1] = 1;
uids[2] = 2;
uids[3] = 3;
uids[4] = 5;
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == 0);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == 0);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cap_setpwent(cappwd);
cmds[0] = "getpwent";
cmds[1] = "getpwent_r";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "setpwent";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 | GETPWENT_R0 |
GETPWENT_R1 | GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cap_setpwent(cappwd);
cmds[0] = "getpwent";
cmds[1] = "getpwent_r";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "setpwent";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 | GETPWENT_R0 |
GETPWENT_R1 | GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent_r";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwent";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT_R2 |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent_r";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwent";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT_R2 |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwent_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwnam";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwent_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT0 | GETPWENT1 |
GETPWNAM | GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwnam";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam_r";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwnam";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM_R | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwnam_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwuid";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwnam_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWUID | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwuid";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwuid";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID_R));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 6) == 0);
cmds[0] = "setpwent";
cmds[1] = "getpwent";
cmds[2] = "getpwent_r";
cmds[3] = "getpwnam";
cmds[4] = "getpwnam_r";
cmds[5] = "getpwuid";
cmds[6] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 7) == -1 && errno == ENOTCAPABLE);
cmds[0] = "getpwuid_r";
CHECK(cap_pwd_limit_cmds(cappwd, cmds, 1) == -1 && errno == ENOTCAPABLE);
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 5) == 0);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R |
GETPWNAM | GETPWNAM_R | GETPWUID));
cap_close(cappwd);
}
#define PW_NAME _PWF_NAME
#define PW_PASSWD _PWF_PASSWD
#define PW_UID _PWF_UID
#define PW_GID _PWF_GID
#define PW_CHANGE _PWF_CHANGE
#define PW_CLASS _PWF_CLASS
#define PW_GECOS _PWF_GECOS
#define PW_DIR _PWF_DIR
#define PW_SHELL _PWF_SHELL
#define PW_EXPIRE _PWF_EXPIRE
static unsigned int
passwd_fields(const struct passwd *pwd)
{
unsigned int result;
result = 0;
if (pwd->pw_name != NULL && pwd->pw_name[0] != '\0')
result |= PW_NAME;
if (pwd->pw_passwd != NULL && pwd->pw_passwd[0] != '\0')
result |= PW_PASSWD;
else if ((pwd->pw_fields & _PWF_PASSWD) != 0)
result |= PW_PASSWD;
if (pwd->pw_uid != (uid_t)-1)
result |= PW_UID;
if (pwd->pw_gid != (gid_t)-1)
result |= PW_GID;
if (pwd->pw_change != 0 || (pwd->pw_fields & _PWF_CHANGE) != 0)
result |= PW_CHANGE;
if (pwd->pw_class != NULL && pwd->pw_class[0] != '\0')
result |= PW_CLASS;
else if ((pwd->pw_fields & _PWF_CLASS) != 0)
result |= PW_CLASS;
if (pwd->pw_gecos != NULL && pwd->pw_gecos[0] != '\0')
result |= PW_GECOS;
else if ((pwd->pw_fields & _PWF_GECOS) != 0)
result |= PW_GECOS;
if (pwd->pw_dir != NULL && pwd->pw_dir[0] != '\0')
result |= PW_DIR;
else if ((pwd->pw_fields & _PWF_DIR) != 0)
result |= PW_DIR;
if (pwd->pw_shell != NULL && pwd->pw_shell[0] != '\0')
result |= PW_SHELL;
else if ((pwd->pw_fields & _PWF_SHELL) != 0)
result |= PW_SHELL;
if (pwd->pw_expire != 0 || (pwd->pw_fields & _PWF_EXPIRE) != 0)
result |= PW_EXPIRE;
if (false && pwd->pw_fields != (int)result) {
printf("fields=0x%x != result=0x%x\n", (const unsigned int)pwd->pw_fields, result);
printf(" fields result\n");
printf("PW_NAME %d %d\n", (pwd->pw_fields & PW_NAME) != 0, (result & PW_NAME) != 0);
printf("PW_PASSWD %d %d\n", (pwd->pw_fields & PW_PASSWD) != 0, (result & PW_PASSWD) != 0);
printf("PW_UID %d %d\n", (pwd->pw_fields & PW_UID) != 0, (result & PW_UID) != 0);
printf("PW_GID %d %d\n", (pwd->pw_fields & PW_GID) != 0, (result & PW_GID) != 0);
printf("PW_CHANGE %d %d\n", (pwd->pw_fields & PW_CHANGE) != 0, (result & PW_CHANGE) != 0);
printf("PW_CLASS %d %d\n", (pwd->pw_fields & PW_CLASS) != 0, (result & PW_CLASS) != 0);
printf("PW_GECOS %d %d\n", (pwd->pw_fields & PW_GECOS) != 0, (result & PW_GECOS) != 0);
printf("PW_DIR %d %d\n", (pwd->pw_fields & PW_DIR) != 0, (result & PW_DIR) != 0);
printf("PW_SHELL %d %d\n", (pwd->pw_fields & PW_SHELL) != 0, (result & PW_SHELL) != 0);
printf("PW_EXPIRE %d %d\n", (pwd->pw_fields & PW_EXPIRE) != 0, (result & PW_EXPIRE) != 0);
}
return (result);
}
static bool
runtest_fields(cap_channel_t *cappwd, unsigned int expected)
{
char buf[1024];
struct passwd *pwd;
struct passwd st;
cap_setpwent(cappwd);
pwd = cap_getpwent(cappwd);
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
cap_setpwent(cappwd);
cap_getpwent_r(cappwd, &st, buf, sizeof(buf), &pwd);
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
pwd = cap_getpwnam(cappwd, "root");
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
cap_getpwnam_r(cappwd, "root", &st, buf, sizeof(buf), &pwd);
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
pwd = cap_getpwuid(cappwd, UID_ROOT);
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
cap_getpwuid_r(cappwd, UID_ROOT, &st, buf, sizeof(buf), &pwd);
if ((passwd_fields(pwd) & ~expected) != 0)
return (false);
return (true);
}
static void
test_fields(cap_channel_t *origcappwd)
{
cap_channel_t *cappwd;
const char *fields[10];
CHECK(runtest_fields(origcappwd, PW_NAME | PW_PASSWD | PW_UID |
PW_GID | PW_CHANGE | PW_CLASS | PW_GECOS | PW_DIR | PW_SHELL |
PW_EXPIRE));
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_name";
fields[1] = "pw_passwd";
fields[2] = "pw_uid";
fields[3] = "pw_gid";
fields[4] = "pw_change";
fields[5] = "pw_class";
fields[6] = "pw_gecos";
fields[7] = "pw_dir";
fields[8] = "pw_shell";
fields[9] = "pw_expire";
CHECK(cap_pwd_limit_fields(cappwd, fields, 10) == 0);
CHECK(runtest_fields(origcappwd, PW_NAME | PW_PASSWD | PW_UID |
PW_GID | PW_CHANGE | PW_CLASS | PW_GECOS | PW_DIR | PW_SHELL |
PW_EXPIRE));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_name";
fields[1] = "pw_passwd";
fields[2] = "pw_uid";
fields[3] = "pw_gid";
fields[4] = "pw_change";
CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
fields[5] = "pw_class";
CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_class";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_NAME | PW_PASSWD | PW_UID |
PW_GID | PW_CHANGE));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_class";
fields[1] = "pw_gecos";
fields[2] = "pw_dir";
fields[3] = "pw_shell";
fields[4] = "pw_expire";
CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
fields[5] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_CLASS | PW_GECOS | PW_DIR |
PW_SHELL | PW_EXPIRE));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_name";
fields[1] = "pw_uid";
fields[2] = "pw_change";
fields[3] = "pw_gecos";
fields[4] = "pw_shell";
CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
fields[5] = "pw_class";
CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_class";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_NAME | PW_UID | PW_CHANGE |
PW_GECOS | PW_SHELL));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_passwd";
fields[1] = "pw_gid";
fields[2] = "pw_class";
fields[3] = "pw_dir";
fields[4] = "pw_expire";
CHECK(cap_pwd_limit_fields(cappwd, fields, 5) == 0);
fields[5] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 6) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_PASSWD | PW_GID | PW_CLASS |
PW_DIR | PW_EXPIRE));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_uid";
fields[1] = "pw_class";
fields[2] = "pw_shell";
CHECK(cap_pwd_limit_fields(cappwd, fields, 3) == 0);
fields[3] = "pw_change";
CHECK(cap_pwd_limit_fields(cappwd, fields, 4) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_change";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_UID | PW_CLASS | PW_SHELL));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
fields[0] = "pw_change";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == 0);
fields[1] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 2) == -1 &&
errno == ENOTCAPABLE);
fields[0] = "pw_uid";
CHECK(cap_pwd_limit_fields(cappwd, fields, 1) == -1 &&
errno == ENOTCAPABLE);
CHECK(runtest_fields(cappwd, PW_CHANGE));
cap_close(cappwd);
}
static bool
runtest_users(cap_channel_t *cappwd, const char **names, const uid_t *uids,
size_t nusers)
{
char buf[1024];
struct passwd *pwd;
struct passwd st;
unsigned int i, got;
cap_setpwent(cappwd);
got = 0;
for (;;) {
pwd = cap_getpwent(cappwd);
if (pwd == NULL)
break;
got++;
for (i = 0; i < nusers; i++) {
if (strcmp(names[i], pwd->pw_name) == 0 &&
uids[i] == pwd->pw_uid) {
break;
}
}
if (i == nusers)
return (false);
}
if (got != nusers)
return (false);
cap_setpwent(cappwd);
got = 0;
for (;;) {
cap_getpwent_r(cappwd, &st, buf, sizeof(buf), &pwd);
if (pwd == NULL)
break;
got++;
for (i = 0; i < nusers; i++) {
if (strcmp(names[i], pwd->pw_name) == 0 &&
uids[i] == pwd->pw_uid) {
break;
}
}
if (i == nusers)
return (false);
}
if (got != nusers)
return (false);
for (i = 0; i < nusers; i++) {
pwd = cap_getpwnam(cappwd, names[i]);
if (pwd == NULL)
return (false);
}
for (i = 0; i < nusers; i++) {
cap_getpwnam_r(cappwd, names[i], &st, buf, sizeof(buf), &pwd);
if (pwd == NULL)
return (false);
}
for (i = 0; i < nusers; i++) {
pwd = cap_getpwuid(cappwd, uids[i]);
if (pwd == NULL)
return (false);
}
for (i = 0; i < nusers; i++) {
cap_getpwuid_r(cappwd, uids[i], &st, buf, sizeof(buf), &pwd);
if (pwd == NULL)
return (false);
}
return (true);
}
static void
test_users(cap_channel_t *origcappwd)
{
cap_channel_t *cappwd;
const char *names[6];
uid_t uids[6];
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "root";
names[1] = "toor";
names[2] = "daemon";
names[3] = "operator";
names[4] = "bin";
names[5] = "tty";
CHECK(cap_pwd_limit_users(cappwd, names, 6, NULL, 0) == 0);
uids[0] = 0;
uids[1] = 0;
uids[2] = 1;
uids[3] = 2;
uids[4] = 3;
uids[5] = 4;
CHECK(runtest_users(cappwd, names, uids, 6));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "operator";
names[2] = "bin";
CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == 0);
names[3] = "tty";
CHECK(cap_pwd_limit_users(cappwd, names, 4, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "tty";
CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "daemon";
uids[0] = 1;
uids[1] = 2;
uids[2] = 3;
CHECK(runtest_users(cappwd, names, uids, 3));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "bin";
names[2] = "tty";
CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == 0);
names[3] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 4, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "daemon";
uids[0] = 1;
uids[1] = 3;
uids[2] = 4;
CHECK(runtest_users(cappwd, names, uids, 3));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "operator";
names[2] = "bin";
uids[0] = 1;
uids[1] = 2;
uids[2] = 3;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == 0);
uids[3] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 4) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 1;
CHECK(runtest_users(cappwd, names, uids, 3));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "bin";
names[2] = "tty";
uids[0] = 1;
uids[1] = 3;
uids[2] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == 0);
uids[3] = 5;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 4) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 5;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 1;
CHECK(runtest_users(cappwd, names, uids, 3));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "bin";
CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == 0);
names[1] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 2, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "bin";
uids[0] = 3;
CHECK(runtest_users(cappwd, names, uids, 1));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "tty";
CHECK(cap_pwd_limit_users(cappwd, names, 2, NULL, 0) == 0);
names[2] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 3, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "operator";
CHECK(cap_pwd_limit_users(cappwd, names, 1, NULL, 0) == -1 &&
errno == ENOTCAPABLE);
names[0] = "daemon";
uids[0] = 1;
uids[1] = 4;
CHECK(runtest_users(cappwd, names, uids, 2));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "bin";
uids[0] = 3;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == 0);
uids[1] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 2) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 3;
CHECK(runtest_users(cappwd, names, uids, 1));
cap_close(cappwd);
cappwd = cap_clone(origcappwd);
CHECK(cappwd != NULL);
names[0] = "daemon";
names[1] = "tty";
uids[0] = 1;
uids[1] = 4;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 2) == 0);
uids[2] = 3;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 3) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 3;
CHECK(cap_pwd_limit_users(cappwd, NULL, 0, uids, 1) == -1 &&
errno == ENOTCAPABLE);
uids[0] = 1;
CHECK(runtest_users(cappwd, names, uids, 2));
cap_close(cappwd);
}
int
main(void)
{
cap_channel_t *capcas, *cappwd;
printf("1..188\n");
fflush(stdout);
capcas = cap_init();
CHECKX(capcas != NULL);
cappwd = cap_service_open(capcas, "system.pwd");
CHECKX(cappwd != NULL);
cap_close(capcas);
CHECK(runtest_cmds(cappwd) == (GETPWENT | GETPWENT_R | GETPWNAM |
GETPWNAM_R | GETPWUID | GETPWUID_R));
test_cmds(cappwd);
test_fields(cappwd);
test_users(cappwd);
cap_close(cappwd);
exit(0);
}