|
Packit Service |
c7be57 |
/*
|
|
Packit Service |
c7be57 |
* Copyright (c) 2019 Andrew G. Morgan <morgan@kernel.org>
|
|
Packit Service |
c7be57 |
*
|
|
Packit Service |
c7be57 |
* This test inlines the pam_cap module and runs test vectors against
|
|
Packit Service |
c7be57 |
* it.
|
|
Packit Service |
c7be57 |
*/
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
#include "./pam_cap.c"
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
const char *test_groups[] = {
|
|
Packit Service |
c7be57 |
"root", "one", "two", "three", "four", "five", "six", "seven"
|
|
Packit Service |
c7be57 |
};
|
|
Packit Service |
c7be57 |
#define n_groups sizeof(test_groups)/sizeof(*test_groups)
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
const char *test_users[] = {
|
|
Packit Service |
c7be57 |
"root", "alpha", "beta", "gamma", "delta"
|
|
Packit Service |
c7be57 |
};
|
|
Packit Service |
c7be57 |
#define n_users sizeof(test_users)/sizeof(*test_users)
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
// Note about memberships:
|
|
Packit Service |
c7be57 |
//
|
|
Packit Service |
c7be57 |
// user gid suppl groups
|
|
Packit Service |
c7be57 |
// root root
|
|
Packit Service |
c7be57 |
// alpha one two
|
|
Packit Service |
c7be57 |
// beta two three four
|
|
Packit Service |
c7be57 |
// gamma three four five six
|
|
Packit Service |
c7be57 |
// delta four five six seven [eight]
|
|
Packit Service |
c7be57 |
//
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
static char *test_user;
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) {
|
|
Packit Service |
c7be57 |
*user = test_user;
|
|
Packit Service |
c7be57 |
if (*user == NULL) {
|
|
Packit Service |
c7be57 |
return PAM_CONV_AGAIN;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
return PAM_SUCCESS;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) {
|
|
Packit Service |
c7be57 |
if (item_type != PAM_USER) {
|
|
Packit Service |
c7be57 |
errno = EINVAL;
|
|
Packit Service |
c7be57 |
return -1;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
*item = test_user;
|
|
Packit Service |
c7be57 |
return 0;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
|
|
Packit Service |
c7be57 |
int i,j;
|
|
Packit Service |
c7be57 |
for (i = 0; i < n_users; i++) {
|
|
Packit Service |
c7be57 |
if (strcmp(user, test_users[i]) == 0) {
|
|
Packit Service |
c7be57 |
*ngroups = i+1;
|
|
Packit Service |
c7be57 |
break;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
if (i == n_users) {
|
|
Packit Service |
c7be57 |
return -1;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
groups[0] = i;
|
|
Packit Service |
c7be57 |
for (j = 1; j < *ngroups; j++) {
|
|
Packit Service |
c7be57 |
groups[j] = i+j;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
return *ngroups;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
static struct group gr;
|
|
Packit Service |
c7be57 |
struct group *getgrgid(gid_t gid) {
|
|
Packit Service |
c7be57 |
if (gid >= n_groups) {
|
|
Packit Service |
c7be57 |
errno = EINVAL;
|
|
Packit Service |
c7be57 |
return NULL;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
gr.gr_name = strdup(test_groups[gid]);
|
|
Packit Service |
c7be57 |
return &gr;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
static struct passwd pw;
|
|
Packit Service |
c7be57 |
struct passwd *getpwnam(const char *name) {
|
|
Packit Service |
c7be57 |
for (int i = 0; i < n_users; i++) {
|
|
Packit Service |
c7be57 |
if (strcmp(name, test_users[i]) == 0) {
|
|
Packit Service |
c7be57 |
pw.pw_gid = i;
|
|
Packit Service |
c7be57 |
return &pw;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
return NULL;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
/* we'll use these to keep track of the three vectors - only use
|
|
Packit Service |
c7be57 |
lowest 64 bits */
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
#define A 0
|
|
Packit Service |
c7be57 |
#define B 1
|
|
Packit Service |
c7be57 |
#define I 2
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
/*
|
|
Packit Service |
c7be57 |
* load_vectors caches a copy of the lowest 64 bits of the inheritable
|
|
Packit Service |
c7be57 |
* cap vectors
|
|
Packit Service |
c7be57 |
*/
|
|
Packit Service |
c7be57 |
static void load_vectors(unsigned long int bits[3]) {
|
|
Packit Service |
c7be57 |
memset(bits, 0, 3*sizeof(unsigned long int));
|
|
Packit Service |
c7be57 |
cap_t prev = cap_get_proc();
|
|
Packit Service |
c7be57 |
for (int i = 0; i < 64; i++) {
|
|
Packit Service |
c7be57 |
unsigned long int mask = (1ULL << i);
|
|
Packit Service |
c7be57 |
int v = cap_get_bound(i);
|
|
Packit Service |
c7be57 |
if (v < 0) {
|
|
Packit Service |
c7be57 |
break;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
bits[B] |= v ? mask : 0;
|
|
Packit Service |
c7be57 |
cap_flag_value_t u;
|
|
Packit Service |
c7be57 |
if (cap_get_flag(prev, i, CAP_INHERITABLE, &u) != 0) {
|
|
Packit Service |
c7be57 |
break;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
bits[I] |= u ? mask : 0;
|
|
Packit Service |
c7be57 |
v = cap_get_ambient(i);
|
|
Packit Service |
c7be57 |
if (v > 0) {
|
|
Packit Service |
c7be57 |
bits[A] |= mask;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
cap_free(prev);
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
/*
|
|
Packit Service |
c7be57 |
* args: user a b i config-args...
|
|
Packit Service |
c7be57 |
*/
|
|
Packit Service |
c7be57 |
int main(int argc, char *argv[]) {
|
|
Packit Service |
c7be57 |
unsigned long int before[3], change[3], after[3];
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
/*
|
|
Packit Service |
c7be57 |
* Start out with a cleared inheritable set.
|
|
Packit Service |
c7be57 |
*/
|
|
Packit Service |
c7be57 |
cap_t orig = cap_get_proc();
|
|
Packit Service |
c7be57 |
cap_clear_flag(orig, CAP_INHERITABLE);
|
|
Packit Service |
c7be57 |
cap_set_proc(orig);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
change[A] = strtoul(argv[2], NULL, 0);
|
|
Packit Service |
c7be57 |
change[B] = strtoul(argv[3], NULL, 0);
|
|
Packit Service |
c7be57 |
change[I] = strtoul(argv[4], NULL, 0);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
void* args_for_pam = argv+4;
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
int status = pam_sm_authenticate(NULL, 0, argc-4,
|
|
Packit Service |
c7be57 |
(const char **) args_for_pam);
|
|
Packit Service |
c7be57 |
if (status != PAM_INCOMPLETE) {
|
|
Packit Service |
c7be57 |
printf("failed to recognize no username\n");
|
|
Packit Service |
c7be57 |
exit(1);
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
test_user = argv[1];
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
status = pam_sm_authenticate(NULL, 0, argc-4, (const char **) args_for_pam);
|
|
Packit Service |
c7be57 |
if (status == PAM_IGNORE) {
|
|
Packit Service |
c7be57 |
if (strcmp(test_user, "root") == 0) {
|
|
Packit Service |
c7be57 |
exit(0);
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
printf("unconfigured non-root user: %s\n", test_user);
|
|
Packit Service |
c7be57 |
exit(1);
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
if (status != PAM_SUCCESS) {
|
|
Packit Service |
c7be57 |
printf("failed to recognize username\n");
|
|
Packit Service |
c7be57 |
exit(1);
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
// Now it is time to execute the credential setting
|
|
Packit Service |
c7be57 |
load_vectors(before);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
status = pam_sm_setcred(NULL, PAM_ESTABLISH_CRED, argc-4,
|
|
Packit Service |
c7be57 |
(const char **) args_for_pam);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
load_vectors(after);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
printf("before: A=0x%016lx B=0x%016lx I=0x%016lx\n",
|
|
Packit Service |
c7be57 |
before[A], before[B], before[I]);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
long unsigned int dA = before[A] ^ after[A];
|
|
Packit Service |
c7be57 |
long unsigned int dB = before[B] ^ after[B];
|
|
Packit Service |
c7be57 |
long unsigned int dI = before[I] ^ after[I];
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
printf("diff : A=0x%016lx B=0x%016lx I=0x%016lx\n", dA, dB, dI);
|
|
Packit Service |
c7be57 |
printf("after : A=0x%016lx B=0x%016lx I=0x%016lx\n",
|
|
Packit Service |
c7be57 |
after[A], after[B], after[I]);
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
int failure = 0;
|
|
Packit Service |
c7be57 |
if (after[A] != change[A]) {
|
|
Packit Service |
c7be57 |
printf("Ambient set error: got=0x%016lx, want=0x%016lx\n",
|
|
Packit Service |
c7be57 |
after[A], change[A]);
|
|
Packit Service |
c7be57 |
failure = 1;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
if (dB != change[B]) {
|
|
Packit Service |
c7be57 |
printf("Bounding set error: got=0x%016lx, want=0x%016lx\n",
|
|
Packit Service |
c7be57 |
after[B], before[B] ^ change[B]);
|
|
Packit Service |
c7be57 |
failure = 1;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
if (after[I] != change[I]) {
|
|
Packit Service |
c7be57 |
printf("Inheritable set error: got=0x%016lx, want=0x%016lx\n",
|
|
Packit Service |
c7be57 |
after[I], change[I]);
|
|
Packit Service |
c7be57 |
failure = 1;
|
|
Packit Service |
c7be57 |
}
|
|
Packit Service |
c7be57 |
|
|
Packit Service |
c7be57 |
exit(failure);
|
|
Packit Service |
c7be57 |
}
|