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