... | ... |
@@ -36,20 +36,20 @@ clamonacc_SOURCES = \ |
36 | 36 |
$(top_srcdir)/shared/clamdcom.c \ |
37 | 37 |
$(top_srcdir)/shared/clamdcom.h \ |
38 | 38 |
clamonacc.c \ |
39 |
- onaccess_client.c \ |
|
40 |
- onaccess_client.h \ |
|
41 |
- onaccess_proto.c \ |
|
42 |
- onaccess_proto.h \ |
|
43 |
- onaccess_ddd.c \ |
|
44 |
- onaccess_ddd.h \ |
|
45 |
- onaccess_fan.c \ |
|
46 |
- onaccess_fan.h \ |
|
47 |
- onaccess_hash.c \ |
|
48 |
- onaccess_hash.h \ |
|
49 |
- onaccess_others.c \ |
|
50 |
- onaccess_others.h \ |
|
51 |
- onaccess_scth.c \ |
|
52 |
- onaccess_scth.h |
|
39 |
+ ./client/onaccess_client.c \ |
|
40 |
+ ./client/onaccess_client.h \ |
|
41 |
+ ./client/onaccess_proto.c \ |
|
42 |
+ ./client/onaccess_proto.h \ |
|
43 |
+ ./inotif/onaccess_ddd.c \ |
|
44 |
+ ./inotif/onaccess_ddd.h \ |
|
45 |
+ ./fanotif/onaccess_fan.c \ |
|
46 |
+ ./fanotif/onaccess_fan.h \ |
|
47 |
+ ./inotif/onaccess_hash.c \ |
|
48 |
+ ./inotif/onaccess_hash.h \ |
|
49 |
+ ./misc/onaccess_others.c \ |
|
50 |
+ ./misc/onaccess_others.h \ |
|
51 |
+ ./scan/onaccess_scth.c \ |
|
52 |
+ ./scan/onaccess_scth.h |
|
53 | 53 |
|
54 | 54 |
AM_CFLAGS=@WERR_CFLAGS@ |
55 | 55 |
endif |
... | ... |
@@ -203,11 +203,14 @@ am__clamonacc_SOURCES_DIST = $(top_srcdir)/shared/output.c \ |
203 | 203 |
$(top_srcdir)/shared/misc.h $(top_srcdir)/shared/getopt.c \ |
204 | 204 |
$(top_srcdir)/shared/getopt.h $(top_srcdir)/shared/actions.c \ |
205 | 205 |
$(top_srcdir)/shared/actions.h $(top_srcdir)/shared/clamdcom.c \ |
206 |
- $(top_srcdir)/shared/clamdcom.h clamonacc.c onaccess_client.c \ |
|
207 |
- onaccess_client.h onaccess_proto.c onaccess_proto.h \ |
|
208 |
- onaccess_ddd.c onaccess_ddd.h onaccess_fan.c onaccess_fan.h \ |
|
209 |
- onaccess_hash.c onaccess_hash.h onaccess_others.c \ |
|
210 |
- onaccess_others.h onaccess_scth.c onaccess_scth.h |
|
206 |
+ $(top_srcdir)/shared/clamdcom.h clamonacc.c \ |
|
207 |
+ ./client/onaccess_client.c ./client/onaccess_client.h \ |
|
208 |
+ ./client/onaccess_proto.c ./client/onaccess_proto.h \ |
|
209 |
+ ./inotif/onaccess_ddd.c ./inotif/onaccess_ddd.h \ |
|
210 |
+ ./fanotif/onaccess_fan.c ./fanotif/onaccess_fan.h \ |
|
211 |
+ ./inotif/onaccess_hash.c ./inotif/onaccess_hash.h \ |
|
212 |
+ ./misc/onaccess_others.c ./misc/onaccess_others.h \ |
|
213 |
+ ./scan/onaccess_scth.c ./scan/onaccess_scth.h |
|
211 | 214 |
@BUILD_CLAMD_TRUE@am_clamonacc_OBJECTS = output.$(OBJEXT) \ |
212 | 215 |
@BUILD_CLAMD_TRUE@ optparser.$(OBJEXT) misc.$(OBJEXT) \ |
213 | 216 |
@BUILD_CLAMD_TRUE@ getopt.$(OBJEXT) actions.$(OBJEXT) \ |
... | ... |
@@ -238,9 +241,8 @@ am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) |
238 | 238 |
am__v_at_0 = @ |
239 | 239 |
am__v_at_1 = |
240 | 240 |
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/libclammspack |
241 |
-depcomp = $(SHELL) $(top_srcdir)/config/depcomp |
|
242 |
-am__depfiles_maybe = depfiles |
|
243 |
-am__mv = mv -f |
|
241 |
+depcomp = |
|
242 |
+am__depfiles_maybe = |
|
244 | 243 |
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ |
245 | 244 |
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
246 | 245 |
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ |
... | ... |
@@ -285,7 +287,7 @@ am__define_uniq_tagged_files = \ |
285 | 285 |
done | $(am__uniquify_input)` |
286 | 286 |
ETAGS = etags |
287 | 287 |
CTAGS = ctags |
288 |
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp |
|
288 |
+am__DIST_COMMON = $(srcdir)/Makefile.in |
|
289 | 289 |
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) |
290 | 290 |
ACLOCAL = @ACLOCAL@ |
291 | 291 |
AMTAR = @AMTAR@ |
... | ... |
@@ -531,20 +533,20 @@ top_srcdir = @top_srcdir@ |
531 | 531 |
@BUILD_CLAMD_TRUE@ $(top_srcdir)/shared/clamdcom.c \ |
532 | 532 |
@BUILD_CLAMD_TRUE@ $(top_srcdir)/shared/clamdcom.h \ |
533 | 533 |
@BUILD_CLAMD_TRUE@ clamonacc.c \ |
534 |
-@BUILD_CLAMD_TRUE@ onaccess_client.c \ |
|
535 |
-@BUILD_CLAMD_TRUE@ onaccess_client.h \ |
|
536 |
-@BUILD_CLAMD_TRUE@ onaccess_proto.c \ |
|
537 |
-@BUILD_CLAMD_TRUE@ onaccess_proto.h \ |
|
538 |
-@BUILD_CLAMD_TRUE@ onaccess_ddd.c \ |
|
539 |
-@BUILD_CLAMD_TRUE@ onaccess_ddd.h \ |
|
540 |
-@BUILD_CLAMD_TRUE@ onaccess_fan.c \ |
|
541 |
-@BUILD_CLAMD_TRUE@ onaccess_fan.h \ |
|
542 |
-@BUILD_CLAMD_TRUE@ onaccess_hash.c \ |
|
543 |
-@BUILD_CLAMD_TRUE@ onaccess_hash.h \ |
|
544 |
-@BUILD_CLAMD_TRUE@ onaccess_others.c \ |
|
545 |
-@BUILD_CLAMD_TRUE@ onaccess_others.h \ |
|
546 |
-@BUILD_CLAMD_TRUE@ onaccess_scth.c \ |
|
547 |
-@BUILD_CLAMD_TRUE@ onaccess_scth.h |
|
534 |
+@BUILD_CLAMD_TRUE@ ./client/onaccess_client.c \ |
|
535 |
+@BUILD_CLAMD_TRUE@ ./client/onaccess_client.h \ |
|
536 |
+@BUILD_CLAMD_TRUE@ ./client/onaccess_proto.c \ |
|
537 |
+@BUILD_CLAMD_TRUE@ ./client/onaccess_proto.h \ |
|
538 |
+@BUILD_CLAMD_TRUE@ ./inotif/onaccess_ddd.c \ |
|
539 |
+@BUILD_CLAMD_TRUE@ ./inotif/onaccess_ddd.h \ |
|
540 |
+@BUILD_CLAMD_TRUE@ ./fanotif/onaccess_fan.c \ |
|
541 |
+@BUILD_CLAMD_TRUE@ ./fanotif/onaccess_fan.h \ |
|
542 |
+@BUILD_CLAMD_TRUE@ ./inotif/onaccess_hash.c \ |
|
543 |
+@BUILD_CLAMD_TRUE@ ./inotif/onaccess_hash.h \ |
|
544 |
+@BUILD_CLAMD_TRUE@ ./misc/onaccess_others.c \ |
|
545 |
+@BUILD_CLAMD_TRUE@ ./misc/onaccess_others.h \ |
|
546 |
+@BUILD_CLAMD_TRUE@ ./scan/onaccess_scth.c \ |
|
547 |
+@BUILD_CLAMD_TRUE@ ./scan/onaccess_scth.h |
|
548 | 548 |
|
549 | 549 |
@BUILD_CLAMD_TRUE@AM_CFLAGS = @WERR_CFLAGS@ |
550 | 550 |
AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/clamd -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav @SSL_CPPFLAGS@ @CLAMONACC_CPPFLAGS@ @JSON_CPPFLAGS@ @PCRE_CPPFLAGS@ |
... | ... |
@@ -563,9 +565,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi |
563 | 563 |
exit 1;; \ |
564 | 564 |
esac; \ |
565 | 565 |
done; \ |
566 |
- echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign clamonacc/Makefile'; \ |
|
566 |
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps clamonacc/Makefile'; \ |
|
567 | 567 |
$(am__cd) $(top_srcdir) && \ |
568 |
- $(AUTOMAKE) --foreign clamonacc/Makefile |
|
568 |
+ $(AUTOMAKE) --foreign --ignore-deps clamonacc/Makefile |
|
569 | 569 |
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status |
570 | 570 |
@case '$?' in \ |
571 | 571 |
*config.status*) \ |
... | ... |
@@ -659,125 +661,92 @@ mostlyclean-compile: |
659 | 659 |
distclean-compile: |
660 | 660 |
-rm -f *.tab.c |
661 | 661 |
|
662 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/actions.Po@am__quote@ |
|
663 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clamdcom.Po@am__quote@ |
|
664 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clamonacc.Po@am__quote@ |
|
665 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getopt.Po@am__quote@ |
|
666 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@ |
|
667 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_client.Po@am__quote@ |
|
668 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_ddd.Po@am__quote@ |
|
669 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_fan.Po@am__quote@ |
|
670 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_hash.Po@am__quote@ |
|
671 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_others.Po@am__quote@ |
|
672 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_proto.Po@am__quote@ |
|
673 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/onaccess_scth.Po@am__quote@ |
|
674 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optparser.Po@am__quote@ |
|
675 |
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@ |
|
676 |
- |
|
677 | 662 |
.c.o: |
678 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
|
679 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po |
|
680 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ |
|
681 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
682 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< |
|
663 |
+ $(AM_V_CC)$(COMPILE) -c -o $@ $< |
|
683 | 664 |
|
684 | 665 |
.c.obj: |
685 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` |
|
686 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po |
|
687 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ |
|
688 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
689 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` |
|
666 |
+ $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` |
|
690 | 667 |
|
691 | 668 |
.c.lo: |
692 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
|
693 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo |
|
694 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ |
|
695 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
696 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< |
|
669 |
+ $(AM_V_CC)$(LTCOMPILE) -c -o $@ $< |
|
697 | 670 |
|
698 | 671 |
output.o: $(top_srcdir)/shared/output.c |
699 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT output.o -MD -MP -MF $(DEPDIR)/output.Tpo -c -o output.o `test -f '$(top_srcdir)/shared/output.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/output.c |
|
700 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/output.Tpo $(DEPDIR)/output.Po |
|
701 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/output.c' object='output.o' libtool=no @AMDEPBACKSLASH@ |
|
702 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
703 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output.o `test -f '$(top_srcdir)/shared/output.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/output.c |
|
672 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output.o `test -f '$(top_srcdir)/shared/output.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/output.c |
|
704 | 673 |
|
705 | 674 |
output.obj: $(top_srcdir)/shared/output.c |
706 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT output.obj -MD -MP -MF $(DEPDIR)/output.Tpo -c -o output.obj `if test -f '$(top_srcdir)/shared/output.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/output.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/output.c'; fi` |
|
707 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/output.Tpo $(DEPDIR)/output.Po |
|
708 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/output.c' object='output.obj' libtool=no @AMDEPBACKSLASH@ |
|
709 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
710 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output.obj `if test -f '$(top_srcdir)/shared/output.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/output.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/output.c'; fi` |
|
675 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o output.obj `if test -f '$(top_srcdir)/shared/output.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/output.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/output.c'; fi` |
|
711 | 676 |
|
712 | 677 |
optparser.o: $(top_srcdir)/shared/optparser.c |
713 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT optparser.o -MD -MP -MF $(DEPDIR)/optparser.Tpo -c -o optparser.o `test -f '$(top_srcdir)/shared/optparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/optparser.c |
|
714 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/optparser.Tpo $(DEPDIR)/optparser.Po |
|
715 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/optparser.c' object='optparser.o' libtool=no @AMDEPBACKSLASH@ |
|
716 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
717 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.o `test -f '$(top_srcdir)/shared/optparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/optparser.c |
|
678 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.o `test -f '$(top_srcdir)/shared/optparser.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/optparser.c |
|
718 | 679 |
|
719 | 680 |
optparser.obj: $(top_srcdir)/shared/optparser.c |
720 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT optparser.obj -MD -MP -MF $(DEPDIR)/optparser.Tpo -c -o optparser.obj `if test -f '$(top_srcdir)/shared/optparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/optparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/optparser.c'; fi` |
|
721 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/optparser.Tpo $(DEPDIR)/optparser.Po |
|
722 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/optparser.c' object='optparser.obj' libtool=no @AMDEPBACKSLASH@ |
|
723 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
724 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.obj `if test -f '$(top_srcdir)/shared/optparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/optparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/optparser.c'; fi` |
|
681 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optparser.obj `if test -f '$(top_srcdir)/shared/optparser.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/optparser.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/optparser.c'; fi` |
|
725 | 682 |
|
726 | 683 |
misc.o: $(top_srcdir)/shared/misc.c |
727 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT misc.o -MD -MP -MF $(DEPDIR)/misc.Tpo -c -o misc.o `test -f '$(top_srcdir)/shared/misc.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/misc.c |
|
728 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/misc.Tpo $(DEPDIR)/misc.Po |
|
729 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/misc.c' object='misc.o' libtool=no @AMDEPBACKSLASH@ |
|
730 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
731 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o misc.o `test -f '$(top_srcdir)/shared/misc.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/misc.c |
|
684 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o misc.o `test -f '$(top_srcdir)/shared/misc.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/misc.c |
|
732 | 685 |
|
733 | 686 |
misc.obj: $(top_srcdir)/shared/misc.c |
734 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT misc.obj -MD -MP -MF $(DEPDIR)/misc.Tpo -c -o misc.obj `if test -f '$(top_srcdir)/shared/misc.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/misc.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/misc.c'; fi` |
|
735 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/misc.Tpo $(DEPDIR)/misc.Po |
|
736 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/misc.c' object='misc.obj' libtool=no @AMDEPBACKSLASH@ |
|
737 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
738 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o misc.obj `if test -f '$(top_srcdir)/shared/misc.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/misc.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/misc.c'; fi` |
|
687 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o misc.obj `if test -f '$(top_srcdir)/shared/misc.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/misc.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/misc.c'; fi` |
|
739 | 688 |
|
740 | 689 |
getopt.o: $(top_srcdir)/shared/getopt.c |
741 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getopt.o -MD -MP -MF $(DEPDIR)/getopt.Tpo -c -o getopt.o `test -f '$(top_srcdir)/shared/getopt.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/getopt.c |
|
742 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getopt.Tpo $(DEPDIR)/getopt.Po |
|
743 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/getopt.c' object='getopt.o' libtool=no @AMDEPBACKSLASH@ |
|
744 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
745 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getopt.o `test -f '$(top_srcdir)/shared/getopt.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/getopt.c |
|
690 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getopt.o `test -f '$(top_srcdir)/shared/getopt.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/getopt.c |
|
746 | 691 |
|
747 | 692 |
getopt.obj: $(top_srcdir)/shared/getopt.c |
748 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT getopt.obj -MD -MP -MF $(DEPDIR)/getopt.Tpo -c -o getopt.obj `if test -f '$(top_srcdir)/shared/getopt.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/getopt.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/getopt.c'; fi` |
|
749 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/getopt.Tpo $(DEPDIR)/getopt.Po |
|
750 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/getopt.c' object='getopt.obj' libtool=no @AMDEPBACKSLASH@ |
|
751 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
752 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getopt.obj `if test -f '$(top_srcdir)/shared/getopt.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/getopt.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/getopt.c'; fi` |
|
693 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o getopt.obj `if test -f '$(top_srcdir)/shared/getopt.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/getopt.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/getopt.c'; fi` |
|
753 | 694 |
|
754 | 695 |
actions.o: $(top_srcdir)/shared/actions.c |
755 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT actions.o -MD -MP -MF $(DEPDIR)/actions.Tpo -c -o actions.o `test -f '$(top_srcdir)/shared/actions.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/actions.c |
|
756 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/actions.Tpo $(DEPDIR)/actions.Po |
|
757 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/actions.c' object='actions.o' libtool=no @AMDEPBACKSLASH@ |
|
758 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
759 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o actions.o `test -f '$(top_srcdir)/shared/actions.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/actions.c |
|
696 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o actions.o `test -f '$(top_srcdir)/shared/actions.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/actions.c |
|
760 | 697 |
|
761 | 698 |
actions.obj: $(top_srcdir)/shared/actions.c |
762 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT actions.obj -MD -MP -MF $(DEPDIR)/actions.Tpo -c -o actions.obj `if test -f '$(top_srcdir)/shared/actions.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/actions.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/actions.c'; fi` |
|
763 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/actions.Tpo $(DEPDIR)/actions.Po |
|
764 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/actions.c' object='actions.obj' libtool=no @AMDEPBACKSLASH@ |
|
765 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
766 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o actions.obj `if test -f '$(top_srcdir)/shared/actions.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/actions.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/actions.c'; fi` |
|
699 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o actions.obj `if test -f '$(top_srcdir)/shared/actions.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/actions.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/actions.c'; fi` |
|
767 | 700 |
|
768 | 701 |
clamdcom.o: $(top_srcdir)/shared/clamdcom.c |
769 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT clamdcom.o -MD -MP -MF $(DEPDIR)/clamdcom.Tpo -c -o clamdcom.o `test -f '$(top_srcdir)/shared/clamdcom.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/clamdcom.c |
|
770 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clamdcom.Tpo $(DEPDIR)/clamdcom.Po |
|
771 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/clamdcom.c' object='clamdcom.o' libtool=no @AMDEPBACKSLASH@ |
|
772 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
773 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o clamdcom.o `test -f '$(top_srcdir)/shared/clamdcom.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/clamdcom.c |
|
702 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o clamdcom.o `test -f '$(top_srcdir)/shared/clamdcom.c' || echo '$(srcdir)/'`$(top_srcdir)/shared/clamdcom.c |
|
774 | 703 |
|
775 | 704 |
clamdcom.obj: $(top_srcdir)/shared/clamdcom.c |
776 |
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT clamdcom.obj -MD -MP -MF $(DEPDIR)/clamdcom.Tpo -c -o clamdcom.obj `if test -f '$(top_srcdir)/shared/clamdcom.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/clamdcom.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/clamdcom.c'; fi` |
|
777 |
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/clamdcom.Tpo $(DEPDIR)/clamdcom.Po |
|
778 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/shared/clamdcom.c' object='clamdcom.obj' libtool=no @AMDEPBACKSLASH@ |
|
779 |
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
780 |
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o clamdcom.obj `if test -f '$(top_srcdir)/shared/clamdcom.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/clamdcom.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/clamdcom.c'; fi` |
|
705 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o clamdcom.obj `if test -f '$(top_srcdir)/shared/clamdcom.c'; then $(CYGPATH_W) '$(top_srcdir)/shared/clamdcom.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/shared/clamdcom.c'; fi` |
|
706 |
+ |
|
707 |
+onaccess_client.o: ./client/onaccess_client.c |
|
708 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_client.o `test -f './client/onaccess_client.c' || echo '$(srcdir)/'`./client/onaccess_client.c |
|
709 |
+ |
|
710 |
+onaccess_client.obj: ./client/onaccess_client.c |
|
711 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_client.obj `if test -f './client/onaccess_client.c'; then $(CYGPATH_W) './client/onaccess_client.c'; else $(CYGPATH_W) '$(srcdir)/./client/onaccess_client.c'; fi` |
|
712 |
+ |
|
713 |
+onaccess_proto.o: ./client/onaccess_proto.c |
|
714 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_proto.o `test -f './client/onaccess_proto.c' || echo '$(srcdir)/'`./client/onaccess_proto.c |
|
715 |
+ |
|
716 |
+onaccess_proto.obj: ./client/onaccess_proto.c |
|
717 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_proto.obj `if test -f './client/onaccess_proto.c'; then $(CYGPATH_W) './client/onaccess_proto.c'; else $(CYGPATH_W) '$(srcdir)/./client/onaccess_proto.c'; fi` |
|
718 |
+ |
|
719 |
+onaccess_ddd.o: ./inotif/onaccess_ddd.c |
|
720 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_ddd.o `test -f './inotif/onaccess_ddd.c' || echo '$(srcdir)/'`./inotif/onaccess_ddd.c |
|
721 |
+ |
|
722 |
+onaccess_ddd.obj: ./inotif/onaccess_ddd.c |
|
723 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_ddd.obj `if test -f './inotif/onaccess_ddd.c'; then $(CYGPATH_W) './inotif/onaccess_ddd.c'; else $(CYGPATH_W) '$(srcdir)/./inotif/onaccess_ddd.c'; fi` |
|
724 |
+ |
|
725 |
+onaccess_fan.o: ./fanotif/onaccess_fan.c |
|
726 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_fan.o `test -f './fanotif/onaccess_fan.c' || echo '$(srcdir)/'`./fanotif/onaccess_fan.c |
|
727 |
+ |
|
728 |
+onaccess_fan.obj: ./fanotif/onaccess_fan.c |
|
729 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_fan.obj `if test -f './fanotif/onaccess_fan.c'; then $(CYGPATH_W) './fanotif/onaccess_fan.c'; else $(CYGPATH_W) '$(srcdir)/./fanotif/onaccess_fan.c'; fi` |
|
730 |
+ |
|
731 |
+onaccess_hash.o: ./inotif/onaccess_hash.c |
|
732 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_hash.o `test -f './inotif/onaccess_hash.c' || echo '$(srcdir)/'`./inotif/onaccess_hash.c |
|
733 |
+ |
|
734 |
+onaccess_hash.obj: ./inotif/onaccess_hash.c |
|
735 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_hash.obj `if test -f './inotif/onaccess_hash.c'; then $(CYGPATH_W) './inotif/onaccess_hash.c'; else $(CYGPATH_W) '$(srcdir)/./inotif/onaccess_hash.c'; fi` |
|
736 |
+ |
|
737 |
+onaccess_others.o: ./misc/onaccess_others.c |
|
738 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_others.o `test -f './misc/onaccess_others.c' || echo '$(srcdir)/'`./misc/onaccess_others.c |
|
739 |
+ |
|
740 |
+onaccess_others.obj: ./misc/onaccess_others.c |
|
741 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_others.obj `if test -f './misc/onaccess_others.c'; then $(CYGPATH_W) './misc/onaccess_others.c'; else $(CYGPATH_W) '$(srcdir)/./misc/onaccess_others.c'; fi` |
|
742 |
+ |
|
743 |
+onaccess_scth.o: ./scan/onaccess_scth.c |
|
744 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_scth.o `test -f './scan/onaccess_scth.c' || echo '$(srcdir)/'`./scan/onaccess_scth.c |
|
745 |
+ |
|
746 |
+onaccess_scth.obj: ./scan/onaccess_scth.c |
|
747 |
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o onaccess_scth.obj `if test -f './scan/onaccess_scth.c'; then $(CYGPATH_W) './scan/onaccess_scth.c'; else $(CYGPATH_W) '$(srcdir)/./scan/onaccess_scth.c'; fi` |
|
781 | 748 |
|
782 | 749 |
mostlyclean-libtool: |
783 | 750 |
-rm -f *.lo |
... | ... |
@@ -910,7 +879,6 @@ clean: clean-am |
910 | 910 |
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am |
911 | 911 |
|
912 | 912 |
distclean: distclean-am |
913 |
- -rm -rf ./$(DEPDIR) |
|
914 | 913 |
-rm -f Makefile |
915 | 914 |
distclean-am: clean-am distclean-compile distclean-generic \ |
916 | 915 |
distclean-tags |
... | ... |
@@ -956,7 +924,6 @@ install-ps-am: |
956 | 956 |
installcheck-am: installcheck-binPROGRAMS |
957 | 957 |
|
958 | 958 |
maintainer-clean: maintainer-clean-am |
959 |
- -rm -rf ./$(DEPDIR) |
|
960 | 959 |
-rm -f Makefile |
961 | 960 |
maintainer-clean-am: distclean-am maintainer-clean-generic |
962 | 961 |
|
... | ... |
@@ -43,7 +43,7 @@ |
43 | 43 |
#include "shared/optparser.h" |
44 | 44 |
#include "shared/actions.h" |
45 | 45 |
|
46 |
-#include "onaccess_client.h" |
|
46 |
+#include "./client/onaccess_client.h" |
|
47 | 47 |
|
48 | 48 |
void help(void); |
49 | 49 |
|
... | ... |
@@ -117,7 +117,7 @@ int main(int argc, char **argv) |
117 | 117 |
optfree(clamdopts); |
118 | 118 |
exit(2); |
119 | 119 |
} |
120 |
- } else |
|
120 |
+ } else |
|
121 | 121 |
logg_file = NULL; |
122 | 122 |
|
123 | 123 |
|
124 | 124 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,322 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2009 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm, aCaB, Mickey Sola |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#if HAVE_CONFIG_H |
|
22 |
+#include "clamav-config.h" |
|
23 |
+#endif |
|
24 |
+ |
|
25 |
+#include <stdio.h> |
|
26 |
+#include <stdlib.h> |
|
27 |
+#ifdef HAVE_UNISTD_H |
|
28 |
+#include <unistd.h> |
|
29 |
+#endif |
|
30 |
+#include <string.h> |
|
31 |
+#include <sys/types.h> |
|
32 |
+#include <sys/stat.h> |
|
33 |
+#ifdef HAVE_SYS_LIMITS_H |
|
34 |
+#include <sys/limits.h> |
|
35 |
+#endif |
|
36 |
+#ifdef HAVE_SYS_SELECT_H |
|
37 |
+#include <sys/select.h> |
|
38 |
+#endif |
|
39 |
+#include <sys/socket.h> |
|
40 |
+#include <sys/un.h> |
|
41 |
+#include <netinet/in.h> |
|
42 |
+#include <arpa/inet.h> |
|
43 |
+#include <netdb.h> |
|
44 |
+#include <utime.h> |
|
45 |
+#include <errno.h> |
|
46 |
+#include <dirent.h> |
|
47 |
+#include <fcntl.h> |
|
48 |
+ |
|
49 |
+#ifdef HAVE_SYS_UIO_H |
|
50 |
+#include <sys/uio.h> |
|
51 |
+#endif |
|
52 |
+ |
|
53 |
+#include "libclamav/clamav.h" |
|
54 |
+#include "shared/optparser.h" |
|
55 |
+#include "shared/output.h" |
|
56 |
+#include "shared/misc.h" |
|
57 |
+#include "shared/actions.h" |
|
58 |
+#include "shared/clamdcom.h" |
|
59 |
+ |
|
60 |
+#include "libclamav/str.h" |
|
61 |
+#include "libclamav/others.h" |
|
62 |
+ |
|
63 |
+#include "onaccess_client.h" |
|
64 |
+#include "onaccess_proto.h" |
|
65 |
+ |
|
66 |
+unsigned long int maxstream; |
|
67 |
+struct sockaddr_un nixsock; |
|
68 |
+extern struct optstruct *clamdopts; |
|
69 |
+ |
|
70 |
+/* Inits the communication layer |
|
71 |
+ * Returns 0 if clamd is local, non zero if clamd is remote */ |
|
72 |
+static int isremote(const struct optstruct *opts) { |
|
73 |
+ int s, ret; |
|
74 |
+ const struct optstruct *opt; |
|
75 |
+ char *ipaddr, port[10]; |
|
76 |
+ struct addrinfo hints, *info, *p; |
|
77 |
+ int res; |
|
78 |
+ |
|
79 |
+ UNUSEDPARAM(opts); |
|
80 |
+ |
|
81 |
+#ifndef _WIN32 |
|
82 |
+ if((opt = optget(clamdopts, "LocalSocket"))->enabled) { |
|
83 |
+ memset((void *)&nixsock, 0, sizeof(nixsock)); |
|
84 |
+ nixsock.sun_family = AF_UNIX; |
|
85 |
+ strncpy(nixsock.sun_path, opt->strarg, sizeof(nixsock.sun_path)); |
|
86 |
+ nixsock.sun_path[sizeof(nixsock.sun_path)-1]='\0'; |
|
87 |
+ return 0; |
|
88 |
+ } |
|
89 |
+#endif |
|
90 |
+ if(!(opt = optget(clamdopts, "TCPSocket"))->enabled) |
|
91 |
+ return 0; |
|
92 |
+ |
|
93 |
+ snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg); |
|
94 |
+ |
|
95 |
+ opt = optget(clamdopts, "TCPAddr"); |
|
96 |
+ while (opt) { |
|
97 |
+ ipaddr = NULL; |
|
98 |
+ if (opt->strarg) |
|
99 |
+ ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg); |
|
100 |
+ |
|
101 |
+ memset(&hints, 0x00, sizeof(struct addrinfo)); |
|
102 |
+ hints.ai_family = AF_UNSPEC; |
|
103 |
+ hints.ai_socktype = SOCK_STREAM; |
|
104 |
+ hints.ai_flags = AI_PASSIVE; |
|
105 |
+ |
|
106 |
+ if ((res = getaddrinfo(ipaddr, port, &hints, &info))) { |
|
107 |
+ logg("!Can't lookup clamd hostname: %s\n", gai_strerror(res)); |
|
108 |
+ opt = opt->nextarg; |
|
109 |
+ continue; |
|
110 |
+ } |
|
111 |
+ |
|
112 |
+ for (p = info; p != NULL; p = p->ai_next) { |
|
113 |
+ if((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { |
|
114 |
+ logg("isremote: socket() returning: %s.\n", strerror(errno)); |
|
115 |
+ continue; |
|
116 |
+ } |
|
117 |
+ |
|
118 |
+ switch (p->ai_family) { |
|
119 |
+ case AF_INET: |
|
120 |
+ ((struct sockaddr_in *)(p->ai_addr))->sin_port = htons(INADDR_ANY); |
|
121 |
+ break; |
|
122 |
+ case AF_INET6: |
|
123 |
+ ((struct sockaddr_in6 *)(p->ai_addr))->sin6_port = htons(INADDR_ANY); |
|
124 |
+ break; |
|
125 |
+ default: |
|
126 |
+ break; |
|
127 |
+ } |
|
128 |
+ |
|
129 |
+ ret = bind(s, p->ai_addr, p->ai_addrlen); |
|
130 |
+ if (ret) { |
|
131 |
+ if (errno == EADDRINUSE) { |
|
132 |
+ /* |
|
133 |
+ * If we can't bind, then either we're attempting to listen on an IP that isn't |
|
134 |
+ * ours or that clamd is already listening on. |
|
135 |
+ */ |
|
136 |
+ closesocket(s); |
|
137 |
+ freeaddrinfo(info); |
|
138 |
+ return 0; |
|
139 |
+ } |
|
140 |
+ |
|
141 |
+ closesocket(s); |
|
142 |
+ freeaddrinfo(info); |
|
143 |
+ return 1; |
|
144 |
+ } |
|
145 |
+ |
|
146 |
+ closesocket(s); |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ freeaddrinfo(info); |
|
150 |
+ |
|
151 |
+ opt = opt->nextarg; |
|
152 |
+ } |
|
153 |
+ |
|
154 |
+ return 0; |
|
155 |
+} |
|
156 |
+ |
|
157 |
+ |
|
158 |
+/* Turns a relative path into an absolute one |
|
159 |
+ * Returns a pointer to the path (which must be |
|
160 |
+ * freed by the caller) or NULL on error */ |
|
161 |
+static char *makeabs(const char *basepath) { |
|
162 |
+ int namelen; |
|
163 |
+ char *ret; |
|
164 |
+ |
|
165 |
+ if(!(ret = malloc(PATH_MAX + 1))) { |
|
166 |
+ logg("^Can't make room for fullpath.\n"); |
|
167 |
+ return NULL; |
|
168 |
+ } |
|
169 |
+ if(!cli_is_abspath(basepath)) { |
|
170 |
+ if(!getcwd(ret, PATH_MAX)) { |
|
171 |
+ logg("^Can't get absolute pathname of current working directory.\n"); |
|
172 |
+ free(ret); |
|
173 |
+ return NULL; |
|
174 |
+ } |
|
175 |
+ if(*basepath == '\\') { |
|
176 |
+ namelen = 2; |
|
177 |
+ basepath++; |
|
178 |
+ } else |
|
179 |
+ namelen = strlen(ret); |
|
180 |
+ snprintf(&ret[namelen], PATH_MAX - namelen, PATHSEP"%s", basepath); |
|
181 |
+ } else { |
|
182 |
+ strncpy(ret, basepath, PATH_MAX); |
|
183 |
+ } |
|
184 |
+ ret[PATH_MAX] = '\0'; |
|
185 |
+ return ret; |
|
186 |
+} |
|
187 |
+ |
|
188 |
+/* Recursively scans a path with the given scantype |
|
189 |
+ * Returns non zero for serious errors, zero otherwise */ |
|
190 |
+static int client_scan(const char *file, int scantype, int *infected, int *err, int maxlevel, int session, int flags) { |
|
191 |
+ int ret; |
|
192 |
+ char *fullpath = makeabs(file); |
|
193 |
+ |
|
194 |
+ if(!fullpath) |
|
195 |
+ return 0; |
|
196 |
+ if (!session) |
|
197 |
+ ret = serial_client_scan(fullpath, scantype, infected, err, maxlevel, flags); |
|
198 |
+ else |
|
199 |
+ ret = parallel_client_scan(fullpath, scantype, infected, err, maxlevel, flags); |
|
200 |
+ free(fullpath); |
|
201 |
+ return ret; |
|
202 |
+} |
|
203 |
+ |
|
204 |
+int get_clamd_version(const struct optstruct *opts) |
|
205 |
+{ |
|
206 |
+ char *buff; |
|
207 |
+ int len, sockd; |
|
208 |
+ struct RCVLN rcv; |
|
209 |
+ |
|
210 |
+ isremote(opts); |
|
211 |
+ if((sockd = dconnect()) < 0) return 2; |
|
212 |
+ recvlninit(&rcv, sockd); |
|
213 |
+ |
|
214 |
+ if(sendln(sockd, "zVERSION", 9)) { |
|
215 |
+ closesocket(sockd); |
|
216 |
+ return 2; |
|
217 |
+ } |
|
218 |
+ |
|
219 |
+ while((len = recvln(&rcv, &buff, NULL))) { |
|
220 |
+ if(len == -1) { |
|
221 |
+ logg("!Error occurred while receiving version information.\n"); |
|
222 |
+ break; |
|
223 |
+ } |
|
224 |
+ printf("%s\n", buff); |
|
225 |
+ } |
|
226 |
+ |
|
227 |
+ closesocket(sockd); |
|
228 |
+ return 0; |
|
229 |
+} |
|
230 |
+ |
|
231 |
+int reload_clamd_database(const struct optstruct *opts) |
|
232 |
+{ |
|
233 |
+ char *buff; |
|
234 |
+ int len, sockd; |
|
235 |
+ struct RCVLN rcv; |
|
236 |
+ |
|
237 |
+ isremote(opts); |
|
238 |
+ if((sockd = dconnect()) < 0) return 2; |
|
239 |
+ recvlninit(&rcv, sockd); |
|
240 |
+ |
|
241 |
+ if(sendln(sockd, "zRELOAD", 8)) { |
|
242 |
+ closesocket(sockd); |
|
243 |
+ return 2; |
|
244 |
+ } |
|
245 |
+ |
|
246 |
+ if(!(len = recvln(&rcv, &buff, NULL)) || len < 10 || memcmp(buff, "RELOADING", 9)) { |
|
247 |
+ logg("!Clamd did not reload the database\n"); |
|
248 |
+ closesocket(sockd); |
|
249 |
+ return 2; |
|
250 |
+ } |
|
251 |
+ closesocket(sockd); |
|
252 |
+ return 0; |
|
253 |
+} |
|
254 |
+ |
|
255 |
+int client(const struct optstruct *opts, int *infected, int *err) |
|
256 |
+{ |
|
257 |
+ int remote, scantype, session = 0, errors = 0, scandash = 0, maxrec, flags = 0; |
|
258 |
+ const char *fname; |
|
259 |
+ |
|
260 |
+ scandash = (opts->filename && opts->filename[0] && !strcmp(opts->filename[0], "-") && !optget(opts, "file-list")->enabled && !opts->filename[1]); |
|
261 |
+ remote = isremote(opts) | optget(opts, "stream")->enabled; |
|
262 |
+#ifdef HAVE_FD_PASSING |
|
263 |
+ if(!remote && optget(clamdopts, "LocalSocket")->enabled && (optget(opts, "fdpass")->enabled || scandash)) { |
|
264 |
+ scantype = FILDES; |
|
265 |
+ session = optget(opts, "multiscan")->enabled; |
|
266 |
+ } else |
|
267 |
+#endif |
|
268 |
+ if(remote || scandash) { |
|
269 |
+ scantype = STREAM; |
|
270 |
+ session = optget(opts, "multiscan")->enabled; |
|
271 |
+ } |
|
272 |
+ else if(optget(opts, "multiscan")->enabled) scantype = MULTI; |
|
273 |
+ else if(optget(opts, "allmatch")->enabled) scantype = ALLMATCH; |
|
274 |
+ else scantype = CONT; |
|
275 |
+ |
|
276 |
+ maxrec = optget(clamdopts, "MaxDirectoryRecursion")->numarg; |
|
277 |
+ maxstream = optget(clamdopts, "StreamMaxLength")->numarg; |
|
278 |
+ if (optget(clamdopts, "FollowDirectorySymlinks")->enabled) |
|
279 |
+ flags |= CLI_FTW_FOLLOW_DIR_SYMLINK; |
|
280 |
+ if (optget(clamdopts, "FollowFileSymlinks")->enabled) |
|
281 |
+ flags |= CLI_FTW_FOLLOW_FILE_SYMLINK; |
|
282 |
+ flags |= CLI_FTW_TRIM_SLASHES; |
|
283 |
+ |
|
284 |
+ *infected = 0; |
|
285 |
+ |
|
286 |
+ if(scandash) { |
|
287 |
+ int sockd, ret; |
|
288 |
+ STATBUF sb; |
|
289 |
+ if(FSTAT(0, &sb) < 0) { |
|
290 |
+ logg("client.c: fstat failed for file name \"%s\", with %s\n.", |
|
291 |
+ opts->filename[0], strerror(errno)); |
|
292 |
+ return 2; |
|
293 |
+ } |
|
294 |
+ if((sb.st_mode & S_IFMT) != S_IFREG) scantype = STREAM; |
|
295 |
+ if((sockd = dconnect()) >= 0 && (ret = dsresult(sockd, scantype, NULL, &ret, NULL)) >= 0) |
|
296 |
+ *infected = ret; |
|
297 |
+ else |
|
298 |
+ errors = 1; |
|
299 |
+ if(sockd >= 0) closesocket(sockd); |
|
300 |
+ } else if(opts->filename || optget(opts, "file-list")->enabled) { |
|
301 |
+ if(opts->filename && optget(opts, "file-list")->enabled) |
|
302 |
+ logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); |
|
303 |
+ |
|
304 |
+ while((fname = filelist(opts, NULL))) { |
|
305 |
+ if(!strcmp(fname, "-")) { |
|
306 |
+ logg("!Scanning from standard input requires \"-\" to be the only file argument\n"); |
|
307 |
+ continue; |
|
308 |
+ } |
|
309 |
+ errors += client_scan(fname, scantype, infected, err, maxrec, session, flags); |
|
310 |
+ /* this may be too strict |
|
311 |
+ if(errors >= 10) { |
|
312 |
+ logg("!Too many errors\n"); |
|
313 |
+ break; |
|
314 |
+ } |
|
315 |
+ */ |
|
316 |
+ } |
|
317 |
+ } else { |
|
318 |
+ errors = client_scan("", scantype, infected, err, maxrec, session, flags); |
|
319 |
+ } |
|
320 |
+ return *infected ? 1 : (errors ? 2 : 0); |
|
321 |
+} |
0 | 322 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,40 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2009 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm, aCaB |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#ifndef __ONAS_CLIENT_H |
|
22 |
+#define __ONAS_CLIENT_H |
|
23 |
+ |
|
24 |
+#include "shared/optparser.h" |
|
25 |
+ |
|
26 |
+enum { |
|
27 |
+ CONT, |
|
28 |
+ MULTI, |
|
29 |
+ STREAM, |
|
30 |
+ FILDES, |
|
31 |
+ ALLMATCH, |
|
32 |
+ MAX_SCANTYPE = ALLMATCH |
|
33 |
+}; |
|
34 |
+ |
|
35 |
+int client(const struct optstruct *opts, int *infected, int *err); |
|
36 |
+int get_clamd_version(const struct optstruct *opts); |
|
37 |
+int reload_clamd_database(const struct optstruct *opts); |
|
38 |
+ |
|
39 |
+#endif |
0 | 40 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,691 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2009 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm, aCaB |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#if HAVE_CONFIG_H |
|
22 |
+#include "clamav-config.h" |
|
23 |
+#endif |
|
24 |
+ |
|
25 |
+#if defined(C_SOLARIS) |
|
26 |
+#ifndef __EXTENSIONS__ |
|
27 |
+#define __EXTENSIONS__ |
|
28 |
+#endif |
|
29 |
+#endif |
|
30 |
+ |
|
31 |
+/* must be first because it may define _XOPEN_SOURCE */ |
|
32 |
+#include "shared/fdpassing.h" |
|
33 |
+#include <stdio.h> |
|
34 |
+#ifdef HAVE_UNISTD_H |
|
35 |
+#include <unistd.h> |
|
36 |
+#endif |
|
37 |
+#include <string.h> |
|
38 |
+#include <errno.h> |
|
39 |
+#include <stdlib.h> |
|
40 |
+#include <sys/types.h> |
|
41 |
+#include <sys/stat.h> |
|
42 |
+#include <fcntl.h> |
|
43 |
+#include <sys/types.h> |
|
44 |
+#ifdef HAVE_SYS_SELECT_H |
|
45 |
+#include <sys/select.h> |
|
46 |
+#endif |
|
47 |
+#ifndef _WIN32 |
|
48 |
+#include <arpa/inet.h> |
|
49 |
+#include <sys/socket.h> |
|
50 |
+#include <sys/un.h> |
|
51 |
+#include <netdb.h> |
|
52 |
+#endif |
|
53 |
+ |
|
54 |
+#include "libclamav/clamav.h" |
|
55 |
+#include "libclamav/others.h" |
|
56 |
+#include "shared/actions.h" |
|
57 |
+#include "shared/output.h" |
|
58 |
+#include "shared/misc.h" |
|
59 |
+#include "shared/clamdcom.h" |
|
60 |
+ |
|
61 |
+#include "onaccess_proto.h" |
|
62 |
+#include "onaccess_client.h" |
|
63 |
+ |
|
64 |
+extern unsigned long int maxstream; |
|
65 |
+int printinfected; |
|
66 |
+extern struct optstruct *clamdopts; |
|
67 |
+#ifndef _WIN32 |
|
68 |
+extern struct sockaddr_un nixsock; |
|
69 |
+#endif |
|
70 |
+ |
|
71 |
+static const char *scancmd[] = { "CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN" }; |
|
72 |
+ |
|
73 |
+/* Connects to clamd |
|
74 |
+ * Returns a FD or -1 on error */ |
|
75 |
+int dconnect() { |
|
76 |
+ int sockd, res; |
|
77 |
+ const struct optstruct *opt; |
|
78 |
+ struct addrinfo hints, *info, *p; |
|
79 |
+ char port[10]; |
|
80 |
+ char *ipaddr; |
|
81 |
+ |
|
82 |
+#ifndef _WIN32 |
|
83 |
+ opt = optget(clamdopts, "LocalSocket"); |
|
84 |
+ if (opt->enabled) { |
|
85 |
+ if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { |
|
86 |
+ if (connect(sockd, (struct sockaddr *)&nixsock, sizeof(nixsock)) == 0) |
|
87 |
+ return sockd; |
|
88 |
+ else { |
|
89 |
+ logg("!Could not connect to clamd on LocalSocket %s: %s\n", opt->strarg, strerror(errno)); |
|
90 |
+ close(sockd); |
|
91 |
+ } |
|
92 |
+ } |
|
93 |
+ } |
|
94 |
+#endif |
|
95 |
+ |
|
96 |
+ snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg); |
|
97 |
+ |
|
98 |
+ opt = optget(clamdopts, "TCPAddr"); |
|
99 |
+ while (opt) { |
|
100 |
+ if (opt->enabled) { |
|
101 |
+ ipaddr = NULL; |
|
102 |
+ if (opt->strarg) |
|
103 |
+ ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg); |
|
104 |
+ |
|
105 |
+ memset(&hints, 0x00, sizeof(struct addrinfo)); |
|
106 |
+ hints.ai_family = AF_UNSPEC; |
|
107 |
+ hints.ai_socktype = SOCK_STREAM; |
|
108 |
+ |
|
109 |
+ if ((res = getaddrinfo(ipaddr, port, &hints, &info))) { |
|
110 |
+ logg("!Could not lookup %s: %s\n", ipaddr ? ipaddr : "", gai_strerror(res)); |
|
111 |
+ opt = opt->nextarg; |
|
112 |
+ continue; |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ for (p = info; p != NULL; p = p->ai_next) { |
|
116 |
+ if((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { |
|
117 |
+ logg("!Can't create the socket: %s\n", strerror(errno)); |
|
118 |
+ continue; |
|
119 |
+ } |
|
120 |
+ |
|
121 |
+ if(connect(sockd, p->ai_addr, p->ai_addrlen) < 0) { |
|
122 |
+ logg("!Could not connect to clamd on %s: %s\n", opt->strarg, strerror(errno)); |
|
123 |
+ closesocket(sockd); |
|
124 |
+ continue; |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ freeaddrinfo(info); |
|
128 |
+ return sockd; |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ freeaddrinfo(info); |
|
132 |
+ } |
|
133 |
+ opt = opt->nextarg; |
|
134 |
+ } |
|
135 |
+ |
|
136 |
+ return -1; |
|
137 |
+} |
|
138 |
+ |
|
139 |
+/* Issues an INSTREAM command to clamd and streams the given file |
|
140 |
+ * Returns >0 on success, 0 soft fail, -1 hard fail */ |
|
141 |
+static int send_stream(int sockd, const char *filename) { |
|
142 |
+ uint32_t buf[BUFSIZ/sizeof(uint32_t)]; |
|
143 |
+ int fd, len; |
|
144 |
+ unsigned long int todo = maxstream; |
|
145 |
+ |
|
146 |
+ if(filename) { |
|
147 |
+ if((fd = safe_open(filename, O_RDONLY | O_BINARY))<0) { |
|
148 |
+ logg("~%s: Access denied. ERROR\n", filename); |
|
149 |
+ return 0; |
|
150 |
+ } |
|
151 |
+ } else fd = 0; |
|
152 |
+ |
|
153 |
+ if(sendln(sockd, "zINSTREAM", 10)) { |
|
154 |
+ close(fd); |
|
155 |
+ return -1; |
|
156 |
+ } |
|
157 |
+ |
|
158 |
+ while((len = read(fd, &buf[1], sizeof(buf) - sizeof(uint32_t))) > 0) { |
|
159 |
+ if((unsigned int)len > todo) len = todo; |
|
160 |
+ buf[0] = htonl(len); |
|
161 |
+ if(sendln(sockd, (const char *)buf, len+sizeof(uint32_t))) { |
|
162 |
+ close(fd); |
|
163 |
+ return -1; |
|
164 |
+ } |
|
165 |
+ todo -= len; |
|
166 |
+ if(!todo) { |
|
167 |
+ len = 0; |
|
168 |
+ break; |
|
169 |
+ } |
|
170 |
+ } |
|
171 |
+ close(fd); |
|
172 |
+ if(len) { |
|
173 |
+ logg("!Failed to read from %s.\n", filename ? filename : "STDIN"); |
|
174 |
+ return 0; |
|
175 |
+ } |
|
176 |
+ *buf=0; |
|
177 |
+ sendln(sockd, (const char *)buf, 4); |
|
178 |
+ return 1; |
|
179 |
+} |
|
180 |
+ |
|
181 |
+#ifdef HAVE_FD_PASSING |
|
182 |
+/* Issues a FILDES command and pass a FD to clamd |
|
183 |
+ * Returns >0 on success, 0 soft fail, -1 hard fail */ |
|
184 |
+static int send_fdpass(int sockd, const char *filename) { |
|
185 |
+ struct iovec iov[1]; |
|
186 |
+ struct msghdr msg; |
|
187 |
+ struct cmsghdr *cmsg; |
|
188 |
+ unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
|
189 |
+ char dummy[]=""; |
|
190 |
+ int fd; |
|
191 |
+ |
|
192 |
+ if(filename) { |
|
193 |
+ if((fd = open(filename, O_RDONLY))<0) { |
|
194 |
+ logg("~%s: Access denied. ERROR\n", filename); |
|
195 |
+ return 0; |
|
196 |
+ } |
|
197 |
+ } else fd = 0; |
|
198 |
+ if(sendln(sockd, "zFILDES", 8)) { |
|
199 |
+ close(fd); |
|
200 |
+ return -1; |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ iov[0].iov_base = dummy; |
|
204 |
+ iov[0].iov_len = 1; |
|
205 |
+ memset(&msg, 0, sizeof(msg)); |
|
206 |
+ msg.msg_control = fdbuf; |
|
207 |
+ msg.msg_iov = iov; |
|
208 |
+ msg.msg_iovlen = 1; |
|
209 |
+ msg.msg_controllen = CMSG_LEN(sizeof(int)); |
|
210 |
+ cmsg = CMSG_FIRSTHDR(&msg); |
|
211 |
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
|
212 |
+ cmsg->cmsg_level = SOL_SOCKET; |
|
213 |
+ cmsg->cmsg_type = SCM_RIGHTS; |
|
214 |
+ *(int *)CMSG_DATA(cmsg) = fd; |
|
215 |
+ if(sendmsg(sockd, &msg, 0) == -1) { |
|
216 |
+ logg("!FD send failed: %s\n", strerror(errno)); |
|
217 |
+ close(fd); |
|
218 |
+ return -1; |
|
219 |
+ } |
|
220 |
+ close(fd); |
|
221 |
+ return 1; |
|
222 |
+} |
|
223 |
+#endif |
|
224 |
+ |
|
225 |
+/* 0: scan, 1: skip */ |
|
226 |
+static int chkpath(const char *path) |
|
227 |
+{ |
|
228 |
+ const struct optstruct *opt; |
|
229 |
+ |
|
230 |
+ if((opt = optget(clamdopts, "ExcludePath"))->enabled) { |
|
231 |
+ while(opt) { |
|
232 |
+ if(match_regex(path, opt->strarg) == 1) { |
|
233 |
+ if (printinfected != 1) |
|
234 |
+ logg("~%s: Excluded\n", path); |
|
235 |
+ return 1; |
|
236 |
+ } |
|
237 |
+ opt = opt->nextarg; |
|
238 |
+ } |
|
239 |
+ } |
|
240 |
+ return 0; |
|
241 |
+} |
|
242 |
+ |
|
243 |
+static int ftw_chkpath(const char *path, struct cli_ftw_cbdata *data) |
|
244 |
+{ |
|
245 |
+ UNUSEDPARAM(data); |
|
246 |
+ return chkpath(path); |
|
247 |
+} |
|
248 |
+ |
|
249 |
+/* Sends a proper scan request to clamd and parses its replies |
|
250 |
+ * This is used only in non IDSESSION mode |
|
251 |
+ * Returns the number of infected files or -1 on error |
|
252 |
+ * NOTE: filename may be NULL for STREAM scantype. */ |
|
253 |
+int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors) { |
|
254 |
+ int infected = 0, len = 0, beenthere = 0; |
|
255 |
+ char *bol, *eol; |
|
256 |
+ struct RCVLN rcv; |
|
257 |
+ STATBUF sb; |
|
258 |
+ |
|
259 |
+ if(filename && chkpath(filename)) |
|
260 |
+ return 0; |
|
261 |
+ recvlninit(&rcv, sockd); |
|
262 |
+ |
|
263 |
+ switch(scantype) { |
|
264 |
+ case MULTI: |
|
265 |
+ case CONT: |
|
266 |
+ case ALLMATCH: |
|
267 |
+ if (!filename) { |
|
268 |
+ logg("Filename cannot be NULL for MULTISCAN or CONTSCAN.\n"); |
|
269 |
+ return -1; |
|
270 |
+ } |
|
271 |
+ len = strlen(filename) + strlen(scancmd[scantype]) + 3; |
|
272 |
+ if (!(bol = malloc(len))) { |
|
273 |
+ logg("!Cannot allocate a command buffer: %s\n", strerror(errno)); |
|
274 |
+ return -1; |
|
275 |
+ } |
|
276 |
+ sprintf(bol, "z%s %s", scancmd[scantype], filename); |
|
277 |
+ if(sendln(sockd, bol, len)) { |
|
278 |
+ free(bol); |
|
279 |
+ return -1; |
|
280 |
+ } |
|
281 |
+ free(bol); |
|
282 |
+ break; |
|
283 |
+ |
|
284 |
+ case STREAM: |
|
285 |
+ /* NULL filename safe in send_stream() */ |
|
286 |
+ len = send_stream(sockd, filename); |
|
287 |
+ break; |
|
288 |
+#ifdef HAVE_FD_PASSING |
|
289 |
+ case FILDES: |
|
290 |
+ /* NULL filename safe in send_fdpass() */ |
|
291 |
+ len = send_fdpass(sockd, filename); |
|
292 |
+ break; |
|
293 |
+#endif |
|
294 |
+ } |
|
295 |
+ |
|
296 |
+ if(len <=0) { |
|
297 |
+ *printok = 0; |
|
298 |
+ if(errors) |
|
299 |
+ (*errors)++; |
|
300 |
+ return len; |
|
301 |
+ } |
|
302 |
+ |
|
303 |
+ while((len = recvln(&rcv, &bol, &eol))) { |
|
304 |
+ if(len == -1) return -1; |
|
305 |
+ beenthere = 1; |
|
306 |
+ if(!filename) logg("~%s\n", bol); |
|
307 |
+ if(len > 7) { |
|
308 |
+ char *colon = strrchr(bol, ':'); |
|
309 |
+ if(colon && colon[1] != ' ') { |
|
310 |
+ char *br; |
|
311 |
+ *colon = 0; |
|
312 |
+ br = strrchr(bol, '('); |
|
313 |
+ if(br) |
|
314 |
+ *br = 0; |
|
315 |
+ colon = strrchr(bol, ':'); |
|
316 |
+ } |
|
317 |
+ if(!colon) { |
|
318 |
+ char * unkco = "UNKNOWN COMMAND"; |
|
319 |
+ if (!strncmp(bol, unkco, sizeof(unkco) - 1)) |
|
320 |
+ logg("clamd replied \"UNKNOWN COMMAND\". Command was %s\n", |
|
321 |
+ (scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" : |
|
322 |
+ scancmd[scantype]); |
|
323 |
+ else |
|
324 |
+ logg("Failed to parse reply: \"%s\"\n", bol); |
|
325 |
+ return -1; |
|
326 |
+ } else if(!memcmp(eol - 7, " FOUND", 6)) { |
|
327 |
+ static char last_filename[PATH_MAX+1] = {'\0'}; |
|
328 |
+ *(eol - 7) = 0; |
|
329 |
+ *printok = 0; |
|
330 |
+ if (scantype != ALLMATCH) { |
|
331 |
+ infected++; |
|
332 |
+ } else { |
|
333 |
+ if (filename != NULL && strcmp(filename, last_filename)) { |
|
334 |
+ infected++; |
|
335 |
+ strncpy(last_filename, filename, PATH_MAX); |
|
336 |
+ last_filename[PATH_MAX] = '\0'; |
|
337 |
+ } |
|
338 |
+ } |
|
339 |
+ if(filename) { |
|
340 |
+ if(scantype >= STREAM) { |
|
341 |
+ logg("~%s%s FOUND\n", filename, colon); |
|
342 |
+ if(action) action(filename); |
|
343 |
+ } else { |
|
344 |
+ logg("~%s FOUND\n", bol); |
|
345 |
+ *colon = '\0'; |
|
346 |
+ if(action) |
|
347 |
+ action(bol); |
|
348 |
+ } |
|
349 |
+ } |
|
350 |
+ } else if(!memcmp(eol-7, " ERROR", 6)) { |
|
351 |
+ if(errors) |
|
352 |
+ (*errors)++; |
|
353 |
+ *printok = 0; |
|
354 |
+ if(filename) { |
|
355 |
+ if(scantype >= STREAM) |
|
356 |
+ logg("~%s%s\n", filename, colon); |
|
357 |
+ else |
|
358 |
+ logg("~%s\n", bol); |
|
359 |
+ } |
|
360 |
+ } |
|
361 |
+ } |
|
362 |
+ } |
|
363 |
+ if(!beenthere) { |
|
364 |
+ if (!filename) { |
|
365 |
+ logg("STDIN: noreply from clamd\n."); |
|
366 |
+ return -1; |
|
367 |
+ } |
|
368 |
+ if(CLAMSTAT(filename, &sb) == -1) { |
|
369 |
+ logg("~%s: stat() failed with %s, clamd may not be responding\n", |
|
370 |
+ filename, strerror(errno)); |
|
371 |
+ return -1; |
|
372 |
+ } |
|
373 |
+ if(!S_ISDIR(sb.st_mode)) { |
|
374 |
+ logg("~%s: no reply from clamd\n", filename); |
|
375 |
+ return -1; |
|
376 |
+ } |
|
377 |
+ } |
|
378 |
+ return infected; |
|
379 |
+} |
|
380 |
+ |
|
381 |
+/* Used by serial_callback() */ |
|
382 |
+struct client_serial_data { |
|
383 |
+ int infected; |
|
384 |
+ int scantype; |
|
385 |
+ int printok; |
|
386 |
+ int files; |
|
387 |
+ int errors; |
|
388 |
+}; |
|
389 |
+ |
|
390 |
+/* FTW callback for scanning in non IDSESSION mode |
|
391 |
+ * Returns SUCCESS or BREAK on success, CL_EXXX on error */ |
|
392 |
+static int serial_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) { |
|
393 |
+ struct client_serial_data *c = (struct client_serial_data *)data->data; |
|
394 |
+ int sockd, ret; |
|
395 |
+ const char *f = filename; |
|
396 |
+ |
|
397 |
+ UNUSEDPARAM(sb); |
|
398 |
+ |
|
399 |
+ if(chkpath(path)) |
|
400 |
+ return CL_SUCCESS; |
|
401 |
+ c->files++; |
|
402 |
+ switch(reason) { |
|
403 |
+ case error_stat: |
|
404 |
+ logg("!Can't access file %s\n", path); |
|
405 |
+ c->errors++; |
|
406 |
+ return CL_SUCCESS; |
|
407 |
+ case error_mem: |
|
408 |
+ logg("!Memory allocation failed in ftw\n"); |
|
409 |
+ c->errors++; |
|
410 |
+ return CL_EMEM; |
|
411 |
+ case warning_skipped_dir: |
|
412 |
+ logg("^Directory recursion limit reached\n"); |
|
413 |
+ case warning_skipped_link: |
|
414 |
+ return CL_SUCCESS; |
|
415 |
+ case warning_skipped_special: |
|
416 |
+ logg("^%s: Not supported file type\n", path); |
|
417 |
+ c->errors++; |
|
418 |
+ return CL_SUCCESS; |
|
419 |
+ case visit_directory_toplev: |
|
420 |
+ if(c->scantype >= STREAM) |
|
421 |
+ return CL_SUCCESS; |
|
422 |
+ f = path; |
|
423 |
+ filename = NULL; |
|
424 |
+ case visit_file: |
|
425 |
+ break; |
|
426 |
+ } |
|
427 |
+ |
|
428 |
+ if((sockd = dconnect()) < 0) { |
|
429 |
+ if(filename) free(filename); |
|
430 |
+ c->errors++; |
|
431 |
+ return CL_EOPEN; |
|
432 |
+ } |
|
433 |
+ ret = dsresult(sockd, c->scantype, f, &c->printok, &c->errors); |
|
434 |
+ if(filename) free(filename); |
|
435 |
+ closesocket(sockd); |
|
436 |
+ if(ret < 0) { |
|
437 |
+ c->errors++; |
|
438 |
+ return CL_EOPEN; |
|
439 |
+ } |
|
440 |
+ c->infected += ret; |
|
441 |
+ if(reason == visit_directory_toplev) |
|
442 |
+ return CL_BREAK; |
|
443 |
+ return CL_SUCCESS; |
|
444 |
+} |
|
445 |
+ |
|
446 |
+/* Non-IDSESSION handler |
|
447 |
+ * Returns non zero for serious errors, zero otherwise */ |
|
448 |
+int serial_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags) { |
|
449 |
+ struct cli_ftw_cbdata data; |
|
450 |
+ struct client_serial_data cdata; |
|
451 |
+ int ftw; |
|
452 |
+ |
|
453 |
+ cdata.infected = 0; |
|
454 |
+ cdata.files = 0; |
|
455 |
+ cdata.errors = 0; |
|
456 |
+ cdata.printok = printinfected^1; |
|
457 |
+ cdata.scantype = scantype; |
|
458 |
+ data.data = &cdata; |
|
459 |
+ |
|
460 |
+ ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, serial_callback, &data, ftw_chkpath); |
|
461 |
+ *infected += cdata.infected; |
|
462 |
+ *err += cdata.errors; |
|
463 |
+ |
|
464 |
+ if(!cdata.errors && (ftw == CL_SUCCESS || ftw == CL_BREAK)) { |
|
465 |
+ if(cdata.printok) |
|
466 |
+ logg("~%s: OK\n", file); |
|
467 |
+ return 0; |
|
468 |
+ } else if(!cdata.files) { |
|
469 |
+ logg("~%s: No files scanned\n", file); |
|
470 |
+ return 0; |
|
471 |
+ } |
|
472 |
+ return 1; |
|
473 |
+} |
|
474 |
+ |
|
475 |
+/* Used in IDSESSION mode */ |
|
476 |
+struct client_parallel_data { |
|
477 |
+ int infected; |
|
478 |
+ int files; |
|
479 |
+ int errors; |
|
480 |
+ int scantype; |
|
481 |
+ int sockd; |
|
482 |
+ int lastid; |
|
483 |
+ int printok; |
|
484 |
+ struct SCANID { |
|
485 |
+ unsigned int id; |
|
486 |
+ const char *file; |
|
487 |
+ struct SCANID *next; |
|
488 |
+ } *ids; |
|
489 |
+}; |
|
490 |
+ |
|
491 |
+/* Sends a proper scan request to clamd and parses its replies |
|
492 |
+ * This is used only in IDSESSION mode |
|
493 |
+ * Returns 0 on success, 1 on hard failures, 2 on len == 0 (bb#1717) */ |
|
494 |
+static int dspresult(struct client_parallel_data *c) { |
|
495 |
+ const char *filename; |
|
496 |
+ char *bol, *eol; |
|
497 |
+ unsigned int rid; |
|
498 |
+ int len; |
|
499 |
+ struct SCANID **id = NULL; |
|
500 |
+ struct RCVLN rcv; |
|
501 |
+ |
|
502 |
+ recvlninit(&rcv, c->sockd); |
|
503 |
+ do { |
|
504 |
+ len = recvln(&rcv, &bol, &eol); |
|
505 |
+ if(len < 0) return 1; |
|
506 |
+ if(!len) return 2; |
|
507 |
+ if((rid = atoi(bol))) { |
|
508 |
+ id = &c->ids; |
|
509 |
+ while(*id) { |
|
510 |
+ if((*id)->id == rid) break; |
|
511 |
+ id = &((*id)->next); |
|
512 |
+ } |
|
513 |
+ if(!*id) id = NULL; |
|
514 |
+ } |
|
515 |
+ if(!id) { |
|
516 |
+ logg("!Bogus session id from clamd\n"); |
|
517 |
+ return 1; |
|
518 |
+ } |
|
519 |
+ filename = (*id)->file; |
|
520 |
+ if(len > 7) { |
|
521 |
+ char *colon = strrchr(bol, ':'); |
|
522 |
+ if(!colon) { |
|
523 |
+ logg("!Failed to parse reply\n"); |
|
524 |
+ free((void *)filename); |
|
525 |
+ return 1; |
|
526 |
+ } else if(!memcmp(eol - 7, " FOUND", 6)) { |
|
527 |
+ c->infected++; |
|
528 |
+ c->printok = 0; |
|
529 |
+ logg("~%s%s\n", filename, colon); |
|
530 |
+ if(action) action(filename); |
|
531 |
+ } else if(!memcmp(eol-7, " ERROR", 6)) { |
|
532 |
+ c->errors++; |
|
533 |
+ c->printok = 0; |
|
534 |
+ logg("~%s%s\n", filename, colon); |
|
535 |
+ } |
|
536 |
+ } |
|
537 |
+ free((void *)filename); |
|
538 |
+ bol = (char *)*id; |
|
539 |
+ *id = (*id)->next; |
|
540 |
+ free(bol); |
|
541 |
+ } while(rcv.cur != rcv.buf); /* clamd sends whole lines, so, on partial lines, we just assume |
|
542 |
+ more data can be recv()'d with close to zero latency */ |
|
543 |
+ return 0; |
|
544 |
+} |
|
545 |
+ |
|
546 |
+/* FTW callback for scanning in IDSESSION mode |
|
547 |
+ * Returns SUCCESS on success, CL_EXXX or BREAK on error */ |
|
548 |
+static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) { |
|
549 |
+ struct client_parallel_data *c = (struct client_parallel_data *)data->data; |
|
550 |
+ struct SCANID *cid; |
|
551 |
+ int res = CL_CLEAN; |
|
552 |
+ |
|
553 |
+ UNUSEDPARAM(sb); |
|
554 |
+ |
|
555 |
+ if(chkpath(path)) |
|
556 |
+ return CL_SUCCESS; |
|
557 |
+ c->files++; |
|
558 |
+ switch(reason) { |
|
559 |
+ case error_stat: |
|
560 |
+ logg("!Can't access file %s\n", path); |
|
561 |
+ c->errors++; |
|
562 |
+ return CL_SUCCESS; |
|
563 |
+ case error_mem: |
|
564 |
+ logg("!Memory allocation failed in ftw\n"); |
|
565 |
+ c->errors++; |
|
566 |
+ return CL_EMEM; |
|
567 |
+ case warning_skipped_dir: |
|
568 |
+ logg("^Directory recursion limit reached\n"); |
|
569 |
+ return CL_SUCCESS; |
|
570 |
+ case warning_skipped_special: |
|
571 |
+ logg("^%s: Not supported file type\n", path); |
|
572 |
+ c->errors++; |
|
573 |
+ case warning_skipped_link: |
|
574 |
+ case visit_directory_toplev: |
|
575 |
+ return CL_SUCCESS; |
|
576 |
+ case visit_file: |
|
577 |
+ break; |
|
578 |
+ } |
|
579 |
+ |
|
580 |
+ while(1) { |
|
581 |
+ /* consume all the available input to let some of the clamd |
|
582 |
+ * threads blocked on send() to be dead. |
|
583 |
+ * by doing so we shouldn't deadlock on the next recv() */ |
|
584 |
+ fd_set rfds, wfds; |
|
585 |
+ FD_ZERO(&rfds); |
|
586 |
+ FD_SET(c->sockd, &rfds); |
|
587 |
+ FD_ZERO(&wfds); |
|
588 |
+ FD_SET(c->sockd, &wfds); |
|
589 |
+ if(select(c->sockd + 1, &rfds, &wfds, NULL, NULL) < 0) { |
|
590 |
+ if(errno == EINTR) continue; |
|
591 |
+ free(filename); |
|
592 |
+ logg("!select() failed during session: %s\n", strerror(errno)); |
|
593 |
+ return CL_BREAK; |
|
594 |
+ } |
|
595 |
+ if(FD_ISSET(c->sockd, &rfds)) { |
|
596 |
+ if(dspresult(c)) { |
|
597 |
+ free(filename); |
|
598 |
+ return CL_BREAK; |
|
599 |
+ } else continue; |
|
600 |
+ } |
|
601 |
+ if(FD_ISSET(c->sockd, &wfds)) break; |
|
602 |
+ } |
|
603 |
+ |
|
604 |
+ cid = (struct SCANID *)malloc(sizeof(struct SCANID)); |
|
605 |
+ if(!cid) { |
|
606 |
+ free(filename); |
|
607 |
+ logg("!Failed to allocate scanid entry: %s\n", strerror(errno)); |
|
608 |
+ return CL_BREAK; |
|
609 |
+ } |
|
610 |
+ cid->id = ++c->lastid; |
|
611 |
+ cid->file = filename; |
|
612 |
+ cid->next = c->ids; |
|
613 |
+ c->ids = cid; |
|
614 |
+ |
|
615 |
+ switch(c->scantype) { |
|
616 |
+#ifdef HAVE_FD_PASSING |
|
617 |
+ case FILDES: |
|
618 |
+ res = send_fdpass(c->sockd, filename); |
|
619 |
+ break; |
|
620 |
+#endif |
|
621 |
+ case STREAM: |
|
622 |
+ res = send_stream(c->sockd, filename); |
|
623 |
+ break; |
|
624 |
+ } |
|
625 |
+ if(res <= 0) { |
|
626 |
+ c->printok = 0; |
|
627 |
+ c->errors++; |
|
628 |
+ c->ids = cid->next; |
|
629 |
+ c->lastid--; |
|
630 |
+ free(cid); |
|
631 |
+ free(filename); |
|
632 |
+ return res ? CL_BREAK : CL_SUCCESS; |
|
633 |
+ } |
|
634 |
+ return CL_SUCCESS; |
|
635 |
+} |
|
636 |
+ |
|
637 |
+/* IDSESSION handler |
|
638 |
+ * Returns non zero for serious errors, zero otherwise */ |
|
639 |
+int parallel_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags) { |
|
640 |
+ struct cli_ftw_cbdata data; |
|
641 |
+ struct client_parallel_data cdata; |
|
642 |
+ int ftw; |
|
643 |
+ |
|
644 |
+ if((cdata.sockd = dconnect()) < 0) |
|
645 |
+ return 1; |
|
646 |
+ |
|
647 |
+ if(sendln(cdata.sockd, "zIDSESSION", 11)) { |
|
648 |
+ closesocket(cdata.sockd); |
|
649 |
+ return 1; |
|
650 |
+ } |
|
651 |
+ |
|
652 |
+ cdata.infected = 0; |
|
653 |
+ cdata.files = 0; |
|
654 |
+ cdata.errors = 0; |
|
655 |
+ cdata.scantype = scantype; |
|
656 |
+ cdata.lastid = 0; |
|
657 |
+ cdata.ids = NULL; |
|
658 |
+ cdata.printok = printinfected^1; |
|
659 |
+ data.data = &cdata; |
|
660 |
+ |
|
661 |
+ ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, parallel_callback, &data, ftw_chkpath); |
|
662 |
+ |
|
663 |
+ if(ftw != CL_SUCCESS) { |
|
664 |
+ *err += cdata.errors; |
|
665 |
+ *infected += cdata.infected; |
|
666 |
+ closesocket(cdata.sockd); |
|
667 |
+ return 1; |
|
668 |
+ } |
|
669 |
+ |
|
670 |
+ sendln(cdata.sockd, "zEND", 5); |
|
671 |
+ while(cdata.ids && !dspresult(&cdata)); |
|
672 |
+ closesocket(cdata.sockd); |
|
673 |
+ |
|
674 |
+ *infected += cdata.infected; |
|
675 |
+ *err += cdata.errors; |
|
676 |
+ |
|
677 |
+ if(cdata.ids) { |
|
678 |
+ logg("!Clamd closed the connection before scanning all files.\n"); |
|
679 |
+ return 1; |
|
680 |
+ } |
|
681 |
+ if(cdata.errors) |
|
682 |
+ return 1; |
|
683 |
+ |
|
684 |
+ if(!cdata.files) |
|
685 |
+ return 0; |
|
686 |
+ |
|
687 |
+ if(cdata.printok) |
|
688 |
+ logg("~%s: OK\n", file); |
|
689 |
+ return 0; |
|
690 |
+} |
0 | 691 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,30 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2009 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm, aCaB |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#ifndef ONAS_PROTO_H |
|
22 |
+#define ONAS_PROTO_H |
|
23 |
+#include "shared/misc.h" |
|
24 |
+ |
|
25 |
+int dconnect(void); |
|
26 |
+int serial_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags); |
|
27 |
+int parallel_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags); |
|
28 |
+int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors); |
|
29 |
+#endif |
0 | 30 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,306 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2011-2013 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm, Mickey Sola |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#if HAVE_CONFIG_H |
|
22 |
+#include "clamav-config.h" |
|
23 |
+#endif |
|
24 |
+ |
|
25 |
+#if defined(FANOTIFY) |
|
26 |
+ |
|
27 |
+#include <stdio.h> |
|
28 |
+#include <unistd.h> |
|
29 |
+#include <sys/types.h> |
|
30 |
+#include <sys/stat.h> |
|
31 |
+#include <fcntl.h> |
|
32 |
+#include <signal.h> |
|
33 |
+#include <pthread.h> |
|
34 |
+#include <string.h> |
|
35 |
+#include <errno.h> |
|
36 |
+#include <time.h> |
|
37 |
+ |
|
38 |
+#include <sys/fanotify.h> |
|
39 |
+ |
|
40 |
+#include "libclamav/clamav.h" |
|
41 |
+#include "libclamav/scanners.h" |
|
42 |
+ |
|
43 |
+#include "shared/optparser.h" |
|
44 |
+#include "shared/output.h" |
|
45 |
+ |
|
46 |
+#include "../misc/onaccess_others.h" |
|
47 |
+#include "clamd/server.h" |
|
48 |
+ |
|
49 |
+#include "onaccess_fan.h" |
|
50 |
+#include "../inotif/onaccess_hash.h" |
|
51 |
+#include "../inotif/onaccess_ddd.h" |
|
52 |
+ |
|
53 |
+static pthread_t ddd_pid; |
|
54 |
+static int onas_fan_fd; |
|
55 |
+ |
|
56 |
+static void onas_fan_exit(int sig) |
|
57 |
+{ |
|
58 |
+ logg("*ScanOnAccess: onas_fan_exit(), signal %d\n", sig); |
|
59 |
+ |
|
60 |
+ close(onas_fan_fd); |
|
61 |
+ |
|
62 |
+ if (ddd_pid > 0) { |
|
63 |
+ pthread_kill(ddd_pid, SIGUSR1); |
|
64 |
+ pthread_join(ddd_pid, NULL); |
|
65 |
+ } |
|
66 |
+ |
|
67 |
+ pthread_exit(NULL); |
|
68 |
+ logg("ScanOnAccess: stopped\n"); |
|
69 |
+} |
|
70 |
+ |
|
71 |
+static int onas_fan_scanfile(int fan_fd, const char *fname, struct fanotify_event_metadata *fmd, int scan, int extinfo, struct thrarg *tharg) |
|
72 |
+{ |
|
73 |
+ struct fanotify_response res; |
|
74 |
+ const char *virname = NULL; |
|
75 |
+ int ret = 0; |
|
76 |
+ |
|
77 |
+ res.fd = fmd->fd; |
|
78 |
+ res.response = FAN_ALLOW; |
|
79 |
+ |
|
80 |
+ if (scan) { |
|
81 |
+ if (onas_scan(fname, fmd->fd, &virname, tharg->engine, tharg->options, extinfo) == CL_VIRUS) { |
|
82 |
+ /* TODO : FIXME? virusaction forks. This could be extraordinarily problematic, lead to deadlocks, |
|
83 |
+ * or at the very least lead to extreme memory consumption. Leaving disabled for now.*/ |
|
84 |
+ //virusaction(fname, virname, tharg->opts); |
|
85 |
+ res.response = FAN_DENY; |
|
86 |
+ } |
|
87 |
+ } |
|
88 |
+ |
|
89 |
+ if (fmd->mask & FAN_ALL_PERM_EVENTS) { |
|
90 |
+ ret = write(fan_fd, &res, sizeof(res)); |
|
91 |
+ if (ret == -1) |
|
92 |
+ logg("!ScanOnAccess: Internal error (can't write to fanotify)\n"); |
|
93 |
+ } |
|
94 |
+ |
|
95 |
+ return ret; |
|
96 |
+} |
|
97 |
+ |
|
98 |
+void *onas_fan_th(void *arg) |
|
99 |
+{ |
|
100 |
+ struct thrarg *tharg = (struct thrarg *)arg; |
|
101 |
+ sigset_t sigset; |
|
102 |
+ struct sigaction act; |
|
103 |
+ const struct optstruct *pt; |
|
104 |
+ short int scan; |
|
105 |
+ unsigned int sizelimit = 0, extinfo; |
|
106 |
+ STATBUF sb; |
|
107 |
+ uint64_t fan_mask = FAN_EVENT_ON_CHILD | FAN_CLOSE; |
|
108 |
+ fd_set rfds; |
|
109 |
+ char buf[4096]; |
|
110 |
+ ssize_t bread; |
|
111 |
+ struct fanotify_event_metadata *fmd; |
|
112 |
+ char fname[1024]; |
|
113 |
+ int ret, len, check; |
|
114 |
+ char err[128]; |
|
115 |
+ |
|
116 |
+ pthread_attr_t ddd_attr; |
|
117 |
+ struct ddd_thrarg *ddd_tharg = NULL; |
|
118 |
+ |
|
119 |
+ ddd_pid = 0; |
|
120 |
+ |
|
121 |
+ /* ignore all signals except SIGUSR1 */ |
|
122 |
+ sigfillset(&sigset); |
|
123 |
+ sigdelset(&sigset, SIGUSR1); |
|
124 |
+ /* The behavior of a process is undefined after it ignores a |
|
125 |
+ * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
126 |
+ sigdelset(&sigset, SIGFPE); |
|
127 |
+ sigdelset(&sigset, SIGILL); |
|
128 |
+ sigdelset(&sigset, SIGSEGV); |
|
129 |
+#ifdef SIGBUS |
|
130 |
+ sigdelset(&sigset, SIGBUS); |
|
131 |
+#endif |
|
132 |
+ pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
133 |
+ memset(&act, 0, sizeof(struct sigaction)); |
|
134 |
+ act.sa_handler = onas_fan_exit; |
|
135 |
+ sigfillset(&(act.sa_mask)); |
|
136 |
+ sigaction(SIGUSR1, &act, NULL); |
|
137 |
+ sigaction(SIGSEGV, &act, NULL); |
|
138 |
+ |
|
139 |
+ /* Initialize fanotify */ |
|
140 |
+ onas_fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY); |
|
141 |
+ if (onas_fan_fd < 0) { |
|
142 |
+ logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
143 |
+ if (errno == EPERM) |
|
144 |
+ logg("ScanOnAccess: clamd must be started by root\n"); |
|
145 |
+ return NULL; |
|
146 |
+ } |
|
147 |
+ |
|
148 |
+ if (!tharg) { |
|
149 |
+ logg("!Unable to start on-access scanner. Bad thread args.\n"); |
|
150 |
+ return NULL; |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ if (optget(tharg->opts, "OnAccessPrevention")->enabled && !optget(tharg->opts, "OnAccessMountPath")->enabled) { |
|
154 |
+ logg("ScanOnAccess: preventing access attempts on malicious files.\n"); |
|
155 |
+ fan_mask |= FAN_ACCESS_PERM | FAN_OPEN_PERM; |
|
156 |
+ } else { |
|
157 |
+ logg("ScanOnAccess: notifying only for access attempts.\n"); |
|
158 |
+ fan_mask |= FAN_ACCESS | FAN_OPEN; |
|
159 |
+ } |
|
160 |
+ |
|
161 |
+ if ((pt = optget(tharg->opts, "OnAccessMountPath"))->enabled) { |
|
162 |
+ while (pt) { |
|
163 |
+ if (fanotify_mark(onas_fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, fan_mask, onas_fan_fd, pt->strarg) != 0) { |
|
164 |
+ logg("!ScanOnAccess: Can't include mountpoint '%s'\n", pt->strarg); |
|
165 |
+ return NULL; |
|
166 |
+ } else |
|
167 |
+ logg("ScanOnAccess: Protecting '%s' and rest of mount.\n", pt->strarg); |
|
168 |
+ pt = (struct optstruct *)pt->nextarg; |
|
169 |
+ } |
|
170 |
+ |
|
171 |
+ } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) { |
|
172 |
+ int thread_started = 1; |
|
173 |
+ do { |
|
174 |
+ if (pthread_attr_init(&ddd_attr)) break; |
|
175 |
+ pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE); |
|
176 |
+ |
|
177 |
+ /* Allocate memory for arguments. Thread is responsible for freeing it. */ |
|
178 |
+ if (!(ddd_tharg = (struct ddd_thrarg *)calloc(sizeof(struct ddd_thrarg), 1))) break; |
|
179 |
+ if (!(ddd_tharg->options = (struct cl_scan_options *)calloc(sizeof(struct cl_scan_options), 1))) break; |
|
180 |
+ |
|
181 |
+ (void)memcpy(ddd_tharg->options, tharg->options, sizeof(struct cl_scan_options)); |
|
182 |
+ ddd_tharg->fan_fd = onas_fan_fd; |
|
183 |
+ ddd_tharg->fan_mask = fan_mask; |
|
184 |
+ ddd_tharg->opts = tharg->opts; |
|
185 |
+ ddd_tharg->engine = tharg->engine; |
|
186 |
+ |
|
187 |
+ thread_started = pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg); |
|
188 |
+ } while (0); |
|
189 |
+ |
|
190 |
+ if (0 != thread_started) { |
|
191 |
+ /* Failed to create thread. Free anything we may have allocated. */ |
|
192 |
+ logg("!Unable to start dynamic directory determination.\n"); |
|
193 |
+ if (NULL != ddd_tharg) { |
|
194 |
+ if (NULL != ddd_tharg->options) { |
|
195 |
+ free(ddd_tharg->options); |
|
196 |
+ ddd_tharg->options = NULL; |
|
197 |
+ } |
|
198 |
+ free(ddd_tharg); |
|
199 |
+ ddd_tharg = NULL; |
|
200 |
+ } |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ } else { |
|
204 |
+ if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
205 |
+ while (pt) { |
|
206 |
+ if (fanotify_mark(onas_fan_fd, FAN_MARK_ADD, fan_mask, onas_fan_fd, pt->strarg) != 0) { |
|
207 |
+ logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); |
|
208 |
+ return NULL; |
|
209 |
+ } else |
|
210 |
+ logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg); |
|
211 |
+ pt = (struct optstruct *)pt->nextarg; |
|
212 |
+ } |
|
213 |
+ } else { |
|
214 |
+ logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); |
|
215 |
+ return NULL; |
|
216 |
+ } |
|
217 |
+ } |
|
218 |
+ |
|
219 |
+ /* Load other options. */ |
|
220 |
+ sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg; |
|
221 |
+ if (sizelimit) |
|
222 |
+ logg("ScanOnAccess: Max file size limited to %u bytes\n", sizelimit); |
|
223 |
+ else |
|
224 |
+ logg("ScanOnAccess: File size limit disabled\n"); |
|
225 |
+ |
|
226 |
+ extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
227 |
+ |
|
228 |
+ FD_ZERO(&rfds); |
|
229 |
+ FD_SET(onas_fan_fd, &rfds); |
|
230 |
+ do { |
|
231 |
+ if (reload) sleep(1); |
|
232 |
+ ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); |
|
233 |
+ } while ((ret == -1 && errno == EINTR) || reload); |
|
234 |
+ |
|
235 |
+ time_t start = time(NULL) - 30; |
|
236 |
+ while (((bread = read(onas_fan_fd, buf, sizeof(buf))) > 0) || errno == EOVERFLOW) { |
|
237 |
+ |
|
238 |
+ if (errno == EOVERFLOW) { |
|
239 |
+ if (time(NULL) - start >= 30) { |
|
240 |
+ logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); |
|
241 |
+ logg("!ScanOnAccess: File too large for fanotify ... recovering and continuing scans...\n"); |
|
242 |
+ start = time(NULL); |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ errno = 0; |
|
246 |
+ continue; |
|
247 |
+ } |
|
248 |
+ |
|
249 |
+ fmd = (struct fanotify_event_metadata *)buf; |
|
250 |
+ while (FAN_EVENT_OK(fmd, bread)) { |
|
251 |
+ scan = 1; |
|
252 |
+ if (fmd->fd >= 0) { |
|
253 |
+ sprintf(fname, "/proc/self/fd/%d", fmd->fd); |
|
254 |
+ len = readlink(fname, fname, sizeof(fname) - 1); |
|
255 |
+ if (len == -1) { |
|
256 |
+ close(fmd->fd); |
|
257 |
+ logg("!ScanOnAccess: Internal error (readlink() failed)\n"); |
|
258 |
+ return NULL; |
|
259 |
+ } |
|
260 |
+ fname[len] = 0; |
|
261 |
+ |
|
262 |
+ if ((check = onas_fan_checkowner(fmd->pid, tharg->opts))) { |
|
263 |
+ scan = 0; |
|
264 |
+/* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
265 |
+#if 0 |
|
266 |
+ if ((check != CHK_SELF) || !(optget(tharg->opts, "OnAccessExtraScanning")->enabled)) { |
|
267 |
+#else |
|
268 |
+ if (check != CHK_SELF) { |
|
269 |
+#endif |
|
270 |
+ logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname); |
|
271 |
+ } |
|
272 |
+ } |
|
273 |
+ |
|
274 |
+ if (sizelimit) { |
|
275 |
+ if (FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) { |
|
276 |
+ scan = 0; |
|
277 |
+ /* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */ |
|
278 |
+ } |
|
279 |
+ } |
|
280 |
+ |
|
281 |
+ if (onas_fan_scanfile(onas_fan_fd, fname, fmd, scan, extinfo, tharg) == -1) { |
|
282 |
+ close(fmd->fd); |
|
283 |
+ return NULL; |
|
284 |
+ } |
|
285 |
+ |
|
286 |
+ if (close(fmd->fd) == -1) { |
|
287 |
+ printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd); |
|
288 |
+ close(fmd->fd); |
|
289 |
+ return NULL; |
|
290 |
+ } |
|
291 |
+ } |
|
292 |
+ fmd = FAN_EVENT_NEXT(fmd, bread); |
|
293 |
+ } |
|
294 |
+ do { |
|
295 |
+ if (reload) sleep(1); |
|
296 |
+ ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); |
|
297 |
+ } while ((ret == -1 && errno == EINTR) || reload); |
|
298 |
+} |
|
299 |
+ |
|
300 |
+if (bread < 0) |
|
301 |
+ logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); |
|
302 |
+ |
|
303 |
+return NULL; |
|
304 |
+} |
|
305 |
+#endif |
0 | 306 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,27 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2011-2013 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Tomasz Kojm |
|
5 |
+ * |
|
6 |
+ * This program is free software; you can redistribute it and/or modify |
|
7 |
+ * it under the terms of the GNU General Public License version 2 as |
|
8 |
+ * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
+ * MA 02110-1301, USA. |
|
19 |
+ */ |
|
20 |
+ |
|
21 |
+#ifndef __FAN_H |
|
22 |
+#define __FAN_H |
|
23 |
+ |
|
24 |
+void *onas_fan_th(void *arg); |
|
25 |
+ |
|
26 |
+#endif |
0 | 27 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,609 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#if HAVE_CONFIG_H |
|
21 |
+#include "clamav-config.h" |
|
22 |
+#endif |
|
23 |
+ |
|
24 |
+#if defined(FANOTIFY) |
|
25 |
+ |
|
26 |
+#include <stdio.h> |
|
27 |
+#include <stdlib.h> |
|
28 |
+#include <unistd.h> |
|
29 |
+#include <sys/types.h> |
|
30 |
+#include <sys/stat.h> |
|
31 |
+#include <fcntl.h> |
|
32 |
+#include <signal.h> |
|
33 |
+#include <pthread.h> |
|
34 |
+#include <string.h> |
|
35 |
+#include <errno.h> |
|
36 |
+#include <stdbool.h> |
|
37 |
+ |
|
38 |
+#include <sys/fanotify.h> |
|
39 |
+#include <sys/inotify.h> |
|
40 |
+ |
|
41 |
+#include "../fanotif/onaccess_fan.h" |
|
42 |
+#include "onaccess_hash.h" |
|
43 |
+#include "onaccess_ddd.h" |
|
44 |
+#include "../scan/onaccess_scth.h" |
|
45 |
+ |
|
46 |
+#include "libclamav/clamav.h" |
|
47 |
+#include "libclamav/scanners.h" |
|
48 |
+ |
|
49 |
+#include "shared/optparser.h" |
|
50 |
+#include "shared/output.h" |
|
51 |
+ |
|
52 |
+#include "clamd/server.h" |
|
53 |
+#include "clamd/others.h" |
|
54 |
+#include "clamd/scanner.h" |
|
55 |
+ |
|
56 |
+static int onas_ddd_init_ht(uint32_t ht_size); |
|
57 |
+static int onas_ddd_init_wdlt(uint64_t nwatches); |
|
58 |
+static int onas_ddd_grow_wdlt(); |
|
59 |
+ |
|
60 |
+static int onas_ddd_watch(const char *pathname, int fan_fd, uint64_t fan_mask, int in_fd, uint64_t in_mask); |
|
61 |
+static int onas_ddd_watch_hierarchy(const char *pathname, size_t len, int fd, uint64_t mask, uint32_t type); |
|
62 |
+static int onas_ddd_unwatch(const char *pathname, int fan_fd, int in_fd); |
|
63 |
+static int onas_ddd_unwatch_hierarchy(const char *pathname, size_t len, int fd, uint32_t type); |
|
64 |
+ |
|
65 |
+static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask); |
|
66 |
+static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask); |
|
67 |
+static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); |
|
68 |
+static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); |
|
69 |
+static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options); |
|
70 |
+ |
|
71 |
+static void onas_ddd_exit(int sig); |
|
72 |
+ |
|
73 |
+/* TODO: Unglobalize these. */ |
|
74 |
+static struct onas_ht *ddd_ht; |
|
75 |
+static char **wdlt; |
|
76 |
+static uint32_t wdlt_len; |
|
77 |
+static int onas_in_fd; |
|
78 |
+ |
|
79 |
+static int onas_ddd_init_ht(uint32_t ht_size) |
|
80 |
+{ |
|
81 |
+ |
|
82 |
+ if (ht_size <= 0) |
|
83 |
+ ht_size = ONAS_DEFAULT_HT_SIZE; |
|
84 |
+ |
|
85 |
+ return onas_ht_init(&ddd_ht, ht_size); |
|
86 |
+} |
|
87 |
+ |
|
88 |
+static int onas_ddd_init_wdlt(uint64_t nwatches) |
|
89 |
+{ |
|
90 |
+ |
|
91 |
+ if (nwatches <= 0) return CL_EARG; |
|
92 |
+ |
|
93 |
+ wdlt = (char **)cli_calloc(nwatches << 1, sizeof(char *)); |
|
94 |
+ if (!wdlt) return CL_EMEM; |
|
95 |
+ |
|
96 |
+ wdlt_len = nwatches << 1; |
|
97 |
+ |
|
98 |
+ return CL_SUCCESS; |
|
99 |
+} |
|
100 |
+ |
|
101 |
+static int onas_ddd_grow_wdlt() |
|
102 |
+{ |
|
103 |
+ |
|
104 |
+ char **ptr = NULL; |
|
105 |
+ |
|
106 |
+ ptr = (char **)cli_realloc(wdlt, wdlt_len << 1); |
|
107 |
+ if (ptr) { |
|
108 |
+ wdlt = ptr; |
|
109 |
+ memset(&ptr[wdlt_len], 0, sizeof(char *) * (wdlt_len - 1)); |
|
110 |
+ } else { |
|
111 |
+ return CL_EMEM; |
|
112 |
+ } |
|
113 |
+ |
|
114 |
+ wdlt_len <<= 1; |
|
115 |
+ |
|
116 |
+ return CL_SUCCESS; |
|
117 |
+} |
|
118 |
+ |
|
119 |
+/* TODO: Support configuration for changing/setting number of inotify watches. */ |
|
120 |
+int onas_ddd_init(uint64_t nwatches, size_t ht_size) |
|
121 |
+{ |
|
122 |
+ |
|
123 |
+ const char *nwatch_file = "/proc/sys/fs/inotify/max_user_watches"; |
|
124 |
+ int nwfd = 0; |
|
125 |
+ int ret = 0; |
|
126 |
+ char nwatch_str[MAX_WATCH_LEN]; |
|
127 |
+ char *p = NULL; |
|
128 |
+ nwatches = 0; |
|
129 |
+ |
|
130 |
+ nwfd = open(nwatch_file, O_RDONLY); |
|
131 |
+ if (nwfd < 0) return CL_EOPEN; |
|
132 |
+ |
|
133 |
+ ret = read(nwfd, nwatch_str, MAX_WATCH_LEN); |
|
134 |
+ close(nwfd); |
|
135 |
+ if (ret < 0) return CL_EREAD; |
|
136 |
+ |
|
137 |
+ nwatches = strtol(nwatch_str, &p, 10); |
|
138 |
+ |
|
139 |
+ ret = onas_ddd_init_wdlt(nwatches); |
|
140 |
+ if (ret) return ret; |
|
141 |
+ |
|
142 |
+ ret = onas_ddd_init_ht(ht_size); |
|
143 |
+ if (ret) return ret; |
|
144 |
+ |
|
145 |
+ return CL_SUCCESS; |
|
146 |
+} |
|
147 |
+ |
|
148 |
+static int onas_ddd_watch(const char *pathname, int fan_fd, uint64_t fan_mask, int in_fd, uint64_t in_mask) |
|
149 |
+{ |
|
150 |
+ if (!pathname || fan_fd <= 0 || in_fd <= 0) return CL_ENULLARG; |
|
151 |
+ |
|
152 |
+ int ret = CL_SUCCESS; |
|
153 |
+ size_t len = strlen(pathname); |
|
154 |
+ |
|
155 |
+ ret = onas_ddd_watch_hierarchy(pathname, len, in_fd, in_mask, ONAS_IN); |
|
156 |
+ if (ret) return ret; |
|
157 |
+ |
|
158 |
+ ret = onas_ddd_watch_hierarchy(pathname, len, fan_fd, fan_mask, ONAS_FAN); |
|
159 |
+ if (ret) return ret; |
|
160 |
+ |
|
161 |
+ return CL_SUCCESS; |
|
162 |
+} |
|
163 |
+ |
|
164 |
+static int onas_ddd_watch_hierarchy(const char *pathname, size_t len, int fd, uint64_t mask, uint32_t type) |
|
165 |
+{ |
|
166 |
+ |
|
167 |
+ if (!pathname || fd <= 0 || !type) return CL_ENULLARG; |
|
168 |
+ |
|
169 |
+ if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG; |
|
170 |
+ |
|
171 |
+ struct onas_hnode *hnode = NULL; |
|
172 |
+ struct onas_element *elem = NULL; |
|
173 |
+ int wd = 0; |
|
174 |
+ |
|
175 |
+ if (onas_ht_get(ddd_ht, pathname, len, &elem) != CL_SUCCESS) return CL_EARG; |
|
176 |
+ |
|
177 |
+ hnode = elem->data; |
|
178 |
+ |
|
179 |
+ if (type & ONAS_IN) { |
|
180 |
+ wd = inotify_add_watch(fd, pathname, (uint32_t)mask); |
|
181 |
+ |
|
182 |
+ if (wd < 0) return CL_EARG; |
|
183 |
+ |
|
184 |
+ if ((uint32_t)wd >= wdlt_len) { |
|
185 |
+ onas_ddd_grow_wdlt(); |
|
186 |
+ } |
|
187 |
+ |
|
188 |
+ /* Link the hash node to the watch descriptor lookup table */ |
|
189 |
+ hnode->wd = wd; |
|
190 |
+ wdlt[wd] = hnode->pathname; |
|
191 |
+ |
|
192 |
+ hnode->watched |= ONAS_INWATCH; |
|
193 |
+ } else if (type & ONAS_FAN) { |
|
194 |
+ if (fanotify_mark(fd, FAN_MARK_ADD, mask, AT_FDCWD, hnode->pathname) < 0) return CL_EARG; |
|
195 |
+ hnode->watched |= ONAS_FANWATCH; |
|
196 |
+ } else { |
|
197 |
+ return CL_EARG; |
|
198 |
+ } |
|
199 |
+ |
|
200 |
+ struct onas_lnode *curr = hnode->childhead; |
|
201 |
+ |
|
202 |
+ while (curr->next != hnode->childtail) { |
|
203 |
+ curr = curr->next; |
|
204 |
+ |
|
205 |
+ size_t size = len + strlen(curr->dirname) + 2; |
|
206 |
+ char *child_path = (char *)cli_malloc(size); |
|
207 |
+ if (child_path == NULL) |
|
208 |
+ return CL_EMEM; |
|
209 |
+ if (hnode->pathname[len - 1] == '/') |
|
210 |
+ snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname); |
|
211 |
+ else |
|
212 |
+ snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
213 |
+ |
|
214 |
+ if (onas_ddd_watch_hierarchy(child_path, strlen(child_path), fd, mask, type)) { |
|
215 |
+ return CL_EARG; |
|
216 |
+ } |
|
217 |
+ free(child_path); |
|
218 |
+ } |
|
219 |
+ |
|
220 |
+ return CL_SUCCESS; |
|
221 |
+} |
|
222 |
+ |
|
223 |
+static int onas_ddd_unwatch(const char *pathname, int fan_fd, int in_fd) |
|
224 |
+{ |
|
225 |
+ if (!pathname || fan_fd <= 0 || in_fd <= 0) return CL_ENULLARG; |
|
226 |
+ |
|
227 |
+ int ret = CL_SUCCESS; |
|
228 |
+ size_t len = strlen(pathname); |
|
229 |
+ |
|
230 |
+ ret = onas_ddd_unwatch_hierarchy(pathname, len, in_fd, ONAS_IN); |
|
231 |
+ if (ret) return ret; |
|
232 |
+ |
|
233 |
+ ret = onas_ddd_unwatch_hierarchy(pathname, len, fan_fd, ONAS_FAN); |
|
234 |
+ if (ret) return ret; |
|
235 |
+ |
|
236 |
+ return CL_SUCCESS; |
|
237 |
+} |
|
238 |
+ |
|
239 |
+static int onas_ddd_unwatch_hierarchy(const char *pathname, size_t len, int fd, uint32_t type) |
|
240 |
+{ |
|
241 |
+ |
|
242 |
+ if (!pathname || fd <= 0 || !type) return CL_ENULLARG; |
|
243 |
+ |
|
244 |
+ if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG; |
|
245 |
+ |
|
246 |
+ struct onas_hnode *hnode = NULL; |
|
247 |
+ struct onas_element *elem = NULL; |
|
248 |
+ int wd = 0; |
|
249 |
+ |
|
250 |
+ if (onas_ht_get(ddd_ht, pathname, len, &elem)) return CL_EARG; |
|
251 |
+ |
|
252 |
+ hnode = elem->data; |
|
253 |
+ |
|
254 |
+ if (type & ONAS_IN) { |
|
255 |
+ wd = hnode->wd; |
|
256 |
+ |
|
257 |
+ if (!inotify_rm_watch(fd, wd)) return CL_EARG; |
|
258 |
+ |
|
259 |
+ /* Unlink the hash node from the watch descriptor lookup table */ |
|
260 |
+ hnode->wd = 0; |
|
261 |
+ wdlt[wd] = NULL; |
|
262 |
+ |
|
263 |
+ hnode->watched = ONAS_STOPWATCH; |
|
264 |
+ } else if (type & ONAS_FAN) { |
|
265 |
+ if (fanotify_mark(fd, FAN_MARK_REMOVE, 0, AT_FDCWD, hnode->pathname) < 0) return CL_EARG; |
|
266 |
+ hnode->watched = ONAS_STOPWATCH; |
|
267 |
+ } else { |
|
268 |
+ return CL_EARG; |
|
269 |
+ } |
|
270 |
+ |
|
271 |
+ struct onas_lnode *curr = hnode->childhead; |
|
272 |
+ |
|
273 |
+ while (curr->next != hnode->childtail) { |
|
274 |
+ curr = curr->next; |
|
275 |
+ |
|
276 |
+ size_t size = len + strlen(curr->dirname) + 2; |
|
277 |
+ char *child_path = (char *)cli_malloc(size); |
|
278 |
+ if (child_path == NULL) |
|
279 |
+ return CL_EMEM; |
|
280 |
+ if (hnode->pathname[len - 1] == '/') |
|
281 |
+ snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname); |
|
282 |
+ else |
|
283 |
+ snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
284 |
+ |
|
285 |
+ onas_ddd_unwatch_hierarchy(child_path, strlen(child_path), fd, type); |
|
286 |
+ free(child_path); |
|
287 |
+ } |
|
288 |
+ |
|
289 |
+ return CL_SUCCESS; |
|
290 |
+} |
|
291 |
+ |
|
292 |
+void *onas_ddd_th(void *arg) |
|
293 |
+{ |
|
294 |
+ struct ddd_thrarg *tharg = (struct ddd_thrarg *)arg; |
|
295 |
+ sigset_t sigset; |
|
296 |
+ struct sigaction act; |
|
297 |
+ const struct optstruct *pt; |
|
298 |
+ uint64_t in_mask = IN_ONLYDIR | IN_MOVE | IN_DELETE | IN_CREATE; |
|
299 |
+ fd_set rfds; |
|
300 |
+ char buf[4096]; |
|
301 |
+ ssize_t bread; |
|
302 |
+ const struct inotify_event *event; |
|
303 |
+ int ret, len; |
|
304 |
+ |
|
305 |
+ /* ignore all signals except SIGUSR1 */ |
|
306 |
+ sigfillset(&sigset); |
|
307 |
+ sigdelset(&sigset, SIGUSR1); |
|
308 |
+ /* The behavior of a process is undefined after it ignores a |
|
309 |
+ * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
310 |
+ sigdelset(&sigset, SIGFPE); |
|
311 |
+ sigdelset(&sigset, SIGILL); |
|
312 |
+ sigdelset(&sigset, SIGSEGV); |
|
313 |
+#ifdef SIGBUS |
|
314 |
+ sigdelset(&sigset, SIGBUS); |
|
315 |
+#endif |
|
316 |
+ pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
317 |
+ memset(&act, 0, sizeof(struct sigaction)); |
|
318 |
+ act.sa_handler = onas_ddd_exit; |
|
319 |
+ sigfillset(&(act.sa_mask)); |
|
320 |
+ sigaction(SIGUSR1, &act, NULL); |
|
321 |
+ sigaction(SIGSEGV, &act, NULL); |
|
322 |
+ |
|
323 |
+ onas_in_fd = inotify_init1(IN_NONBLOCK); |
|
324 |
+ if (onas_in_fd == -1) { |
|
325 |
+ logg("!ScanOnAccess: Could not init inotify."); |
|
326 |
+ return NULL; |
|
327 |
+ } |
|
328 |
+ |
|
329 |
+ ret = onas_ddd_init(0, ONAS_DEFAULT_HT_SIZE); |
|
330 |
+ if (ret) { |
|
331 |
+ logg("!ScanOnAccess: Failed to initialize 3D. \n"); |
|
332 |
+ return NULL; |
|
333 |
+ } |
|
334 |
+ |
|
335 |
+ /* Add provided paths recursively. */ |
|
336 |
+ if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
337 |
+ while (pt) { |
|
338 |
+ if (!strcmp(pt->strarg, "/")) { |
|
339 |
+ logg("!ScanOnAccess: Not including path '%s' while DDD is enabled\n", pt->strarg); |
|
340 |
+ logg("!ScanOnAccess: Please use the OnAccessMountPath option to watch '%s'\n", pt->strarg); |
|
341 |
+ pt = (struct optstruct *)pt->nextarg; |
|
342 |
+ continue; |
|
343 |
+ } |
|
344 |
+ if (onas_ht_get(ddd_ht, pt->strarg, strlen(pt->strarg), NULL) != CL_SUCCESS) { |
|
345 |
+ if (onas_ht_add_hierarchy(ddd_ht, pt->strarg)) { |
|
346 |
+ logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); |
|
347 |
+ return NULL; |
|
348 |
+ } else |
|
349 |
+ logg("ScanOnAccess: Protecting directory '%s' (and all sub-directories)\n", pt->strarg); |
|
350 |
+ } |
|
351 |
+ |
|
352 |
+ pt = (struct optstruct *)pt->nextarg; |
|
353 |
+ } |
|
354 |
+ } else { |
|
355 |
+ logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); |
|
356 |
+ return NULL; |
|
357 |
+ } |
|
358 |
+ |
|
359 |
+ /* Remove provided paths recursively. */ |
|
360 |
+ if ((pt = optget(tharg->opts, "OnAccessExcludePath"))->enabled) { |
|
361 |
+ while (pt) { |
|
362 |
+ size_t ptlen = strlen(pt->strarg); |
|
363 |
+ if (onas_ht_get(ddd_ht, pt->strarg, ptlen, NULL) == CL_SUCCESS) { |
|
364 |
+ if (onas_ht_rm_hierarchy(ddd_ht, pt->strarg, ptlen, 0)) { |
|
365 |
+ logg("!ScanOnAccess: Can't exclude path '%s'\n", pt->strarg); |
|
366 |
+ return NULL; |
|
367 |
+ } else |
|
368 |
+ logg("ScanOnAccess: Excluding directory '%s' (and all sub-directories)\n", pt->strarg); |
|
369 |
+ } |
|
370 |
+ |
|
371 |
+ pt = (struct optstruct *)pt->nextarg; |
|
372 |
+ } |
|
373 |
+ } |
|
374 |
+ |
|
375 |
+ /* Watch provided paths recursively */ |
|
376 |
+ if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
377 |
+ while (pt) { |
|
378 |
+ size_t ptlen = strlen(pt->strarg); |
|
379 |
+ if (onas_ht_get(ddd_ht, pt->strarg, ptlen, NULL) == CL_SUCCESS) { |
|
380 |
+ if (onas_ddd_watch(pt->strarg, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask)) { |
|
381 |
+ logg("!ScanOnAccess: Could not watch path '%s', %s\n", pt->strarg, strerror(errno)); |
|
382 |
+ if (errno == EINVAL && optget(tharg->opts, "OnAccessPrevention")->enabled) { |
|
383 |
+ logg("!ScanOnAccess: When using the OnAccessPrevention option, please ensure your kernel\n\t\t\twas compiled with CONFIG_FANOTIFY_ACCESS_PERMISSIONS set to Y\n"); |
|
384 |
+ |
|
385 |
+ kill(getpid(), SIGTERM); |
|
386 |
+ } |
|
387 |
+ return NULL; |
|
388 |
+ } |
|
389 |
+ } |
|
390 |
+ pt = (struct optstruct *)pt->nextarg; |
|
391 |
+ } |
|
392 |
+ } |
|
393 |
+ |
|
394 |
+ /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
395 |
+#if 0 |
|
396 |
+ if(optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
397 |
+ logg("ScanOnAccess: Extra scanning and notifications enabled.\n"); |
|
398 |
+} |
|
399 |
+#endif |
|
400 |
+ |
|
401 |
+ FD_ZERO(&rfds); |
|
402 |
+ FD_SET(onas_in_fd, &rfds); |
|
403 |
+ |
|
404 |
+ while (1) { |
|
405 |
+ do { |
|
406 |
+ ret = select(onas_in_fd + 1, &rfds, NULL, NULL, NULL); |
|
407 |
+ } while (ret == -1 && errno == EINTR); |
|
408 |
+ |
|
409 |
+ while ((bread = read(onas_in_fd, buf, sizeof(buf))) > 0) { |
|
410 |
+ |
|
411 |
+ /* Handle events. */ |
|
412 |
+ int wd; |
|
413 |
+ char *p = buf; |
|
414 |
+ const char *path = NULL; |
|
415 |
+ const char *child = NULL; |
|
416 |
+ for (; p < buf + bread; p += sizeof(struct inotify_event) + event->len) { |
|
417 |
+ |
|
418 |
+ event = (const struct inotify_event *)p; |
|
419 |
+ wd = event->wd; |
|
420 |
+ path = wdlt[wd]; |
|
421 |
+ child = event->name; |
|
422 |
+ |
|
423 |
+ len = strlen(path); |
|
424 |
+ size_t size = strlen(child) + len + 2; |
|
425 |
+ char *child_path = (char *)cli_malloc(size); |
|
426 |
+ if (child_path == NULL) |
|
427 |
+ return NULL; |
|
428 |
+ |
|
429 |
+ if (path[len - 1] == '/') |
|
430 |
+ snprintf(child_path, --size, "%s%s", path, child); |
|
431 |
+ else |
|
432 |
+ snprintf(child_path, size, "%s/%s", path, child); |
|
433 |
+ |
|
434 |
+ if (event->mask & IN_DELETE) { |
|
435 |
+ onas_ddd_handle_in_delete(tharg, path, child_path, event, wd); |
|
436 |
+ |
|
437 |
+ } else if (event->mask & IN_MOVED_FROM) { |
|
438 |
+ onas_ddd_handle_in_moved_from(tharg, path, child_path, event, wd); |
|
439 |
+ |
|
440 |
+ } else if (event->mask & IN_CREATE) { |
|
441 |
+ onas_ddd_handle_in_create(tharg, path, child_path, event, wd, in_mask); |
|
442 |
+ |
|
443 |
+ } else if (event->mask & IN_MOVED_TO) { |
|
444 |
+ onas_ddd_handle_in_moved_to(tharg, path, child_path, event, wd, in_mask); |
|
445 |
+ } |
|
446 |
+ } |
|
447 |
+ } |
|
448 |
+ } |
|
449 |
+ |
|
450 |
+ return NULL; |
|
451 |
+} |
|
452 |
+ |
|
453 |
+static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, |
|
454 |
+ const char *path, const char *child_path, const struct inotify_event *event, int wd) |
|
455 |
+{ |
|
456 |
+ |
|
457 |
+ struct stat s; |
|
458 |
+ if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
459 |
+ if (!(event->mask & IN_ISDIR)) return; |
|
460 |
+ |
|
461 |
+ logg("*ddd: DELETE - Removing %s from %s with wd:%d\n", child_path, path, wd); |
|
462 |
+ onas_ddd_unwatch(child_path, tharg->fan_fd, onas_in_fd); |
|
463 |
+ onas_ht_rm_hierarchy(ddd_ht, child_path, strlen(child_path), 0); |
|
464 |
+ |
|
465 |
+ return; |
|
466 |
+} |
|
467 |
+ |
|
468 |
+static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, |
|
469 |
+ const char *path, const char *child_path, const struct inotify_event *event, int wd) |
|
470 |
+{ |
|
471 |
+ |
|
472 |
+ struct stat s; |
|
473 |
+ if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
474 |
+ if (!(event->mask & IN_ISDIR)) return; |
|
475 |
+ |
|
476 |
+ logg("*ddd: MOVED_FROM - Removing %s from %s with wd:%d\n", child_path, path, wd); |
|
477 |
+ onas_ddd_unwatch(child_path, tharg->fan_fd, onas_in_fd); |
|
478 |
+ onas_ht_rm_hierarchy(ddd_ht, child_path, strlen(child_path), 0); |
|
479 |
+ |
|
480 |
+ return; |
|
481 |
+} |
|
482 |
+ |
|
483 |
+static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, |
|
484 |
+ const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask) |
|
485 |
+{ |
|
486 |
+ |
|
487 |
+ struct stat s; |
|
488 |
+ |
|
489 |
+ /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
490 |
+#if 0 |
|
491 |
+ if (optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
492 |
+ if(stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) { |
|
493 |
+ onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISFILE); |
|
494 |
+ |
|
495 |
+ } else if(stat(child_path, &s) == 0 && S_ISDIR(s.st_mode)) { |
|
496 |
+ logg("*ddd: CREATE - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
497 |
+ onas_ht_add_hierarchy(ddd_ht, child_path); |
|
498 |
+ onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
499 |
+ |
|
500 |
+ onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISDIR); |
|
501 |
+ } |
|
502 |
+ } |
|
503 |
+ else |
|
504 |
+#endif |
|
505 |
+ { |
|
506 |
+ if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
507 |
+ if (!(event->mask & IN_ISDIR)) return; |
|
508 |
+ |
|
509 |
+ logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
510 |
+ onas_ht_add_hierarchy(ddd_ht, child_path); |
|
511 |
+ onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ return; |
|
515 |
+} |
|
516 |
+ |
|
517 |
+static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, |
|
518 |
+ const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask) |
|
519 |
+{ |
|
520 |
+ |
|
521 |
+ struct stat s; |
|
522 |
+ /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
523 |
+#if 0 |
|
524 |
+ if (optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
525 |
+ if(stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) { |
|
526 |
+ onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISFILE); |
|
527 |
+ |
|
528 |
+ } else if(stat(child_path, &s) == 0 && S_ISDIR(s.st_mode)) { |
|
529 |
+ logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
530 |
+ onas_ht_add_hierarchy(ddd_ht, child_path); |
|
531 |
+ onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
532 |
+ |
|
533 |
+ onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISDIR); |
|
534 |
+ } |
|
535 |
+ } |
|
536 |
+ else |
|
537 |
+#endif |
|
538 |
+ { |
|
539 |
+ if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
540 |
+ if (!(event->mask & IN_ISDIR)) return; |
|
541 |
+ |
|
542 |
+ logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
543 |
+ onas_ht_add_hierarchy(ddd_ht, child_path); |
|
544 |
+ onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
545 |
+ } |
|
546 |
+ |
|
547 |
+ return; |
|
548 |
+} |
|
549 |
+ |
|
550 |
+static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options) |
|
551 |
+{ |
|
552 |
+ |
|
553 |
+ int thread_started = 1; |
|
554 |
+ struct scth_thrarg *scth_tharg = NULL; |
|
555 |
+ pthread_attr_t scth_attr; |
|
556 |
+ pthread_t scth_pid = 0; |
|
557 |
+ |
|
558 |
+ do { |
|
559 |
+ if (pthread_attr_init(&scth_attr)) break; |
|
560 |
+ pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE); |
|
561 |
+ |
|
562 |
+ /* Allocate memory for arguments. Thread is responsible for freeing it. */ |
|
563 |
+ if (!(scth_tharg = (struct scth_thrarg *)calloc(sizeof(struct scth_thrarg), 1))) break; |
|
564 |
+ if (!(scth_tharg->options = (struct cl_scan_options *)calloc(sizeof(struct cl_scan_options), 1))) break; |
|
565 |
+ |
|
566 |
+ (void)memcpy(scth_tharg->options, tharg->options, sizeof(struct cl_scan_options)); |
|
567 |
+ |
|
568 |
+ scth_tharg->extra_options = extra_options; |
|
569 |
+ scth_tharg->opts = tharg->opts; |
|
570 |
+ scth_tharg->pathname = strdup(pathname); |
|
571 |
+ scth_tharg->engine = tharg->engine; |
|
572 |
+ |
|
573 |
+ thread_started = pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg); |
|
574 |
+ } while (0); |
|
575 |
+ |
|
576 |
+ if (0 != thread_started) { |
|
577 |
+ /* Failed to create thread. Free anything we may have allocated. */ |
|
578 |
+ logg("!ScanOnAccess: Unable to kick off extra scanning.\n"); |
|
579 |
+ if (NULL != scth_tharg) { |
|
580 |
+ if (NULL != scth_tharg->pathname) { |
|
581 |
+ free(scth_tharg->pathname); |
|
582 |
+ scth_tharg->pathname = NULL; |
|
583 |
+ } |
|
584 |
+ if (NULL != scth_tharg->options) { |
|
585 |
+ free(scth_tharg->options); |
|
586 |
+ scth_tharg->options = NULL; |
|
587 |
+ } |
|
588 |
+ free(scth_tharg); |
|
589 |
+ scth_tharg = NULL; |
|
590 |
+ } |
|
591 |
+ } |
|
592 |
+ |
|
593 |
+ return; |
|
594 |
+} |
|
595 |
+ |
|
596 |
+static void onas_ddd_exit(int sig) |
|
597 |
+{ |
|
598 |
+ logg("*ScanOnAccess: onas_ddd_exit(), signal %d\n", sig); |
|
599 |
+ |
|
600 |
+ close(onas_in_fd); |
|
601 |
+ |
|
602 |
+ onas_free_ht(ddd_ht); |
|
603 |
+ free(wdlt); |
|
604 |
+ |
|
605 |
+ pthread_exit(NULL); |
|
606 |
+ logg("ScanOnAccess: stopped\n"); |
|
607 |
+} |
|
608 |
+#endif |
0 | 609 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,47 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef __ONAS_IN_H |
|
21 |
+#define __ONAS_IN_H |
|
22 |
+ |
|
23 |
+#include "shared/optparser.h" |
|
24 |
+#include "libclamav/clamav.h" |
|
25 |
+ |
|
26 |
+/* |
|
27 |
+ * Extra options for onas_scan_th(). |
|
28 |
+ */ |
|
29 |
+#define ONAS_IN 0x01 |
|
30 |
+#define ONAS_FAN 0x02 |
|
31 |
+ |
|
32 |
+#define MAX_WATCH_LEN 7 |
|
33 |
+ |
|
34 |
+struct ddd_thrarg { |
|
35 |
+ int sid; |
|
36 |
+ struct cl_scan_options *options; |
|
37 |
+ int fan_fd; |
|
38 |
+ uint64_t fan_mask; |
|
39 |
+ const struct optstruct *opts; |
|
40 |
+ const struct cl_engine *engine; |
|
41 |
+}; |
|
42 |
+ |
|
43 |
+int onas_ddd_init(uint64_t nwatches, size_t ht_size); |
|
44 |
+void *onas_ddd_th(void *arg); |
|
45 |
+ |
|
46 |
+#endif |
0 | 47 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,700 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#if HAVE_CONFIG_H |
|
21 |
+#include "clamav-config.h" |
|
22 |
+#endif |
|
23 |
+ |
|
24 |
+#if defined(FANOTIFY) |
|
25 |
+#include <stdio.h> |
|
26 |
+#include <unistd.h> |
|
27 |
+#include <sys/types.h> |
|
28 |
+#include <sys/stat.h> |
|
29 |
+#include <fcntl.h> |
|
30 |
+#include <signal.h> |
|
31 |
+#include <pthread.h> |
|
32 |
+#include <string.h> |
|
33 |
+#include <errno.h> |
|
34 |
+#include <stdbool.h> |
|
35 |
+ |
|
36 |
+#include <sys/fanotify.h> |
|
37 |
+ |
|
38 |
+#include "../fanotif/onaccess_fan.h" |
|
39 |
+#include "onaccess_hash.h" |
|
40 |
+#include "onaccess_ddd.h" |
|
41 |
+ |
|
42 |
+#include "libclamav/clamav.h" |
|
43 |
+#include "libclamav/scanners.h" |
|
44 |
+#include "libclamav/str.h" |
|
45 |
+ |
|
46 |
+#include "shared/optparser.h" |
|
47 |
+#include "shared/output.h" |
|
48 |
+ |
|
49 |
+#include "clamd/server.h" |
|
50 |
+#include "clamd/others.h" |
|
51 |
+#include "clamd/scanner.h" |
|
52 |
+#include "clamd/priv_fts.h" |
|
53 |
+ |
|
54 |
+static struct onas_bucket *onas_bucket_init(); |
|
55 |
+static void onas_free_bucket(struct onas_bucket *bckt); |
|
56 |
+static int onas_bucket_insert(struct onas_bucket *bckt, struct onas_element *elem); |
|
57 |
+static int onas_bucket_remove(struct onas_bucket *bckt, struct onas_element *elem); |
|
58 |
+ |
|
59 |
+static int onas_add_hashnode_child(struct onas_hnode *node, const char *dirname); |
|
60 |
+ |
|
61 |
+static struct onas_lnode *onas_listnode_init(void); |
|
62 |
+ |
|
63 |
+static struct onas_hnode *onas_hashnode_init(void); |
|
64 |
+ |
|
65 |
+static inline uint32_t onas_hshift(uint32_t hash) |
|
66 |
+{ |
|
67 |
+ |
|
68 |
+ hash = ~hash; |
|
69 |
+ |
|
70 |
+ hash += (hash << 15); |
|
71 |
+ hash ^= (hash >> 12); |
|
72 |
+ hash += (hash << 2); |
|
73 |
+ hash ^= (hash >> 4); |
|
74 |
+ hash += (hash << 3); |
|
75 |
+ hash += (hash << 11); |
|
76 |
+ hash ^= (hash >> 16); |
|
77 |
+ |
|
78 |
+ return hash; |
|
79 |
+} |
|
80 |
+ |
|
81 |
+static inline int onas_hash(const char *key, size_t keylen, uint32_t size) |
|
82 |
+{ |
|
83 |
+ |
|
84 |
+ uint32_t hash = 1; |
|
85 |
+ uint32_t i; |
|
86 |
+ |
|
87 |
+ for (i = 0; i < keylen; i++) { |
|
88 |
+ hash += key[i]; |
|
89 |
+ hash = onas_hshift(hash); |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ return hash & (size - 1); |
|
93 |
+} |
|
94 |
+ |
|
95 |
+int onas_ht_init(struct onas_ht **ht, uint32_t size) |
|
96 |
+{ |
|
97 |
+ |
|
98 |
+ if (size == 0 || (size & (~size + 1)) != size) return CL_EARG; |
|
99 |
+ |
|
100 |
+ *ht = (struct onas_ht *)cli_malloc(sizeof(struct onas_ht)); |
|
101 |
+ if (!(*ht)) return CL_EMEM; |
|
102 |
+ |
|
103 |
+ **ht = (struct onas_ht){ |
|
104 |
+ .htable = NULL, |
|
105 |
+ .size = size, |
|
106 |
+ .nbckts = 0, |
|
107 |
+ }; |
|
108 |
+ |
|
109 |
+ if (!((*ht)->htable = (struct onas_bucket **)cli_calloc(size, sizeof(struct onas_bucket *)))) { |
|
110 |
+ onas_free_ht(*ht); |
|
111 |
+ return CL_EMEM; |
|
112 |
+ } |
|
113 |
+ |
|
114 |
+ return CL_SUCCESS; |
|
115 |
+} |
|
116 |
+ |
|
117 |
+void onas_free_ht(struct onas_ht *ht) |
|
118 |
+{ |
|
119 |
+ |
|
120 |
+ if (!ht || ht->size == 0) return; |
|
121 |
+ |
|
122 |
+ if (!ht->htable) { |
|
123 |
+ free(ht); |
|
124 |
+ return; |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ uint32_t i = 0; |
|
128 |
+ for (i = 0; i < ht->size; i++) { |
|
129 |
+ onas_free_bucket(ht->htable[i]); |
|
130 |
+ ht->htable[i] = NULL; |
|
131 |
+ } |
|
132 |
+ |
|
133 |
+ free(ht->htable); |
|
134 |
+ ht->htable = NULL; |
|
135 |
+ |
|
136 |
+ free(ht); |
|
137 |
+ |
|
138 |
+ return; |
|
139 |
+} |
|
140 |
+ |
|
141 |
+static struct onas_bucket *onas_bucket_init() |
|
142 |
+{ |
|
143 |
+ |
|
144 |
+ struct onas_bucket *bckt = (struct onas_bucket *)cli_malloc(sizeof(struct onas_bucket)); |
|
145 |
+ if (!bckt) return NULL; |
|
146 |
+ |
|
147 |
+ *bckt = (struct onas_bucket){ |
|
148 |
+ .size = 0, |
|
149 |
+ .head = NULL, |
|
150 |
+ .tail = NULL}; |
|
151 |
+ |
|
152 |
+ return bckt; |
|
153 |
+} |
|
154 |
+ |
|
155 |
+static void onas_free_bucket(struct onas_bucket *bckt) |
|
156 |
+{ |
|
157 |
+ |
|
158 |
+ if (!bckt) return; |
|
159 |
+ |
|
160 |
+ uint32_t i = 0; |
|
161 |
+ struct onas_element *curr = NULL; |
|
162 |
+ |
|
163 |
+ for (i = 0; i < bckt->size; i++) { |
|
164 |
+ curr = bckt->head; |
|
165 |
+ bckt->head = curr->next; |
|
166 |
+ onas_free_element(curr); |
|
167 |
+ curr = NULL; |
|
168 |
+ } |
|
169 |
+ |
|
170 |
+ free(bckt); |
|
171 |
+ |
|
172 |
+ return; |
|
173 |
+} |
|
174 |
+ |
|
175 |
+struct onas_element *onas_element_init(struct onas_hnode *value, const char *key, size_t klen) |
|
176 |
+{ |
|
177 |
+ |
|
178 |
+ struct onas_element *elem = (struct onas_element *)cli_malloc(sizeof(struct onas_element)); |
|
179 |
+ if (!elem) return NULL; |
|
180 |
+ |
|
181 |
+ *elem = (struct onas_element){ |
|
182 |
+ .key = key, |
|
183 |
+ .klen = klen, |
|
184 |
+ .data = value, |
|
185 |
+ .next = NULL, |
|
186 |
+ .prev = NULL}; |
|
187 |
+ |
|
188 |
+ return elem; |
|
189 |
+} |
|
190 |
+ |
|
191 |
+void onas_free_element(struct onas_element *elem) |
|
192 |
+{ |
|
193 |
+ |
|
194 |
+ if (!elem) return; |
|
195 |
+ |
|
196 |
+ onas_free_hashnode(elem->data); |
|
197 |
+ |
|
198 |
+ elem->prev = NULL; |
|
199 |
+ elem->next = NULL; |
|
200 |
+ |
|
201 |
+ free(elem); |
|
202 |
+ |
|
203 |
+ return; |
|
204 |
+} |
|
205 |
+ |
|
206 |
+int onas_ht_insert(struct onas_ht *ht, struct onas_element *elem) |
|
207 |
+{ |
|
208 |
+ |
|
209 |
+ if (!ht || !elem || !elem->key) return CL_ENULLARG; |
|
210 |
+ |
|
211 |
+ int idx = onas_hash(elem->key, elem->klen, ht->size); |
|
212 |
+ struct onas_bucket *bckt = ht->htable[idx]; |
|
213 |
+ |
|
214 |
+ int ret = 0; |
|
215 |
+ uint32_t bsize = 0; |
|
216 |
+ |
|
217 |
+ if (bckt == NULL) { |
|
218 |
+ ht->htable[idx] = onas_bucket_init(); |
|
219 |
+ bckt = ht->htable[idx]; |
|
220 |
+ } |
|
221 |
+ |
|
222 |
+ bsize = bckt->size; |
|
223 |
+ ret = onas_bucket_insert(bckt, elem); |
|
224 |
+ |
|
225 |
+ if (ret == CL_SUCCESS) |
|
226 |
+ if (bsize < bckt->size) |
|
227 |
+ ht->nbckts++; |
|
228 |
+ |
|
229 |
+ return ret; |
|
230 |
+} |
|
231 |
+ |
|
232 |
+static int onas_bucket_insert(struct onas_bucket *bckt, struct onas_element *elem) |
|
233 |
+{ |
|
234 |
+ if (!bckt || !elem) return CL_ENULLARG; |
|
235 |
+ |
|
236 |
+ if (bckt->size == 0) { |
|
237 |
+ bckt->head = elem; |
|
238 |
+ bckt->tail = elem; |
|
239 |
+ elem->prev = NULL; |
|
240 |
+ elem->next = NULL; |
|
241 |
+ bckt->size++; |
|
242 |
+ } else { |
|
243 |
+ struct onas_element *btail = bckt->tail; |
|
244 |
+ |
|
245 |
+ btail->next = elem; |
|
246 |
+ elem->prev = btail; |
|
247 |
+ elem->next = NULL; |
|
248 |
+ bckt->tail = elem; |
|
249 |
+ bckt->size++; |
|
250 |
+ } |
|
251 |
+ |
|
252 |
+ return CL_SUCCESS; |
|
253 |
+} |
|
254 |
+ |
|
255 |
+/* Checks if key exists and optionally stores address to the element corresponding to the key within elem */ |
|
256 |
+int onas_ht_get(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem) |
|
257 |
+{ |
|
258 |
+ |
|
259 |
+ if (elem) *elem = NULL; |
|
260 |
+ |
|
261 |
+ if (!ht || !key || klen <= 0) return CL_ENULLARG; |
|
262 |
+ |
|
263 |
+ struct onas_bucket *bckt = ht->htable[onas_hash(key, klen, ht->size)]; |
|
264 |
+ |
|
265 |
+ if (!bckt || bckt->size == 0) return CL_EARG; |
|
266 |
+ |
|
267 |
+ struct onas_element *curr = bckt->head; |
|
268 |
+ |
|
269 |
+ while (curr && strcmp(curr->key, key)) { |
|
270 |
+ curr = curr->next; |
|
271 |
+ } |
|
272 |
+ |
|
273 |
+ if (!curr) return CL_EARG; |
|
274 |
+ |
|
275 |
+ if (elem) *elem = curr; |
|
276 |
+ |
|
277 |
+ return CL_SUCCESS; |
|
278 |
+} |
|
279 |
+ |
|
280 |
+/* Removes the element corresponding to key from the hashtable and optionally returns a pointer to the removed element. */ |
|
281 |
+int onas_ht_remove(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **relem) |
|
282 |
+{ |
|
283 |
+ if (!ht || !key || klen <= 0) return CL_ENULLARG; |
|
284 |
+ |
|
285 |
+ struct onas_bucket *bckt = ht->htable[onas_hash(key, klen, ht->size)]; |
|
286 |
+ |
|
287 |
+ if (!bckt) return CL_EARG; |
|
288 |
+ |
|
289 |
+ struct onas_element *elem = NULL; |
|
290 |
+ onas_ht_get(ht, key, klen, &elem); |
|
291 |
+ |
|
292 |
+ if (!elem) return CL_EARG; |
|
293 |
+ |
|
294 |
+ int ret = onas_bucket_remove(bckt, elem); |
|
295 |
+ |
|
296 |
+ if (relem) *relem = elem; |
|
297 |
+ |
|
298 |
+ return ret; |
|
299 |
+} |
|
300 |
+ |
|
301 |
+static int onas_bucket_remove(struct onas_bucket *bckt, struct onas_element *elem) |
|
302 |
+{ |
|
303 |
+ if (!bckt || !elem) return CL_ENULLARG; |
|
304 |
+ |
|
305 |
+ struct onas_element *curr = bckt->head; |
|
306 |
+ |
|
307 |
+ while (curr && curr != elem) { |
|
308 |
+ curr = curr->next; |
|
309 |
+ } |
|
310 |
+ |
|
311 |
+ if (!curr) return CL_EARG; |
|
312 |
+ |
|
313 |
+ if (bckt->head == elem) { |
|
314 |
+ bckt->head = elem->next; |
|
315 |
+ if (bckt->head) bckt->head->prev = NULL; |
|
316 |
+ |
|
317 |
+ elem->next = NULL; |
|
318 |
+ } else if (bckt->tail == elem) { |
|
319 |
+ bckt->tail = elem->prev; |
|
320 |
+ if (bckt->tail) bckt->tail->next = NULL; |
|
321 |
+ |
|
322 |
+ elem->prev = NULL; |
|
323 |
+ } else { |
|
324 |
+ struct onas_element *tmp = NULL; |
|
325 |
+ |
|
326 |
+ tmp = elem->prev; |
|
327 |
+ if (tmp) { |
|
328 |
+ tmp->next = elem->next; |
|
329 |
+ tmp = elem->next; |
|
330 |
+ tmp->prev = elem->prev; |
|
331 |
+ } |
|
332 |
+ |
|
333 |
+ elem->prev = NULL; |
|
334 |
+ elem->next = NULL; |
|
335 |
+ } |
|
336 |
+ |
|
337 |
+ bckt->size--; |
|
338 |
+ |
|
339 |
+ return CL_SUCCESS; |
|
340 |
+} |
|
341 |
+ |
|
342 |
+/* Dealing with hash nodes and list nodes */ |
|
343 |
+ |
|
344 |
+/* Function to initialize hashnode. */ |
|
345 |
+static struct onas_hnode *onas_hashnode_init(void) |
|
346 |
+{ |
|
347 |
+ struct onas_hnode *hnode = NULL; |
|
348 |
+ if (!(hnode = (struct onas_hnode *)cli_malloc(sizeof(struct onas_hnode)))) { |
|
349 |
+ return NULL; |
|
350 |
+ } |
|
351 |
+ |
|
352 |
+ *hnode = (struct onas_hnode){ |
|
353 |
+ .pathlen = 0, |
|
354 |
+ .pathname = NULL, |
|
355 |
+ .prnt_pathlen = 0, |
|
356 |
+ .prnt_pathname = NULL, |
|
357 |
+ .childhead = NULL, |
|
358 |
+ .childtail = NULL, |
|
359 |
+ .wd = 0, |
|
360 |
+ .watched = 0}; |
|
361 |
+ |
|
362 |
+ if (!(hnode->childhead = (struct onas_lnode *)onas_listnode_init())) { |
|
363 |
+ onas_free_hashnode(hnode); |
|
364 |
+ return NULL; |
|
365 |
+ } |
|
366 |
+ |
|
367 |
+ if (!(hnode->childtail = (struct onas_lnode *)onas_listnode_init())) { |
|
368 |
+ onas_free_hashnode(hnode); |
|
369 |
+ return NULL; |
|
370 |
+ } |
|
371 |
+ |
|
372 |
+ hnode->childhead->next = (struct onas_lnode *)hnode->childtail; |
|
373 |
+ hnode->childtail->prev = (struct onas_lnode *)hnode->childhead; |
|
374 |
+ |
|
375 |
+ return hnode; |
|
376 |
+} |
|
377 |
+ |
|
378 |
+/* Function to initialize listnode. */ |
|
379 |
+static struct onas_lnode *onas_listnode_init(void) |
|
380 |
+{ |
|
381 |
+ struct onas_lnode *lnode = NULL; |
|
382 |
+ if (!(lnode = (struct onas_lnode *)cli_malloc(sizeof(struct onas_lnode)))) { |
|
383 |
+ return NULL; |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ *lnode = (struct onas_lnode){ |
|
387 |
+ .dirname = NULL, |
|
388 |
+ .next = NULL, |
|
389 |
+ .prev = NULL}; |
|
390 |
+ |
|
391 |
+ return lnode; |
|
392 |
+} |
|
393 |
+ |
|
394 |
+/* Function to free hashnode. */ |
|
395 |
+void onas_free_hashnode(struct onas_hnode *hnode) |
|
396 |
+{ |
|
397 |
+ if (!hnode) return; |
|
398 |
+ |
|
399 |
+ onas_free_dirlist(hnode->childhead); |
|
400 |
+ hnode->childhead = NULL; |
|
401 |
+ |
|
402 |
+ free(hnode->pathname); |
|
403 |
+ hnode->pathname = NULL; |
|
404 |
+ |
|
405 |
+ free(hnode->prnt_pathname); |
|
406 |
+ hnode->prnt_pathname = NULL; |
|
407 |
+ |
|
408 |
+ free(hnode); |
|
409 |
+ |
|
410 |
+ return; |
|
411 |
+} |
|
412 |
+ |
|
413 |
+/* Function to free list of listnodes. */ |
|
414 |
+void onas_free_dirlist(struct onas_lnode *head) |
|
415 |
+{ |
|
416 |
+ if (!head) return; |
|
417 |
+ struct onas_lnode *curr = head; |
|
418 |
+ struct onas_lnode *tmp = curr; |
|
419 |
+ |
|
420 |
+ while (curr) { |
|
421 |
+ tmp = curr->next; |
|
422 |
+ onas_free_listnode(curr); |
|
423 |
+ curr = tmp; |
|
424 |
+ } |
|
425 |
+ |
|
426 |
+ return; |
|
427 |
+} |
|
428 |
+ |
|
429 |
+/* Function to free a listnode. */ |
|
430 |
+void onas_free_listnode(struct onas_lnode *lnode) |
|
431 |
+{ |
|
432 |
+ if (!lnode) return; |
|
433 |
+ |
|
434 |
+ lnode->next = NULL; |
|
435 |
+ lnode->prev = NULL; |
|
436 |
+ |
|
437 |
+ free(lnode->dirname); |
|
438 |
+ lnode->dirname = NULL; |
|
439 |
+ |
|
440 |
+ free(lnode); |
|
441 |
+ |
|
442 |
+ return; |
|
443 |
+} |
|
444 |
+ |
|
445 |
+static int onas_add_hashnode_child(struct onas_hnode *node, const char *dirname) |
|
446 |
+{ |
|
447 |
+ if (!node || !dirname) return CL_ENULLARG; |
|
448 |
+ |
|
449 |
+ struct onas_lnode *child = onas_listnode_init(); |
|
450 |
+ if (!child) return CL_EMEM; |
|
451 |
+ |
|
452 |
+ size_t n = strlen(dirname); |
|
453 |
+ child->dirname = cli_strndup(dirname, n); |
|
454 |
+ |
|
455 |
+ onas_add_listnode(node->childtail, child); |
|
456 |
+ |
|
457 |
+ return CL_SUCCESS; |
|
458 |
+} |
|
459 |
+ |
|
460 |
+/* Function to add a dir_listnode to a list */ |
|
461 |
+int onas_add_listnode(struct onas_lnode *tail, struct onas_lnode *node) |
|
462 |
+{ |
|
463 |
+ if (!tail || !node) return CL_ENULLARG; |
|
464 |
+ |
|
465 |
+ struct onas_lnode *tmp = tail->prev; |
|
466 |
+ |
|
467 |
+ tmp->next = node; |
|
468 |
+ node->prev = tail->prev; |
|
469 |
+ |
|
470 |
+ node->next = tail; |
|
471 |
+ tail->prev = node; |
|
472 |
+ |
|
473 |
+ return CL_SUCCESS; |
|
474 |
+} |
|
475 |
+ |
|
476 |
+/* Function to remove a listnode based on dirname. */ |
|
477 |
+int onas_rm_listnode(struct onas_lnode *head, const char *dirname) |
|
478 |
+{ |
|
479 |
+ if (!dirname || !head) return CL_ENULLARG; |
|
480 |
+ |
|
481 |
+ struct onas_lnode *curr = head; |
|
482 |
+ size_t n = strlen(dirname); |
|
483 |
+ |
|
484 |
+ while ((curr = curr->next)) { |
|
485 |
+ if (!strncmp(curr->dirname, dirname, n)) { |
|
486 |
+ struct onas_lnode *tmp = curr->prev; |
|
487 |
+ tmp->next = curr->next; |
|
488 |
+ tmp = curr->next; |
|
489 |
+ tmp->prev = curr->prev; |
|
490 |
+ |
|
491 |
+ onas_free_listnode(curr); |
|
492 |
+ |
|
493 |
+ return CL_SUCCESS; |
|
494 |
+ } |
|
495 |
+ } |
|
496 |
+ |
|
497 |
+ return -1; |
|
498 |
+} |
|
499 |
+ |
|
500 |
+/*** Dealing with parent/child relationships in the table. ***/ |
|
501 |
+ |
|
502 |
+/* Determines parent and returns a copy based on full pathname. */ |
|
503 |
+inline static char *onas_get_parent(const char *pathname, size_t len) |
|
504 |
+{ |
|
505 |
+ if (!pathname || len <= 1) return NULL; |
|
506 |
+ |
|
507 |
+ int idx = len - 2; |
|
508 |
+ char *ret = NULL; |
|
509 |
+ |
|
510 |
+ while (idx >= 0 && pathname[idx] != '/') { |
|
511 |
+ idx--; |
|
512 |
+ } |
|
513 |
+ |
|
514 |
+ if (idx == 0) { |
|
515 |
+ idx++; |
|
516 |
+ } |
|
517 |
+ |
|
518 |
+ ret = cli_strndup(pathname, idx); |
|
519 |
+ if (!ret) { |
|
520 |
+ errno = ENOMEM; |
|
521 |
+ return NULL; |
|
522 |
+ } |
|
523 |
+ |
|
524 |
+ return ret; |
|
525 |
+} |
|
526 |
+ |
|
527 |
+/* Gets the index at which the name of directory begins from the full pathname. */ |
|
528 |
+inline static int onas_get_dirname_idx(const char *pathname, size_t len) |
|
529 |
+{ |
|
530 |
+ if (!pathname || len <= 1) return -1; |
|
531 |
+ |
|
532 |
+ int idx = len - 2; |
|
533 |
+ |
|
534 |
+ while (idx >= 0 && pathname[idx] != '/') { |
|
535 |
+ idx--; |
|
536 |
+ } |
|
537 |
+ |
|
538 |
+ if (pathname[idx] == '/') |
|
539 |
+ return idx + 1; |
|
540 |
+ |
|
541 |
+ return idx; |
|
542 |
+} |
|
543 |
+ |
|
544 |
+/* Emancipates the specified child from the specified parent. */ |
|
545 |
+int onas_ht_rm_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen) |
|
546 |
+{ |
|
547 |
+ |
|
548 |
+ if (!ht || !prntpath || prntlen <= 0 || !childpath || childlen <= 1) return CL_ENULLARG; |
|
549 |
+ |
|
550 |
+ struct onas_element *elem = NULL; |
|
551 |
+ struct onas_hnode *hnode = NULL; |
|
552 |
+ int idx = onas_get_dirname_idx(childpath, childlen); |
|
553 |
+ int ret = 0; |
|
554 |
+ |
|
555 |
+ if (idx <= 0) return CL_SUCCESS; |
|
556 |
+ |
|
557 |
+ if (onas_ht_get(ht, prntpath, prntlen, &elem) != CL_SUCCESS) return CL_EARG; |
|
558 |
+ |
|
559 |
+ hnode = elem->data; |
|
560 |
+ |
|
561 |
+ if ((ret = onas_rm_listnode(hnode->childhead, &(childpath[idx])))) return CL_EARG; |
|
562 |
+ |
|
563 |
+ return CL_SUCCESS; |
|
564 |
+} |
|
565 |
+ |
|
566 |
+/* The specified parent adds the specified child to its list. */ |
|
567 |
+int onas_ht_add_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen) |
|
568 |
+{ |
|
569 |
+ if (!ht || !prntpath || prntlen <= 0 || !childpath || childlen <= 1) return CL_ENULLARG; |
|
570 |
+ |
|
571 |
+ struct onas_element *elem = NULL; |
|
572 |
+ struct onas_hnode *hnode = NULL; |
|
573 |
+ int idx = onas_get_dirname_idx(childpath, childlen); |
|
574 |
+ |
|
575 |
+ if (idx <= 0) return CL_SUCCESS; |
|
576 |
+ |
|
577 |
+ if (onas_ht_get(ht, prntpath, prntlen, &elem)) return CL_EARG; |
|
578 |
+ hnode = elem->data; |
|
579 |
+ |
|
580 |
+ return onas_add_hashnode_child(hnode, &(childpath[idx])); |
|
581 |
+} |
|
582 |
+ |
|
583 |
+/*** Dealing with hierarchy changes. ***/ |
|
584 |
+ |
|
585 |
+/* Adds the hierarchy under pathname to the tree and allocates all necessary memory. */ |
|
586 |
+int onas_ht_add_hierarchy(struct onas_ht *ht, const char *pathname) |
|
587 |
+{ |
|
588 |
+ if (!ht || !pathname) return CL_ENULLARG; |
|
589 |
+ |
|
590 |
+ FTS *ftsp = NULL; |
|
591 |
+ int ftspopts = FTS_PHYSICAL | FTS_XDEV; |
|
592 |
+ FTSENT *curr = NULL; |
|
593 |
+ FTSENT *childlist = NULL; |
|
594 |
+ |
|
595 |
+ size_t len = strlen(pathname); |
|
596 |
+ char *prnt = onas_get_parent(pathname, len); |
|
597 |
+ if (prnt) onas_ht_add_child(ht, prnt, strlen(prnt), pathname, len); |
|
598 |
+ free(prnt); |
|
599 |
+ |
|
600 |
+ char *const pathargv[] = {(char *)pathname, NULL}; |
|
601 |
+ if (!(ftsp = _priv_fts_open(pathargv, ftspopts, NULL))) { |
|
602 |
+ logg("!ScanOnAccess: Could not open '%s'\n", pathname); |
|
603 |
+ return CL_EARG; |
|
604 |
+ } |
|
605 |
+ |
|
606 |
+ while ((curr = _priv_fts_read(ftsp))) { |
|
607 |
+ |
|
608 |
+ struct onas_hnode *hnode = NULL; |
|
609 |
+ |
|
610 |
+ /* May want to handle other options in the future. */ |
|
611 |
+ switch (curr->fts_info) { |
|
612 |
+ case FTS_D: |
|
613 |
+ hnode = onas_hashnode_init(); |
|
614 |
+ if (!hnode) return CL_EMEM; |
|
615 |
+ |
|
616 |
+ hnode->pathlen = curr->fts_pathlen; |
|
617 |
+ hnode->pathname = cli_strndup(curr->fts_path, hnode->pathlen); |
|
618 |
+ |
|
619 |
+ hnode->prnt_pathname = onas_get_parent(hnode->pathname, hnode->pathlen); |
|
620 |
+ if (hnode->prnt_pathname) |
|
621 |
+ hnode->prnt_pathlen = strlen(hnode->prnt_pathname); |
|
622 |
+ else |
|
623 |
+ hnode->prnt_pathlen = 0; |
|
624 |
+ break; |
|
625 |
+ default: |
|
626 |
+ continue; |
|
627 |
+ } |
|
628 |
+ |
|
629 |
+ if ((childlist = _priv_fts_children(ftsp, 0))) { |
|
630 |
+ do { |
|
631 |
+ if (childlist->fts_info == FTS_D) { |
|
632 |
+ if (CL_EMEM == onas_add_hashnode_child(hnode, childlist->fts_name)) { |
|
633 |
+ onas_free_hashnode(hnode); |
|
634 |
+ return CL_EMEM; |
|
635 |
+ } |
|
636 |
+ } |
|
637 |
+ |
|
638 |
+ } while ((childlist = childlist->fts_link)); |
|
639 |
+ } |
|
640 |
+ |
|
641 |
+ struct onas_element *elem = onas_element_init(hnode, hnode->pathname, hnode->pathlen); |
|
642 |
+ if (!elem) return CL_EMEM; |
|
643 |
+ |
|
644 |
+ if (onas_ht_insert(ht, elem)) { |
|
645 |
+ onas_free_element(elem); |
|
646 |
+ return CL_EMEM; |
|
647 |
+ } |
|
648 |
+ } |
|
649 |
+ |
|
650 |
+ _priv_fts_close(ftsp); |
|
651 |
+ return CL_SUCCESS; |
|
652 |
+} |
|
653 |
+ |
|
654 |
+/* Removes the underlying hierarchy from the tree and frees all associated memory. */ |
|
655 |
+int onas_ht_rm_hierarchy(struct onas_ht *ht, const char *pathname, size_t len, int level) |
|
656 |
+{ |
|
657 |
+ if (!ht || !pathname || len <= 0) return CL_ENULLARG; |
|
658 |
+ |
|
659 |
+ struct onas_hnode *hnode = NULL; |
|
660 |
+ struct onas_element *elem = NULL; |
|
661 |
+ char *prntname = NULL; |
|
662 |
+ size_t prntlen = 0; |
|
663 |
+ |
|
664 |
+ if (onas_ht_get(ht, pathname, len, &elem)) return CL_EARG; |
|
665 |
+ |
|
666 |
+ hnode = elem->data; |
|
667 |
+ |
|
668 |
+ struct onas_lnode *curr = hnode->childhead; |
|
669 |
+ |
|
670 |
+ if (level == 0) { |
|
671 |
+ if (!(prntname = onas_get_parent(pathname, len))) return CL_EARG; |
|
672 |
+ |
|
673 |
+ prntlen = strlen(prntname); |
|
674 |
+ if (onas_ht_rm_child(ht, prntname, prntlen, pathname, len)) return CL_EARG; |
|
675 |
+ |
|
676 |
+ free(prntname); |
|
677 |
+ } |
|
678 |
+ |
|
679 |
+ while (curr->next != hnode->childtail) { |
|
680 |
+ curr = curr->next; |
|
681 |
+ |
|
682 |
+ size_t size = len + strlen(curr->dirname) + 2; |
|
683 |
+ char *child_path = (char *)cli_malloc(size); |
|
684 |
+ if (child_path == NULL) |
|
685 |
+ return CL_EMEM; |
|
686 |
+ if (hnode->pathname[len - 1] == '/') |
|
687 |
+ snprintf(child_path, size, "%s%s", hnode->pathname, curr->dirname); |
|
688 |
+ else |
|
689 |
+ snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
690 |
+ onas_ht_rm_hierarchy(ht, child_path, size, level + 1); |
|
691 |
+ free(child_path); |
|
692 |
+ } |
|
693 |
+ |
|
694 |
+ onas_ht_remove(ht, pathname, len, NULL); |
|
695 |
+ onas_free_element(elem); |
|
696 |
+ |
|
697 |
+ return CL_SUCCESS; |
|
698 |
+} |
|
699 |
+#endif |
0 | 700 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,109 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef __ONAS_HASH_H |
|
21 |
+#define __ONAS_HASH_H |
|
22 |
+ |
|
23 |
+#define ONAS_FANWATCH 0x1 |
|
24 |
+#define ONAS_INWATCH 0x2 |
|
25 |
+#define ONAS_STOPWATCH 0x3 |
|
26 |
+ |
|
27 |
+#define ONAS_DEFAULT_HT_SIZE 1 << 18 |
|
28 |
+ |
|
29 |
+struct onas_element { |
|
30 |
+ |
|
31 |
+ const char *key; |
|
32 |
+ size_t klen; |
|
33 |
+ struct onas_hnode *data; |
|
34 |
+ |
|
35 |
+ struct onas_element *next; |
|
36 |
+ struct onas_element *prev; |
|
37 |
+}; |
|
38 |
+ |
|
39 |
+struct onas_bucket { |
|
40 |
+ |
|
41 |
+ uint32_t size; |
|
42 |
+ |
|
43 |
+ struct onas_element *head; |
|
44 |
+ struct onas_element *tail; |
|
45 |
+}; |
|
46 |
+ |
|
47 |
+struct onas_ht { |
|
48 |
+ |
|
49 |
+ struct onas_bucket **htable; |
|
50 |
+ |
|
51 |
+ /* Must be a sufficiently high power of two--will not grow. */ |
|
52 |
+ uint32_t size; |
|
53 |
+ uint32_t nbckts; |
|
54 |
+}; |
|
55 |
+ |
|
56 |
+/* Directory node struct for lists */ |
|
57 |
+struct onas_lnode { |
|
58 |
+ |
|
59 |
+ /* List stuffs */ |
|
60 |
+ char *dirname; |
|
61 |
+ struct onas_lnode *next; |
|
62 |
+ struct onas_lnode *prev; |
|
63 |
+}; |
|
64 |
+ |
|
65 |
+/* Directory node struct for hash tables */ |
|
66 |
+struct onas_hnode { |
|
67 |
+ |
|
68 |
+ /* Path info */ |
|
69 |
+ int pathlen; |
|
70 |
+ char *pathname; |
|
71 |
+ |
|
72 |
+ /* Parent info */ |
|
73 |
+ int prnt_pathlen; |
|
74 |
+ char *prnt_pathname; |
|
75 |
+ |
|
76 |
+ /* Child head and tail are empty sentinels */ |
|
77 |
+ struct onas_lnode *childhead; |
|
78 |
+ struct onas_lnode *childtail; |
|
79 |
+ |
|
80 |
+ /* Inotify watch descriptor */ |
|
81 |
+ int wd; |
|
82 |
+ |
|
83 |
+ /* Watched stuffs */ |
|
84 |
+ uint32_t watched; |
|
85 |
+}; |
|
86 |
+ |
|
87 |
+void onas_free_ht(struct onas_ht *ht); |
|
88 |
+int onas_ht_init(struct onas_ht **ht, uint32_t table_size); |
|
89 |
+int onas_ht_insert(struct onas_ht *ht, struct onas_element *elem); |
|
90 |
+int onas_ht_remove(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem); |
|
91 |
+int onas_ht_get(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem); |
|
92 |
+int onas_ht_rm_hierarchy(struct onas_ht *ht, const char *pathname, size_t len, int level); |
|
93 |
+int onas_ht_add_hierarchy(struct onas_ht *ht, const char *pathname); |
|
94 |
+int onas_ht_add_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen); |
|
95 |
+int onas_ht_rm_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen); |
|
96 |
+ |
|
97 |
+void onas_free_element(struct onas_element *elem); |
|
98 |
+struct onas_element *onas_element_init(struct onas_hnode *value, const char *key, size_t klen); |
|
99 |
+ |
|
100 |
+void onas_free_hashnode(struct onas_hnode *hnode); |
|
101 |
+ |
|
102 |
+void onas_free_listnode(struct onas_lnode *lnode); |
|
103 |
+int onas_add_listnode(struct onas_lnode *tail, struct onas_lnode *node); |
|
104 |
+int onas_rm_listnode(struct onas_lnode *head, const char *dirname); |
|
105 |
+ |
|
106 |
+void onas_free_dirlist(struct onas_lnode *head); |
|
107 |
+ |
|
108 |
+#endif |
0 | 109 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,120 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2017-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#if HAVE_CONFIG_H |
|
21 |
+#include "clamav-config.h" |
|
22 |
+#endif |
|
23 |
+ |
|
24 |
+#if defined(FANOTIFY) |
|
25 |
+ |
|
26 |
+#include <stdio.h> |
|
27 |
+#include <stdarg.h> |
|
28 |
+#include <stdlib.h> |
|
29 |
+#include <string.h> |
|
30 |
+//#include <fcntl.h> |
|
31 |
+#include <sys/stat.h> |
|
32 |
+#include <errno.h> |
|
33 |
+#include <pthread.h> |
|
34 |
+//#include <limits.h> |
|
35 |
+#include "libclamav/clamav.h" |
|
36 |
+//#include "libclamav/scanners.h" |
|
37 |
+#include "shared/optparser.h" |
|
38 |
+#include "shared/output.h" |
|
39 |
+//#include "shared/misc.h" |
|
40 |
+//#include "libclamav/others.h" |
|
41 |
+ |
|
42 |
+//#include "others.h" |
|
43 |
+ |
|
44 |
+#include "onaccess_others.h" |
|
45 |
+#include "clamd/scanner.h" |
|
46 |
+ |
|
47 |
+static pthread_mutex_t onas_scan_lock = PTHREAD_MUTEX_INITIALIZER; |
|
48 |
+ |
|
49 |
+int onas_fan_checkowner(int pid, const struct optstruct *opts) |
|
50 |
+{ |
|
51 |
+ char path[32]; |
|
52 |
+ STATBUF sb; |
|
53 |
+ const struct optstruct *opt = NULL; |
|
54 |
+ const struct optstruct *opt_root = NULL; |
|
55 |
+ |
|
56 |
+ /* always ignore ourselves */ |
|
57 |
+ if (pid == (int)getpid()) { |
|
58 |
+ return CHK_SELF; |
|
59 |
+ } |
|
60 |
+ |
|
61 |
+ /* look up options */ |
|
62 |
+ opt = optget(opts, "OnAccessExcludeUID"); |
|
63 |
+ opt_root = optget(opts, "OnAccessExcludeRootUID"); |
|
64 |
+ |
|
65 |
+ /* we can return immediately if no uid exclusions were requested */ |
|
66 |
+ if (!(opt->enabled || opt_root->enabled)) |
|
67 |
+ return CHK_CLEAN; |
|
68 |
+ |
|
69 |
+ /* perform exclusion checks if we can stat OK */ |
|
70 |
+ snprintf(path, sizeof(path), "/proc/%u", pid); |
|
71 |
+ if (CLAMSTAT(path, &sb) == 0) { |
|
72 |
+ /* check all our non-root UIDs first */ |
|
73 |
+ if (opt->enabled) { |
|
74 |
+ while (opt) { |
|
75 |
+ if (opt->numarg == (long long)sb.st_uid) |
|
76 |
+ return CHK_FOUND; |
|
77 |
+ opt = opt->nextarg; |
|
78 |
+ } |
|
79 |
+ } |
|
80 |
+ /* finally check root UID */ |
|
81 |
+ if (opt_root->enabled) { |
|
82 |
+ if (0 == (long long)sb.st_uid) |
|
83 |
+ return CHK_FOUND; |
|
84 |
+ } |
|
85 |
+ } else if (errno == EACCES) { |
|
86 |
+ logg("*Permission denied to stat /proc/%d to exclude UIDs... perhaps SELinux denial?\n", pid); |
|
87 |
+ } else if (errno == ENOENT) { |
|
88 |
+ /* FIXME: should this be configurable? */ |
|
89 |
+ logg("$/proc/%d vanished before UIDs could be excluded; scanning anyway\n", pid); |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ return CHK_CLEAN; |
|
93 |
+} |
|
94 |
+ |
|
95 |
+int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo) |
|
96 |
+{ |
|
97 |
+ int ret = 0; |
|
98 |
+ struct cb_context context; |
|
99 |
+ |
|
100 |
+ pthread_mutex_lock(&onas_scan_lock); |
|
101 |
+ |
|
102 |
+ context.filename = fname; |
|
103 |
+ context.virsize = 0; |
|
104 |
+ context.scandata = NULL; |
|
105 |
+ |
|
106 |
+ /*ret = cl_scandesc_callback(fd, fname, virname, NULL, engine, options, &context);*/ |
|
107 |
+ |
|
108 |
+ if (ret) { |
|
109 |
+ if (extinfo && context.virsize) |
|
110 |
+ logg("ScanOnAccess: %s: %s(%s:%llu) FOUND\n", fname, *virname, context.virhash, context.virsize); |
|
111 |
+ else |
|
112 |
+ logg("ScanOnAccess: %s: %s FOUND\n", fname, *virname); |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ pthread_mutex_unlock(&onas_scan_lock); |
|
116 |
+ |
|
117 |
+ return ret; |
|
118 |
+} |
|
119 |
+#endif |
0 | 120 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,36 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2017-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef __CLAMD_ONAS_OTHERS_H |
|
21 |
+#define __CLAMD_ONAS_OTHERS_H |
|
22 |
+ |
|
23 |
+#include "shared/optparser.h" |
|
24 |
+#include "libclamav/clamav.h" |
|
25 |
+ |
|
26 |
+typedef enum { |
|
27 |
+ CHK_CLEAN, |
|
28 |
+ CHK_FOUND, |
|
29 |
+ CHK_SELF |
|
30 |
+} cli_check_t; |
|
31 |
+ |
|
32 |
+int onas_fan_checkowner(int pid, const struct optstruct *opts); |
|
33 |
+int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo); |
|
34 |
+ |
|
35 |
+#endif |
0 | 36 |
deleted file mode 100644 |
... | ... |
@@ -1,322 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2009 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm, aCaB, Mickey Sola |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#if HAVE_CONFIG_H |
|
23 |
-#include "clamav-config.h" |
|
24 |
-#endif |
|
25 |
- |
|
26 |
-#include <stdio.h> |
|
27 |
-#include <stdlib.h> |
|
28 |
-#ifdef HAVE_UNISTD_H |
|
29 |
-#include <unistd.h> |
|
30 |
-#endif |
|
31 |
-#include <string.h> |
|
32 |
-#include <sys/types.h> |
|
33 |
-#include <sys/stat.h> |
|
34 |
-#ifdef HAVE_SYS_LIMITS_H |
|
35 |
-#include <sys/limits.h> |
|
36 |
-#endif |
|
37 |
-#ifdef HAVE_SYS_SELECT_H |
|
38 |
-#include <sys/select.h> |
|
39 |
-#endif |
|
40 |
-#include <sys/socket.h> |
|
41 |
-#include <sys/un.h> |
|
42 |
-#include <netinet/in.h> |
|
43 |
-#include <arpa/inet.h> |
|
44 |
-#include <netdb.h> |
|
45 |
-#include <utime.h> |
|
46 |
-#include <errno.h> |
|
47 |
-#include <dirent.h> |
|
48 |
-#include <fcntl.h> |
|
49 |
- |
|
50 |
-#ifdef HAVE_SYS_UIO_H |
|
51 |
-#include <sys/uio.h> |
|
52 |
-#endif |
|
53 |
- |
|
54 |
-#include "libclamav/clamav.h" |
|
55 |
-#include "shared/optparser.h" |
|
56 |
-#include "shared/output.h" |
|
57 |
-#include "shared/misc.h" |
|
58 |
-#include "shared/actions.h" |
|
59 |
-#include "shared/clamdcom.h" |
|
60 |
- |
|
61 |
-#include "libclamav/str.h" |
|
62 |
-#include "libclamav/others.h" |
|
63 |
- |
|
64 |
-#include "onaccess_client.h" |
|
65 |
-#include "onaccess_proto.h" |
|
66 |
- |
|
67 |
-unsigned long int maxstream; |
|
68 |
-struct sockaddr_un nixsock; |
|
69 |
-extern struct optstruct *clamdopts; |
|
70 |
- |
|
71 |
-/* Inits the communication layer |
|
72 |
- * Returns 0 if clamd is local, non zero if clamd is remote */ |
|
73 |
-static int isremote(const struct optstruct *opts) { |
|
74 |
- int s, ret; |
|
75 |
- const struct optstruct *opt; |
|
76 |
- char *ipaddr, port[10]; |
|
77 |
- struct addrinfo hints, *info, *p; |
|
78 |
- int res; |
|
79 |
- |
|
80 |
- UNUSEDPARAM(opts); |
|
81 |
- |
|
82 |
-#ifndef _WIN32 |
|
83 |
- if((opt = optget(clamdopts, "LocalSocket"))->enabled) { |
|
84 |
- memset((void *)&nixsock, 0, sizeof(nixsock)); |
|
85 |
- nixsock.sun_family = AF_UNIX; |
|
86 |
- strncpy(nixsock.sun_path, opt->strarg, sizeof(nixsock.sun_path)); |
|
87 |
- nixsock.sun_path[sizeof(nixsock.sun_path)-1]='\0'; |
|
88 |
- return 0; |
|
89 |
- } |
|
90 |
-#endif |
|
91 |
- if(!(opt = optget(clamdopts, "TCPSocket"))->enabled) |
|
92 |
- return 0; |
|
93 |
- |
|
94 |
- snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg); |
|
95 |
- |
|
96 |
- opt = optget(clamdopts, "TCPAddr"); |
|
97 |
- while (opt) { |
|
98 |
- ipaddr = NULL; |
|
99 |
- if (opt->strarg) |
|
100 |
- ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg); |
|
101 |
- |
|
102 |
- memset(&hints, 0x00, sizeof(struct addrinfo)); |
|
103 |
- hints.ai_family = AF_UNSPEC; |
|
104 |
- hints.ai_socktype = SOCK_STREAM; |
|
105 |
- hints.ai_flags = AI_PASSIVE; |
|
106 |
- |
|
107 |
- if ((res = getaddrinfo(ipaddr, port, &hints, &info))) { |
|
108 |
- logg("!Can't lookup clamd hostname: %s\n", gai_strerror(res)); |
|
109 |
- opt = opt->nextarg; |
|
110 |
- continue; |
|
111 |
- } |
|
112 |
- |
|
113 |
- for (p = info; p != NULL; p = p->ai_next) { |
|
114 |
- if((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { |
|
115 |
- logg("isremote: socket() returning: %s.\n", strerror(errno)); |
|
116 |
- continue; |
|
117 |
- } |
|
118 |
- |
|
119 |
- switch (p->ai_family) { |
|
120 |
- case AF_INET: |
|
121 |
- ((struct sockaddr_in *)(p->ai_addr))->sin_port = htons(INADDR_ANY); |
|
122 |
- break; |
|
123 |
- case AF_INET6: |
|
124 |
- ((struct sockaddr_in6 *)(p->ai_addr))->sin6_port = htons(INADDR_ANY); |
|
125 |
- break; |
|
126 |
- default: |
|
127 |
- break; |
|
128 |
- } |
|
129 |
- |
|
130 |
- ret = bind(s, p->ai_addr, p->ai_addrlen); |
|
131 |
- if (ret) { |
|
132 |
- if (errno == EADDRINUSE) { |
|
133 |
- /* |
|
134 |
- * If we can't bind, then either we're attempting to listen on an IP that isn't |
|
135 |
- * ours or that clamd is already listening on. |
|
136 |
- */ |
|
137 |
- closesocket(s); |
|
138 |
- freeaddrinfo(info); |
|
139 |
- return 0; |
|
140 |
- } |
|
141 |
- |
|
142 |
- closesocket(s); |
|
143 |
- freeaddrinfo(info); |
|
144 |
- return 1; |
|
145 |
- } |
|
146 |
- |
|
147 |
- closesocket(s); |
|
148 |
- } |
|
149 |
- |
|
150 |
- freeaddrinfo(info); |
|
151 |
- |
|
152 |
- opt = opt->nextarg; |
|
153 |
- } |
|
154 |
- |
|
155 |
- return 0; |
|
156 |
-} |
|
157 |
- |
|
158 |
- |
|
159 |
-/* Turns a relative path into an absolute one |
|
160 |
- * Returns a pointer to the path (which must be |
|
161 |
- * freed by the caller) or NULL on error */ |
|
162 |
-static char *makeabs(const char *basepath) { |
|
163 |
- int namelen; |
|
164 |
- char *ret; |
|
165 |
- |
|
166 |
- if(!(ret = malloc(PATH_MAX + 1))) { |
|
167 |
- logg("^Can't make room for fullpath.\n"); |
|
168 |
- return NULL; |
|
169 |
- } |
|
170 |
- if(!cli_is_abspath(basepath)) { |
|
171 |
- if(!getcwd(ret, PATH_MAX)) { |
|
172 |
- logg("^Can't get absolute pathname of current working directory.\n"); |
|
173 |
- free(ret); |
|
174 |
- return NULL; |
|
175 |
- } |
|
176 |
- if(*basepath == '\\') { |
|
177 |
- namelen = 2; |
|
178 |
- basepath++; |
|
179 |
- } else |
|
180 |
- namelen = strlen(ret); |
|
181 |
- snprintf(&ret[namelen], PATH_MAX - namelen, PATHSEP"%s", basepath); |
|
182 |
- } else { |
|
183 |
- strncpy(ret, basepath, PATH_MAX); |
|
184 |
- } |
|
185 |
- ret[PATH_MAX] = '\0'; |
|
186 |
- return ret; |
|
187 |
-} |
|
188 |
- |
|
189 |
-/* Recursively scans a path with the given scantype |
|
190 |
- * Returns non zero for serious errors, zero otherwise */ |
|
191 |
-static int client_scan(const char *file, int scantype, int *infected, int *err, int maxlevel, int session, int flags) { |
|
192 |
- int ret; |
|
193 |
- char *fullpath = makeabs(file); |
|
194 |
- |
|
195 |
- if(!fullpath) |
|
196 |
- return 0; |
|
197 |
- if (!session) |
|
198 |
- ret = serial_client_scan(fullpath, scantype, infected, err, maxlevel, flags); |
|
199 |
- else |
|
200 |
- ret = parallel_client_scan(fullpath, scantype, infected, err, maxlevel, flags); |
|
201 |
- free(fullpath); |
|
202 |
- return ret; |
|
203 |
-} |
|
204 |
- |
|
205 |
-int get_clamd_version(const struct optstruct *opts) |
|
206 |
-{ |
|
207 |
- char *buff; |
|
208 |
- int len, sockd; |
|
209 |
- struct RCVLN rcv; |
|
210 |
- |
|
211 |
- isremote(opts); |
|
212 |
- if((sockd = dconnect()) < 0) return 2; |
|
213 |
- recvlninit(&rcv, sockd); |
|
214 |
- |
|
215 |
- if(sendln(sockd, "zVERSION", 9)) { |
|
216 |
- closesocket(sockd); |
|
217 |
- return 2; |
|
218 |
- } |
|
219 |
- |
|
220 |
- while((len = recvln(&rcv, &buff, NULL))) { |
|
221 |
- if(len == -1) { |
|
222 |
- logg("!Error occurred while receiving version information.\n"); |
|
223 |
- break; |
|
224 |
- } |
|
225 |
- printf("%s\n", buff); |
|
226 |
- } |
|
227 |
- |
|
228 |
- closesocket(sockd); |
|
229 |
- return 0; |
|
230 |
-} |
|
231 |
- |
|
232 |
-int reload_clamd_database(const struct optstruct *opts) |
|
233 |
-{ |
|
234 |
- char *buff; |
|
235 |
- int len, sockd; |
|
236 |
- struct RCVLN rcv; |
|
237 |
- |
|
238 |
- isremote(opts); |
|
239 |
- if((sockd = dconnect()) < 0) return 2; |
|
240 |
- recvlninit(&rcv, sockd); |
|
241 |
- |
|
242 |
- if(sendln(sockd, "zRELOAD", 8)) { |
|
243 |
- closesocket(sockd); |
|
244 |
- return 2; |
|
245 |
- } |
|
246 |
- |
|
247 |
- if(!(len = recvln(&rcv, &buff, NULL)) || len < 10 || memcmp(buff, "RELOADING", 9)) { |
|
248 |
- logg("!Clamd did not reload the database\n"); |
|
249 |
- closesocket(sockd); |
|
250 |
- return 2; |
|
251 |
- } |
|
252 |
- closesocket(sockd); |
|
253 |
- return 0; |
|
254 |
-} |
|
255 |
- |
|
256 |
-int client(const struct optstruct *opts, int *infected, int *err) |
|
257 |
-{ |
|
258 |
- int remote, scantype, session = 0, errors = 0, scandash = 0, maxrec, flags = 0; |
|
259 |
- const char *fname; |
|
260 |
- |
|
261 |
- scandash = (opts->filename && opts->filename[0] && !strcmp(opts->filename[0], "-") && !optget(opts, "file-list")->enabled && !opts->filename[1]); |
|
262 |
- remote = isremote(opts) | optget(opts, "stream")->enabled; |
|
263 |
-#ifdef HAVE_FD_PASSING |
|
264 |
- if(!remote && optget(clamdopts, "LocalSocket")->enabled && (optget(opts, "fdpass")->enabled || scandash)) { |
|
265 |
- scantype = FILDES; |
|
266 |
- session = optget(opts, "multiscan")->enabled; |
|
267 |
- } else |
|
268 |
-#endif |
|
269 |
- if(remote || scandash) { |
|
270 |
- scantype = STREAM; |
|
271 |
- session = optget(opts, "multiscan")->enabled; |
|
272 |
- } |
|
273 |
- else if(optget(opts, "multiscan")->enabled) scantype = MULTI; |
|
274 |
- else if(optget(opts, "allmatch")->enabled) scantype = ALLMATCH; |
|
275 |
- else scantype = CONT; |
|
276 |
- |
|
277 |
- maxrec = optget(clamdopts, "MaxDirectoryRecursion")->numarg; |
|
278 |
- maxstream = optget(clamdopts, "StreamMaxLength")->numarg; |
|
279 |
- if (optget(clamdopts, "FollowDirectorySymlinks")->enabled) |
|
280 |
- flags |= CLI_FTW_FOLLOW_DIR_SYMLINK; |
|
281 |
- if (optget(clamdopts, "FollowFileSymlinks")->enabled) |
|
282 |
- flags |= CLI_FTW_FOLLOW_FILE_SYMLINK; |
|
283 |
- flags |= CLI_FTW_TRIM_SLASHES; |
|
284 |
- |
|
285 |
- *infected = 0; |
|
286 |
- |
|
287 |
- if(scandash) { |
|
288 |
- int sockd, ret; |
|
289 |
- STATBUF sb; |
|
290 |
- if(FSTAT(0, &sb) < 0) { |
|
291 |
- logg("client.c: fstat failed for file name \"%s\", with %s\n.", |
|
292 |
- opts->filename[0], strerror(errno)); |
|
293 |
- return 2; |
|
294 |
- } |
|
295 |
- if((sb.st_mode & S_IFMT) != S_IFREG) scantype = STREAM; |
|
296 |
- if((sockd = dconnect()) >= 0 && (ret = dsresult(sockd, scantype, NULL, &ret, NULL)) >= 0) |
|
297 |
- *infected = ret; |
|
298 |
- else |
|
299 |
- errors = 1; |
|
300 |
- if(sockd >= 0) closesocket(sockd); |
|
301 |
- } else if(opts->filename || optget(opts, "file-list")->enabled) { |
|
302 |
- if(opts->filename && optget(opts, "file-list")->enabled) |
|
303 |
- logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n"); |
|
304 |
- |
|
305 |
- while((fname = filelist(opts, NULL))) { |
|
306 |
- if(!strcmp(fname, "-")) { |
|
307 |
- logg("!Scanning from standard input requires \"-\" to be the only file argument\n"); |
|
308 |
- continue; |
|
309 |
- } |
|
310 |
- errors += client_scan(fname, scantype, infected, err, maxrec, session, flags); |
|
311 |
- /* this may be too strict |
|
312 |
- if(errors >= 10) { |
|
313 |
- logg("!Too many errors\n"); |
|
314 |
- break; |
|
315 |
- } |
|
316 |
- */ |
|
317 |
- } |
|
318 |
- } else { |
|
319 |
- errors = client_scan("", scantype, infected, err, maxrec, session, flags); |
|
320 |
- } |
|
321 |
- return *infected ? 1 : (errors ? 2 : 0); |
|
322 |
-} |
323 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,40 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2009 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm, aCaB |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#ifndef __ONAS_CLIENT_H |
|
23 |
-#define __ONAS_CLIENT_H |
|
24 |
- |
|
25 |
-#include "shared/optparser.h" |
|
26 |
- |
|
27 |
-enum { |
|
28 |
- CONT, |
|
29 |
- MULTI, |
|
30 |
- STREAM, |
|
31 |
- FILDES, |
|
32 |
- ALLMATCH, |
|
33 |
- MAX_SCANTYPE = ALLMATCH |
|
34 |
-}; |
|
35 |
- |
|
36 |
-int client(const struct optstruct *opts, int *infected, int *err); |
|
37 |
-int get_clamd_version(const struct optstruct *opts); |
|
38 |
-int reload_clamd_database(const struct optstruct *opts); |
|
39 |
- |
|
40 |
-#endif |
41 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,609 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#if HAVE_CONFIG_H |
|
22 |
-#include "clamav-config.h" |
|
23 |
-#endif |
|
24 |
- |
|
25 |
-#if defined(FANOTIFY) |
|
26 |
- |
|
27 |
-#include <stdio.h> |
|
28 |
-#include <stdlib.h> |
|
29 |
-#include <unistd.h> |
|
30 |
-#include <sys/types.h> |
|
31 |
-#include <sys/stat.h> |
|
32 |
-#include <fcntl.h> |
|
33 |
-#include <signal.h> |
|
34 |
-#include <pthread.h> |
|
35 |
-#include <string.h> |
|
36 |
-#include <errno.h> |
|
37 |
-#include <stdbool.h> |
|
38 |
- |
|
39 |
-#include <sys/fanotify.h> |
|
40 |
-#include <sys/inotify.h> |
|
41 |
- |
|
42 |
-#include "onaccess_fan.h" |
|
43 |
-#include "onaccess_hash.h" |
|
44 |
-#include "onaccess_ddd.h" |
|
45 |
-#include "onaccess_scth.h" |
|
46 |
- |
|
47 |
-#include "libclamav/clamav.h" |
|
48 |
-#include "libclamav/scanners.h" |
|
49 |
- |
|
50 |
-#include "shared/optparser.h" |
|
51 |
-#include "shared/output.h" |
|
52 |
- |
|
53 |
-#include "clamd/server.h" |
|
54 |
-#include "clamd/others.h" |
|
55 |
-#include "clamd/scanner.h" |
|
56 |
- |
|
57 |
-static int onas_ddd_init_ht(uint32_t ht_size); |
|
58 |
-static int onas_ddd_init_wdlt(uint64_t nwatches); |
|
59 |
-static int onas_ddd_grow_wdlt(); |
|
60 |
- |
|
61 |
-static int onas_ddd_watch(const char *pathname, int fan_fd, uint64_t fan_mask, int in_fd, uint64_t in_mask); |
|
62 |
-static int onas_ddd_watch_hierarchy(const char *pathname, size_t len, int fd, uint64_t mask, uint32_t type); |
|
63 |
-static int onas_ddd_unwatch(const char *pathname, int fan_fd, int in_fd); |
|
64 |
-static int onas_ddd_unwatch_hierarchy(const char *pathname, size_t len, int fd, uint32_t type); |
|
65 |
- |
|
66 |
-static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask); |
|
67 |
-static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask); |
|
68 |
-static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); |
|
69 |
-static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, const char *path, const char *child_path, const struct inotify_event *event, int wd); |
|
70 |
-static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options); |
|
71 |
- |
|
72 |
-static void onas_ddd_exit(int sig); |
|
73 |
- |
|
74 |
-/* TODO: Unglobalize these. */ |
|
75 |
-static struct onas_ht *ddd_ht; |
|
76 |
-static char **wdlt; |
|
77 |
-static uint32_t wdlt_len; |
|
78 |
-static int onas_in_fd; |
|
79 |
- |
|
80 |
-static int onas_ddd_init_ht(uint32_t ht_size) |
|
81 |
-{ |
|
82 |
- |
|
83 |
- if (ht_size <= 0) |
|
84 |
- ht_size = ONAS_DEFAULT_HT_SIZE; |
|
85 |
- |
|
86 |
- return onas_ht_init(&ddd_ht, ht_size); |
|
87 |
-} |
|
88 |
- |
|
89 |
-static int onas_ddd_init_wdlt(uint64_t nwatches) |
|
90 |
-{ |
|
91 |
- |
|
92 |
- if (nwatches <= 0) return CL_EARG; |
|
93 |
- |
|
94 |
- wdlt = (char **)cli_calloc(nwatches << 1, sizeof(char *)); |
|
95 |
- if (!wdlt) return CL_EMEM; |
|
96 |
- |
|
97 |
- wdlt_len = nwatches << 1; |
|
98 |
- |
|
99 |
- return CL_SUCCESS; |
|
100 |
-} |
|
101 |
- |
|
102 |
-static int onas_ddd_grow_wdlt() |
|
103 |
-{ |
|
104 |
- |
|
105 |
- char **ptr = NULL; |
|
106 |
- |
|
107 |
- ptr = (char **)cli_realloc(wdlt, wdlt_len << 1); |
|
108 |
- if (ptr) { |
|
109 |
- wdlt = ptr; |
|
110 |
- memset(&ptr[wdlt_len], 0, sizeof(char *) * (wdlt_len - 1)); |
|
111 |
- } else { |
|
112 |
- return CL_EMEM; |
|
113 |
- } |
|
114 |
- |
|
115 |
- wdlt_len <<= 1; |
|
116 |
- |
|
117 |
- return CL_SUCCESS; |
|
118 |
-} |
|
119 |
- |
|
120 |
-/* TODO: Support configuration for changing/setting number of inotify watches. */ |
|
121 |
-int onas_ddd_init(uint64_t nwatches, size_t ht_size) |
|
122 |
-{ |
|
123 |
- |
|
124 |
- const char *nwatch_file = "/proc/sys/fs/inotify/max_user_watches"; |
|
125 |
- int nwfd = 0; |
|
126 |
- int ret = 0; |
|
127 |
- char nwatch_str[MAX_WATCH_LEN]; |
|
128 |
- char *p = NULL; |
|
129 |
- nwatches = 0; |
|
130 |
- |
|
131 |
- nwfd = open(nwatch_file, O_RDONLY); |
|
132 |
- if (nwfd < 0) return CL_EOPEN; |
|
133 |
- |
|
134 |
- ret = read(nwfd, nwatch_str, MAX_WATCH_LEN); |
|
135 |
- close(nwfd); |
|
136 |
- if (ret < 0) return CL_EREAD; |
|
137 |
- |
|
138 |
- nwatches = strtol(nwatch_str, &p, 10); |
|
139 |
- |
|
140 |
- ret = onas_ddd_init_wdlt(nwatches); |
|
141 |
- if (ret) return ret; |
|
142 |
- |
|
143 |
- ret = onas_ddd_init_ht(ht_size); |
|
144 |
- if (ret) return ret; |
|
145 |
- |
|
146 |
- return CL_SUCCESS; |
|
147 |
-} |
|
148 |
- |
|
149 |
-static int onas_ddd_watch(const char *pathname, int fan_fd, uint64_t fan_mask, int in_fd, uint64_t in_mask) |
|
150 |
-{ |
|
151 |
- if (!pathname || fan_fd <= 0 || in_fd <= 0) return CL_ENULLARG; |
|
152 |
- |
|
153 |
- int ret = CL_SUCCESS; |
|
154 |
- size_t len = strlen(pathname); |
|
155 |
- |
|
156 |
- ret = onas_ddd_watch_hierarchy(pathname, len, in_fd, in_mask, ONAS_IN); |
|
157 |
- if (ret) return ret; |
|
158 |
- |
|
159 |
- ret = onas_ddd_watch_hierarchy(pathname, len, fan_fd, fan_mask, ONAS_FAN); |
|
160 |
- if (ret) return ret; |
|
161 |
- |
|
162 |
- return CL_SUCCESS; |
|
163 |
-} |
|
164 |
- |
|
165 |
-static int onas_ddd_watch_hierarchy(const char *pathname, size_t len, int fd, uint64_t mask, uint32_t type) |
|
166 |
-{ |
|
167 |
- |
|
168 |
- if (!pathname || fd <= 0 || !type) return CL_ENULLARG; |
|
169 |
- |
|
170 |
- if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG; |
|
171 |
- |
|
172 |
- struct onas_hnode *hnode = NULL; |
|
173 |
- struct onas_element *elem = NULL; |
|
174 |
- int wd = 0; |
|
175 |
- |
|
176 |
- if (onas_ht_get(ddd_ht, pathname, len, &elem) != CL_SUCCESS) return CL_EARG; |
|
177 |
- |
|
178 |
- hnode = elem->data; |
|
179 |
- |
|
180 |
- if (type & ONAS_IN) { |
|
181 |
- wd = inotify_add_watch(fd, pathname, (uint32_t)mask); |
|
182 |
- |
|
183 |
- if (wd < 0) return CL_EARG; |
|
184 |
- |
|
185 |
- if ((uint32_t)wd >= wdlt_len) { |
|
186 |
- onas_ddd_grow_wdlt(); |
|
187 |
- } |
|
188 |
- |
|
189 |
- /* Link the hash node to the watch descriptor lookup table */ |
|
190 |
- hnode->wd = wd; |
|
191 |
- wdlt[wd] = hnode->pathname; |
|
192 |
- |
|
193 |
- hnode->watched |= ONAS_INWATCH; |
|
194 |
- } else if (type & ONAS_FAN) { |
|
195 |
- if (fanotify_mark(fd, FAN_MARK_ADD, mask, AT_FDCWD, hnode->pathname) < 0) return CL_EARG; |
|
196 |
- hnode->watched |= ONAS_FANWATCH; |
|
197 |
- } else { |
|
198 |
- return CL_EARG; |
|
199 |
- } |
|
200 |
- |
|
201 |
- struct onas_lnode *curr = hnode->childhead; |
|
202 |
- |
|
203 |
- while (curr->next != hnode->childtail) { |
|
204 |
- curr = curr->next; |
|
205 |
- |
|
206 |
- size_t size = len + strlen(curr->dirname) + 2; |
|
207 |
- char *child_path = (char *)cli_malloc(size); |
|
208 |
- if (child_path == NULL) |
|
209 |
- return CL_EMEM; |
|
210 |
- if (hnode->pathname[len - 1] == '/') |
|
211 |
- snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname); |
|
212 |
- else |
|
213 |
- snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
214 |
- |
|
215 |
- if (onas_ddd_watch_hierarchy(child_path, strlen(child_path), fd, mask, type)) { |
|
216 |
- return CL_EARG; |
|
217 |
- } |
|
218 |
- free(child_path); |
|
219 |
- } |
|
220 |
- |
|
221 |
- return CL_SUCCESS; |
|
222 |
-} |
|
223 |
- |
|
224 |
-static int onas_ddd_unwatch(const char *pathname, int fan_fd, int in_fd) |
|
225 |
-{ |
|
226 |
- if (!pathname || fan_fd <= 0 || in_fd <= 0) return CL_ENULLARG; |
|
227 |
- |
|
228 |
- int ret = CL_SUCCESS; |
|
229 |
- size_t len = strlen(pathname); |
|
230 |
- |
|
231 |
- ret = onas_ddd_unwatch_hierarchy(pathname, len, in_fd, ONAS_IN); |
|
232 |
- if (ret) return ret; |
|
233 |
- |
|
234 |
- ret = onas_ddd_unwatch_hierarchy(pathname, len, fan_fd, ONAS_FAN); |
|
235 |
- if (ret) return ret; |
|
236 |
- |
|
237 |
- return CL_SUCCESS; |
|
238 |
-} |
|
239 |
- |
|
240 |
-static int onas_ddd_unwatch_hierarchy(const char *pathname, size_t len, int fd, uint32_t type) |
|
241 |
-{ |
|
242 |
- |
|
243 |
- if (!pathname || fd <= 0 || !type) return CL_ENULLARG; |
|
244 |
- |
|
245 |
- if (type == (ONAS_IN | ONAS_FAN)) return CL_EARG; |
|
246 |
- |
|
247 |
- struct onas_hnode *hnode = NULL; |
|
248 |
- struct onas_element *elem = NULL; |
|
249 |
- int wd = 0; |
|
250 |
- |
|
251 |
- if (onas_ht_get(ddd_ht, pathname, len, &elem)) return CL_EARG; |
|
252 |
- |
|
253 |
- hnode = elem->data; |
|
254 |
- |
|
255 |
- if (type & ONAS_IN) { |
|
256 |
- wd = hnode->wd; |
|
257 |
- |
|
258 |
- if (!inotify_rm_watch(fd, wd)) return CL_EARG; |
|
259 |
- |
|
260 |
- /* Unlink the hash node from the watch descriptor lookup table */ |
|
261 |
- hnode->wd = 0; |
|
262 |
- wdlt[wd] = NULL; |
|
263 |
- |
|
264 |
- hnode->watched = ONAS_STOPWATCH; |
|
265 |
- } else if (type & ONAS_FAN) { |
|
266 |
- if (fanotify_mark(fd, FAN_MARK_REMOVE, 0, AT_FDCWD, hnode->pathname) < 0) return CL_EARG; |
|
267 |
- hnode->watched = ONAS_STOPWATCH; |
|
268 |
- } else { |
|
269 |
- return CL_EARG; |
|
270 |
- } |
|
271 |
- |
|
272 |
- struct onas_lnode *curr = hnode->childhead; |
|
273 |
- |
|
274 |
- while (curr->next != hnode->childtail) { |
|
275 |
- curr = curr->next; |
|
276 |
- |
|
277 |
- size_t size = len + strlen(curr->dirname) + 2; |
|
278 |
- char *child_path = (char *)cli_malloc(size); |
|
279 |
- if (child_path == NULL) |
|
280 |
- return CL_EMEM; |
|
281 |
- if (hnode->pathname[len - 1] == '/') |
|
282 |
- snprintf(child_path, --size, "%s%s", hnode->pathname, curr->dirname); |
|
283 |
- else |
|
284 |
- snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
285 |
- |
|
286 |
- onas_ddd_unwatch_hierarchy(child_path, strlen(child_path), fd, type); |
|
287 |
- free(child_path); |
|
288 |
- } |
|
289 |
- |
|
290 |
- return CL_SUCCESS; |
|
291 |
-} |
|
292 |
- |
|
293 |
-void *onas_ddd_th(void *arg) |
|
294 |
-{ |
|
295 |
- struct ddd_thrarg *tharg = (struct ddd_thrarg *)arg; |
|
296 |
- sigset_t sigset; |
|
297 |
- struct sigaction act; |
|
298 |
- const struct optstruct *pt; |
|
299 |
- uint64_t in_mask = IN_ONLYDIR | IN_MOVE | IN_DELETE | IN_CREATE; |
|
300 |
- fd_set rfds; |
|
301 |
- char buf[4096]; |
|
302 |
- ssize_t bread; |
|
303 |
- const struct inotify_event *event; |
|
304 |
- int ret, len; |
|
305 |
- |
|
306 |
- /* ignore all signals except SIGUSR1 */ |
|
307 |
- sigfillset(&sigset); |
|
308 |
- sigdelset(&sigset, SIGUSR1); |
|
309 |
- /* The behavior of a process is undefined after it ignores a |
|
310 |
- * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
311 |
- sigdelset(&sigset, SIGFPE); |
|
312 |
- sigdelset(&sigset, SIGILL); |
|
313 |
- sigdelset(&sigset, SIGSEGV); |
|
314 |
-#ifdef SIGBUS |
|
315 |
- sigdelset(&sigset, SIGBUS); |
|
316 |
-#endif |
|
317 |
- pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
318 |
- memset(&act, 0, sizeof(struct sigaction)); |
|
319 |
- act.sa_handler = onas_ddd_exit; |
|
320 |
- sigfillset(&(act.sa_mask)); |
|
321 |
- sigaction(SIGUSR1, &act, NULL); |
|
322 |
- sigaction(SIGSEGV, &act, NULL); |
|
323 |
- |
|
324 |
- onas_in_fd = inotify_init1(IN_NONBLOCK); |
|
325 |
- if (onas_in_fd == -1) { |
|
326 |
- logg("!ScanOnAccess: Could not init inotify."); |
|
327 |
- return NULL; |
|
328 |
- } |
|
329 |
- |
|
330 |
- ret = onas_ddd_init(0, ONAS_DEFAULT_HT_SIZE); |
|
331 |
- if (ret) { |
|
332 |
- logg("!ScanOnAccess: Failed to initialize 3D. \n"); |
|
333 |
- return NULL; |
|
334 |
- } |
|
335 |
- |
|
336 |
- /* Add provided paths recursively. */ |
|
337 |
- if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
338 |
- while (pt) { |
|
339 |
- if (!strcmp(pt->strarg, "/")) { |
|
340 |
- logg("!ScanOnAccess: Not including path '%s' while DDD is enabled\n", pt->strarg); |
|
341 |
- logg("!ScanOnAccess: Please use the OnAccessMountPath option to watch '%s'\n", pt->strarg); |
|
342 |
- pt = (struct optstruct *)pt->nextarg; |
|
343 |
- continue; |
|
344 |
- } |
|
345 |
- if (onas_ht_get(ddd_ht, pt->strarg, strlen(pt->strarg), NULL) != CL_SUCCESS) { |
|
346 |
- if (onas_ht_add_hierarchy(ddd_ht, pt->strarg)) { |
|
347 |
- logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); |
|
348 |
- return NULL; |
|
349 |
- } else |
|
350 |
- logg("ScanOnAccess: Protecting directory '%s' (and all sub-directories)\n", pt->strarg); |
|
351 |
- } |
|
352 |
- |
|
353 |
- pt = (struct optstruct *)pt->nextarg; |
|
354 |
- } |
|
355 |
- } else { |
|
356 |
- logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); |
|
357 |
- return NULL; |
|
358 |
- } |
|
359 |
- |
|
360 |
- /* Remove provided paths recursively. */ |
|
361 |
- if ((pt = optget(tharg->opts, "OnAccessExcludePath"))->enabled) { |
|
362 |
- while (pt) { |
|
363 |
- size_t ptlen = strlen(pt->strarg); |
|
364 |
- if (onas_ht_get(ddd_ht, pt->strarg, ptlen, NULL) == CL_SUCCESS) { |
|
365 |
- if (onas_ht_rm_hierarchy(ddd_ht, pt->strarg, ptlen, 0)) { |
|
366 |
- logg("!ScanOnAccess: Can't exclude path '%s'\n", pt->strarg); |
|
367 |
- return NULL; |
|
368 |
- } else |
|
369 |
- logg("ScanOnAccess: Excluding directory '%s' (and all sub-directories)\n", pt->strarg); |
|
370 |
- } |
|
371 |
- |
|
372 |
- pt = (struct optstruct *)pt->nextarg; |
|
373 |
- } |
|
374 |
- } |
|
375 |
- |
|
376 |
- /* Watch provided paths recursively */ |
|
377 |
- if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
378 |
- while (pt) { |
|
379 |
- size_t ptlen = strlen(pt->strarg); |
|
380 |
- if (onas_ht_get(ddd_ht, pt->strarg, ptlen, NULL) == CL_SUCCESS) { |
|
381 |
- if (onas_ddd_watch(pt->strarg, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask)) { |
|
382 |
- logg("!ScanOnAccess: Could not watch path '%s', %s\n", pt->strarg, strerror(errno)); |
|
383 |
- if (errno == EINVAL && optget(tharg->opts, "OnAccessPrevention")->enabled) { |
|
384 |
- logg("!ScanOnAccess: When using the OnAccessPrevention option, please ensure your kernel\n\t\t\twas compiled with CONFIG_FANOTIFY_ACCESS_PERMISSIONS set to Y\n"); |
|
385 |
- |
|
386 |
- kill(getpid(), SIGTERM); |
|
387 |
- } |
|
388 |
- return NULL; |
|
389 |
- } |
|
390 |
- } |
|
391 |
- pt = (struct optstruct *)pt->nextarg; |
|
392 |
- } |
|
393 |
- } |
|
394 |
- |
|
395 |
- /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
396 |
-#if 0 |
|
397 |
- if(optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
398 |
- logg("ScanOnAccess: Extra scanning and notifications enabled.\n"); |
|
399 |
-} |
|
400 |
-#endif |
|
401 |
- |
|
402 |
- FD_ZERO(&rfds); |
|
403 |
- FD_SET(onas_in_fd, &rfds); |
|
404 |
- |
|
405 |
- while (1) { |
|
406 |
- do { |
|
407 |
- ret = select(onas_in_fd + 1, &rfds, NULL, NULL, NULL); |
|
408 |
- } while (ret == -1 && errno == EINTR); |
|
409 |
- |
|
410 |
- while ((bread = read(onas_in_fd, buf, sizeof(buf))) > 0) { |
|
411 |
- |
|
412 |
- /* Handle events. */ |
|
413 |
- int wd; |
|
414 |
- char *p = buf; |
|
415 |
- const char *path = NULL; |
|
416 |
- const char *child = NULL; |
|
417 |
- for (; p < buf + bread; p += sizeof(struct inotify_event) + event->len) { |
|
418 |
- |
|
419 |
- event = (const struct inotify_event *)p; |
|
420 |
- wd = event->wd; |
|
421 |
- path = wdlt[wd]; |
|
422 |
- child = event->name; |
|
423 |
- |
|
424 |
- len = strlen(path); |
|
425 |
- size_t size = strlen(child) + len + 2; |
|
426 |
- char *child_path = (char *)cli_malloc(size); |
|
427 |
- if (child_path == NULL) |
|
428 |
- return NULL; |
|
429 |
- |
|
430 |
- if (path[len - 1] == '/') |
|
431 |
- snprintf(child_path, --size, "%s%s", path, child); |
|
432 |
- else |
|
433 |
- snprintf(child_path, size, "%s/%s", path, child); |
|
434 |
- |
|
435 |
- if (event->mask & IN_DELETE) { |
|
436 |
- onas_ddd_handle_in_delete(tharg, path, child_path, event, wd); |
|
437 |
- |
|
438 |
- } else if (event->mask & IN_MOVED_FROM) { |
|
439 |
- onas_ddd_handle_in_moved_from(tharg, path, child_path, event, wd); |
|
440 |
- |
|
441 |
- } else if (event->mask & IN_CREATE) { |
|
442 |
- onas_ddd_handle_in_create(tharg, path, child_path, event, wd, in_mask); |
|
443 |
- |
|
444 |
- } else if (event->mask & IN_MOVED_TO) { |
|
445 |
- onas_ddd_handle_in_moved_to(tharg, path, child_path, event, wd, in_mask); |
|
446 |
- } |
|
447 |
- } |
|
448 |
- } |
|
449 |
- } |
|
450 |
- |
|
451 |
- return NULL; |
|
452 |
-} |
|
453 |
- |
|
454 |
-static void onas_ddd_handle_in_delete(struct ddd_thrarg *tharg, |
|
455 |
- const char *path, const char *child_path, const struct inotify_event *event, int wd) |
|
456 |
-{ |
|
457 |
- |
|
458 |
- struct stat s; |
|
459 |
- if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
460 |
- if (!(event->mask & IN_ISDIR)) return; |
|
461 |
- |
|
462 |
- logg("*ddd: DELETE - Removing %s from %s with wd:%d\n", child_path, path, wd); |
|
463 |
- onas_ddd_unwatch(child_path, tharg->fan_fd, onas_in_fd); |
|
464 |
- onas_ht_rm_hierarchy(ddd_ht, child_path, strlen(child_path), 0); |
|
465 |
- |
|
466 |
- return; |
|
467 |
-} |
|
468 |
- |
|
469 |
-static void onas_ddd_handle_in_moved_from(struct ddd_thrarg *tharg, |
|
470 |
- const char *path, const char *child_path, const struct inotify_event *event, int wd) |
|
471 |
-{ |
|
472 |
- |
|
473 |
- struct stat s; |
|
474 |
- if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
475 |
- if (!(event->mask & IN_ISDIR)) return; |
|
476 |
- |
|
477 |
- logg("*ddd: MOVED_FROM - Removing %s from %s with wd:%d\n", child_path, path, wd); |
|
478 |
- onas_ddd_unwatch(child_path, tharg->fan_fd, onas_in_fd); |
|
479 |
- onas_ht_rm_hierarchy(ddd_ht, child_path, strlen(child_path), 0); |
|
480 |
- |
|
481 |
- return; |
|
482 |
-} |
|
483 |
- |
|
484 |
-static void onas_ddd_handle_in_create(struct ddd_thrarg *tharg, |
|
485 |
- const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask) |
|
486 |
-{ |
|
487 |
- |
|
488 |
- struct stat s; |
|
489 |
- |
|
490 |
- /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
491 |
-#if 0 |
|
492 |
- if (optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
493 |
- if(stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) { |
|
494 |
- onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISFILE); |
|
495 |
- |
|
496 |
- } else if(stat(child_path, &s) == 0 && S_ISDIR(s.st_mode)) { |
|
497 |
- logg("*ddd: CREATE - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
498 |
- onas_ht_add_hierarchy(ddd_ht, child_path); |
|
499 |
- onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
500 |
- |
|
501 |
- onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISDIR); |
|
502 |
- } |
|
503 |
- } |
|
504 |
- else |
|
505 |
-#endif |
|
506 |
- { |
|
507 |
- if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
508 |
- if (!(event->mask & IN_ISDIR)) return; |
|
509 |
- |
|
510 |
- logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
511 |
- onas_ht_add_hierarchy(ddd_ht, child_path); |
|
512 |
- onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
513 |
- } |
|
514 |
- |
|
515 |
- return; |
|
516 |
-} |
|
517 |
- |
|
518 |
-static void onas_ddd_handle_in_moved_to(struct ddd_thrarg *tharg, |
|
519 |
- const char *path, const char *child_path, const struct inotify_event *event, int wd, uint64_t in_mask) |
|
520 |
-{ |
|
521 |
- |
|
522 |
- struct stat s; |
|
523 |
- /* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
524 |
-#if 0 |
|
525 |
- if (optget(tharg->opts, "OnAccessExtraScanning")->enabled) { |
|
526 |
- if(stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) { |
|
527 |
- onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISFILE); |
|
528 |
- |
|
529 |
- } else if(stat(child_path, &s) == 0 && S_ISDIR(s.st_mode)) { |
|
530 |
- logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
531 |
- onas_ht_add_hierarchy(ddd_ht, child_path); |
|
532 |
- onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
533 |
- |
|
534 |
- onas_ddd_handle_extra_scanning(tharg, child_path, ONAS_SCTH_ISDIR); |
|
535 |
- } |
|
536 |
- } |
|
537 |
- else |
|
538 |
-#endif |
|
539 |
- { |
|
540 |
- if (stat(child_path, &s) == 0 && S_ISREG(s.st_mode)) return; |
|
541 |
- if (!(event->mask & IN_ISDIR)) return; |
|
542 |
- |
|
543 |
- logg("*ddd: MOVED_TO - Adding %s to %s with wd:%d\n", child_path, path, wd); |
|
544 |
- onas_ht_add_hierarchy(ddd_ht, child_path); |
|
545 |
- onas_ddd_watch(child_path, tharg->fan_fd, tharg->fan_mask, onas_in_fd, in_mask); |
|
546 |
- } |
|
547 |
- |
|
548 |
- return; |
|
549 |
-} |
|
550 |
- |
|
551 |
-static void onas_ddd_handle_extra_scanning(struct ddd_thrarg *tharg, const char *pathname, int extra_options) |
|
552 |
-{ |
|
553 |
- |
|
554 |
- int thread_started = 1; |
|
555 |
- struct scth_thrarg *scth_tharg = NULL; |
|
556 |
- pthread_attr_t scth_attr; |
|
557 |
- pthread_t scth_pid = 0; |
|
558 |
- |
|
559 |
- do { |
|
560 |
- if (pthread_attr_init(&scth_attr)) break; |
|
561 |
- pthread_attr_setdetachstate(&scth_attr, PTHREAD_CREATE_JOINABLE); |
|
562 |
- |
|
563 |
- /* Allocate memory for arguments. Thread is responsible for freeing it. */ |
|
564 |
- if (!(scth_tharg = (struct scth_thrarg *)calloc(sizeof(struct scth_thrarg), 1))) break; |
|
565 |
- if (!(scth_tharg->options = (struct cl_scan_options *)calloc(sizeof(struct cl_scan_options), 1))) break; |
|
566 |
- |
|
567 |
- (void)memcpy(scth_tharg->options, tharg->options, sizeof(struct cl_scan_options)); |
|
568 |
- |
|
569 |
- scth_tharg->extra_options = extra_options; |
|
570 |
- scth_tharg->opts = tharg->opts; |
|
571 |
- scth_tharg->pathname = strdup(pathname); |
|
572 |
- scth_tharg->engine = tharg->engine; |
|
573 |
- |
|
574 |
- thread_started = pthread_create(&scth_pid, &scth_attr, onas_scan_th, scth_tharg); |
|
575 |
- } while (0); |
|
576 |
- |
|
577 |
- if (0 != thread_started) { |
|
578 |
- /* Failed to create thread. Free anything we may have allocated. */ |
|
579 |
- logg("!ScanOnAccess: Unable to kick off extra scanning.\n"); |
|
580 |
- if (NULL != scth_tharg) { |
|
581 |
- if (NULL != scth_tharg->pathname) { |
|
582 |
- free(scth_tharg->pathname); |
|
583 |
- scth_tharg->pathname = NULL; |
|
584 |
- } |
|
585 |
- if (NULL != scth_tharg->options) { |
|
586 |
- free(scth_tharg->options); |
|
587 |
- scth_tharg->options = NULL; |
|
588 |
- } |
|
589 |
- free(scth_tharg); |
|
590 |
- scth_tharg = NULL; |
|
591 |
- } |
|
592 |
- } |
|
593 |
- |
|
594 |
- return; |
|
595 |
-} |
|
596 |
- |
|
597 |
-static void onas_ddd_exit(int sig) |
|
598 |
-{ |
|
599 |
- logg("*ScanOnAccess: onas_ddd_exit(), signal %d\n", sig); |
|
600 |
- |
|
601 |
- close(onas_in_fd); |
|
602 |
- |
|
603 |
- onas_free_ht(ddd_ht); |
|
604 |
- free(wdlt); |
|
605 |
- |
|
606 |
- pthread_exit(NULL); |
|
607 |
- logg("ScanOnAccess: stopped\n"); |
|
608 |
-} |
|
609 |
-#endif |
610 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,47 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#ifndef __ONAS_IN_H |
|
22 |
-#define __ONAS_IN_H |
|
23 |
- |
|
24 |
-#include "shared/optparser.h" |
|
25 |
-#include "libclamav/clamav.h" |
|
26 |
- |
|
27 |
-/* |
|
28 |
- * Extra options for onas_scan_th(). |
|
29 |
- */ |
|
30 |
-#define ONAS_IN 0x01 |
|
31 |
-#define ONAS_FAN 0x02 |
|
32 |
- |
|
33 |
-#define MAX_WATCH_LEN 7 |
|
34 |
- |
|
35 |
-struct ddd_thrarg { |
|
36 |
- int sid; |
|
37 |
- struct cl_scan_options *options; |
|
38 |
- int fan_fd; |
|
39 |
- uint64_t fan_mask; |
|
40 |
- const struct optstruct *opts; |
|
41 |
- const struct cl_engine *engine; |
|
42 |
-}; |
|
43 |
- |
|
44 |
-int onas_ddd_init(uint64_t nwatches, size_t ht_size); |
|
45 |
-void *onas_ddd_th(void *arg); |
|
46 |
- |
|
47 |
-#endif |
48 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,306 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2011-2013 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm, Mickey Sola |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#if HAVE_CONFIG_H |
|
23 |
-#include "clamav-config.h" |
|
24 |
-#endif |
|
25 |
- |
|
26 |
-#if defined(FANOTIFY) |
|
27 |
- |
|
28 |
-#include <stdio.h> |
|
29 |
-#include <unistd.h> |
|
30 |
-#include <sys/types.h> |
|
31 |
-#include <sys/stat.h> |
|
32 |
-#include <fcntl.h> |
|
33 |
-#include <signal.h> |
|
34 |
-#include <pthread.h> |
|
35 |
-#include <string.h> |
|
36 |
-#include <errno.h> |
|
37 |
-#include <time.h> |
|
38 |
- |
|
39 |
-#include <sys/fanotify.h> |
|
40 |
- |
|
41 |
-#include "libclamav/clamav.h" |
|
42 |
-#include "libclamav/scanners.h" |
|
43 |
- |
|
44 |
-#include "shared/optparser.h" |
|
45 |
-#include "shared/output.h" |
|
46 |
- |
|
47 |
-#include "onaccess_others.h" |
|
48 |
-#include "clamd/server.h" |
|
49 |
- |
|
50 |
-#include "onaccess_fan.h" |
|
51 |
-#include "onaccess_hash.h" |
|
52 |
-#include "onaccess_ddd.h" |
|
53 |
- |
|
54 |
-static pthread_t ddd_pid; |
|
55 |
-static int onas_fan_fd; |
|
56 |
- |
|
57 |
-static void onas_fan_exit(int sig) |
|
58 |
-{ |
|
59 |
- logg("*ScanOnAccess: onas_fan_exit(), signal %d\n", sig); |
|
60 |
- |
|
61 |
- close(onas_fan_fd); |
|
62 |
- |
|
63 |
- if (ddd_pid > 0) { |
|
64 |
- pthread_kill(ddd_pid, SIGUSR1); |
|
65 |
- pthread_join(ddd_pid, NULL); |
|
66 |
- } |
|
67 |
- |
|
68 |
- pthread_exit(NULL); |
|
69 |
- logg("ScanOnAccess: stopped\n"); |
|
70 |
-} |
|
71 |
- |
|
72 |
-static int onas_fan_scanfile(int fan_fd, const char *fname, struct fanotify_event_metadata *fmd, int scan, int extinfo, struct thrarg *tharg) |
|
73 |
-{ |
|
74 |
- struct fanotify_response res; |
|
75 |
- const char *virname = NULL; |
|
76 |
- int ret = 0; |
|
77 |
- |
|
78 |
- res.fd = fmd->fd; |
|
79 |
- res.response = FAN_ALLOW; |
|
80 |
- |
|
81 |
- if (scan) { |
|
82 |
- if (onas_scan(fname, fmd->fd, &virname, tharg->engine, tharg->options, extinfo) == CL_VIRUS) { |
|
83 |
- /* TODO : FIXME? virusaction forks. This could be extraordinarily problematic, lead to deadlocks, |
|
84 |
- * or at the very least lead to extreme memory consumption. Leaving disabled for now.*/ |
|
85 |
- //virusaction(fname, virname, tharg->opts); |
|
86 |
- res.response = FAN_DENY; |
|
87 |
- } |
|
88 |
- } |
|
89 |
- |
|
90 |
- if (fmd->mask & FAN_ALL_PERM_EVENTS) { |
|
91 |
- ret = write(fan_fd, &res, sizeof(res)); |
|
92 |
- if (ret == -1) |
|
93 |
- logg("!ScanOnAccess: Internal error (can't write to fanotify)\n"); |
|
94 |
- } |
|
95 |
- |
|
96 |
- return ret; |
|
97 |
-} |
|
98 |
- |
|
99 |
-void *onas_fan_th(void *arg) |
|
100 |
-{ |
|
101 |
- struct thrarg *tharg = (struct thrarg *)arg; |
|
102 |
- sigset_t sigset; |
|
103 |
- struct sigaction act; |
|
104 |
- const struct optstruct *pt; |
|
105 |
- short int scan; |
|
106 |
- unsigned int sizelimit = 0, extinfo; |
|
107 |
- STATBUF sb; |
|
108 |
- uint64_t fan_mask = FAN_EVENT_ON_CHILD | FAN_CLOSE; |
|
109 |
- fd_set rfds; |
|
110 |
- char buf[4096]; |
|
111 |
- ssize_t bread; |
|
112 |
- struct fanotify_event_metadata *fmd; |
|
113 |
- char fname[1024]; |
|
114 |
- int ret, len, check; |
|
115 |
- char err[128]; |
|
116 |
- |
|
117 |
- pthread_attr_t ddd_attr; |
|
118 |
- struct ddd_thrarg *ddd_tharg = NULL; |
|
119 |
- |
|
120 |
- ddd_pid = 0; |
|
121 |
- |
|
122 |
- /* ignore all signals except SIGUSR1 */ |
|
123 |
- sigfillset(&sigset); |
|
124 |
- sigdelset(&sigset, SIGUSR1); |
|
125 |
- /* The behavior of a process is undefined after it ignores a |
|
126 |
- * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
127 |
- sigdelset(&sigset, SIGFPE); |
|
128 |
- sigdelset(&sigset, SIGILL); |
|
129 |
- sigdelset(&sigset, SIGSEGV); |
|
130 |
-#ifdef SIGBUS |
|
131 |
- sigdelset(&sigset, SIGBUS); |
|
132 |
-#endif |
|
133 |
- pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
134 |
- memset(&act, 0, sizeof(struct sigaction)); |
|
135 |
- act.sa_handler = onas_fan_exit; |
|
136 |
- sigfillset(&(act.sa_mask)); |
|
137 |
- sigaction(SIGUSR1, &act, NULL); |
|
138 |
- sigaction(SIGSEGV, &act, NULL); |
|
139 |
- |
|
140 |
- /* Initialize fanotify */ |
|
141 |
- onas_fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY); |
|
142 |
- if (onas_fan_fd < 0) { |
|
143 |
- logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err))); |
|
144 |
- if (errno == EPERM) |
|
145 |
- logg("ScanOnAccess: clamd must be started by root\n"); |
|
146 |
- return NULL; |
|
147 |
- } |
|
148 |
- |
|
149 |
- if (!tharg) { |
|
150 |
- logg("!Unable to start on-access scanner. Bad thread args.\n"); |
|
151 |
- return NULL; |
|
152 |
- } |
|
153 |
- |
|
154 |
- if (optget(tharg->opts, "OnAccessPrevention")->enabled && !optget(tharg->opts, "OnAccessMountPath")->enabled) { |
|
155 |
- logg("ScanOnAccess: preventing access attempts on malicious files.\n"); |
|
156 |
- fan_mask |= FAN_ACCESS_PERM | FAN_OPEN_PERM; |
|
157 |
- } else { |
|
158 |
- logg("ScanOnAccess: notifying only for access attempts.\n"); |
|
159 |
- fan_mask |= FAN_ACCESS | FAN_OPEN; |
|
160 |
- } |
|
161 |
- |
|
162 |
- if ((pt = optget(tharg->opts, "OnAccessMountPath"))->enabled) { |
|
163 |
- while (pt) { |
|
164 |
- if (fanotify_mark(onas_fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, fan_mask, onas_fan_fd, pt->strarg) != 0) { |
|
165 |
- logg("!ScanOnAccess: Can't include mountpoint '%s'\n", pt->strarg); |
|
166 |
- return NULL; |
|
167 |
- } else |
|
168 |
- logg("ScanOnAccess: Protecting '%s' and rest of mount.\n", pt->strarg); |
|
169 |
- pt = (struct optstruct *)pt->nextarg; |
|
170 |
- } |
|
171 |
- |
|
172 |
- } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) { |
|
173 |
- int thread_started = 1; |
|
174 |
- do { |
|
175 |
- if (pthread_attr_init(&ddd_attr)) break; |
|
176 |
- pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE); |
|
177 |
- |
|
178 |
- /* Allocate memory for arguments. Thread is responsible for freeing it. */ |
|
179 |
- if (!(ddd_tharg = (struct ddd_thrarg *)calloc(sizeof(struct ddd_thrarg), 1))) break; |
|
180 |
- if (!(ddd_tharg->options = (struct cl_scan_options *)calloc(sizeof(struct cl_scan_options), 1))) break; |
|
181 |
- |
|
182 |
- (void)memcpy(ddd_tharg->options, tharg->options, sizeof(struct cl_scan_options)); |
|
183 |
- ddd_tharg->fan_fd = onas_fan_fd; |
|
184 |
- ddd_tharg->fan_mask = fan_mask; |
|
185 |
- ddd_tharg->opts = tharg->opts; |
|
186 |
- ddd_tharg->engine = tharg->engine; |
|
187 |
- |
|
188 |
- thread_started = pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg); |
|
189 |
- } while (0); |
|
190 |
- |
|
191 |
- if (0 != thread_started) { |
|
192 |
- /* Failed to create thread. Free anything we may have allocated. */ |
|
193 |
- logg("!Unable to start dynamic directory determination.\n"); |
|
194 |
- if (NULL != ddd_tharg) { |
|
195 |
- if (NULL != ddd_tharg->options) { |
|
196 |
- free(ddd_tharg->options); |
|
197 |
- ddd_tharg->options = NULL; |
|
198 |
- } |
|
199 |
- free(ddd_tharg); |
|
200 |
- ddd_tharg = NULL; |
|
201 |
- } |
|
202 |
- } |
|
203 |
- |
|
204 |
- } else { |
|
205 |
- if ((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { |
|
206 |
- while (pt) { |
|
207 |
- if (fanotify_mark(onas_fan_fd, FAN_MARK_ADD, fan_mask, onas_fan_fd, pt->strarg) != 0) { |
|
208 |
- logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); |
|
209 |
- return NULL; |
|
210 |
- } else |
|
211 |
- logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg); |
|
212 |
- pt = (struct optstruct *)pt->nextarg; |
|
213 |
- } |
|
214 |
- } else { |
|
215 |
- logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); |
|
216 |
- return NULL; |
|
217 |
- } |
|
218 |
- } |
|
219 |
- |
|
220 |
- /* Load other options. */ |
|
221 |
- sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg; |
|
222 |
- if (sizelimit) |
|
223 |
- logg("ScanOnAccess: Max file size limited to %u bytes\n", sizelimit); |
|
224 |
- else |
|
225 |
- logg("ScanOnAccess: File size limit disabled\n"); |
|
226 |
- |
|
227 |
- extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
228 |
- |
|
229 |
- FD_ZERO(&rfds); |
|
230 |
- FD_SET(onas_fan_fd, &rfds); |
|
231 |
- do { |
|
232 |
- if (reload) sleep(1); |
|
233 |
- ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); |
|
234 |
- } while ((ret == -1 && errno == EINTR) || reload); |
|
235 |
- |
|
236 |
- time_t start = time(NULL) - 30; |
|
237 |
- while (((bread = read(onas_fan_fd, buf, sizeof(buf))) > 0) || errno == EOVERFLOW) { |
|
238 |
- |
|
239 |
- if (errno == EOVERFLOW) { |
|
240 |
- if (time(NULL) - start >= 30) { |
|
241 |
- logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); |
|
242 |
- logg("!ScanOnAccess: File too large for fanotify ... recovering and continuing scans...\n"); |
|
243 |
- start = time(NULL); |
|
244 |
- } |
|
245 |
- |
|
246 |
- errno = 0; |
|
247 |
- continue; |
|
248 |
- } |
|
249 |
- |
|
250 |
- fmd = (struct fanotify_event_metadata *)buf; |
|
251 |
- while (FAN_EVENT_OK(fmd, bread)) { |
|
252 |
- scan = 1; |
|
253 |
- if (fmd->fd >= 0) { |
|
254 |
- sprintf(fname, "/proc/self/fd/%d", fmd->fd); |
|
255 |
- len = readlink(fname, fname, sizeof(fname) - 1); |
|
256 |
- if (len == -1) { |
|
257 |
- close(fmd->fd); |
|
258 |
- logg("!ScanOnAccess: Internal error (readlink() failed)\n"); |
|
259 |
- return NULL; |
|
260 |
- } |
|
261 |
- fname[len] = 0; |
|
262 |
- |
|
263 |
- if ((check = onas_fan_checkowner(fmd->pid, tharg->opts))) { |
|
264 |
- scan = 0; |
|
265 |
-/* TODO: Re-enable OnAccessExtraScanning once the thread resource consumption issue is resolved. */ |
|
266 |
-#if 0 |
|
267 |
- if ((check != CHK_SELF) || !(optget(tharg->opts, "OnAccessExtraScanning")->enabled)) { |
|
268 |
-#else |
|
269 |
- if (check != CHK_SELF) { |
|
270 |
-#endif |
|
271 |
- logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname); |
|
272 |
- } |
|
273 |
- } |
|
274 |
- |
|
275 |
- if (sizelimit) { |
|
276 |
- if (FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) { |
|
277 |
- scan = 0; |
|
278 |
- /* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */ |
|
279 |
- } |
|
280 |
- } |
|
281 |
- |
|
282 |
- if (onas_fan_scanfile(onas_fan_fd, fname, fmd, scan, extinfo, tharg) == -1) { |
|
283 |
- close(fmd->fd); |
|
284 |
- return NULL; |
|
285 |
- } |
|
286 |
- |
|
287 |
- if (close(fmd->fd) == -1) { |
|
288 |
- printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd); |
|
289 |
- close(fmd->fd); |
|
290 |
- return NULL; |
|
291 |
- } |
|
292 |
- } |
|
293 |
- fmd = FAN_EVENT_NEXT(fmd, bread); |
|
294 |
- } |
|
295 |
- do { |
|
296 |
- if (reload) sleep(1); |
|
297 |
- ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); |
|
298 |
- } while ((ret == -1 && errno == EINTR) || reload); |
|
299 |
-} |
|
300 |
- |
|
301 |
-if (bread < 0) |
|
302 |
- logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); |
|
303 |
- |
|
304 |
-return NULL; |
|
305 |
-} |
|
306 |
-#endif |
307 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,27 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2011-2013 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#ifndef __FAN_H |
|
23 |
-#define __FAN_H |
|
24 |
- |
|
25 |
-void *onas_fan_th(void *arg); |
|
26 |
- |
|
27 |
-#endif |
28 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,700 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#if HAVE_CONFIG_H |
|
22 |
-#include "clamav-config.h" |
|
23 |
-#endif |
|
24 |
- |
|
25 |
-#if defined(FANOTIFY) |
|
26 |
-#include <stdio.h> |
|
27 |
-#include <unistd.h> |
|
28 |
-#include <sys/types.h> |
|
29 |
-#include <sys/stat.h> |
|
30 |
-#include <fcntl.h> |
|
31 |
-#include <signal.h> |
|
32 |
-#include <pthread.h> |
|
33 |
-#include <string.h> |
|
34 |
-#include <errno.h> |
|
35 |
-#include <stdbool.h> |
|
36 |
- |
|
37 |
-#include <sys/fanotify.h> |
|
38 |
- |
|
39 |
-#include "onaccess_fan.h" |
|
40 |
-#include "onaccess_hash.h" |
|
41 |
-#include "onaccess_ddd.h" |
|
42 |
- |
|
43 |
-#include "libclamav/clamav.h" |
|
44 |
-#include "libclamav/scanners.h" |
|
45 |
-#include "libclamav/str.h" |
|
46 |
- |
|
47 |
-#include "shared/optparser.h" |
|
48 |
-#include "shared/output.h" |
|
49 |
- |
|
50 |
-#include "clamd/server.h" |
|
51 |
-#include "clamd/others.h" |
|
52 |
-#include "clamd/scanner.h" |
|
53 |
-#include "clamd/priv_fts.h" |
|
54 |
- |
|
55 |
-static struct onas_bucket *onas_bucket_init(); |
|
56 |
-static void onas_free_bucket(struct onas_bucket *bckt); |
|
57 |
-static int onas_bucket_insert(struct onas_bucket *bckt, struct onas_element *elem); |
|
58 |
-static int onas_bucket_remove(struct onas_bucket *bckt, struct onas_element *elem); |
|
59 |
- |
|
60 |
-static int onas_add_hashnode_child(struct onas_hnode *node, const char *dirname); |
|
61 |
- |
|
62 |
-static struct onas_lnode *onas_listnode_init(void); |
|
63 |
- |
|
64 |
-static struct onas_hnode *onas_hashnode_init(void); |
|
65 |
- |
|
66 |
-static inline uint32_t onas_hshift(uint32_t hash) |
|
67 |
-{ |
|
68 |
- |
|
69 |
- hash = ~hash; |
|
70 |
- |
|
71 |
- hash += (hash << 15); |
|
72 |
- hash ^= (hash >> 12); |
|
73 |
- hash += (hash << 2); |
|
74 |
- hash ^= (hash >> 4); |
|
75 |
- hash += (hash << 3); |
|
76 |
- hash += (hash << 11); |
|
77 |
- hash ^= (hash >> 16); |
|
78 |
- |
|
79 |
- return hash; |
|
80 |
-} |
|
81 |
- |
|
82 |
-static inline int onas_hash(const char *key, size_t keylen, uint32_t size) |
|
83 |
-{ |
|
84 |
- |
|
85 |
- uint32_t hash = 1; |
|
86 |
- uint32_t i; |
|
87 |
- |
|
88 |
- for (i = 0; i < keylen; i++) { |
|
89 |
- hash += key[i]; |
|
90 |
- hash = onas_hshift(hash); |
|
91 |
- } |
|
92 |
- |
|
93 |
- return hash & (size - 1); |
|
94 |
-} |
|
95 |
- |
|
96 |
-int onas_ht_init(struct onas_ht **ht, uint32_t size) |
|
97 |
-{ |
|
98 |
- |
|
99 |
- if (size == 0 || (size & (~size + 1)) != size) return CL_EARG; |
|
100 |
- |
|
101 |
- *ht = (struct onas_ht *)cli_malloc(sizeof(struct onas_ht)); |
|
102 |
- if (!(*ht)) return CL_EMEM; |
|
103 |
- |
|
104 |
- **ht = (struct onas_ht){ |
|
105 |
- .htable = NULL, |
|
106 |
- .size = size, |
|
107 |
- .nbckts = 0, |
|
108 |
- }; |
|
109 |
- |
|
110 |
- if (!((*ht)->htable = (struct onas_bucket **)cli_calloc(size, sizeof(struct onas_bucket *)))) { |
|
111 |
- onas_free_ht(*ht); |
|
112 |
- return CL_EMEM; |
|
113 |
- } |
|
114 |
- |
|
115 |
- return CL_SUCCESS; |
|
116 |
-} |
|
117 |
- |
|
118 |
-void onas_free_ht(struct onas_ht *ht) |
|
119 |
-{ |
|
120 |
- |
|
121 |
- if (!ht || ht->size == 0) return; |
|
122 |
- |
|
123 |
- if (!ht->htable) { |
|
124 |
- free(ht); |
|
125 |
- return; |
|
126 |
- } |
|
127 |
- |
|
128 |
- uint32_t i = 0; |
|
129 |
- for (i = 0; i < ht->size; i++) { |
|
130 |
- onas_free_bucket(ht->htable[i]); |
|
131 |
- ht->htable[i] = NULL; |
|
132 |
- } |
|
133 |
- |
|
134 |
- free(ht->htable); |
|
135 |
- ht->htable = NULL; |
|
136 |
- |
|
137 |
- free(ht); |
|
138 |
- |
|
139 |
- return; |
|
140 |
-} |
|
141 |
- |
|
142 |
-static struct onas_bucket *onas_bucket_init() |
|
143 |
-{ |
|
144 |
- |
|
145 |
- struct onas_bucket *bckt = (struct onas_bucket *)cli_malloc(sizeof(struct onas_bucket)); |
|
146 |
- if (!bckt) return NULL; |
|
147 |
- |
|
148 |
- *bckt = (struct onas_bucket){ |
|
149 |
- .size = 0, |
|
150 |
- .head = NULL, |
|
151 |
- .tail = NULL}; |
|
152 |
- |
|
153 |
- return bckt; |
|
154 |
-} |
|
155 |
- |
|
156 |
-static void onas_free_bucket(struct onas_bucket *bckt) |
|
157 |
-{ |
|
158 |
- |
|
159 |
- if (!bckt) return; |
|
160 |
- |
|
161 |
- uint32_t i = 0; |
|
162 |
- struct onas_element *curr = NULL; |
|
163 |
- |
|
164 |
- for (i = 0; i < bckt->size; i++) { |
|
165 |
- curr = bckt->head; |
|
166 |
- bckt->head = curr->next; |
|
167 |
- onas_free_element(curr); |
|
168 |
- curr = NULL; |
|
169 |
- } |
|
170 |
- |
|
171 |
- free(bckt); |
|
172 |
- |
|
173 |
- return; |
|
174 |
-} |
|
175 |
- |
|
176 |
-struct onas_element *onas_element_init(struct onas_hnode *value, const char *key, size_t klen) |
|
177 |
-{ |
|
178 |
- |
|
179 |
- struct onas_element *elem = (struct onas_element *)cli_malloc(sizeof(struct onas_element)); |
|
180 |
- if (!elem) return NULL; |
|
181 |
- |
|
182 |
- *elem = (struct onas_element){ |
|
183 |
- .key = key, |
|
184 |
- .klen = klen, |
|
185 |
- .data = value, |
|
186 |
- .next = NULL, |
|
187 |
- .prev = NULL}; |
|
188 |
- |
|
189 |
- return elem; |
|
190 |
-} |
|
191 |
- |
|
192 |
-void onas_free_element(struct onas_element *elem) |
|
193 |
-{ |
|
194 |
- |
|
195 |
- if (!elem) return; |
|
196 |
- |
|
197 |
- onas_free_hashnode(elem->data); |
|
198 |
- |
|
199 |
- elem->prev = NULL; |
|
200 |
- elem->next = NULL; |
|
201 |
- |
|
202 |
- free(elem); |
|
203 |
- |
|
204 |
- return; |
|
205 |
-} |
|
206 |
- |
|
207 |
-int onas_ht_insert(struct onas_ht *ht, struct onas_element *elem) |
|
208 |
-{ |
|
209 |
- |
|
210 |
- if (!ht || !elem || !elem->key) return CL_ENULLARG; |
|
211 |
- |
|
212 |
- int idx = onas_hash(elem->key, elem->klen, ht->size); |
|
213 |
- struct onas_bucket *bckt = ht->htable[idx]; |
|
214 |
- |
|
215 |
- int ret = 0; |
|
216 |
- uint32_t bsize = 0; |
|
217 |
- |
|
218 |
- if (bckt == NULL) { |
|
219 |
- ht->htable[idx] = onas_bucket_init(); |
|
220 |
- bckt = ht->htable[idx]; |
|
221 |
- } |
|
222 |
- |
|
223 |
- bsize = bckt->size; |
|
224 |
- ret = onas_bucket_insert(bckt, elem); |
|
225 |
- |
|
226 |
- if (ret == CL_SUCCESS) |
|
227 |
- if (bsize < bckt->size) |
|
228 |
- ht->nbckts++; |
|
229 |
- |
|
230 |
- return ret; |
|
231 |
-} |
|
232 |
- |
|
233 |
-static int onas_bucket_insert(struct onas_bucket *bckt, struct onas_element *elem) |
|
234 |
-{ |
|
235 |
- if (!bckt || !elem) return CL_ENULLARG; |
|
236 |
- |
|
237 |
- if (bckt->size == 0) { |
|
238 |
- bckt->head = elem; |
|
239 |
- bckt->tail = elem; |
|
240 |
- elem->prev = NULL; |
|
241 |
- elem->next = NULL; |
|
242 |
- bckt->size++; |
|
243 |
- } else { |
|
244 |
- struct onas_element *btail = bckt->tail; |
|
245 |
- |
|
246 |
- btail->next = elem; |
|
247 |
- elem->prev = btail; |
|
248 |
- elem->next = NULL; |
|
249 |
- bckt->tail = elem; |
|
250 |
- bckt->size++; |
|
251 |
- } |
|
252 |
- |
|
253 |
- return CL_SUCCESS; |
|
254 |
-} |
|
255 |
- |
|
256 |
-/* Checks if key exists and optionally stores address to the element corresponding to the key within elem */ |
|
257 |
-int onas_ht_get(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem) |
|
258 |
-{ |
|
259 |
- |
|
260 |
- if (elem) *elem = NULL; |
|
261 |
- |
|
262 |
- if (!ht || !key || klen <= 0) return CL_ENULLARG; |
|
263 |
- |
|
264 |
- struct onas_bucket *bckt = ht->htable[onas_hash(key, klen, ht->size)]; |
|
265 |
- |
|
266 |
- if (!bckt || bckt->size == 0) return CL_EARG; |
|
267 |
- |
|
268 |
- struct onas_element *curr = bckt->head; |
|
269 |
- |
|
270 |
- while (curr && strcmp(curr->key, key)) { |
|
271 |
- curr = curr->next; |
|
272 |
- } |
|
273 |
- |
|
274 |
- if (!curr) return CL_EARG; |
|
275 |
- |
|
276 |
- if (elem) *elem = curr; |
|
277 |
- |
|
278 |
- return CL_SUCCESS; |
|
279 |
-} |
|
280 |
- |
|
281 |
-/* Removes the element corresponding to key from the hashtable and optionally returns a pointer to the removed element. */ |
|
282 |
-int onas_ht_remove(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **relem) |
|
283 |
-{ |
|
284 |
- if (!ht || !key || klen <= 0) return CL_ENULLARG; |
|
285 |
- |
|
286 |
- struct onas_bucket *bckt = ht->htable[onas_hash(key, klen, ht->size)]; |
|
287 |
- |
|
288 |
- if (!bckt) return CL_EARG; |
|
289 |
- |
|
290 |
- struct onas_element *elem = NULL; |
|
291 |
- onas_ht_get(ht, key, klen, &elem); |
|
292 |
- |
|
293 |
- if (!elem) return CL_EARG; |
|
294 |
- |
|
295 |
- int ret = onas_bucket_remove(bckt, elem); |
|
296 |
- |
|
297 |
- if (relem) *relem = elem; |
|
298 |
- |
|
299 |
- return ret; |
|
300 |
-} |
|
301 |
- |
|
302 |
-static int onas_bucket_remove(struct onas_bucket *bckt, struct onas_element *elem) |
|
303 |
-{ |
|
304 |
- if (!bckt || !elem) return CL_ENULLARG; |
|
305 |
- |
|
306 |
- struct onas_element *curr = bckt->head; |
|
307 |
- |
|
308 |
- while (curr && curr != elem) { |
|
309 |
- curr = curr->next; |
|
310 |
- } |
|
311 |
- |
|
312 |
- if (!curr) return CL_EARG; |
|
313 |
- |
|
314 |
- if (bckt->head == elem) { |
|
315 |
- bckt->head = elem->next; |
|
316 |
- if (bckt->head) bckt->head->prev = NULL; |
|
317 |
- |
|
318 |
- elem->next = NULL; |
|
319 |
- } else if (bckt->tail == elem) { |
|
320 |
- bckt->tail = elem->prev; |
|
321 |
- if (bckt->tail) bckt->tail->next = NULL; |
|
322 |
- |
|
323 |
- elem->prev = NULL; |
|
324 |
- } else { |
|
325 |
- struct onas_element *tmp = NULL; |
|
326 |
- |
|
327 |
- tmp = elem->prev; |
|
328 |
- if (tmp) { |
|
329 |
- tmp->next = elem->next; |
|
330 |
- tmp = elem->next; |
|
331 |
- tmp->prev = elem->prev; |
|
332 |
- } |
|
333 |
- |
|
334 |
- elem->prev = NULL; |
|
335 |
- elem->next = NULL; |
|
336 |
- } |
|
337 |
- |
|
338 |
- bckt->size--; |
|
339 |
- |
|
340 |
- return CL_SUCCESS; |
|
341 |
-} |
|
342 |
- |
|
343 |
-/* Dealing with hash nodes and list nodes */ |
|
344 |
- |
|
345 |
-/* Function to initialize hashnode. */ |
|
346 |
-static struct onas_hnode *onas_hashnode_init(void) |
|
347 |
-{ |
|
348 |
- struct onas_hnode *hnode = NULL; |
|
349 |
- if (!(hnode = (struct onas_hnode *)cli_malloc(sizeof(struct onas_hnode)))) { |
|
350 |
- return NULL; |
|
351 |
- } |
|
352 |
- |
|
353 |
- *hnode = (struct onas_hnode){ |
|
354 |
- .pathlen = 0, |
|
355 |
- .pathname = NULL, |
|
356 |
- .prnt_pathlen = 0, |
|
357 |
- .prnt_pathname = NULL, |
|
358 |
- .childhead = NULL, |
|
359 |
- .childtail = NULL, |
|
360 |
- .wd = 0, |
|
361 |
- .watched = 0}; |
|
362 |
- |
|
363 |
- if (!(hnode->childhead = (struct onas_lnode *)onas_listnode_init())) { |
|
364 |
- onas_free_hashnode(hnode); |
|
365 |
- return NULL; |
|
366 |
- } |
|
367 |
- |
|
368 |
- if (!(hnode->childtail = (struct onas_lnode *)onas_listnode_init())) { |
|
369 |
- onas_free_hashnode(hnode); |
|
370 |
- return NULL; |
|
371 |
- } |
|
372 |
- |
|
373 |
- hnode->childhead->next = (struct onas_lnode *)hnode->childtail; |
|
374 |
- hnode->childtail->prev = (struct onas_lnode *)hnode->childhead; |
|
375 |
- |
|
376 |
- return hnode; |
|
377 |
-} |
|
378 |
- |
|
379 |
-/* Function to initialize listnode. */ |
|
380 |
-static struct onas_lnode *onas_listnode_init(void) |
|
381 |
-{ |
|
382 |
- struct onas_lnode *lnode = NULL; |
|
383 |
- if (!(lnode = (struct onas_lnode *)cli_malloc(sizeof(struct onas_lnode)))) { |
|
384 |
- return NULL; |
|
385 |
- } |
|
386 |
- |
|
387 |
- *lnode = (struct onas_lnode){ |
|
388 |
- .dirname = NULL, |
|
389 |
- .next = NULL, |
|
390 |
- .prev = NULL}; |
|
391 |
- |
|
392 |
- return lnode; |
|
393 |
-} |
|
394 |
- |
|
395 |
-/* Function to free hashnode. */ |
|
396 |
-void onas_free_hashnode(struct onas_hnode *hnode) |
|
397 |
-{ |
|
398 |
- if (!hnode) return; |
|
399 |
- |
|
400 |
- onas_free_dirlist(hnode->childhead); |
|
401 |
- hnode->childhead = NULL; |
|
402 |
- |
|
403 |
- free(hnode->pathname); |
|
404 |
- hnode->pathname = NULL; |
|
405 |
- |
|
406 |
- free(hnode->prnt_pathname); |
|
407 |
- hnode->prnt_pathname = NULL; |
|
408 |
- |
|
409 |
- free(hnode); |
|
410 |
- |
|
411 |
- return; |
|
412 |
-} |
|
413 |
- |
|
414 |
-/* Function to free list of listnodes. */ |
|
415 |
-void onas_free_dirlist(struct onas_lnode *head) |
|
416 |
-{ |
|
417 |
- if (!head) return; |
|
418 |
- struct onas_lnode *curr = head; |
|
419 |
- struct onas_lnode *tmp = curr; |
|
420 |
- |
|
421 |
- while (curr) { |
|
422 |
- tmp = curr->next; |
|
423 |
- onas_free_listnode(curr); |
|
424 |
- curr = tmp; |
|
425 |
- } |
|
426 |
- |
|
427 |
- return; |
|
428 |
-} |
|
429 |
- |
|
430 |
-/* Function to free a listnode. */ |
|
431 |
-void onas_free_listnode(struct onas_lnode *lnode) |
|
432 |
-{ |
|
433 |
- if (!lnode) return; |
|
434 |
- |
|
435 |
- lnode->next = NULL; |
|
436 |
- lnode->prev = NULL; |
|
437 |
- |
|
438 |
- free(lnode->dirname); |
|
439 |
- lnode->dirname = NULL; |
|
440 |
- |
|
441 |
- free(lnode); |
|
442 |
- |
|
443 |
- return; |
|
444 |
-} |
|
445 |
- |
|
446 |
-static int onas_add_hashnode_child(struct onas_hnode *node, const char *dirname) |
|
447 |
-{ |
|
448 |
- if (!node || !dirname) return CL_ENULLARG; |
|
449 |
- |
|
450 |
- struct onas_lnode *child = onas_listnode_init(); |
|
451 |
- if (!child) return CL_EMEM; |
|
452 |
- |
|
453 |
- size_t n = strlen(dirname); |
|
454 |
- child->dirname = cli_strndup(dirname, n); |
|
455 |
- |
|
456 |
- onas_add_listnode(node->childtail, child); |
|
457 |
- |
|
458 |
- return CL_SUCCESS; |
|
459 |
-} |
|
460 |
- |
|
461 |
-/* Function to add a dir_listnode to a list */ |
|
462 |
-int onas_add_listnode(struct onas_lnode *tail, struct onas_lnode *node) |
|
463 |
-{ |
|
464 |
- if (!tail || !node) return CL_ENULLARG; |
|
465 |
- |
|
466 |
- struct onas_lnode *tmp = tail->prev; |
|
467 |
- |
|
468 |
- tmp->next = node; |
|
469 |
- node->prev = tail->prev; |
|
470 |
- |
|
471 |
- node->next = tail; |
|
472 |
- tail->prev = node; |
|
473 |
- |
|
474 |
- return CL_SUCCESS; |
|
475 |
-} |
|
476 |
- |
|
477 |
-/* Function to remove a listnode based on dirname. */ |
|
478 |
-int onas_rm_listnode(struct onas_lnode *head, const char *dirname) |
|
479 |
-{ |
|
480 |
- if (!dirname || !head) return CL_ENULLARG; |
|
481 |
- |
|
482 |
- struct onas_lnode *curr = head; |
|
483 |
- size_t n = strlen(dirname); |
|
484 |
- |
|
485 |
- while ((curr = curr->next)) { |
|
486 |
- if (!strncmp(curr->dirname, dirname, n)) { |
|
487 |
- struct onas_lnode *tmp = curr->prev; |
|
488 |
- tmp->next = curr->next; |
|
489 |
- tmp = curr->next; |
|
490 |
- tmp->prev = curr->prev; |
|
491 |
- |
|
492 |
- onas_free_listnode(curr); |
|
493 |
- |
|
494 |
- return CL_SUCCESS; |
|
495 |
- } |
|
496 |
- } |
|
497 |
- |
|
498 |
- return -1; |
|
499 |
-} |
|
500 |
- |
|
501 |
-/*** Dealing with parent/child relationships in the table. ***/ |
|
502 |
- |
|
503 |
-/* Determines parent and returns a copy based on full pathname. */ |
|
504 |
-inline static char *onas_get_parent(const char *pathname, size_t len) |
|
505 |
-{ |
|
506 |
- if (!pathname || len <= 1) return NULL; |
|
507 |
- |
|
508 |
- int idx = len - 2; |
|
509 |
- char *ret = NULL; |
|
510 |
- |
|
511 |
- while (idx >= 0 && pathname[idx] != '/') { |
|
512 |
- idx--; |
|
513 |
- } |
|
514 |
- |
|
515 |
- if (idx == 0) { |
|
516 |
- idx++; |
|
517 |
- } |
|
518 |
- |
|
519 |
- ret = cli_strndup(pathname, idx); |
|
520 |
- if (!ret) { |
|
521 |
- errno = ENOMEM; |
|
522 |
- return NULL; |
|
523 |
- } |
|
524 |
- |
|
525 |
- return ret; |
|
526 |
-} |
|
527 |
- |
|
528 |
-/* Gets the index at which the name of directory begins from the full pathname. */ |
|
529 |
-inline static int onas_get_dirname_idx(const char *pathname, size_t len) |
|
530 |
-{ |
|
531 |
- if (!pathname || len <= 1) return -1; |
|
532 |
- |
|
533 |
- int idx = len - 2; |
|
534 |
- |
|
535 |
- while (idx >= 0 && pathname[idx] != '/') { |
|
536 |
- idx--; |
|
537 |
- } |
|
538 |
- |
|
539 |
- if (pathname[idx] == '/') |
|
540 |
- return idx + 1; |
|
541 |
- |
|
542 |
- return idx; |
|
543 |
-} |
|
544 |
- |
|
545 |
-/* Emancipates the specified child from the specified parent. */ |
|
546 |
-int onas_ht_rm_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen) |
|
547 |
-{ |
|
548 |
- |
|
549 |
- if (!ht || !prntpath || prntlen <= 0 || !childpath || childlen <= 1) return CL_ENULLARG; |
|
550 |
- |
|
551 |
- struct onas_element *elem = NULL; |
|
552 |
- struct onas_hnode *hnode = NULL; |
|
553 |
- int idx = onas_get_dirname_idx(childpath, childlen); |
|
554 |
- int ret = 0; |
|
555 |
- |
|
556 |
- if (idx <= 0) return CL_SUCCESS; |
|
557 |
- |
|
558 |
- if (onas_ht_get(ht, prntpath, prntlen, &elem) != CL_SUCCESS) return CL_EARG; |
|
559 |
- |
|
560 |
- hnode = elem->data; |
|
561 |
- |
|
562 |
- if ((ret = onas_rm_listnode(hnode->childhead, &(childpath[idx])))) return CL_EARG; |
|
563 |
- |
|
564 |
- return CL_SUCCESS; |
|
565 |
-} |
|
566 |
- |
|
567 |
-/* The specified parent adds the specified child to its list. */ |
|
568 |
-int onas_ht_add_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen) |
|
569 |
-{ |
|
570 |
- if (!ht || !prntpath || prntlen <= 0 || !childpath || childlen <= 1) return CL_ENULLARG; |
|
571 |
- |
|
572 |
- struct onas_element *elem = NULL; |
|
573 |
- struct onas_hnode *hnode = NULL; |
|
574 |
- int idx = onas_get_dirname_idx(childpath, childlen); |
|
575 |
- |
|
576 |
- if (idx <= 0) return CL_SUCCESS; |
|
577 |
- |
|
578 |
- if (onas_ht_get(ht, prntpath, prntlen, &elem)) return CL_EARG; |
|
579 |
- hnode = elem->data; |
|
580 |
- |
|
581 |
- return onas_add_hashnode_child(hnode, &(childpath[idx])); |
|
582 |
-} |
|
583 |
- |
|
584 |
-/*** Dealing with hierarchy changes. ***/ |
|
585 |
- |
|
586 |
-/* Adds the hierarchy under pathname to the tree and allocates all necessary memory. */ |
|
587 |
-int onas_ht_add_hierarchy(struct onas_ht *ht, const char *pathname) |
|
588 |
-{ |
|
589 |
- if (!ht || !pathname) return CL_ENULLARG; |
|
590 |
- |
|
591 |
- FTS *ftsp = NULL; |
|
592 |
- int ftspopts = FTS_PHYSICAL | FTS_XDEV; |
|
593 |
- FTSENT *curr = NULL; |
|
594 |
- FTSENT *childlist = NULL; |
|
595 |
- |
|
596 |
- size_t len = strlen(pathname); |
|
597 |
- char *prnt = onas_get_parent(pathname, len); |
|
598 |
- if (prnt) onas_ht_add_child(ht, prnt, strlen(prnt), pathname, len); |
|
599 |
- free(prnt); |
|
600 |
- |
|
601 |
- char *const pathargv[] = {(char *)pathname, NULL}; |
|
602 |
- if (!(ftsp = _priv_fts_open(pathargv, ftspopts, NULL))) { |
|
603 |
- logg("!ScanOnAccess: Could not open '%s'\n", pathname); |
|
604 |
- return CL_EARG; |
|
605 |
- } |
|
606 |
- |
|
607 |
- while ((curr = _priv_fts_read(ftsp))) { |
|
608 |
- |
|
609 |
- struct onas_hnode *hnode = NULL; |
|
610 |
- |
|
611 |
- /* May want to handle other options in the future. */ |
|
612 |
- switch (curr->fts_info) { |
|
613 |
- case FTS_D: |
|
614 |
- hnode = onas_hashnode_init(); |
|
615 |
- if (!hnode) return CL_EMEM; |
|
616 |
- |
|
617 |
- hnode->pathlen = curr->fts_pathlen; |
|
618 |
- hnode->pathname = cli_strndup(curr->fts_path, hnode->pathlen); |
|
619 |
- |
|
620 |
- hnode->prnt_pathname = onas_get_parent(hnode->pathname, hnode->pathlen); |
|
621 |
- if (hnode->prnt_pathname) |
|
622 |
- hnode->prnt_pathlen = strlen(hnode->prnt_pathname); |
|
623 |
- else |
|
624 |
- hnode->prnt_pathlen = 0; |
|
625 |
- break; |
|
626 |
- default: |
|
627 |
- continue; |
|
628 |
- } |
|
629 |
- |
|
630 |
- if ((childlist = _priv_fts_children(ftsp, 0))) { |
|
631 |
- do { |
|
632 |
- if (childlist->fts_info == FTS_D) { |
|
633 |
- if (CL_EMEM == onas_add_hashnode_child(hnode, childlist->fts_name)) { |
|
634 |
- onas_free_hashnode(hnode); |
|
635 |
- return CL_EMEM; |
|
636 |
- } |
|
637 |
- } |
|
638 |
- |
|
639 |
- } while ((childlist = childlist->fts_link)); |
|
640 |
- } |
|
641 |
- |
|
642 |
- struct onas_element *elem = onas_element_init(hnode, hnode->pathname, hnode->pathlen); |
|
643 |
- if (!elem) return CL_EMEM; |
|
644 |
- |
|
645 |
- if (onas_ht_insert(ht, elem)) { |
|
646 |
- onas_free_element(elem); |
|
647 |
- return CL_EMEM; |
|
648 |
- } |
|
649 |
- } |
|
650 |
- |
|
651 |
- _priv_fts_close(ftsp); |
|
652 |
- return CL_SUCCESS; |
|
653 |
-} |
|
654 |
- |
|
655 |
-/* Removes the underlying hierarchy from the tree and frees all associated memory. */ |
|
656 |
-int onas_ht_rm_hierarchy(struct onas_ht *ht, const char *pathname, size_t len, int level) |
|
657 |
-{ |
|
658 |
- if (!ht || !pathname || len <= 0) return CL_ENULLARG; |
|
659 |
- |
|
660 |
- struct onas_hnode *hnode = NULL; |
|
661 |
- struct onas_element *elem = NULL; |
|
662 |
- char *prntname = NULL; |
|
663 |
- size_t prntlen = 0; |
|
664 |
- |
|
665 |
- if (onas_ht_get(ht, pathname, len, &elem)) return CL_EARG; |
|
666 |
- |
|
667 |
- hnode = elem->data; |
|
668 |
- |
|
669 |
- struct onas_lnode *curr = hnode->childhead; |
|
670 |
- |
|
671 |
- if (level == 0) { |
|
672 |
- if (!(prntname = onas_get_parent(pathname, len))) return CL_EARG; |
|
673 |
- |
|
674 |
- prntlen = strlen(prntname); |
|
675 |
- if (onas_ht_rm_child(ht, prntname, prntlen, pathname, len)) return CL_EARG; |
|
676 |
- |
|
677 |
- free(prntname); |
|
678 |
- } |
|
679 |
- |
|
680 |
- while (curr->next != hnode->childtail) { |
|
681 |
- curr = curr->next; |
|
682 |
- |
|
683 |
- size_t size = len + strlen(curr->dirname) + 2; |
|
684 |
- char *child_path = (char *)cli_malloc(size); |
|
685 |
- if (child_path == NULL) |
|
686 |
- return CL_EMEM; |
|
687 |
- if (hnode->pathname[len - 1] == '/') |
|
688 |
- snprintf(child_path, size, "%s%s", hnode->pathname, curr->dirname); |
|
689 |
- else |
|
690 |
- snprintf(child_path, size, "%s/%s", hnode->pathname, curr->dirname); |
|
691 |
- onas_ht_rm_hierarchy(ht, child_path, size, level + 1); |
|
692 |
- free(child_path); |
|
693 |
- } |
|
694 |
- |
|
695 |
- onas_ht_remove(ht, pathname, len, NULL); |
|
696 |
- onas_free_element(elem); |
|
697 |
- |
|
698 |
- return CL_SUCCESS; |
|
699 |
-} |
|
700 |
-#endif |
701 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,109 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#ifndef __ONAS_HASH_H |
|
22 |
-#define __ONAS_HASH_H |
|
23 |
- |
|
24 |
-#define ONAS_FANWATCH 0x1 |
|
25 |
-#define ONAS_INWATCH 0x2 |
|
26 |
-#define ONAS_STOPWATCH 0x3 |
|
27 |
- |
|
28 |
-#define ONAS_DEFAULT_HT_SIZE 1 << 18 |
|
29 |
- |
|
30 |
-struct onas_element { |
|
31 |
- |
|
32 |
- const char *key; |
|
33 |
- size_t klen; |
|
34 |
- struct onas_hnode *data; |
|
35 |
- |
|
36 |
- struct onas_element *next; |
|
37 |
- struct onas_element *prev; |
|
38 |
-}; |
|
39 |
- |
|
40 |
-struct onas_bucket { |
|
41 |
- |
|
42 |
- uint32_t size; |
|
43 |
- |
|
44 |
- struct onas_element *head; |
|
45 |
- struct onas_element *tail; |
|
46 |
-}; |
|
47 |
- |
|
48 |
-struct onas_ht { |
|
49 |
- |
|
50 |
- struct onas_bucket **htable; |
|
51 |
- |
|
52 |
- /* Must be a sufficiently high power of two--will not grow. */ |
|
53 |
- uint32_t size; |
|
54 |
- uint32_t nbckts; |
|
55 |
-}; |
|
56 |
- |
|
57 |
-/* Directory node struct for lists */ |
|
58 |
-struct onas_lnode { |
|
59 |
- |
|
60 |
- /* List stuffs */ |
|
61 |
- char *dirname; |
|
62 |
- struct onas_lnode *next; |
|
63 |
- struct onas_lnode *prev; |
|
64 |
-}; |
|
65 |
- |
|
66 |
-/* Directory node struct for hash tables */ |
|
67 |
-struct onas_hnode { |
|
68 |
- |
|
69 |
- /* Path info */ |
|
70 |
- int pathlen; |
|
71 |
- char *pathname; |
|
72 |
- |
|
73 |
- /* Parent info */ |
|
74 |
- int prnt_pathlen; |
|
75 |
- char *prnt_pathname; |
|
76 |
- |
|
77 |
- /* Child head and tail are empty sentinels */ |
|
78 |
- struct onas_lnode *childhead; |
|
79 |
- struct onas_lnode *childtail; |
|
80 |
- |
|
81 |
- /* Inotify watch descriptor */ |
|
82 |
- int wd; |
|
83 |
- |
|
84 |
- /* Watched stuffs */ |
|
85 |
- uint32_t watched; |
|
86 |
-}; |
|
87 |
- |
|
88 |
-void onas_free_ht(struct onas_ht *ht); |
|
89 |
-int onas_ht_init(struct onas_ht **ht, uint32_t table_size); |
|
90 |
-int onas_ht_insert(struct onas_ht *ht, struct onas_element *elem); |
|
91 |
-int onas_ht_remove(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem); |
|
92 |
-int onas_ht_get(struct onas_ht *ht, const char *key, size_t klen, struct onas_element **elem); |
|
93 |
-int onas_ht_rm_hierarchy(struct onas_ht *ht, const char *pathname, size_t len, int level); |
|
94 |
-int onas_ht_add_hierarchy(struct onas_ht *ht, const char *pathname); |
|
95 |
-int onas_ht_add_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen); |
|
96 |
-int onas_ht_rm_child(struct onas_ht *ht, const char *prntpath, size_t prntlen, const char *childpath, size_t childlen); |
|
97 |
- |
|
98 |
-void onas_free_element(struct onas_element *elem); |
|
99 |
-struct onas_element *onas_element_init(struct onas_hnode *value, const char *key, size_t klen); |
|
100 |
- |
|
101 |
-void onas_free_hashnode(struct onas_hnode *hnode); |
|
102 |
- |
|
103 |
-void onas_free_listnode(struct onas_lnode *lnode); |
|
104 |
-int onas_add_listnode(struct onas_lnode *tail, struct onas_lnode *node); |
|
105 |
-int onas_rm_listnode(struct onas_lnode *head, const char *dirname); |
|
106 |
- |
|
107 |
-void onas_free_dirlist(struct onas_lnode *head); |
|
108 |
- |
|
109 |
-#endif |
110 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,120 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2017-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#if HAVE_CONFIG_H |
|
22 |
-#include "clamav-config.h" |
|
23 |
-#endif |
|
24 |
- |
|
25 |
-#if defined(FANOTIFY) |
|
26 |
- |
|
27 |
-#include <stdio.h> |
|
28 |
-#include <stdarg.h> |
|
29 |
-#include <stdlib.h> |
|
30 |
-#include <string.h> |
|
31 |
-//#include <fcntl.h> |
|
32 |
-#include <sys/stat.h> |
|
33 |
-#include <errno.h> |
|
34 |
-#include <pthread.h> |
|
35 |
-//#include <limits.h> |
|
36 |
-#include "libclamav/clamav.h" |
|
37 |
-//#include "libclamav/scanners.h" |
|
38 |
-#include "shared/optparser.h" |
|
39 |
-#include "shared/output.h" |
|
40 |
-//#include "shared/misc.h" |
|
41 |
-//#include "libclamav/others.h" |
|
42 |
- |
|
43 |
-//#include "others.h" |
|
44 |
- |
|
45 |
-#include "onaccess_others.h" |
|
46 |
-#include "clamd/scanner.h" |
|
47 |
- |
|
48 |
-static pthread_mutex_t onas_scan_lock = PTHREAD_MUTEX_INITIALIZER; |
|
49 |
- |
|
50 |
-int onas_fan_checkowner(int pid, const struct optstruct *opts) |
|
51 |
-{ |
|
52 |
- char path[32]; |
|
53 |
- STATBUF sb; |
|
54 |
- const struct optstruct *opt = NULL; |
|
55 |
- const struct optstruct *opt_root = NULL; |
|
56 |
- |
|
57 |
- /* always ignore ourselves */ |
|
58 |
- if (pid == (int)getpid()) { |
|
59 |
- return CHK_SELF; |
|
60 |
- } |
|
61 |
- |
|
62 |
- /* look up options */ |
|
63 |
- opt = optget(opts, "OnAccessExcludeUID"); |
|
64 |
- opt_root = optget(opts, "OnAccessExcludeRootUID"); |
|
65 |
- |
|
66 |
- /* we can return immediately if no uid exclusions were requested */ |
|
67 |
- if (!(opt->enabled || opt_root->enabled)) |
|
68 |
- return CHK_CLEAN; |
|
69 |
- |
|
70 |
- /* perform exclusion checks if we can stat OK */ |
|
71 |
- snprintf(path, sizeof(path), "/proc/%u", pid); |
|
72 |
- if (CLAMSTAT(path, &sb) == 0) { |
|
73 |
- /* check all our non-root UIDs first */ |
|
74 |
- if (opt->enabled) { |
|
75 |
- while (opt) { |
|
76 |
- if (opt->numarg == (long long)sb.st_uid) |
|
77 |
- return CHK_FOUND; |
|
78 |
- opt = opt->nextarg; |
|
79 |
- } |
|
80 |
- } |
|
81 |
- /* finally check root UID */ |
|
82 |
- if (opt_root->enabled) { |
|
83 |
- if (0 == (long long)sb.st_uid) |
|
84 |
- return CHK_FOUND; |
|
85 |
- } |
|
86 |
- } else if (errno == EACCES) { |
|
87 |
- logg("*Permission denied to stat /proc/%d to exclude UIDs... perhaps SELinux denial?\n", pid); |
|
88 |
- } else if (errno == ENOENT) { |
|
89 |
- /* FIXME: should this be configurable? */ |
|
90 |
- logg("$/proc/%d vanished before UIDs could be excluded; scanning anyway\n", pid); |
|
91 |
- } |
|
92 |
- |
|
93 |
- return CHK_CLEAN; |
|
94 |
-} |
|
95 |
- |
|
96 |
-int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo) |
|
97 |
-{ |
|
98 |
- int ret = 0; |
|
99 |
- struct cb_context context; |
|
100 |
- |
|
101 |
- pthread_mutex_lock(&onas_scan_lock); |
|
102 |
- |
|
103 |
- context.filename = fname; |
|
104 |
- context.virsize = 0; |
|
105 |
- context.scandata = NULL; |
|
106 |
- |
|
107 |
- /*ret = cl_scandesc_callback(fd, fname, virname, NULL, engine, options, &context);*/ |
|
108 |
- |
|
109 |
- if (ret) { |
|
110 |
- if (extinfo && context.virsize) |
|
111 |
- logg("ScanOnAccess: %s: %s(%s:%llu) FOUND\n", fname, *virname, context.virhash, context.virsize); |
|
112 |
- else |
|
113 |
- logg("ScanOnAccess: %s: %s FOUND\n", fname, *virname); |
|
114 |
- } |
|
115 |
- |
|
116 |
- pthread_mutex_unlock(&onas_scan_lock); |
|
117 |
- |
|
118 |
- return ret; |
|
119 |
-} |
|
120 |
-#endif |
121 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,36 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2017-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#ifndef __CLAMD_ONAS_OTHERS_H |
|
22 |
-#define __CLAMD_ONAS_OTHERS_H |
|
23 |
- |
|
24 |
-#include "shared/optparser.h" |
|
25 |
-#include "libclamav/clamav.h" |
|
26 |
- |
|
27 |
-typedef enum { |
|
28 |
- CHK_CLEAN, |
|
29 |
- CHK_FOUND, |
|
30 |
- CHK_SELF |
|
31 |
-} cli_check_t; |
|
32 |
- |
|
33 |
-int onas_fan_checkowner(int pid, const struct optstruct *opts); |
|
34 |
-int onas_scan(const char *fname, int fd, const char **virname, const struct cl_engine *engine, struct cl_scan_options *options, int extinfo); |
|
35 |
- |
|
36 |
-#endif |
37 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,691 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2009 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm, aCaB |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#if HAVE_CONFIG_H |
|
23 |
-#include "clamav-config.h" |
|
24 |
-#endif |
|
25 |
- |
|
26 |
-#if defined(C_SOLARIS) |
|
27 |
-#ifndef __EXTENSIONS__ |
|
28 |
-#define __EXTENSIONS__ |
|
29 |
-#endif |
|
30 |
-#endif |
|
31 |
- |
|
32 |
-/* must be first because it may define _XOPEN_SOURCE */ |
|
33 |
-#include "shared/fdpassing.h" |
|
34 |
-#include <stdio.h> |
|
35 |
-#ifdef HAVE_UNISTD_H |
|
36 |
-#include <unistd.h> |
|
37 |
-#endif |
|
38 |
-#include <string.h> |
|
39 |
-#include <errno.h> |
|
40 |
-#include <stdlib.h> |
|
41 |
-#include <sys/types.h> |
|
42 |
-#include <sys/stat.h> |
|
43 |
-#include <fcntl.h> |
|
44 |
-#include <sys/types.h> |
|
45 |
-#ifdef HAVE_SYS_SELECT_H |
|
46 |
-#include <sys/select.h> |
|
47 |
-#endif |
|
48 |
-#ifndef _WIN32 |
|
49 |
-#include <arpa/inet.h> |
|
50 |
-#include <sys/socket.h> |
|
51 |
-#include <sys/un.h> |
|
52 |
-#include <netdb.h> |
|
53 |
-#endif |
|
54 |
- |
|
55 |
-#include "libclamav/clamav.h" |
|
56 |
-#include "libclamav/others.h" |
|
57 |
-#include "shared/actions.h" |
|
58 |
-#include "shared/output.h" |
|
59 |
-#include "shared/misc.h" |
|
60 |
-#include "shared/clamdcom.h" |
|
61 |
- |
|
62 |
-#include "onaccess_proto.h" |
|
63 |
-#include "onaccess_client.h" |
|
64 |
- |
|
65 |
-extern unsigned long int maxstream; |
|
66 |
-int printinfected; |
|
67 |
-extern struct optstruct *clamdopts; |
|
68 |
-#ifndef _WIN32 |
|
69 |
-extern struct sockaddr_un nixsock; |
|
70 |
-#endif |
|
71 |
- |
|
72 |
-static const char *scancmd[] = { "CONTSCAN", "MULTISCAN", "INSTREAM", "FILDES", "ALLMATCHSCAN" }; |
|
73 |
- |
|
74 |
-/* Connects to clamd |
|
75 |
- * Returns a FD or -1 on error */ |
|
76 |
-int dconnect() { |
|
77 |
- int sockd, res; |
|
78 |
- const struct optstruct *opt; |
|
79 |
- struct addrinfo hints, *info, *p; |
|
80 |
- char port[10]; |
|
81 |
- char *ipaddr; |
|
82 |
- |
|
83 |
-#ifndef _WIN32 |
|
84 |
- opt = optget(clamdopts, "LocalSocket"); |
|
85 |
- if (opt->enabled) { |
|
86 |
- if ((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { |
|
87 |
- if (connect(sockd, (struct sockaddr *)&nixsock, sizeof(nixsock)) == 0) |
|
88 |
- return sockd; |
|
89 |
- else { |
|
90 |
- logg("!Could not connect to clamd on LocalSocket %s: %s\n", opt->strarg, strerror(errno)); |
|
91 |
- close(sockd); |
|
92 |
- } |
|
93 |
- } |
|
94 |
- } |
|
95 |
-#endif |
|
96 |
- |
|
97 |
- snprintf(port, sizeof(port), "%lld", optget(clamdopts, "TCPSocket")->numarg); |
|
98 |
- |
|
99 |
- opt = optget(clamdopts, "TCPAddr"); |
|
100 |
- while (opt) { |
|
101 |
- if (opt->enabled) { |
|
102 |
- ipaddr = NULL; |
|
103 |
- if (opt->strarg) |
|
104 |
- ipaddr = (!strcmp(opt->strarg, "any") ? NULL : opt->strarg); |
|
105 |
- |
|
106 |
- memset(&hints, 0x00, sizeof(struct addrinfo)); |
|
107 |
- hints.ai_family = AF_UNSPEC; |
|
108 |
- hints.ai_socktype = SOCK_STREAM; |
|
109 |
- |
|
110 |
- if ((res = getaddrinfo(ipaddr, port, &hints, &info))) { |
|
111 |
- logg("!Could not lookup %s: %s\n", ipaddr ? ipaddr : "", gai_strerror(res)); |
|
112 |
- opt = opt->nextarg; |
|
113 |
- continue; |
|
114 |
- } |
|
115 |
- |
|
116 |
- for (p = info; p != NULL; p = p->ai_next) { |
|
117 |
- if((sockd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { |
|
118 |
- logg("!Can't create the socket: %s\n", strerror(errno)); |
|
119 |
- continue; |
|
120 |
- } |
|
121 |
- |
|
122 |
- if(connect(sockd, p->ai_addr, p->ai_addrlen) < 0) { |
|
123 |
- logg("!Could not connect to clamd on %s: %s\n", opt->strarg, strerror(errno)); |
|
124 |
- closesocket(sockd); |
|
125 |
- continue; |
|
126 |
- } |
|
127 |
- |
|
128 |
- freeaddrinfo(info); |
|
129 |
- return sockd; |
|
130 |
- } |
|
131 |
- |
|
132 |
- freeaddrinfo(info); |
|
133 |
- } |
|
134 |
- opt = opt->nextarg; |
|
135 |
- } |
|
136 |
- |
|
137 |
- return -1; |
|
138 |
-} |
|
139 |
- |
|
140 |
-/* Issues an INSTREAM command to clamd and streams the given file |
|
141 |
- * Returns >0 on success, 0 soft fail, -1 hard fail */ |
|
142 |
-static int send_stream(int sockd, const char *filename) { |
|
143 |
- uint32_t buf[BUFSIZ/sizeof(uint32_t)]; |
|
144 |
- int fd, len; |
|
145 |
- unsigned long int todo = maxstream; |
|
146 |
- |
|
147 |
- if(filename) { |
|
148 |
- if((fd = safe_open(filename, O_RDONLY | O_BINARY))<0) { |
|
149 |
- logg("~%s: Access denied. ERROR\n", filename); |
|
150 |
- return 0; |
|
151 |
- } |
|
152 |
- } else fd = 0; |
|
153 |
- |
|
154 |
- if(sendln(sockd, "zINSTREAM", 10)) { |
|
155 |
- close(fd); |
|
156 |
- return -1; |
|
157 |
- } |
|
158 |
- |
|
159 |
- while((len = read(fd, &buf[1], sizeof(buf) - sizeof(uint32_t))) > 0) { |
|
160 |
- if((unsigned int)len > todo) len = todo; |
|
161 |
- buf[0] = htonl(len); |
|
162 |
- if(sendln(sockd, (const char *)buf, len+sizeof(uint32_t))) { |
|
163 |
- close(fd); |
|
164 |
- return -1; |
|
165 |
- } |
|
166 |
- todo -= len; |
|
167 |
- if(!todo) { |
|
168 |
- len = 0; |
|
169 |
- break; |
|
170 |
- } |
|
171 |
- } |
|
172 |
- close(fd); |
|
173 |
- if(len) { |
|
174 |
- logg("!Failed to read from %s.\n", filename ? filename : "STDIN"); |
|
175 |
- return 0; |
|
176 |
- } |
|
177 |
- *buf=0; |
|
178 |
- sendln(sockd, (const char *)buf, 4); |
|
179 |
- return 1; |
|
180 |
-} |
|
181 |
- |
|
182 |
-#ifdef HAVE_FD_PASSING |
|
183 |
-/* Issues a FILDES command and pass a FD to clamd |
|
184 |
- * Returns >0 on success, 0 soft fail, -1 hard fail */ |
|
185 |
-static int send_fdpass(int sockd, const char *filename) { |
|
186 |
- struct iovec iov[1]; |
|
187 |
- struct msghdr msg; |
|
188 |
- struct cmsghdr *cmsg; |
|
189 |
- unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
|
190 |
- char dummy[]=""; |
|
191 |
- int fd; |
|
192 |
- |
|
193 |
- if(filename) { |
|
194 |
- if((fd = open(filename, O_RDONLY))<0) { |
|
195 |
- logg("~%s: Access denied. ERROR\n", filename); |
|
196 |
- return 0; |
|
197 |
- } |
|
198 |
- } else fd = 0; |
|
199 |
- if(sendln(sockd, "zFILDES", 8)) { |
|
200 |
- close(fd); |
|
201 |
- return -1; |
|
202 |
- } |
|
203 |
- |
|
204 |
- iov[0].iov_base = dummy; |
|
205 |
- iov[0].iov_len = 1; |
|
206 |
- memset(&msg, 0, sizeof(msg)); |
|
207 |
- msg.msg_control = fdbuf; |
|
208 |
- msg.msg_iov = iov; |
|
209 |
- msg.msg_iovlen = 1; |
|
210 |
- msg.msg_controllen = CMSG_LEN(sizeof(int)); |
|
211 |
- cmsg = CMSG_FIRSTHDR(&msg); |
|
212 |
- cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
|
213 |
- cmsg->cmsg_level = SOL_SOCKET; |
|
214 |
- cmsg->cmsg_type = SCM_RIGHTS; |
|
215 |
- *(int *)CMSG_DATA(cmsg) = fd; |
|
216 |
- if(sendmsg(sockd, &msg, 0) == -1) { |
|
217 |
- logg("!FD send failed: %s\n", strerror(errno)); |
|
218 |
- close(fd); |
|
219 |
- return -1; |
|
220 |
- } |
|
221 |
- close(fd); |
|
222 |
- return 1; |
|
223 |
-} |
|
224 |
-#endif |
|
225 |
- |
|
226 |
-/* 0: scan, 1: skip */ |
|
227 |
-static int chkpath(const char *path) |
|
228 |
-{ |
|
229 |
- const struct optstruct *opt; |
|
230 |
- |
|
231 |
- if((opt = optget(clamdopts, "ExcludePath"))->enabled) { |
|
232 |
- while(opt) { |
|
233 |
- if(match_regex(path, opt->strarg) == 1) { |
|
234 |
- if (printinfected != 1) |
|
235 |
- logg("~%s: Excluded\n", path); |
|
236 |
- return 1; |
|
237 |
- } |
|
238 |
- opt = opt->nextarg; |
|
239 |
- } |
|
240 |
- } |
|
241 |
- return 0; |
|
242 |
-} |
|
243 |
- |
|
244 |
-static int ftw_chkpath(const char *path, struct cli_ftw_cbdata *data) |
|
245 |
-{ |
|
246 |
- UNUSEDPARAM(data); |
|
247 |
- return chkpath(path); |
|
248 |
-} |
|
249 |
- |
|
250 |
-/* Sends a proper scan request to clamd and parses its replies |
|
251 |
- * This is used only in non IDSESSION mode |
|
252 |
- * Returns the number of infected files or -1 on error |
|
253 |
- * NOTE: filename may be NULL for STREAM scantype. */ |
|
254 |
-int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors) { |
|
255 |
- int infected = 0, len = 0, beenthere = 0; |
|
256 |
- char *bol, *eol; |
|
257 |
- struct RCVLN rcv; |
|
258 |
- STATBUF sb; |
|
259 |
- |
|
260 |
- if(filename && chkpath(filename)) |
|
261 |
- return 0; |
|
262 |
- recvlninit(&rcv, sockd); |
|
263 |
- |
|
264 |
- switch(scantype) { |
|
265 |
- case MULTI: |
|
266 |
- case CONT: |
|
267 |
- case ALLMATCH: |
|
268 |
- if (!filename) { |
|
269 |
- logg("Filename cannot be NULL for MULTISCAN or CONTSCAN.\n"); |
|
270 |
- return -1; |
|
271 |
- } |
|
272 |
- len = strlen(filename) + strlen(scancmd[scantype]) + 3; |
|
273 |
- if (!(bol = malloc(len))) { |
|
274 |
- logg("!Cannot allocate a command buffer: %s\n", strerror(errno)); |
|
275 |
- return -1; |
|
276 |
- } |
|
277 |
- sprintf(bol, "z%s %s", scancmd[scantype], filename); |
|
278 |
- if(sendln(sockd, bol, len)) { |
|
279 |
- free(bol); |
|
280 |
- return -1; |
|
281 |
- } |
|
282 |
- free(bol); |
|
283 |
- break; |
|
284 |
- |
|
285 |
- case STREAM: |
|
286 |
- /* NULL filename safe in send_stream() */ |
|
287 |
- len = send_stream(sockd, filename); |
|
288 |
- break; |
|
289 |
-#ifdef HAVE_FD_PASSING |
|
290 |
- case FILDES: |
|
291 |
- /* NULL filename safe in send_fdpass() */ |
|
292 |
- len = send_fdpass(sockd, filename); |
|
293 |
- break; |
|
294 |
-#endif |
|
295 |
- } |
|
296 |
- |
|
297 |
- if(len <=0) { |
|
298 |
- *printok = 0; |
|
299 |
- if(errors) |
|
300 |
- (*errors)++; |
|
301 |
- return len; |
|
302 |
- } |
|
303 |
- |
|
304 |
- while((len = recvln(&rcv, &bol, &eol))) { |
|
305 |
- if(len == -1) return -1; |
|
306 |
- beenthere = 1; |
|
307 |
- if(!filename) logg("~%s\n", bol); |
|
308 |
- if(len > 7) { |
|
309 |
- char *colon = strrchr(bol, ':'); |
|
310 |
- if(colon && colon[1] != ' ') { |
|
311 |
- char *br; |
|
312 |
- *colon = 0; |
|
313 |
- br = strrchr(bol, '('); |
|
314 |
- if(br) |
|
315 |
- *br = 0; |
|
316 |
- colon = strrchr(bol, ':'); |
|
317 |
- } |
|
318 |
- if(!colon) { |
|
319 |
- char * unkco = "UNKNOWN COMMAND"; |
|
320 |
- if (!strncmp(bol, unkco, sizeof(unkco) - 1)) |
|
321 |
- logg("clamd replied \"UNKNOWN COMMAND\". Command was %s\n", |
|
322 |
- (scantype < 0 || scantype > MAX_SCANTYPE) ? "unidentified" : |
|
323 |
- scancmd[scantype]); |
|
324 |
- else |
|
325 |
- logg("Failed to parse reply: \"%s\"\n", bol); |
|
326 |
- return -1; |
|
327 |
- } else if(!memcmp(eol - 7, " FOUND", 6)) { |
|
328 |
- static char last_filename[PATH_MAX+1] = {'\0'}; |
|
329 |
- *(eol - 7) = 0; |
|
330 |
- *printok = 0; |
|
331 |
- if (scantype != ALLMATCH) { |
|
332 |
- infected++; |
|
333 |
- } else { |
|
334 |
- if (filename != NULL && strcmp(filename, last_filename)) { |
|
335 |
- infected++; |
|
336 |
- strncpy(last_filename, filename, PATH_MAX); |
|
337 |
- last_filename[PATH_MAX] = '\0'; |
|
338 |
- } |
|
339 |
- } |
|
340 |
- if(filename) { |
|
341 |
- if(scantype >= STREAM) { |
|
342 |
- logg("~%s%s FOUND\n", filename, colon); |
|
343 |
- if(action) action(filename); |
|
344 |
- } else { |
|
345 |
- logg("~%s FOUND\n", bol); |
|
346 |
- *colon = '\0'; |
|
347 |
- if(action) |
|
348 |
- action(bol); |
|
349 |
- } |
|
350 |
- } |
|
351 |
- } else if(!memcmp(eol-7, " ERROR", 6)) { |
|
352 |
- if(errors) |
|
353 |
- (*errors)++; |
|
354 |
- *printok = 0; |
|
355 |
- if(filename) { |
|
356 |
- if(scantype >= STREAM) |
|
357 |
- logg("~%s%s\n", filename, colon); |
|
358 |
- else |
|
359 |
- logg("~%s\n", bol); |
|
360 |
- } |
|
361 |
- } |
|
362 |
- } |
|
363 |
- } |
|
364 |
- if(!beenthere) { |
|
365 |
- if (!filename) { |
|
366 |
- logg("STDIN: noreply from clamd\n."); |
|
367 |
- return -1; |
|
368 |
- } |
|
369 |
- if(CLAMSTAT(filename, &sb) == -1) { |
|
370 |
- logg("~%s: stat() failed with %s, clamd may not be responding\n", |
|
371 |
- filename, strerror(errno)); |
|
372 |
- return -1; |
|
373 |
- } |
|
374 |
- if(!S_ISDIR(sb.st_mode)) { |
|
375 |
- logg("~%s: no reply from clamd\n", filename); |
|
376 |
- return -1; |
|
377 |
- } |
|
378 |
- } |
|
379 |
- return infected; |
|
380 |
-} |
|
381 |
- |
|
382 |
-/* Used by serial_callback() */ |
|
383 |
-struct client_serial_data { |
|
384 |
- int infected; |
|
385 |
- int scantype; |
|
386 |
- int printok; |
|
387 |
- int files; |
|
388 |
- int errors; |
|
389 |
-}; |
|
390 |
- |
|
391 |
-/* FTW callback for scanning in non IDSESSION mode |
|
392 |
- * Returns SUCCESS or BREAK on success, CL_EXXX on error */ |
|
393 |
-static int serial_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) { |
|
394 |
- struct client_serial_data *c = (struct client_serial_data *)data->data; |
|
395 |
- int sockd, ret; |
|
396 |
- const char *f = filename; |
|
397 |
- |
|
398 |
- UNUSEDPARAM(sb); |
|
399 |
- |
|
400 |
- if(chkpath(path)) |
|
401 |
- return CL_SUCCESS; |
|
402 |
- c->files++; |
|
403 |
- switch(reason) { |
|
404 |
- case error_stat: |
|
405 |
- logg("!Can't access file %s\n", path); |
|
406 |
- c->errors++; |
|
407 |
- return CL_SUCCESS; |
|
408 |
- case error_mem: |
|
409 |
- logg("!Memory allocation failed in ftw\n"); |
|
410 |
- c->errors++; |
|
411 |
- return CL_EMEM; |
|
412 |
- case warning_skipped_dir: |
|
413 |
- logg("^Directory recursion limit reached\n"); |
|
414 |
- case warning_skipped_link: |
|
415 |
- return CL_SUCCESS; |
|
416 |
- case warning_skipped_special: |
|
417 |
- logg("^%s: Not supported file type\n", path); |
|
418 |
- c->errors++; |
|
419 |
- return CL_SUCCESS; |
|
420 |
- case visit_directory_toplev: |
|
421 |
- if(c->scantype >= STREAM) |
|
422 |
- return CL_SUCCESS; |
|
423 |
- f = path; |
|
424 |
- filename = NULL; |
|
425 |
- case visit_file: |
|
426 |
- break; |
|
427 |
- } |
|
428 |
- |
|
429 |
- if((sockd = dconnect()) < 0) { |
|
430 |
- if(filename) free(filename); |
|
431 |
- c->errors++; |
|
432 |
- return CL_EOPEN; |
|
433 |
- } |
|
434 |
- ret = dsresult(sockd, c->scantype, f, &c->printok, &c->errors); |
|
435 |
- if(filename) free(filename); |
|
436 |
- closesocket(sockd); |
|
437 |
- if(ret < 0) { |
|
438 |
- c->errors++; |
|
439 |
- return CL_EOPEN; |
|
440 |
- } |
|
441 |
- c->infected += ret; |
|
442 |
- if(reason == visit_directory_toplev) |
|
443 |
- return CL_BREAK; |
|
444 |
- return CL_SUCCESS; |
|
445 |
-} |
|
446 |
- |
|
447 |
-/* Non-IDSESSION handler |
|
448 |
- * Returns non zero for serious errors, zero otherwise */ |
|
449 |
-int serial_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags) { |
|
450 |
- struct cli_ftw_cbdata data; |
|
451 |
- struct client_serial_data cdata; |
|
452 |
- int ftw; |
|
453 |
- |
|
454 |
- cdata.infected = 0; |
|
455 |
- cdata.files = 0; |
|
456 |
- cdata.errors = 0; |
|
457 |
- cdata.printok = printinfected^1; |
|
458 |
- cdata.scantype = scantype; |
|
459 |
- data.data = &cdata; |
|
460 |
- |
|
461 |
- ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, serial_callback, &data, ftw_chkpath); |
|
462 |
- *infected += cdata.infected; |
|
463 |
- *err += cdata.errors; |
|
464 |
- |
|
465 |
- if(!cdata.errors && (ftw == CL_SUCCESS || ftw == CL_BREAK)) { |
|
466 |
- if(cdata.printok) |
|
467 |
- logg("~%s: OK\n", file); |
|
468 |
- return 0; |
|
469 |
- } else if(!cdata.files) { |
|
470 |
- logg("~%s: No files scanned\n", file); |
|
471 |
- return 0; |
|
472 |
- } |
|
473 |
- return 1; |
|
474 |
-} |
|
475 |
- |
|
476 |
-/* Used in IDSESSION mode */ |
|
477 |
-struct client_parallel_data { |
|
478 |
- int infected; |
|
479 |
- int files; |
|
480 |
- int errors; |
|
481 |
- int scantype; |
|
482 |
- int sockd; |
|
483 |
- int lastid; |
|
484 |
- int printok; |
|
485 |
- struct SCANID { |
|
486 |
- unsigned int id; |
|
487 |
- const char *file; |
|
488 |
- struct SCANID *next; |
|
489 |
- } *ids; |
|
490 |
-}; |
|
491 |
- |
|
492 |
-/* Sends a proper scan request to clamd and parses its replies |
|
493 |
- * This is used only in IDSESSION mode |
|
494 |
- * Returns 0 on success, 1 on hard failures, 2 on len == 0 (bb#1717) */ |
|
495 |
-static int dspresult(struct client_parallel_data *c) { |
|
496 |
- const char *filename; |
|
497 |
- char *bol, *eol; |
|
498 |
- unsigned int rid; |
|
499 |
- int len; |
|
500 |
- struct SCANID **id = NULL; |
|
501 |
- struct RCVLN rcv; |
|
502 |
- |
|
503 |
- recvlninit(&rcv, c->sockd); |
|
504 |
- do { |
|
505 |
- len = recvln(&rcv, &bol, &eol); |
|
506 |
- if(len < 0) return 1; |
|
507 |
- if(!len) return 2; |
|
508 |
- if((rid = atoi(bol))) { |
|
509 |
- id = &c->ids; |
|
510 |
- while(*id) { |
|
511 |
- if((*id)->id == rid) break; |
|
512 |
- id = &((*id)->next); |
|
513 |
- } |
|
514 |
- if(!*id) id = NULL; |
|
515 |
- } |
|
516 |
- if(!id) { |
|
517 |
- logg("!Bogus session id from clamd\n"); |
|
518 |
- return 1; |
|
519 |
- } |
|
520 |
- filename = (*id)->file; |
|
521 |
- if(len > 7) { |
|
522 |
- char *colon = strrchr(bol, ':'); |
|
523 |
- if(!colon) { |
|
524 |
- logg("!Failed to parse reply\n"); |
|
525 |
- free((void *)filename); |
|
526 |
- return 1; |
|
527 |
- } else if(!memcmp(eol - 7, " FOUND", 6)) { |
|
528 |
- c->infected++; |
|
529 |
- c->printok = 0; |
|
530 |
- logg("~%s%s\n", filename, colon); |
|
531 |
- if(action) action(filename); |
|
532 |
- } else if(!memcmp(eol-7, " ERROR", 6)) { |
|
533 |
- c->errors++; |
|
534 |
- c->printok = 0; |
|
535 |
- logg("~%s%s\n", filename, colon); |
|
536 |
- } |
|
537 |
- } |
|
538 |
- free((void *)filename); |
|
539 |
- bol = (char *)*id; |
|
540 |
- *id = (*id)->next; |
|
541 |
- free(bol); |
|
542 |
- } while(rcv.cur != rcv.buf); /* clamd sends whole lines, so, on partial lines, we just assume |
|
543 |
- more data can be recv()'d with close to zero latency */ |
|
544 |
- return 0; |
|
545 |
-} |
|
546 |
- |
|
547 |
-/* FTW callback for scanning in IDSESSION mode |
|
548 |
- * Returns SUCCESS on success, CL_EXXX or BREAK on error */ |
|
549 |
-static int parallel_callback(STATBUF *sb, char *filename, const char *path, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data) { |
|
550 |
- struct client_parallel_data *c = (struct client_parallel_data *)data->data; |
|
551 |
- struct SCANID *cid; |
|
552 |
- int res = CL_CLEAN; |
|
553 |
- |
|
554 |
- UNUSEDPARAM(sb); |
|
555 |
- |
|
556 |
- if(chkpath(path)) |
|
557 |
- return CL_SUCCESS; |
|
558 |
- c->files++; |
|
559 |
- switch(reason) { |
|
560 |
- case error_stat: |
|
561 |
- logg("!Can't access file %s\n", path); |
|
562 |
- c->errors++; |
|
563 |
- return CL_SUCCESS; |
|
564 |
- case error_mem: |
|
565 |
- logg("!Memory allocation failed in ftw\n"); |
|
566 |
- c->errors++; |
|
567 |
- return CL_EMEM; |
|
568 |
- case warning_skipped_dir: |
|
569 |
- logg("^Directory recursion limit reached\n"); |
|
570 |
- return CL_SUCCESS; |
|
571 |
- case warning_skipped_special: |
|
572 |
- logg("^%s: Not supported file type\n", path); |
|
573 |
- c->errors++; |
|
574 |
- case warning_skipped_link: |
|
575 |
- case visit_directory_toplev: |
|
576 |
- return CL_SUCCESS; |
|
577 |
- case visit_file: |
|
578 |
- break; |
|
579 |
- } |
|
580 |
- |
|
581 |
- while(1) { |
|
582 |
- /* consume all the available input to let some of the clamd |
|
583 |
- * threads blocked on send() to be dead. |
|
584 |
- * by doing so we shouldn't deadlock on the next recv() */ |
|
585 |
- fd_set rfds, wfds; |
|
586 |
- FD_ZERO(&rfds); |
|
587 |
- FD_SET(c->sockd, &rfds); |
|
588 |
- FD_ZERO(&wfds); |
|
589 |
- FD_SET(c->sockd, &wfds); |
|
590 |
- if(select(c->sockd + 1, &rfds, &wfds, NULL, NULL) < 0) { |
|
591 |
- if(errno == EINTR) continue; |
|
592 |
- free(filename); |
|
593 |
- logg("!select() failed during session: %s\n", strerror(errno)); |
|
594 |
- return CL_BREAK; |
|
595 |
- } |
|
596 |
- if(FD_ISSET(c->sockd, &rfds)) { |
|
597 |
- if(dspresult(c)) { |
|
598 |
- free(filename); |
|
599 |
- return CL_BREAK; |
|
600 |
- } else continue; |
|
601 |
- } |
|
602 |
- if(FD_ISSET(c->sockd, &wfds)) break; |
|
603 |
- } |
|
604 |
- |
|
605 |
- cid = (struct SCANID *)malloc(sizeof(struct SCANID)); |
|
606 |
- if(!cid) { |
|
607 |
- free(filename); |
|
608 |
- logg("!Failed to allocate scanid entry: %s\n", strerror(errno)); |
|
609 |
- return CL_BREAK; |
|
610 |
- } |
|
611 |
- cid->id = ++c->lastid; |
|
612 |
- cid->file = filename; |
|
613 |
- cid->next = c->ids; |
|
614 |
- c->ids = cid; |
|
615 |
- |
|
616 |
- switch(c->scantype) { |
|
617 |
-#ifdef HAVE_FD_PASSING |
|
618 |
- case FILDES: |
|
619 |
- res = send_fdpass(c->sockd, filename); |
|
620 |
- break; |
|
621 |
-#endif |
|
622 |
- case STREAM: |
|
623 |
- res = send_stream(c->sockd, filename); |
|
624 |
- break; |
|
625 |
- } |
|
626 |
- if(res <= 0) { |
|
627 |
- c->printok = 0; |
|
628 |
- c->errors++; |
|
629 |
- c->ids = cid->next; |
|
630 |
- c->lastid--; |
|
631 |
- free(cid); |
|
632 |
- free(filename); |
|
633 |
- return res ? CL_BREAK : CL_SUCCESS; |
|
634 |
- } |
|
635 |
- return CL_SUCCESS; |
|
636 |
-} |
|
637 |
- |
|
638 |
-/* IDSESSION handler |
|
639 |
- * Returns non zero for serious errors, zero otherwise */ |
|
640 |
-int parallel_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags) { |
|
641 |
- struct cli_ftw_cbdata data; |
|
642 |
- struct client_parallel_data cdata; |
|
643 |
- int ftw; |
|
644 |
- |
|
645 |
- if((cdata.sockd = dconnect()) < 0) |
|
646 |
- return 1; |
|
647 |
- |
|
648 |
- if(sendln(cdata.sockd, "zIDSESSION", 11)) { |
|
649 |
- closesocket(cdata.sockd); |
|
650 |
- return 1; |
|
651 |
- } |
|
652 |
- |
|
653 |
- cdata.infected = 0; |
|
654 |
- cdata.files = 0; |
|
655 |
- cdata.errors = 0; |
|
656 |
- cdata.scantype = scantype; |
|
657 |
- cdata.lastid = 0; |
|
658 |
- cdata.ids = NULL; |
|
659 |
- cdata.printok = printinfected^1; |
|
660 |
- data.data = &cdata; |
|
661 |
- |
|
662 |
- ftw = cli_ftw(file, flags, maxlevel ? maxlevel : INT_MAX, parallel_callback, &data, ftw_chkpath); |
|
663 |
- |
|
664 |
- if(ftw != CL_SUCCESS) { |
|
665 |
- *err += cdata.errors; |
|
666 |
- *infected += cdata.infected; |
|
667 |
- closesocket(cdata.sockd); |
|
668 |
- return 1; |
|
669 |
- } |
|
670 |
- |
|
671 |
- sendln(cdata.sockd, "zEND", 5); |
|
672 |
- while(cdata.ids && !dspresult(&cdata)); |
|
673 |
- closesocket(cdata.sockd); |
|
674 |
- |
|
675 |
- *infected += cdata.infected; |
|
676 |
- *err += cdata.errors; |
|
677 |
- |
|
678 |
- if(cdata.ids) { |
|
679 |
- logg("!Clamd closed the connection before scanning all files.\n"); |
|
680 |
- return 1; |
|
681 |
- } |
|
682 |
- if(cdata.errors) |
|
683 |
- return 1; |
|
684 |
- |
|
685 |
- if(!cdata.files) |
|
686 |
- return 0; |
|
687 |
- |
|
688 |
- if(cdata.printok) |
|
689 |
- logg("~%s: OK\n", file); |
|
690 |
- return 0; |
|
691 |
-} |
692 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,30 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * Copyright (C) 2009 Sourcefire, Inc. |
|
4 |
- * |
|
5 |
- * Authors: Tomasz Kojm, aCaB |
|
6 |
- * |
|
7 |
- * This program is free software; you can redistribute it and/or modify |
|
8 |
- * it under the terms of the GNU General Public License version 2 as |
|
9 |
- * published by the Free Software Foundation. |
|
10 |
- * |
|
11 |
- * This program is distributed in the hope that it will be useful, |
|
12 |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
- * GNU General Public License for more details. |
|
15 |
- * |
|
16 |
- * You should have received a copy of the GNU General Public License |
|
17 |
- * along with this program; if not, write to the Free Software |
|
18 |
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
- * MA 02110-1301, USA. |
|
20 |
- */ |
|
21 |
- |
|
22 |
-#ifndef ONAS_PROTO_H |
|
23 |
-#define ONAS_PROTO_H |
|
24 |
-#include "shared/misc.h" |
|
25 |
- |
|
26 |
-int dconnect(void); |
|
27 |
-int serial_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags); |
|
28 |
-int parallel_client_scan(char *file, int scantype, int *infected, int *err, int maxlevel, int flags); |
|
29 |
-int dsresult(int sockd, int scantype, const char *filename, int *printok, int *errors); |
|
30 |
-#endif |
31 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,167 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#if HAVE_CONFIG_H |
|
22 |
-#include "clamav-config.h" |
|
23 |
-#endif |
|
24 |
- |
|
25 |
-#if defined(FANOTIFY) |
|
26 |
- |
|
27 |
-#include <stdio.h> |
|
28 |
-#include <unistd.h> |
|
29 |
-#include <string.h> |
|
30 |
-#include <fcntl.h> |
|
31 |
-#include <signal.h> |
|
32 |
-#include <pthread.h> |
|
33 |
- |
|
34 |
-#include "shared/optparser.h" |
|
35 |
-#include "shared/output.h" |
|
36 |
- |
|
37 |
-#include "others.h" |
|
38 |
-#include "clamd/priv_fts.h" |
|
39 |
-#include "onaccess_others.h" |
|
40 |
-#include "onaccess_scth.h" |
|
41 |
-#include "onaccess_others.h" |
|
42 |
- |
|
43 |
-#include "libclamav/clamav.h" |
|
44 |
- |
|
45 |
-static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg); |
|
46 |
-static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg); |
|
47 |
-static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg); |
|
48 |
- |
|
49 |
-static void onas_scth_exit(int sig); |
|
50 |
- |
|
51 |
-static void onas_scth_exit(int sig) |
|
52 |
-{ |
|
53 |
- logg("*ScanOnAccess: onas_scth_exit(), signal %d\n", sig); |
|
54 |
- |
|
55 |
- pthread_exit(NULL); |
|
56 |
-} |
|
57 |
- |
|
58 |
-static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg) |
|
59 |
-{ |
|
60 |
- int ret = 0; |
|
61 |
- const char *virname = NULL; |
|
62 |
- |
|
63 |
- return onas_scan(fname, fd, &virname, tharg->engine, tharg->options, extinfo); |
|
64 |
-} |
|
65 |
- |
|
66 |
-static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg) |
|
67 |
-{ |
|
68 |
- FTS *ftsp = NULL; |
|
69 |
- int fd; |
|
70 |
- int ftspopts = FTS_PHYSICAL | FTS_XDEV; |
|
71 |
- int extinfo; |
|
72 |
- int ret; |
|
73 |
- FTSENT *curr = NULL; |
|
74 |
- |
|
75 |
- extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
76 |
- |
|
77 |
- char *const pathargv[] = {(char *)pathname, NULL}; |
|
78 |
- if (!(ftsp = _priv_fts_open(pathargv, ftspopts, NULL))) return CL_EOPEN; |
|
79 |
- |
|
80 |
- while ((curr = _priv_fts_read(ftsp))) { |
|
81 |
- if (curr->fts_info != FTS_D) { |
|
82 |
- if ((fd = safe_open(curr->fts_path, O_RDONLY | O_BINARY)) == -1) |
|
83 |
- return CL_EOPEN; |
|
84 |
- |
|
85 |
- if (onas_scth_scanfile(curr->fts_path, fd, extinfo, tharg) == CL_VIRUS) |
|
86 |
- ; |
|
87 |
- ret = CL_VIRUS; |
|
88 |
- |
|
89 |
- close(fd); |
|
90 |
- } |
|
91 |
- } |
|
92 |
- |
|
93 |
- return ret; |
|
94 |
-} |
|
95 |
- |
|
96 |
-static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg) |
|
97 |
-{ |
|
98 |
- int fd; |
|
99 |
- int extinfo; |
|
100 |
- int ret; |
|
101 |
- |
|
102 |
- if (!pathname) return CL_ENULLARG; |
|
103 |
- |
|
104 |
- extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
105 |
- |
|
106 |
- if ((fd = safe_open(pathname, O_RDONLY | O_BINARY)) == -1) |
|
107 |
- return CL_EOPEN; |
|
108 |
- ret = onas_scth_scanfile(pathname, fd, extinfo, tharg); |
|
109 |
- |
|
110 |
- close(fd); |
|
111 |
- |
|
112 |
- return ret; |
|
113 |
-} |
|
114 |
- |
|
115 |
-void *onas_scan_th(void *arg) |
|
116 |
-{ |
|
117 |
- struct scth_thrarg *tharg = (struct scth_thrarg *)arg; |
|
118 |
- sigset_t sigset; |
|
119 |
- struct sigaction act; |
|
120 |
- |
|
121 |
- /* ignore all signals except SIGUSR1 */ |
|
122 |
- sigfillset(&sigset); |
|
123 |
- sigdelset(&sigset, SIGUSR1); |
|
124 |
- /* The behavior of a process is undefined after it ignores a |
|
125 |
- * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
126 |
- sigdelset(&sigset, SIGFPE); |
|
127 |
- sigdelset(&sigset, SIGILL); |
|
128 |
- sigdelset(&sigset, SIGSEGV); |
|
129 |
-#ifdef SIGBUS |
|
130 |
- sigdelset(&sigset, SIGBUS); |
|
131 |
-#endif |
|
132 |
- pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
133 |
- memset(&act, 0, sizeof(struct sigaction)); |
|
134 |
- act.sa_handler = onas_scth_exit; |
|
135 |
- sigfillset(&(act.sa_mask)); |
|
136 |
- sigaction(SIGUSR1, &act, NULL); |
|
137 |
- sigaction(SIGSEGV, &act, NULL); |
|
138 |
- |
|
139 |
- if (NULL == tharg || NULL == tharg->pathname || NULL == tharg->opts || NULL == tharg->engine) { |
|
140 |
- logg("ScanOnAccess: Invalid thread arguments for extra scanning\n"); |
|
141 |
- goto done; |
|
142 |
- } |
|
143 |
- |
|
144 |
- if (tharg->extra_options & ONAS_SCTH_ISDIR) { |
|
145 |
- logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", tharg->pathname); |
|
146 |
- onas_scth_handle_dir(tharg->pathname, tharg); |
|
147 |
- } else if (tharg->extra_options & ONAS_SCTH_ISFILE) { |
|
148 |
- logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", tharg->pathname); |
|
149 |
- onas_scth_handle_file(tharg->pathname, tharg); |
|
150 |
- } |
|
151 |
- |
|
152 |
-done: |
|
153 |
- if (NULL != tharg->pathname) { |
|
154 |
- free(tharg->pathname); |
|
155 |
- tharg->pathname = NULL; |
|
156 |
- } |
|
157 |
- if (NULL != tharg->options) { |
|
158 |
- free(tharg->options); |
|
159 |
- tharg->options = NULL; |
|
160 |
- } |
|
161 |
- if (NULL != tharg) { |
|
162 |
- free(tharg); |
|
163 |
- } |
|
164 |
- |
|
165 |
- return NULL; |
|
166 |
-} |
|
167 |
-#endif |
168 | 1 |
deleted file mode 100644 |
... | ... |
@@ -1,40 +0,0 @@ |
1 |
-/* |
|
2 |
- * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 |
- * |
|
4 |
- * Authors: Mickey Sola |
|
5 |
- * |
|
6 |
- * This program is free software; you can redistribute it and/or modify |
|
7 |
- * it under the terms of the GNU General Public License version 2 as |
|
8 |
- * published by the Free Software Foundation. |
|
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, Fifth Floor, Boston, |
|
18 |
- * MA 02110-1301, USA. |
|
19 |
- */ |
|
20 |
- |
|
21 |
-#ifndef __ONAS_SCTH_H |
|
22 |
-#define __ONAS_SCTH_H |
|
23 |
- |
|
24 |
-#include "shared/optparser.h" |
|
25 |
-#include "libclamav/clamav.h" |
|
26 |
- |
|
27 |
-#define ONAS_SCTH_ISDIR 0x01 |
|
28 |
-#define ONAS_SCTH_ISFILE 0x02 |
|
29 |
- |
|
30 |
-struct scth_thrarg { |
|
31 |
- uint32_t extra_options; |
|
32 |
- struct cl_scan_options *options; |
|
33 |
- const struct optstruct *opts; |
|
34 |
- const struct cl_engine *engine; |
|
35 |
- char *pathname; |
|
36 |
-}; |
|
37 |
- |
|
38 |
-void *onas_scan_th(void *arg); |
|
39 |
- |
|
40 |
-#endif |
41 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,167 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#if HAVE_CONFIG_H |
|
21 |
+#include "clamav-config.h" |
|
22 |
+#endif |
|
23 |
+ |
|
24 |
+#if defined(FANOTIFY) |
|
25 |
+ |
|
26 |
+#include <stdio.h> |
|
27 |
+#include <unistd.h> |
|
28 |
+#include <string.h> |
|
29 |
+#include <fcntl.h> |
|
30 |
+#include <signal.h> |
|
31 |
+#include <pthread.h> |
|
32 |
+ |
|
33 |
+#include "shared/optparser.h" |
|
34 |
+#include "shared/output.h" |
|
35 |
+ |
|
36 |
+#include "others.h" |
|
37 |
+#include "clamd/priv_fts.h" |
|
38 |
+#include "../misc/onaccess_others.h" |
|
39 |
+#include "onaccess_scth.h" |
|
40 |
+//#include "onaccess_others.h" |
|
41 |
+ |
|
42 |
+#include "libclamav/clamav.h" |
|
43 |
+ |
|
44 |
+static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg); |
|
45 |
+static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg); |
|
46 |
+static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg); |
|
47 |
+ |
|
48 |
+static void onas_scth_exit(int sig); |
|
49 |
+ |
|
50 |
+static void onas_scth_exit(int sig) |
|
51 |
+{ |
|
52 |
+ logg("*ScanOnAccess: onas_scth_exit(), signal %d\n", sig); |
|
53 |
+ |
|
54 |
+ pthread_exit(NULL); |
|
55 |
+} |
|
56 |
+ |
|
57 |
+static int onas_scth_scanfile(const char *fname, int fd, int extinfo, struct scth_thrarg *tharg) |
|
58 |
+{ |
|
59 |
+ int ret = 0; |
|
60 |
+ const char *virname = NULL; |
|
61 |
+ |
|
62 |
+ return onas_scan(fname, fd, &virname, tharg->engine, tharg->options, extinfo); |
|
63 |
+} |
|
64 |
+ |
|
65 |
+static int onas_scth_handle_dir(const char *pathname, struct scth_thrarg *tharg) |
|
66 |
+{ |
|
67 |
+ FTS *ftsp = NULL; |
|
68 |
+ int fd; |
|
69 |
+ int ftspopts = FTS_PHYSICAL | FTS_XDEV; |
|
70 |
+ int extinfo; |
|
71 |
+ int ret; |
|
72 |
+ FTSENT *curr = NULL; |
|
73 |
+ |
|
74 |
+ extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
75 |
+ |
|
76 |
+ char *const pathargv[] = {(char *)pathname, NULL}; |
|
77 |
+ if (!(ftsp = _priv_fts_open(pathargv, ftspopts, NULL))) return CL_EOPEN; |
|
78 |
+ |
|
79 |
+ while ((curr = _priv_fts_read(ftsp))) { |
|
80 |
+ if (curr->fts_info != FTS_D) { |
|
81 |
+ if ((fd = safe_open(curr->fts_path, O_RDONLY | O_BINARY)) == -1) |
|
82 |
+ return CL_EOPEN; |
|
83 |
+ |
|
84 |
+ if (onas_scth_scanfile(curr->fts_path, fd, extinfo, tharg) == CL_VIRUS) |
|
85 |
+ ; |
|
86 |
+ ret = CL_VIRUS; |
|
87 |
+ |
|
88 |
+ close(fd); |
|
89 |
+ } |
|
90 |
+ } |
|
91 |
+ |
|
92 |
+ return ret; |
|
93 |
+} |
|
94 |
+ |
|
95 |
+static int onas_scth_handle_file(const char *pathname, struct scth_thrarg *tharg) |
|
96 |
+{ |
|
97 |
+ int fd; |
|
98 |
+ int extinfo; |
|
99 |
+ int ret; |
|
100 |
+ |
|
101 |
+ if (!pathname) return CL_ENULLARG; |
|
102 |
+ |
|
103 |
+ extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; |
|
104 |
+ |
|
105 |
+ if ((fd = safe_open(pathname, O_RDONLY | O_BINARY)) == -1) |
|
106 |
+ return CL_EOPEN; |
|
107 |
+ ret = onas_scth_scanfile(pathname, fd, extinfo, tharg); |
|
108 |
+ |
|
109 |
+ close(fd); |
|
110 |
+ |
|
111 |
+ return ret; |
|
112 |
+} |
|
113 |
+ |
|
114 |
+void *onas_scan_th(void *arg) |
|
115 |
+{ |
|
116 |
+ struct scth_thrarg *tharg = (struct scth_thrarg *)arg; |
|
117 |
+ sigset_t sigset; |
|
118 |
+ struct sigaction act; |
|
119 |
+ |
|
120 |
+ /* ignore all signals except SIGUSR1 */ |
|
121 |
+ sigfillset(&sigset); |
|
122 |
+ sigdelset(&sigset, SIGUSR1); |
|
123 |
+ /* The behavior of a process is undefined after it ignores a |
|
124 |
+ * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ |
|
125 |
+ sigdelset(&sigset, SIGFPE); |
|
126 |
+ sigdelset(&sigset, SIGILL); |
|
127 |
+ sigdelset(&sigset, SIGSEGV); |
|
128 |
+#ifdef SIGBUS |
|
129 |
+ sigdelset(&sigset, SIGBUS); |
|
130 |
+#endif |
|
131 |
+ pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
|
132 |
+ memset(&act, 0, sizeof(struct sigaction)); |
|
133 |
+ act.sa_handler = onas_scth_exit; |
|
134 |
+ sigfillset(&(act.sa_mask)); |
|
135 |
+ sigaction(SIGUSR1, &act, NULL); |
|
136 |
+ sigaction(SIGSEGV, &act, NULL); |
|
137 |
+ |
|
138 |
+ if (NULL == tharg || NULL == tharg->pathname || NULL == tharg->opts || NULL == tharg->engine) { |
|
139 |
+ logg("ScanOnAccess: Invalid thread arguments for extra scanning\n"); |
|
140 |
+ goto done; |
|
141 |
+ } |
|
142 |
+ |
|
143 |
+ if (tharg->extra_options & ONAS_SCTH_ISDIR) { |
|
144 |
+ logg("*ScanOnAccess: Performing additional scanning on directory '%s'\n", tharg->pathname); |
|
145 |
+ onas_scth_handle_dir(tharg->pathname, tharg); |
|
146 |
+ } else if (tharg->extra_options & ONAS_SCTH_ISFILE) { |
|
147 |
+ logg("*ScanOnAccess: Performing additional scanning on file '%s'\n", tharg->pathname); |
|
148 |
+ onas_scth_handle_file(tharg->pathname, tharg); |
|
149 |
+ } |
|
150 |
+ |
|
151 |
+done: |
|
152 |
+ if (NULL != tharg->pathname) { |
|
153 |
+ free(tharg->pathname); |
|
154 |
+ tharg->pathname = NULL; |
|
155 |
+ } |
|
156 |
+ if (NULL != tharg->options) { |
|
157 |
+ free(tharg->options); |
|
158 |
+ tharg->options = NULL; |
|
159 |
+ } |
|
160 |
+ if (NULL != tharg) { |
|
161 |
+ free(tharg); |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ return NULL; |
|
165 |
+} |
|
166 |
+#endif |
0 | 167 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,40 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Mickey Sola |
|
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 version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#ifndef __ONAS_SCTH_H |
|
21 |
+#define __ONAS_SCTH_H |
|
22 |
+ |
|
23 |
+#include "shared/optparser.h" |
|
24 |
+#include "libclamav/clamav.h" |
|
25 |
+ |
|
26 |
+#define ONAS_SCTH_ISDIR 0x01 |
|
27 |
+#define ONAS_SCTH_ISFILE 0x02 |
|
28 |
+ |
|
29 |
+struct scth_thrarg { |
|
30 |
+ uint32_t extra_options; |
|
31 |
+ struct cl_scan_options *options; |
|
32 |
+ const struct optstruct *opts; |
|
33 |
+ const struct cl_engine *engine; |
|
34 |
+ char *pathname; |
|
35 |
+}; |
|
36 |
+ |
|
37 |
+void *onas_scan_th(void *arg); |
|
38 |
+ |
|
39 |
+#endif |