Browse code

newlimits merge

git-svn: trunk@3614

aCaB authored on 2008/02/12 02:38:21
Showing 29 changed files
... ...
@@ -1,3 +1,13 @@
1
+Mon Feb 11 18:19:48 CET 2008 (acab)
2
+-----------------------------------
3
+  * WARNING: NEW LOGIC IN SCAN LIMITS
4
+    The logic in the scanner limits have been reworked. This results in
5
+    different command line options to clamscan, different config options to
6
+    clamd and, overall, a different behaviour.
7
+    I repeat: SOME THINGS HAVE CHANGED, BE CAREFUL!
8
+    At the moment this is a work in progress. Final version will be available
9
+    soon which will include a detailed ChangeLog and updated documentation.
10
+
1 11
 Mon Feb 11 18:33:22 EET 2008 (edwin)
2 12
 ------------------------------------
3 13
   * libclamav/mbox.c: replace getc() with getc_unlocked() when available. This
... ...
@@ -315,33 +315,36 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
315 315
     logg("*Listening daemon: PID: %u\n", (unsigned int) mainpid);
316 316
     max_threads = cfgopt(copt, "MaxThreads")->numarg;
317 317
 
318
-    if(cfgopt(copt, "ScanArchive")->enabled) {
318
+    if(cfgopt(copt, "ScanArchive")->enabled) { /* FIXMELIMITS: unparsed if archives disabled! */
319 319
 
320 320
 	/* set up limits */
321 321
 	memset(&limits, 0, sizeof(struct cl_limits));
322 322
 
323
-	if((limits.maxfilesize = cfgopt(copt, "ArchiveMaxFileSize")->numarg)) {
324
-	    logg("Archive: Archived file size limit set to %lu bytes.\n", limits.maxfilesize);
323
+	logg("Archive support enabled.\n");
324
+	options |= CL_SCAN_ARCHIVE;
325
+
326
+	if((limits.maxfilesize = cfgopt(copt, "MaxScanSize")->numarg)) {
327
+	    logg("Limits: Global size limit set to %lu bytes.\n", limits.maxscansize);
325 328
 	} else {
326
-	    logg("^Archive: File size limit protection disabled.\n");
329
+	    logg("^Limits: Global size limit protection disabled.\n");
327 330
 	}
328 331
 
329
-	if((limits.maxreclevel = cfgopt(copt, "ArchiveMaxRecursion")->numarg)) {
330
-	    logg("Archive: Recursion level limit set to %u.\n", limits.maxreclevel);
332
+	if((limits.maxfilesize = cfgopt(copt, "MaxFileSize")->numarg)) {
333
+	    logg("Limits: File size limit set to %lu bytes.\n", limits.maxfilesize);
331 334
 	} else {
332
-	    logg("^Archive: Recursion level limit protection disabled.\n");
335
+	    logg("^Limits: File size limit protection disabled.\n");
333 336
 	}
334 337
 
335
-	if((limits.maxfiles = cfgopt(copt, "ArchiveMaxFiles")->numarg)) {
336
-	    logg("Archive: Files limit set to %u.\n", limits.maxfiles);
338
+	if((limits.maxreclevel = cfgopt(copt, "MaxRecursion")->numarg)) {
339
+	    logg("Limits: Recursion level limit set to %u.\n", limits.maxreclevel);
337 340
 	} else {
338
-	    logg("^Archive: Files limit protection disabled.\n");
341
+	    logg("^Limits: Recursion level limit protection disabled.\n");
339 342
 	}
340 343
 
341
-	if((limits.maxratio = cfgopt(copt, "ArchiveMaxCompressionRatio")->numarg)) {
342
-	    logg("Archive: Compression ratio limit set to %u.\n", limits.maxratio);
344
+	if((limits.maxfiles = cfgopt(copt, "MaxFiles")->numarg)) {
345
+	    logg("Limits: Files limit set to %u.\n", limits.maxfiles);
343 346
 	} else {
344
-	    logg("^Archive: Compression ratio limit disabled.\n");
347
+	    logg("^Limits: Files limit protection disabled.\n");
345 348
 	}
346 349
 
347 350
 	if(cfgopt(copt, "ArchiveLimitMemoryUsage")->enabled) {
... ...
@@ -350,22 +353,12 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
350 350
 	} else {
351 351
 	    limits.archivememlim = 0;
352 352
 	}
353
-    }
354
-
355
-    if(cfgopt(copt, "ScanArchive")->enabled) {
356
-	logg("Archive support enabled.\n");
357
-	options |= CL_SCAN_ARCHIVE;
358 353
 
359 354
 	if(cfgopt(copt, "ArchiveBlockEncrypted")->enabled) {
360 355
 	    logg("Archive: Blocking encrypted archives.\n");
361 356
 	    options |= CL_SCAN_BLOCKENCRYPTED;
362 357
 	}
363 358
 
364
-	if(cfgopt(copt, "ArchiveBlockMax")->enabled) {
365
-	    logg("Archive: Blocking archives that exceed limits.\n");
366
-	    options |= CL_SCAN_BLOCKMAX;
367
-	}
368
-
369 359
     } else {
370 360
 	logg("Archive support disabled.\n");
371 361
     }
... ...
@@ -407,12 +400,6 @@ int acceptloop_th(int *socketds, int nsockets, struct cl_engine *engine, unsigne
407 407
 	    options |= CL_SCAN_MAILURL;
408 408
 	}
409 409
 
410
-	if((limits.maxmailrec = cfgopt(copt, "MailMaxRecursion")->numarg)) {
411
-	    logg("Mail: Recursion level limit set to %u.\n", limits.maxmailrec);
412
-	} else {
413
-	    logg("^Mail: Recursion level limit protection disabled.\n");
414
-	}
415
-
416 410
     } else {
417 411
 	logg("Mail files support disabled.\n");
418 412
     }
... ...
@@ -146,11 +146,22 @@ int main(int argc, char **argv)
146 146
 
147 147
     /* validate some numerical options */
148 148
 
149
-    if(opt_check(opt, "max-space")) {
150
-	pt = opt_arg(opt, "max-space");
149
+    if(opt_check(opt, "max-scansize")) {
150
+	pt = opt_arg(opt, "max-scansize");
151 151
 	if(!strchr(pt, 'M') && !strchr(pt, 'm')) {
152 152
 	    if(!cli_isnumber(pt)) {
153
-		logg("!--max-space requires a natural number\n");
153
+		logg("!--max-scansize requires a natural number\n");
154
+		opt_free(opt);
155
+		return 40;
156
+	    }
157
+	}
158
+    }
159
+
160
+    if(opt_check(opt, "max-filesize")) {
161
+	pt = opt_arg(opt, "max-filesize");
162
+	if(!strchr(pt, 'M') && !strchr(pt, 'm')) {
163
+	    if(!cli_isnumber(pt)) {
164
+		logg("!--max-filesize requires a natural number\n");
154 165
 		opt_free(opt);
155 166
 		return 40;
156 167
 	    }
... ...
@@ -313,14 +324,11 @@ void help(void)
313 313
     mprintf("    --block-max                          Block archives that exceed limits\n");
314 314
     mprintf("    --mail-follow-urls                   Download and scan URLs\n");
315 315
     mprintf("\n");
316
-    mprintf("    --max-space=#n                       Only extract first #n kilobytes from\n");
317
-    mprintf("                                         archived files\n");
318
-    mprintf("    --max-files=#n                       Only extract first #n files from\n");
319
-    mprintf("                                         archives\n");
320
-    mprintf("    --max-ratio=#n                       Maximum compression ratio limit\n");
316
+    mprintf("    --max-scansize=#n                    FIXMELIMITS\n");
317
+    mprintf("    --max-filesize=#n                    FIXMELIMITS\n");
318
+    mprintf("    --max-files=#n                       FIXMELIMITS\n");
321 319
     mprintf("    --max-recursion=#n                   Maximum archive recursion level\n");
322 320
     mprintf("    --max-dir-recursion=#n               Maximum directory recursion level\n");
323
-    mprintf("    --max-mail-recursion=#n              Maximum mail recursion level\n");
324 321
     mprintf("    --unzip[=FULLPATH]                   Enable support for .zip files\n");
325 322
     mprintf("    --unrar[=FULLPATH]                   Enable support for .rar files\n");
326 323
     mprintf("    --arj[=FULLPATH]                     Enable support for .arj files\n");
... ...
@@ -54,17 +54,15 @@ static struct option clamscan_longopt[] = {
54 54
     {"include", 1, 0, 0},
55 55
     {"include-dir", 1, 0, 0},
56 56
     {"max-files", 1, 0, 0},
57
-    {"max-space", 1, 0, 0},
58
-    {"max-ratio", 1, 0, 0},
57
+    {"max-filesize", 1, 0, 0},
58
+    {"max-scansize", 1, 0, 0},
59 59
     {"max-recursion", 1, 0, 0},
60 60
     {"max-dir-recursion", 1, 0, 0},
61
-    {"max-mail-recursion", 1, 0, 0},
62 61
     {"detect-pua", 0, 0, 0},
63 62
     {"disable-archive", 0, 0, 0},
64 63
     {"no-archive", 0, 0, 0},
65 64
     {"detect-broken", 0, 0, 0},
66 65
     {"block-encrypted", 0, 0, 0},
67
-    {"block-max", 0, 0, 0},
68 66
     {"no-pe", 0, 0, 0},
69 67
     {"no-elf", 0, 0, 0},
70 68
     {"no-ole2", 0, 0, 0},
... ...
@@ -220,9 +220,22 @@ int scanmanager(const struct optstruct *opt)
220 220
     /* set limits */
221 221
     memset(&limits, 0, sizeof(struct cl_limits));
222 222
 
223
-    if(opt_check(opt, "max-space")) {
223
+    if(opt_check(opt, "max-scansize")) {
224 224
 	char *cpy, *ptr;
225
-	ptr = opt_arg(opt, "max-space");
225
+	ptr = opt_arg(opt, "max-scansize");
226
+	if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
227
+	    cpy = calloc(strlen(ptr), 1);
228
+	    strncpy(cpy, ptr, strlen(ptr) - 1);
229
+	    limits.maxfilesize = atoi(cpy) * 1024 * 1024;
230
+	    free(cpy);
231
+	} else
232
+	    limits.maxscansize = atoi(ptr) * 1024;
233
+    } else
234
+	limits.maxscansize = 104857600;  /* FIXMELIMITS */
235
+
236
+    if(opt_check(opt, "max-filesize")) {
237
+	char *cpy, *ptr;
238
+	ptr = opt_arg(opt, "max-filesize");
226 239
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
227 240
 	    cpy = calloc(strlen(ptr), 1);
228 241
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
... ...
@@ -231,7 +244,7 @@ int scanmanager(const struct optstruct *opt)
231 231
 	} else
232 232
 	    limits.maxfilesize = atoi(ptr) * 1024;
233 233
     } else
234
-	limits.maxfilesize = 10485760;
234
+	limits.maxfilesize = 10485760;  /* FIXMELIMITS */
235 235
 
236 236
     if(opt_check(opt, "max-files"))
237 237
 	limits.maxfiles = atoi(opt_arg(opt, "max-files"));
... ...
@@ -243,16 +256,6 @@ int scanmanager(const struct optstruct *opt)
243 243
     else
244 244
         limits.maxreclevel = 8;
245 245
 
246
-    if(opt_check(opt, "max-mail-recursion"))
247
-        limits.maxmailrec = atoi(opt_arg(opt, "max-mail-recursion"));
248
-    else
249
-        limits.maxmailrec = 64;
250
-
251
-    if(opt_check(opt, "max-ratio"))
252
-        limits.maxratio = atoi(opt_arg(opt, "max-ratio"));
253
-    else
254
-        limits.maxratio = 250;
255
-
256 246
     /* set options */
257 247
 
258 248
     if(opt_check(opt, "disable-archive") || opt_check(opt, "no-archive"))
... ...
@@ -266,9 +269,6 @@ int scanmanager(const struct optstruct *opt)
266 266
     if(opt_check(opt, "block-encrypted"))
267 267
 	options |= CL_SCAN_BLOCKENCRYPTED;
268 268
 
269
-    if(opt_check(opt, "block-max"))
270
-	options |= CL_SCAN_BLOCKMAX;
271
-
272 269
     if(opt_check(opt, "no-pe"))
273 270
 	options &= ~CL_SCAN_PE;
274 271
     else
... ...
@@ -425,9 +425,10 @@ static int clamav_unpack(const char *prog, const char **args, const char *tmpdir
425 425
     else
426 426
 	maxfiles = 0;
427 427
 
428
-    if(opt_check(opt, "max-space")) {
428
+    /* FIXMELIMITS */
429
+    if(opt_check(opt, "max-filesize")) {
429 430
 	    char *cpy, *ptr;
430
-	ptr = opt_arg(opt, "max-space");
431
+	ptr = opt_arg(opt, "max-filesize");
431 432
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
432 433
 	    cpy = calloc(strlen(ptr), 1);
433 434
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
... ...
@@ -224,10 +224,6 @@ LocalSocket /tmp/clamd.socket
224 224
 # Default: no
225 225
 #MailFollowURLs no
226 226
 
227
-# Recursion level limit for the mail scanner.
228
-# Default: 64
229
-#MailMaxRecursion 128
230
-
231 227
 # With this option enabled ClamAV will try to detect phishing attempts by using
232 228
 # signatures.
233 229
 # Default: yes
... ...
@@ -270,28 +266,27 @@ LocalSocket /tmp/clamd.socket
270 270
 # The options below protect your system against Denial of Service attacks
271 271
 # using archive bombs.
272 272
 
273
+# FIXMELIMITS
274
+# Value of 0 disables the limit.
275
+# Default: FIXMELIMITS
276
+#MaxScanSize 15M
277
+
273 278
 # Files in archives larger than this limit won't be scanned.
274 279
 # Value of 0 disables the limit.
275 280
 # Default: 10M
276
-#ArchiveMaxFileSize 15M
281
+#MaxFileSize 15M
277 282
 
278 283
 # Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR
279 284
 # file, all files within it will also be scanned. This options specifies how
280 285
 # deeply the process should be continued.
281 286
 # Value of 0 disables the limit.
282 287
 # Default: 8
283
-#ArchiveMaxRecursion 10
288
+#MaxRecursion 10
284 289
 
285 290
 # Number of files to be scanned within an archive.
286 291
 # Value of 0 disables the limit.
287 292
 # Default: 1000
288
-#ArchiveMaxFiles 1500
289
-
290
-# If a file in an archive is compressed more than ArchiveMaxCompressionRatio
291
-# times it will be marked as a virus (Oversized.ArchiveType, e.g. Oversized.Zip)
292
-# Value of 0 disables the limit.
293
-# Default: 250
294
-#ArchiveMaxCompressionRatio 300
293
+#MaxFiles 1500
295 294
 
296 295
 # Use slower but memory efficient decompression algorithm.
297 296
 # only affects the bzip2 decompressor.
... ...
@@ -302,12 +297,6 @@ LocalSocket /tmp/clamd.socket
302 302
 # Default: no
303 303
 #ArchiveBlockEncrypted no
304 304
 
305
-# Mark archives as viruses (e.g. RAR.ExceededFileSize, Zip.ExceededFilesLimit)
306
-# if ArchiveMaxFiles, ArchiveMaxFileSize, or ArchiveMaxRecursion limit is
307
-# reached.
308
-# Default: no
309
-#ArchiveBlockMax no
310
-
311 305
 
312 306
 ##
313 307
 ## Clamuko settings
... ...
@@ -181,7 +181,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
181 181
   uint8_t b[300], comp;
182 182
   uint8_t *buf = b;
183 183
   uint32_t s, m4sum=0;
184
-  int i;
184
+  int i, ret;
185 185
   unsigned int files=0;
186 186
   char tempfile[1024];
187 187
   struct UNP UNP;
... ...
@@ -192,7 +192,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
192 192
   for (i=0; i<16; i++)
193 193
     m4sum += buf[i];
194 194
 
195
-  while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) {
195
+  while((ret=cli_checklimits("autoit", ctx, 0, 0, 0))==CL_CLEAN) {
196 196
     buf = b;
197 197
     if (cli_readn(desc, buf, 8)!=8)
198 198
       return CL_CLEAN;
... ...
@@ -250,8 +250,8 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
250 250
     cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x45aa);
251 251
     cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xc3d2);
252 252
 
253
-    if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) {
254
-      cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
253
+    
254
+    if(cli_checklimits("autoit", ctx, UNP.csize, 0, 0)!=CL_CLEAN) {
255 255
       lseek(desc, UNP.csize, SEEK_CUR);
256 256
       continue;
257 257
     }
... ...
@@ -275,8 +275,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
275 275
 
276 276
       if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4))))
277 277
 	UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */
278
-      if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) {
279
-	cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
278
+      if(cli_checklimits("autoit", ctx, UNP.usize, 0, 0)!=CL_CLEAN) {
280 279
 	free(buf);
281 280
 	continue;
282 281
       }
... ...
@@ -382,8 +381,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
382 382
     close(i);
383 383
     if(!cli_leavetemps_flag) unlink(tempfile);
384 384
   }
385
-  cli_dbgmsg("autoit: files limit reached (max: %u)\n", ctx->limits->maxfiles);
386
-  return CL_EMAXFILES;
385
+  return ret;
387 386
 }
388 387
 
389 388
 
... ...
@@ -478,7 +476,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
478 478
   uint8_t b[600], comp, script;
479 479
   uint8_t *buf;
480 480
   uint32_t s;
481
-  int i;
481
+  int i, ret;
482 482
   unsigned int files=0;
483 483
   char tempfile[1024];
484 484
   const char prefixes[] = { '\0', '\0', '@', '$', '\0', '.', '"', '#' };
... ...
@@ -492,7 +490,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
492 492
   /*   buf+=0x10; */
493 493
   lseek(desc, 16, SEEK_CUR);   /* for now we just skip the garbage */
494 494
 
495
-  while(!ctx->limits || !ctx->limits->maxfiles || files < ctx->limits->maxfiles) {
495
+  while((ret=cli_checklimits("cli_autoit", ctx, 0, 0, 0))==CL_CLEAN) {
496 496
     buf = b;
497 497
     if (cli_readn(desc, buf, 8)!=8)
498 498
       return CL_CLEAN;
... ...
@@ -555,8 +553,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
555 555
     cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x87bc);
556 556
     cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xa685);
557 557
 
558
-    if(ctx->limits && ctx->limits->maxfilesize && UNP.csize > ctx->limits->maxfilesize) {
559
-      cli_dbgmsg("autoit: skipping file due to size limit (%u, max: %lu)\n", UNP.csize, ctx->limits->maxfilesize);
558
+    if(cli_checklimits("autoit", ctx, UNP.csize, 0, 0)!=CL_CLEAN) {
560 559
       lseek(desc, UNP.csize, SEEK_CUR);
561 560
       continue;
562 561
     }
... ...
@@ -581,7 +578,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
581 581
 
582 582
       if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4))))
583 583
 	UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */
584
-      if(ctx->limits && ctx->limits->maxfilesize && UNP.usize > ctx->limits->maxfilesize) {
584
+      if(cli_checklimits("autoit", ctx, UNP.usize, 0, 0)!=CL_CLEAN) {
585 585
 	free(buf);
586 586
 	continue;
587 587
       }
... ...
@@ -893,8 +890,7 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
893 893
     close(i);
894 894
     if(!cli_leavetemps_flag) unlink(tempfile);
895 895
   }
896
-  cli_dbgmsg("autoit: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
897
-  return CL_EMAXFILES;
896
+  return ret;
898 897
 }
899 898
 
900 899
 #endif /* FPU_WORDS_BIGENDIAN */
... ...
@@ -617,7 +617,7 @@ fileblobAddData(fileblob *fb, const unsigned char *data, size_t len)
617 617
 		if(ctx) {
618 618
 			int do_scan = 1;
619 619
 
620
-			if(ctx->limits)
620
+			if(ctx->limits && ctx->limits->maxfilesize) /* FIXMELIMITS */
621 621
 				if(fb->bytes_scanned >= ctx->limits->maxfilesize)
622 622
 					do_scan = 0;
623 623
 
... ...
@@ -49,7 +49,7 @@
49 49
 #endif
50 50
 
51 51
 /* hard limits */
52
-#define CAB_FOLDER_LIMIT    5000
52
+#define CAB_FOLDER_LIMIT    5000 /* FIXMELIMITS */
53 53
 #define CAB_FILE_LIMIT	    5000
54 54
 
55 55
 /* Cabinet format data structures */
... ...
@@ -116,5 +116,8 @@ int cli_chm_open(int fd, const char *dirname, chm_metadata_t *metadata);
116 116
 int cli_chm_prepare_file(int fd, char *dirname, chm_metadata_t *metadata);
117 117
 int cli_chm_extract_file(int fd, char *dirname, chm_metadata_t *metadata);
118 118
 void cli_chm_close(chm_metadata_t *metadata);
119
-
119
+int cli_chm_open(int fd, const char *dirname, chm_metadata_t *metadata);
120
+void cli_chm_close(chm_metadata_t *metadata);
121
+int cli_chm_extract_file(int fd, char *dirname, chm_metadata_t *metadata);
122
+int cli_chm_prepare_file(int fd, char *dirname, chm_metadata_t *metadata);
120 123
 #endif
... ...
@@ -142,16 +142,17 @@ struct cl_engine {
142 142
 };
143 143
 
144 144
 struct cl_limits {
145
+    unsigned long int maxscansize;  /* during the scanning of archives this size
146
+				     * will never be exceeded
147
+				     */
148
+    unsigned long int maxfilesize;  /* compressed files will only be decompressed
149
+				     * and scanned up to this size
150
+				     */
145 151
     unsigned int maxreclevel;	    /* maximum recursion level for archives */
146 152
     unsigned int maxfiles;	    /* maximum number of files to be scanned
147 153
 				     * within a single archive
148 154
 				     */
149
-    unsigned int maxmailrec;	    /* maximum recursion level for mail files */
150
-    unsigned int maxratio;	    /* maximum compression ratio */
151 155
     unsigned short archivememlim;   /* limit memory usage for some unpackers */
152
-    unsigned long int maxfilesize;  /* compressed files larger than this limit
153
-				     * will not be scanned
154
-				     */
155 156
 };
156 157
 
157 158
 struct cl_stat {
... ...
@@ -1988,7 +1988,6 @@ parseEmailHeader(message *m, const char *line, const table_t *rfc821)
1988 1988
 
1989 1989
 /*
1990 1990
  * This is a recursive routine.
1991
- * FIXME: We are not passed &mrec so we can't check against MAX_MAIL_RECURSION
1992 1991
  *
1993 1992
  * This function parses the body of mainMessage and saves its attachments in dir
1994 1993
  *
... ...
@@ -2011,22 +2010,17 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
2011 2011
 	cli_dbgmsg("in parseEmailBody, %u files saved so far\n",
2012 2012
 		mctx->files);
2013 2013
 
2014
-	if(limits) {
2015
-		if(limits->maxmailrec) {
2014
+	if(limits) { /* FIXMELIMITS */
2015
+		if(limits->maxreclevel) {
2016 2016
 			const cli_ctx *ctx = mctx->ctx;	/* needed for BLOCKMAX :-( */
2017 2017
 
2018 2018
 			/*
2019 2019
 			 * This is approximate
2020 2020
 			 */
2021
-			if(recursion_level > limits->maxmailrec) {
2021
+			if(recursion_level > limits->maxreclevel) {
2022 2022
 
2023 2023
 				cli_warnmsg("parseEmailBody: hit maximum recursion level (%u)\n", recursion_level);
2024
-				if(BLOCKMAX) {
2025
-					if(ctx->virname)
2026
-						*ctx->virname = "MIME.RecursionLimit";
2027
-					return VIRUS;
2028
-				} else
2029
-					return MAXREC;
2024
+				return MAXREC;
2030 2025
 			}
2031 2026
 		}
2032 2027
 		if(limits->maxfiles && (mctx->files >= limits->maxfiles)) {
... ...
@@ -108,15 +108,8 @@ int cli_msexpand(int fd, int ofd, cli_ctx *ctx)
108 108
 
109 109
     cli_dbgmsg("MSEXPAND: File size from header: %u\n", hdr.fsize);
110 110
 
111
-    if(ctx->limits && ctx->limits->maxfilesize && (hdr.fsize > ctx->limits->maxfilesize)) {
112
-	cli_dbgmsg("MSEXPAND: Size exceeded (%u, max: %lu)\n", hdr.fsize, ctx->limits->maxfilesize);
113
-        if(BLOCKMAX) {
114
-	    *ctx->virname = "MSEXPAND.ExceededFileSize";
115
-            return CL_VIRUS;
116
-        }
117
-	hdr.fsize = ctx->limits->maxfilesize;
118
-	cli_dbgmsg("MSEXPAND: Only extracting first %u bytes\n", hdr.fsize); /* may extract up to 2kB more */
119
-    }
111
+    if(cli_checklimits("MSEXPAND", ctx, hdr.fsize, 0, 0)!=CL_CLEAN)
112
+        return CL_SUCCESS;
120 113
 
121 114
     while(1) {
122 115
 
... ...
@@ -163,7 +163,6 @@ static int nsis_decomp(struct nsis_st *n) {
163 163
       break;
164 164
     case Z_STREAM_END:
165 165
       ret = CL_BREAK;
166
-    /* FIXME: regression needed */ 
167 166
     }
168 167
     n->nsis.avail_in = n->z.avail_in;
169 168
     n->nsis.next_in = n->z.next_in;
... ...
@@ -184,10 +183,9 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
184 184
     cli_dbgmsg("NSIS: extraction complete\n");
185 185
     return CL_BREAK;
186 186
   }
187
-  if (ctx->limits && ctx->limits->maxfiles && n->fno >= ctx->limits->maxfiles) {
188
-    cli_dbgmsg("NSIS: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
189
-    return CL_EMAXFILES;
190
-  }
187
+  
188
+  if ((ret=cli_checklimits("NSIS", ctx, 0, 0, 0))!=CL_CLEAN)
189
+    return ret;
191 190
 
192 191
   if (n->fno)
193 192
     snprintf(n->ofn, 1023, "%s/content.%.3u", n->dir, n->fno);
... ...
@@ -225,11 +223,10 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
225 225
 
226 226
     n->asz -= size+4;
227 227
 
228
-    if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
229
-      cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize);
228
+    if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
230 229
       close(n->ofd);
231 230
       if (lseek(n->ifd, size, SEEK_CUR)==-1) return CL_EIO;
232
-      return CL_EMAXSIZE;
231
+      return ret;
233 232
     }
234 233
     if (!(ibuf= (unsigned char *) cli_malloc(size))) {
235 234
       	cli_dbgmsg("NSIS: out of memory"__AT__"\n");
... ...
@@ -274,12 +271,11 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
274 274
 	  n->nsis.next_out = obuf;
275 275
 	  n->nsis.avail_out = BUFSIZ;
276 276
 	  loops=0;
277
-	  if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
278
-	    cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize);
277
+	  if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
279 278
 	    free(ibuf);
280 279
 	    close(n->ofd);
281 280
 	    nsis_shutdown(n);
282
-	    return CL_EMAXSIZE;
281
+	    return ret;
283 282
 	  }
284 283
 	} else if (++loops > 10) {
285 284
 	  cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
... ...
@@ -367,10 +363,9 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
367 367
     }
368 368
 
369 369
     size=cli_readint32(obuf);
370
-    if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
371
-      cli_dbgmsg("NSIS: Breaking out due to filesize limit (%u, max: %lu) in solid archive\n", size, ctx->limits->maxfilesize);
370
+    if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
372 371
       close(n->ofd);
373
-      return CL_EFORMAT;
372
+      return ret;
374 373
     }
375 374
 
376 375
     n->nsis.next_out = obuf;
... ...
@@ -503,10 +498,6 @@ int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset) {
503 503
 	struct nsis_st nsist;
504 504
 
505 505
     cli_dbgmsg("in scannulsft()\n");
506
-    if(ctx->limits && ctx->limits->maxreclevel && ctx->arec >= ctx->limits->maxreclevel) {
507
-        cli_dbgmsg("Archive recursion limit exceeded (arec == %u).\n", ctx->arec+1);
508
-	return CL_EMAXREC;
509
-    }
510 506
 
511 507
     memset(&nsist, 0, sizeof(struct nsis_st));
512 508
 
... ...
@@ -522,33 +513,25 @@ int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset) {
522 522
 
523 523
     if(cli_leavetemps_flag) cli_dbgmsg("NSIS: Extracting files to %s\n", nsist.dir);
524 524
 
525
-    ctx->arec++;
526
-
527 525
     do {
528 526
         ret = cli_nsis_unpack(&nsist, ctx);
529
-	if(ret != CL_SUCCESS) {
530
-	    if(ret == CL_EMAXSIZE) {
531
-	        if(BLOCKMAX) {
532
-		    *ctx->virname = "NSIS.ExceededFileSize";
533
-		    ret=CL_VIRUS;
534
-		} else {
535
-		    ret = nsist.solid ? CL_BREAK : CL_SUCCESS;
536
-		}
537
-	    }
538
-	} else {
539
-	    cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno);
540
-	    lseek(nsist.ofd, 0, SEEK_SET);
541
-	    if(nsist.fno == 1)
542
-	        ret=cli_scandesc(nsist.ofd, ctx, 0, 0, 0, NULL);
543
-	    else
544
-	        ret=cli_magic_scandesc(nsist.ofd, ctx);
545
-	    close(nsist.ofd);
546
-	    if(!cli_leavetemps_flag)
547
-	        unlink(nsist.ofn);
527
+	if (ret == CL_SUCCESS) {
528
+	  cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno);
529
+	  lseek(nsist.ofd, 0, SEEK_SET);
530
+	  if(nsist.fno == 1)
531
+	    ret=cli_scandesc(nsist.ofd, ctx, 0, 0, 0, NULL);
532
+	  else
533
+	    ret=cli_magic_scandesc(nsist.ofd, ctx);
534
+	  close(nsist.ofd);
535
+	  if(!cli_leavetemps_flag)
536
+	    unlink(nsist.ofn);
537
+	} else if(ret == CL_EMAXSIZE) {
538
+	    cli_errmsg("returned %d\n", ret);
539
+	    ret = nsist.solid ? CL_BREAK : CL_SUCCESS;
548 540
 	}
549 541
     } while(ret == CL_SUCCESS);
550 542
 
551
-    if(ret == CL_BREAK)
543
+    if(ret == CL_BREAK || ret == CL_EMAXFILES)
552 544
 	ret = CL_CLEAN;
553 545
 
554 546
     cli_nsis_free(&nsist);
... ...
@@ -558,7 +541,6 @@ int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset) {
558 558
 
559 559
     free(nsist.dir);
560 560
 
561
-    ctx->arec--;    
562 561
     return ret;
563 562
 }
564 563
 
... ...
@@ -475,7 +475,9 @@ static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir,
475 475
 	if ((prop_index < 0) || (prop_index > (int32_t) hdr->max_block_no) || (rec_level > 100) || (*file_count > 100000)) {
476 476
 		return;
477 477
 	}
478
-
478
+	/* FIXMELIMITS
479
+	 * DOES recursion on virtual object make sense ?
480
+	 * WHY no size checking ? */
479 481
 	if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
480 482
 		cli_dbgmsg("OLE2: File limit reached (max: %d)\n", limits->maxfiles);
481 483
 		return;
... ...
@@ -778,7 +780,7 @@ static int ole2_read_header(int fd, ole2_header_t *hdr)
778 778
 }
779 779
 #endif
780 780
 
781
-int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits)
781
+int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
782 782
 {
783 783
 	ole2_header_t hdr;
784 784
 	int hdr_size;
... ...
@@ -878,7 +880,7 @@ int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits
878 878
 	
879 879
 	/* OR */
880 880
 	
881
-	ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, limits);
881
+	ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, ctx->limits);
882 882
 
883 883
 abort:
884 884
 #ifdef HAVE_MMAP
... ...
@@ -24,8 +24,8 @@
24 24
 #ifndef __OLE2_EXTRACT_H
25 25
 #define __OLE2_EXTRACT_H
26 26
 
27
-#include "clamav.h"
27
+#include "others.h"
28 28
 
29
-int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits);
29
+int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx);
30 30
 
31 31
 #endif
... ...
@@ -204,6 +204,51 @@ const char *cl_strerror(int clerror)
204 204
     }
205 205
 }
206 206
 
207
+int cli_checklimits(const char *who, cli_ctx *ctx, unsigned long need1, unsigned long need2, unsigned long need3) {
208
+    int ret = CL_SUCCESS;
209
+    unsigned long needed;
210
+
211
+    /* if called without limits, go on, unpack, scan */
212
+    if(!ctx || !ctx->limits) return CL_CLEAN;
213
+
214
+    needed = (need1>need2)?need1:need2;
215
+    needed = (needed>need3)?needed:need3;
216
+
217
+    /* if we have global scan limits */
218
+    if(needed && ctx->limits->maxscansize) {
219
+        /* if the remaining scansize is too small... */
220
+        if(ctx->limits->maxscansize-ctx->scansize<needed) {
221
+	    /* ... we tell the caller to skip this file */
222
+	    cli_dbgmsg("%s: scansize exceeded (initial: %lu, remaining: %lu, needed: %lu)\n", who, ctx->limits->maxscansize, ctx->scansize, needed);
223
+	    ret = CL_EMAXSIZE;
224
+	}
225
+    }
226
+
227
+    /* if we have per-file size limits, and we are overlimit... */
228
+    if(needed && ctx->limits->maxfilesize && ctx->limits->maxfilesize<needed) {
229
+	/* ... we tell the caller to skip this file */
230
+        cli_dbgmsg("%s: filesize exceeded (allowed: %lu, needed: %lu)\n", who, ctx->limits->maxfilesize, needed);
231
+	ret = CL_EMAXSIZE;
232
+    }
233
+
234
+    if(ctx->limits->maxfiles && ctx->scannedfiles>=ctx->limits->maxfiles) {
235
+        cli_dbgmsg("%s: files limit reached (max: %u)\n", who, ctx->limits->maxfiles);
236
+	return CL_EMAXFILES;
237
+    }
238
+    return ret;
239
+}
240
+
241
+int cli_updatelimits(cli_ctx *ctx, unsigned long needed) {
242
+    int ret=cli_checklimits("cli_updatelimits", ctx, needed, 0, 0);
243
+
244
+    if (ret != CL_CLEAN) return ret;
245
+    ctx->scannedfiles++;
246
+    ctx->scansize+=needed;
247
+    if(ctx->scansize > ctx->limits->maxscansize)
248
+        ctx->scansize = ctx->limits->maxscansize;
249
+    return CL_CLEAN;
250
+}
251
+
207 252
 unsigned char *cli_md5digest(int desc)
208 253
 {
209 254
 	unsigned char *digest;
... ...
@@ -636,11 +681,7 @@ int cli_rmdirs(const char *dirname)
636 636
 			    return -1;
637 637
 			}
638 638
 
639
-#ifdef	C_WINDOWS
640
-			sprintf(path, "%s\\%s", dirname, dent->d_name);
641
-#else
642 639
 			sprintf(path, "%s/%s", dirname, dent->d_name);
643
-#endif
644 640
 
645 641
 			/* stat the file */
646 642
 			if(lstat(path, &statbuf) != -1) {
... ...
@@ -83,9 +83,10 @@ typedef struct {
83 83
     const struct cli_matcher *root;
84 84
     const struct cl_engine *engine;
85 85
     const struct cl_limits *limits;
86
+    unsigned long scansize;
86 87
     unsigned int options;
87
-    unsigned int arec;
88
-    unsigned int mrec;
88
+    unsigned int recursion;
89
+    unsigned int scannedfiles;
89 90
     unsigned int found_possibly_unwanted;
90 91
     struct cli_dconf *dconf;
91 92
 } cli_ctx;
... ...
@@ -99,7 +100,7 @@ typedef struct {
99 99
 #define SCAN_ELF	    (ctx->options & CL_SCAN_ELF)
100 100
 #define SCAN_ALGO 	    (ctx->options & CL_SCAN_ALGORITHMIC)
101 101
 #define DETECT_ENCRYPTED    (ctx->options & CL_SCAN_BLOCKENCRYPTED)
102
-#define BLOCKMAX	    (ctx->options & CL_SCAN_BLOCKMAX)
102
+/* #define BLOCKMAX	    (ctx->options & CL_SCAN_BLOCKMAX) */
103 103
 #define DETECT_BROKEN	    (ctx->options & CL_SCAN_BLOCKBROKEN)
104 104
 
105 105
 /* based on macros from A. Melnikoff */
... ...
@@ -234,5 +235,7 @@ void cli_bitset_free(bitset_t *bs);
234 234
 int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
235 235
 int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
236 236
 const char* cli_ctime(const time_t *timep, char *buf, const size_t bufsize);
237
-
237
+int cli_checklimits(const char *, cli_ctx *, unsigned long, unsigned long, unsigned long);
238
+int cli_updatelimits(cli_ctx *, unsigned long);
239
+unsigned long cli_getsizelimit(cli_ctx *, unsigned long);
238 240
 #endif
... ...
@@ -79,10 +79,9 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx)
79 79
 	char *buf;	/* start of memory mapped area */
80 80
 	const char *p, *q, *trailerstart;
81 81
 	const char *xrefstart;	/* cross reference table */
82
-	const struct cl_limits *limits;
83 82
 	/*size_t xreflength;*/
84 83
 	table_t *md5table;
85
-	int printed_predictor_message, printed_embedded_font_message, rc;
84
+	int printed_predictor_message, printed_embedded_font_message, rc, ret;
86 85
 	unsigned int files;
87 86
 	struct stat statb;
88 87
 
... ...
@@ -192,12 +191,11 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx)
192 192
 
193 193
 	rc = CL_CLEAN;
194 194
 	files = 0;
195
-	limits = ctx->limits;
196 195
 
197 196
 	/*
198 197
 	 * The body section consists of a sequence of indirect objects
199 198
 	 */
200
-	while((p < xrefstart) && (rc == CL_CLEAN) &&
199
+	while((p < xrefstart) && ((rc=cli_checklimits("cli_pdf", ctx, 0, 0, 0))==CL_CLEAN) &&
201 200
 	      ((q = pdf_nextobject(p, bytesleft)) != NULL)) {
202 201
 		int is_ascii85decode, is_flatedecode, fout, len, has_cr;
203 202
 		/*int object_number, generation_number;*/
... ...
@@ -494,11 +492,6 @@ cli_pdf(const char *dir, int desc, const cli_ctx *ctx)
494 494
 		free(md5digest);
495 495
 		cli_dbgmsg("cli_pdf: extracted file %u to %s\n", ++files,
496 496
 			fullname);
497
-		if(limits && limits->maxfiles && (files >= limits->maxfiles)) {
498
-			/* Bug 698 */
499
-			cli_dbgmsg("cli_pdf: number of files exceeded %u\n", limits->maxfiles);
500
-			rc = CL_EMAXFILES;
501
-		}
502 497
 	}
503 498
 
504 499
 	munmap(buf, size);
... ...
@@ -541,7 +534,7 @@ try_flatedecode(unsigned char *buf, off_t real_len, off_t calculated_len, int fo
541 541
 static int
542 542
 flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx)
543 543
 {
544
-	int zstat;
544
+	int zstat, ret;
545 545
 	off_t nbytes;
546 546
 	z_stream stream;
547 547
 	unsigned char output[BUFSIZ];
... ...
@@ -611,17 +604,10 @@ flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx)
611 611
 					}
612 612
 					nbytes += written;
613 613
 
614
-					if(ctx->limits &&
615
-					   ctx->limits->maxfilesize &&
616
-					   (nbytes > (off_t) ctx->limits->maxfilesize)) {
617
-						cli_dbgmsg("cli_pdf: flatedecode size exceeded (%lu > %lu)\n",
618
-							   (unsigned long)nbytes, (unsigned long)ctx->limits->maxfilesize);
614
+					if((ret=cli_checklimits("cli_pdf", ctx, nbytes, 0, 0))!=CL_CLEAN) {
615
+						/* FIXMELIMITS */
619 616
 						inflateEnd(&stream);
620
-						if(BLOCKMAX) {
621
-							*ctx->virname = "PDF.ExceededFileSize";
622
-							return CL_VIRUS;
623
-						}
624
-						return CL_CLEAN;
617
+						return ret;
625 618
 					}
626 619
 					stream.next_out = output;
627 620
 					stream.avail_out = sizeof(output);
... ...
@@ -651,28 +637,6 @@ flatedecode(unsigned char *buf, off_t len, int fout, const cli_ctx *ctx)
651 651
 		}
652 652
 	}
653 653
 			
654
-
655
-	/*
656
-	 * On BSD systems total_in and total_out are "long long", so these
657
-	 * numbers could (in theory) get truncated in the debug statement
658
-	 */
659
-	cli_dbgmsg("cli_pdf: flatedecode in=%lu out=%lu ratio %lu (max %u)\n",
660
-		(unsigned long)stream.total_in, (unsigned long)stream.total_out,
661
-		(unsigned long)(stream.total_out / stream.total_in),
662
-		ctx->limits ? ctx->limits->maxratio : 0);
663
-
664
-	if(ctx->limits &&
665
-	   ctx->limits->maxratio &&
666
-	   ((stream.total_out / stream.total_in) > ctx->limits->maxratio)) {
667
-		cli_dbgmsg("cli_pdf: flatedecode Max ratio reached\n");
668
-		inflateEnd(&stream);
669
-		if(BLOCKMAX) {
670
-			*ctx->virname = "Oversized.PDF";
671
-			return CL_VIRUS;
672
-		}
673
-		return CL_CLEAN;
674
-	}
675
-
676 654
 #ifdef	SAVE_TMP
677 655
 	unlink(tmpfilename);
678 656
 #endif
... ...
@@ -82,15 +82,9 @@
82 82
 #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
83 83
 
84 84
 #define CLI_UNPSIZELIMITS(NAME,CHK) \
85
-if(ctx->limits && ctx->limits->maxfilesize && (CHK) > ctx->limits->maxfilesize) { \
86
-  cli_dbgmsg(NAME": Sizes exceeded (%lu > %lu)\n", (unsigned long)(CHK), (unsigned long)ctx->limits->maxfilesize); \
87
-    free(exe_sections); \
88
-    if(BLOCKMAX) { \
89
-        *ctx->virname = "PE."NAME".ExceededFileSize"; \
90
-        return CL_VIRUS; \
91
-    } else { \
92
-        return CL_CLEAN; \
93
-    } \
85
+if(cli_checklimits(NAME, ctx, (CHK), 0, 0)!=CL_CLEAN) {	\
86
+    free(exe_sections);					\
87
+    return CL_CLEAN;					\
94 88
 }
95 89
 
96 90
 #define CLI_UNPTEMP(NAME,FREEME) \
... ...
@@ -124,12 +118,6 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \
124 124
 	close(ndesc); \
125 125
 	unlink(tempfile); \
126 126
 	cli_dbgmsg("PESpin: Size exceeded\n"); \
127
-	if(BLOCKMAX) { \
128
-	    free(tempfile); \
129
-	    free(exe_sections); \
130
-	    *ctx->virname = "PE.Pespin.ExceededFileSize"; \
131
-	    return CL_VIRUS; \
132
-	} \
133 127
 	free(tempfile); \
134 128
 	break; \
135 129
 
... ...
@@ -102,9 +102,6 @@
102 102
 #include <stddef.h>
103 103
 #endif
104 104
 
105
-#define MAX_MAIL_RECURSION  15
106
-
107
-
108 105
 static int cli_scanfile(const char *filename, cli_ctx *ctx);
109 106
 
110 107
 #ifdef ENABLE_UNRAR
... ...
@@ -121,10 +118,10 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
121 121
 	    *sfx_check = metadata->crc;
122 122
     }
123 123
 
124
-    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u (max: %u)\n",
124
+    cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
125 125
 	metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
126 126
 	(unsigned int) metadata->unpack_size, metadata->method,
127
-	metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0);
127
+	metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0);
128 128
 
129 129
     /* Scan metadata */
130 130
     mdata = ctx->engine->rar_mlist;
... ...
@@ -147,7 +144,7 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
147 147
 	if(mdata->fileno && mdata->fileno != files)
148 148
 	    continue;
149 149
 
150
-	if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
150
+	if(mdata->maxdepth && ctx->recursion > mdata->maxdepth) /* FIXMELIMITS */
151 151
 	    continue;
152 152
 
153 153
 	/* TODO add support for regex */
... ...
@@ -177,42 +174,6 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
177 177
     return ret;
178 178
 }
179 179
 
180
-static int cli_unrar_checklimits(const cli_ctx *ctx, const unrar_metadata_t *metadata, unsigned int files)
181
-{
182
-    if(ctx->limits) {
183
-	if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) {
184
-	    if(metadata->unpack_size / metadata->pack_size >= ctx->limits->maxratio) {
185
-		cli_dbgmsg("RAR: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->unpack_size / metadata->pack_size), ctx->limits->maxratio);
186
-		if(BLOCKMAX) {
187
-		    *ctx->virname = "Oversized.RAR";
188
-		    return CL_VIRUS;
189
-		}
190
-		return CL_EMAXSIZE;
191
-	    }
192
-	}
193
-
194
-	if(ctx->limits->maxfilesize && (metadata->unpack_size > ctx->limits->maxfilesize)) {
195
-	    cli_dbgmsg("RAR: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename, (unsigned long int) metadata->unpack_size, ctx->limits->maxfilesize);
196
-	    if(BLOCKMAX) {
197
-		*ctx->virname = "RAR.ExceededFileSize";
198
-		return CL_VIRUS;
199
-	    }
200
-	    return CL_EMAXSIZE;
201
-	}
202
-
203
-	if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
204
-	    cli_dbgmsg("RAR: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
205
-	    if(BLOCKMAX) {
206
-		*ctx->virname = "RAR.ExceededFilesLimit";
207
-		return CL_VIRUS;
208
-	    }
209
-	    return CL_EMAXFILES;
210
-	}
211
-    }
212
-
213
-    return CL_SUCCESS;
214
-}
215
-
216 180
 static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
217 181
 {
218 182
 	int ret = CL_CLEAN;
... ...
@@ -258,17 +219,11 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
258 258
 		ret = CL_ERAR;
259 259
 	    break;
260 260
 	}
261
-	ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count);
262
-	if(ret && ret != CL_VIRUS) {
261
+	if((ret=cli_checklimits("RAR", ctx, rar_state.metadata_tail->unpack_size, rar_state.metadata_tail->pack_size, 0)!=CL_CLEAN)) {
263 262
 	    free(rar_state.file_header->filename);
264 263
 	    free(rar_state.file_header);
265 264
 	    ret = CL_CLEAN;
266 265
 	    continue;
267
-	} else if(ret == CL_VIRUS) {
268
-	    /* needed since we didn't reach unrar_extract_next to clean this up*/
269
-	    free(rar_state.file_header->filename);
270
-	    free(rar_state.file_header);	   
271
-	    break;
272 266
 	}
273 267
 	ret = unrar_extract_next(&rar_state,dir);
274 268
 	if(ret == UNRAR_OK)
... ...
@@ -324,52 +279,11 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
324 324
 }
325 325
 #endif /* ENABLE_UNRAR */
326 326
 
327
-static int cli_unarj_checklimits(const cli_ctx *ctx, const arj_metadata_t *metadata, unsigned int files)
328
-{
329
-    if (ctx->limits) {
330
-	if (ctx->limits->maxfilesize && (metadata->orig_size > ctx->limits->maxfilesize)) {
331
-	    cli_dbgmsg("ARJ: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename ? metadata->filename : "(none)",
332
-	    		(unsigned long int) metadata->orig_size, ctx->limits->maxfilesize);
333
-	    if (BLOCKMAX) {
334
-		*ctx->virname = "ARJ.ExceededFileSize";
335
-		return CL_VIRUS;
336
-	    }
337
-	    return CL_EMAXSIZE;
338
-	}
339
-	
340
-	if (ctx->limits->maxratio && metadata->orig_size && metadata->comp_size) {
341
-	    if (metadata->orig_size / metadata->comp_size >= ctx->limits->maxratio) {
342
-		cli_dbgmsg("ARJ: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->orig_size / metadata->comp_size), ctx->limits->maxratio);
343
-		if (ctx->limits->maxfilesize && (metadata->orig_size <= ctx->limits->maxfilesize)) {
344
-		    cli_dbgmsg("ARJ: Ignoring ratio limit (file size doesn't hit limits)\n");
345
-		} else {
346
-		    if(BLOCKMAX) {
347
-		    	*ctx->virname = "Oversized.ARJ";
348
-			return CL_VIRUS;
349
-		    }
350
-		}
351
-	    }
352
-	}
353
-	
354
-	if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
355
-	    cli_dbgmsg("ARJ: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
356
-	    if (BLOCKMAX) {
357
-	    	*ctx->virname = "ARJ.ExceededFilesLimit";
358
-		return CL_VIRUS;
359
-	    }
360
-	    return CL_EMAXFILES;
361
-	}
362
-    }
363
-    
364
-    return CL_SUCCESS;
365
-}
366
-
367 327
 static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
368 328
 {
369 329
 	int ret = CL_CLEAN, rc;
370 330
 	arj_metadata_t metadata;
371 331
 	char *dir;
372
-	unsigned int file_count = 1;
373 332
 
374 333
     cli_dbgmsg("in cli_scanarj()\n");
375 334
 
... ...
@@ -400,9 +314,10 @@ static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
400 400
 	if (ret != CL_SUCCESS) {
401 401
 	   break;
402 402
 	}
403
-	ret = cli_unarj_checklimits(ctx, &metadata, file_count);
404
-	if (ret == CL_VIRUS) {
405
-		break;
403
+	if ((ret = cli_checklimits("ARJ", ctx, metadata.orig_size, metadata.comp_size, 0))!=CL_CLEAN) {
404
+	  /* FIXMELIMITS: is this correct, shall I free something? */
405
+	    ret = CL_SUCCESS;
406
+	    continue;
406 407
 	}
407 408
 	ret = cli_unarj_extract_file(desc, dir, &metadata);
408 409
 	if (metadata.ofd >= 0) {
... ...
@@ -472,15 +387,8 @@ static int cli_scangzip(int desc, cli_ctx *ctx)
472 472
     while((bytes = gzread(gd, buff, FILEBUFF)) > 0) {
473 473
 	size += bytes;
474 474
 
475
-	if(ctx->limits)
476
-	    if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
477
-		cli_dbgmsg("GZip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
478
-		if(BLOCKMAX) {
479
-		    *ctx->virname = "GZip.ExceededFileSize";
480
-		    ret = CL_VIRUS;
481
-		}
482
-		break;
483
-	    }
475
+	if(cli_checklimits("GZip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
476
+	    break;
484 477
 
485 478
 	if(cli_writen(fd, buff, bytes) != bytes) {
486 479
 	    cli_dbgmsg("GZip: Can't write to file.\n");
... ...
@@ -586,15 +494,8 @@ static int cli_scanbzip(int desc, cli_ctx *ctx)
586 586
     while((bytes = BZ2_bzRead(&bzerror, bfd, buff, FILEBUFF)) > 0) {
587 587
 	size += bytes;
588 588
 
589
-	if(ctx->limits)
590
-	    if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
591
-		cli_dbgmsg("Bzip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
592
-		if(BLOCKMAX) {
593
-		    *ctx->virname = "BZip.ExceededFileSize";
594
-		    ret = CL_VIRUS;
595
-		}
596
-		break;
597
-	    }
589
+	if(cli_checklimits("Bzip", ctx, size + FILEBUFF, 0, 0)!=CL_CLEAN)
590
+	    break;
598 591
 
599 592
 	if(cli_writen(fd, buff, bytes) != bytes) {
600 593
 	    cli_dbgmsg("Bzip: Can't write to file.\n");
... ...
@@ -697,25 +598,8 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
697 697
     for(file = cab.files; file; file = file->next) {
698 698
 	files++;
699 699
 
700
-	if(ctx->limits && ctx->limits->maxfilesize && (file->length > ctx->limits->maxfilesize)) {
701
-	    cli_dbgmsg("CAB: %s: Size exceeded (%u, max: %lu)\n", file->name, file->length, ctx->limits->maxfilesize);
702
-	    if(BLOCKMAX) {
703
-		*ctx->virname = "CAB.ExceededFileSize";
704
-		cab_free(&cab);
705
-		return CL_VIRUS;
706
-	    }
700
+	if(cli_checklimits("CAB", ctx, file->length, 0, 0)!=CL_CLEAN)
707 701
 	    continue;
708
-	}
709
-
710
-	if(ctx->limits && ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
711
-	    cli_dbgmsg("CAB: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
712
-            cab_free(&cab);
713
-	    if(BLOCKMAX) {
714
-		*ctx->virname = "CAB.ExceededFilesLimit";
715
-		return CL_VIRUS;
716
-	    }
717
-	    return CL_CLEAN;
718
-	}
719 702
 
720 703
 	tempname = cli_gentemp(NULL);
721 704
 	cli_dbgmsg("CAB: Extracting file %s to %s, size %u\n", file->name, tempname, file->length);
... ...
@@ -1190,6 +1074,9 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
1190 1190
 
1191 1191
     cli_dbgmsg("in cli_scanole2()\n");
1192 1192
 
1193
+    if(ctx->limits && ctx->limits->maxreclevel && ctx->recursion >= ctx->limits->maxreclevel)
1194
+        return CL_EMAXREC;
1195
+
1193 1196
     /* generate the temporary directory */
1194 1197
     dir = cli_gentemp(NULL);
1195 1198
     if(mkdir(dir, 0700)) {
... ...
@@ -1198,20 +1085,25 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
1198 1198
 	return CL_ETMPDIR;
1199 1199
     }
1200 1200
 
1201
-    if((ret = cli_ole2_extract(desc, dir, ctx->limits))) {
1201
+    if((ret = cli_ole2_extract(desc, dir, ctx))) {
1202 1202
 	cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
1203 1203
 	if(!cli_leavetemps_flag)
1204 1204
 	    cli_rmdirs(dir);
1205 1205
 	free(dir);
1206
+	ctx->recursion--;
1206 1207
 	return ret;
1207 1208
     }
1208 1209
 
1210
+    ctx->recursion++;
1211
+
1209 1212
     if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
1210 1213
 	if(cli_scandir(dir, ctx) == CL_VIRUS) {
1211 1214
 	    ret = CL_VIRUS;
1212 1215
 	}
1213 1216
     }
1214 1217
 
1218
+    ctx->recursion--;
1219
+
1215 1220
     if(!cli_leavetemps_flag)
1216 1221
 	cli_rmdirs(dir);
1217 1222
     free(dir);
... ...
@@ -1234,7 +1126,7 @@ static int cli_scantar(int desc, cli_ctx *ctx, unsigned int posix)
1234 1234
 	return CL_ETMPDIR;
1235 1235
     }
1236 1236
 
1237
-    if((ret = cli_untar(dir, desc, posix, ctx->limits)))
1237
+    if((ret = cli_untar(dir, desc, posix, ctx)))
1238 1238
 	cli_dbgmsg("Tar: %s\n", cl_strerror(ret));
1239 1239
     else
1240 1240
 	ret = cli_scandir(dir, ctx);
... ...
@@ -1546,7 +1438,7 @@ static int cli_scanmail(int desc, cli_ctx *ctx)
1546 1546
 	int ret;
1547 1547
 
1548 1548
 
1549
-    cli_dbgmsg("Starting cli_scanmail(), mrec == %u, arec == %u\n", ctx->mrec, ctx->arec);
1549
+    cli_dbgmsg("Starting cli_scanmail(), recursion = %u\n", ctx->recursion);
1550 1550
 
1551 1551
     /* generate the temporary directory */
1552 1552
     dir = cli_gentemp(NULL);
... ...
@@ -1596,11 +1488,8 @@ static int cli_scanembpe(int desc, cli_ctx *ctx)
1596 1596
     while((bytes = read(desc, buff, sizeof(buff))) > 0) {
1597 1597
 	size += bytes;
1598 1598
 
1599
-	if(ctx->limits && ctx->limits->maxfilesize && (size + sizeof(buff) > ctx->limits->maxfilesize)) {
1600
-	    cli_dbgmsg("cli_scanembpe: Size exceeded (stopped at %lu, max: %lu)\n", size, ctx->limits->maxfilesize);
1601
-	    /* BLOCKMAX should be ignored here */
1599
+	if(cli_checklimits("cli_scanembpe", ctx, size + sizeof(buff), 0, 0)!=CL_CLEAN)
1602 1600
 	    break;
1603
-	}
1604 1601
 
1605 1602
 	if(cli_writen(fd, buff, bytes) != bytes) {
1606 1603
 	    cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
... ...
@@ -1757,7 +1646,7 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg)
1757 1757
 	    }
1758 1758
 	}
1759 1759
 
1760
-	ret == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
1760
+	ctx->recursion++;
1761 1761
 
1762 1762
 	if(nret != CL_VIRUS) switch(ret) {
1763 1763
 	    case CL_TYPE_HTML:
... ...
@@ -1773,7 +1662,7 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg)
1773 1773
 	    default:
1774 1774
 		break;
1775 1775
 	}
1776
-	ret == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
1776
+	ctx->recursion--;
1777 1777
 	ret = nret;
1778 1778
     }
1779 1779
 
... ...
@@ -1798,7 +1687,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1798 1798
 
1799 1799
 
1800 1800
     if(fstat(desc, &sb) == -1) {
1801
-	cli_errmsg("Can't fstat descriptor %d\n", desc);
1801
+	cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
1802 1802
 	return CL_EIO;
1803 1803
     }
1804 1804
 
... ...
@@ -1819,22 +1708,13 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1819 1819
 	return ret;
1820 1820
     }
1821 1821
 
1822
-    if(SCAN_ARCHIVE && ctx->limits && ctx->limits->maxreclevel)
1823
-	if(ctx->arec > ctx->limits->maxreclevel) {
1824
-	    cli_dbgmsg("Archive recursion limit exceeded (arec == %u).\n", ctx->arec);
1825
-	    if(BLOCKMAX) {
1826
-		*ctx->virname = "Archive.ExceededRecursionLimit";
1827
-		return CL_VIRUS;
1828
-	    }
1829
-	    return CL_CLEAN;
1830
-	}
1822
+    if(cli_updatelimits(ctx, sb.st_size)!=CL_CLEAN)
1823
+        return CL_CLEAN;
1831 1824
 
1832
-    if(SCAN_MAIL)
1833
-	if(ctx->mrec > MAX_MAIL_RECURSION) {
1834
-	    cli_dbgmsg("Mail recursion level exceeded (mrec == %u).\n", ctx->mrec);
1835
-	    /* return CL_EMAXREC; */
1836
-	    return CL_CLEAN;
1837
-	}
1825
+    if((SCAN_MAIL || SCAN_ARCHIVE) && ctx->limits && ctx->limits->maxreclevel && ctx->recursion > ctx->limits->maxreclevel) {
1826
+        cli_dbgmsg("Archive recursion limit exceeded (level = %u).\n", ctx->recursion);
1827
+	return CL_CLEAN;
1828
+    }
1838 1829
 
1839 1830
     lseek(desc, 0, SEEK_SET);
1840 1831
     type = cli_filetype2(desc, ctx->engine);
... ...
@@ -1850,7 +1730,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1850 1850
 	lseek(desc, 0, SEEK_SET);
1851 1851
     }
1852 1852
 
1853
-    type == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
1853
+    ctx->recursion++;
1854 1854
 
1855 1855
     switch(type) {
1856 1856
 	case CL_TYPE_IGNORED:
... ...
@@ -1887,7 +1767,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1887 1887
 	    break;
1888 1888
 
1889 1889
         case CL_TYPE_NULSFT:
1890
-	    if(SCAN_ARCHIVE)
1890
+	  if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_NSIS))
1891 1891
 		ret = cli_scannulsft(desc, ctx, 0);
1892 1892
 	    break;
1893 1893
 
... ...
@@ -1922,7 +1802,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1922 1922
 	    break;
1923 1923
 
1924 1924
 	case CL_TYPE_RTF:
1925
-	    if(DCONF_DOC & DOC_CONF_RTF)
1925
+	    if(SCAN_ARCHIVE && (DCONF_DOC & DOC_CONF_RTF))
1926 1926
 		ret = cli_scanrtf(desc, ctx);
1927 1927
 	    break;
1928 1928
 
... ...
@@ -2009,7 +1889,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2009 2009
 	    break;
2010 2010
     }
2011 2011
 
2012
-    type == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
2012
+    ctx->recursion--;
2013 2013
 
2014 2014
     if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
2015 2015
 	if(sb.st_size > 1048576) {
... ...
@@ -2024,7 +1904,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2024 2024
 	    return CL_VIRUS;
2025 2025
     }
2026 2026
 
2027
-    ctx->arec++;
2027
+    ctx->recursion++;
2028 2028
     lseek(desc, 0, SEEK_SET);
2029 2029
     switch(type) {
2030 2030
 	/* Due to performance reasons all executables were first scanned
... ...
@@ -2038,7 +1918,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2038 2038
 	default:
2039 2039
 	    break;
2040 2040
     }
2041
-    ctx->arec--;
2041
+    ctx->recursion--;
2042 2042
 
2043 2043
     if(ret == CL_EFORMAT) {
2044 2044
 	cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(CL_EFORMAT));
... ...
@@ -2051,16 +1931,20 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
2051 2051
 int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
2052 2052
 {
2053 2053
     cli_ctx ctx;
2054
+    struct cl_limits l_limits;
2054 2055
     int rc;
2055 2056
 
2056 2057
     memset(&ctx, '\0', sizeof(cli_ctx));
2057 2058
     ctx.engine = engine;
2058 2059
     ctx.virname = virname;
2059
-    ctx.limits = limits;
2060 2060
     ctx.scanned = scanned;
2061 2061
     ctx.options = options;
2062 2062
     ctx.found_possibly_unwanted = 0;
2063 2063
     ctx.dconf = (struct cli_dconf *) engine->dconf;
2064
+    if (limits) {
2065
+      ctx.limits = &l_limits;
2066
+      memcpy(&l_limits, limits, sizeof(struct cl_limits));
2067
+    }
2064 2068
 
2065 2069
     rc = cli_magic_scandesc(desc, &ctx);
2066 2070
     if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
... ...
@@ -453,10 +453,7 @@ static int real_scansis(FILE *f, cli_ctx *ctx, const char *tmpd) {
453 453
 	    cli_dbgmsg("\tSkipping empty file\n");
454 454
 	    continue;
455 455
 	  }
456
-	  if (ctx->limits && ctx->limits->maxfilesize && lens[j] > ctx->limits->maxfilesize) {
457
-	    cli_dbgmsg("\tSkipping file due to size limit (%u, max: %lu)\n", lens[j], ctx->limits->maxfilesize);
458
-	    continue;
459
-	  }
456
+	  if (cli_checklimits("sis", ctx,lens[j], 0, 0)!=CL_CLEAN) continue;
460 457
 	  cli_dbgmsg("\tUnpacking lang#%d - ptr:%x csize:%x osize:%x\n", j, ptrs[j], lens[j], olens[j]);
461 458
 	  if (!(comp=cli_malloc(lens[j]))) {
462 459
 	    cli_dbgmsg("\tOOM\n");
... ...
@@ -471,15 +468,13 @@ static int real_scansis(FILE *f, cli_ctx *ctx, const char *tmpd) {
471 471
 	    continue;
472 472
 	  }
473 473
 	  if (compd) {
474
-	    olen = (olens[j]<=lens[j]*3  || (ctx->limits && ctx->limits->maxfilesize && olens[j] > ctx->limits->maxfilesize)) ? lens[j]*3 : olens[j];
475
-	    if (ctx->limits && ctx->limits->maxfilesize && olen > ctx->limits->maxfilesize) {
476
-	      if (olens[j] < ctx->limits->maxfilesize)
477
-		olen = olens[j];
478
-	      else {
479
-		cli_dbgmsg("\tSkipping file due to size limit (%u, max: %lu)\n", (unsigned int)olen, ctx->limits->maxfilesize);
480
-		free(comp);
481
-		continue;
482
-	      }
474
+	    if (olens[j]<=lens[j]*3 && cli_checklimits("sis", ctx, lens[j]*3, 0, 0)==CL_CLEAN)
475
+	      olen=lens[j]*3;
476
+	    else if (cli_checklimits("sis", ctx, olens[j], 0, 0)==CL_CLEAN)
477
+	      olen=olens[j];
478
+	    else {
479
+	      free(comp);
480
+	      continue;
483 481
 	    }
484 482
 	      
485 483
 	    if (!(decomp=cli_malloc(olen))) {
... ...
@@ -524,12 +519,6 @@ static int real_scansis(FILE *f, cli_ctx *ctx, const char *tmpd) {
524 524
 	  }
525 525
 	  close(fd);
526 526
 	  umped++;
527
-	  if (ctx->limits && umped > ctx->limits->maxfiles) {
528
-	    cli_dbgmsg("NSIS: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
529
-	    free(ptrs);
530
-	    free(alangs);
531
-	    return CL_EMAXFILES;
532
-	  }
533 527
 	}
534 528
 	fseek(f,fpos,SEEK_SET);
535 529
       }
... ...
@@ -726,10 +715,7 @@ static int real_scansis9x(FILE *f, cli_ctx *ctx, const char *tmpd) {
726 726
 	      fseek(s->f, -(long)s->sleft, SEEK_CUR);
727 727
 	      s->sleft = s->smax = 0;
728 728
 
729
-	      if (ctx->limits && ctx->limits->maxfilesize && ALIGN4(s->fsize[s->level]) > ctx->limits->maxfilesize) {
730
-		cli_dbgmsg("SIS: Skipping file due to size limit (%u, max: %lu)\n", ALIGN4(s->fsize[s->level]), ctx->limits->maxfilesize);
731
-		break;
732
-	      }
729
+	      if (cli_checklimits("sis", ctx,ALIGN4(s->fsize[s->level]), 0, 0)!=CL_CLEAN) break;
733 730
 	      if (!(src=cli_malloc(ALIGN4(s->fsize[s->level])))) break;
734 731
 	      if (fread(src, ALIGN4(s->fsize[s->level]),1,s->f) != 1) {
735 732
 		free(src);
... ...
@@ -739,16 +725,15 @@ static int real_scansis9x(FILE *f, cli_ctx *ctx, const char *tmpd) {
739 739
 	      if(field) { /* compressed */
740 740
 		int zresult;
741 741
 
742
-		uusize = (usize<=s->fsize[s->level]*3 || (ctx->limits && ctx->limits->maxfilesize && uusize > ctx->limits->maxfilesize)) ? s->fsize[s->level]*3 : usize;
743
-		if (ctx->limits && ctx->limits->maxfilesize && uusize > ctx->limits->maxfilesize) {
744
-		  if (usize < ctx->limits->maxfilesize)
745
-		    uusize = usize;
746
-		  else {
747
-		    cli_dbgmsg("\tSkipping file due to size limit (%u, max: %lu)\n", (unsigned int)uusize, ctx->limits->maxfilesize);
748
-		    free(src);
749
-		    break;
750
-		  }
742
+		if (usize<=s->fsize[s->level]*3 && cli_checklimits("sis", ctx, s->fsize[s->level]*3, 0, 0)==CL_CLEAN)
743
+		  uusize=s->fsize[s->level]*3;
744
+		else if (cli_checklimits("sis", ctx, usize, 0, 0)==CL_CLEAN)
745
+		  uusize=usize;
746
+		else {
747
+		  free(src);
748
+		  break;
751 749
 		}
750
+
752 751
 		if (!(dst=cli_malloc(uusize))) {
753 752
 		  free(src);
754 753
 		  break;
... ...
@@ -372,6 +372,7 @@ int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt,
372 372
   bitmap = cli_readint32(ep+0x3061);
373 373
   bitman = bitmap;
374 374
 
375
+  /* FIXMELIMITS */
375 376
   if(ctx->limits && ctx->limits->maxfilesize) {
376 377
     unsigned long int filesize = 0;
377 378
     
... ...
@@ -142,9 +142,9 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u
142 142
   i = allocsz;
143 143
   c = (tre+i)&0xff;
144 144
   tablesz = ((0x300<<c)+0x736)*sizeof(uint16_t);
145
-  if(ctx->limits && ctx->limits->maxfilesize && tablesz > ctx->limits->maxfilesize) {
145
+
146
+  if(cli_checklimits("nspack", ctx, tablesz, 0, 0)!=CL_CLEAN)
146 147
     return 1; /* Should be ~15KB, if it's so big it's prolly just not nspacked */
147
-  }
148 148
     
149 149
   cli_dbgmsg("unsp: table size = %d\n", tablesz);
150 150
   if (!(table = cli_malloc(tablesz))) return 1;
... ...
@@ -61,9 +61,9 @@ octal(const char *str)
61 61
 }
62 62
 
63 63
 int
64
-cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits)
64
+cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx)
65 65
 {
66
-	int size = 0;
66
+	int size = 0, ret;
67 67
 	int in_block = 0;
68 68
 	unsigned int files = 0;
69 69
 	char fullname[NAME_MAX + 1];
... ...
@@ -103,11 +103,8 @@ cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits
103 103
 
104 104
 			if(block[0] == '\0')	/* We're done */
105 105
 				break;
106
-
107
-			if(limits && limits->maxfiles && (files >= limits->maxfiles)) {
108
-				cli_dbgmsg("cli_untar: number of files exceeded %u\n", limits->maxfiles);
109
-				return CL_CLEAN;
110
-			}
106
+			if((ret=cli_checklimits("cli_untar", ctx, 0, 0, 0))!=CL_CLEAN)
107
+				return ret;
111 108
 
112 109
 			/* Notice assumption that BLOCKSIZE > 262 */
113 110
 			if(posix) {
... ...
@@ -176,8 +173,7 @@ cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits
176 176
 				return CL_EFORMAT;
177 177
 			}
178 178
 			cli_dbgmsg("cli_untar: size = %d\n", size);
179
-			if(limits && limits->maxfilesize && ((unsigned int)size > limits->maxfilesize)) {
180
-				cli_dbgmsg("cli_untar: size exceeded %d bytes\n", size);
179
+			if((ret=cli_checklimits("cli_untar", ctx, size, 0, 0))!=CL_CLEAN) {
181 180
 				skipEntry++;
182 181
 			}
183 182
 
... ...
@@ -250,7 +246,7 @@ cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits
250 250
 		}
251 251
 		if (size == 0)
252 252
 			in_block = 0;
253
-	}
253
+        }	
254 254
 	if(outfile)
255 255
 		return fclose(outfile);
256 256
 
... ...
@@ -34,4 +34,12 @@
34 34
  * First draft
35 35
  *
36 36
  */
37
-int cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits);
37
+
38
+#ifndef __UNTAR_H
39
+#define __UNTAR_H
40
+
41
+#include "others.h"
42
+
43
+int cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx);
44
+
45
+#endif
... ...
@@ -93,11 +93,6 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui
93 93
     }
94 94
     if(res==1) {
95 95
       if(ctx->limits && ctx->limits->maxfilesize && csize > ctx->limits->maxfilesize) {
96
-	if(BLOCKMAX) {
97
-	  *ctx->virname = "Zip.ExceededFileSize";
98
-	  ret = CL_VIRUS;
99
-	  break;
100
-	}
101 96
 	cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
102 97
 	csize = ctx->limits->maxfilesize;
103 98
       }
... ...
@@ -159,11 +154,6 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui
159 159
       if(*avail_out!=sizeof(obuf)) {
160 160
 	written+=sizeof(obuf)-(*avail_out);
161 161
 	if(ctx->limits && ctx->limits->maxfilesize && written > ctx->limits->maxfilesize) {
162
-	  if(BLOCKMAX) {
163
-	    *ctx->virname = "Zip.ExceededFileSize";
164
-	    ret = CL_VIRUS;
165
-	    break;
166
-	  }
167 162
 	  cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
168 163
 	  res = Z_STREAM_END;
169 164
 	  break;
... ...
@@ -201,11 +191,6 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui
201 201
       if(strm.avail_out!=sizeof(obuf)) {
202 202
 	written+=sizeof(obuf)-strm.avail_out;
203 203
 	if(ctx->limits && ctx->limits->maxfilesize && written > ctx->limits->maxfilesize) {
204
-	  if(BLOCKMAX) {
205
-	    *ctx->virname = "Zip.ExceededFileSize";
206
-	    ret = CL_VIRUS;
207
-	    break;
208
-	  }
209 204
 	  cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
210 205
 	  res = BZ_STREAM_END;
211 206
 	  break;
... ...
@@ -244,11 +229,6 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui
244 244
       if(strm.avail_out!=sizeof(obuf)) {
245 245
 	written+=sizeof(obuf)-strm.avail_out;
246 246
 	if(ctx->limits && ctx->limits->maxfilesize && written > ctx->limits->maxfilesize) {
247
-	  if(BLOCKMAX) {
248
-	    *ctx->virname = "Zip.ExceededFileSize";
249
-	    ret = CL_VIRUS;
250
-	    break;
251
-	  }
252 247
 	  cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", ctx->limits->maxfilesize);
253 248
 	  res = 0;
254 249
 	  break;
... ...
@@ -346,7 +326,7 @@ static unsigned int lhdr(uint8_t *zip, uint32_t zsize, unsigned int *fu, unsigne
346 346
   zip+=LH_flen;
347 347
   zsize-=LH_flen;
348 348
 
349
-  cli_dbgmsg("cli_unzip: lh - ZMDNAME:%d:%s:%u:%u:%u:%u:%u:%u\n", ((LH_flags & F_ENCR)==0), name, LH_usize, LH_csize, LH_crc32, LH_method, fc, ctx->arec);
349
+  cli_dbgmsg("cli_unzip: lh - ZMDNAME:%d:%s:%u:%u:%u:%u:%u:%u\n", ((LH_flags & F_ENCR)==0), name, LH_usize, LH_csize, LH_crc32, LH_method, fc, ctx->recursion);
350 350
   /* ZMDfmt virname:encrypted(0-1):filename(exact|*):usize(exact|*):csize(exact|*):crc32(exact|*):method(exact|*):fileno(exact|*):maxdepth(exact|*) */
351 351
 
352 352
   while(meta &&
... ...
@@ -357,7 +337,7 @@ static unsigned int lhdr(uint8_t *zip, uint32_t zsize, unsigned int *fu, unsigne
357 357
 	 (meta->crc32    && meta->crc32  != LH_crc32) ||
358 358
 	 (meta->method>0 && meta->method != LH_method) ||
359 359
 	 (meta->fileno   && meta->fileno != fc ) ||
360
-	 (meta->maxdepth && ctx->arec > meta->maxdepth) ||
360
+	 (meta->maxdepth && ctx->recursion > meta->maxdepth) ||
361 361
 	 (meta->filename && strcmp(name, meta->filename)) /* TODO: use a regex */
362 362
 	 )
363 363
 	) meta = meta->next;
... ...
@@ -401,10 +381,6 @@ static unsigned int lhdr(uint8_t *zip, uint32_t zsize, unsigned int *fu, unsigne
401 401
 	return 0;
402 402
       }
403 403
       cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n");
404
-    } else if(ctx->limits && ctx->limits->maxratio > 0 && (usize / csize) >= ctx->limits->maxratio) {
405
-      *ctx->virname = "Oversized.Zip";
406
-      *ret = CL_VIRUS;
407
-      return 0;
408 404
     } else *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd);
409 405
     zip+=csize;
410 406
     zsize-=csize;
... ...
@@ -561,11 +537,6 @@ int cli_unzip(int f, cli_ctx *ctx) {
561 561
     }
562 562
   }
563 563
 
564
-  if(ret == CL_EMAXFILES && BLOCKMAX) {
565
-    *ctx->virname = "Zip.ExceededFilesLimit";
566
-    ret = CL_VIRUS;
567
-  }
568
-
569 564
   munmap(map, fsize);
570 565
   if (!cli_leavetemps_flag) cli_rmdirs(tmpd);
571 566
   free(tmpd);
... ...
@@ -590,7 +590,7 @@ cli_decode_ole_object(int fd, const char *dir)
590 590
 	int ofd;
591 591
 	uint32_t object_size;
592 592
 	struct stat statbuf;
593
-	char fullname[NAME_MAX + 1];
593
+	char *fullname;
594 594
 
595 595
 	if(dir == NULL)
596 596
 		return -1;
... ...
@@ -629,15 +629,19 @@ cli_decode_ole_object(int fd, const char *dir)
629 629
 		if(!read_uint32(fd, &object_size, FALSE))
630 630
 			return -1;
631 631
 	}
632
-	snprintf(fullname, sizeof(fullname) - 1, "%s/_clam_ole_object", dir);
632
+	if(!(fullname = cli_gentemp(dir))) {
633
+		return -1;
634
+	}
633 635
 	ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
634 636
 		S_IWUSR|S_IRUSR);
635 637
 	if (ofd < 0) {
636
-		cli_warnmsg("cli_decode_ole_object: can't create %s\n",
637
-			fullname);
638
+		cli_warnmsg("cli_decode_ole_object: can't create %s\n",	fullname);
639
+		free(fullname);
638 640
 		return -1;
641
+	} else {
642
+		cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
639 643
 	}
640
-
644
+	free(fullname);
641 645
 	ole_copy_file_data(fd, ofd, object_size);
642 646
 	lseek(ofd, 0, SEEK_SET);
643 647
 	return ofd;
... ...
@@ -47,7 +47,6 @@ struct cfgoption cfg_options[] = {
47 47
     {"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
48 48
     {"ScanMail", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
49 49
     {"MailFollowURLs", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
50
-    {"MailMaxRecursion", OPT_NUM, 64, NULL, 0, OPT_CLAMD},
51 50
     {"PhishingSignatures", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
52 51
     {"PhishingScanURLs",OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
53 52
     /* these are FP prone options, if default isn't used */
... ...
@@ -61,13 +60,12 @@ struct cfgoption cfg_options[] = {
61 61
     {"ScanOLE2", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
62 62
     {"ScanPDF", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
63 63
     {"ScanArchive", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
64
-    {"ArchiveMaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
65
-    {"ArchiveMaxRecursion", OPT_NUM, 8, NULL, 0, OPT_CLAMD},
66
-    {"ArchiveMaxFiles", OPT_NUM, 1000, NULL, 0, OPT_CLAMD},
67
-    {"ArchiveMaxCompressionRatio", OPT_NUM, 250, NULL, 0, OPT_CLAMD},
64
+    {"MaxScanSize", OPT_COMPSIZE, 104857600, NULL, 0, OPT_CLAMD}, /* FIXMELIMITS */
65
+    {"MaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
66
+    {"MaxRecursion", OPT_NUM, 8, NULL, 0, OPT_CLAMD},
67
+    {"MaxFiles", OPT_NUM, 1000, NULL, 0, OPT_CLAMD},
68 68
     {"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
69 69
     {"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
70
-    {"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
71 70
     {"DatabaseDirectory", OPT_QUOTESTR, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM},
72 71
     {"TCPAddr", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
73 72
     {"TCPSocket", OPT_NUM, -1, NULL, 0, OPT_CLAMD},