1 /*
2 * Copyright (c) 2019 Andrew G. Morgan <morgan@kernel.org>
3 *
4 * This test inlines the pam_cap module and runs test vectors against
5 * it.
6 */
7
8 #include "./pam_cap.c"
9
10 const char *test_groups[] = {
11 "root", "one", "two", "three", "four", "five", "six", "seven"
12 };
13 #define n_groups sizeof(test_groups)/sizeof(*test_groups)
14
15 const char *test_users[] = {
16 "root", "alpha", "beta", "gamma", "delta"
17 };
18 #define n_users sizeof(test_users)/sizeof(*test_users)
19
20 /* Note about memberships:
21 *
22 * user gid suppl groups
23 * root root
24 * alpha one two
25 * beta two three four
26 * gamma three four five six
27 * delta four five six seven [eight]
28 */
29
30 static char *test_user;
31
pam_get_user(pam_handle_t * pamh,const char ** user,const char * prompt)32 int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) {
33 *user = test_user;
34 if (*user == NULL) {
35 return PAM_CONV_AGAIN;
36 }
37 return PAM_SUCCESS;
38 }
39
pam_get_item(const pam_handle_t * pamh,int item_type,const void ** item)40 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) {
41 if (item_type != PAM_USER) {
42 errno = EINVAL;
43 return -1;
44 }
45 *item = test_user;
46 return 0;
47 }
48
getgrouplist(const char * user,gid_t group,gid_t * groups,int * ngroups)49 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
50 int i,j;
51 for (i = 0; i < n_users; i++) {
52 if (strcmp(user, test_users[i]) == 0) {
53 *ngroups = i+1;
54 break;
55 }
56 }
57 if (i == n_users) {
58 return -1;
59 }
60 groups[0] = i;
61 for (j = 1; j < *ngroups; j++) {
62 groups[j] = i+j;
63 }
64 return *ngroups;
65 }
66
67 static struct group gr;
getgrgid(gid_t gid)68 struct group *getgrgid(gid_t gid) {
69 if (gid >= n_groups) {
70 errno = EINVAL;
71 return NULL;
72 }
73 gr.gr_name = strdup(test_groups[gid]);
74 return &gr;
75 }
76
77 static struct passwd pw;
getpwnam(const char * name)78 struct passwd *getpwnam(const char *name) {
79 int i;
80 for (i = 0; i < n_users; i++) {
81 if (strcmp(name, test_users[i]) == 0) {
82 pw.pw_gid = i;
83 return &pw;
84 }
85 }
86 return NULL;
87 }
88
89 /* we'll use these to keep track of the three vectors - only use
90 lowest 64 bits */
91
92 #define A 0
93 #define B 1
94 #define I 2
95
96 /*
97 * load_vectors caches a copy of the lowest 64 bits of the inheritable
98 * cap vectors
99 */
load_vectors(unsigned long int bits[3])100 static void load_vectors(unsigned long int bits[3]) {
101 memset(bits, 0, 3*sizeof(unsigned long int));
102 cap_t prev = cap_get_proc();
103 int i;
104 for (i = 0; i < 64; i++) {
105 unsigned long int mask = (1ULL << i);
106 int v = cap_get_bound(i);
107 if (v < 0) {
108 break;
109 }
110 bits[B] |= v ? mask : 0;
111 cap_flag_value_t u;
112 if (cap_get_flag(prev, i, CAP_INHERITABLE, &u) != 0) {
113 break;
114 }
115 bits[I] |= u ? mask : 0;
116 v = cap_get_ambient(i);
117 if (v > 0) {
118 bits[A] |= mask;
119 }
120 }
121 cap_free(prev);
122 }
123
124 /*
125 * args: user a b i config-args...
126 */
main(int argc,char * argv[])127 int main(int argc, char *argv[]) {
128 unsigned long int before[3], change[3], after[3];
129
130 /*
131 * Start out with a cleared inheritable set.
132 */
133 cap_t orig = cap_get_proc();
134 cap_clear_flag(orig, CAP_INHERITABLE);
135 cap_set_proc(orig);
136
137 change[A] = strtoul(argv[2], NULL, 0);
138 change[B] = strtoul(argv[3], NULL, 0);
139 change[I] = strtoul(argv[4], NULL, 0);
140
141 void* args_for_pam = argv+4;
142
143 int status = pam_sm_authenticate(NULL, 0, argc-4,
144 (const char **) args_for_pam);
145 if (status != PAM_INCOMPLETE) {
146 printf("failed to recognize no username\n");
147 exit(1);
148 }
149
150 test_user = argv[1];
151
152 status = pam_sm_authenticate(NULL, 0, argc-4, (const char **) args_for_pam);
153 if (status == PAM_IGNORE) {
154 if (strcmp(test_user, "root") == 0) {
155 exit(0);
156 }
157 printf("unconfigured non-root user: %s\n", test_user);
158 exit(1);
159 }
160 if (status != PAM_SUCCESS) {
161 printf("failed to recognize username\n");
162 exit(1);
163 }
164
165 /* Now it is time to execute the credential setting */
166 load_vectors(before);
167
168 status = pam_sm_setcred(NULL, PAM_ESTABLISH_CRED, argc-4,
169 (const char **) args_for_pam);
170
171 load_vectors(after);
172
173 printf("before: A=0x%016lx B=0x%016lx I=0x%016lx\n",
174 before[A], before[B], before[I]);
175
176 long unsigned int dA = before[A] ^ after[A];
177 long unsigned int dB = before[B] ^ after[B];
178 long unsigned int dI = before[I] ^ after[I];
179
180 printf("diff : A=0x%016lx B=0x%016lx I=0x%016lx\n", dA, dB, dI);
181 printf("after : A=0x%016lx B=0x%016lx I=0x%016lx\n",
182 after[A], after[B], after[I]);
183
184 int failure = 0;
185 if (after[A] != change[A]) {
186 printf("Ambient set error: got=0x%016lx, want=0x%016lx\n",
187 after[A], change[A]);
188 failure = 1;
189 }
190 if (dB != change[B]) {
191 printf("Bounding set error: got=0x%016lx, want=0x%016lx\n",
192 after[B], before[B] ^ change[B]);
193 failure = 1;
194 }
195 if (after[I] != change[I]) {
196 printf("Inheritable set error: got=0x%016lx, want=0x%016lx\n",
197 after[I], change[I]);
198 failure = 1;
199 }
200
201 exit(failure);
202 }
203