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