78
static int scandirs(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
80
return treewalk(dirname, engine, user, opt, limits, options, 1);
77
static void move_infected(const char *filename, const struct optstruct *opt);
79
static int scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options)
81
int ret = 0, fd, included, printclean = 1;
82
const struct optnode *optnode;
88
/* argh, don't scan /proc files */
90
if(stat(filename, &sb) != -1)
91
if(sb.st_dev == procdev) {
93
logg("~%s: Excluded (/proc)\n", filename);
98
if(opt_check(opt, "exclude")) {
99
argument = opt_firstarg(opt, "exclude", &optnode);
101
if(match_regex(filename, argument) == 1) {
103
logg("~%s: Excluded\n", filename);
106
argument = opt_nextarg(&optnode, "exclude");
110
if(opt_check(opt, "include")) {
112
argument = opt_firstarg(opt, "include", &optnode);
113
while(argument && !included) {
114
if(match_regex(filename, argument) == 1) {
118
argument = opt_nextarg(&optnode, "include");
123
logg("~%s: Excluded\n", filename);
128
if(fileinfo(filename, 1) == 0) {
130
logg("~%s: Empty file\n", filename);
136
if(checkaccess(filename, NULL, R_OK) != 1) {
138
logg("~%s: Access denied\n", filename);
143
logg("*Scanning %s\n", filename);
145
if((fd = open(filename, O_RDONLY|O_BINARY)) == -1) {
146
logg("^Can't open file %s\n", filename);
152
if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
153
logg("~%s: %s FOUND\n", filename, virname);
157
fprintf(stderr, "\007");
159
} else if(ret == CL_CLEAN) {
160
if(!printinfected && printclean)
161
mprintf("~%s: OK\n", filename);
164
logg("~%s: %s\n", filename, cl_strerror(ret));
168
if(ret == CL_VIRUS) {
169
if(opt_check(opt, "remove")) {
170
if(unlink(filename)) {
171
logg("^%s: Can't remove\n", filename);
174
logg("~%s: Removed\n", filename);
176
} else if(opt_check(opt, "move") || opt_check(opt, "copy"))
177
move_infected(filename, opt);
183
static int scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth)
189
int scanret = 0, included;
190
unsigned int maxdepth;
191
const struct optnode *optnode;
195
if(opt_check(opt, "exclude-dir")) {
196
argument = opt_firstarg(opt, "exclude-dir", &optnode);
198
if(match_regex(dirname, argument) == 1) {
200
logg("~%s: Excluded\n", dirname);
203
argument = opt_nextarg(&optnode, "exclude-dir");
207
if(opt_check(opt, "include-dir")) {
209
argument = opt_firstarg(opt, "include-dir", &optnode);
210
while(argument && !included) {
211
if(match_regex(dirname, argument) == 1) {
215
argument = opt_nextarg(&optnode, "include-dir");
220
logg("~%s: Excluded\n", dirname);
225
if(opt_check(opt, "max-dir-recursion"))
226
maxdepth = atoi(opt_arg(opt, "max-dir-recursion"));
236
if((dd = opendir(dirname)) != NULL) {
237
while((dent = readdir(dd))) {
238
#if !defined(C_INTERIX) && !defined(C_WINDOWS)
242
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
243
/* build the full name */
244
fname = malloc(strlen(dirname) + strlen(dent->d_name) + 2);
245
sprintf(fname, "%s/%s", dirname, dent->d_name);
248
if(lstat(fname, &statbuf) != -1) {
249
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode) && recursion) {
250
if(scandirs(fname, engine, opt, limits, options, depth) == 1)
253
if(S_ISREG(statbuf.st_mode))
254
scanret += scanfile(fname, engine, opt, limits, options);
264
logg("~%s: Can't open directory.\n", dirname);
83
277
static int scanstdin(const struct cl_engine *engine, const struct cl_limits *limits, int options)
633
768
free(movefilename);
636
static int checkfile(const char *filename, const struct cl_engine *engine, const struct cl_limits *limits, int options, short printclean)
642
logg("*Scanning %s\n", filename);
644
if((fd = open(filename, O_RDONLY|O_BINARY)) == -1) {
645
logg("^Can't open file %s\n", filename);
649
if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
650
logg("~%s: %s FOUND\n", filename, virname);
654
fprintf(stderr, "\007");
656
} else if(ret == CL_CLEAN) {
657
if(!printinfected && printclean)
658
mprintf("~%s: OK\n", filename);
661
logg("~%s: %s\n", filename, cl_strerror(ret));
667
static int scancompressed(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
670
char *gendir, *userprg;
675
stat(filename, &statbuf);
677
if(!S_ISREG(statbuf.st_mode)) {
678
logg("^Suspect archive %s (not a regular file)\n", filename);
679
return 0; /* hmm ? */
682
/* check write access */
684
tmpdir = getenv("TMPDIR");
693
if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
694
logg("!Can't write to the temporary directory\n");
698
/* generate the temporary directory */
700
gendir = cli_gentemp(tmpdir);
701
if(mkdir(gendir, 0700)) {
702
logg("!Can't create the temporary directory %s\n", gendir);
703
exit(63); /* critical */
706
#if !defined(C_OS2) && !defined(C_WINDOWS)
707
/* FIXME: do the correct native windows way */
709
chown(gendir, user->pw_uid, user->pw_gid);
712
/* unpack file - as unprivileged user */
713
if(cli_strbcasestr(filename, ".zip")) {
714
const char *args[] = { "unzip", "-P", "clam", "-o", NULL, NULL };
715
/* Sun's SUNWspro C compiler doesn't allow direct initialisation
720
if((userprg = opt_arg(opt, "unzip")))
721
ret = clamav_unpack(userprg, args, gendir, user, opt);
723
ret = clamav_unpack("unzip", args, gendir, user, opt);
725
} else if(cli_strbcasestr(filename, ".rar")) {
726
const char *args[] = { "unrar", "x", "-p-", "-y", NULL, NULL };
728
if((userprg = opt_arg(opt, "unrar")))
729
ret = clamav_unpack(userprg, args, gendir, user, opt);
731
ret = clamav_unpack("unrar", args, gendir, user, opt);
733
} else if(cli_strbcasestr(filename, ".arj")) {
734
const char *args[] = { "arj", "x","-y", NULL, NULL };
736
if((userprg = opt_arg(opt, "arj")))
737
ret = clamav_unpack(userprg, args, gendir, user, opt);
739
ret = clamav_unpack("arj", args, gendir, user, opt);
741
} else if(cli_strbcasestr(filename, ".zoo")) {
742
const char *args[] = { "unzoo", "-x","-j","./", NULL, NULL };
744
if((userprg = opt_arg(opt, "unzoo")))
745
ret = clamav_unpack(userprg, args, gendir, user, opt);
747
ret = clamav_unpack("unzoo", args, gendir, user, opt);
749
} else if(cli_strbcasestr(filename, ".jar")) {
750
const char *args[] = { "unzip", "-P", "clam", "-o", NULL, NULL };
752
if((userprg = opt_arg(opt, "jar")))
753
ret = clamav_unpack(userprg, args, gendir, user, opt);
755
ret = clamav_unpack("unzip", args, gendir, user, opt);
757
} else if(cli_strbcasestr(filename, ".lzh")) {
758
const char *args[] = { "lha", "xf", NULL, NULL };
760
if((userprg = opt_arg(opt, "lha")))
761
ret = clamav_unpack(userprg, args, gendir, user, opt);
763
ret = clamav_unpack("lha", args, gendir, user, opt);
765
} else if(cli_strbcasestr(filename, ".tar")) {
766
const char *args[] = { "tar", "-xpvf", NULL, NULL };
768
if((userprg = opt_arg(opt, "tar")))
769
ret = clamav_unpack(userprg, args, gendir, user, opt);
771
ret = clamav_unpack("tar", args, gendir, user, opt);
773
} else if(cli_strbcasestr(filename, ".deb")) {
774
const char *args[] = { "ar", "x", NULL, NULL };
776
if((userprg = opt_arg(opt, "deb")))
777
ret = clamav_unpack(userprg, args, gendir, user, opt);
779
ret = clamav_unpack("ar", args, gendir, user, opt);
781
} else if((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz"))) {
782
const char *args[] = { "tar", "-zxpvf", NULL, NULL };
784
if((userprg = opt_arg(opt, "tgz")))
785
ret = clamav_unpack(userprg, args, gendir, user, opt);
787
ret = clamav_unpack("tar", args, gendir, user, opt);
790
/* fix permissions of extracted files */
793
if(!ret) { /* execute successful */
794
short oldrec = recursion;
797
ret = treewalk(gendir, engine, user, opt, limits, options, 1);
801
/* remove the directory - as clamav */
802
if(!opt_check(opt, "leave-temps"))
803
clamav_rmdirs(gendir);
805
/* free gendir - it's not necessary now */
810
logg("!Can't fork()\n");
811
exit(61); /* this is critical problem, so we just exit here */
813
logg("^Can't execute some unpacker. Check paths and permissions on the temporary directory\n");
814
/* This is no longer a critical error (since 0.24). We scan
817
if((ret = checkfile(filename, engine, limits, 0, 0)) == CL_VIRUS) {
818
if(opt_check(opt, "remove")) {
819
if(unlink(filename)) {
820
logg("^%s: Can't remove\n", filename);
823
logg("~%s: Removed\n", filename);
825
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
826
move_infected(filename, opt);
832
/* no viruses found in archive, we scan just in case a raw file
834
if((ret = checkfile(filename, engine, limits, 0, 1)) == CL_VIRUS) {
835
if(opt_check(opt, "remove")) {
836
if(unlink(filename)) {
837
logg("^%s: Can't remove\n", filename);
840
logg("~%s: Removed\n", filename);
842
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
843
move_infected(filename, opt);
847
logg("~%s: Infected.Archive FOUND\n", filename);
850
fprintf(stderr, "\007");
852
if(opt_check(opt, "remove")) {
853
if(unlink(filename)) {
854
logg("^%s: Can't remove\n", filename);
857
logg("~%s: Removed\n", filename);
859
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
860
move_infected(filename, opt);
864
logg("^Strange value (%d) returned in scancompressed()\n", ret);
869
static int scandenied(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, int options)
871
char *gendir, *tmp_file;
872
const char *tmpdir, *pt;
876
stat(filename, &statbuf);
877
if(!S_ISREG(statbuf.st_mode)) {
878
logg("^Suspect archive %s (not a regular file)\n", filename);
882
/* check write access */
884
tmpdir = getenv("TMPDIR");
894
if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
895
logg("!Can't write to the temporary directory %s\n", tmpdir);
899
/* generate the temporary directory */
900
gendir = cli_gentemp(tmpdir);
901
if(mkdir(gendir, 0700)) {
902
logg("^Can't create the temporary directory %s\n", gendir);
903
exit(63); /* critical */
906
tmp_file = (char *) malloc(strlen(gendir) + strlen(filename) + 10);
907
pt = strrchr(filename, '/');
913
sprintf(tmp_file, "%s/%s", gendir, pt);
915
if(filecopy(filename, tmp_file) == -1) {
916
logg("!I/O error\n");
917
perror("copyfile()");
923
#if !defined(C_OS2) && !defined(C_WINDOWS)
925
chown(gendir, user->pw_uid, user->pw_gid);
926
chown(tmp_file, user->pw_uid, user->pw_gid);
930
if((ret = treewalk(gendir, engine, user, opt, limits, options, 1)) == 1) {
931
logg("(Real infected archive: %s)\n", filename);
933
if(opt_check(opt, "remove")) {
934
if(unlink(filename)) {
935
logg("^%s: Can't remove\n", filename);
938
logg("~%s: Removed\n", filename);
940
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
941
move_infected(filename, opt);
944
/* remove the directory - as clamav */
945
clamav_rmdirs(gendir);
953
int scanfile(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options)
955
int ret = 0, included, printclean = 1;
956
const struct optnode *optnode;
961
/* argh, don't scan /proc files */
963
if(stat(filename, &sb) != -1)
964
if(sb.st_dev == procdev) {
966
logg("~%s: Excluded (/proc)\n", filename);
971
if(opt_check(opt, "exclude")) {
972
argument = opt_firstarg(opt, "exclude", &optnode);
974
if(match_regex(filename, argument) == 1) {
976
logg("~%s: Excluded\n", filename);
979
argument = opt_nextarg(&optnode, "exclude");
983
if(opt_check(opt, "include")) {
985
argument = opt_firstarg(opt, "include", &optnode);
986
while(argument && !included) {
987
if(match_regex(filename, argument) == 1) {
991
argument = opt_nextarg(&optnode, "include");
996
logg("~%s: Excluded\n", filename);
1001
if(fileinfo(filename, 1) == 0) {
1003
logg("~%s: Empty file\n", filename);
1009
if(checkaccess(filename, NULL, R_OK) != 1) {
1011
logg("~%s: Access denied\n", filename);
1019
* check the extension - this is a special case, normally we don't need to
1020
* do this (libclamav detects archive by its magic string), but here we
1021
* want to know the exit code from internal unpacker and try to use
1022
* external (if provided) when internal cannot extract data.
1025
if((cli_strbcasestr(filename, ".zip") || cli_strbcasestr(filename, ".rar")) && (options & CL_SCAN_ARCHIVE)) {
1027
#ifndef ENABLE_UNRAR
1028
if(cli_strbcasestr(filename, ".zip"))
1030
/* try to use internal archivers */
1031
if((ret = checkfile(filename, engine, limits, options, 1)) == CL_VIRUS) {
1032
if(opt_check(opt, "remove")) {
1033
if(unlink(filename)) {
1034
logg("^%s: Can't remove\n", filename);
1037
logg("~%s: Removed\n", filename);
1039
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
1040
move_infected(filename, opt);
1044
} else if(ret == CL_CLEAN) {
1046
} else if(ret == 54) {
1050
/* in other case try to continue with external archivers */
1051
options &= ~CL_SCAN_ARCHIVE; /* and disable decompression for the checkfile() below */
1054
if((cli_strbcasestr(filename, ".zip") && opt_check(opt, "unzip"))
1055
|| (cli_strbcasestr(filename, ".rar") && opt_check(opt, "unrar"))
1056
|| (cli_strbcasestr(filename, ".arj") && opt_check(opt, "arj"))
1057
|| (cli_strbcasestr(filename, ".zoo") && opt_check(opt, "unzoo"))
1058
|| (cli_strbcasestr(filename, ".jar") && opt_check(opt, "jar"))
1059
|| (cli_strbcasestr(filename, ".lzh") && opt_check(opt, "lha"))
1060
|| (cli_strbcasestr(filename, ".tar") && opt_check(opt, "tar"))
1061
|| (cli_strbcasestr(filename, ".deb") && opt_check(opt, "deb"))
1062
|| ((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz"))
1063
&& (opt_check(opt, "tgz") || opt_check(opt, "deb"))) ) {
1065
/* check permissions */
1066
switch(checkaccess(filename, CLAMAVUSER, R_OK)) {
1068
logg("^Can't get information about user "CLAMAVUSER"\n");
1069
exit(60); /* this is a critical problem so we just exit here */
1071
logg("^Can't fork\n");
1073
case 0: /* read access denied */
1076
logg("^%s: Access denied to archive\n", filename);
1079
if(limits && limits->maxfilesize)
1080
if((unsigned int) fileinfo(filename, 1) / 1024 > limits->maxfilesize) {
1082
logg("^%s: Archive too big\n", filename);
1086
return(scandenied(filename, engine, user, opt, limits, options));
1090
return(scancompressed(filename, engine, user, opt, limits, options));
1094
if((ret = checkfile(filename, engine, limits, options, printclean)) == CL_VIRUS) {
1095
if(opt_check(opt, "remove")) {
1096
if(unlink(filename)) {
1097
logg("^%s: Can't remove\n", filename);
1100
logg("~%s: Removed\n", filename);
1102
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
1103
move_infected(filename, opt);