1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2008-2017 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Modules API tests */
26 
27 #include "tests.h"
28 
29 extern module *loaded_modules;
30 
31 static pool *p = NULL;
32 
set_up(void)33 static void set_up(void) {
34   if (p == NULL) {
35     p = permanent_pool = make_sub_pool(NULL);
36   }
37 
38   modules_init();
39 }
40 
tear_down(void)41 static void tear_down(void) {
42   loaded_modules = NULL;
43 
44   if (p) {
45     destroy_pool(p);
46     p = permanent_pool = NULL;
47   }
48 }
49 
50 /* Tests */
51 
52 static int sess_init_eperm = FALSE;
53 
module_sess_init_cb(void)54 static int module_sess_init_cb(void) {
55   if (sess_init_eperm) {
56     sess_init_eperm = FALSE;
57     errno = EPERM;
58     return -1;
59   }
60 
61   return 0;
62 }
63 
START_TEST(module_sess_init_test)64 START_TEST (module_sess_init_test) {
65   int res;
66   module m;
67 
68   res = modules_session_init();
69   fail_unless(res == 0, "Failed to initialize modules: %s", strerror(errno));
70 
71   memset(&m, 0, sizeof(m));
72   m.name = "testsuite";
73 
74   loaded_modules = &m;
75   res = modules_session_init();
76   fail_unless(res == 0, "Failed to initialize modules: %s", strerror(errno));
77 
78   m.sess_init = module_sess_init_cb;
79   res = modules_session_init();
80   fail_unless(res == 0, "Failed to initialize modules: %s", strerror(errno));
81 
82   sess_init_eperm = TRUE;
83   res = modules_session_init();
84   fail_unless(res < 0, "Initialized modules unexpectedly");
85   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
86     strerror(errno), errno);
87 
88   loaded_modules = NULL;
89 }
90 END_TEST
91 
START_TEST(module_command_exists_test)92 START_TEST (module_command_exists_test) {
93   int res;
94 
95   res = command_exists(NULL);
96   fail_unless(res == FALSE, "Expected FALSE, got %d", res);
97 }
98 END_TEST
99 
START_TEST(module_exists_test)100 START_TEST (module_exists_test) {
101   unsigned char res;
102   module m;
103 
104   res = pr_module_exists(NULL);
105   fail_unless(res == FALSE, "Failed to handle null argument");
106   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
107     strerror(errno), errno);
108 
109   res = pr_module_exists("mod_foo.c");
110   fail_unless(res == FALSE, "Failed to handle nonexistent module");
111   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
112     strerror(errno), errno);
113 
114   memset(&m, 0, sizeof(m));
115   m.name = "bar";
116 
117   loaded_modules = &m;
118 
119   res = pr_module_exists("mod_foo.c");
120   fail_unless(res == FALSE, "Failed to handle nonexistent module");
121   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
122     strerror(errno), errno);
123 
124   res = pr_module_exists("mod_bar.c");
125   fail_unless(res == TRUE, "Failed to detect existing module");
126 
127   res = pr_module_exists("mod_BAR.c");
128   fail_unless(res == FALSE, "Failed to handle nonexistent module");
129   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
130     strerror(errno), errno);
131 
132   loaded_modules = NULL;
133 }
134 END_TEST
135 
START_TEST(module_get_test)136 START_TEST (module_get_test) {
137   module m, *res;
138 
139   res = pr_module_get(NULL);
140   fail_unless(res == NULL, "Failed to handle null argument");
141   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
142     strerror(errno), errno);
143 
144   res = pr_module_get("mod_foo.c");
145   fail_unless(res == NULL, "Failed to handle nonexistent module");
146   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
147     strerror(errno), errno);
148 
149   memset(&m, 0, sizeof(m));
150   m.name = "bar";
151 
152   loaded_modules = &m;
153 
154   res = pr_module_get("mod_foo.c");
155   fail_unless(res == NULL, "Failed to handle nonexistent module");
156   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
157     strerror(errno), errno);
158 
159   res = pr_module_get("mod_bar.c");
160   fail_unless(res != NULL, "Failed to detect existing module");
161   fail_unless(res == &m, "Expected %p, got %p", &m, res);
162 
163   res = pr_module_get("mod_BAR.c");
164   fail_unless(res == NULL, "Failed to handle nonexistent module");
165   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
166     strerror(errno), errno);
167 
168   loaded_modules = NULL;
169 }
170 END_TEST
171 
172 static unsigned int listed = 0;
module_listf(const char * fmt,...)173 static int module_listf(const char *fmt, ...) {
174   listed++;
175   return 0;
176 }
177 
START_TEST(module_list_test)178 START_TEST (module_list_test) {
179   module m, m2;
180 
181   mark_point();
182   listed = 0;
183   modules_list2(module_listf, 0);
184   fail_unless(listed > 0, "Expected >0, got %u", listed);
185 
186   memset(&m, 0, sizeof(m));
187   m.name = "testsuite";
188   m.module_version = "a.b";
189 
190   memset(&m2, 0, sizeof(m2));
191   m2.name = "testsuite2";
192 
193   m.next = &m2;
194   loaded_modules = &m;
195 
196   mark_point();
197   listed = 0;
198   modules_list2(module_listf, PR_MODULES_LIST_FL_SHOW_STATIC);
199   fail_unless(listed > 0, "Expected >0, got %u", listed);
200 
201   mark_point();
202   listed = 0;
203   modules_list2(module_listf, PR_MODULES_LIST_FL_SHOW_VERSION);
204   fail_unless(listed > 0, "Expected >0, got %u", listed);
205 
206   mark_point();
207   modules_list(PR_MODULES_LIST_FL_SHOW_STATIC);
208 
209   loaded_modules = NULL;
210 }
211 END_TEST
212 
init_cb(void)213 static int init_cb(void) {
214   errno = EACCES;
215   return -1;
216 }
217 
START_TEST(module_load_test)218 START_TEST (module_load_test) {
219   int res;
220   module m;
221 
222   res = pr_module_load(NULL);
223   fail_unless(res < 0, "Failed to handle null argument");
224   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
225     strerror(errno), errno);
226 
227   memset(&m, 0, sizeof(m));
228 
229   res = pr_module_load(&m);
230   fail_unless(res < 0, "Failed to handle null name");
231   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
232     strerror(errno), errno);
233 
234   m.name = "foo";
235 
236   res = pr_module_load(&m);
237   fail_unless(res < 0, "Failed to handle badly versioned module");
238   fail_unless(errno == EACCES, "Expected EACCES (%d), got %s (%d)", EACCES,
239     strerror(errno), errno);
240 
241   m.api_version = PR_MODULE_API_VERSION;
242   m.init = init_cb;
243 
244   res = pr_module_load(&m);
245   fail_unless(res < 0, "Failed to handle bad module init callback");
246   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
247     strerror(errno), errno);
248 
249   m.init = NULL;
250 
251   res = pr_module_load(&m);
252   fail_unless(res == 0, "Failed to load module: %s", strerror(errno));
253 
254   res = pr_module_load(&m);
255   fail_unless(res < 0, "Failed to handle duplicate module load");
256   fail_unless(errno == EEXIST, "Expected EEXIST (%d), got %s (%d)", EEXIST,
257     strerror(errno), errno);
258 }
259 END_TEST
260 
START_TEST(module_unload_test)261 START_TEST (module_unload_test) {
262   int res;
263   module m;
264   authtable authtab[] = {
265     { 0, "setpwent", NULL },
266     { 0, NULL, NULL }
267   };
268   cmdtable cmdtab[] = {
269     { CMD, C_RETR, G_READ, NULL, TRUE, FALSE, CL_READ },
270     { HOOK, "foo", G_READ, NULL, FALSE, FALSE },
271     { 0, NULL }
272   };
273   conftable conftab[] = {
274     { "TestSuite", NULL, NULL },
275     { NULL }
276   };
277 
278   res = pr_module_unload(NULL);
279   fail_unless(res < 0, "Failed to handle null argument");
280   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
281     strerror(errno), errno);
282 
283   memset(&m, 0, sizeof(m));
284 
285   res = pr_module_unload(&m);
286   fail_unless(res < 0, "Failed to handle null module name");
287   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
288     strerror(errno), errno);
289 
290   m.name = "bar";
291 
292   res = pr_module_unload(&m);
293   fail_unless(res < 0, "Failed to handle nonexistent module");
294   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
295     strerror(errno), errno);
296 
297   loaded_modules = &m;
298 
299   res = pr_module_unload(&m);
300   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
301 
302   res = pr_module_unload(&m);
303   fail_unless(res < 0, "Failed to handle nonexistent module");
304   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
305     strerror(errno), errno);
306 
307   m.authtable = authtab;
308   m.cmdtable = cmdtab;
309   m.conftable = conftab;
310   loaded_modules = &m;
311 
312   res = pr_module_unload(&m);
313   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
314 
315   loaded_modules = NULL;
316 }
317 END_TEST
318 
START_TEST(module_load_authtab_test)319 START_TEST (module_load_authtab_test) {
320   int res;
321   module m;
322   authtable authtab[] = {
323     { 0, "setpwent", NULL },
324     { 0, NULL, NULL }
325   };
326 
327   res = pr_module_load_authtab(NULL);
328   fail_unless(res < 0, "Failed to handle null arguments");
329   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
330     strerror(errno), errno);
331 
332   memset(&m, 0, sizeof(m));
333 
334   res = pr_module_load_authtab(&m);
335   fail_unless(res < 0, "Failed to handle null module name");
336   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
337     strerror(errno), errno);
338 
339   m.name = "testsuite";
340   res = pr_module_load_authtab(&m);
341   fail_unless(res == 0, "Failed to load module authtab: %s", strerror(errno));
342 
343   pr_module_unload(&m);
344   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
345 
346   m.authtable = authtab;
347   res = pr_module_load_authtab(&m);
348   fail_unless(res == 0, "Failed to load module authtab: %s", strerror(errno));
349 
350   pr_module_unload(&m);
351   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
352 }
353 END_TEST
354 
START_TEST(module_load_cmdtab_test)355 START_TEST (module_load_cmdtab_test) {
356   int res;
357   module m;
358   cmdtable cmdtab[] = {
359     { CMD, C_RETR, G_READ, NULL, TRUE, FALSE, CL_READ },
360     { HOOK, "foo", G_READ, NULL, FALSE, FALSE },
361     { 0, NULL }
362   };
363 
364   res = pr_module_load_cmdtab(NULL);
365   fail_unless(res < 0, "Failed to handle null arguments");
366   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
367     strerror(errno), errno);
368 
369   memset(&m, 0, sizeof(m));
370 
371   res = pr_module_load_cmdtab(&m);
372   fail_unless(res < 0, "Failed to handle null module name");
373   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
374     strerror(errno), errno);
375 
376   m.name = "testsuite";
377   res = pr_module_load_cmdtab(&m);
378   fail_unless(res == 0, "Failed to load module cmdtab: %s", strerror(errno));
379 
380   pr_module_unload(&m);
381   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
382 
383   m.name = "testsuite";
384   m.cmdtable = cmdtab;
385   res = pr_module_load_cmdtab(&m);
386   fail_unless(res == 0, "Failed to load module cmdtab: %s", strerror(errno));
387 
388   pr_module_unload(&m);
389   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
390 }
391 END_TEST
392 
START_TEST(module_load_conftab_test)393 START_TEST (module_load_conftab_test) {
394   int res;
395   module m;
396   conftable conftab[] = {
397     { "TestSuite", NULL, NULL },
398     { NULL }
399   };
400 
401   res = pr_module_load_conftab(NULL);
402   fail_unless(res < 0, "Failed to handle null arguments");
403   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
404     strerror(errno), errno);
405 
406   memset(&m, 0, sizeof(m));
407 
408   res = pr_module_load_conftab(&m);
409   fail_unless(res < 0, "Failed to handle null module name");
410   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
411     strerror(errno), errno);
412 
413   m.name = "testsuite";
414   res = pr_module_load_conftab(&m);
415   fail_unless(res == 0, "Failed to load module conftab: %s", strerror(errno));
416 
417   pr_module_unload(&m);
418   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
419 
420   m.conftable = conftab;
421   res = pr_module_load_conftab(&m);
422   fail_unless(res == 0, "Failed to load module conftab: %s", strerror(errno));
423 
424   pr_module_unload(&m);
425   fail_unless(res == 0, "Failed to unload module: %s", strerror(errno));
426 }
427 END_TEST
428 
call_cb(cmd_rec * cmd)429 static modret_t *call_cb(cmd_rec *cmd) {
430   return PR_HANDLED(cmd);
431 }
432 
START_TEST(module_call_test)433 START_TEST (module_call_test) {
434   modret_t *res;
435   module m;
436   cmd_rec *cmd;
437 
438   res = pr_module_call(NULL, NULL, NULL);
439   fail_unless(res == NULL, "Failed to handle null arguments");
440   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
441     errno);
442 
443   memset(&m, 0, sizeof(m));
444 
445   res = pr_module_call(&m, NULL, NULL);
446   fail_unless(res == NULL, "Failed to handle null callback, cmd arguments");
447   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
448     errno);
449 
450   res = pr_module_call(NULL, call_cb, NULL);
451   fail_unless(res == NULL, "Failed to handle null module, cmd arguments");
452   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
453     errno);
454 
455   cmd = pcalloc(p, sizeof(cmd_rec));
456   cmd->pool = p;
457 
458   res = pr_module_call(NULL, NULL, cmd);
459   fail_unless(res == NULL, "Failed to handle null module, callback arguments");
460   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
461     errno);
462 
463   res = pr_module_call(&m, call_cb, NULL);
464   fail_unless(res == NULL, "Failed to handle null cmd argument");
465   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
466     errno);
467 
468   res = pr_module_call(&m, NULL, cmd);
469   fail_unless(res == NULL, "Failed to handle null callback argument");
470   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
471     errno);
472 
473   res = pr_module_call(NULL, call_cb, cmd);
474   fail_unless(res == NULL, "Failed to handle null module argument");
475   fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
476     errno);
477 
478   res = pr_module_call(&m, call_cb, cmd);
479   fail_unless(res != NULL, "Failed to call function: %s", strerror(errno));
480   fail_unless(MODRET_ISHANDLED(res), "Expected HANDLED result");
481 }
482 END_TEST
483 
START_TEST(module_create_ret_test)484 START_TEST (module_create_ret_test) {
485   cmd_rec *cmd;
486   modret_t *mr;
487   char *numeric, *msg;
488 
489   mr = mod_create_ret(NULL, 0, NULL, NULL);
490   fail_unless(mr == NULL, "Failed to handle null arguments");
491   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
492     strerror(errno), errno);
493 
494   cmd = pr_cmd_alloc(p, 1, "testsuite");
495   mr = mod_create_ret(cmd, 1, NULL, NULL);
496   fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
497   fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
498   fail_unless(mr->mr_numeric == NULL, "Expected null, got '%s'",
499     mr->mr_numeric);
500   fail_unless(mr->mr_message == NULL, "Expected null, got '%s'",
501     mr->mr_message);
502 
503   numeric = "foo";
504   msg = "bar";
505   mr = mod_create_ret(cmd, 1, numeric, msg);
506   fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
507   fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
508   fail_unless(mr->mr_numeric != NULL, "Expected '%s', got null");
509   fail_unless(strcmp(mr->mr_numeric, numeric) == 0,
510     "Expected '%s', got '%s'", numeric, mr->mr_numeric);
511   fail_unless(mr->mr_message != NULL, "Expected '%s', got null");
512   fail_unless(strcmp(mr->mr_message, msg) == 0,
513     "Expected '%s', got '%s'", msg, mr->mr_message);
514 }
515 END_TEST
516 
START_TEST(module_create_error_test)517 START_TEST (module_create_error_test) {
518   cmd_rec *cmd;
519   modret_t *mr;
520 
521   mr = mod_create_error(NULL, 0);
522   fail_unless(mr == NULL, "Failed to handle null arguments");
523   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
524     strerror(errno), errno);
525 
526   cmd = pr_cmd_alloc(p, 1, "testsuite");
527   mr = mod_create_error(cmd, 1);
528   fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
529   fail_unless(mr->mr_error == 1, "Expected 1, got %d", mr->mr_error);
530 }
531 END_TEST
532 
START_TEST(module_create_data_test)533 START_TEST (module_create_data_test) {
534   cmd_rec *cmd;
535   modret_t *mr;
536   int data = 1;
537 
538   mr = mod_create_data(NULL, NULL);
539   fail_unless(mr == NULL, "Failed to handle null arguments");
540   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
541     strerror(errno), errno);
542 
543   cmd = pr_cmd_alloc(p, 1, "testsuite");
544   mr = mod_create_data(cmd, &data);
545   fail_unless(mr != NULL, "Failed to create modret: %s", strerror(errno));
546   fail_unless(mr->data == &data, "Expected %p, got %p", &data, mr->data);
547 }
548 END_TEST
549 
tests_get_modules_suite(void)550 Suite *tests_get_modules_suite(void) {
551   Suite *suite;
552   TCase *testcase;
553 
554   suite = suite_create("modules");
555 
556   testcase = tcase_create("module");
557   tcase_add_checked_fixture(testcase, set_up, tear_down);
558 
559   tcase_add_test(testcase, module_sess_init_test);
560   tcase_add_test(testcase, module_command_exists_test);
561   tcase_add_test(testcase, module_exists_test);
562   tcase_add_test(testcase, module_get_test);
563   tcase_add_test(testcase, module_list_test);
564   tcase_add_test(testcase, module_load_test);
565   tcase_add_test(testcase, module_unload_test);
566   tcase_add_test(testcase, module_load_authtab_test);
567   tcase_add_test(testcase, module_load_cmdtab_test);
568   tcase_add_test(testcase, module_load_conftab_test);
569   tcase_add_test(testcase, module_call_test);
570 
571   tcase_add_test(testcase, module_create_ret_test);
572   tcase_add_test(testcase, module_create_error_test);
573   tcase_add_test(testcase, module_create_data_test);
574 
575   suite_add_tcase(suite, testcase);
576   return suite;
577 }
578