Browse code

add is_extract_cab

aCaB authored on 2009/07/15 02:42:27
Showing 1 changed files
... ...
@@ -250,11 +250,11 @@ int cli_scanishield_msi(int desc, cli_ctx *ctx, off_t off) {
250 250
 	    csize -= z.avail_in;
251 251
 	    z.next_in = buf;
252 252
 	    do {
253
-		int def;
253
+		int inf;
254 254
 		z.avail_out = sizeof(obuf);
255 255
 		z.next_out = obuf;
256
-		def = inflate(&z, 0);
257
-		if(def != Z_OK && def != Z_STREAM_END && def != Z_BUF_ERROR) {
256
+		inf = inflate(&z, 0);
257
+		if(inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
258 258
 		    cli_dbgmsg("ishield-msi: bad stream\n");
259 259
 		    csize = 0;
260 260
 		    lseek(desc, csize, SEEK_CUR);
... ...
@@ -307,8 +307,8 @@ struct IS_CABSTUFF {
307 307
 };
308 308
 
309 309
 static void md5str(uint8_t *sum);
310
-static int is_parse_hdr(int desc, struct IS_CABSTUFF *c);
311
-
310
+static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c);
311
+static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize);
312 312
 
313 313
 /* Extract the content of older (non-MSI) IS */
314 314
 int cli_scanishield(int desc, cli_ctx *ctx, off_t off, size_t sz) {
... ...
@@ -392,7 +392,7 @@ int cli_scanishield(int desc, cli_ctx *ctx, off_t off, size_t sz) {
392 392
     }
393 393
 
394 394
     if(ret == CL_CLEAN && (c.cabcnt || c.hdr != -1)) {
395
-	if(is_parse_hdr(desc, &c) == CL_CLEAN /* FIXMEISHIELD */) {
395
+	if(is_parse_hdr(desc, ctx, &c) == CL_CLEAN /* FIXMEISHIELD */) {
396 396
 	    unsigned int i;
397 397
 	    if(c.hdr != -1) ret = is_dump_and_scan(desc, ctx, c.hdr, c.hdrsz);
398 398
 	    for(i=0; i<c.cabcnt && ret == CL_CLEAN; i++) {
... ...
@@ -461,7 +461,7 @@ struct IS_HDR {
461 461
 };
462 462
 
463 463
 
464
-static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell parent whether we completed the task or not */
464
+static int is_parse_hdr(int desc, cli_ctx *ctx, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell parent whether we completed the task or not */
465 465
     uint32_t h1_data_off, objs_files_cnt, objs_dirs_off;
466 466
     unsigned int off, i;
467 467
     char hash[33], *hdr;
... ...
@@ -472,10 +472,10 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell
472 472
 
473 473
     /* FIXMEISHIELD: sanitize c here */
474 474
 
475
-    if(!(hdr = (char *)cli_malloc(c->hdrsz)))
475
+    if(!(hdr = (char *)cli_malloc(c->hdrsz))) /* FIXMEISHIELD: mmap if large */
476 476
 	return CL_EMEM;
477 477
 
478
-    if(pread(desc, hdr, c->hdrsz, c->hdr) < c->hdrsz) {
478
+    if(pread(desc, hdr, c->hdrsz, c->hdr) < (ssize_t)c->hdrsz) {
479 479
 	cli_errmsg("is_parse_hdr: short read for header\n");
480 480
 	free(hdr);
481 481
 	return CL_EREAD;
... ...
@@ -574,7 +574,11 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell
574 574
 		    cli_errmsg("is_parse_hdr: not scanned (dup)\n");
575 575
 		else {
576 576
 		    if(file->size) { /* FIXMEISHIELD: limits */
577
-			//is_extract(inhash, hash, file->stream_off, file->size, file->csize);
577
+			int ret = is_extract_cab(desc, ctx, le64_to_host(file->stream_off), le64_to_host(file->size), le64_to_host(file->csize));
578
+			if(ret != CL_CLEAN) {
579
+			    free(hdr);
580
+			    return ret;
581
+			}
578 582
 		    }
579 583
 		}
580 584
 		break;
... ...
@@ -585,7 +589,8 @@ static int is_parse_hdr(int desc, struct IS_CABSTUFF *c) { /* FIXMEISHIELD: tell
585 585
 	    cli_errmsg("is_parse_hdr: FILEITEM out of bounds\n");
586 586
 	off+=sizeof(*file);
587 587
     }
588
-    return 0;
588
+    free(hdr);
589
+    return CL_CLEAN;
589 590
 }
590 591
 
591 592
 
... ...
@@ -601,3 +606,115 @@ static void md5str(uint8_t *sum) {
601 601
     }
602 602
     sum[32] = '\0';
603 603
 }
604
+
605
+
606
+#define IS_CABBUFSZ 65536
607
+
608
+static int is_extract_cab(int desc, cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize) {
609
+    uint8_t *inbuf, *outbuf;
610
+    char *tempfile;
611
+    FILE *in;
612
+    int ofd, ret = CL_CLEAN;
613
+    z_stream z;
614
+    uint64_t outsz = 0;
615
+    int success = 0;
616
+
617
+    if((ofd=dup(desc)) < 0) {
618
+	cli_errmsg("is_extract_cab: dup failed\n");
619
+	return CL_EDUP;
620
+    }
621
+    if(!(in = fdopen(ofd, "rb"))) {
622
+	cli_errmsg("is_extract_cab: fdopen failed\n");
623
+	close(ofd);
624
+	return CL_EOPEN;
625
+    }
626
+    if(fseeko(in, off, SEEK_SET)) {
627
+	cli_errmsg("is_extract_cab: fseek failed\n");
628
+	fclose(in);
629
+	return CL_ESEEK;
630
+    }
631
+    if(!(inbuf = cli_malloc(IS_CABBUFSZ))) {
632
+	fclose(in);
633
+	return CL_EMEM;
634
+    }
635
+    if(!(outbuf = cli_malloc(IS_CABBUFSZ))) {
636
+	free(inbuf);
637
+	fclose(in);
638
+	return CL_EMEM;
639
+    }
640
+    if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) return CL_EMEM;
641
+    if((ofd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
642
+	cli_errmsg("is_extract_cab: failed to create file %s\n", tempfile);
643
+	free(tempfile);
644
+	fclose(in);
645
+	return CL_ECREAT;
646
+    }
647
+
648
+    while(csize) {
649
+	uint16_t chunksz;
650
+	success = 0;
651
+	if(csize<2) {
652
+	    cli_errmsg("is_extract_cab: no room for chunk size\n");
653
+	    break;
654
+	}
655
+	csize -= 2;
656
+	if(!fread(outbuf, 2, 1, in)) {
657
+	    cli_dbgmsg("is_extract_cab: short read for chunk size\n");
658
+	    break;
659
+	}
660
+	chunksz = outbuf[0] | (outbuf[1] << 8);
661
+	if(!chunksz) {
662
+	    cli_dbgmsg("is_extract_cab: zero sized chunk\n");
663
+	    continue;
664
+	}
665
+	if(csize < chunksz) {
666
+	    cli_dbgmsg("is_extract_cab: chunk is bigger than csize\n");
667
+	    break;
668
+	}
669
+	csize -= chunksz;
670
+	if(!fread(inbuf, chunksz, 1, in)) {
671
+	    cli_dbgmsg("is_extract_cab: short read for chunk\n");
672
+	    break;
673
+	}
674
+	memset(&z, 0, sizeof(z));
675
+	inflateInit2(&z, -MAX_WBITS);
676
+	z.next_in = (uint8_t *)inbuf;
677
+	z.avail_in = chunksz;
678
+	while(1) {
679
+	    int zret;
680
+	    z.next_out = outbuf;
681
+	    z.avail_out = IS_CABBUFSZ;
682
+	    zret = inflate(&z, 0);
683
+	    if(zret == Z_OK || zret == Z_STREAM_END || zret == Z_BUF_ERROR) {
684
+		unsigned int umpd = IS_CABBUFSZ - z.avail_out;
685
+		if(cli_writen(ofd, outbuf, umpd) < (ssize_t)umpd)
686
+		    break;
687
+		outsz += umpd;
688
+		if(zret == Z_STREAM_END || z.avail_out == IS_CABBUFSZ /* FIXMEISHIELD: is the latter ok? */) {
689
+		    success = 1;
690
+		    break;
691
+		}
692
+		continue;
693
+	    }
694
+	    cli_dbgmsg("is_extract_cab: file decompression failed with %d\n", zret);
695
+	    break;
696
+	}
697
+	inflateEnd(&z);
698
+	if(!success) break;
699
+    }
700
+    fclose(in);
701
+    if(success) {
702
+	if (outsz != size)
703
+	    cli_dbgmsg("is_extract_cab: extracted %llu bytes to %s, expected %llu, scanning anyway.\n", outsz, tempfile, size);
704
+	else
705
+	    cli_dbgmsg("is_extract_cab: extracted to %s\n", tempfile);
706
+	lseek(ofd, 0, SEEK_SET);
707
+	ret = cli_magic_scandesc(ofd, ctx);
708
+    }
709
+
710
+    close(ofd);
711
+    if(!ctx->engine->keeptmp)
712
+	if(cli_unlink(tempfile)) ret = CL_EUNLINK;
713
+    free(tempfile);
714
+    return success ? ret : CL_CLEAN;
715
+}