• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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 
getgrouplist(const char * user,gid_t group,gid_t * groups,int * ngroups)54 int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
55     int i,j;
56     for (i = 0; i < n_users; i++) {
57 	if (strcmp(user, test_users[i]) == 0) {
58 	    *ngroups = i+1;
59 	    break;
60 	}
61     }
62     if (i == n_users) {
63 	return -1;
64     }
65     groups[0] = i;
66     for (j = 1; j < *ngroups; j++) {
67 	groups[j] = i+j;
68     }
69     return *ngroups;
70 }
71 
72 static struct group gr;
getgrgid(gid_t gid)73 struct group *getgrgid(gid_t gid) {
74     if (gid >= n_groups) {
75 	errno = EINVAL;
76 	return NULL;
77     }
78     gr.gr_name = strdup(test_groups[gid]);
79     return &gr;
80 }
81 
82 static struct passwd pw;
getpwnam(const char * name)83 struct passwd *getpwnam(const char *name) {
84     int i;
85     for (i = 0; i < n_users; i++) {
86 	if (strcmp(name, test_users[i]) == 0) {
87 	    pw.pw_gid = i;
88 	    return &pw;
89 	}
90     }
91     return NULL;
92 }
93 
94 /* we'll use these to keep track of the three vectors - only use
95    lowest 64 bits */
96 
97 #define A 0
98 #define B 1
99 #define I 2
100 
101 /*
102  * load_vectors caches a copy of the lowest 64 bits of the inheritable
103  * cap vectors
104  */
load_vectors(unsigned long int bits[3])105 static void load_vectors(unsigned long int bits[3]) {
106     memset(bits, 0, 3*sizeof(unsigned long int));
107     cap_t prev = cap_get_proc();
108     int i;
109     for (i = 0; i < 64; i++) {
110 	unsigned long int mask = (1ULL << i);
111 	int v = cap_get_bound(i);
112 	if (v < 0) {
113 	    break;
114 	}
115 	bits[B] |= v ? mask : 0;
116 	cap_flag_value_t u;
117 	if (cap_get_flag(prev, i, CAP_INHERITABLE, &u) != 0) {
118 	    break;
119 	}
120 	bits[I] |= u ? mask : 0;
121 	v = cap_get_ambient(i);
122 	if (v > 0) {
123 	    bits[A] |= mask;
124 	}
125     }
126     cap_free(prev);
127 }
128 
129 struct vargs {
130     struct pam_cap_s cs;
131     const char *args[5];
132 };
133 
test_arg_parsing(void)134 static int test_arg_parsing(void) {
135     static struct vargs vs[] = {
136 	{
137 	    { 1, 0, 0, NULL, NULL, NULL },
138 	    { "debug", NULL }
139 	},
140 	{
141 	    { 0, 1, 0, NULL, NULL, NULL },
142 	    { "keepcaps", NULL }
143 	},
144 	{
145 	    { 0, 0, 1, NULL, NULL, NULL },
146 	    { "autoauth", NULL }
147 	},
148 	{
149 	    { 1, 0, 1, NULL, NULL, NULL },
150 	    { "autoauth", "debug", NULL }
151 	},
152 	{
153 	    { 0, 0, 0, NULL, "/over/there", NULL },
154 	    { "config=/over/there", NULL }
155 	},
156 	{
157 	    { 0, 0, 0, NULL, NULL, "^cap_setfcap" },
158 	    { "default=^cap_setfcap", NULL }
159 	},
160 	{
161 	    { 0, 0, 0, NULL, NULL, NULL },
162 	    { NULL }
163 	}
164     };
165     int i;
166 
167     for (i=0; ; i++) {
168 	int argc;
169 	const char **argv;
170 	struct vargs *v;
171 
172 	v = &vs[i];
173 	argv = v->args;
174 
175 	for (argc = 0; argv[argc] != NULL; argc++);
176 
177 	struct pam_cap_s cs;
178 	parse_args(argc, argv, &cs);
179 
180 	if (cs.debug != v->cs.debug) {
181 	    printf("test_arg_parsing[%d]: debug=%d, wanted debug=%d\n",
182 		   i, cs.debug, v->cs.debug);
183 	    return 1;
184 	}
185 	if (cs.keepcaps != v->cs.keepcaps) {
186 	    printf("test_arg_parsing[%d]: keepcaps=%d, wanted keepcaps=%d\n",
187 		   i, cs.keepcaps, v->cs.keepcaps);
188 	    return 1;
189 	}
190 	if (cs.autoauth != v->cs.autoauth) {
191 	    printf("test_arg_parsing[%d]: autoauth=%d, wanted autoauth=%d\n",
192 		   i, cs.autoauth, v->cs.autoauth);
193 	    return 1;
194 	}
195 	if (cs.conf_filename != v->cs.conf_filename &&
196 	    strcmp(cs.conf_filename, v->cs.conf_filename)) {
197 	    printf("test_arg_parsing[%d]: conf_filename=[%s], wanted=[%s]\n",
198 		   i, cs.conf_filename, v->cs.conf_filename);
199 	    return 1;
200 	}
201 	if (cs.fallback != v->cs.fallback &&
202 	    strcmp(cs.fallback, v->cs.fallback)) {
203 	    printf("test_arg_parsing[%d]: fallback=[%s], wanted=[%s]\n",
204 		   i, cs.fallback, v->cs.fallback);
205 	    return 1;
206 	}
207 
208 	if (argc == 0) {
209 	    break;
210 	}
211     }
212     return 0;
213 }
214 
215 /*
216  * args: user a b i config-args...
217  */
main(int argc,char * argv[])218 int main(int argc, char *argv[]) {
219     unsigned long int before[3], change[3], after[3];
220 
221     if (test_arg_parsing()) {
222 	printf("failed to parse arguments\n");
223 	exit(1);
224     }
225     if (read_capabilities_for_user("morgan", "/dev/null") != NULL) {
226 	printf("/dev/null is not a valid config file\n");
227     }
228 
229     /*
230      * Start out with a cleared inheritable set.
231      */
232     cap_t orig = cap_get_proc();
233     cap_clear_flag(orig, CAP_INHERITABLE);
234     cap_set_proc(orig);
235 
236     if (getuid() != 0) {
237 	cap_free(orig);
238 	printf("test_pam_cap: OK! (Skipping privileged tests (uid!=0))\n");
239 	exit(0);
240     }
241 
242     change[A] = strtoul(argv[2], NULL, 0);
243     change[B] = strtoul(argv[3], NULL, 0);
244     change[I] = strtoul(argv[4], NULL, 0);
245 
246     void* args_for_pam = argv+4;
247 
248     int status = pam_sm_authenticate(NULL, 0, argc-4,
249 				     (const char **) args_for_pam);
250     if (status != PAM_INCOMPLETE) {
251 	printf("failed to recognize no username\n");
252 	exit(1);
253     }
254 
255     test_user = argv[1];
256 
257     status = pam_sm_authenticate(NULL, 0, argc-4, (const char **) args_for_pam);
258     if (status == PAM_IGNORE) {
259 	if (strcmp(test_user, "root") == 0) {
260 	    exit(0);
261 	}
262 	printf("unconfigured non-root user: %s\n", test_user);
263 	exit(1);
264     }
265     if (status != PAM_SUCCESS) {
266 	printf("failed to recognize username\n");
267 	exit(1);
268     }
269 
270     /* Now it is time to execute the credential setting */
271     load_vectors(before);
272 
273     status = pam_sm_setcred(NULL, PAM_ESTABLISH_CRED, argc-4,
274 			    (const char **) args_for_pam);
275 
276     load_vectors(after);
277 
278     printf("before: A=0x%016lx B=0x%016lx I=0x%016lx\n",
279 	   before[A], before[B], before[I]);
280 
281     long unsigned int dA = before[A] ^ after[A];
282     long unsigned int dB = before[B] ^ after[B];
283     long unsigned int dI = before[I] ^ after[I];
284 
285     printf("diff  : A=0x%016lx B=0x%016lx I=0x%016lx\n", dA, dB, dI);
286     printf("after : A=0x%016lx B=0x%016lx I=0x%016lx\n",
287 	   after[A], after[B], after[I]);
288 
289     int failure = 0;
290     if (after[A] != change[A]) {
291 	printf("Ambient set error: got=0x%016lx, want=0x%016lx\n",
292 	       after[A], change[A]);
293 	failure = 1;
294     }
295     if (dB != change[B]) {
296 	printf("Bounding set error: got=0x%016lx, want=0x%016lx\n",
297 	       after[B], before[B] ^ change[B]);
298 	failure = 1;
299     }
300     if (after[I] != change[I]) {
301 	printf("Inheritable set error: got=0x%016lx, want=0x%016lx\n",
302 	       after[I], change[I]);
303 	failure = 1;
304     }
305 
306     exit(failure);
307 }
308