xref: /aosp_15_r20/external/libcap/pam_cap/test_pam_cap.c (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
1 /*
2  * Copyright (c) 2019 Andrew G. Morgan <[email protected]>
3  *
4  * This test inlines the pam_cap module and runs test vectors against
5  * it.
6  */
7 
8 #define _DEFAULT_SOURCE
9 
10 #include <unistd.h>
11 #include <sys/types.h>
12 
13 #include "./pam_cap.c"
14 
15 const char *test_groups[] = {
16     "root", "one", "two", "three", "four", "five", "six", "seven"
17 };
18 #define n_groups sizeof(test_groups)/sizeof(*test_groups)
19 
20 const char *test_users[] = {
21     "root", "alpha", "beta", "gamma", "delta"
22 };
23 #define n_users sizeof(test_users)/sizeof(*test_users)
24 
25 /* Note about memberships:
26  *
27  *  user gid   suppl groups
28  *  root  root
29  *  alpha one   two
30  *  beta  two   three four
31  *  gamma three four five six
32  *  delta four  five six seven [eight]
33  */
34 
35 static char *test_user;
36 
pam_get_user(pam_handle_t * pamh,const char ** user,const char * prompt)37 int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) {
38     *user = test_user;
39     if (*user == NULL) {
40 	return PAM_CONV_AGAIN;
41     }
42     return PAM_SUCCESS;
43 }
44 
pam_get_item(const pam_handle_t * pamh,int item_type,const void ** item)45 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) {
46     if (item_type != PAM_USER) {
47 	errno = EINVAL;
48 	return -1;
49     }
50     *item = test_user;
51     return 0;
52 }
53 
pam_set_data(pam_handle_t * pamh,const char * module_data_name,void * data,void (* cleanup)(pam_handle_t * pamh,void * data,int error_status))54 int pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
55 		 void (*cleanup)(pam_handle_t *pamh, void *data,
56 				 int error_status)) {
57     if (cleanup != iab_apply) {
58 	errno = EINVAL;
59 	return -1;
60     }
61     cap_free(data);
62     return -1;
63 }
64 
getgrouplist(const char * user,gid_t group,gid_t * groups,int * ngroups)65 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
66     int i,j;
67     for (i = 0; i < n_users; i++) {
68 	if (strcmp(user, test_users[i]) == 0) {
69 	    *ngroups = i+1;
70 	    break;
71 	}
72     }
73     if (i == n_users) {
74 	return -1;
75     }
76     groups[0] = i;
77     for (j = 1; j < *ngroups; j++) {
78 	groups[j] = i+j;
79     }
80     return *ngroups;
81 }
82 
83 static struct group gr;
getgrgid(gid_t gid)84 struct group *getgrgid(gid_t gid) {
85     if (gid >= n_groups) {
86 	errno = EINVAL;
87 	return NULL;
88     }
89     gr.gr_name = strdup(test_groups[gid]);
90     return &gr;
91 }
92 
93 static struct passwd pw;
getpwnam(const char * name)94 struct passwd *getpwnam(const char *name) {
95     int i;
96     for (i = 0; i < n_users; i++) {
97 	if (strcmp(name, test_users[i]) == 0) {
98 	    pw.pw_gid = i;
99 	    return &pw;
100 	}
101     }
102     return NULL;
103 }
104 
105 /* we'll use these to keep track of the three vectors - only use
106    lowest 64 bits */
107 
108 #define A 0
109 #define B 1
110 #define I 2
111 
112 /*
113  * load_vectors caches a copy of the lowest 64 bits of the inheritable
114  * cap vectors
115  */
load_vectors(unsigned long int bits[3])116 static void load_vectors(unsigned long int bits[3]) {
117     memset(bits, 0, 3*sizeof(unsigned long int));
118     cap_t prev = cap_get_proc();
119     int i;
120     for (i = 0; i < 64; i++) {
121 	unsigned long int mask = (1ULL << i);
122 	int v = cap_get_bound(i);
123 	if (v < 0) {
124 	    break;
125 	}
126 	bits[B] |= v ? mask : 0;
127 	cap_flag_value_t u;
128 	if (cap_get_flag(prev, i, CAP_INHERITABLE, &u) != 0) {
129 	    break;
130 	}
131 	bits[I] |= u ? mask : 0;
132 	v = cap_get_ambient(i);
133 	if (v > 0) {
134 	    bits[A] |= mask;
135 	}
136     }
137     cap_free(prev);
138 }
139 
140 struct vargs {
141     struct pam_cap_s cs;
142     const char *args[5];
143 };
144 
test_arg_parsing(void)145 static int test_arg_parsing(void) {
146     static struct vargs vs[] = {
147 	{
148 	    { 1, 0, 0, 0, NULL, NULL, NULL },
149 	    { "debug", NULL }
150 	},
151 	{
152 	    { 0, 1, 0, 0, NULL, NULL, NULL },
153 	    { "keepcaps", NULL }
154 	},
155 	{
156 	    { 0, 0, 1, 0, NULL, NULL, NULL },
157 	    { "autoauth", NULL }
158 	},
159 	{
160 	    { 1, 0, 1, 0, NULL, NULL, NULL },
161 	    { "autoauth", "debug", NULL }
162 	},
163 	{
164 	    { 0, 0, 0, 0, NULL, "/over/there", NULL },
165 	    { "config=/over/there", NULL }
166 	},
167 	{
168 	    { 0, 0, 0, 0, NULL, NULL, "^cap_setfcap" },
169 	    { "default=^cap_setfcap", NULL }
170 	},
171 	{
172 	    { 0, 0, 0, 1, NULL, NULL, NULL },
173 	    { "defer", NULL }
174 	},
175 	{
176 	    { 0, 0, 0, 0, NULL, NULL, NULL },
177 	    { NULL }
178 	}
179     };
180     int i;
181 
182     for (i=0; ; i++) {
183 	int argc;
184 	const char **argv;
185 	struct vargs *v;
186 
187 	v = &vs[i];
188 	argv = v->args;
189 
190 	for (argc = 0; argv[argc] != NULL; argc++);
191 
192 	struct pam_cap_s cs;
193 	parse_args(argc, argv, &cs);
194 
195 	if (cs.debug != v->cs.debug) {
196 	    printf("test_arg_parsing[%d]: debug=%d, wanted debug=%d\n",
197 		   i, cs.debug, v->cs.debug);
198 	    return 1;
199 	}
200 	if (cs.keepcaps != v->cs.keepcaps) {
201 	    printf("test_arg_parsing[%d]: keepcaps=%d, wanted keepcaps=%d\n",
202 		   i, cs.keepcaps, v->cs.keepcaps);
203 	    return 1;
204 	}
205 	if (cs.autoauth != v->cs.autoauth) {
206 	    printf("test_arg_parsing[%d]: autoauth=%d, wanted autoauth=%d\n",
207 		   i, cs.autoauth, v->cs.autoauth);
208 	    return 1;
209 	}
210 	if (cs.conf_filename != v->cs.conf_filename &&
211 	    strcmp(cs.conf_filename, v->cs.conf_filename)) {
212 	    printf("test_arg_parsing[%d]: conf_filename=[%s], wanted=[%s]\n",
213 		   i, cs.conf_filename, v->cs.conf_filename);
214 	    return 1;
215 	}
216 	if (cs.fallback != v->cs.fallback &&
217 	    strcmp(cs.fallback, v->cs.fallback)) {
218 	    printf("test_arg_parsing[%d]: fallback=[%s], wanted=[%s]\n",
219 		   i, cs.fallback, v->cs.fallback);
220 	    return 1;
221 	}
222 
223 	if (argc == 0) {
224 	    break;
225 	}
226     }
227     return 0;
228 }
229 
230 /*
231  * args: user a b i config-args...
232  */
main(int argc,char * argv[])233 int main(int argc, char *argv[]) {
234     unsigned long int before[3], change[3], after[3];
235 
236     if (test_arg_parsing()) {
237 	printf("failed to parse arguments\n");
238 	exit(1);
239     }
240     if (read_capabilities_for_user("alpha", "/dev/null") != NULL) {
241 	printf("/dev/null should return no capabilities\n");
242 	exit(1);
243     }
244     if (read_capabilities_for_user("unknown", "capability.conf") != NULL) {
245 	printf("capability.conf should return no capabilities for unknown\n");
246 	exit(1);
247     }
248     char *iab_text = read_capabilities_for_user("alpha", "./incapable.conf");
249     if (iab_text != NULL) {
250 	printf("./incapable.conf should grant no capabilities: got=%s\n",
251 	       iab_text);
252 	free(iab_text);
253 	exit(1);
254     }
255 
256     /*
257      * Start out with a cleared inheritable set.
258      */
259     cap_t orig = cap_get_proc();
260     cap_clear_flag(orig, CAP_INHERITABLE);
261     cap_set_proc(orig);
262 
263     if (getuid() != 0) {
264 	cap_free(orig);
265 	printf("test_pam_cap: OK! (Skipping privileged tests (uid!=0))\n");
266 	exit(0);
267     }
268     if (argc == 1) {
269 	printf("test_pam_cap: OK (kick the tires test)\n");
270 	exit(0);
271     }
272 
273     change[A] = strtoul(argv[2], NULL, 0);
274     change[B] = strtoul(argv[3], NULL, 0);
275     change[I] = strtoul(argv[4], NULL, 0);
276 
277     void* args_for_pam = argv+4;
278 
279     int status = pam_sm_authenticate(NULL, 0, argc-4,
280 				     (const char **) args_for_pam);
281     if (status != PAM_INCOMPLETE) {
282 	printf("failed to recognize no username\n");
283 	exit(1);
284     }
285 
286     test_user = argv[1];
287 
288     status = pam_sm_authenticate(NULL, 0, argc-4, (const char **) args_for_pam);
289     if (status == PAM_IGNORE) {
290 	if (strcmp(test_user, "root") == 0) {
291 	    exit(0);
292 	}
293 	printf("unconfigured non-root user: %s\n", test_user);
294 	exit(1);
295     }
296     if (status != PAM_SUCCESS) {
297 	printf("failed to recognize username\n");
298 	exit(1);
299     }
300 
301     /* Now it is time to execute the credential setting */
302     load_vectors(before);
303 
304     status = pam_sm_setcred(NULL, PAM_ESTABLISH_CRED, argc-4,
305 			    (const char **) args_for_pam);
306 
307     load_vectors(after);
308 
309     printf("before: A=0x%016lx B=0x%016lx I=0x%016lx\n",
310 	   before[A], before[B], before[I]);
311 
312     long unsigned int dA = before[A] ^ after[A];
313     long unsigned int dB = before[B] ^ after[B];
314     long unsigned int dI = before[I] ^ after[I];
315 
316     printf("diff  : A=0x%016lx B=0x%016lx I=0x%016lx\n", dA, dB, dI);
317     printf("after : A=0x%016lx B=0x%016lx I=0x%016lx\n",
318 	   after[A], after[B], after[I]);
319 
320     int failure = 0;
321     if (after[A] != change[A]) {
322 	printf("Ambient set error: got=0x%016lx, want=0x%016lx\n",
323 	       after[A], change[A]);
324 	failure = 1;
325     }
326     if (dB != change[B]) {
327 	printf("Bounding set error: got=0x%016lx, want=0x%016lx\n",
328 	       after[B], before[B] ^ change[B]);
329 	failure = 1;
330     }
331     if (after[I] != change[I]) {
332 	printf("Inheritable set error: got=0x%016lx, want=0x%016lx\n",
333 	       after[I], change[I]);
334 	failure = 1;
335     }
336 
337     exit(failure);
338 }
339