1 /*
2 * ProFTPD - FTP server testsuite
3 * Copyright (c) 2015-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 /* Miscellaneous tests
26 */
27
28 #include "tests.h"
29
30 static pool *p = NULL;
31
32 static unsigned int schedule_called = 0;
33 static const char *misc_test_shutmsg = "/tmp/prt-shutmsg.dat";
34 static const char *misc_test_readlink = "/tmp/prt-readlink.lnk";
35 static const char *misc_test_readlink2_dir = "/tmp/prt-readlink/";
36 static const char *misc_test_readlink2 = "/tmp/prt-readlink/test.lnk";
37
38 /* Fixtures */
39
set_up(void)40 static void set_up(void) {
41 (void) unlink(misc_test_readlink);
42 (void) unlink(misc_test_readlink2);
43 (void) unlink(misc_test_shutmsg);
44 (void) rmdir(misc_test_readlink2_dir);
45
46 if (p == NULL) {
47 p = permanent_pool = make_sub_pool(NULL);
48 }
49
50 init_fs();
51 pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE,
52 PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0);
53
54 if (getenv("TEST_VERBOSE") != NULL) {
55 pr_trace_set_levels("auth", 1, 20);
56 pr_trace_set_levels("fsio", 1, 20);
57 pr_trace_set_levels("fs.statcache", 1, 20);
58 }
59
60 schedule_called = 0;
61 session.user = NULL;
62 }
63
tear_down(void)64 static void tear_down(void) {
65 (void) unlink(misc_test_readlink);
66 (void) unlink(misc_test_readlink2);
67 (void) unlink(misc_test_shutmsg);
68 (void) rmdir(misc_test_readlink2_dir);
69
70 pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE,
71 PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0);
72
73 if (getenv("TEST_VERBOSE") != NULL) {
74 pr_trace_set_levels("auth", 0, 0);
75 pr_trace_set_levels("fsio", 0, 0);
76 pr_trace_set_levels("fs.statcache", 0, 0);
77 }
78
79 session.user = NULL;
80
81 if (p) {
82 destroy_pool(p);
83 p = session.pool = permanent_pool = NULL;
84 }
85 }
86
schedule_cb(void * arg1,void * arg2,void * arg3,void * arg4)87 static void schedule_cb(void *arg1, void *arg2, void *arg3, void *arg4) {
88 schedule_called++;
89 }
90
91 /* Tests */
92
START_TEST(schedule_test)93 START_TEST (schedule_test) {
94 mark_point();
95 schedule(NULL, 0, NULL, NULL, NULL, NULL);
96
97 mark_point();
98 schedule(schedule_cb, -1, NULL, NULL, NULL, NULL);
99
100 mark_point();
101 run_schedule();
102
103 mark_point();
104 schedule(schedule_cb, 0, NULL, NULL, NULL, NULL);
105
106 run_schedule();
107 fail_unless(schedule_called == 1, "Expected 1, got %u", schedule_called);
108
109 run_schedule();
110 fail_unless(schedule_called == 1, "Expected 1, got %u", schedule_called);
111
112 mark_point();
113 schedule(schedule_cb, 0, NULL, NULL, NULL, NULL);
114 schedule(schedule_cb, 0, NULL, NULL, NULL, NULL);
115
116 run_schedule();
117 fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called);
118
119 run_schedule();
120 fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called);
121
122 mark_point();
123
124 /* Schedule this callback to run after 2 "loops", i.e. calls to
125 * run_schedule().
126 */
127 schedule(schedule_cb, 2, NULL, NULL, NULL, NULL);
128
129 run_schedule();
130 fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called);
131
132 run_schedule();
133 fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called);
134
135 run_schedule();
136 fail_unless(schedule_called == 4, "Expected 4, got %u", schedule_called);
137 }
138 END_TEST
139
START_TEST(get_name_max_test)140 START_TEST (get_name_max_test) {
141 long res;
142 char *path;
143 int fd;
144
145 res = get_name_max(NULL, -1);
146 fail_unless(res < 0, "Failed to handle invalid arguments");
147 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
148 strerror(errno), errno);
149
150 path = "/";
151 res = get_name_max(path, -1);
152 fail_if(res < 0, "Failed to handle path '%s': %s", path, strerror(errno));
153
154 fd = 1;
155 res = get_name_max(NULL, fd);
156
157 /* It seems that fpathconf(2) on some platforms will handle stdin as a
158 * valid file descriptor, and some will not.
159 */
160 if (res < 0) {
161 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
162 strerror(errno), errno);
163 }
164 }
165 END_TEST
166
START_TEST(dir_interpolate_test)167 START_TEST (dir_interpolate_test) {
168 char *res;
169 const char *path;
170
171 res = dir_interpolate(NULL, NULL);
172 fail_unless(res == NULL, "Failed to handle null arguments");
173 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
174 strerror(errno), errno);
175
176 res = dir_interpolate(p, NULL);
177 fail_unless(res == NULL, "Failed to handle null path");
178 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
179 strerror(errno), errno);
180
181 mark_point();
182 path = "/foo";
183 res = dir_interpolate(p, path);
184 fail_unless(path != NULL, "Failed to interpolate '%s': %s", path,
185 strerror(errno));
186 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
187
188 mark_point();
189 path = "~foo.bar.bar.quxx.quzz/foo";
190 res = dir_interpolate(p, path);
191 fail_unless(path != NULL, "Failed to interpolate '%s': %s", path,
192 strerror(errno));
193 fail_unless(*path == '~', "Interpolated path with unknown user unexpectedly");
194 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
195 strerror(errno), errno);
196 }
197 END_TEST
198
START_TEST(dir_best_path_test)199 START_TEST (dir_best_path_test) {
200 char *res;
201 const char *path;
202
203 res = dir_best_path(NULL, NULL);
204 fail_unless(res == NULL, "Failed to handle null arguments");
205 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
206 strerror(errno), errno);
207
208 res = dir_best_path(p, NULL);
209 fail_unless(res == NULL, "Failed to handle null path");
210 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
211 strerror(errno), errno);
212
213 mark_point();
214 path = "/foo";
215 res = dir_best_path(p, path);
216 fail_unless(path != NULL, "Failed to get best path for '%s': %s", path,
217 strerror(errno));
218 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
219 }
220 END_TEST
221
START_TEST(dir_canonical_path_test)222 START_TEST (dir_canonical_path_test) {
223 char *res;
224 const char *path;
225
226 res = dir_canonical_path(NULL, NULL);
227 fail_unless(res == NULL, "Failed to handle null arguments");
228 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
229 strerror(errno), errno);
230
231 res = dir_canonical_path(p, NULL);
232 fail_unless(res == NULL, "Failed to handle null path");
233 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
234 strerror(errno), errno);
235
236 mark_point();
237 path = "/foo";
238 res = dir_canonical_path(p, path);
239 fail_unless(path != NULL, "Failed to get canonical path for '%s': %s", path,
240 strerror(errno));
241 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
242 }
243 END_TEST
244
START_TEST(dir_canonical_vpath_test)245 START_TEST (dir_canonical_vpath_test) {
246 char *res;
247 const char *path;
248
249 res = dir_canonical_vpath(NULL, NULL);
250 fail_unless(res == NULL, "Failed to handle null arguments");
251 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
252 strerror(errno), errno);
253
254 res = dir_canonical_vpath(p, NULL);
255 fail_unless(res == NULL, "Failed to handle null path");
256 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
257 strerror(errno), errno);
258
259 mark_point();
260 path = "/foo";
261 res = dir_canonical_vpath(p, path);
262 fail_unless(path != NULL, "Failed to get canonical vpath for '%s': %s", path,
263 strerror(errno));
264 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
265 }
266 END_TEST
267
START_TEST(dir_readlink_test)268 START_TEST (dir_readlink_test) {
269 int res, flags = 0;
270 const char *path;
271 char *buf, *dst_path, *expected_path;
272 size_t bufsz, dst_pathlen, expected_pathlen;
273
274 (void) unlink(misc_test_readlink);
275
276 /* Parameter validation */
277 res = dir_readlink(NULL, NULL, NULL, 0, flags);
278 fail_unless(res < 0, "Failed to handle null arguments");
279 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
280 strerror(errno), errno);
281
282 res = dir_readlink(p, NULL, NULL, 0, flags);
283 fail_unless(res < 0, "Failed to handle null path");
284 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
285 strerror(errno), errno);
286
287 path = misc_test_readlink;
288 res = dir_readlink(p, path, NULL, 0, flags);
289 fail_unless(res < 0, "Failed to handle null buffer");
290 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
291 strerror(errno), errno);
292
293 bufsz = 1024;
294 buf = palloc(p, bufsz);
295 res = dir_readlink(p, path, buf, 0, flags);
296 fail_unless(res == 0, "Failed to handle zero buffer length");
297
298 res = dir_readlink(p, path, buf, bufsz, flags);
299 fail_unless(res < 0, "Failed to handle nonexistent file");
300 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
301 strerror(errno), errno);
302
303 dst_path = "";
304 res = symlink(dst_path, path);
305 if (res == 0) {
306 /* Some platforms will not allow creation of empty symlinks. Nice of
307 * them.
308 */
309 res = dir_readlink(p, path, buf, bufsz, flags);
310 fail_unless(res == 0, "Failed to handle empty symlink");
311 }
312 (void) unlink(path);
313
314 /* Not chrooted, absolute dst path */
315 memset(buf, '\0', bufsz);
316 dst_path = "/home/user/file.dat";
317 dst_pathlen = strlen(dst_path);
318 res = symlink(dst_path, path);
319 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
320 strerror(errno));
321
322 res = dir_readlink(p, path, buf, bufsz, flags);
323 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
324 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
325 (unsigned long) dst_pathlen, res);
326 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
327 dst_path, buf);
328
329 /* Not chrooted, relative dst path, flags to ignore rel path */
330 memset(buf, '\0', bufsz);
331 dst_path = "./file.dat";
332 dst_pathlen = strlen(dst_path);
333
334 (void) unlink(path);
335 res = symlink(dst_path, path);
336 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
337 strerror(errno));
338
339 res = dir_readlink(p, path, buf, bufsz, flags);
340 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
341 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
342 (unsigned long) dst_pathlen, res);
343 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
344 dst_path, buf);
345
346 /* Not chrooted, relative dst path without leading '.', flags to ignore rel
347 * path.
348 */
349 memset(buf, '\0', bufsz);
350 dst_path = "file.dat";
351 dst_pathlen = strlen(dst_path);
352
353 (void) unlink(path);
354 res = symlink(dst_path, path);
355 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
356 strerror(errno));
357
358 res = dir_readlink(p, path, buf, bufsz, flags);
359 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
360 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
361 (unsigned long) dst_pathlen, res);
362 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
363 dst_path, buf);
364
365 /* Not chrooted, relative dst path, flags to HANDLE rel path */
366 memset(buf, '\0', bufsz);
367 dst_path = "./file.dat";
368 dst_pathlen = strlen(dst_path);
369 expected_path = "/tmp/file.dat";
370 expected_pathlen = strlen(expected_path);
371
372 (void) unlink(path);
373 res = symlink(dst_path, path);
374 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
375 strerror(errno));
376
377 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
378 res = dir_readlink(p, path, buf, bufsz, flags);
379 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
380 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
381 (unsigned long) expected_pathlen, res);
382 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
383 expected_path, buf);
384
385 /* Not chrooted, relative dst path without leading '.', flags to HANDLE rel
386 * path.
387 */
388 memset(buf, '\0', bufsz);
389 dst_path = "file.dat";
390 dst_pathlen = strlen(dst_path);
391 expected_path = "/tmp/file.dat";
392 expected_pathlen = strlen(expected_path);
393
394 (void) unlink(path);
395 res = symlink(dst_path, path);
396 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
397 strerror(errno));
398
399 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
400 res = dir_readlink(p, path, buf, bufsz, flags);
401 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
402 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
403 (unsigned long) expected_pathlen, res);
404 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
405 expected_path, buf);
406
407 /* Not chrooted, dst path longer than given buffer */
408 flags = 0;
409 memset(buf, '\0', bufsz);
410 res = dir_readlink(p, path, buf, 2, flags);
411 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
412 fail_unless(res == 2, "Expected length 2, got %d", res);
413 fail_unless(strncmp(buf, dst_path, 2) == 0, "Expected '%*s', got '%*s'",
414 2, dst_path, 2, buf);
415
416 /* Chrooted to "/" */
417 session.chroot_path = "/";
418 memset(buf, '\0', bufsz);
419 res = dir_readlink(p, path, buf, bufsz, flags);
420 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
421 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
422 (unsigned long) dst_pathlen, res);
423 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
424 dst_path, buf);
425
426 /* Chrooted, absolute destination path shorter than chroot path */
427 session.chroot_path = "/home/user";
428 memset(buf, '\0', bufsz);
429 dst_path = "/foo";
430 dst_pathlen = strlen(dst_path);
431
432 (void) unlink(path);
433 res = symlink(dst_path, path);
434 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
435 strerror(errno));
436
437 res = dir_readlink(p, path, buf, bufsz, flags);
438 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
439 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
440 (unsigned long) dst_pathlen, res);
441 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
442 dst_path, buf);
443
444 /* Chrooted, overlapping chroot to non-dir */
445 memset(buf, '\0', bufsz);
446 dst_path = "/home/user2";
447 dst_pathlen = strlen(dst_path);
448
449 (void) unlink(path);
450 res = symlink(dst_path, path);
451 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
452 strerror(errno));
453
454 res = dir_readlink(p, path, buf, bufsz, flags);
455 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
456 fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d",
457 (unsigned long) dst_pathlen, res);
458 fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'",
459 dst_path, buf);
460
461 /* Chrooted, absolute destination within chroot */
462 memset(buf, '\0', bufsz);
463 dst_path = "/home/user/file.txt";
464 dst_pathlen = strlen(dst_path);
465 expected_path = "/file.txt";
466 expected_pathlen = strlen(expected_path);
467
468 (void) unlink(path);
469 res = symlink(dst_path, path);
470 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
471 strerror(errno));
472
473 res = dir_readlink(p, path, buf, bufsz, flags);
474 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
475 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
476 (unsigned long) expected_pathlen, res);
477 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
478 expected_path, buf);
479
480 /* Chrooted, absolute destination outside of chroot */
481 memset(buf, '\0', bufsz);
482 dst_path = "/home/user/../file.txt";
483 dst_pathlen = strlen(dst_path);
484 expected_path = "/home/file.txt";
485 expected_pathlen = strlen(expected_path);
486
487 (void) unlink(path);
488 res = symlink(dst_path, path);
489 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
490 strerror(errno));
491
492 res = dir_readlink(p, path, buf, bufsz, flags);
493 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
494 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
495 (unsigned long) expected_pathlen, res);
496 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
497 expected_path, buf);
498
499 /* Chrooted, relative destination within chroot */
500 memset(buf, '\0', bufsz);
501 dst_path = "./file.txt";
502 dst_pathlen = strlen(dst_path);
503 expected_path = "./file.txt";
504 expected_pathlen = strlen(expected_path);
505
506 (void) unlink(path);
507 res = symlink(dst_path, path);
508 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
509 strerror(errno));
510
511 res = dir_readlink(p, path, buf, bufsz, flags);
512 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
513 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
514 (unsigned long) expected_pathlen, res);
515 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
516 expected_path, buf);
517
518 /* Chrooted, relative destination (without leading '.') within chroot */
519 memset(buf, '\0', bufsz);
520 dst_path = "file.txt";
521 dst_pathlen = strlen(dst_path);
522 expected_path = "file.txt";
523 expected_pathlen = strlen(expected_path);
524
525 (void) unlink(path);
526 res = symlink(dst_path, path);
527 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
528 strerror(errno));
529
530 res = dir_readlink(p, path, buf, bufsz, flags);
531 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
532 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
533 (unsigned long) expected_pathlen, res);
534 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
535 expected_path, buf);
536
537 /* Chrooted, relative destination outside of chroot */
538 memset(buf, '\0', bufsz);
539 dst_path = "../file.txt";
540 dst_pathlen = strlen(dst_path);
541 expected_path = "../file.txt";
542 expected_pathlen = strlen(expected_path);
543
544 (void) unlink(path);
545 res = symlink(dst_path, path);
546 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
547 strerror(errno));
548
549 /* First, tell dir_readlink() to ignore relative destination paths. */
550 flags = 0;
551 res = dir_readlink(p, path, buf, bufsz, flags);
552 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
553 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
554 (unsigned long) expected_pathlen, res);
555 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
556 expected_path, buf);
557
558 /* Now do it again, telling dir_readlink() to handle relative destination
559 * paths.
560 */
561 memset(buf, '\0', bufsz);
562 dst_path = "../file.txt";
563 dst_pathlen = strlen(dst_path);
564 expected_path = "/file.txt";
565 expected_pathlen = strlen(expected_path);
566
567 (void) unlink(path);
568 res = symlink(dst_path, path);
569 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
570 strerror(errno));
571
572 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
573 res = dir_readlink(p, path, buf, bufsz, flags);
574 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
575 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
576 (unsigned long) expected_pathlen, res);
577 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
578 expected_path, buf);
579
580 /* One more time, this time changing the chroot path to align with the
581 * source path.
582 */
583 memset(buf, '\0', bufsz);
584 dst_path = "../file.txt";
585 dst_pathlen = strlen(dst_path);
586 expected_path = "/file.txt";
587 expected_pathlen = strlen(expected_path);
588
589 (void) unlink(path);
590 res = symlink(dst_path, path);
591 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
592 strerror(errno));
593
594 session.chroot_path = "/tmp";
595 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
596 res = dir_readlink(p, path, buf, bufsz, flags);
597 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
598 fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d",
599 (unsigned long) expected_pathlen, res);
600 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
601 expected_path, buf);
602
603 /* Now use a relative path that does not start with '.' */
604 memset(buf, '\0', bufsz);
605 dst_path = "file.txt";
606 dst_pathlen = strlen(dst_path);
607 expected_path = "./file.txt";
608 expected_pathlen = strlen(expected_path);
609
610 (void) unlink(path);
611 res = symlink(dst_path, path);
612 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
613 strerror(errno));
614
615 session.chroot_path = "/tmp";
616 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
617 res = dir_readlink(p, path, buf, bufsz, flags);
618 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
619 fail_unless((size_t) res == expected_pathlen,
620 "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res,
621 buf);
622 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
623 expected_path, buf);
624
625 /* Now use a relative path that does not start with '.', and a chroot
626 * deeper down than one directory.
627 */
628 memset(buf, '\0', bufsz);
629 dst_path = "file.txt";
630 dst_pathlen = strlen(dst_path);
631 expected_path = "/tmp/file.txt";
632 expected_pathlen = strlen(expected_path);
633
634 (void) unlink(path);
635 res = symlink(dst_path, path);
636 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
637 strerror(errno));
638
639 session.chroot_path = "/tmp/foo/bar";
640 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
641 res = dir_readlink(p, path, buf, bufsz, flags);
642 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
643 fail_unless((size_t) res == expected_pathlen,
644 "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res,
645 buf);
646 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
647 expected_path, buf);
648
649 /* Now use a relative path, and a chroot deeper down than one directory, and
650 * a deeper/longer source path.
651 */
652 memset(buf, '\0', bufsz);
653 dst_path = "./file.txt";
654 dst_pathlen = strlen(dst_path);
655 expected_path = "/tmp/prt-readlink/file.txt";
656 expected_pathlen = strlen(expected_path);
657
658 (void) unlink(path);
659 (void) rmdir(misc_test_readlink2_dir);
660 (void) mkdir(misc_test_readlink2_dir, 0777);
661 path = misc_test_readlink2;
662 res = symlink(dst_path, path);
663 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
664 strerror(errno));
665
666 session.chroot_path = "/tmp/foo/bar";
667 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
668 res = dir_readlink(p, path, buf, bufsz, flags);
669 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
670 fail_unless((size_t) res == expected_pathlen,
671 "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res,
672 buf);
673 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
674 expected_path, buf);
675
676 /* Now use a relative path that does not start with '.', and a chroot
677 * deeper down than one directory, and a deeper/longer source path.
678 */
679 memset(buf, '\0', bufsz);
680 dst_path = "file.txt";
681 dst_pathlen = strlen(dst_path);
682 expected_path = "/tmp/prt-readlink/file.txt";
683 expected_pathlen = strlen(expected_path);
684
685 (void) unlink(path);
686 (void) rmdir(misc_test_readlink2_dir);
687 (void) mkdir(misc_test_readlink2_dir, 0777);
688 path = misc_test_readlink2;
689 res = symlink(dst_path, path);
690 fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path,
691 strerror(errno));
692
693 session.chroot_path = "/tmp/foo/bar";
694 flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH;
695 res = dir_readlink(p, path, buf, bufsz, flags);
696 fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno));
697 fail_unless((size_t) res == expected_pathlen,
698 "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res,
699 buf);
700 fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'",
701 expected_path, buf);
702
703 (void) unlink(misc_test_readlink);
704 (void) unlink(misc_test_readlink2);
705 (void) rmdir(misc_test_readlink2_dir);
706 }
707 END_TEST
708
START_TEST(dir_realpath_test)709 START_TEST (dir_realpath_test) {
710 char *res;
711 const char *path;
712
713 res = dir_realpath(NULL, NULL);
714 fail_unless(res == NULL, "Failed to handle null arguments");
715 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
716 strerror(errno), errno);
717
718 res = dir_realpath(p, NULL);
719 fail_unless(res == NULL, "Failed to handle null path");
720 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
721 strerror(errno), errno);
722
723 mark_point();
724 path = "/foo";
725 res = dir_realpath(p, path);
726 fail_unless(res == NULL, "Got real path for '%s' unexpectedly", path);
727 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
728 strerror(errno), errno);
729
730 mark_point();
731 path = "/";
732 res = dir_realpath(p, path);
733 fail_unless(res != NULL, "Failed to get real path for '%s': %s", path,
734 strerror(errno));
735 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
736 }
737 END_TEST
738
START_TEST(dir_abs_path_test)739 START_TEST (dir_abs_path_test) {
740 char *res;
741 const char *path;
742
743 res = dir_abs_path(NULL, NULL, TRUE);
744 fail_unless(res == NULL, "Failed to handle null arguments");
745 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
746 strerror(errno), errno);
747
748 res = dir_abs_path(p, NULL, TRUE);
749 fail_unless(res == NULL, "Failed to handle null path");
750 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
751 strerror(errno), errno);
752
753 mark_point();
754 path = "/foo";
755 res = dir_abs_path(p, path, TRUE);
756 fail_unless(path != NULL, "Failed to get absolute path for '%s': %s", path,
757 strerror(errno));
758 fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res);
759 }
760 END_TEST
761
START_TEST(safe_token_test)762 START_TEST (safe_token_test) {
763 char *res, *text, *expected;
764
765 mark_point();
766 expected = "";
767 res = safe_token(NULL);
768 fail_unless(res != NULL, "Failed to handle null arguments");
769 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
770 res);
771
772 mark_point();
773 text = "";
774 expected = "";
775 res = safe_token(&text);
776 fail_unless(res != NULL, "Failed to handle null arguments");
777 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
778 res);
779
780 mark_point();
781 text = "foo";
782 expected = text;
783 res = safe_token(&text);
784 fail_unless(res != NULL, "Failed to handle null arguments");
785 fail_unless(res == expected, "Expected '%s', got '%s'", expected, res);
786 fail_unless(strcmp(text, "") == 0, "Expected '', got '%s'", text);
787
788 mark_point();
789 text = " foo";
790 expected = text + 2;
791 res = safe_token(&text);
792 fail_unless(res != NULL, "Failed to handle null arguments");
793 fail_unless(res == expected, "Expected '%s', got '%s'", expected, res);
794 fail_unless(strcmp(text, "") == 0, "Expected '', got '%s'", text);
795
796 mark_point();
797 text = " \t";
798 expected = "";
799 res = safe_token(&text);
800 fail_unless(res != NULL, "Failed to handle null arguments");
801 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
802 res);
803 }
804 END_TEST
805
write_shutmsg(const char * path,const char * line)806 static int write_shutmsg(const char *path, const char *line) {
807 FILE *fh;
808 int res;
809 size_t line_len;
810
811 fh = fopen(path, "w+");
812 if (fh == NULL) {
813 return -1;
814 }
815
816
817 line_len = strlen(line);
818 fwrite(line, line_len, 1, fh);
819
820 res = fclose(fh);
821 return res;
822 }
823
START_TEST(check_shutmsg_test)824 START_TEST (check_shutmsg_test) {
825 int res;
826 const char *path;
827 time_t when_shutdown = 0, when_deny = 0, when_disconnect = 0;
828 char shutdown_msg[PR_TUNABLE_BUFFER_SIZE];
829
830 res = check_shutmsg(NULL, NULL, NULL, NULL, NULL, NULL, 0);
831 fail_unless(res < 0, "Failed to handle null arguments");
832 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
833 strerror(errno), errno);
834
835 path = "/foo/bar/baz/quxx/quzz";
836 res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0);
837 fail_unless(res < 0, "Failed to handle nonexistent path");
838 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
839 strerror(errno), errno);
840
841 path = "/";
842 res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0);
843 fail_unless(res < 0, "Failed to handle directory path");
844 fail_unless(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR,
845 strerror(errno), errno);
846
847 /* XXX More testing needed */
848
849 path = misc_test_shutmsg;
850
851 (void) unlink(path);
852 res = write_shutmsg(path,
853 "1970 1 1 0 0 0 0000 0000\nGoodbye, cruel world!\n");
854 fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno));
855
856 memset(shutdown_msg, '\0', sizeof(shutdown_msg));
857 pr_env_set(p, "TZ", "GMT");
858
859 mark_point();
860 res = check_shutmsg(p, path, &when_shutdown, &when_deny, &when_disconnect,
861 shutdown_msg, sizeof(shutdown_msg));
862 fail_unless(res == 1, "Expected 1, got %d", res);
863 fail_unless(when_shutdown == (time_t) 0, "Expected 0, got %lu",
864 (unsigned long) when_shutdown);
865 fail_unless(when_deny == (time_t) 0, "Expected 0, got %lu",
866 (unsigned long) when_deny);
867 fail_unless(when_disconnect == (time_t) 0, "Expected 0, got %lu",
868 (unsigned long) when_disconnect);
869 fail_unless(strcmp(shutdown_msg, "Goodbye, cruel world!") == 0,
870 "Expected 'Goodbye, cruel world!', got '%s'", shutdown_msg);
871
872 (void) unlink(path);
873 res = write_shutmsg(path,
874 "2037 1 1 0 0 0 0000 0000\nGoodbye, cruel world!\n");
875 fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno));
876
877 mark_point();
878 res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0);
879 fail_unless(res == 1, "Expected 1, got %d", res);
880
881 (void) unlink(path);
882 res = write_shutmsg(path,
883 "0 0 0 0 0 0 0000 0000\nGoodbye, cruel world!\n");
884 fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno));
885
886 mark_point();
887 res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0);
888
889 (void) unlink(misc_test_shutmsg);
890 }
891 END_TEST
892
START_TEST(memscrub_test)893 START_TEST (memscrub_test) {
894 size_t len;
895 char *expected, *text;
896
897 mark_point();
898 pr_memscrub(NULL, 1);
899
900 expected = "Hello, World!";
901 text = pstrdup(p, expected);
902
903 mark_point();
904 pr_memscrub(text, 0);
905
906 len = strlen(text);
907
908 mark_point();
909 pr_memscrub(text, len);
910 fail_unless(strncmp(text, expected, len + 1) != 0,
911 "Expected other than '%s'", expected);
912 }
913 END_TEST
914
START_TEST(getopt_reset_test)915 START_TEST (getopt_reset_test) {
916 mark_point();
917 pr_getopt_reset();
918 }
919 END_TEST
920
START_TEST(exists_test)921 START_TEST (exists_test) {
922 int res;
923 const char *path;
924
925 res = exists(NULL);
926 fail_unless(res == FALSE, "Failed to handle null path");
927
928 path = "/";
929 res = exists(path);
930 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
931 }
932 END_TEST
933
START_TEST(exists2_test)934 START_TEST (exists2_test) {
935 int res;
936 const char *path;
937
938 res = exists2(NULL, NULL);
939 fail_unless(res == FALSE, "Failed to handle null arguments");
940
941 res = exists2(p, NULL);
942 fail_unless(res == FALSE, "Failed to handle null path");
943
944 path = "/";
945 res = exists2(p, path);
946 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
947 }
948 END_TEST
949
START_TEST(dir_exists_test)950 START_TEST (dir_exists_test) {
951 int res;
952 const char *path;
953
954 res = dir_exists(NULL);
955 fail_unless(res == FALSE, "Failed to handle null path");
956
957 path = "/";
958 res = dir_exists(path);
959 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
960
961 path = "./api-tests";
962 res = dir_exists(path);
963 fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path);
964 }
965 END_TEST
966
START_TEST(dir_exists2_test)967 START_TEST (dir_exists2_test) {
968 int res;
969 const char *path;
970
971 res = dir_exists2(NULL, NULL);
972 fail_unless(res == FALSE, "Failed to handle null arguments");
973
974 res = dir_exists2(p, NULL);
975 fail_unless(res == FALSE, "Failed to handle null path");
976
977 path = "/";
978 res = dir_exists2(p, path);
979 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
980
981 path = "./api-tests";
982 res = dir_exists2(p, path);
983 fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path);
984 }
985 END_TEST
986
START_TEST(symlink_mode_test)987 START_TEST (symlink_mode_test) {
988 mode_t res;
989 const char *path;
990
991 res = symlink_mode(NULL);
992 fail_unless(res == 0, "Failed to handle null arguments");
993 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
994 strerror(errno), errno);
995
996 path = "/";
997 res = symlink_mode(path);
998 fail_unless(res == 0, "Found mode for non-symlink '%s'", path);
999 }
1000 END_TEST
1001
START_TEST(symlink_mode2_test)1002 START_TEST (symlink_mode2_test) {
1003 mode_t res;
1004 const char *path;
1005
1006 res = symlink_mode2(NULL, NULL);
1007 fail_unless(res == 0, "Failed to handle null arguments");
1008 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1009 strerror(errno), errno);
1010
1011 res = symlink_mode2(p, NULL);
1012 fail_unless(res == 0, "Failed to handle null path");
1013 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1014 strerror(errno), errno);
1015
1016 path = "/";
1017 res = symlink_mode2(p, path);
1018 fail_unless(res == 0, "Found mode for non-symlink '%s'", path);
1019 }
1020 END_TEST
1021
START_TEST(file_mode_test)1022 START_TEST (file_mode_test) {
1023 mode_t res;
1024 const char *path;
1025
1026 res = file_mode(NULL);
1027 fail_unless(res == 0, "Failed to handle null path");
1028 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1029 strerror(errno), errno);
1030
1031 path = "/";
1032 res = file_mode(path);
1033 fail_unless(res != 0, "Failed to find mode for '%s': %s", path,
1034 strerror(errno));
1035 }
1036 END_TEST
1037
START_TEST(file_mode2_test)1038 START_TEST (file_mode2_test) {
1039 mode_t res;
1040 const char *path;
1041
1042 res = file_mode2(NULL, NULL);
1043 fail_unless(res == 0, "Failed to handle null arguments");
1044 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1045 strerror(errno), errno);
1046
1047 res = file_mode2(p, NULL);
1048 fail_unless(res == 0, "Failed to handle null path");
1049 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1050 strerror(errno), errno);
1051
1052 path = "/";
1053 res = file_mode2(p, path);
1054 fail_unless(res != 0, "Failed to find mode for '%s': %s", path,
1055 strerror(errno));
1056 }
1057 END_TEST
1058
START_TEST(file_exists_test)1059 START_TEST (file_exists_test) {
1060 int res;
1061 const char *path;
1062
1063 res = file_exists(NULL);
1064 fail_unless(res == FALSE, "Failed to handle null path");
1065
1066 path = "/";
1067 res = file_exists(path);
1068 fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path);
1069
1070 path = "./api-tests";
1071 res = file_exists(path);
1072 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
1073 }
1074 END_TEST
1075
START_TEST(file_exists2_test)1076 START_TEST (file_exists2_test) {
1077 int res;
1078 const char *path;
1079
1080 res = file_exists2(NULL, NULL);
1081 fail_unless(res == FALSE, "Failed to handle null arguments");
1082
1083 res = file_exists2(p, NULL);
1084 fail_unless(res == FALSE, "Failed to handle null path");
1085
1086 path = "/";
1087 res = file_exists2(p, path);
1088 fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path);
1089
1090 path = "./api-tests";
1091 res = file_exists2(p, path);
1092 fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path);
1093 }
1094 END_TEST
1095
START_TEST(gmtime_test)1096 START_TEST (gmtime_test) {
1097 struct tm *res;
1098 time_t now;
1099
1100 mark_point();
1101 res = pr_gmtime(NULL, NULL);
1102 fail_unless(res == NULL, "Failed to handle null arguments");
1103 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1104 strerror(errno), errno);
1105
1106 time(&now);
1107
1108 mark_point();
1109 res = pr_gmtime(NULL, &now);
1110 #if defined(HAVE_GMTIME_R)
1111 fail_unless(res == NULL, "Failed to handle null pool");
1112 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1113 strerror(errno), errno);
1114 #else
1115 fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now,
1116 strerror(errno));
1117 #endif /* HAVE_GMTIME_R */
1118
1119 mark_point();
1120 res = pr_gmtime(p, &now);
1121 fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now,
1122 strerror(errno));
1123 }
1124 END_TEST
1125
START_TEST(localtime_test)1126 START_TEST (localtime_test) {
1127 struct tm *res;
1128 time_t now;
1129
1130 mark_point();
1131 res = pr_localtime(NULL, NULL);
1132 fail_unless(res == NULL, "Failed to handle null arguments");
1133 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1134 strerror(errno), errno);
1135
1136 time(&now);
1137
1138 mark_point();
1139 res = pr_localtime(NULL, &now);
1140 #if defined(HAVE_LOCALTIME_R)
1141 fail_unless(res == NULL, "Failed to handle null pool");
1142 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1143 strerror(errno), errno);
1144 #else
1145 fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now,
1146 strerror(errno));
1147 #endif /* HAVE_LOCALTIME_R */
1148
1149 mark_point();
1150 res = pr_localtime(p, &now);
1151 fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now,
1152 strerror(errno));
1153 }
1154 END_TEST
1155
START_TEST(strtime_test)1156 START_TEST (strtime_test) {
1157 const char *res;
1158 time_t now;
1159
1160 mark_point();
1161 now = 0;
1162 res = pr_strtime(now);
1163 #if defined(HAVE_LOCALTIME_R)
1164 fail_unless(res == NULL, "Failed to handle null pool");
1165 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1166 strerror(errno), errno);
1167 #else
1168 fail_unless(res != NULL, "Failed to convert time %lu: %s",
1169 (unsigned long) now, strerror(errno));
1170 #endif /* HAVE_LOCALTIME_R */
1171 }
1172 END_TEST
1173
START_TEST(strtime2_test)1174 START_TEST (strtime2_test) {
1175 const char *res;
1176 char *expected;
1177 time_t now;
1178
1179 mark_point();
1180 now = 0;
1181 expected = "Thu Jan 01 00:00:00 1970";
1182 res = pr_strtime2(now, TRUE);
1183 #if defined(HAVE_GMTIME_R)
1184 fail_unless(res == NULL, "Failed to handle null pool");
1185 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1186 strerror(errno), errno);
1187 #else
1188 fail_unless(res != NULL, "Failed to convert time %lu: %s",
1189 (unsigned long) now, strerror(errno));
1190 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1191 res);
1192 #endif /* HAVE_GMTIME_R */
1193 }
1194 END_TEST
1195
START_TEST(strtime3_test)1196 START_TEST (strtime3_test) {
1197 const char *res;
1198 char *expected;
1199 time_t now;
1200
1201 mark_point();
1202 now = 0;
1203 #if defined(HAVE_GMTIME_R)
1204 res = pr_strtime3(NULL, now, TRUE);
1205 fail_unless(res == NULL, "Failed to handle null pool argument");
1206 fail_unless(errno == EINVAL, "Expected EINVAL (%s), got %s (%d)",
1207 strerror(EINVAL), strerror(errno), errno);
1208 #endif /* HAVE_GMTIME_R */
1209
1210 mark_point();
1211 expected = "Thu Jan 01 00:00:00 1970";
1212 res = pr_strtime3(p, now, TRUE);
1213 fail_unless(res != NULL, "Failed to convert time %lu: %s",
1214 (unsigned long) now, strerror(errno));
1215 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1216 res);
1217 }
1218 END_TEST
1219
START_TEST(timeval2millis_test)1220 START_TEST (timeval2millis_test) {
1221 int res;
1222 struct timeval tv;
1223 uint64_t ms;
1224
1225 res = pr_timeval2millis(NULL, NULL);
1226 fail_unless(res < 0, "Failed to handle null arguments");
1227 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1228 strerror(errno), errno);
1229
1230 res = pr_timeval2millis(&tv, NULL);
1231 fail_unless(res < 0, "Failed to handle null millis argument");
1232 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1233 strerror(errno), errno);
1234
1235 tv.tv_sec = tv.tv_usec = 0;
1236 res = pr_timeval2millis(&tv, &ms);
1237 fail_unless(res == 0, "Failed to convert timeval to millis: %s",
1238 strerror(errno));
1239 fail_unless(ms == 0, "Expected 0 ms, got %lu", (unsigned long) ms);
1240 }
1241 END_TEST
1242
START_TEST(gettimeofday_millis_test)1243 START_TEST (gettimeofday_millis_test) {
1244 int res;
1245 uint64_t ms;
1246
1247 res = pr_gettimeofday_millis(NULL);
1248 fail_unless(res < 0, "Failed to handle null argument");
1249 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1250 strerror(errno), errno);
1251
1252 ms = 0;
1253 res = pr_gettimeofday_millis(&ms);
1254 fail_unless(res == 0, "Failed to get current time ms: %s", strerror(errno));
1255 fail_unless(ms > 0, "Expected >0, got %lu", (unsigned long) ms);
1256 }
1257 END_TEST
1258
START_TEST(snprintf_test)1259 START_TEST (snprintf_test) {
1260 char *buf;
1261 size_t bufsz;
1262 int res, expected;
1263
1264 res = pr_snprintf(NULL, 0, NULL);
1265 fail_unless(res < 0, "Failed to handle null buffer");
1266 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1267 strerror(errno), errno);
1268
1269 bufsz = 1;
1270 buf = palloc(p, bufsz);
1271
1272 res = pr_snprintf(buf, 0, NULL);
1273 fail_unless(res < 0, "Failed to handle null format");
1274 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1275 strerror(errno), errno);
1276
1277 res = pr_snprintf(buf, 0, "%d", 0);
1278 fail_unless(res == 0, "Failed to handle zero-length buffer");
1279
1280 res = pr_snprintf(buf, bufsz, "%d", 0);
1281 fail_unless(res < 0, "Failed to handle too-small buffer");
1282 fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC,
1283 strerror(errno), errno);
1284
1285 res = pr_snprintf(buf, bufsz, "%s", "foobar");
1286 fail_unless(res < 0, "Failed to handle too-small buffer");
1287 fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC,
1288 strerror(errno), errno);
1289
1290 bufsz = 32;
1291 buf = palloc(p, bufsz);
1292
1293 expected = 6;
1294 res = pr_snprintf(buf, bufsz, "%s", "foobar");
1295 fail_unless(res == expected, "Expected %d, got %d", expected, res);
1296 }
1297 END_TEST
1298
START_TEST(snprintfl_test)1299 START_TEST (snprintfl_test) {
1300 char *buf;
1301 size_t bufsz;
1302 int res, expected;
1303
1304 res = pr_snprintfl(NULL, -1, NULL, 0, NULL);
1305 fail_unless(res < 0, "Failed to handle null buffer");
1306 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1307 strerror(errno), errno);
1308
1309 bufsz = 1;
1310 buf = palloc(p, bufsz);
1311
1312 res = pr_snprintfl(NULL, -1, buf, 0, NULL);
1313 fail_unless(res < 0, "Failed to handle null format");
1314 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1315 strerror(errno), errno);
1316
1317 res = pr_snprintfl(__FILE__, __LINE__, buf, 0, "%d", 0);
1318 fail_unless(res == 0, "Failed to handle zero-length buffer");
1319
1320 res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%d", 0);
1321 fail_unless(res < 0, "Failed to handle too-small buffer");
1322 fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC,
1323 strerror(errno), errno);
1324
1325 res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%s", "foobar");
1326 fail_unless(res < 0, "Failed to handle too-small buffer");
1327 fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC,
1328 strerror(errno), errno);
1329
1330 bufsz = 32;
1331 buf = palloc(p, bufsz);
1332
1333 expected = 6;
1334 res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%s", "foobar");
1335 fail_unless(res == expected, "Expected %d, got %d", expected, res);
1336 }
1337 END_TEST
1338
START_TEST(path_subst_uservar_test)1339 START_TEST (path_subst_uservar_test) {
1340 const char *path = NULL, *res, *original, *expected;
1341
1342 res = path_subst_uservar(NULL, NULL);
1343 fail_unless(res == NULL, "Failed to handle null pool");
1344 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1345 strerror(errno), errno);
1346
1347 res = path_subst_uservar(p, NULL);
1348 fail_unless(res == NULL, "Failed to handle null path pointer");
1349 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1350 strerror(errno), errno);
1351
1352 res = path_subst_uservar(p, &path);
1353 fail_unless(res == NULL, "Failed to handle null path");
1354 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1355 strerror(errno), errno);
1356
1357 original = expected = "somepathhere";
1358 path = pstrdup(p, expected);
1359 mark_point();
1360 res = path_subst_uservar(p, &path);
1361 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1362 strerror(errno));
1363 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1364 res);
1365
1366 session.user = "user";
1367 original = "/home/%u";
1368 expected = "/home/user";
1369 path = pstrdup(p, original);
1370 mark_point();
1371 res = path_subst_uservar(p, &path);
1372 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1373 strerror(errno));
1374 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1375 res);
1376
1377 session.user = "user";
1378 original = "/home/%u[";
1379 expected = "/home/user[";
1380 path = pstrdup(p, original);
1381 mark_point();
1382 res = path_subst_uservar(p, &path);
1383 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1384 strerror(errno));
1385 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1386 res);
1387
1388 session.user = "user";
1389 original = "/home/%u[]";
1390 expected = "/home/user[]";
1391 path = pstrdup(p, original);
1392 mark_point();
1393 res = path_subst_uservar(p, &path);
1394 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1395 strerror(errno));
1396 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1397 res);
1398
1399 session.user = "user";
1400 original = "/home/users/%u[0]/%u[0]%u[1]/%u";
1401 expected = "/home/users/u/us/user";
1402 path = pstrdup(p, original);
1403 mark_point();
1404 res = path_subst_uservar(p, &path);
1405 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1406 strerror(errno));
1407 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1408 res);
1409
1410 /* Attempt to use an invalid index */
1411 session.user = "user";
1412 original = "/home/users/%u[a]/%u[b]%u[c]/%u";
1413 expected = original;
1414 path = pstrdup(p, original);
1415 mark_point();
1416 res = path_subst_uservar(p, &path);
1417 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1418 strerror(errno));
1419 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1420 res);
1421
1422 /* Attempt to use an out-of-bounds index */
1423 session.user = "user";
1424 original = "/home/users/%u[0]/%u[-1]%u[1]/%u";
1425 expected = original;
1426 path = pstrdup(p, original);
1427 mark_point();
1428 res = path_subst_uservar(p, &path);
1429 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1430 strerror(errno));
1431 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1432 res);
1433
1434 /* Attempt to use an out-of-bounds index */
1435 session.user = "user";
1436 original = "/home/users/%u[0]/%u[0]%u[4]/%u";
1437 expected = original;
1438 path = pstrdup(p, original);
1439 mark_point();
1440 res = path_subst_uservar(p, &path);
1441 fail_unless(res != NULL, "Failed to handle path '%s': %s", path,
1442 strerror(errno));
1443 fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected,
1444 res);
1445 }
1446 END_TEST
1447
tests_get_misc_suite(void)1448 Suite *tests_get_misc_suite(void) {
1449 Suite *suite;
1450 TCase *testcase;
1451
1452 suite = suite_create("misc");
1453
1454 testcase = tcase_create("base");
1455 tcase_add_checked_fixture(testcase, set_up, tear_down);
1456
1457 tcase_add_test(testcase, schedule_test);
1458 tcase_add_test(testcase, get_name_max_test);
1459 tcase_add_test(testcase, dir_interpolate_test);
1460 tcase_add_test(testcase, dir_best_path_test);
1461 tcase_add_test(testcase, dir_canonical_path_test);
1462 tcase_add_test(testcase, dir_canonical_vpath_test);
1463 tcase_add_test(testcase, dir_readlink_test);
1464 tcase_add_test(testcase, dir_realpath_test);
1465 tcase_add_test(testcase, dir_abs_path_test);
1466 tcase_add_test(testcase, symlink_mode_test);
1467 tcase_add_test(testcase, symlink_mode2_test);
1468 tcase_add_test(testcase, file_mode_test);
1469 tcase_add_test(testcase, file_mode2_test);
1470 tcase_add_test(testcase, exists_test);
1471 tcase_add_test(testcase, exists2_test);
1472 tcase_add_test(testcase, dir_exists_test);
1473 tcase_add_test(testcase, dir_exists2_test);
1474 tcase_add_test(testcase, file_exists_test);
1475 tcase_add_test(testcase, file_exists2_test);
1476 tcase_add_test(testcase, safe_token_test);
1477 tcase_add_test(testcase, check_shutmsg_test);
1478 tcase_add_test(testcase, memscrub_test);
1479 tcase_add_test(testcase, getopt_reset_test);
1480 tcase_add_test(testcase, gmtime_test);
1481 tcase_add_test(testcase, localtime_test);
1482 tcase_add_test(testcase, strtime_test);
1483 tcase_add_test(testcase, strtime2_test);
1484 tcase_add_test(testcase, strtime3_test);
1485 tcase_add_test(testcase, timeval2millis_test);
1486 tcase_add_test(testcase, gettimeofday_millis_test);
1487 tcase_add_test(testcase, snprintf_test);
1488 tcase_add_test(testcase, snprintfl_test);
1489 tcase_add_test(testcase, path_subst_uservar_test);
1490
1491 suite_add_tcase(suite, testcase);
1492 return suite;
1493 }
1494