1 /*
2 * ProFTPD - FTP server testsuite
3 * Copyright (c) 2011-2020 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 /* Response API tests */
26
27 #include "tests.h"
28
29 extern pr_response_t *resp_list, *resp_err_list;
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 init_netio();
39 init_inet();
40
41 if (getenv("TEST_VERBOSE") != NULL) {
42 pr_trace_set_levels("netio", 1, 20);
43 pr_trace_set_levels("response", 1, 20);
44 }
45 }
46
tear_down(void)47 static void tear_down(void) {
48 pr_response_register_handler(NULL);
49
50 if (session.c != NULL) {
51 pr_inet_close(p, session.c);
52 session.c = NULL;
53 }
54
55 pr_unregister_netio(PR_NETIO_STRM_CTRL);
56
57 if (getenv("TEST_VERBOSE") != NULL) {
58 pr_trace_set_levels("netio", 0, 0);
59 pr_trace_set_levels("response", 0, 0);
60 }
61
62 if (p) {
63 destroy_pool(p);
64 p = permanent_pool = NULL;
65 }
66 }
67
START_TEST(response_pool_get_test)68 START_TEST (response_pool_get_test) {
69 pool *res;
70
71 res = pr_response_get_pool();
72 fail_unless(res == NULL, "Response pool not null as expected");
73 }
74 END_TEST
75
START_TEST(response_pool_set_test)76 START_TEST (response_pool_set_test) {
77 pool *res;
78
79 pr_response_set_pool(p);
80 res = pr_response_get_pool();
81 fail_unless(res == p, "Response pool not %p as expected", p);
82 }
83 END_TEST
84
START_TEST(response_add_test)85 START_TEST (response_add_test) {
86 int res;
87 const char *last_resp_code = NULL, *last_resp_msg = NULL;
88 char *resp_code = R_200, *resp_msg = "OK";
89
90 pr_response_set_pool(NULL);
91
92 mark_point();
93 pr_response_add(resp_code, "%s", resp_msg);
94
95 pr_response_set_pool(p);
96
97 mark_point();
98 pr_response_add(NULL, NULL);
99
100 mark_point();
101 pr_response_add(NULL, "%s", resp_msg);
102
103 mark_point();
104 pr_response_add(resp_code, "%s", resp_msg);
105 pr_response_add(NULL, "%s", resp_msg);
106
107 res = pr_response_get_last(p, &last_resp_code, &last_resp_msg);
108 fail_unless(res == 0, "Failed to get last values: %d (%s)", errno,
109 strerror(errno));
110
111 fail_unless(last_resp_code != NULL, "Last response code unexpectedly null");
112 fail_unless(strcmp(last_resp_code, resp_code) == 0,
113 "Expected response code '%s', got '%s'", resp_code, last_resp_code);
114
115 fail_unless(last_resp_msg != NULL, "Last response message unexpectedly null");
116 fail_unless(strcmp(last_resp_msg, resp_msg) == 0,
117 "Expected response message '%s', got '%s'", resp_msg, last_resp_msg);
118 }
119 END_TEST
120
START_TEST(response_add_err_test)121 START_TEST (response_add_err_test) {
122 int res;
123 const char *last_resp_code = NULL, *last_resp_msg = NULL;
124 char *resp_code = R_450, *resp_msg = "Busy";
125
126 pr_response_set_pool(NULL);
127
128 mark_point();
129 pr_response_add(resp_code, "%s", resp_msg);
130
131 pr_response_set_pool(p);
132
133 mark_point();
134 pr_response_add_err(NULL, NULL);
135
136 mark_point();
137 pr_response_add_err(resp_code, "%s", resp_msg);
138
139 res = pr_response_get_last(p, &last_resp_code, &last_resp_msg);
140 fail_unless(res == 0, "Failed to get last values: %d (%s)", errno,
141 strerror(errno));
142
143 fail_unless(last_resp_code != NULL, "Last response code unexpectedly null");
144 fail_unless(strcmp(last_resp_code, resp_code) == 0,
145 "Expected response code '%s', got '%s'", resp_code, last_resp_code);
146
147 fail_unless(last_resp_msg != NULL, "Last response message unexpectedly null");
148 fail_unless(strcmp(last_resp_msg, resp_msg) == 0,
149 "Expected response message '%s', got '%s'", resp_msg, last_resp_msg);
150 }
151 END_TEST
152
START_TEST(response_get_last_test)153 START_TEST (response_get_last_test) {
154 int res;
155 const char *resp_code = NULL, *resp_msg = NULL;
156
157 res = pr_response_get_last(NULL, NULL, NULL);
158 fail_unless(res == -1, "Failed to handle null pool");
159 fail_unless(errno == EINVAL, "Expected errno %d (%s), got %d (%s)",
160 EINVAL, strerror(EINVAL), errno, strerror(errno));
161
162 res = pr_response_get_last(p, NULL, NULL);
163 fail_unless(res == -1, "Failed to handle null argument");
164 fail_unless(errno == EINVAL, "Expected errno %d (%s), got %d (%s)",
165 EINVAL, strerror(EINVAL), errno, strerror(errno));
166
167 res = pr_response_get_last(p, &resp_code, &resp_msg);
168 fail_unless(res == 0, "Failed to get last values: %d (%s)", errno,
169 strerror(errno));
170
171 fail_unless(resp_code == NULL,
172 "Last response code not null as expected: %s", resp_code);
173 fail_unless(resp_msg == NULL,
174 "Last response message not null as expected: %s", resp_msg);
175 }
176 END_TEST
177
START_TEST(response_block_test)178 START_TEST (response_block_test) {
179 int res;
180
181 res = pr_response_block(-1);
182 fail_unless(res == -1, "Failed to handle invalid argument");
183 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)",
184 EINVAL, strerror(errno), errno);
185
186 res = pr_response_block(TRUE);
187 fail_unless(res == 0, "Failed to block responses: %s", strerror(errno));
188
189 res = pr_response_block(FALSE);
190 fail_unless(res == 0, "Failed to unblock responses: %s", strerror(errno));
191 }
192 END_TEST
193
START_TEST(response_blocked_test)194 START_TEST (response_blocked_test) {
195 int res;
196
197 (void) pr_response_block(TRUE);
198 res = pr_response_blocked();
199 fail_unless(res == TRUE, "Failed to detect blocked responses");
200
201 (void) pr_response_block(FALSE);
202 res = pr_response_blocked();
203 fail_unless(res == FALSE, "Failed to detect unblocked responses");
204 }
205 END_TEST
206
START_TEST(response_clear_test)207 START_TEST (response_clear_test) {
208 mark_point();
209 pr_response_clear(NULL);
210
211 pr_response_set_pool(p);
212 pr_response_add(R_200, "%s", "OK");
213 pr_response_clear(&resp_list);
214 }
215 END_TEST
216
response_netio_poll_cb(pr_netio_stream_t * nstrm)217 static int response_netio_poll_cb(pr_netio_stream_t *nstrm) {
218 /* Always return >0, to indicate that we haven't timed out, AND that there
219 * is a writable fd available.
220 */
221 return 7;
222 }
223
response_netio_write_cb(pr_netio_stream_t * nstrm,char * buf,size_t buflen)224 static int response_netio_write_cb(pr_netio_stream_t *nstrm, char *buf,
225 size_t buflen) {
226 return buflen;
227 }
228
229 static unsigned int resp_nlines = 0;
230 static char *resp_line = NULL;
231
response_handler_cb(pool * cb_pool,const char * fmt,...)232 static char *response_handler_cb(pool *cb_pool, const char *fmt, ...) {
233 char buf[PR_RESPONSE_BUFFER_SIZE] = {'\0'};
234 va_list msg;
235
236 va_start(msg, fmt);
237 vsnprintf(buf, sizeof(buf), fmt, msg);
238 va_end(msg);
239
240 buf[sizeof(buf)-1] = '\0';
241
242 resp_nlines++;
243 resp_line = pstrdup(cb_pool, buf);
244 return resp_line;
245 }
246
START_TEST(response_flush_test)247 START_TEST (response_flush_test) {
248 int res, sockfd = -2;
249 conn_t *conn;
250 pr_netio_t *netio;
251
252 mark_point();
253 pr_response_flush(NULL);
254
255 netio = pr_alloc_netio2(p, NULL, "testsuite");
256 netio->poll = response_netio_poll_cb;
257 netio->write = response_netio_write_cb;
258
259 res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
260 fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
261 strerror(errno));
262
263 conn = pr_inet_create_conn(p, sockfd, NULL, INPORT_ANY, FALSE);
264 session.c = conn;
265
266 pr_response_register_handler(response_handler_cb);
267
268 resp_nlines = 0;
269 resp_line = NULL;
270 pr_response_set_pool(p);
271
272 pr_response_add(R_200, "%s", "OK");
273 pr_response_add(R_DUP, "%s", "Still OK");
274 pr_response_add(R_DUP, "%s", "OK already!");
275 pr_response_flush(&resp_list);
276
277 pr_response_register_handler(NULL);
278 pr_inet_close(p, session.c);
279 session.c = NULL;
280 pr_unregister_netio(PR_NETIO_STRM_CTRL);
281
282 fail_unless(resp_nlines == 3, "Expected 3 response lines flushed, got %u",
283 resp_nlines);
284 }
285 END_TEST
286
START_TEST(response_send_test)287 START_TEST (response_send_test) {
288 int res, sockfd = -2;
289 conn_t *conn;
290 pr_netio_t *netio;
291
292 netio = pr_alloc_netio2(p, NULL, "testsuite");
293 netio->poll = response_netio_poll_cb;
294 netio->write = response_netio_write_cb;
295
296 res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
297 fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
298 strerror(errno));
299
300 conn = pr_inet_create_conn(p, sockfd, NULL, INPORT_ANY, FALSE);
301 session.c = conn;
302
303 pr_response_register_handler(response_handler_cb);
304
305 resp_nlines = 0;
306 resp_line = NULL;
307 pr_response_set_pool(p);
308
309 pr_response_send(R_200, "%s", "OK");
310
311 pr_response_register_handler(NULL);
312 pr_inet_close(p, session.c);
313 session.c = NULL;
314 pr_unregister_netio(PR_NETIO_STRM_CTRL);
315
316 fail_unless(resp_nlines == 1, "Expected 1 response line flushed, got %u",
317 resp_nlines);
318 }
319 END_TEST
320
START_TEST(response_send_async_test)321 START_TEST (response_send_async_test) {
322 int res, sockfd = -2;
323 conn_t *conn;
324 pr_netio_t *netio;
325
326 netio = pr_alloc_netio2(p, NULL, "testsuite");
327 netio->poll = response_netio_poll_cb;
328 netio->write = response_netio_write_cb;
329
330 res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
331 fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
332 strerror(errno));
333
334 conn = pr_inet_create_conn(p, sockfd, NULL, INPORT_ANY, FALSE);
335 session.c = conn;
336
337 pr_response_register_handler(response_handler_cb);
338
339 resp_nlines = 0;
340 resp_line = NULL;
341 pr_response_set_pool(p);
342
343 pr_response_send_async(R_200, "%s", "OK");
344
345 pr_response_register_handler(NULL);
346 pr_inet_close(p, session.c);
347 session.c = NULL;
348 pr_unregister_netio(PR_NETIO_STRM_CTRL);
349
350 fail_unless(resp_nlines == 1, "Expected 1 response line flushed, got %u",
351 resp_nlines);
352 fail_unless(resp_line != NULL, "Expected response line");
353 fail_unless(strcmp(resp_line, "200 OK\r\n") == 0,
354 "Expected '200 OK', got '%s'", resp_line);
355 }
356 END_TEST
357
START_TEST(response_send_raw_test)358 START_TEST (response_send_raw_test) {
359 int res, sockfd = -2;
360 conn_t *conn;
361 pr_netio_t *netio;
362
363 netio = pr_alloc_netio2(p, NULL, "testsuite");
364 netio->poll = response_netio_poll_cb;
365 netio->write = response_netio_write_cb;
366
367 res = pr_register_netio(netio, PR_NETIO_STRM_CTRL);
368 fail_unless(res == 0, "Failed to register custom ctrl NetIO: %s",
369 strerror(errno));
370
371 conn = pr_inet_create_conn(p, sockfd, NULL, INPORT_ANY, FALSE);
372 session.c = conn;
373
374 pr_response_register_handler(response_handler_cb);
375
376 resp_nlines = 0;
377 resp_line = NULL;
378 pr_response_set_pool(p);
379
380 pr_response_send_raw("%s", "OK");
381
382 pr_response_register_handler(NULL);
383 pr_inet_close(p, session.c);
384 session.c = NULL;
385 pr_unregister_netio(PR_NETIO_STRM_CTRL);
386
387 fail_unless(resp_nlines == 1, "Expected 1 response line flushed, got %u",
388 resp_nlines);
389 }
390 END_TEST
391
392 #if defined(TEST_BUG3711)
START_TEST(response_pool_bug3711_test)393 START_TEST (response_pool_bug3711_test) {
394 cmd_rec *cmd;
395 pool *resp_pool, *cmd_pool;
396 char *err_code = R_450, *err_msg = "Busy";
397
398 resp_pool = make_sub_pool(p);
399 cmd_pool = make_sub_pool(p);
400
401 cmd = pr_cmd_alloc(cmd_pool, 1, "foo");
402
403 pr_response_set_pool(cmd->pool);
404 pr_response_add_err(err_code, "%s", err_msg);
405
406 /* We expect segfaults here, so use the mark_point() function to get
407 * more accurate reporting of the problematic line of code in the
408 * error logs.
409 */
410 mark_point();
411
412 /* We explicitly do NOT reset the Response API pool here, to emulate the
413 * behavior of Bug#3711.
414 *
415 * In the future, we could address this by proving a Pool API function
416 * that e.g. the Response API could use, to check whether the given
417 * pool is still a valid pool. To do this, the Pool API would keep a
418 * list of allocated pools, which would then be scanned. In practice such
419 * a list is maintained, albeit in a tree form. And there is tracking
420 * of the root trees for pools; permanent_pool is not the only root pool
421 * which can be created/used.
422 */
423 destroy_pool(cmd_pool);
424
425 mark_point();
426 pr_response_add_err(err_code, "%s", err_msg);
427
428 mark_point();
429 pr_response_add_err(err_code, "%s", err_msg);
430
431 mark_point();
432 pr_response_add_err(err_code, "%s", err_msg);
433 }
434 END_TEST
435 #endif /* TEST_BUG3711 */
436
tests_get_response_suite(void)437 Suite *tests_get_response_suite(void) {
438 Suite *suite;
439 TCase *testcase;
440 #if defined(TEST_BUG3711)
441 int bug3711_signo = 0;
442 #endif /* TEST_BUG3711 */
443
444 suite = suite_create("response");
445
446 testcase = tcase_create("base");
447 tcase_add_checked_fixture(testcase, set_up, tear_down);
448
449 tcase_add_test(testcase, response_pool_get_test);
450 tcase_add_test(testcase, response_pool_set_test);
451 tcase_add_test(testcase, response_add_test);
452 tcase_add_test(testcase, response_add_err_test);
453 tcase_add_test(testcase, response_get_last_test);
454
455 tcase_add_test(testcase, response_block_test);
456 tcase_add_test(testcase, response_blocked_test);
457 tcase_add_test(testcase, response_clear_test);
458 tcase_add_test(testcase, response_flush_test);
459 tcase_add_test(testcase, response_send_test);
460 tcase_add_test(testcase, response_send_async_test);
461 tcase_add_test(testcase, response_send_raw_test);
462
463 #if defined(TEST_BUG3711)
464 /* We expect this test to fail due to a segfault; see Bug#3711.
465 *
466 * Note that on some platforms (e.g. Darwin), the test case should fail
467 * with a SIGBUS rather than SIGSEGV, hence the conditional here.
468 */
469 #if defined(DARWIN9) || defined(DARWIN10) || defined(DARWIN11)
470 bug3711_signo = SIGBUS;
471 #else
472 bug3711_signo = SIGSEGV;
473 #endif
474
475 /* Disable this test for now; it's a reproduction recipe rather than
476 * a regression test, and only generates core files which can litter
477 * the filesystems of build/test machines needlessly.
478 */
479 tcase_add_test_raise_signal(testcase, response_pool_bug3711_test,
480 bug3711_signo);
481 #endif /* TEST_BUG3711 */
482
483 suite_add_tcase(suite, testcase);
484 return suite;
485 }
486