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