1 /*
2 * Copyright (c) 2015 Yubico AB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <unistd.h>
38
39 #include <assert.h>
40
41 #include <security/pam_appl.h>
42 #ifdef HAVE_PAM_MODUTIL_DROP_PRIV
43 #include <security/pam_modutil.h>
44 #else
45 #include <pwd.h>
46 struct pam_modutil_privs {
47 int noop;
48 };
49 #endif
50
51 #define YKVAL_PORT1 "17502"
52 #define YKVAL_PORT2 "30559"
53 #define LDAP_PORT "52825"
54
55 #define YKVAL SRCDIR"/aux/ykval.pl"
56 #define LDAP SRCDIR"/aux/ldap.pl"
57 #define AUTHFILE SRCDIR"/aux/authfile"
58
59 static struct data {
60 const char user[255];
61 const char otp[255];
62 } _data[] = {
63 {"foo", "vvincredibletrerdegkkrkkneieultcjdghrejjbckh"},
64 {"bar", "vvincredibletrerdegkkrkkneieultcjdghrejjbckh"},
65 {"foo", "vvincrediblltrerdegkkrkkneieultcjdghrejjbckh"},
66 {"foo", "vvincredibletrerdegkkrkkneieultcjdghrejjbckl"},
67 {"test", "ccccccbchvthlivuitriujjifivbvtrjkjfirllluurj"},
68 {"foo", ""},
69 {"bar", ""},
70 {"nokeys", ""},
71 {"foo", "testpasswordvvincredibletrerdegkkrkkneieultcjdghrejjbckh"},
72 {"foo", "testpassword"},
73 {"bar", "testpassword"},
74 };
75
76
77 static const char *ldap_cfg[] = {
78 "id=1",
79 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
80 "ldap_uri=ldap://localhost:"LDAP_PORT,
81 "ldapdn=ou=users,dc=example,dc=com",
82 "user_attr=uid",
83 "yubi_attr=yubiKeyId",
84 "debug"
85 };
86
87 static const char *ldap_cfg2[] = {
88 "id=1",
89 "urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify;http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
90 "ldap_uri=ldap://localhost:"LDAP_PORT,
91 "ldap_filter=(uid=%u)",
92 "yubi_attr=yubiKeyId",
93 "debug"
94 };
95
test_get_data(void * id)96 static const struct data *test_get_data(void *id) {
97 return &_data[(long)id];
98 }
99
100 #ifdef OPENPAM
pam_strerror(const pam_handle_t * pamh,int errnum)101 const char * pam_strerror(const pam_handle_t *pamh, int errnum) {
102 #else
103 const char * pam_strerror(pam_handle_t *pamh, int errnum) {
104 #endif
105 fprintf(stderr, "in pam_strerror()\n");
106 return "error";
107 }
108
109 int pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
110 void (*cleanup)(pam_handle_t *pamh, void *data, int error_status)) {
111 fprintf(stderr, "in pam_set_data() %s\n", module_data_name);
112 return PAM_SUCCESS;
113 }
114
115 int pam_get_data(const pam_handle_t *pamh, const char *module_data_name, const void **data) {
116 fprintf(stderr, "in pam_get_data() %s\n", module_data_name);
117 return PAM_SUCCESS;
118 }
119
120 #ifdef OPENPAM
121 int pam_get_user(pam_handle_t *pamh, const char **user, const char *prompt) {
122 #else
123 int pam_get_user(const pam_handle_t *pamh, const char **user, const char *prompt) {
124 #endif
125 fprintf(stderr, "in pam_get_user()\n");
126 *user = test_get_data((void*)pamh)->user;
127 return PAM_SUCCESS;
128 }
129
130 static int conv_func(int num_msg, const struct pam_message **msg,
131 struct pam_response **resp, void *appdata_ptr) {
132 struct pam_response *reply;
133 fprintf(stderr, "in conv_func()\n");
134 if(num_msg != 1) {
135 return PAM_CONV_ERR;
136 }
137
138 reply = malloc(sizeof(struct pam_response));
139 reply->resp = strdup(test_get_data(appdata_ptr)->otp);
140 *resp = reply;
141 return PAM_SUCCESS;
142 }
143
144 static struct pam_conv pam_conversation = {
145 conv_func,
146 NULL,
147 };
148
149 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) {
150 fprintf(stderr, "in pam_get_item() %d for %d\n", item_type, (int)(uintptr_t)pamh);
151 if(item_type == PAM_CONV) {
152 pam_conversation.appdata_ptr = (void*)pamh;
153 *item = &pam_conversation;
154 }
155 if(item_type == PAM_AUTHTOK && pamh >= (pam_handle_t*)8) {
156 *item = (void*)_data[(int)(uintptr_t)pamh].otp;
157 }
158 return PAM_SUCCESS;
159 }
160
161 int pam_modutil_drop_priv(pam_handle_t *pamh, struct pam_modutil_privs *p,
162 const struct passwd *pw) {
163 fprintf(stderr, "in pam_modutil_drop_priv()\n");
164 return PAM_SUCCESS;
165 }
166
167 int pam_modutil_regain_priv(pam_handle_t *pamh, struct pam_modutil_privs *p) {
168 fprintf(stderr, "in pam_modutil_regain_priv()\n");
169 return PAM_SUCCESS;
170 }
171
172 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item) {
173 fprintf(stderr, "in pam_set_item()\n");
174 return PAM_SUCCESS;
175 }
176
177 static int test_authenticate1(void) {
178 const char *cfg[] = {
179 "id=1",
180 "url=http://localhost:"YKVAL_PORT1"/wsapi/2/verify?id=%d&otp=%s",
181 "authfile="AUTHFILE,
182 "debug",
183 };
184 return pam_sm_authenticate(0, 0, sizeof(cfg) / sizeof(char*), cfg);
185 }
186
187 static int test_authenticate2(void) {
188 const char *cfg[] = {
189 "id=1",
190 "urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify;http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
191 "authfile="AUTHFILE,
192 "debug",
193 };
194 return pam_sm_authenticate(0, 0, sizeof(cfg) / sizeof(char*), cfg);
195 }
196
197 static int test_authenticate3(void) {
198 const char *cfg[] = {
199 "id=1",
200 "urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
201 "authfile="AUTHFILE,
202 "debug",
203 };
204 return pam_sm_authenticate(4, 0, sizeof(cfg) / sizeof(char*), cfg);
205 }
206
207 static int test_authenticate4(void) {
208 const char *cfg[] = {
209 "id=1",
210 "urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify;http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
211 "authfile="AUTHFILE,
212 "debug",
213 };
214 return pam_sm_authenticate(5, 0, sizeof(cfg) / sizeof(char*), cfg);
215 }
216
217 static int test_authenticate5(void) {
218 const char *cfg[] = {
219 "id=1",
220 "urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify;http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
221 "authfile="AUTHFILE,
222 "debug",
223 };
224 return pam_sm_authenticate(6, 0, sizeof(cfg) / sizeof(char*), cfg);
225 }
226
227 static int test_fail_authenticate1(void) {
228 const char *cfg[] = {
229 "id=1",
230 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
231 "authfile="AUTHFILE,
232 "debug"
233 };
234 return pam_sm_authenticate(1, 0, sizeof(cfg) / sizeof(char*), cfg);
235 }
236
237 static int test_fail_authenticate2(void) {
238 const char *cfg[] = {
239 "id=1",
240 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
241 "authfile="AUTHFILE,
242 "debug"
243 };
244 return pam_sm_authenticate(2, 0, sizeof(cfg) / sizeof(char*), cfg);
245 }
246
247 static int test_fail_authenticate3(void) {
248 const char *cfg[] = {
249 "id=1",
250 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
251 "authfile="AUTHFILE,
252 "debug"
253 };
254 return pam_sm_authenticate(3, 0, sizeof(cfg) / sizeof(char*), cfg);
255 }
256
257 static int test_firstpass_authenticate(void) {
258 const char *cfg[] = {
259 "id=1",
260 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
261 "authfile="AUTHFILE,
262 "use_first_pass",
263 "debug"
264 };
265 return pam_sm_authenticate(8, 0, sizeof(cfg) / sizeof(char*), cfg);
266 }
267
268 static int test_firstpass_fail(void) {
269 const char *cfg[] = {
270 "id=1",
271 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
272 "authfile="AUTHFILE,
273 "use_first_pass",
274 "debug"
275 };
276 return pam_sm_authenticate(9, 0, sizeof(cfg) / sizeof(char*), cfg);
277 }
278
279 static int test_firstpass_fail2(void) {
280 const char *cfg[] = {
281 "id=1",
282 "urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
283 "authfile="AUTHFILE,
284 "use_first_pass",
285 "debug"
286 };
287 return pam_sm_authenticate(10, 0, sizeof(cfg) / sizeof(char*), cfg);
288 }
289
290 static int test_authenticate_ldap1(void) {
291 return pam_sm_authenticate(0, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
292 }
293
294 static int test_authenticate_ldap_fail1(void) {
295 return pam_sm_authenticate(1, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
296 }
297
298 static int test_authenticate_ldap_fail2(void) {
299 return pam_sm_authenticate(2, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
300 }
301
302 static int test_authenticate_ldap2(void) {
303 return pam_sm_authenticate(4, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
304 }
305
306 static int test_authenticate_ldap3(void) {
307 return pam_sm_authenticate(4, 0, sizeof(ldap_cfg2) / sizeof(char*), ldap_cfg2);
308 }
309
310 static int test_authenticate_ldap4(void) {
311 return pam_sm_authenticate(5, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
312 }
313
314 static int test_authenticate_ldap5(void) {
315 return pam_sm_authenticate(6, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
316 }
317
318 static int test_authenticate_ldap6(void) {
319 return pam_sm_authenticate(7, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
320 }
321
322 static pid_t run_mock(const char *port, const char *type) {
323 pid_t pid = fork();
324 if(pid == 0) {
325 execlp(type, type, port, NULL);
326 }
327 return pid;
328 }
329
330 int main(void) {
331 int ret = 0;
332 pid_t child = run_mock(YKVAL_PORT1, YKVAL);
333 pid_t child2 = run_mock(YKVAL_PORT2, YKVAL);
334 #ifdef HAVE_LIBLDAP
335 pid_t child3 = run_mock(LDAP_PORT, LDAP);
336 #endif
337
338 /* Give the "server" time to settle */
339 sleep(1);
340
341 if(test_authenticate1() != PAM_SUCCESS) {
342 ret = 1;
343 goto out;
344 }
345 if(test_authenticate2() != PAM_SUCCESS) {
346 ret = 2;
347 goto out;
348 }
349 if(test_fail_authenticate1() != PAM_USER_UNKNOWN) {
350 ret = 3;
351 goto out;
352 }
353 if(test_fail_authenticate2() != PAM_AUTH_ERR) {
354 ret = 4;
355 goto out;
356 }
357 if(test_fail_authenticate3() != PAM_AUTH_ERR) {
358 ret = 5;
359 goto out;
360 }
361 if(test_authenticate3() != PAM_SUCCESS) {
362 ret = 6;
363 goto out;
364 }
365 if(test_authenticate4() != PAM_AUTH_ERR) {
366 ret = 7;
367 goto out;
368 }
369 if(test_authenticate5() != PAM_USER_UNKNOWN) {
370 ret = 8;
371 goto out;
372 }
373 if(test_firstpass_authenticate() != PAM_SUCCESS) {
374 ret = 9;
375 goto out;
376 }
377 if(test_firstpass_fail() != PAM_AUTH_ERR) {
378 ret = 10;
379 goto out;
380 }
381 if(test_firstpass_fail2() != PAM_USER_UNKNOWN) {
382 ret = 11;
383 goto out;
384 }
385 #ifdef HAVE_LIBLDAP
386 if(test_authenticate_ldap1() != PAM_SUCCESS) {
387 ret = 1001;
388 goto out;
389 }
390 if(test_authenticate_ldap_fail1() != PAM_USER_UNKNOWN) {
391 ret = 1002;
392 goto out;
393 }
394 if(test_authenticate_ldap_fail2() != PAM_AUTH_ERR) {
395 ret = 1003;
396 goto out;
397 }
398 if(test_authenticate_ldap2() != PAM_SUCCESS) {
399 ret = 1004;
400 goto out;
401 }
402 if(test_authenticate_ldap3() != PAM_SUCCESS) {
403 ret = 1005;
404 goto out;
405 }
406 if(test_authenticate_ldap4() != PAM_AUTH_ERR) {
407 ret = 1006;
408 goto out;
409 }
410 if(test_authenticate_ldap5() != PAM_USER_UNKNOWN) {
411 ret = 1007;
412 goto out;
413 }
414 if(test_authenticate_ldap6() != PAM_USER_UNKNOWN) {
415 ret = 1008;
416 goto out;
417 }
418 #endif
419
420 out:
421 kill(child, 9);
422 kill(child2, 9);
423 #ifdef HAVE_LIBLDAP
424 kill(child3, 9);
425 printf("killed %d, %d and %d\n", child, child2, child3);
426 #else
427 printf("killed %d and %d\n", child, child2);
428 #endif
429 if(ret != 0) {
430 fprintf(stderr, "test %d failed!\n", ret);
431 }
432 return ret;
433 }
434