60
52
#include "libclamav/others.h"
61
53
#include "libclamav/matcher-ac.h"
62
54
#include "libclamav/str.h"
63
#include "libclamav/readdb.h"
64
#include "libclamav/cltypes.h"
71
/* FIXME: If possible, handle users correctly */
72
static int checkaccess(const char *path, const char *username, int mode)
74
return !_access(path, mode);
77
static int checkaccess(const char *path, const char *username, int mode)
84
if((user = getpwnam(username)) == NULL) {
93
if(setgid(user->pw_gid)) {
94
fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
98
if(setuid(user->pw_uid)) {
99
fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
103
if(access(path, mode))
110
if(WIFEXITED(status) && WEXITSTATUS(status) == 1)
115
if(!access(path, mode))
123
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, unsigned int options)
125
int ret = 0, fd, included, printclean = 1;
126
const struct optstruct *opt;
130
if((opt = optget(opts, "exclude"))->enabled) {
132
if(match_regex(filename, opt->strarg) == 1) {
134
logg("~%s: Excluded\n", filename);
141
if((opt = optget(opts, "include"))->enabled) {
144
if(match_regex(filename, opt->strarg) == 1) {
152
logg("~%s: Excluded\n", filename);
157
/* argh, don't scan /proc files */
158
if(stat(filename, &sb) != -1) {
160
if(procdev && sb.st_dev == procdev) {
162
logg("~%s: Excluded (/proc)\n", filename);
168
logg("~%s: Empty file\n", filename);
171
info.rblocks += sb.st_size / CL_COUNT_PRECISION;
176
if(checkaccess(filename, NULL, R_OK) != 1) {
178
logg("~%s: Access denied\n", filename);
184
logg("*Scanning %s\n", filename);
186
if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1) {
187
logg("^Can't open file %s: %s\n", filename, strerror(errno));
192
if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
193
logg("~%s: %s FOUND\n", filename, virname);
198
fprintf(stderr, "\007");
200
} else if(ret == CL_CLEAN) {
201
if(!printinfected && printclean)
202
mprintf("~%s: OK\n", filename);
206
logg("~%s: %s ERROR\n", filename, cl_strerror(ret));
212
if(ret == CL_VIRUS && action)
216
static void scandirs(const char *dirname, struct cl_engine *engine, const struct optstruct *opts, unsigned int options, unsigned int depth, dev_t dev)
223
const struct optstruct *opt;
224
unsigned int dirlnk, filelnk;
227
if((opt = optget(opts, "exclude-dir"))->enabled) {
229
if(match_regex(dirname, opt->strarg) == 1) {
231
logg("~%s: Excluded\n", dirname);
238
if((opt = optget(opts, "include-dir"))->enabled) {
241
if(match_regex(dirname, opt->strarg) == 1) {
249
logg("~%s: Excluded\n", dirname);
254
if(depth > (unsigned int) optget(opts, "max-dir-recursion")->numarg)
257
dirlnk = optget(opts, "follow-dir-symlinks")->numarg;
258
filelnk = optget(opts, "follow-file-symlinks")->numarg;
260
if((dd = opendir(dirname)) != NULL) {
263
while((dent = readdir(dd))) {
266
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
267
/* build the full name */
268
fname = malloc(strlen(dirname) + strlen(dent->d_name) + 2);
269
if(!strcmp(dirname, PATHSEP))
270
sprintf(fname, PATHSEP"%s", dent->d_name);
272
sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
275
if(lstat(fname, &sb) != -1) {
276
if(!optget(opts, "cross-fs")->enabled) {
277
if(sb.st_dev != dev) {
279
logg("~%s: Excluded\n", fname);
284
if(S_ISLNK(sb.st_mode)) {
285
if(dirlnk != 2 && filelnk != 2) {
287
logg("%s: Symbolic link\n", fname);
288
} else if(stat(fname, &sb) != -1) {
289
if(S_ISREG(sb.st_mode) && filelnk == 2) {
290
scanfile(fname, engine, opts, options);
291
} else if(S_ISDIR(sb.st_mode) && dirlnk == 2) {
293
scandirs(fname, engine, opts, options, depth, dev);
296
logg("%s: Symbolic link\n", fname);
299
} else if(S_ISREG(sb.st_mode)) {
300
scanfile(fname, engine, opts, options);
301
} else if(S_ISDIR(sb.st_mode) && recursion) {
302
scandirs(fname, engine, opts, options, depth, dev);
312
logg("~%s: Can't open directory.\n", dirname);
317
static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, int options)
60
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)
62
return treewalk(dirname, engine, user, opt, limits, options, 1);
65
static int scanstdin(const struct cl_engine *engine, const struct cl_limits *limits, int options)
320
unsigned int fsize = 0;
321
68
const char *virname, *tmpdir;
322
69
char *file, buff[FILEBUFF];
326
if(optget(opts, "tempdir")->enabled) {
327
tmpdir = optget(opts, "tempdir")->strarg;
329
/* check write access */
330
tmpdir = cli_gettmpdir();
73
/* check write access */
74
tmpdir = getenv("TMPDIR");
332
83
if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
333
84
logg("!Can't write to temporary directory\n");
337
88
file = cli_gentemp(tmpdir);
339
90
if(!(fs = fopen(file, "wb"))) {
340
91
logg("!Can't open %s for writing\n", file);
345
while((bread = fread(buff, 1, FILEBUFF, stdin))) {
347
if(fwrite(buff, 1, bread, fs) < bread) {
348
logg("!Can't write to %s\n", file);
95
while((ret = fread(buff, 1, FILEBUFF, stdin)))
96
fwrite(buff, 1, ret, fs);
356
100
logg("*Checking %s\n", file);
358
info.rblocks += fsize / CL_COUNT_PRECISION;
360
if((ret = cl_scanfile(file, &virname, &info.blocks, engine, options)) == CL_VIRUS) {
103
if((ret = cl_scanfile(file, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
361
104
logg("stdin: %s FOUND\n", virname);
367
110
} else if(ret == CL_CLEAN) {
368
111
if(!printinfected)
369
112
mprintf("stdin: OK\n");
371
114
if(!printinfected)
372
logg("stdin: %s ERROR\n", cl_strerror(ret));
115
logg("stdin: %s\n", cl_strerror(ret));
381
int scanmanager(const struct optstruct *opts)
122
int scanmanager(const struct optstruct *opt)
384
unsigned int options = 0, dboptions = 0, dirlnk = 1, filelnk = 1;
385
struct cl_engine *engine;
125
int ret = 0, compression = 0, fmodeint, i, x;
126
unsigned int options = 0, dboptions = 0;
127
struct cl_engine *engine = NULL;
128
struct cl_limits limits;
129
struct passwd *user = NULL;
387
char *file, cwd[1024], *pua_cats = NULL;
388
const char *filename;
389
const struct optstruct *opt;
131
char *fullpath = NULL, cwd[1024];
134
/* njh@bandsman.co.uk: BeOS */
135
#if !defined(C_CYGWIN) && !defined(C_OS2) && !defined(C_BEOS)
137
if((user = getpwnam(CLAMAVUSER)) == NULL) {
138
logg("!Can't get information about user "CLAMAVUSER"\n");
139
exit(60); /* this is critical problem, so we just exit here */
394
dirlnk = optget(opts, "follow-dir-symlinks")->numarg;
396
logg("!--follow-dir-symlinks: Invalid argument\n");
400
filelnk = optget(opts, "follow-file-symlinks")->numarg;
402
logg("!--follow-file-symlinks: Invalid argument\n");
406
if(optget(opts, "phishing-sigs")->enabled)
144
if(opt_check(opt, "unzip") || opt_check(opt, "unrar") || opt_check(opt, "arj") ||
145
opt_check(opt, "unzoo") || opt_check(opt, "jar") || opt_check(opt, "lha") ||
146
opt_check(opt, "tar") || opt_check(opt, "tgz") || opt_check(opt, "deb"))
150
if(opt_check(opt, "ncore"))
151
dboptions |= CL_DB_NCORE;
153
if(!opt_check(opt, "no-phishing-sigs"))
407
154
dboptions |= CL_DB_PHISHING;
409
if(optget(opts, "official-db-only")->enabled)
410
dboptions |= CL_DB_OFFICIAL_ONLY;
412
if(optget(opts,"phishing-scan-urls")->enabled)
156
#ifdef CL_EXPERIMENTAL
157
if(!opt_check(opt,"no-phishing-scan-urls"))
413
158
dboptions |= CL_DB_PHISHING_URLS;
415
if(optget(opts,"bytecode")->enabled)
416
dboptions |= CL_DB_BYTECODE;
418
if((ret = cl_init(CL_INIT_DEFAULT))) {
419
logg("!Can't initialize libclamav: %s\n", cl_strerror(ret));
423
if(!(engine = cl_engine_new())) {
424
logg("!Can't initialize antivirus engine\n");
428
if(optget(opts, "detect-pua")->enabled) {
429
dboptions |= CL_DB_PUA;
430
if((opt = optget(opts, "exclude-pua"))->enabled) {
431
dboptions |= CL_DB_PUA_EXCLUDE;
434
if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
435
logg("!Can't allocate memory for pua_cats\n");
436
cl_engine_free(engine);
439
sprintf(pua_cats + i, ".%s", opt->strarg);
440
i += strlen(opt->strarg) + 1;
448
if((opt = optget(opts, "include-pua"))->enabled) {
450
logg("!--exclude-pua and --include-pua cannot be used at the same time\n");
451
cl_engine_free(engine);
455
dboptions |= CL_DB_PUA_INCLUDE;
458
if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
459
logg("!Can't allocate memory for pua_cats\n");
462
sprintf(pua_cats + i, ".%s", opt->strarg);
463
i += strlen(opt->strarg) + 1;
472
if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) {
473
logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret));
475
cl_engine_free(engine);
482
if(optget(opts, "dev-ac-only")->enabled)
483
cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
485
if(optget(opts, "dev-ac-depth")->enabled)
486
cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg);
488
if(optget(opts, "leave-temps")->enabled)
489
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
491
if(optget(opts, "bytecode-trust-all")->enabled)
492
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_SECURITY, CL_BYTECODE_TRUST_ALL);
493
if((opt = optget(opts,"bytecode-timeout"))->enabled)
494
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg);
495
if((opt = optget(opts,"bytecode-mode"))->enabled) {
496
enum bytecode_mode mode;
497
if (!strcmp(opt->strarg, "ForceJIT"))
498
mode = CL_BYTECODE_MODE_JIT;
499
else if(!strcmp(opt->strarg, "ForceInterpreter"))
500
mode = CL_BYTECODE_MODE_INTERPRETER;
501
else if(!strcmp(opt->strarg, "Test"))
502
mode = CL_BYTECODE_MODE_TEST;
504
mode = CL_BYTECODE_MODE_AUTO;
505
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode);
508
if((opt = optget(opts, "tempdir"))->enabled) {
509
if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
510
logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
511
cl_engine_free(engine);
516
if((opt = optget(opts, "database"))->active) {
518
if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) {
519
logg("!%s\n", cl_strerror(ret));
520
cl_engine_free(engine);
159
if(!opt_check(opt,"no-phishing-restrictedscan")) {
160
/* not scanning all domains, check only URLs with domains from .pdb */
161
options |= CL_SCAN_PHISHING_DOMAINLIST;
163
if(opt_check(opt,"phishing-ssl")) {
164
options |= CL_SCAN_PHISHING_BLOCKSSL;
166
if(opt_check(opt,"phishing-cloak")) {
167
options |= CL_SCAN_PHISHING_BLOCKCLOAK;
171
if(opt_check(opt, "dev-ac-only")) {
172
dboptions |= CL_DB_ACONLY;
174
if(opt_check(opt, "dev-ac-depth"))
175
cli_ac_setdepth(atoi(opt_arg(opt, "dev-ac-depth")));
178
if(opt_check(opt, "database")) {
179
if((ret = cl_load(opt_arg(opt, "database"), &engine, &info.sigs, dboptions))) {
180
logg("!%s\n", cl_strerror(ret));
526
185
char *dbdir = freshdbdir();
528
if((ret = cl_load(dbdir, engine, &info.sigs, dboptions))) {
187
if((ret = cl_load(dbdir, &engine, &info.sigs, dboptions))) {
529
188
logg("!%s\n", cl_strerror(ret));
531
cl_engine_free(engine);
537
if((ret = cl_engine_compile(engine)) != 0) {
196
logg("!Can't initialize the virus database\n");
200
if((ret = cl_build(engine)) != 0) {
538
201
logg("!Database initialization error: %s\n", cl_strerror(ret));;
539
cl_engine_free(engine);
545
if((opt = optget(opts, "max-scansize"))->active) {
546
if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, opt->numarg))) {
547
logg("!cli_engine_set_num(CL_ENGINE_MAX_SCANSIZE) failed: %s\n", cl_strerror(ret));
548
cl_engine_free(engine);
553
if((opt = optget(opts, "max-filesize"))->active) {
554
if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, opt->numarg))) {
555
logg("!cli_engine_set_num(CL_ENGINE_MAX_FILESIZE) failed: %s\n", cl_strerror(ret));
556
cl_engine_free(engine);
562
if(getrlimit(RLIMIT_FSIZE, &rlim) == 0) {
563
if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_FILESIZE, NULL))
564
logg("^System limit for file size is lower than engine->maxfilesize\n");
565
if(rlim.rlim_cur < (rlim_t) cl_engine_get_num(engine, CL_ENGINE_MAX_SCANSIZE, NULL))
566
logg("^System limit for file size is lower than engine->maxscansize\n");
568
logg("^Cannot obtain resource limits for file size\n");
572
if((opt = optget(opts, "max-files"))->active) {
573
if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_FILES, opt->numarg))) {
574
logg("!cli_engine_set_num(CL_ENGINE_MAX_FILES) failed: %s\n", cl_strerror(ret));
575
cl_engine_free(engine);
580
if((opt = optget(opts, "max-recursion"))->active) {
581
if((ret = cl_engine_set_num(engine, CL_ENGINE_MAX_RECURSION, opt->numarg))) {
582
logg("!cli_engine_set_num(CL_ENGINE_MAX_RECURSION) failed: %s\n", cl_strerror(ret));
583
cl_engine_free(engine);
588
/* set scan options */
589
if(optget(opts,"phishing-ssl")->enabled)
590
options |= CL_SCAN_PHISHING_BLOCKSSL;
592
if(optget(opts,"phishing-cloak")->enabled)
593
options |= CL_SCAN_PHISHING_BLOCKCLOAK;
595
if(optget(opts,"heuristic-scan-precedence")->enabled)
596
options |= CL_SCAN_HEURISTIC_PRECEDENCE;
598
if(optget(opts, "scan-archive")->enabled)
206
memset(&limits, 0, sizeof(struct cl_limits));
208
if(opt_check(opt, "max-space")) {
210
ptr = opt_arg(opt, "max-space");
211
if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
212
cpy = mcalloc(strlen(ptr), sizeof(char));
213
strncpy(cpy, ptr, strlen(ptr) - 1);
214
limits.maxfilesize = atoi(cpy) * 1024 * 1024;
217
limits.maxfilesize = atoi(ptr) * 1024;
219
limits.maxfilesize = 10485760;
221
if(opt_check(opt, "max-files"))
222
limits.maxfiles = atoi(opt_arg(opt, "max-files"));
224
limits.maxfiles = 500;
226
if(opt_check(opt, "max-recursion"))
227
limits.maxreclevel = atoi(opt_arg(opt, "max-recursion"));
229
limits.maxreclevel = 8;
231
if(opt_check(opt, "max-mail-recursion"))
232
limits.maxmailrec = atoi(opt_arg(opt, "max-mail-recursion"));
234
limits.maxmailrec = 64;
236
if(opt_check(opt, "max-ratio"))
237
limits.maxratio = atoi(opt_arg(opt, "max-ratio"));
239
limits.maxratio = 250;
243
if(opt_check(opt, "disable-archive") || opt_check(opt, "no-archive"))
244
options &= ~CL_SCAN_ARCHIVE;
599
246
options |= CL_SCAN_ARCHIVE;
601
if(optget(opts, "detect-broken")->enabled)
248
if(opt_check(opt, "detect-broken"))
602
249
options |= CL_SCAN_BLOCKBROKEN;
604
if(optget(opts, "block-encrypted")->enabled)
251
if(opt_check(opt, "block-encrypted"))
605
252
options |= CL_SCAN_BLOCKENCRYPTED;
607
if(optget(opts, "scan-pe")->enabled)
254
if(opt_check(opt, "block-max"))
255
options |= CL_SCAN_BLOCKMAX;
257
if(opt_check(opt, "no-pe"))
258
options &= ~CL_SCAN_PE;
608
260
options |= CL_SCAN_PE;
610
if(optget(opts, "scan-elf")->enabled)
262
if(opt_check(opt, "no-elf"))
263
options &= ~CL_SCAN_ELF;
611
265
options |= CL_SCAN_ELF;
613
if(optget(opts, "scan-ole2")->enabled)
267
if(opt_check(opt, "no-ole2"))
268
options &= ~CL_SCAN_OLE2;
614
270
options |= CL_SCAN_OLE2;
616
if(optget(opts, "scan-pdf")->enabled)
617
options |= CL_SCAN_PDF;
619
if(optget(opts, "scan-html")->enabled)
272
if(opt_check(opt, "no-html"))
273
options &= ~CL_SCAN_HTML;
620
275
options |= CL_SCAN_HTML;
622
if(optget(opts, "scan-mail")->enabled)
277
if(opt_check(opt, "no-mail")) {
278
options &= ~CL_SCAN_MAIL;
623
280
options |= CL_SCAN_MAIL;
625
if(optget(opts, "algorithmic-detection")->enabled)
282
if(opt_check(opt, "mail-follow-urls"))
283
options |= CL_SCAN_MAILURL;
286
if(opt_check(opt, "no-algorithmic"))
287
options &= ~CL_SCAN_ALGORITHMIC;
626
289
options |= CL_SCAN_ALGORITHMIC;
628
#ifdef HAVE__INTERNAL__SHA_COLLECT
629
if(optget(opts, "dev-collect-hashes")->enabled)
630
options |= CL_SCAN_INTERNAL_COLLECT_SHA;
633
if(optget(opts, "detect-structured")->enabled) {
634
options |= CL_SCAN_STRUCTURED;
636
if((opt = optget(opts, "structured-ssn-format"))->enabled) {
637
switch(opt->numarg) {
639
options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
642
options |= CL_SCAN_STRUCTURED_SSN_STRIPPED;
645
options |= (CL_SCAN_STRUCTURED_SSN_NORMAL | CL_SCAN_STRUCTURED_SSN_STRIPPED);
648
logg("!Invalid argument for --structured-ssn-format\n");
652
options |= CL_SCAN_STRUCTURED_SSN_NORMAL;
655
if((opt = optget(opts, "structured-ssn-count"))->active) {
656
if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_SSN_COUNT, opt->numarg))) {
657
logg("!cli_engine_set_num(CL_ENGINE_MIN_SSN_COUNT) failed: %s\n", cl_strerror(ret));
658
cl_engine_free(engine);
663
if((opt = optget(opts, "structured-cc-count"))->active) {
664
if((ret = cl_engine_set_num(engine, CL_ENGINE_MIN_CC_COUNT, opt->numarg))) {
665
logg("!cli_engine_set_num(CL_ENGINE_MIN_CC_COUNT) failed: %s\n", cl_strerror(ret));
666
cl_engine_free(engine);
672
options &= ~CL_SCAN_STRUCTURED;
676
292
procdev = (dev_t) 0;
677
293
if(stat("/proc", &sb) != -1 && !sb.st_size)
681
297
/* check filetype */
682
if(!opts->filename && !optget(opts, "file-list")->enabled) {
298
if(opt->filename == NULL || strlen(opt->filename) == 0) {
683
300
/* we need full path for some reasons (eg. archive handling) */
684
301
if(!getcwd(cwd, sizeof(cwd))) {
685
302
logg("!Can't get absolute pathname of current working directory\n");
689
scandirs(cwd, engine, opts, options, 1, sb.st_dev);
305
ret = scandirs(cwd, engine, user, opt, &limits, options);
692
} else if(opts->filename && !optget(opts, "file-list")->enabled && !strcmp(opts->filename[0], "-")) { /* read data from stdin */
693
ret = scanstdin(engine, opts, options);
307
} else if(!strcmp(opt->filename, "-")) { /* read data from stdin */
308
ret = scanstdin(engine, &limits, options);
696
if(opts->filename && optget(opts, "file-list")->enabled)
697
logg("^Only scanning files from --file-list (files passed at cmdline are ignored)\n");
699
while((filename = filelist(opts, &ret)) && (file = strdup(filename))) {
700
if(lstat(file, &sb) == -1) {
701
logg("^%s: Can't access file\n", file);
312
for (x = 0; (thefilename = cli_strtok(opt->filename, x, "\t")) != NULL; x++) {
313
if((fmodeint = fileinfo(thefilename, 2)) == -1) {
314
logg("^Can't access file %s\n", thefilename);
705
for(i = strlen(file) - 1; i > 0; i--) {
706
if(file[i] == *PATHSEP)
319
for(i = strlen(thefilename) - 1; i > 0 && slash; i--) {
320
if(thefilename[i] == '/')
712
if(S_ISLNK(sb.st_mode)) {
713
if(dirlnk == 0 && filelnk == 0) {
715
logg("%s: Symbolic link\n", file);
716
} else if(stat(file, &sb) != -1) {
717
if(S_ISREG(sb.st_mode) && filelnk) {
718
scanfile(file, engine, opts, options);
719
} else if(S_ISDIR(sb.st_mode) && dirlnk) {
720
scandirs(file, engine, opts, options, 1, sb.st_dev);
723
logg("%s: Symbolic link\n", file);
326
fmode = (mode_t) fmodeint;
328
if(compression && (thefilename[0] != '/' && thefilename[0] != '\\' && thefilename[1] != ':')) {
329
/* we need to complete the path */
330
if(!getcwd(cwd, sizeof(cwd))) {
331
logg("!Can't get absolute pathname of current working directory\n");
334
fullpath = mcalloc(512, sizeof(char));
336
sprintf(fullpath, "%s/%s", cwd, thefilename);
338
snprintf(fullpath, 512, "%s/%s", cwd, thefilename);
340
logg("*Full path: %s\n", fullpath);
726
} else if(S_ISREG(sb.st_mode)) {
727
scanfile(file, engine, opts, options);
728
} else if(S_ISDIR(sb.st_mode)) {
729
scandirs(file, engine, opts, options, 1, sb.st_dev);
731
logg("^%s: Not supported file type\n", file);
343
fullpath = thefilename;
345
switch(fmode & S_IFMT) {
347
ret = scanfile(fullpath, engine, user, opt, &limits, options);
351
ret = scandirs(fullpath, engine, user, opt, &limits, options);
355
logg("!Not supported file type (%s)\n", thefilename);
359
if(compression && (thefilename[0] != '/' && thefilename[0] != '\\' && thefilename[1] != ':')) {
739
368
/* free the engine */
740
cl_engine_free(engine);
742
/* overwrite return code - infection takes priority */
371
/* overwrite return code */
374
else if(ret < 50) /* hopefully no error detected */
375
ret = 0; /* just make sure it's 0 */
382
* -2 -> can't execute
383
* -3 -> external signal
386
static int clamav_unpack(const char *prog, char **args, const char *tmpdir, const struct passwd *user, const struct optstruct *opt)
389
int status, wret, fdevnull;
390
unsigned int maxfiles, maxspace;
394
if(opt_check(opt, "max-files"))
395
maxfiles = atoi(opt_arg(opt, "max-files"));
399
if(opt_check(opt, "max-space")) {
401
ptr = opt_arg(opt, "max-space");
402
if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
403
cpy = mcalloc(strlen(ptr), sizeof(char));
404
strncpy(cpy, ptr, strlen(ptr) - 1);
405
maxspace = atoi(cpy) * 1024;
407
} else /* default - kilobytes */
408
maxspace = atoi(ptr);
413
switch(pid = fork()) {
418
if(!geteuid() && user) {
420
#ifdef HAVE_SETGROUPS
421
if(setgroups(1, &user->pw_gid)) {
422
fprintf(stderr, "ERROR: setgroups() failed\n");
427
if(setgid(user->pw_gid)) {
428
fprintf(stderr, "ERROR: setgid(%d) failed\n", (int) user->pw_gid);
432
if(setuid(user->pw_uid)) {
433
fprintf(stderr, "ERROR: setuid(%d) failed\n", (int) user->pw_uid);
441
fdevnull = open("/dev/null", O_WRONLY);
443
logg("Non fatal error: cannot open /dev/null. Continuing with full output\n");
451
if(strchr(prog, '/')) /* we have full path */
460
if(maxfiles || maxspace) {
461
while(!(wret = waitpid(pid, &status, WNOHANG))) {
462
memset(&n, 0, sizeof(struct s_du));
465
if((maxfiles && n.files > maxfiles) || (maxspace && n.space > maxspace)) {
466
logg("*n.files: %d, n.space: %d\n", n.files, n.space);
467
kill(pid, 9); /* stop it immediately */
471
waitpid(pid, &status, 0);
474
if(WIFSIGNALED(status)) {
475
switch(WTERMSIG(status)) {
478
logg("\nUnpacker process %d stopped due to exceeded limits\n", pid);
481
logg("^Can't run %s\n", prog);
484
logg("^\nUnpacker stopped with external signal %d\n", WTERMSIG(status));
487
} else if(WIFEXITED(status))
494
static void move_infected(const char *filename, const struct optstruct *opt)
496
char *movedir, *movefilename, *tmp, numext[4 + 1];
497
struct stat fstat, mfstat;
498
int n, len, movefilename_size;
499
int moveflag = opt_check(opt, "move");
503
if((moveflag && !(movedir = opt_arg(opt, "move"))) ||
504
(!moveflag && !(movedir = opt_arg(opt, "copy")))) {
505
/* Should never reach here */
506
logg("!opt_arg() returned NULL\n", filename);
511
if(access(movedir, W_OK|X_OK) == -1) {
512
logg("!Can't %s file '%s': cannot write to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movedir, strerror(errno));
517
if(!(tmp = strrchr(filename, '/')))
518
tmp = (const char *) filename;
520
movefilename_size = sizeof(char) * (strlen(movedir) + strlen(tmp) + sizeof(numext) + 2);
522
if(!(movefilename = mmalloc(movefilename_size))) {
523
logg("!mmalloc() failed\n");
527
if(!(cli_strrcpy(movefilename, movedir))) {
528
logg("!cli_strrcpy() returned NULL\n");
534
strcat(movefilename, "/");
536
if(!(strcat(movefilename, tmp))) {
537
logg("!strcat() returned NULL\n");
543
stat(filename, &fstat);
545
if(!stat(movefilename, &mfstat)) {
546
if(fstat.st_ino == mfstat.st_ino) { /* It's the same file*/
547
logg("File excluded '%s'\n", filename);
552
/* file exists - try to append an ordinal number to the
553
* quranatined file in an attempt not to overwrite existing
554
* files in quarantine
556
len = strlen(movefilename);
559
/* reset the movefilename to it's initial value by
560
* truncating to the original filename length
562
movefilename[len] = 0;
564
sprintf(numext, ".%03d", n++);
565
strcat(movefilename, numext);
566
} while(!stat(movefilename, &mfstat) && (n < 1000));
570
if(!moveflag || rename(filename, movefilename) == -1) {
571
if(filecopy(filename, movefilename) == -1) {
572
logg("!Can't %s '%s' to '%s': %s\n", (moveflag) ? "move" : "copy", filename, movefilename, strerror(errno));
578
chmod(movefilename, fstat.st_mode);
580
chown(movefilename, fstat.st_uid, fstat.st_gid);
583
ubuf.actime = fstat.st_atime;
584
ubuf.modtime = fstat.st_mtime;
585
utime(movefilename, &ubuf);
587
if(moveflag && unlink(filename)) {
588
logg("!Can't unlink '%s': %s\n", filename, strerror(errno));
595
logg("%s: %s to '%s'\n", filename, (moveflag) ? "moved" : "copied", movefilename);
600
static int checkfile(const char *filename, const struct cl_engine *engine, const struct cl_limits *limits, int options, short printclean)
606
logg("*Scanning %s\n", filename);
608
if((fd = open(filename, O_RDONLY)) == -1) {
609
logg("^Can't open file %s\n", filename);
613
if((ret = cl_scandesc(fd, &virname, &info.blocks, engine, limits, options)) == CL_VIRUS) {
614
logg("%s: %s FOUND\n", filename, virname);
618
fprintf(stderr, "\007");
620
} else if(ret == CL_CLEAN) {
621
if(!printinfected && printclean)
622
mprintf("%s: OK\n", filename);
625
logg("%s: %s\n", filename, cl_strerror(ret));
631
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)
634
char *tmpdir, *gendir, *userprg;
638
stat(filename, &statbuf);
640
if(!S_ISREG(statbuf.st_mode)) {
641
logg("^Suspect archive %s (not a regular file)\n", filename);
642
return 0; /* hmm ? */
645
/* check write access */
647
tmpdir = getenv("TMPDIR");
656
if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
657
logg("!Can't write to the temporary directory\n");
661
/* generate the temporary directory */
663
gendir = cli_gentemp(tmpdir);
664
if(mkdir(gendir, 0700)) {
665
logg("!Can't create the temporary directory %s\n", gendir);
666
exit(63); /* critical */
671
chown(gendir, user->pw_uid, user->pw_gid);
674
/* unpack file - as unprivileged user */
675
if(cli_strbcasestr(filename, ".zip")) {
676
char *args[] = { "unzip", "-P", "clam", "-o", NULL, NULL };
677
/* Sun's SUNWspro C compiler doesn't allow direct initialisation
680
args[4] = (char *) filename;
682
if((userprg = opt_arg(opt, "unzip")))
683
ret = clamav_unpack(userprg, args, gendir, user, opt);
685
ret = clamav_unpack("unzip", args, gendir, user, opt);
687
} else if(cli_strbcasestr(filename, ".rar")) {
688
char *args[] = { "unrar", "x", "-p-", "-y", NULL, NULL };
689
args[4] = (char *) filename;
690
if((userprg = opt_arg(opt, "unrar")))
691
ret = clamav_unpack(userprg, args, gendir, user, opt);
693
ret = clamav_unpack("unrar", args, gendir, user, opt);
695
} else if(cli_strbcasestr(filename, ".arj")) {
696
char *args[] = { "arj", "x","-y", NULL, NULL };
697
args[3] = (char *) filename;
698
if((userprg = opt_arg(opt, "arj")))
699
ret = clamav_unpack(userprg, args, gendir, user, opt);
701
ret = clamav_unpack("arj", args, gendir, user, opt);
703
} else if(cli_strbcasestr(filename, ".zoo")) {
704
char *args[] = { "unzoo", "-x","-j","./", NULL, NULL };
705
args[4] = (char *) filename;
706
if((userprg = opt_arg(opt, "unzoo")))
707
ret = clamav_unpack(userprg, args, gendir, user, opt);
709
ret = clamav_unpack("unzoo", args, gendir, user, opt);
711
} else if(cli_strbcasestr(filename, ".jar")) {
712
char *args[] = { "unzip", "-P", "clam", "-o", NULL, NULL };
713
args[4] = (char *) filename;
714
if((userprg = opt_arg(opt, "jar")))
715
ret = clamav_unpack(userprg, args, gendir, user, opt);
717
ret = clamav_unpack("unzip", args, gendir, user, opt);
719
} else if(cli_strbcasestr(filename, ".lzh")) {
720
char *args[] = { "lha", "xf", NULL, NULL };
721
args[2] = (char *) filename;
722
if((userprg = opt_arg(opt, "lha")))
723
ret = clamav_unpack(userprg, args, gendir, user, opt);
725
ret = clamav_unpack("lha", args, gendir, user, opt);
727
} else if(cli_strbcasestr(filename, ".tar")) {
728
char *args[] = { "tar", "-xpvf", NULL, NULL };
729
args[2] = (char *) filename;
730
if((userprg = opt_arg(opt, "tar")))
731
ret = clamav_unpack(userprg, args, gendir, user, opt);
733
ret = clamav_unpack("tar", args, gendir, user, opt);
735
} else if(cli_strbcasestr(filename, ".deb")) {
736
char *args[] = { "ar", "x", NULL, NULL };
737
args[2] = (char *) filename;
738
if((userprg = opt_arg(opt, "deb")))
739
ret = clamav_unpack(userprg, args, gendir, user, opt);
741
ret = clamav_unpack("ar", args, gendir, user, opt);
743
} else if((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz"))) {
744
char *args[] = { "tar", "-zxpvf", NULL, NULL };
745
args[2] = (char *) filename;
746
if((userprg = opt_arg(opt, "tgz")))
747
ret = clamav_unpack(userprg, args, gendir, user, opt);
749
ret = clamav_unpack("tar", args, gendir, user, opt);
752
/* fix permissions of extracted files */
755
if(!ret) { /* execute successful */
756
short oldrec = recursion;
759
ret = treewalk(gendir, engine, user, opt, limits, options, 1);
763
/* remove the directory - as clamav */
764
if(!opt_check(opt, "leave-temps"))
765
clamav_rmdirs(gendir);
767
/* free gendir - it's not necessary now */
772
logg("!Can't fork()\n");
773
exit(61); /* this is critical problem, so we just exit here */
775
logg("^Can't execute some unpacker. Check paths and permissions on the temporary directory\n");
776
/* This is no longer a critical error (since 0.24). We scan
779
if((ret = checkfile(filename, engine, limits, 0, 0)) == CL_VIRUS) {
780
if(opt_check(opt, "remove")) {
781
if(unlink(filename)) {
782
logg("^%s: Can't remove\n", filename);
785
logg("%s: Removed\n", filename);
787
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
788
move_infected(filename, opt);
794
/* no viruses found in archive, we scan just in case a raw file
796
if((ret = checkfile(filename, engine, limits, 0, 1)) == CL_VIRUS) {
797
if(opt_check(opt, "remove")) {
798
if(unlink(filename)) {
799
logg("^%s: Can't remove\n", filename);
802
logg("%s: Removed\n", filename);
804
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
805
move_infected(filename, opt);
809
logg("%s: Infected.Archive FOUND\n", filename);
812
fprintf(stderr, "\007");
814
if(opt_check(opt, "remove")) {
815
if(unlink(filename)) {
816
logg("^%s: Can't remove\n", filename);
819
logg("%s: Removed\n", filename);
821
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
822
move_infected(filename, opt);
826
logg("^Strange value (%d) returned in scancompressed()\n", ret);
831
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)
833
char *tmpdir, *gendir, *tmpfile, *pt;
837
stat(filename, &statbuf);
838
if(!S_ISREG(statbuf.st_mode)) {
839
logg("^Suspect archive %s (not a regular file)\n", filename);
843
/* check write access */
845
tmpdir = getenv("TMPDIR");
855
if(checkaccess(tmpdir, CLAMAVUSER, W_OK) != 1) {
856
logg("!Can't write to the temporary directory %s\n", tmpdir);
860
/* generate the temporary directory */
861
gendir = cli_gentemp(tmpdir);
862
if(mkdir(gendir, 0700)) {
863
logg("^Can't create the temporary directory %s\n", gendir);
864
exit(63); /* critical */
867
tmpfile = (char *) mcalloc(strlen(gendir) + strlen(filename) + 10, sizeof(char));
868
pt = strrchr(filename, '/');
870
pt = (char *) filename;
874
sprintf(tmpfile, "%s/%s", gendir, pt);
876
if(filecopy(filename, tmpfile) == -1) {
877
logg("!I/O error\n");
878
perror("copyfile()");
886
chown(gendir, user->pw_uid, user->pw_gid);
887
chown(tmpfile, user->pw_uid, user->pw_gid);
891
if((ret = treewalk(gendir, engine, user, opt, limits, options, 1)) == 1) {
892
logg("(Real infected archive: %s)\n", filename);
894
if(opt_check(opt, "remove")) {
895
if(unlink(filename)) {
896
logg("^%s: Can't remove\n", filename);
899
logg("%s: Removed\n", filename);
901
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
902
move_infected(filename, opt);
905
/* remove the directory - as clamav */
906
clamav_rmdirs(gendir);
914
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)
916
int ret, included, printclean = 1;
917
const struct optnode *optnode;
922
/* argh, don't scan /proc files */
924
if(stat(filename, &sb) != -1)
925
if(sb.st_dev == procdev) {
927
logg("%s: Excluded (/proc)\n", filename);
932
if(opt_check(opt, "exclude")) {
933
argument = opt_firstarg(opt, "exclude", &optnode);
935
if(match_regex(filename, argument) == 1) {
937
logg("%s: Excluded\n", filename);
940
argument = opt_nextarg(&optnode, "exclude");
944
if(opt_check(opt, "include")) {
946
argument = opt_firstarg(opt, "include", &optnode);
947
while(argument && !included) {
948
if(match_regex(filename, argument) == 1) {
952
argument = opt_nextarg(&optnode, "include");
957
logg("%s: Excluded\n", filename);
962
if(fileinfo(filename, 1) == 0) {
964
logg("%s: Empty file\n", filename);
969
if(checkaccess(filename, NULL, R_OK) != 1) {
971
logg("%s: Access denied\n", filename);
978
* check the extension - this is a special case, normally we don't need to
979
* do this (libclamav detects archive by its magic string), but here we
980
* want to know the exit code from internal unpacker and try to use
981
* external (if provided) when internal cannot extract data.
984
if((cli_strbcasestr(filename, ".zip") || cli_strbcasestr(filename, ".rar")) && (options & CL_SCAN_ARCHIVE)) {
985
/* try to use internal archivers */
986
if((ret = checkfile(filename, engine, limits, options, 1)) == CL_VIRUS) {
987
if(opt_check(opt, "remove")) {
988
if(unlink(filename)) {
989
logg("^%s: Can't remove\n", filename);
992
logg("%s: Removed\n", filename);
994
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
995
move_infected(filename, opt);
999
} else if(ret == CL_CLEAN) {
1001
} else if(ret == 54) {
1005
/* in other case try to continue with external archivers */
1006
options &= ~CL_SCAN_ARCHIVE; /* and disable decompression for the checkfile() below */
1010
if((cli_strbcasestr(filename, ".zip") && opt_check(opt, "unzip"))
1011
|| (cli_strbcasestr(filename, ".rar") && opt_check(opt, "unrar"))
1012
|| (cli_strbcasestr(filename, ".arj") && opt_check(opt, "arj"))
1013
|| (cli_strbcasestr(filename, ".zoo") && opt_check(opt, "unzoo"))
1014
|| (cli_strbcasestr(filename, ".jar") && opt_check(opt, "jar"))
1015
|| (cli_strbcasestr(filename, ".lzh") && opt_check(opt, "lha"))
1016
|| (cli_strbcasestr(filename, ".tar") && opt_check(opt, "tar"))
1017
|| (cli_strbcasestr(filename, ".deb") && opt_check(opt, "deb"))
1018
|| ((cli_strbcasestr(filename, ".tar.gz") || cli_strbcasestr(filename, ".tgz"))
1019
&& (opt_check(opt, "tgz") || opt_check(opt, "deb"))) ) {
1021
/* check permissions */
1022
switch(checkaccess(filename, CLAMAVUSER, R_OK)) {
1024
logg("^Can't get information about user "CLAMAVUSER"\n");
1025
exit(60); /* this is a critical problem so we just exit here */
1027
logg("^Can't fork\n");
1029
case 0: /* read access denied */
1032
logg("^%s: Access denied to archive\n", filename);
1035
if(limits && limits->maxfilesize)
1036
if((unsigned int) fileinfo(filename, 1) / 1024 > limits->maxfilesize) {
1038
logg("^%s: Archive too big\n", filename);
1042
return(scandenied(filename, engine, user, opt, limits, options));
1046
return(scancompressed(filename, engine, user, opt, limits, options));
1050
if((ret = checkfile(filename, engine, limits, options, printclean)) == CL_VIRUS) {
1051
if(opt_check(opt, "remove")) {
1052
if(unlink(filename)) {
1053
logg("^%s: Can't remove\n", filename);
1056
logg("%s: Removed\n", filename);
1058
} else if (opt_check(opt, "move") || opt_check(opt, "copy"))
1059
move_infected(filename, opt);