1 /*
2  * Copyright (c) 2014 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 <assert.h>
32 #include <string.h>
33 #include <stdlib.h>
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 
40 #include <pwd.h>
41 
42 #include "util.h"
43 
test_get_user_cfgfile_path(void)44 static void test_get_user_cfgfile_path(void) {
45   char *file;
46   struct passwd user;
47   int ret;
48   user.pw_name = "root";
49   user.pw_dir = "/root";
50   ret = get_user_cfgfile_path("/foo/bar", "test", &user, &file);
51   assert(ret == 1);
52   assert(strcmp(file, "/foo/bar/test") == 0);
53   free(file);
54   ret = get_user_cfgfile_path(NULL, "test", &user, &file);
55   assert(ret == 1);
56   assert(strcmp(file, "/root/.yubico/test") == 0);
57   free(file);
58 }
59 
test_check_user_token(void)60 static void test_check_user_token(void) {
61   char file[] = "/tmp/pamtest.XXXXXX";
62   int fd = mkstemp(file);
63   FILE *handle;
64   int ret;
65 
66   assert(fd != -1);
67   handle = fdopen(fd, "w");
68   fprintf(handle, "# This is a comment containing foobar:foobar\n");
69   fprintf(handle, "foobar:hhhvhvhdhbid:hnhbhnhbhnhb:\n");
70   fprintf(handle, "# This is a comment in the middle\n");
71   fprintf(handle, "kaka:hdhrhbhjhvhu:hihbhdhrhbhj\n");
72   fprintf(handle, "# foo2 is a user showing up twice in the file\n");
73   fprintf(handle, "foo2:vvvvvvvvvvvv\n");
74   fprintf(handle, "bar:hnhbhnhbhnhb\n");
75   fprintf(handle, "foo2:cccccccccccc\n");
76   fclose(handle);
77 
78   ret = check_user_token(file, "foobar", "hhhvhvhdhbid", 1, stdout);
79   assert(ret == AUTH_FOUND);
80   ret = check_user_token(file, "foobar", "hnhbhnhbhnhb", 1, stdout);
81   assert(ret == AUTH_FOUND);
82   ret = check_user_token(file, "foobar", "hnhbhnhbhnhc", 1, stdout);
83   assert(ret == AUTH_NOT_FOUND);
84   ret = check_user_token(file, "kaka", "hihbhdhrhbhj", 1, stdout);
85   assert(ret == AUTH_FOUND);
86   ret = check_user_token(file, "bar", "hnhbhnhbhnhb", 1, stdout);
87   assert(ret == AUTH_FOUND);
88   ret = check_user_token(file, "foo", "hdhrhbhjhvhu", 1, stdout);
89   assert(ret == AUTH_NO_TOKENS);
90   ret = check_user_token(file, "foo2", "cccccccccccc", 1, stdout);
91   assert(ret == AUTH_FOUND);
92   ret = check_user_token(file, "foo2", "vvvvvvvvvvvv", 1, stdout);
93   assert(ret == AUTH_FOUND);
94   ret = check_user_token(file, "foo2", "vvvvvvvvvvcc", 1, stdout);
95   assert(ret == AUTH_NOT_FOUND);
96   ret = check_user_token(file, "foo2", "", 1, stdout);
97   assert(ret == AUTH_NOT_FOUND);
98   ret = check_user_token(file, "foo", "", 1, stdout);
99   assert(ret == AUTH_NO_TOKENS);
100   remove(file);
101 }
102 
103 #if HAVE_CR
104 
105 #define CHALLENGE1 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
106 #define RESPONSE1 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
107 #define SALT1 "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
108 #define CHALLENGE2 "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
109 #define RESPONSE2 "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
110 
test_load_chalresp_state(void)111 static void test_load_chalresp_state(void) {
112   int ret;
113   FILE *file = tmpfile();
114   CR_STATE state;
115 
116   memset(&state, 0, sizeof(state));
117   fprintf(file, "v2:%s:%s:%s:%d:%d\n", CHALLENGE1, RESPONSE1, SALT1, 1000, 2);
118   rewind(file);
119   ret = load_chalresp_state(file, &state, true, stdout);
120   assert(ret == 1);
121   assert(state.iterations == 1000);
122   assert(state.slot == 2);
123   assert(state.challenge_len == CR_CHALLENGE_SIZE);
124   assert(state.response_len == CR_RESPONSE_SIZE);
125   assert(state.salt_len == CR_SALT_SIZE);
126   rewind(file);
127 
128   memset(&state, 0, sizeof(state));
129   fprintf(file, "v1:%s:%s:%d\n", CHALLENGE2, RESPONSE2, 1);
130   rewind(file);
131   ret = load_chalresp_state(file, &state, true, stdout);
132   assert(ret == 1);
133   assert(state.iterations == CR_DEFAULT_ITERATIONS);
134   assert(state.slot == 1);
135   assert(state.challenge_len == CR_CHALLENGE_SIZE);
136   assert(state.response_len == CR_RESPONSE_SIZE);
137   assert(state.salt_len == 0);
138   rewind(file);
139 
140   /* slot 3 should fail.. */
141   fprintf(file, "v2:%s:%s:%s:%d:%d\n", CHALLENGE1, RESPONSE1, SALT1, 1000, 3);
142   rewind(file);
143   ret = load_chalresp_state(file, &state, true, stdout);
144   assert(ret == 0);
145   fclose(file);
146 }
147 
test_check_user_challenge_file(void)148 static void test_check_user_challenge_file(void) {
149   int ret;
150   char * tmpdir_path;
151   char * buf;
152   FILE * file;
153   struct passwd user;
154 
155   buf = malloc(256);
156 
157 #define create_tmpdir_dir(path) \
158   strcpy(buf, tmpdir_path); \
159   strcat(buf, "/"); \
160   strcat(buf, path); \
161   mkdir(buf, 0755);
162 
163 #define remove_tmpdir_dir(path) \
164   strcpy(buf, tmpdir_path); \
165   strcat(buf, "/"); \
166   strcat(buf, path); \
167   rmdir(buf);
168 
169 #define create_tmpdir_file(path) \
170   strcpy(buf, tmpdir_path); \
171   strcat(buf, "/"); \
172   strcat(buf, path); \
173   file = fopen(buf, "w"); \
174   fclose(file);
175 
176 #define remove_tmpdir_file(path) \
177   strcpy(buf, tmpdir_path); \
178   strcat(buf, "/"); \
179   strcat(buf, path); \
180   unlink(buf);
181 
182   /* create temporary directory */
183   char template[] = "/tmp/pamtest.XXXXXX";
184   tmpdir_path = mkdtemp(template);
185   assert(tmpdir_path != NULL);
186 
187   /* set user data */
188   user.pw_name = "tester";
189   user.pw_dir = tmpdir_path;
190 
191   /* execute tests */
192   /* no asserts here as we have directory to remove */
193 
194   int case_001_empty_chalresp_dir;
195   case_001_empty_chalresp_dir = check_user_challenge_file(tmpdir_path, &user, stdout);
196 
197   int case_002_one_challenge_file;
198   create_tmpdir_file("tester");
199   case_002_one_challenge_file = check_user_challenge_file(tmpdir_path, &user, stdout);
200   remove_tmpdir_file("tester");
201 
202   int case_003_multiple_challenge_files;
203   create_tmpdir_file("tester-001");
204   create_tmpdir_file("tester-002");
205   case_003_multiple_challenge_files = check_user_challenge_file(tmpdir_path, &user, stdout);
206   remove_tmpdir_file("tester-002");
207   remove_tmpdir_file("tester-001");
208 
209   int case_004_other_users_files;
210   create_tmpdir_file("tester1");
211   create_tmpdir_file("tester1-001");
212   case_004_other_users_files = check_user_challenge_file(tmpdir_path, &user, stdout);
213   remove_tmpdir_file("tester1-001");
214   remove_tmpdir_file("tester1");
215 
216   int case_005_no_chalresp_no_yubico;
217   case_005_no_chalresp_no_yubico = check_user_challenge_file(NULL, &user, stdout);
218 
219   int case_006_no_chalresp_empty_yubico;
220   create_tmpdir_dir(".yubico");
221   case_006_no_chalresp_empty_yubico = check_user_challenge_file(NULL, &user, stdout);
222   remove_tmpdir_dir(".yubico");
223 
224   int case_007_no_chalresp_one_challenge_file;
225   create_tmpdir_dir(".yubico");
226   create_tmpdir_file(".yubico/challenge");
227   case_007_no_chalresp_one_challenge_file = check_user_challenge_file(NULL, &user, stdout);
228   remove_tmpdir_file(".yubico/challenge");
229   remove_tmpdir_dir(".yubico");
230 
231   int case_008_no_chalresp_multiple_challenge_files;
232   create_tmpdir_dir(".yubico");
233   create_tmpdir_file(".yubico/challenge-001");
234   create_tmpdir_file(".yubico/challenge-002");
235   case_008_no_chalresp_multiple_challenge_files = check_user_challenge_file(NULL, &user, stdout);
236   remove_tmpdir_file(".yubico/challenge-002");
237   remove_tmpdir_file(".yubico/challenge-001");
238   remove_tmpdir_dir(".yubico");
239 
240   /* remove temporary directory */
241   ret = rmdir(tmpdir_path);
242   assert(ret == 0);
243   free(buf);
244 
245   /* check test results */
246   assert(case_001_empty_chalresp_dir == AUTH_NOT_FOUND);
247   assert(case_002_one_challenge_file == AUTH_FOUND);
248   assert(case_003_multiple_challenge_files == AUTH_FOUND);
249   assert(case_004_other_users_files == AUTH_NOT_FOUND);
250   assert(case_005_no_chalresp_no_yubico == AUTH_NOT_FOUND);
251   assert(case_006_no_chalresp_empty_yubico == AUTH_NOT_FOUND);
252   assert(case_007_no_chalresp_one_challenge_file == AUTH_FOUND);
253   assert(case_008_no_chalresp_multiple_challenge_files == AUTH_FOUND);
254 
255 #undef create_tmpdir_dir
256 #undef remove_tmpdir_dir
257 #undef create_tmpdir_file
258 #undef remove_tmpdir_file
259 }
260 
261 #endif /* HAVE_CR */
262 
test_filter_printf(void)263 static void test_filter_printf(void) {
264     assert(filter_result_len("meno %u", "doof", NULL) == 10);
265     assert(filter_result_len("meno %u %u", "doof", NULL) == 15);
266     assert(filter_result_len("%u meno %u", "doof", NULL) == 15);
267     assert(filter_result_len("%u me %u no %u", "doof", NULL) == 21);
268     assert(filter_result_len("meno %w %%u", "doof", NULL) == 14);
269     assert(filter_result_len("meno %w %%u meno", "doof", NULL) == 19);
270     assert(filter_result_len("meno ", "doof", NULL) == 6);
271 
272     assert(!strcmp(filter_printf("meno %u", "doof"), "meno doof"));
273     assert(!strcmp(filter_printf("meno %u %u", "doof"), "meno doof doof"));
274     assert(!strcmp(filter_printf("%u meno %u", "doof"), "doof meno doof"));
275     assert(!strcmp(filter_printf("%u me %u no %u", "doof"), "doof me doof no doof"));
276     assert(!strcmp(filter_printf("meno %w %%u", "doof"), "meno %w %doof"));
277     assert(!strcmp(filter_printf("meno %w %%u meno", "doof"), "meno %w %doof meno"));
278     assert(!strcmp(filter_printf("meno ", "doof"), "meno "));
279     printf("test_filter_printf OK\n");
280 }
281 
main(void)282 int main (void) {
283   test_filter_printf();
284   test_get_user_cfgfile_path();
285   test_check_user_token();
286 #if HAVE_CR
287   test_load_chalresp_state();
288   test_check_user_challenge_file();
289 #endif /* HAVE_CR */
290   return 0;
291 }
292