Real-path checks are still needed in clamdscan when doing fd-passing and
streaming. This commit remedies that and improves some of the error
handling.
In addition, some cleanup to eliminate warnings on Windows added to the
shared code.
... | ... |
@@ -412,59 +412,81 @@ struct client_serial_data { |
412 | 412 |
|
413 | 413 |
/* FTW callback for scanning in non IDSESSION mode |
414 | 414 |
* Returns SUCCESS or BREAK on success, CL_EXXX on error */ |
415 |
-static int serial_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) |
|
415 |
+static cl_error_t serial_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) |
|
416 | 416 |
{ |
417 |
+ int status = CL_EOPEN; |
|
418 |
+ |
|
417 | 419 |
struct client_serial_data *c = (struct client_serial_data *)data->data; |
418 | 420 |
int sockd, ret; |
419 |
- const char *f = filename; |
|
421 |
+ const char *f = filename; |
|
422 |
+ char *real_filename = NULL; |
|
420 | 423 |
|
421 | 424 |
UNUSEDPARAM(sb); |
422 | 425 |
|
423 |
- if (chkpath(path)) |
|
424 |
- return CL_SUCCESS; |
|
426 |
+ if (reason != visit_directory_toplev) { |
|
427 |
+ if (CL_SUCCESS != cli_realpath((const char *)path, &real_filename)) { |
|
428 |
+ logg("*Failed to determine real filename of %s.\n", path); |
|
429 |
+ } else { |
|
430 |
+ path = real_filename; |
|
431 |
+ } |
|
432 |
+ } |
|
433 |
+ |
|
434 |
+ if (chkpath(path)) { |
|
435 |
+ status = CL_SUCCESS; |
|
436 |
+ goto done; |
|
437 |
+ } |
|
425 | 438 |
c->files++; |
426 | 439 |
switch (reason) { |
427 | 440 |
case error_stat: |
428 | 441 |
logg("!Can't access file %s\n", path); |
429 | 442 |
c->errors++; |
430 |
- return CL_SUCCESS; |
|
443 |
+ status = CL_SUCCESS; |
|
444 |
+ goto done; |
|
431 | 445 |
case error_mem: |
432 | 446 |
logg("!Memory allocation failed in ftw\n"); |
433 | 447 |
c->errors++; |
434 |
- return CL_EMEM; |
|
448 |
+ status = CL_EMEM; |
|
449 |
+ goto done; |
|
435 | 450 |
case warning_skipped_dir: |
436 | 451 |
logg("^Directory recursion limit reached\n"); |
437 | 452 |
case warning_skipped_link: |
438 |
- return CL_SUCCESS; |
|
453 |
+ status = CL_SUCCESS; |
|
454 |
+ goto done; |
|
439 | 455 |
case warning_skipped_special: |
440 | 456 |
logg("^%s: Not supported file type\n", path); |
441 | 457 |
c->errors++; |
442 |
- return CL_SUCCESS; |
|
458 |
+ status = CL_SUCCESS; |
|
459 |
+ goto done; |
|
443 | 460 |
case visit_directory_toplev: |
444 |
- if (c->scantype >= STREAM) |
|
445 |
- return CL_SUCCESS; |
|
446 |
- f = path; |
|
447 |
- filename = NULL; |
|
461 |
+ if (c->scantype >= STREAM) { |
|
462 |
+ status = CL_SUCCESS; |
|
463 |
+ goto done; |
|
464 |
+ } |
|
465 |
+ f = path; |
|
448 | 466 |
case visit_file: |
449 | 467 |
break; |
450 | 468 |
} |
451 | 469 |
|
452 | 470 |
if ((sockd = dconnect()) < 0) { |
453 |
- if (filename) free(filename); |
|
454 | 471 |
c->errors++; |
455 |
- return CL_EOPEN; |
|
472 |
+ goto done; |
|
456 | 473 |
} |
457 | 474 |
ret = dsresult(sockd, c->scantype, f, &c->printok, &c->errors); |
458 |
- if (filename) free(filename); |
|
459 | 475 |
closesocket(sockd); |
460 | 476 |
if (ret < 0) { |
461 | 477 |
c->errors++; |
462 |
- return CL_EOPEN; |
|
478 |
+ goto done; |
|
463 | 479 |
} |
464 | 480 |
c->infected += ret; |
465 |
- if (reason == visit_directory_toplev) |
|
466 |
- return CL_BREAK; |
|
467 |
- return CL_SUCCESS; |
|
481 |
+ if (reason == visit_directory_toplev) { |
|
482 |
+ status = CL_BREAK; |
|
483 |
+ goto done; |
|
484 |
+ } |
|
485 |
+ |
|
486 |
+ status = CL_SUCCESS; |
|
487 |
+done: |
|
488 |
+ free(filename); |
|
489 |
+ return status; |
|
468 | 490 |
} |
469 | 491 |
|
470 | 492 |
/* Non-IDSESSION handler |
... | ... |
@@ -571,43 +593,62 @@ static int dspresult(struct client_parallel_data *c) |
571 | 571 |
|
572 | 572 |
/* FTW callback for scanning in IDSESSION mode |
573 | 573 |
* Returns SUCCESS on success, CL_EXXX or BREAK on error */ |
574 |
-static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) |
|
574 |
+static cl_error_t parallel_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) |
|
575 | 575 |
{ |
576 |
+ cl_error_t status = CL_EOPEN; |
|
577 |
+ |
|
576 | 578 |
struct client_parallel_data *c = (struct client_parallel_data *)data->data; |
577 |
- struct SCANID *cid; |
|
578 |
- int res = CL_CLEAN; |
|
579 |
+ struct SCANID *cid = NULL; |
|
580 |
+ int res = CL_CLEAN; |
|
581 |
+ |
|
582 |
+ char *real_filename = NULL; |
|
579 | 583 |
|
580 | 584 |
UNUSEDPARAM(sb); |
585 |
+ UNUSEDPARAM(path); |
|
586 |
+ |
|
587 |
+ if (reason != visit_directory_toplev) { |
|
588 |
+ if (CL_SUCCESS != cli_realpath((const char *)filename, &real_filename)) { |
|
589 |
+ logg("*Failed to determine real filename of %s.\n", filename); |
|
590 |
+ } else { |
|
591 |
+ free(filename); |
|
592 |
+ filename = real_filename; |
|
593 |
+ } |
|
594 |
+ } |
|
581 | 595 |
|
582 |
- if (chkpath(path)) |
|
583 |
- return CL_SUCCESS; |
|
596 |
+ if (chkpath(filename)) { |
|
597 |
+ goto done; |
|
598 |
+ } |
|
584 | 599 |
c->files++; |
585 | 600 |
switch (reason) { |
586 | 601 |
case error_stat: |
587 |
- logg("!Can't access file %s\n", path); |
|
602 |
+ logg("!Can't access file %s\n", filename); |
|
588 | 603 |
c->errors++; |
589 |
- return CL_SUCCESS; |
|
604 |
+ status = CL_SUCCESS; |
|
605 |
+ goto done; |
|
590 | 606 |
case error_mem: |
591 | 607 |
logg("!Memory allocation failed in ftw\n"); |
592 | 608 |
c->errors++; |
593 |
- return CL_EMEM; |
|
609 |
+ status = CL_EMEM; |
|
610 |
+ goto done; |
|
594 | 611 |
case warning_skipped_dir: |
595 | 612 |
logg("^Directory recursion limit reached\n"); |
596 |
- return CL_SUCCESS; |
|
613 |
+ status = CL_SUCCESS; |
|
614 |
+ goto done; |
|
597 | 615 |
case warning_skipped_special: |
598 |
- logg("^%s: Not supported file type\n", path); |
|
616 |
+ logg("^%s: Not supported file type\n", filename); |
|
599 | 617 |
c->errors++; |
600 | 618 |
case warning_skipped_link: |
601 | 619 |
case visit_directory_toplev: |
602 |
- return CL_SUCCESS; |
|
620 |
+ status = CL_SUCCESS; |
|
621 |
+ goto done; |
|
603 | 622 |
case visit_file: |
604 | 623 |
break; |
605 | 624 |
} |
606 | 625 |
|
607 | 626 |
while (1) { |
608 | 627 |
/* consume all the available input to let some of the clamd |
609 |
- * threads blocked on send() to be dead. |
|
610 |
- * by doing so we shouldn't deadlock on the next recv() */ |
|
628 |
+ * threads blocked on send() to be dead. |
|
629 |
+ * by doing so we shouldn't deadlock on the next recv() */ |
|
611 | 630 |
fd_set rfds, wfds; |
612 | 631 |
FD_ZERO(&rfds); |
613 | 632 |
FD_SET(c->sockd, &rfds); |
... | ... |
@@ -615,31 +656,20 @@ static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum |
615 | 615 |
FD_SET(c->sockd, &wfds); |
616 | 616 |
if (select(c->sockd + 1, &rfds, &wfds, NULL, NULL) < 0) { |
617 | 617 |
if (errno == EINTR) continue; |
618 |
- free(filename); |
|
619 | 618 |
logg("!select() failed during session: %s\n", strerror(errno)); |
620 |
- return CL_BREAK; |
|
619 |
+ status = CL_BREAK; |
|
620 |
+ goto done; |
|
621 | 621 |
} |
622 | 622 |
if (FD_ISSET(c->sockd, &rfds)) { |
623 | 623 |
if (dspresult(c)) { |
624 |
- free(filename); |
|
625 |
- return CL_BREAK; |
|
624 |
+ status = CL_BREAK; |
|
625 |
+ goto done; |
|
626 | 626 |
} else |
627 | 627 |
continue; |
628 | 628 |
} |
629 | 629 |
if (FD_ISSET(c->sockd, &wfds)) break; |
630 | 630 |
} |
631 | 631 |
|
632 |
- cid = (struct SCANID *)malloc(sizeof(struct SCANID)); |
|
633 |
- if (!cid) { |
|
634 |
- free(filename); |
|
635 |
- logg("!Failed to allocate scanid entry: %s\n", strerror(errno)); |
|
636 |
- return CL_BREAK; |
|
637 |
- } |
|
638 |
- cid->id = ++c->lastid; |
|
639 |
- cid->file = filename; |
|
640 |
- cid->next = c->ids; |
|
641 |
- c->ids = cid; |
|
642 |
- |
|
643 | 632 |
switch (c->scantype) { |
644 | 633 |
#ifdef HAVE_FD_PASSING |
645 | 634 |
case FILDES: |
... | ... |
@@ -653,13 +683,32 @@ static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum |
653 | 653 |
if (res <= 0) { |
654 | 654 |
c->printok = 0; |
655 | 655 |
c->errors++; |
656 |
- c->ids = cid->next; |
|
657 |
- c->lastid--; |
|
658 |
- free(cid); |
|
656 |
+ status = res ? CL_BREAK : CL_SUCCESS; |
|
657 |
+ goto done; |
|
658 |
+ } |
|
659 |
+ |
|
660 |
+ cid = (struct SCANID *)malloc(sizeof(struct SCANID)); |
|
661 |
+ if (!cid) { |
|
662 |
+ logg("!Failed to allocate scanid entry: %s\n", strerror(errno)); |
|
663 |
+ status = CL_BREAK; |
|
664 |
+ goto done; |
|
665 |
+ } |
|
666 |
+ |
|
667 |
+ cid->id = ++c->lastid; |
|
668 |
+ cid->file = filename; |
|
669 |
+ cid->next = c->ids; |
|
670 |
+ c->ids = cid; |
|
671 |
+ |
|
672 |
+ /* Give up ownership of the filename to the client parralel scan ID list */ |
|
673 |
+ filename = NULL; |
|
674 |
+ |
|
675 |
+ status = CL_SUCCESS; |
|
676 |
+ |
|
677 |
+done: |
|
678 |
+ if (NULL != filename) { |
|
659 | 679 |
free(filename); |
660 |
- return res ? CL_BREAK : CL_SUCCESS; |
|
661 | 680 |
} |
662 |
- return CL_SUCCESS; |
|
681 |
+ return status; |
|
663 | 682 |
} |
664 | 683 |
|
665 | 684 |
/* IDSESSION handler |
... | ... |
@@ -929,7 +929,7 @@ struct cli_ftw_cbdata { |
929 | 929 |
* after an error, we call the callback with reason == error, |
930 | 930 |
* and if it returns CL_BREAK we break. |
931 | 931 |
*/ |
932 |
-typedef int (*cli_ftw_cb)(STATBUF *stat_buf, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data); |
|
932 |
+typedef cl_error_t (*cli_ftw_cb)(STATBUF *stat_buf, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data); |
|
933 | 933 |
|
934 | 934 |
/* |
935 | 935 |
* returns 1 if the path should be skipped and 0 otherwise |
... | ... |
@@ -696,7 +696,9 @@ int actsetup(const struct optstruct *opts) |
696 | 696 |
{ |
697 | 697 |
int move = optget(opts, "move")->enabled; |
698 | 698 |
if (move || optget(opts, "copy")->enabled) { |
699 |
+#ifndef _WIN32 |
|
699 | 700 |
cl_error_t ret; |
701 |
+#endif |
|
700 | 702 |
actarget = optget(opts, move ? "move" : "copy")->strarg; |
701 | 703 |
#ifndef _WIN32 |
702 | 704 |
ret = cli_realpath((const char *)actarget, &actarget); |
... | ... |
@@ -256,11 +256,9 @@ int filecopy(const char *src, const char *dest) |
256 | 256 |
#endif |
257 | 257 |
} |
258 | 258 |
|
259 |
-int close_std_descriptors() { |
|
260 |
-#ifdef _WIN32 |
|
261 |
- return -1; |
|
262 |
-#else |
|
263 |
- |
|
259 |
+#ifndef _WIN32 |
|
260 |
+int close_std_descriptors() |
|
261 |
+{ |
|
264 | 262 |
int fds[3], i; |
265 | 263 |
|
266 | 264 |
fds[0] = open("/dev/null", O_RDONLY); |
... | ... |
@@ -289,67 +287,51 @@ int close_std_descriptors() { |
289 | 289 |
close(fds[i]); |
290 | 290 |
|
291 | 291 |
return 0; |
292 |
-#endif |
|
293 | 292 |
} |
294 | 293 |
|
295 |
- |
|
296 |
-int daemonize_all_return(void) { |
|
297 |
-#ifdef _WIN32 |
|
298 |
- fputs("Background mode is not supported on your operating system\n", stderr); |
|
299 |
- return -1; |
|
300 |
-#else |
|
294 |
+int daemonize_all_return(void) |
|
295 |
+{ |
|
301 | 296 |
pid_t pid; |
302 | 297 |
|
303 | 298 |
pid = fork(); |
304 | 299 |
|
305 |
- if (0 == pid){ |
|
300 |
+ if (0 == pid) { |
|
306 | 301 |
setsid(); |
307 | 302 |
} |
308 | 303 |
return pid; |
309 |
- |
|
310 |
-#endif |
|
311 | 304 |
} |
312 | 305 |
|
313 |
-int daemonize(void) { |
|
314 |
-#ifdef _WIN32 |
|
315 |
- fputs("Background mode is not supported on your operating system\n", stderr); |
|
316 |
- return -1; |
|
317 |
-#else |
|
318 |
- |
|
306 |
+int daemonize(void) |
|
307 |
+{ |
|
319 | 308 |
int ret = 0; |
320 | 309 |
|
321 | 310 |
ret = close_std_descriptors(); |
322 |
- if (ret){ |
|
311 |
+ if (ret) { |
|
323 | 312 |
return ret; |
324 | 313 |
} |
325 | 314 |
|
326 |
- ret = daemonize_all_return(); |
|
327 |
- pid_t pid = (pid_t) ret; |
|
315 |
+ ret = daemonize_all_return(); |
|
316 |
+ pid_t pid = (pid_t)ret; |
|
328 | 317 |
/*parent process.*/ |
329 |
- if (pid > 0){ |
|
318 |
+ if (pid > 0) { |
|
330 | 319 |
exit(0); |
331 | 320 |
} |
332 | 321 |
|
333 | 322 |
return pid; |
334 |
-#endif |
|
335 | 323 |
} |
336 | 324 |
|
337 |
- |
|
338 |
-static void daemonize_child_initialized_handler(int sig){ |
|
325 |
+static void daemonize_child_initialized_handler(int sig) |
|
326 |
+{ |
|
339 | 327 |
(void)(sig); |
340 | 328 |
exit(0); |
341 | 329 |
} |
342 | 330 |
|
343 |
-int daemonize_parent_wait(){ |
|
344 |
-#ifdef _WIN32 |
|
345 |
- fputs("Background mode is not supported on your operating system\n", stderr); |
|
346 |
- return -1; |
|
347 |
-#else |
|
348 |
- |
|
331 |
+int daemonize_parent_wait() |
|
332 |
+{ |
|
349 | 333 |
int daemonizePid = daemonize_all_return(); |
350 | 334 |
if (daemonizePid == -1) { |
351 | 335 |
return -1; |
352 |
- } else if (daemonizePid){ //parent |
|
336 |
+ } else if (daemonizePid) { //parent |
|
353 | 337 |
/* The parent will wait until either the child process |
354 | 338 |
* exits, or signals the parent that it's initialization is |
355 | 339 |
* complete. If it exits, it is due to an error condition, |
... | ... |
@@ -363,33 +345,27 @@ int daemonize_parent_wait(){ |
363 | 363 |
sigemptyset(&(sig.sa_mask)); |
364 | 364 |
sig.sa_handler = daemonize_child_initialized_handler; |
365 | 365 |
|
366 |
- if (0 != sigaction(SIGINT, &sig, NULL)){ |
|
366 |
+ if (0 != sigaction(SIGINT, &sig, NULL)) { |
|
367 | 367 |
perror("sigaction"); |
368 | 368 |
return -1; |
369 | 369 |
} |
370 | 370 |
|
371 | 371 |
int exitStatus; |
372 | 372 |
wait(&exitStatus); |
373 |
- if (WIFEXITED(exitStatus)){ //error |
|
373 |
+ if (WIFEXITED(exitStatus)) { //error |
|
374 | 374 |
exitStatus = WEXITSTATUS(exitStatus); |
375 | 375 |
exit(exitStatus); |
376 | 376 |
} |
377 |
- |
|
378 | 377 |
} |
379 | 378 |
return 0; |
380 |
-#endif |
|
381 | 379 |
} |
382 | 380 |
|
383 |
-void daemonize_signal_parent(pid_t parentPid){ |
|
384 |
-#ifdef _WIN32 |
|
385 |
- fputs("Background mode is not supported on your operating system\n", stderr); |
|
386 |
- return -1; |
|
387 |
-#else |
|
381 |
+void daemonize_signal_parent(pid_t parentPid) |
|
382 |
+{ |
|
388 | 383 |
close_std_descriptors(); |
389 |
- kill(parentPid, SIGINT) ; |
|
390 |
-#endif |
|
384 |
+ kill(parentPid, SIGINT); |
|
391 | 385 |
} |
392 |
- |
|
386 |
+#endif |
|
393 | 387 |
|
394 | 388 |
int match_regex(const char *filename, const char *pattern) |
395 | 389 |
{ |
... | ... |
@@ -63,24 +63,27 @@ int check_flevel(void); |
63 | 63 |
const char *filelist(const struct optstruct *opts, int *err); |
64 | 64 |
int filecopy(const char *src, const char *dest); |
65 | 65 |
|
66 |
+#ifndef _WIN32 |
|
66 | 67 |
/*Returns 0 on success (only the child process returns.*/ |
67 | 68 |
int daemonize(void); |
68 | 69 |
|
69 | 70 |
/*closes stdin, stdout, stderr. This is called by daemonize, but not |
70 | 71 |
* daemonize_all_return. Users of daemonize_all_return should call this |
71 | 72 |
* when initialization is complete.*/ |
72 |
-int close_std_descriptors() ; |
|
73 |
+int close_std_descriptors(); |
|
74 |
+ |
|
73 | 75 |
/*Returns the return value of fork. All processes return */ |
74 | 76 |
int daemonize_all_return(void); |
77 |
+ |
|
75 | 78 |
/*Parent waits for a SIGINT or the child process to exit. If |
76 | 79 |
* it receives a SIGINT, it exits with exit code 0. If the child |
77 | 80 |
* exits (error), it exits with the child process's exit code.*/ |
78 | 81 |
int daemonize_parent_wait(); |
82 |
+ |
|
79 | 83 |
/*Sends a SIGINT to the parent process. It also closes stdin, stdout, |
80 | 84 |
* and stderr.*/ |
81 | 85 |
void daemonize_signal_parent(pid_t parentPid); |
82 |
- |
|
83 |
- |
|
86 |
+#endif |
|
84 | 87 |
|
85 | 88 |
const char *get_version(void); |
86 | 89 |
int match_regex(const char *filename, const char *pattern); |