1 /*
2 * ProFTPD - FTP server testsuite
3 * Copyright (c) 2008-2016 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 /* Scoreboard API tests */
26
27 #include "tests.h"
28
29 static pool *p = NULL;
30
31 static const char *test_dir = "/tmp/prt-scoreboard/";
32 static const char *test_file = "/tmp/prt-scoreboard/test.dat";
33 static const char *test_mutex = "/tmp/prt-scoreboard/test.dat.lck";
34 static const char *test_file2 = "/tmp/prt-scoreboard-mutex.dat";
35
set_up(void)36 static void set_up(void) {
37 (void) unlink(test_file);
38 (void) unlink(test_file2);
39 (void) unlink(test_mutex);
40 (void) rmdir(test_dir);
41
42 if (p == NULL) {
43 p = permanent_pool = make_sub_pool(NULL);
44 }
45
46 ServerType = SERVER_STANDALONE;
47 init_netaddr();
48
49 if (getenv("TEST_VERBOSE") != NULL) {
50 pr_trace_set_levels("lock", 1, 20);
51 pr_trace_set_levels("scoreboard", 1, 20);
52 }
53 }
54
tear_down(void)55 static void tear_down(void) {
56 (void) unlink(test_file);
57 (void) unlink(test_file2);
58 (void) unlink(test_mutex);
59 (void) rmdir(test_dir);
60
61 if (getenv("TEST_VERBOSE") != NULL) {
62 pr_trace_set_levels("lock", 0, 0);
63 pr_trace_set_levels("scoreboard", 0, 0);
64 }
65
66 if (p) {
67 destroy_pool(p);
68 p = permanent_pool = NULL;
69 }
70 }
71
START_TEST(scoreboard_get_test)72 START_TEST (scoreboard_get_test) {
73 const char *ok, *res;
74
75 ok = PR_RUN_DIR "/proftpd.scoreboard";
76
77 res = pr_get_scoreboard();
78 fail_unless(res != NULL, "Failed to get scoreboard path: %s",
79 strerror(errno));
80 fail_unless(strcmp(res, ok) == 0,
81 "Expected scoreboard path '%s', got '%s'", ok, res);
82
83 ok = PR_RUN_DIR "/proftpd.scoreboard.lck";
84
85 res = pr_get_scoreboard_mutex();
86 fail_unless(res != NULL, "Failed to get scoreboard mutex path: %s",
87 strerror(errno));
88 fail_unless(strcmp(res, ok) == 0,
89 "Expected scoreboard mutex path '%s', got '%s'", ok, res);
90 }
91 END_TEST
92
START_TEST(scoreboard_set_test)93 START_TEST (scoreboard_set_test) {
94 int res;
95 const char *path;
96
97 res = pr_set_scoreboard(NULL);
98 fail_unless(res == -1, "Failed to handle null argument");
99 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
100
101 res = pr_set_scoreboard("foo");
102 fail_unless(res == -1, "Failed to handle non-path argument");
103 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
104 errno);
105
106 res = pr_set_scoreboard("foo/");
107 fail_unless(res == -1, "Failed to handle relative path argument");
108 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
109 errno);
110
111 res = pr_set_scoreboard("/foo");
112 fail_unless(res == -1, "Failed to handle nonexistent path argument");
113 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
114 errno);
115
116 res = pr_set_scoreboard("/tmp");
117 fail_unless(res == -1, "Failed to handle nonexistent path argument");
118 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
119 errno);
120
121 res = pr_set_scoreboard("/tmp/");
122 fail_unless(res == -1, "Failed to handle nonexistent path argument");
123 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL (got %d)",
124 errno);
125
126 res = mkdir(test_dir, 0777);
127 fail_unless(res == 0,
128 "Failed to create tmp directory '%s': %s", test_dir, strerror(errno));
129 res = chmod(test_dir, 0777);
130 fail_unless(res == 0,
131 "Failed to create set 0777 perms on '%s': %s", test_dir, strerror(errno));
132
133 res = pr_set_scoreboard(test_dir);
134 fail_unless(res == -1, "Failed to handle nonexistent file argument");
135 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
136
137 res = pr_set_scoreboard("/tmp/prt-scoreboard/bar");
138 fail_unless(res == -1, "Failed to handle world-writable path argument");
139 fail_unless(errno == EPERM, "Failed to set errno to EPERM");
140
141 res = chmod(test_dir, 0775);
142 fail_unless(res == 0, "Failed to set 0775 perms on '%s': %s", test_dir,
143 strerror(errno));
144
145 res = pr_set_scoreboard("/tmp/prt-scoreboard/bar");
146 fail_unless(res == 0, "Failed to set scoreboard: %s", strerror(errno));
147 (void) rmdir(test_dir);
148
149 path = pr_get_scoreboard();
150 fail_unless(path != NULL, "Failed to get scoreboard path: %s",
151 strerror(errno));
152 fail_unless(strcmp("/tmp/prt-scoreboard/bar", path) == 0,
153 "Expected '%s', got '%s'", "/tmp/prt-scoreboard/bar", path);
154
155 (void) rmdir(test_dir);
156 }
157 END_TEST
158
START_TEST(scoreboard_set_mutex_test)159 START_TEST (scoreboard_set_mutex_test) {
160 int res;
161 const char *path;
162
163 res = pr_set_scoreboard_mutex(NULL);
164 fail_unless(res == -1, "Failed to handle null argument");
165 fail_unless(errno == EINVAL, "Failed to set errno to EINVAL");
166
167 res = pr_set_scoreboard_mutex("/tmp");
168 fail_unless(res == 0, "Failed to set scoreboard mutex: %s", strerror(errno));
169
170 path = pr_get_scoreboard_mutex();
171 fail_unless(path != NULL, "Failed to get scoreboard mutex path: %s",
172 strerror(errno));
173 fail_unless(strcmp("/tmp", path) == 0,
174 "Expected '%s', got '%s'", "/tmp", path);
175 }
176 END_TEST
177
START_TEST(scoreboard_open_close_test)178 START_TEST (scoreboard_open_close_test) {
179 int res;
180 const char *symlink_path = "/tmp/prt-scoreboard/symlink";
181
182 res = mkdir(test_dir, 0775);
183 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
184 strerror(errno));
185
186 res = chmod(test_dir, 0775);
187 fail_unless(res == 0, "Failed to set perms on '%s': %s", test_dir,
188 strerror(errno));
189
190 res = pr_set_scoreboard(test_file);
191 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
192 strerror(errno));
193
194 if (symlink(symlink_path, test_file) == 0) {
195
196 res = pr_open_scoreboard(O_RDWR);
197 if (res == 0) {
198 (void) unlink(symlink_path);
199
200 fail("Unexpectedly opened symlink scoreboard");
201 }
202
203 if (errno != EPERM) {
204 int xerrno = errno;
205
206 (void) unlink(symlink_path);
207
208 fail("Failed to set errno to EPERM (got %d)", xerrno);
209 }
210
211 (void) unlink(symlink_path);
212
213 res = pr_set_scoreboard(test_file);
214 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
215 strerror(errno));
216 }
217
218 res = pr_open_scoreboard(O_RDONLY);
219 fail_unless(res < 0, "Unexpectedly opened scoreboard using O_RDONLY");
220
221 if (errno != EINVAL) {
222 int xerrno = errno;
223
224 (void) unlink(symlink_path);
225
226 fail("Failed to set errno to EINVAL (got %d)", xerrno);
227 }
228
229 (void) unlink(test_mutex);
230 (void) unlink(test_file);
231 res = pr_open_scoreboard(O_RDWR);
232 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
233
234 /* Try opening the scoreboard again; it should be OK, since we are the
235 * opener.
236 */
237 res = pr_open_scoreboard(O_RDWR);
238 fail_unless(res == 0, "Failed to open scoreboard again: %s", strerror(errno));
239
240 /* Now that we have a scoreboard, try opening it again using O_RDONLY. */
241 pr_close_scoreboard(FALSE);
242
243 res = pr_open_scoreboard(O_RDONLY);
244 fail_unless(res < 0, "Unexpectedly opened scoreboard using O_RDONLY");
245 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
246 strerror(errno), errno);
247
248 (void) unlink(test_mutex);
249 (void) unlink(test_file);
250 (void) rmdir(test_dir);
251 }
252 END_TEST
253
START_TEST(scoreboard_lock_test)254 START_TEST (scoreboard_lock_test) {
255 int fd = -1, lock_type = -1, res;
256
257 res = pr_lock_scoreboard(fd, lock_type);
258 fail_unless(res < 0, "Failed to handle bad lock type");
259 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
260 strerror(errno), errno);
261
262 lock_type = F_RDLCK;
263 res = pr_lock_scoreboard(fd, lock_type);
264 fail_unless(res < 0, "Failed to handle bad file descriptor");
265 fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
266 strerror(errno), errno);
267
268 fd = open(test_file2, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
269 fail_unless(fd >= 0, "Failed to open '%s': %s", test_file2, strerror(errno));
270
271 res = pr_lock_scoreboard(fd, lock_type);
272 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
273
274 lock_type = F_WRLCK;
275 res = pr_lock_scoreboard(fd, lock_type);
276 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
277
278 lock_type = F_UNLCK;
279 res = pr_lock_scoreboard(fd, lock_type);
280 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
281
282 lock_type = F_WRLCK;
283 res = pr_lock_scoreboard(fd, lock_type);
284 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
285
286 /* Note: apparently attempt to lock (again) a file on which a lock
287 * (of the same type) is already held will succeed. Huh.
288 */
289 res = pr_lock_scoreboard(fd, lock_type);
290 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
291
292 lock_type = F_RDLCK;
293 res = pr_lock_scoreboard(fd, lock_type);
294 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
295
296 lock_type = F_UNLCK;
297 res = pr_lock_scoreboard(fd, lock_type);
298 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
299
300 (void) unlink(test_file2);
301 }
302 END_TEST
303
START_TEST(scoreboard_delete_test)304 START_TEST (scoreboard_delete_test) {
305 int res;
306 struct stat st;
307
308 res = mkdir(test_dir, 0775);
309 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
310 strerror(errno));
311
312 res = chmod(test_dir, 0775);
313 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
314 strerror(errno));
315
316 res = pr_set_scoreboard(test_file);
317 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
318 strerror(errno));
319
320 res = pr_open_scoreboard(O_RDWR);
321 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
322
323 res = stat(pr_get_scoreboard(), &st);
324 fail_unless(res == 0, "Failed to stat scoreboard: %s", strerror(errno));
325
326 pr_delete_scoreboard();
327
328 res = stat(pr_get_scoreboard(), &st);
329 fail_unless(res < 0, "Unexpectedly found deleted scoreboard");
330
331 res = stat(pr_get_scoreboard_mutex(), &st);
332 fail_unless(res < 0, "Unexpectedly found deleted scoreboard mutex");
333
334 (void) unlink(test_mutex);
335 (void) unlink(test_file);
336 (void) rmdir(test_dir);
337 }
338 END_TEST
339
START_TEST(scoreboard_restore_test)340 START_TEST (scoreboard_restore_test) {
341 int res;
342
343 res = mkdir(test_dir, 0775);
344 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
345 strerror(errno));
346
347 res = chmod(test_dir, 0775);
348 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
349 strerror(errno));
350
351 res = pr_set_scoreboard(test_file);
352 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
353 strerror(errno));
354
355 res = pr_restore_scoreboard();
356 fail_unless(res < 0, "Unexpectedly restored scoreboard");
357 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
358 strerror(errno), errno);
359
360 res = pr_open_scoreboard(O_RDWR);
361 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
362
363 res = pr_restore_scoreboard();
364 fail_unless(res < 0,
365 "Restoring scoreboard before rewind succeeded unexpectedly");
366
367 res = pr_rewind_scoreboard();
368 fail_unless(res == 0, "Failed to rewind scoreboard: %s", strerror(errno));
369
370 res = pr_restore_scoreboard();
371 fail_unless(res == 0, "Failed to restore scoreboard: %s", strerror(errno));
372
373 (void) unlink(test_mutex);
374 (void) unlink(test_file);
375 (void) rmdir(test_dir);
376 }
377 END_TEST
378
START_TEST(scoreboard_rewind_test)379 START_TEST (scoreboard_rewind_test) {
380 int res;
381
382 res = mkdir(test_dir, 0775);
383 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
384 strerror(errno));
385
386 res = chmod(test_dir, 0775);
387 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
388 strerror(errno));
389
390 res = pr_set_scoreboard(test_file);
391 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
392 strerror(errno));
393
394 res = pr_rewind_scoreboard();
395 fail_unless(res < 0, "Unexpectedly rewound scoreboard");
396 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
397 strerror(errno), errno);
398
399 res = pr_open_scoreboard(O_RDWR);
400 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
401
402 res = pr_rewind_scoreboard();
403 fail_unless(res == 0, "Failed to rewind scoreboard: %s", strerror(errno));
404
405 (void) unlink(test_mutex);
406 (void) unlink(test_file);
407 (void) rmdir(test_dir);
408 }
409 END_TEST
410
START_TEST(scoreboard_scrub_test)411 START_TEST (scoreboard_scrub_test) {
412 uid_t euid;
413 int res;
414
415 res = mkdir(test_dir, 0775);
416 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
417 strerror(errno));
418
419 res = chmod(test_dir, 0775);
420 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
421 strerror(errno));
422
423 res = pr_set_scoreboard(test_file);
424 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
425 strerror(errno));
426
427 res = pr_scoreboard_scrub();
428 fail_unless(res < 0, "Unexpectedly scrubbed scoreboard");
429
430 euid = geteuid();
431 if (euid != 0) {
432 if (errno != EPERM &&
433 errno != ENOENT) {
434 fail("Failed to set errno to EPERM/ENOENT, got %d [%s] (euid = %lu)",
435 errno, strerror(errno), (unsigned long) euid);
436 }
437
438 } else {
439 if (errno != ENOENT) {
440 fail("Failed to set errno to ENOENT, got %d [%s] (euid = %lu)", errno,
441 strerror(errno), (unsigned long) euid);
442 }
443 }
444
445 res = pr_open_scoreboard(O_RDWR);
446 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
447
448 res = pr_scoreboard_scrub();
449 fail_unless(res == 0, "Failed to scrub scoreboard: %s", strerror(errno));
450
451 (void) unlink(test_mutex);
452 (void) unlink(test_file);
453 (void) rmdir(test_dir);
454 }
455 END_TEST
456
START_TEST(scoreboard_get_daemon_pid_test)457 START_TEST (scoreboard_get_daemon_pid_test) {
458 int res;
459 pid_t daemon_pid;
460
461 res = mkdir(test_dir, 0775);
462 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
463 strerror(errno));
464
465 res = chmod(test_dir, 0775);
466 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
467 strerror(errno));
468
469 res = pr_set_scoreboard(test_file);
470 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
471 strerror(errno));
472
473 res = pr_open_scoreboard(O_RDWR);
474 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
475
476 daemon_pid = pr_scoreboard_get_daemon_pid();
477 if (daemon_pid != getpid()) {
478 fail("Expected %lu, got %lu", (unsigned long) getpid(),
479 (unsigned long) daemon_pid);
480 }
481
482 pr_delete_scoreboard();
483
484 ServerType = SERVER_INETD;
485
486 res = pr_open_scoreboard(O_RDWR);
487 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
488
489 daemon_pid = pr_scoreboard_get_daemon_pid();
490 if (daemon_pid != 0) {
491 fail("Expected %lu, got %lu", (unsigned long) 0,
492 (unsigned long) daemon_pid);
493 }
494
495 (void) unlink(test_mutex);
496 (void) unlink(test_file);
497 (void) rmdir(test_dir);
498 }
499 END_TEST
500
START_TEST(scoreboard_get_daemon_uptime_test)501 START_TEST (scoreboard_get_daemon_uptime_test) {
502 int res;
503 time_t daemon_uptime, now;
504
505 res = mkdir(test_dir, 0775);
506 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
507 strerror(errno));
508
509 res = chmod(test_dir, 0775);
510 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
511 strerror(errno));
512
513 res = pr_set_scoreboard(test_file);
514 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
515 strerror(errno));
516
517 res = pr_open_scoreboard(O_RDWR);
518 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
519
520 daemon_uptime = pr_scoreboard_get_daemon_uptime();
521 now = time(NULL);
522
523 if (daemon_uptime > now) {
524 fail("Expected %lu, got %lu", (unsigned long) now,
525 (unsigned long) daemon_uptime);
526 }
527
528 pr_delete_scoreboard();
529
530 ServerType = SERVER_INETD;
531
532 res = pr_open_scoreboard(O_RDWR);
533 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
534
535 daemon_uptime = pr_scoreboard_get_daemon_uptime();
536 if (daemon_uptime != 0) {
537 fail("Expected %lu, got %lu", (unsigned long) 0,
538 (unsigned long) daemon_uptime);
539 }
540
541 (void) unlink(test_mutex);
542 (void) unlink(test_file);
543 (void) rmdir(test_dir);
544 }
545 END_TEST
546
START_TEST(scoreboard_entry_add_test)547 START_TEST (scoreboard_entry_add_test) {
548 int res;
549
550 res = mkdir(test_dir, 0775);
551 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
552 strerror(errno));
553
554 res = chmod(test_dir, 0775);
555 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
556 strerror(errno));
557
558 res = pr_set_scoreboard(test_file);
559 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
560 strerror(errno));
561
562 res = pr_scoreboard_entry_add();
563 fail_unless(res < 0, "Unexpectedly added entry to scoreboard");
564 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
565 strerror(errno), errno);
566
567 res = pr_open_scoreboard(O_RDWR);
568 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
569
570 res = pr_scoreboard_entry_add();
571 fail_unless(res == 0, "Failed to add entry to scoreboard: %s",
572 strerror(errno));
573
574 res = pr_scoreboard_entry_add();
575 fail_unless(res < 0, "Unexpectedly added entry to scoreboard");
576 fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
577 strerror(errno), errno);
578
579 (void) unlink(test_mutex);
580 (void) unlink(test_file);
581 (void) rmdir(test_dir);
582 }
583 END_TEST
584
START_TEST(scoreboard_entry_del_test)585 START_TEST (scoreboard_entry_del_test) {
586 int res;
587
588 res = mkdir(test_dir, 0775);
589 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
590 strerror(errno));
591
592 res = chmod(test_dir, 0775);
593 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
594 strerror(errno));
595
596 res = pr_set_scoreboard(test_file);
597 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
598 strerror(errno));
599
600 res = pr_scoreboard_entry_del(FALSE);
601 fail_unless(res < 0, "Unexpectedly deleted entry from scoreboard");
602 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
603 strerror(errno), errno);
604
605 res = pr_open_scoreboard(O_RDWR);
606 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
607
608 res = pr_scoreboard_entry_del(FALSE);
609 fail_unless(res < 0, "Unexpectedly deleted entry from scoreboard");
610 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
611 strerror(errno), errno);
612
613 res = pr_scoreboard_entry_add();
614 fail_unless(res == 0, "Failed to add entry to scoreboard: %s",
615 strerror(errno));
616
617 res = pr_scoreboard_entry_del(FALSE);
618 fail_unless(res == 0, "Failed to delete entry from scoreboard: %s",
619 strerror(errno));
620
621 res = pr_scoreboard_entry_del(FALSE);
622 fail_unless(res < 0, "Unexpectedly deleted entry from scoreboard");
623 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
624 strerror(errno), errno);
625
626 (void) unlink(test_mutex);
627 (void) unlink(test_file);
628 (void) rmdir(test_dir);
629 }
630 END_TEST
631
START_TEST(scoreboard_entry_read_test)632 START_TEST (scoreboard_entry_read_test) {
633 int res;
634 pr_scoreboard_entry_t *score;
635
636 res = mkdir(test_dir, 0775);
637 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
638 strerror(errno));
639
640 res = chmod(test_dir, 0775);
641 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
642 strerror(errno));
643
644 res = pr_set_scoreboard(test_file);
645 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
646 strerror(errno));
647
648 score = pr_scoreboard_entry_read();
649 fail_unless(score == NULL, "Unexpectedly read scoreboard entry");
650 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
651 strerror(errno), errno);
652
653 res = pr_open_scoreboard(O_RDWR);
654 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
655
656 /* We expect NULL here because the scoreboard file should be empty. */
657 score = pr_scoreboard_entry_read();
658 fail_unless(score == NULL, "Unexpectedly read scoreboard entry");
659
660 res = pr_scoreboard_entry_add();
661 fail_unless(res == 0, "Failed to add entry to scoreboard: %s",
662 strerror(errno));
663
664 score = pr_scoreboard_entry_read();
665 fail_unless(score != NULL, "Failed to read scoreboard entry: %s",
666 strerror(errno));
667
668 if (score->sce_pid != getpid()) {
669 fail("Failed to read expected scoreboard entry (expected PID %lu, got %lu)",
670 (unsigned long) getpid(), (unsigned long) score->sce_pid);
671 }
672
673 score = pr_scoreboard_entry_read();
674 fail_unless(score == NULL, "Unexpectedly read scoreboard entry");
675
676 (void) unlink(test_mutex);
677 (void) unlink(test_file);
678 (void) rmdir(test_dir);
679 }
680 END_TEST
681
START_TEST(scoreboard_entry_get_test)682 START_TEST (scoreboard_entry_get_test) {
683 register unsigned int i;
684 int res;
685 const char *val;
686 int scoreboard_fields[] = {
687 PR_SCORE_USER,
688 PR_SCORE_CLIENT_ADDR,
689 PR_SCORE_CLIENT_NAME,
690 PR_SCORE_CLASS,
691 PR_SCORE_CWD,
692 PR_SCORE_CMD,
693 PR_SCORE_CMD_ARG,
694 PR_SCORE_PROTOCOL,
695 -1
696 };
697
698 res = mkdir(test_dir, 0775);
699 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
700 strerror(errno));
701
702 res = chmod(test_dir, 0775);
703 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
704 strerror(errno));
705
706 res = pr_set_scoreboard(test_file);
707 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
708 strerror(errno));
709
710 val = pr_scoreboard_entry_get(-1);
711 fail_unless(val == NULL, "Unexpectedly read value from scoreboard entry");
712 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
713 strerror(errno), errno);
714
715 res = pr_open_scoreboard(O_RDWR);
716 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
717
718 val = pr_scoreboard_entry_get(-1);
719 fail_unless(val == NULL, "Unexpectedly read value from scoreboard entry");
720 fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
721 strerror(errno), errno);
722
723 res = pr_scoreboard_entry_add();
724 fail_unless(res == 0, "Failed to add entry to scoreboard: %s",
725 strerror(errno));
726
727 val = pr_scoreboard_entry_get(-1);
728 fail_unless(val == NULL, "Unexpectedly read value from scoreboard entry");
729 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
730 strerror(errno), errno);
731
732 for (i = 0; scoreboard_fields[i] != -1; i++) {
733 val = pr_scoreboard_entry_get(scoreboard_fields[i]);
734 fail_unless(val != NULL, "Failed to read scoreboard field %d: %s",
735 scoreboard_fields[i], strerror(errno));
736 }
737
738 (void) unlink(test_mutex);
739 (void) unlink(test_file);
740 (void) rmdir(test_dir);
741 }
742 END_TEST
743
START_TEST(scoreboard_entry_update_test)744 START_TEST (scoreboard_entry_update_test) {
745 int num, res;
746 const char *val;
747 pid_t pid = getpid();
748 const pr_netaddr_t *addr;
749 time_t now;
750 off_t len;
751 unsigned long elapsed;
752
753 res = mkdir(test_dir, 0775);
754 fail_unless(res == 0, "Failed to create directory '%s': %s", test_dir,
755 strerror(errno));
756
757 res = chmod(test_dir, 0775);
758 fail_unless(res == 0, "Failed to set perms on '%s' to 0775': %s", test_dir,
759 strerror(errno));
760
761 res = pr_set_scoreboard(test_file);
762 fail_unless(res == 0, "Failed to set scoreboard to '%s': %s", test_file,
763 strerror(errno));
764
765 res = pr_scoreboard_entry_update(pid, 0);
766 fail_unless(res < 0, "Unexpectedly updated scoreboard entry");
767 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
768 strerror(errno), errno);
769
770 res = pr_open_scoreboard(O_RDWR);
771 fail_unless(res == 0, "Failed to open scoreboard: %s", strerror(errno));
772
773 res = pr_scoreboard_entry_update(pid, 0);
774 fail_unless(res < 0, "Unexpectedly updated scoreboard entry");
775 fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
776 strerror(errno), errno);
777
778 res = pr_scoreboard_entry_add();
779 fail_unless(res == 0, "Failed to add entry to scoreboard: %s",
780 strerror(errno));
781
782 res = pr_scoreboard_entry_update(pid, -1);
783 fail_unless(res < 0, "Unexpectedly updated scoreboard entry");
784 fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
785 strerror(errno), errno);
786
787 val = "cwd";
788 res = pr_scoreboard_entry_update(pid, PR_SCORE_CWD, val, NULL);
789 fail_unless(res == 0, "Failed to update PR_SCORE_CWD: %s", strerror(errno));
790
791 val = pr_scoreboard_entry_get(PR_SCORE_CWD);
792 fail_unless(val != NULL, "Failed to get entry PR_SCORE_CWD: %s",
793 strerror(errno));
794 fail_unless(strcmp(val, "cwd") == 0, "Expected 'cwd', got '%s'", val);
795
796 val = "user";
797 res = pr_scoreboard_entry_update(pid, PR_SCORE_USER, val, NULL);
798 fail_unless(res == 0, "Failed to update PR_SCORE_USER: %s", strerror(errno));
799
800 addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
801 fail_unless(addr != NULL, "Failed to resolve '127.0.0.1': %s",
802 strerror(errno));
803
804 res = pr_scoreboard_entry_update(pid, PR_SCORE_CLIENT_ADDR, addr, NULL);
805 fail_unless(res == 0, "Failed to update PR_SCORE_CLIENT_ADDR: %s",
806 strerror(errno));
807
808 val = "remote_name";
809 res = pr_scoreboard_entry_update(pid, PR_SCORE_CLIENT_NAME, val, NULL);
810 fail_unless(res == 0, "Failed to update PR_SCORE_CLIENT_NAME: %s",
811 strerror(errno));
812
813 val = "session_class";
814 res = pr_scoreboard_entry_update(pid, PR_SCORE_CLASS, val, NULL);
815 fail_unless(res == 0, "Failed to update PR_SCORE_CLASS: %s", strerror(errno));
816
817 val = "USER";
818 res = pr_scoreboard_entry_update(pid, PR_SCORE_CMD, "%s", val, NULL, NULL);
819 fail_unless(res == 0, "Failed to update PR_SCORE_CMD: %s", strerror(errno));
820
821 val = "foo bar";
822 res = pr_scoreboard_entry_update(pid, PR_SCORE_CMD_ARG, "%s", val, NULL,
823 NULL);
824 fail_unless(res == 0, "Failed to update PR_SCORE_CMD_ARG: %s",
825 strerror(errno));
826
827 num = 77;
828 res = pr_scoreboard_entry_update(pid, PR_SCORE_SERVER_PORT, num, NULL);
829 fail_unless(res == 0, "Failed to update PR_SCORE_SERVER_PORT: %s",
830 strerror(errno));
831
832 res = pr_scoreboard_entry_update(pid, PR_SCORE_SERVER_ADDR, addr, num, NULL);
833 fail_unless(res == 0, "Failed to update PR_SCORE_SERVER_ADDR: %s",
834 strerror(errno));
835
836 val = "label";
837 res = pr_scoreboard_entry_update(pid, PR_SCORE_SERVER_LABEL, val, NULL);
838 fail_unless(res == 0, "Failed to update PR_SCORE_SERVER_LABEL: %s",
839 strerror(errno));
840
841 now = 1;
842 res = pr_scoreboard_entry_update(pid, PR_SCORE_BEGIN_IDLE, now, NULL);
843 fail_unless(res == 0, "Failed to update PR_SCORE_BEGIN_IDLE: %s",
844 strerror(errno));
845
846 now = 2;
847 res = pr_scoreboard_entry_update(pid, PR_SCORE_BEGIN_SESSION, now, NULL);
848 fail_unless(res == 0, "Failed to update PR_SCORE_BEGIN_SESSION: %s",
849 strerror(errno));
850
851 len = 7;
852 res = pr_scoreboard_entry_update(pid, PR_SCORE_XFER_DONE, len, NULL);
853 fail_unless(res == 0, "Failed to update PR_SCORE_XFER_DONE: %s",
854 strerror(errno));
855
856 len = 8;
857 res = pr_scoreboard_entry_update(pid, PR_SCORE_XFER_SIZE, len, NULL);
858 fail_unless(res == 0, "Failed to update PR_SCORE_XFER_SIZE: %s",
859 strerror(errno));
860
861 len = 9;
862 res = pr_scoreboard_entry_update(pid, PR_SCORE_XFER_LEN, len, NULL);
863 fail_unless(res == 0, "Failed to update PR_SCORE_XFER_LEN: %s",
864 strerror(errno));
865
866 elapsed = 1;
867 res = pr_scoreboard_entry_update(pid, PR_SCORE_XFER_ELAPSED, elapsed, NULL);
868 fail_unless(res == 0, "Failed to update PR_SCORE_XFER_ELAPSED: %s",
869 strerror(errno));
870
871 val = "protocol";
872 res = pr_scoreboard_entry_update(pid, PR_SCORE_PROTOCOL, val, NULL);
873 fail_unless(res == 0, "Failed to update PR_SCORE_PROTOCOL: %s",
874 strerror(errno));
875
876 (void) unlink(test_mutex);
877 (void) unlink(test_file);
878 (void) rmdir(test_dir);
879 }
880 END_TEST
881
START_TEST(scoreboard_entry_kill_test)882 START_TEST (scoreboard_entry_kill_test) {
883 int res;
884 pr_scoreboard_entry_t sce;
885
886 res = pr_scoreboard_entry_kill(NULL, 0);
887 fail_unless(res < 0, "Failed to handle null arguments");
888 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
889 strerror(errno), errno);
890
891 sce.sce_pid = getpid();
892 res = pr_scoreboard_entry_kill(&sce, 0);
893 fail_unless(res == 0, "Failed to send signal 0 to PID %lu: %s",
894 (unsigned long) sce.sce_pid, strerror(errno));
895 }
896 END_TEST
897
START_TEST(scoreboard_entry_lock_test)898 START_TEST (scoreboard_entry_lock_test) {
899 int fd = -1, lock_type = -1, res;
900
901 res = pr_scoreboard_entry_lock(fd, lock_type);
902 fail_unless(res < 0, "Failed to handle bad lock type");
903 fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
904 strerror(errno), errno);
905
906 lock_type = F_RDLCK;
907 res = pr_scoreboard_entry_lock(fd, lock_type);
908 fail_unless(res < 0, "Failed to handle bad file descriptor");
909 fail_unless(errno == EBADF, "Expected EBADF (%d), got %s (%d)", EBADF,
910 strerror(errno), errno);
911
912 fd = open(test_file2, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
913 fail_unless(fd >= 0, "Failed to open '%s': %s", test_file2, strerror(errno));
914
915 res = pr_scoreboard_entry_lock(fd, lock_type);
916 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
917
918 lock_type = F_WRLCK;
919 res = pr_scoreboard_entry_lock(fd, lock_type);
920 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
921
922 lock_type = F_UNLCK;
923 res = pr_scoreboard_entry_lock(fd, lock_type);
924 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
925
926 lock_type = F_WRLCK;
927 res = pr_scoreboard_entry_lock(fd, lock_type);
928 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
929
930 /* Note: apparently attempt to lock (again) a file on which a lock
931 * (of the same type) is already held will succeed. Huh.
932 */
933 res = pr_scoreboard_entry_lock(fd, lock_type);
934 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
935
936 lock_type = F_RDLCK;
937 res = pr_scoreboard_entry_lock(fd, lock_type);
938 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
939
940 lock_type = F_UNLCK;
941 res = pr_scoreboard_entry_lock(fd, lock_type);
942 fail_unless(res == 0, "Failed to lock fd %d: %s", fd, strerror(errno));
943
944 (void) unlink(test_file2);
945 }
946 END_TEST
947
START_TEST(scoreboard_disabled_test)948 START_TEST (scoreboard_disabled_test) {
949 register unsigned int i = 0;
950 const char *paths[4] = {
951 "/dev/null",
952 "none",
953 "off",
954 NULL
955 };
956 const char *path;
957
958 for (path = paths[i]; path != NULL; path = paths[i++]) {
959 int res;
960 const char *field, *ok;
961 pid_t scoreboard_pid;
962 time_t scoreboard_uptime;
963 pr_scoreboard_entry_t *score;
964
965 res = pr_set_scoreboard(path);
966 fail_unless(res == 0, "Failed set to scoreboard to '%s': %s", path,
967 strerror(errno));
968
969 ok = PR_RUN_DIR "/proftpd.scoreboard";
970
971 path = pr_get_scoreboard();
972 fail_unless(path != NULL, "Failed to get scoreboard path: %s",
973 strerror(errno));
974 fail_unless(strcmp(path, ok) == 0,
975 "Expected path '%s', got '%s'", ok, path);
976
977 res = pr_open_scoreboard(O_RDONLY);
978 fail_unless(res == 0, "Failed to open '%s' scoreboard: %s", path,
979 strerror(errno));
980
981 res = pr_scoreboard_scrub();
982 fail_unless(res == 0, "Failed to scrub '%s' scoreboard: %s", path,
983 strerror(errno));
984
985 scoreboard_pid = pr_scoreboard_get_daemon_pid();
986 fail_unless(scoreboard_pid == 0,
987 "Expected to get scoreboard PID 0, got %lu",
988 (unsigned long) scoreboard_pid);
989
990 scoreboard_uptime = pr_scoreboard_get_daemon_uptime();
991 fail_unless(scoreboard_uptime == 0,
992 "Expected to get scoreboard uptime 0, got %lu",
993 (unsigned long) scoreboard_uptime);
994
995 res = pr_scoreboard_entry_add();
996 fail_unless(res == 0, "Failed to add entry to '%s' scoreboard: %s", path,
997 strerror(errno));
998
999 score = pr_scoreboard_entry_read();
1000 fail_unless(score == NULL, "Expected null entry");
1001
1002 field = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG);
1003 fail_unless(field == NULL, "Expected null CMD_ARG field");
1004
1005 res = pr_scoreboard_entry_update(getpid(), PR_SCORE_CWD, "foo", NULL);
1006 fail_unless(res == 0, "Failed to update CWD field: %s", strerror(errno));
1007
1008 res = pr_scoreboard_entry_del(FALSE);
1009 fail_unless(res == 0, "Failed to delete entry from '%s' scoreboard: %s",
1010 path, strerror(errno));
1011
1012 res = pr_close_scoreboard(FALSE);
1013 fail_unless(res == 0, "Failed to close '%s' scoreboard: %s", path,
1014 strerror(errno));
1015
1016 /* Internal hack: even calling pr_set_scoreboard() with a NULL
1017 * argument will set the Scoreboard API internal flag back to true.
1018 */
1019 pr_set_scoreboard(NULL);
1020 }
1021 }
1022 END_TEST
1023
tests_get_scoreboard_suite(void)1024 Suite *tests_get_scoreboard_suite(void) {
1025 Suite *suite;
1026 TCase *testcase;
1027
1028 suite = suite_create("scoreboard");
1029
1030 testcase = tcase_create("base");
1031 tcase_add_checked_fixture(testcase, set_up, tear_down);
1032
1033 tcase_add_test(testcase, scoreboard_get_test);
1034 tcase_add_test(testcase, scoreboard_set_test);
1035 tcase_add_test(testcase, scoreboard_set_mutex_test);
1036 tcase_add_test(testcase, scoreboard_open_close_test);
1037 tcase_add_test(testcase, scoreboard_lock_test);
1038 tcase_add_test(testcase, scoreboard_delete_test);
1039 tcase_add_test(testcase, scoreboard_restore_test);
1040 tcase_add_test(testcase, scoreboard_rewind_test);
1041 tcase_add_test(testcase, scoreboard_scrub_test);
1042 tcase_add_test(testcase, scoreboard_get_daemon_pid_test);
1043 tcase_add_test(testcase, scoreboard_get_daemon_uptime_test);
1044 tcase_add_test(testcase, scoreboard_entry_add_test);
1045 tcase_add_test(testcase, scoreboard_entry_del_test);
1046 tcase_add_test(testcase, scoreboard_entry_read_test);
1047 tcase_add_test(testcase, scoreboard_entry_get_test);
1048 tcase_add_test(testcase, scoreboard_entry_update_test);
1049 tcase_add_test(testcase, scoreboard_entry_kill_test);
1050 tcase_add_test(testcase, scoreboard_entry_lock_test);
1051 tcase_add_test(testcase, scoreboard_disabled_test);
1052
1053 suite_add_tcase(suite, testcase);
1054 return suite;
1055 }
1056