Browse code

improve handling of PDF, CAB, RTF, OLE2 and HTML files (sync with branch/0.93)

git-svn: trunk@3862

Tomasz Kojm authored on 2008/05/28 01:30:47
Showing 34 changed files
... ...
@@ -1,3 +1,8 @@
1
+Tue May 27 17:39:06 CEST 2008
2
+-----------------------------
3
+  * improve handling of PDF, CAB, RTF, OLE2 and HTML files (sync with
4
+    branch/0.93)
5
+
1 6
 Sat May 24 21:38:47 EEST 2008 (edwin)
2 7
 -------------------------------------
3 8
   * clamd/others.c, session.c, m4/fdpassing.m4:
... ...
@@ -1167,6 +1167,7 @@ main(int argc, char **argv)
1167 1167
 
1168 1168
 			memset(&ifr, '\0', sizeof(struct ifreq));
1169 1169
 			strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
1170
+			ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';
1170 1171
 			if(setsockopt(broadcastSock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
1171 1172
 				perror(iface);
1172 1173
 				return EX_CONFIG;
... ...
@@ -1515,6 +1516,7 @@ main(int argc, char **argv)
1515 1515
 		memset((char *)&sockun, 0, sizeof(struct sockaddr_un));
1516 1516
 		sockun.sun_family = AF_UNIX;
1517 1517
 		strncpy(sockun.sun_path, localSocket, sizeof(sockun.sun_path));
1518
+		sockun.sun_path[sizeof(sockun.sun_path)-1]='\0';
1518 1519
 
1519 1520
 		sessions = (struct session *)cli_malloc(sizeof(struct session));
1520 1521
 		if((sessions[0].sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
... ...
@@ -2197,6 +2199,7 @@ pingServer(int serverNumber)
2197 2197
 		memset((char *)&server, 0, sizeof(struct sockaddr_un));
2198 2198
 		server.sun_family = AF_UNIX;
2199 2199
 		strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
2200
+		server.sun_path[sizeof(server.sun_path)-1]='\0';
2200 2201
 
2201 2202
 		if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
2202 2203
 			perror(localSocket);
... ...
@@ -2749,6 +2752,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
2749 2749
 		}
2750 2750
 #else
2751 2751
 		strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip));
2752
+		ip[sizeof(ip)-1]='\0';
2752 2753
 #endif
2753 2754
 
2754 2755
 		/*
... ...
@@ -3409,6 +3413,7 @@ clamfi_eom(SMFICTX *ctx)
3409 3409
 		memset((char *)&server, 0, sizeof(struct sockaddr_un));
3410 3410
 		server.sun_family = AF_UNIX;
3411 3411
 		strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
3412
+		server.sun_path[sizeof(server.sun_path)-1]='\0';
3412 3413
 
3413 3414
 		if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
3414 3415
 			perror(localSocket);
... ...
@@ -3530,19 +3535,20 @@ clamfi_eom(SMFICTX *ctx)
3530 3530
 				const char *j = smfi_getsymval(ctx, "{j}");
3531 3531
 
3532 3532
 				if(j)
3533
-					strncpy(hostname, j,
3534
-						sizeof(hostname) - 1);
3533
+					strncpy(hostname, j, sizeof(hostname) - 1);
3535 3534
 				else
3536 3535
 					strcpy(hostname, _("Error determining host"));
3536
+				hostname[sizeof(hostname)-1]='\0';
3537 3537
 			} else if(strchr(hostname, '.') == NULL) {
3538 3538
 				/*
3539 3539
 				 * Determine fully qualified name
3540 3540
 				 */
3541 3541
 				struct hostent hostent;
3542 3542
 
3543
-				if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) &&
3544
-				   hostent.h_name)
3543
+				if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) && hostent.h_name) {
3545 3544
 					strncpy(hostname, hostent.h_name, sizeof(hostname));
3545
+					hostname[sizeof(hostname)-1]='\0';
3546
+				}
3546 3547
 			}
3547 3548
 
3548 3549
 #ifdef	SESSION
... ...
@@ -4557,6 +4563,7 @@ connect2clamd(struct privdata *privdata)
4557 4557
 			memset((char *)&server, 0, sizeof(struct sockaddr_un));
4558 4558
 			server.sun_family = AF_UNIX;
4559 4559
 			strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
4560
+			server.sun_path[sizeof(server.sun_path)-1]='\0';
4560 4561
 
4561 4562
 			if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
4562 4563
 				perror("socket");
... ...
@@ -6405,6 +6412,7 @@ spf(struct privdata *privdata, table_t *prevhosts)
6405 6405
 			continue;
6406 6406
 		}
6407 6407
 		strncpy(txt, (const char *)&p[1], sizeof(txt) - 1);
6408
+		txt[sizeof(txt)-1]='\0';
6408 6409
 		txt[len - 1] = '\0';
6409 6410
 		if((strncmp(txt, "v=spf1 ", 7) == 0) || (strncmp(txt, "spf2.0/pra ", 11) == 0)) {
6410 6411
 			int j;
... ...
@@ -173,11 +173,13 @@ int dazukoRegister_TS(dazuko_id_t **dazuko_id, const char *groupName, const char
173 173
 	if (strcasecmp(mode, "r") == 0)
174 174
 	{
175 175
 		strncpy(regMode, "R", sizeof(regMode));
176
+		regMode[sizeof(regMode)-1]='\0';
176 177
 		write_mode = 0;
177 178
 	}
178 179
 	else if (strcasecmp(mode, "r+") == 0 || strcasecmp(mode, "rw") == 0)
179 180
 	{
180 181
 		strncpy(regMode, "RW", sizeof(regMode));
182
+		regMode[sizeof(regMode)-1]='\0';
181 183
 		write_mode = 1;
182 184
 	}
183 185
 	else
... ...
@@ -116,6 +116,7 @@ int dazukoRegister_TS_compat12(struct dazuko_id *dazuko, const char *groupName)
116 116
 
117 117
 	opt->command = REGISTER;
118 118
 	strncpy(opt->buffer, groupName, sizeof(opt->buffer) - 1);
119
+	opt->buffer[sizeof(opt->buffer)-1]='\0';
119 120
 	opt->buffer_length = strlen(opt->buffer) + 1;
120 121
 
121 122
 	if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0)
... ...
@@ -186,6 +187,7 @@ int dazuko_set_path_compat12(struct dazuko_id *dazuko, const char *path, int com
186 186
 
187 187
 	opt->command = command;
188 188
 	strncpy(opt->buffer, path, sizeof(opt->buffer) - 1);
189
+	opt->buffer[sizeof(opt->buffer)-1]='\0';
189 190
 	opt->buffer_length = strlen(opt->buffer) + 1;
190 191
 
191 192
 	if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0)
... ...
@@ -64,6 +64,7 @@ int localserver(const struct cfgstruct *copt)
64 64
     memset((char *) &server, 0, sizeof(server));
65 65
     server.sun_family = AF_UNIX;
66 66
     strncpy(server.sun_path, cfgopt(copt, "LocalSocket")->strarg, sizeof(server.sun_path));
67
+    server.sun_path[sizeof(server.sun_path)-1]='\0';
67 68
 
68 69
     if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
69 70
 	estr = strerror(errno);
... ...
@@ -376,6 +376,8 @@ int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeou
376 376
 		break;
377 377
 	    } else {
378 378
 		n = recv(sockfd, buf+boff, n, 0);
379
+		if(n < 0)
380
+		    return -1;
379 381
 		if((boff+n) == size)
380 382
 		    break;
381 383
 		boff += n;
... ...
@@ -284,6 +284,7 @@ static int dconnect(const struct optstruct *opt)
284 284
 
285 285
 	server.sun_family = AF_UNIX;
286 286
 	strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
287
+	server.sun_path[sizeof(server.sun_path)-1]='\0';
287 288
 
288 289
 	if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
289 290
 	    perror("socket()");
... ...
@@ -226,6 +226,7 @@ int scanmanager(const struct optstruct *opt)
226 226
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
227 227
 	    cpy = calloc(strlen(ptr), 1);
228 228
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
229
+	    cpy[strlen(ptr)-1]='\0';
229 230
 	    limits.maxscansize = atoi(cpy) * 1024 * 1024;
230 231
 	    free(cpy);
231 232
 	} else
... ...
@@ -239,6 +240,7 @@ int scanmanager(const struct optstruct *opt)
239 239
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
240 240
 	    cpy = calloc(strlen(ptr), 1);
241 241
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
242
+	    cpy[strlen(ptr)-1]='\0';
242 243
 	    limits.maxfilesize = atoi(cpy) * 1024 * 1024;
243 244
 	    free(cpy);
244 245
 	} else
... ...
@@ -467,6 +469,7 @@ static int clamav_unpack(const char *prog, const char **args, const char *tmpdir
467 467
 	if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
468 468
 	    cpy = calloc(strlen(ptr), 1);
469 469
 	    strncpy(cpy, ptr, strlen(ptr) - 1);
470
+	    cpy[strlen(ptr)-1]='\0';
470 471
 	    maxscansize = atoi(cpy) * 1024;
471 472
 	    free(cpy);
472 473
 	} else /* default - kilobytes */
... ...
@@ -150,14 +150,17 @@ int match_regex(const char *filename, const char *pattern)
150 150
 #else
151 151
 	if(pattern[strlen(pattern) - 1] == '\\') {
152 152
 	    strncpy(fname, filename, 510);
153
+	    fname[509]='\0';
153 154
 	    len = strlen(fname);
154 155
 	    if(fname[len - 1] != '\\') {
155 156
 		fname[len] = '\\';
156 157
 		fname[len + 1] = 0;
157 158
 	    }
158 159
 #endif
159
-	} else
160
+	} else {
160 161
 	    strncpy(fname, filename, 513);
162
+	    fname[512]='\0';
163
+	}
161 164
 
162 165
 	match = (cli_regexec(&reg, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
163 166
 	cli_regfree(&reg);
... ...
@@ -73,6 +73,7 @@ int notify(const char *cfgfile)
73 73
 	socktype = "UNIX";
74 74
 	server.sun_family = AF_UNIX;
75 75
 	strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
76
+	server.sun_path[sizeof(server.sun_path)-1]='\0';
76 77
 
77 78
 	if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
78 79
 	    logg("^Clamd was NOT notified: Can't create socket endpoint for %s\n", cpt->strarg);
... ...
@@ -122,7 +122,6 @@ static char *cab_readstr(int fd, int *ret)
122 122
     }
123 123
 
124 124
     if(lseek(fd, (off_t) (pos + i + 1), SEEK_SET) == -1) {
125
-	/* *ret = CL_EIO; */
126 125
 	*ret = CL_EFORMAT; /* most likely a corrupted file */
127 126
 	return NULL;
128 127
     }
... ...
@@ -136,15 +135,17 @@ static char *cab_readstr(int fd, int *ret)
136 136
     return str;
137 137
 }
138 138
 
139
-static int cab_chkname(const char *name)
139
+static int cab_chkname(char *name, int san)
140 140
 {
141 141
 	size_t i, len = strlen(name);
142 142
 
143 143
 
144 144
     for(i = 0; i < len; i++) {
145
-	if(strchr("%/*?|\\\"+=<>;:\t ", name[i]) || !isascii(name[i])) {
145
+	if(!san && (strchr("%/*?|\\\"+=<>;:\t ", name[i]) || !isascii(name[i]))) {
146 146
 	    cli_dbgmsg("cab_chkname: File name contains disallowed characters\n");
147 147
 	    return 1;
148
+	} else if(san && !isalnum(name[i])) {
149
+	    name[i] = '*';
148 150
 	}
149 151
     }
150 152
 
... ...
@@ -189,7 +190,7 @@ void cab_free(struct cab_archive *cab)
189 189
 
190 190
 int cab_open(int fd, off_t offset, struct cab_archive *cab)
191 191
 {
192
-	unsigned int i, bscore = 0, badname = 0;
192
+	unsigned int i, folders = 0;
193 193
 	struct cab_file *file, *lfile = NULL;
194 194
 	struct cab_folder *folder, *lfolder = NULL;
195 195
 	struct cab_hdr hdr;
... ...
@@ -210,7 +211,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
210 210
 
211 211
     if(cli_readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
212 212
 	cli_dbgmsg("cab_open: Can't read cabinet header\n");
213
-	/* return CL_EIO; */
214 213
 	return CL_EFORMAT; /* most likely a corrupted file */
215 214
     }
216 215
 
... ...
@@ -232,8 +232,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
232 232
     cab->length = EC32(hdr.cbCabinet);
233 233
     cli_dbgmsg("CAB: Cabinet length: %u\n", cab->length);
234 234
     if((off_t) cab->length > rsize) {
235
+	cli_dbgmsg("CAB: Truncating file size from %lu to %lu\n", (unsigned long int) cab->length, (unsigned long int) rsize);
235 236
 	cab->length = (uint32_t) rsize;
236
-	bscore++;
237 237
     }
238 238
 
239 239
     cab->nfolders = EC16(hdr.cFolders);
... ...
@@ -245,7 +245,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
245 245
 	if(cab->nfolders > CAB_FOLDER_LIMIT) {
246 246
 	    cab->nfolders = CAB_FOLDER_LIMIT;
247 247
 	    cli_dbgmsg("CAB: *** Number of folders limited to %u ***\n", cab->nfolders);
248
-	    bscore++;
249 248
 	}
250 249
     }
251 250
 
... ...
@@ -258,19 +257,15 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
258 258
 	if(cab->nfiles > CAB_FILE_LIMIT) {
259 259
 	    cab->nfiles = CAB_FILE_LIMIT;
260 260
 	    cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles);
261
-	    bscore++;
262 261
 	}
263 262
     }
264 263
 
265 264
     cli_dbgmsg("CAB: File format version: %u.%u\n", hdr.versionMajor, hdr.versionMinor);
266
-    if(hdr.versionMajor != 1 || hdr.versionMinor != 3)
267
-	bscore++;
268 265
 
269 266
     cab->flags = EC16(hdr.flags);
270 267
     if(cab->flags & 0x0004) {
271 268
 	if(cli_readn(fd, &hdr_opt, sizeof(hdr_opt)) != sizeof(hdr_opt)) {
272 269
 	    cli_dbgmsg("cab_open: Can't read file header (fake cab?)\n");
273
-	    /* return CL_EIO; */
274 270
 	    return CL_EFORMAT; /* most likely a corrupted file */
275 271
 	}
276 272
 
... ...
@@ -281,7 +276,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
281 281
 	if(cab->reshdr) {
282 282
 	    if(lseek(fd, cab->reshdr, SEEK_CUR) == -1) {
283 283
 		cli_dbgmsg("cab_open: Can't lseek to %u (fake cab?)\n", cab->reshdr);
284
-		/* return CL_EIO; */
285 284
 		return CL_EFORMAT; /* most likely a corrupted file */
286 285
 	    }
287 286
 	}
... ...
@@ -292,8 +286,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
292 292
 	pt = cab_readstr(fd, &ret);
293 293
 	if(ret)
294 294
 	    return ret;
295
-	if(cab_chkname(pt))
296
-	    badname = 1;
295
+	if(cab_chkname(pt, 0))
296
+	    cli_dbgmsg("CAB: Invalid name of preceeding cabinet\n");
297 297
 	else
298 298
 	    cli_dbgmsg("CAB: Preceeding cabinet name: %s\n", pt);
299 299
 	free(pt);
... ...
@@ -301,8 +295,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
301 301
 	pt = cab_readstr(fd, &ret);
302 302
 	if(ret)
303 303
 	    return ret;
304
-	if(cab_chkname(pt))
305
-	    badname = 1;
304
+	if(cab_chkname(pt, 0))
305
+	    cli_dbgmsg("CAB: Invalid info for preceeding cabinet\n");
306 306
 	else
307 307
 	    cli_dbgmsg("CAB: Preceeding cabinet info: %s\n", pt);
308 308
 	free(pt);
... ...
@@ -313,8 +307,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
313 313
 	pt = cab_readstr(fd, &ret);
314 314
 	if(ret)
315 315
 	    return ret;
316
-	if(cab_chkname(pt))
317
-	    badname = 1;
316
+	if(cab_chkname(pt, 0))
317
+	    cli_dbgmsg("CAB: Invalid name of next cabinet\n");
318 318
 	else
319 319
 	    cli_dbgmsg("CAB: Next cabinet name: %s\n", pt);
320 320
 	free(pt);
... ...
@@ -322,37 +316,37 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
322 322
 	pt = cab_readstr(fd, &ret);
323 323
 	if(ret)
324 324
 	    return ret;
325
-	if(cab_chkname(pt))
326
-	    badname = 1;
325
+	if(cab_chkname(pt, 0))
326
+	    cli_dbgmsg("CAB: Invalid info for next cabinet\n");
327 327
 	else
328 328
 	    cli_dbgmsg("CAB: Next cabinet info: %s\n", pt);
329 329
 	free(pt);
330 330
     }
331
-    bscore += badname;
332
-
333
-    if(bscore >= 4) {
334
-	cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
335
-	return CL_EFORMAT;
336
-    }
337 331
 
338 332
     /* folders */
339 333
     for(i = 0; i < cab->nfolders; i++) {
340 334
 	if(cli_readn(fd, &folder_hdr, sizeof(folder_hdr)) != sizeof(folder_hdr)) {
341
-	    cli_errmsg("cab_open: Can't read header for folder %u\n", i);
342
-	    cab_free(cab);
343
-	    /* return CL_EIO; */
344
-	    return CL_EFORMAT; /* most likely a corrupted file */
335
+	    cli_dbgmsg("cab_open: Can't read header for folder %u\n", i);
336
+	    break;
345 337
 	}
346 338
 
347 339
 	if(resfold) {
348 340
 	    if(lseek(fd, resfold, SEEK_CUR) == -1) {
349
-		cli_errmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold);
350
-		cab_free(cab);
351
-		/* return CL_EIO; */
352
-		return CL_EFORMAT; /* most likely a corrupted file */
341
+		cli_dbgmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold);
342
+		break;
353 343
 	    }
354 344
 	}
355 345
 
346
+	if(EC32(folder_hdr.coffCabStart) + offset > rsize) {
347
+	    cli_dbgmsg("CAB: Folder out of file\n");
348
+	    continue;
349
+	}
350
+
351
+	if((EC16(folder_hdr.typeCompress) & 0x000f) > 3) {
352
+	    cli_dbgmsg("CAB: Unknown compression method\n");
353
+	    continue;
354
+	}
355
+
356 356
 	folder = (struct cab_folder *) cli_calloc(1, sizeof(struct cab_folder));
357 357
 	if(!folder) {
358 358
 	    cli_errmsg("cab_open: Can't allocate memory for folder\n");
... ...
@@ -362,16 +356,12 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
362 362
 
363 363
 	folder->cab = (struct cab_archive *) cab;
364 364
 	folder->offset = (off_t) EC32(folder_hdr.coffCabStart) + offset;
365
-	if(folder->offset > rsize)
366
-	    bscore++;
367 365
 	folder->nblocks = EC16(folder_hdr.cCFData);
368 366
 	folder->cmethod = EC16(folder_hdr.typeCompress);
369 367
 
370 368
 	cli_dbgmsg("CAB: Folder record %u\n", i);
371 369
 	cli_dbgmsg("CAB: Folder offset: %u\n", (unsigned int) folder->offset);
372 370
 	cli_dbgmsg("CAB: Folder compression method: %d\n", folder->cmethod);
373
-	if((folder->cmethod & 0x000f) > 3)
374
-	    bscore++;
375 371
 
376 372
 	if(!lfolder)
377 373
 	    cab->folders = folder;
... ...
@@ -379,27 +369,20 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
379 379
 	    lfolder->next = folder;
380 380
 
381 381
 	lfolder = folder;
382
-
383
-	if(bscore > 10) {
384
-	    cab_free(cab);
385
-	    cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
386
-	    return CL_EFORMAT;
387
-	}
382
+	folders++;
388 383
     }
384
+    cli_dbgmsg("CAB: Recorded folders: %u\n", folders);
389 385
 
390 386
     /* files */
387
+    if(cab->nfolders != folders && lseek(fd, EC16(hdr.coffFiles), SEEK_SET) == -1) {
388
+	cli_dbgmsg("cab_open: Can't lseek to hdr.coffFiles\n");
389
+	cab_free(cab);
390
+	return CL_EFORMAT;
391
+    }
391 392
     for(i = 0; i < cab->nfiles; i++) {
392
-	if(bscore > 10) {
393
-	    cab_free(cab);
394
-	    cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
395
-	    return CL_EFORMAT;
396
-	}
397
-
398 393
 	if(cli_readn(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
399
-	    cli_errmsg("cab_open: Can't read file %u header\n", i);
400
-	    cab_free(cab);
401
-	    /* return CL_EIO; */
402
-	    return CL_EFORMAT; /* most likely a corrupted file */
394
+	    cli_dbgmsg("cab_open: Can't read file %u header\n", i);
395
+	    break;
403 396
 	}
404 397
 
405 398
 	file = (struct cab_file *) cli_calloc(1, sizeof(struct cab_file));
... ...
@@ -411,17 +394,18 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
411 411
 
412 412
 	file->cab = cab;
413 413
 	file->fd = fd;
414
-	file->length = EC32(file_hdr.cbFile);
415 414
 	file->offset = EC32(file_hdr.uoffFolderStart);
415
+	file->length = EC32(file_hdr.cbFile);
416 416
 	file->attribs = EC32(file_hdr.attribs);
417 417
 	fidx = EC32(file_hdr.iFolder);
418
+	file->error = CL_SUCCESS;
418 419
 
419 420
 	file->name = cab_readstr(fd, &ret);
420 421
 	if(ret) {
421 422
 	    free(file);
422
-	    cab_free(cab);
423
-	    return ret;
423
+	    continue;
424 424
 	}
425
+	cab_chkname(file->name, 1);
425 426
 
426 427
 	cli_dbgmsg("CAB: File record %u\n", i);
427 428
 	cli_dbgmsg("CAB: File name: %s\n", file->name);
... ...
@@ -444,9 +428,7 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
444 444
 	/* folder index */
445 445
 	if(fidx < 0xfffd) {
446 446
 	    if(fidx > cab->nfolders) {
447
-		if(bscore < 3)
448
-		    cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
449
-		bscore++;
447
+		cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
450 448
 		free(file->name);
451 449
 		free(file);
452 450
 		continue;
... ...
@@ -457,11 +439,10 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
457 457
 		file->folder = file->folder->next;
458 458
 
459 459
 	    if(!file->folder) {
460
-		cli_errmsg("cab_open: Folder not found for file %s\n", file->name);
460
+		cli_dbgmsg("cab_open: Folder not found for file %s\n", file->name);
461 461
 		free(file->name);
462 462
 		free(file);
463
-		cab_free(cab);
464
-		return CL_EFORMAT;
463
+		continue;
465 464
 	    }
466 465
 
467 466
 	} else {
... ...
@@ -490,13 +471,11 @@ static int cab_read_block(int fd, struct cab_state *state, uint16_t resdata)
490 490
 
491 491
     if(cli_readn(fd, &block_hdr, sizeof(block_hdr)) != sizeof(block_hdr)) {
492 492
 	cli_dbgmsg("cab_read_block: Can't read block header\n");
493
-	/* return CL_EIO; */
494 493
 	return CL_EFORMAT; /* most likely a corrupted file */
495 494
     }
496 495
 
497 496
     if(resdata && lseek(fd, (off_t) resdata, SEEK_CUR) == -1) {
498 497
 	cli_dbgmsg("cab_read_block: lseek failed\n");
499
-	/* return CL_EIO; */
500 498
 	return CL_EFORMAT; /* most likely a corrupted file */
501 499
     }
502 500
 
... ...
@@ -515,7 +494,6 @@ static int cab_read_block(int fd, struct cab_state *state, uint16_t resdata)
515 515
 
516 516
     if(cli_readn(fd, state->block, state->blklen) != state->blklen) {
517 517
 	cli_dbgmsg("cab_read_block: Can't read block data\n");
518
-	/* return CL_EIO; */
519 518
 	return CL_EFORMAT; /* most likely a corrupted file */
520 519
     }
521 520
 
... ...
@@ -530,6 +508,11 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
530 530
 	uint16_t todo, left;
531 531
 
532 532
 
533
+    if((file->cab->state->blknum > file->folder->nblocks) && !file->lread) {
534
+	file->error = CL_BREAK;
535
+	return -1;
536
+    }
537
+
533 538
     todo = bytes;
534 539
     while(todo > 0) {
535 540
 	left = file->cab->state->end - file->cab->state->pt;
... ...
@@ -544,10 +527,8 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
544 544
 	    todo -= left;
545 545
 
546 546
 	} else {
547
-	    if(file->cab->state->blknum++ >= file->folder->nblocks) {
548
-		file->error = CL_EFORMAT;
547
+	    if(file->cab->state->blknum++ >= file->folder->nblocks)
549 548
 		break;
550
-	    }
551 549
 
552 550
 	    file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata);
553 551
 	    if(file->error)
... ...
@@ -568,7 +549,7 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
568 568
 	}
569 569
     }
570 570
 
571
-    return bytes - todo;
571
+    return file->lread = bytes - todo;
572 572
 }
573 573
 
574 574
 static int cab_unstore(struct cab_file *file, int bytes)
... ...
@@ -721,11 +702,14 @@ int cab_extract(struct cab_file *file, const char *name)
721 721
 	    break;
722 722
 
723 723
 	default:
724
-	    cli_warnmsg("CAB: Not supported compression method: 0x%x\n", file->folder->cmethod & 0x000f);
724
+	    cli_dbgmsg("CAB: Not supported compression method: 0x%x\n", file->folder->cmethod & 0x000f);
725 725
 	    ret = CL_EFORMAT;
726 726
     }
727 727
 
728 728
     close(file->ofd);
729 729
 
730
+    if(ret == CL_BREAK)
731
+	ret = CL_SUCCESS;
732
+
730 733
     return ret;
731 734
 }
... ...
@@ -54,6 +54,7 @@ struct cab_file {
54 54
     char *name;
55 55
     uint32_t length;
56 56
     int error;
57
+    int lread;
57 58
     int fd;
58 59
     int ofd;
59 60
     struct cab_folder *folder;
... ...
@@ -135,7 +135,7 @@ int is_tar(unsigned char *buf, unsigned int nbytes);
135 135
 
136 136
 cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
137 137
 {
138
-	unsigned char smallbuff[MAGIC_BUFFER_SIZE + 1], *decoded, *bigbuff;
138
+	unsigned char buff[MAGIC_BUFFER_SIZE + 1], *decoded;
139 139
 	int bread, sret;
140 140
 	cli_file_t ret = CL_TYPE_BINARY_DATA;
141 141
 	struct cli_matcher *root;
... ...
@@ -147,12 +147,13 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
147 147
 	return CL_TYPE_ERROR;
148 148
     }
149 149
 
150
-    memset(smallbuff, 0, sizeof(smallbuff));
151
-    bread = cli_readn(desc, smallbuff, MAGIC_BUFFER_SIZE);
150
+    memset(buff, 0, sizeof(buff));
151
+    bread = cli_readn(desc, buff, MAGIC_BUFFER_SIZE);
152 152
     if(bread == -1)
153 153
 	return CL_TYPE_ERROR;
154
+    buff[bread] = 0;
154 155
 
155
-    ret = cli_filetype(smallbuff, bread, engine);
156
+    ret = cli_filetype(buff, bread, engine);
156 157
 
157 158
     if(ret >= CL_TYPE_TEXT_ASCII && ret <= CL_TYPE_BINARY_DATA) {
158 159
 	/* HTML files may contain special characters and could be
... ...
@@ -165,7 +166,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
165 165
 	if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
166 166
 	    return ret;
167 167
 
168
-	sret = cli_ac_scanbuff(smallbuff, bread, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
168
+	sret = cli_ac_scanbuff(buff, bread, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
169 169
 
170 170
 	cli_ac_freedata(&mdata);
171 171
 
... ...
@@ -175,7 +176,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
175 175
 	    if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
176 176
 		return ret;
177 177
 
178
-	    decoded = (unsigned char *) cli_utf16toascii((char *) smallbuff, bread);
178
+	    decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread);
179 179
 	    if(decoded) {
180 180
 		sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, desc, NULL, AC_SCAN_FT, NULL);
181 181
 		free(decoded);
... ...
@@ -190,11 +191,11 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
190 190
 		    /* check if we can autodetect this encoding.
191 191
 		     * If we can't don't try to detect HTML sig, since
192 192
 		     * we just tried that above, and failed */
193
-		    if((encoding = encoding_detect_bom(smallbuff, bread))) {
194
-			    unsigned char decodedbuff[sizeof(smallbuff)*2];
193
+		    if((encoding = encoding_detect_bom(buff, bread))) {
194
+			    unsigned char decodedbuff[sizeof(buff)*2];
195 195
 			    m_area_t in_area, out_area;
196 196
 
197
-			    in_area.buffer = (unsigned char *) smallbuff;
197
+			    in_area.buffer = (unsigned char *) buff;
198 198
 			    in_area.length = bread;
199 199
 			    in_area.offset = 0;
200 200
 			    out_area.buffer = decodedbuff;
... ...
@@ -227,38 +228,16 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
227 227
     }
228 228
 
229 229
     if(ret == CL_TYPE_BINARY_DATA) {
230
-
231
-	if(!(bigbuff = (unsigned char *) cli_calloc(37638 + 1, sizeof(unsigned char))))
232
-	    return ret;
233
-
234
-	lseek(desc, 0, SEEK_SET);
235
-	if((bread = cli_readn(desc, bigbuff, 37638)) > 0) {
236
-
237
-	    bigbuff[bread] = 0;
238
-
239
-	    switch(is_tar(bigbuff, bread)) {
240
-		case 1:
241
-		    ret = CL_TYPE_OLD_TAR;
242
-		    cli_dbgmsg("Recognized old fashioned tar file\n");
243
-		    break;
244
-		case 2:
245
-		    ret = CL_TYPE_POSIX_TAR;
246
-		    cli_dbgmsg("Recognized POSIX tar file\n");
247
-		    break;
248
-	    }
230
+	switch(is_tar(buff, bread)) {
231
+	    case 1:
232
+		ret = CL_TYPE_OLD_TAR;
233
+		cli_dbgmsg("Recognized old fashioned tar file\n");
234
+		break;
235
+	    case 2:
236
+		ret = CL_TYPE_POSIX_TAR;
237
+		cli_dbgmsg("Recognized POSIX tar file\n");
238
+		break;
249 239
 	}
250
-
251
-	if(ret == CL_TYPE_BINARY_DATA) {
252
-	    if(!memcmp(bigbuff + 32769, "CD001" , 5) || !memcmp(bigbuff + 37633, "CD001" , 5)) {
253
-		cli_dbgmsg("Recognized ISO 9660 CD-ROM data\n");
254
-		ret = CL_TYPE_IGNORED;
255
-	    } else if(!memcmp(bigbuff + 32776, "CDROM" , 5)) {
256
-		cli_dbgmsg("Recognized High Sierra CD-ROM data\n");
257
-		ret = CL_TYPE_IGNORED;
258
-	    }
259
-	}
260
-
261
-	free(bigbuff);
262 240
     }
263 241
 
264 242
     return ret;
... ...
@@ -315,6 +315,7 @@ int hashtab_insert(struct hashtable *s, const char* key, const size_t len, const
315 315
 				if(!thekey)
316 316
 					return CL_EMEM;
317 317
 				strncpy(thekey, key, len+1);
318
+				thekey[len]='\0';
318 319
 				element->key = thekey;
319 320
 				element->data = data;
320 321
 				element->len = len;
... ...
@@ -557,3 +558,26 @@ ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array)
557 557
 	}
558 558
 	return j;
559 559
 }
560
+
561
+struct uniq *uniq_init(uint32_t count) {
562
+	struct uniq *U;
563
+	if(!count) return NULL;
564
+ 	count = count <= 256 ? 256 : count + (count*20/100);
565
+	U = (struct uniqueid *)cli_calloc(1, sizeof(U)+sizeof(uint32_t)*count);
566
+	if(!U) return NULL;
567
+	U->count = count;
568
+	return U;
569
+}
570
+
571
+uint32_t uniq_add(struct uniq *U, const char *key, uint32_t key_len, uint32_t *rhash) {
572
+	uint32_t h = hash((const unsigned char *)key, key_len, U->count);
573
+	if(rhash) *rhash = h;
574
+	return U->uniques[h]++;
575
+}
576
+
577
+uint32_t uniq_get(struct uniq *U, const char *key, uint32_t key_len, uint32_t *rhash) {
578
+	uint32_t h = hash((const unsigned char *)key, key_len, U->count);
579
+	if(rhash) *rhash = h;
580
+	return U->uniques[h];
581
+}
582
+
... ...
@@ -20,11 +20,11 @@
20 20
  *  MA 02110-1301, USA.
21 21
  */
22 22
 
23
-#include <stdio.h>
24
-#include <stddef.h>
25 23
 #ifndef _HASHTAB_H
26 24
 #define _HASHTAB_H
27
-
25
+#include <stdio.h>
26
+#include <stddef.h>
27
+#include "cltypes.h"
28 28
 typedef long element_data;
29 29
 
30 30
 /* define this for debugging/profiling purposes only, NOT in production/release code */
... ...
@@ -105,5 +105,17 @@ int hashset_clear(struct hashset* hs);
105 105
 void hashset_destroy(struct hashset* hs);
106 106
 ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array);
107 107
 
108
+
109
+/* A basic storage for unique IDs */
110
+struct uniq {
111
+	uint32_t count;
112
+        uint32_t uniques[];
113
+};
114
+
115
+struct uniq *uniq_init(uint32_t);
116
+#define uniq_free(X) free(X);
117
+uint32_t uniq_add(struct uniq *, const char *, uint32_t, uint32_t *);
118
+uint32_t uniq_get(struct uniq *, const char *, uint32_t, uint32_t *);
119
+
108 120
 #endif
109 121
 
... ...
@@ -555,7 +555,7 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
555 555
 		/* this will still contains scripts that are inside comments */
556 556
 		snprintf(filename, 1024, "%s/nocomment.html", dirname);
557 557
 		file_buff_o2->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
558
-		if (!file_buff_o2->fd) {
558
+		if (file_buff_o2->fd == -1) {
559 559
 			cli_dbgmsg("open failed: %s\n", filename);
560 560
 			free(file_buff_o2);
561 561
 			file_buff_o2 = file_buff_text = NULL;
... ...
@@ -564,6 +564,7 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
564 564
 
565 565
 		file_buff_text = (file_buff_t *) cli_malloc(sizeof(file_buff_t));
566 566
 		if(!file_buff_text) {
567
+			close(file_buff_o2->fd);
567 568
 			free(file_buff_o2);
568 569
 			file_buff_o2 = file_buff_text = NULL;
569 570
 			goto abort;
... ...
@@ -571,12 +572,13 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
571 571
 
572 572
 		snprintf(filename, 1024, "%s/notags.html", dirname);
573 573
 		file_buff_text->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
574
-		if(!file_buff_text->fd) {
574
+		if(file_buff_text->fd == -1) {
575 575
 			cli_dbgmsg("open failed: %s\n", filename);
576 576
 			close(file_buff_o2->fd);
577 577
 			free(file_buff_o2);
578 578
 			free(file_buff_text);
579 579
 			file_buff_o2 = file_buff_text = NULL;
580
+			goto abort;
580 581
 		}
581 582
 		file_buff_o2->length = 0;
582 583
 		file_buff_text->length = 0;
... ...
@@ -74,6 +74,7 @@ CLAMAV_PRIVATE {
74 74
     cli_warnmsg;
75 75
     cli_strtokbuf;
76 76
     cli_leavetemps_flag;
77
+    uniq_get;
77 78
   local:
78 79
     *;
79 80
 };
... ...
@@ -1079,6 +1079,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
1079 1079
 	return CL_EMEM;
1080 1080
     }
1081 1081
     strncpy(new->virname, virname, namelen);
1082
+    new->virname[namelen]='\0';
1082 1083
 
1083 1084
     if(offset) {
1084 1085
 	new->offset = cli_strdup(offset);
... ...
@@ -104,7 +104,7 @@ static const unsigned short mszip_bit_mask_tab[17] = {
104 104
       if (mszip_read_input(zip)) return zip->error;                      \
105 105
       i_ptr = zip->i_ptr;                                               \
106 106
       i_end = zip->i_end;                                               \
107
-      if(i_ptr == i_end) return CL_EFORMAT;				\
107
+      if(i_ptr == i_end) break;						\
108 108
     }                                                                   \
109 109
     bit_buffer |= *i_ptr++ << bits_left; bits_left  += 8;               \
110 110
   }                                                                     \
... ...
@@ -125,7 +125,12 @@ static const unsigned short mszip_bit_mask_tab[17] = {
125 125
 
126 126
 static int mszip_read_input(struct mszip_stream *zip) {
127 127
   int nread = zip->read_cb ? zip->read_cb(zip->file, zip->inbuf, (int)zip->inbuf_size) : cli_readn(zip->fd, zip->inbuf, (int)zip->inbuf_size);
128
-  if (nread < 0) return zip->error = CL_EFORMAT;
128
+  if (nread < 0) {
129
+    if (zip->file->error == CL_BREAK)
130
+      return zip->error = CL_BREAK;
131
+    else
132
+      return zip->error = CL_EFORMAT;
133
+  }
129 134
 
130 135
   zip->i_ptr = &zip->inbuf[0];
131 136
   zip->i_end = &zip->inbuf[nread];
... ...
@@ -749,7 +754,12 @@ void mszip_free(struct mszip_stream *zip) {
749 749
 
750 750
 static int lzx_read_input(struct lzx_stream *lzx) {
751 751
   int bread = lzx->read_cb ? lzx->read_cb(lzx->file, &lzx->inbuf[0], (int)lzx->inbuf_size) : cli_readn(lzx->fd, &lzx->inbuf[0], (int)lzx->inbuf_size);
752
-  if (bread < 0) return lzx->error = CL_EFORMAT;
752
+  if (bread < 0) {
753
+    if (lzx->file->error == CL_BREAK)
754
+      return lzx->error = CL_BREAK;
755
+    else
756
+      return lzx->error = CL_EFORMAT;
757
+  }
753 758
 
754 759
   /* huff decode's ENSURE_BYTES(16) might overrun the input stream, even
755 760
    * if those bits aren't used, so fake 2 more bytes */
... ...
@@ -1577,7 +1587,12 @@ void lzx_free(struct lzx_stream *lzx) {
1577 1577
 
1578 1578
 static int qtm_read_input(struct qtm_stream *qtm) {
1579 1579
   int nread = qtm->read_cb ? qtm->read_cb(qtm->file, &qtm->inbuf[0], (int)qtm->inbuf_size) : cli_readn(qtm->fd, &qtm->inbuf[0], (int)qtm->inbuf_size);
1580
-  if (nread < 0) return qtm->error = CL_EFORMAT;
1580
+  if (nread < 0) {
1581
+    if (qtm->file->error == CL_BREAK)
1582
+      return qtm->error = CL_BREAK;
1583
+    else
1584
+      return qtm->error = CL_EFORMAT;
1585
+  }
1581 1586
 
1582 1587
   qtm->i_ptr = &qtm->inbuf[0];
1583 1588
   qtm->i_end = &qtm->inbuf[nread];
... ...
@@ -47,9 +47,10 @@
47 47
 #include "cltypes.h"
48 48
 #include "others.h"
49 49
 #include "ole2_extract.h"
50
+#include "scanners.h"
51
+#include "hashtab.h"
50 52
 
51 53
 #include "mbox.h"
52
-#include "blob.h" /* sanitiseName() */
53 54
 
54 55
 #define ole2_endian_convert_16(v) le16_to_host((uint16_t)(v))
55 56
 #define ole2_endian_convert_32(v) le32_to_host((uint32_t)(v))
... ...
@@ -70,6 +71,7 @@
70 70
 #define	O_BINARY	0
71 71
 #endif
72 72
 
73
+
73 74
 typedef struct ole2_header_tag
74 75
 {
75 76
 	unsigned char magic[8];		/* should be: 0xd0cf11e0a1b11ae1 */
... ...
@@ -102,8 +104,11 @@ typedef struct ole2_header_tag
102 102
 	unsigned char *m_area;
103 103
 	off_t m_length;
104 104
 	bitset_t *bitset;
105
+	struct uniq *U;
106
+	int has_vba;
105 107
 } ole2_header_t;
106 108
 
109
+
107 110
 typedef struct property_tag
108 111
 {
109 112
 	char name[64];		/* in unicode */
... ...
@@ -136,7 +141,8 @@ typedef struct property_tag
136 136
 
137 137
 static unsigned char magic_id[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1};
138 138
 
139
-static char *get_property_name(char *name, int size)
139
+
140
+static char *get_property_name2(char *name, int size)
140 141
 {
141 142
 	int i, j;
142 143
 	char *newname;
... ...
@@ -153,7 +159,7 @@ static char *get_property_name(char *name, int size)
153 153
 	/* size-2 to ignore trailing NULL */
154 154
 	for (i=0 ; i < size-2; i+=2) {
155 155
 		if((!(name[i]&0x80)) && isprint(name[i])) {
156
-			newname[j++] = name[i];
156
+		        newname[j++] = tolower(name[i]);
157 157
 		} else {
158 158
 			if (name[i] < 10 && name[i] >= 0) {
159 159
 				newname[j++] = '_';
... ...
@@ -179,50 +185,72 @@ static char *get_property_name(char *name, int size)
179 179
 	return newname;
180 180
 }
181 181
 
182
-static void print_property_name(char *pname, int size)
183
-{
184
-        char *name;
185
-                                                                                                                                              
186
-        name = get_property_name(pname, size);
187
-        if (!name) {
188
-                return;
189
-        }
190
-        cli_dbgmsg("%34s ", name);
191
-        free(name);
192
-        return;
182
+static char *get_property_name(char *name, int size) {
183
+  const char *carray = "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz._";
184
+  int csize = size>>1;
185
+  char *newname, *cname;
186
+  char *oname = name;
187
+
188
+	if (csize<=0) return NULL;
189
+
190
+  newname = cname = (char *)cli_malloc(size);
191
+  if (!newname) return NULL;
192
+
193
+  while(--csize) {
194
+    uint16_t lo, hi, u=cli_readint16(oname)-0x3800;
195
+    oname+=2;
196
+    if (u > 0x1040) {
197
+      free(newname);
198
+      return get_property_name2(name, size);
199
+    }
200
+    lo = u % 64;
201
+    u >>= 6;
202
+    hi = u % 64;
203
+    *cname++=carray[lo];
204
+    if(csize!=1 || u!= 64) *cname++=carray[hi];
205
+  }
206
+  *cname='\0';
207
+  return newname;
193 208
 }
194 209
 
210
+
195 211
 static void print_ole2_property(property_t *property)
196 212
 {
213
+	char spam[128], *buf;
197 214
 	if (property->name_size > 64) {
198 215
                 cli_dbgmsg("[err name len: %d]\n", property->name_size);
199 216
                 return;
200 217
         }
201
-	print_property_name(property->name, property->name_size);
218
+	buf = get_property_name(property->name, property->name_size);
219
+	snprintf(spam, sizeof(spam), "OLE2: %s ", buf ? buf : "<noname>");
220
+	spam[sizeof(spam)-1]='\0';
221
+	if (buf) free(buf);
202 222
 	switch (property->type) {
203 223
 	case 2:
204
-		cli_dbgmsg(" [file] ");
224
+		strncat(spam, " [file] ", sizeof(spam) - 1 - strlen(spam));
205 225
 		break;
206 226
 	case 1:
207
-		cli_dbgmsg(" [dir ] ");
227
+		strncat(spam, " [dir ] ", sizeof(spam) - 1 - strlen(spam));
208 228
 		break;
209 229
 	case 5:
210
-		cli_dbgmsg(" [root] ");
230
+		strncat(spam, " [root] ", sizeof(spam) - 1 - strlen(spam));
211 231
 		break;
212 232
 	default:
213
-		cli_dbgmsg(" [%d]", property->type);
233
+		strncat(spam, " [unkn] ", sizeof(spam) - 1 - strlen(spam));
214 234
 	}
235
+	spam[sizeof(spam)-1]='\0';
215 236
 	switch (property->color) {
216 237
 	case 0:
217
-		cli_dbgmsg(" r ");
238
+		strncat(spam, " r  ", sizeof(spam) - 1 - strlen(spam));
218 239
 		break;
219 240
 	case 1:
220
-		cli_dbgmsg(" b ");
241
+		strncat(spam, " b  ", sizeof(spam) - 1 - strlen(spam));
221 242
 		break;
222 243
 	default:
223
-		cli_dbgmsg(" u ");
244
+		strncat(spam, " u  ", sizeof(spam) - 1 - strlen(spam));
224 245
 	}
225
-	cli_dbgmsg(" 0x%.8x 0x%.8x\n", property->size, property->user_flags);
246
+	spam[sizeof(spam)-1]='\0';
247
+	cli_dbgmsg("%s size:0x%.8x flags:0x%.8x\n", spam, property->size, property->user_flags);
226 248
 }
227 249
 
228 250
 static void print_ole2_header(ole2_header_t *hdr)
... ...
@@ -461,44 +489,45 @@ static void ole2_read_property_tree(int fd, ole2_header_t *hdr, const char *dir,
461 461
 }
462 462
 */
463 463
 
464
-static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, int32_t prop_index,
465
-				int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir),
466
-				    unsigned int rec_level, unsigned int *file_count, cli_ctx *ctx, unsigned long *scansize)
464
+static int ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, int32_t prop_index,
465
+				   int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx),
466
+				   unsigned int rec_level, unsigned int *file_count, cli_ctx *ctx, unsigned long *scansize)
467 467
 {
468 468
 	property_t prop_block[4];
469 469
 	int32_t idx, current_block, i;
470 470
 	char *dirname;
471
+	int ret;
471 472
 	const struct cl_limits *limits = ctx ? ctx->limits : NULL;
472 473
 
473 474
 	current_block = hdr->prop_start;
474 475
 
475 476
 	if ((prop_index < 0) || (prop_index > (int32_t) hdr->max_block_no) || (rec_level > 100) || (*file_count > 100000)) {
476
-		return;
477
+		return CL_SUCCESS;
477 478
 	}
478 479
 	if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
479 480
 		cli_dbgmsg("OLE2: File limit reached (max: %d)\n", limits->maxfiles);
480
-		return;
481
+		return CL_SUCCESS;
481 482
 	}
482 483
 	
483 484
 	if (limits && limits->maxreclevel && (rec_level > limits->maxreclevel)) {
484 485
 		cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", limits->maxreclevel);
485
-		return;
486
+		return CL_SUCCESS;
486 487
 	}
487 488
 
488 489
 	idx = prop_index / 4;
489 490
 	for (i=0 ; i < idx ; i++) {
490 491
 		current_block = ole2_get_next_block_number(fd, hdr, current_block);
491 492
 		if (current_block < 0) {
492
-			return;
493
+			return CL_SUCCESS;
493 494
 		}
494 495
 	}
495 496
 	idx = prop_index % 4;
496 497
 	if (!ole2_read_block(fd, hdr, prop_block,
497 498
 			current_block)) {
498
-		return;
499
+		return CL_SUCCESS;
499 500
 	}	
500 501
 	if (prop_block[idx].type <= 0) {
501
-		return;
502
+		return CL_SUCCESS;
502 503
 	}
503 504
 	prop_block[idx].name_size = ole2_endian_convert_16(prop_block[idx].name_size);
504 505
 	prop_block[idx].prev = ole2_endian_convert_32(prop_block[idx].prev);
... ...
@@ -512,16 +541,16 @@ static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir,
512 512
 	prop_block[idx].start_block = ole2_endian_convert_32(prop_block[idx].start_block);
513 513
 	prop_block[idx].size = ole2_endian_convert_32(prop_block[idx].size);
514 514
 	
515
-	print_ole2_property(&prop_block[idx]);
515
+	if (dir) print_ole2_property(&prop_block[idx]);
516 516
 
517 517
 	/* Check we aren't in a loop */
518 518
 	if (cli_bitset_test(hdr->bitset, (unsigned long) prop_index)) {
519 519
 		/* Loop in property tree detected */
520 520
 		cli_dbgmsg("OLE2: Property tree loop detected at index %d\n", prop_index);
521
-		return;
521
+		return CL_BREAK;
522 522
 	}
523 523
 	if (!cli_bitset_set(hdr->bitset, (unsigned long) prop_index)) {
524
-		return;
524
+		return CL_SUCCESS;
525 525
 	}
526 526
 
527 527
 	switch (prop_block[idx].type) {
... ...
@@ -530,162 +559,143 @@ static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir,
530 530
 					(*file_count != 0)) {
531 531
 				/* Can only have RootEntry as the top */
532 532
 				cli_dbgmsg("ERROR: illegal Root Entry\n");
533
-				return;
533
+				return CL_SUCCESS;
534 534
 			}
535 535
 			hdr->sbat_root_start = prop_block[idx].start_block;
536
-			ole2_walk_property_tree(fd, hdr, dir,
537
-				prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize);
538
-			ole2_walk_property_tree(fd, hdr, dir,
539
-				prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize);
540
-			ole2_walk_property_tree(fd, hdr, dir,
541
-				prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize);
536
+			if (
537
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
538
+				||
539
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
540
+				||
541
+				(ret=ole2_walk_property_tree(fd, hdr, dir,prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
542
+			) return ret;
542 543
 			break;
543 544
 		case 2: /* File */
544 545
 			if (limits && limits->maxfiles && ctx->scannedfiles + *file_count > limits->maxfiles) {
545
-			  cli_dbgmsg("ole2: files limit reached (max: %u)\n", ctx->limits->maxfiles);
546
-			  break;
546
+				cli_dbgmsg("OLE2: files limit reached (max: %u)\n", ctx->limits->maxfiles);
547
+				return CL_BREAK;
547 548
 			}
548 549
 			if (!limits || !limits->maxfilesize || prop_block[idx].size <= limits->maxfilesize || *scansize == -1 || prop_block[idx].size <= *scansize) {
549 550
 				(*file_count)++;
550 551
 				*scansize-=prop_block[idx].size;
551
-				if (!handler(fd, hdr, &prop_block[idx], dir)) {
552
-					cli_dbgmsg("ERROR: handler failed\n");
553
-					/* If we don't return on this error then
554
-					   we can sometimes pull VBA code
555
-					   from corrupted files.
556
-					*/
557
-			
558
-				}
552
+				if ((ret=handler(fd, hdr, &prop_block[idx], dir, ctx)) != CL_SUCCESS)
553
+					return ret;
559 554
 			} else {
560
-				cli_dbgmsg("ole2: filesize exceeded\n");
555
+				cli_dbgmsg("OLE2: filesize exceeded\n");
561 556
 			}
562
-			ole2_walk_property_tree(fd, hdr, dir,
563
-				prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize);
564
-			ole2_walk_property_tree(fd, hdr, dir,
565
-				prop_block[idx].next, handler, rec_level, file_count, ctx, scansize);
566
-			ole2_walk_property_tree(fd, hdr, dir,
567
-				prop_block[idx].child, handler, rec_level, file_count, ctx, scansize);
557
+			if (
558
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
559
+				||
560
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
561
+				||
562
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].child, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
563
+			) return ret;
568 564
 			break;
569 565
 		case 1: /* Directory */
570
-			dirname = (char *) cli_malloc(strlen(dir)+8);
571
-			if (!dirname)  {
572
-				return;
573
-			}
574
-			snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index);
575
-			if (mkdir(dirname, 0700) != 0) {
576
-				free(dirname);
577
-				return;
578
-			}
579
-			cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
580
-			ole2_walk_property_tree(fd, hdr, dir,
581
-				prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize);
582
-			ole2_walk_property_tree(fd, hdr, dir,
583
-				prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize);
584
-			ole2_walk_property_tree(fd, hdr, dirname,
585
-				prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize);
586
-			free(dirname);
566
+			if (dir) {
567
+				dirname = (char *) cli_malloc(strlen(dir)+8);
568
+				if (!dirname) return CL_BREAK;
569
+				snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index);
570
+				if (mkdir(dirname, 0700) != 0) {
571
+					free(dirname);
572
+					return CL_BREAK;
573
+				}
574
+				cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
575
+			} else dirname = NULL;
576
+			if (
577
+				(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
578
+				||
579
+				(ret=ole2_walk_property_tree(fd, hdr, dir,prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
580
+				||
581
+				(ret=ole2_walk_property_tree(fd, hdr, dirname, prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
582
+			) {} 
583
+			if (dirname) free(dirname);
584
+			return ret;
587 585
 			break;
588 586
 		default:
589 587
 			cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type);
590 588
 			break;
591 589
 	}
592
-	return;
590
+	return CL_SUCCESS;
593 591
 }
594 592
 /* Write file Handler - write the contents of the entry to a file */
595
-static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const char *dir)
593
+static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
596 594
 {
597 595
 	unsigned char *buff;
598 596
 	int32_t current_block, ofd, len, offset;
599
-	char *name, *newname;
597
+	char *name, newname[1024];
600 598
 	bitset_t *blk_bitset;
599
+	uint32_t hash, cnt;
601 600
 
602 601
 	if (prop->type != 2) {
603 602
 		/* Not a file */
604
-		return TRUE;
603
+		return CL_SUCCESS;
605 604
 	}
606 605
 
607 606
 	if (prop->name_size > 64) {
608
-		cli_dbgmsg("\nERROR: property name too long: %d\n", prop->name_size);
609
-		return FALSE;
610
-	}
611
-
612
-	if (! (name = get_property_name(prop->name, prop->name_size))) {
613
-		/* File without a name - create a name for it */
614
-		off_t i;
615
-                                                                                                                            
616
-		i = lseek(fd, 0, SEEK_CUR);
617
-		name = (char *) cli_malloc(11);
618
-		if (!name) {
619
-			return FALSE;
620
-		}
621
-		snprintf(name, 11, "%.10ld", (long int) (i + (long int) prop));
622
-	} else {
623
-		/* Sanitize the file name */
624
-		sanitiseName(name);
625
-	}
626
-
627
-	newname = (char *) cli_malloc(strlen(name) + strlen(dir) + 2);
628
-	if (!newname) {
629
-		free(name);
630
-		return FALSE;
607
+		cli_dbgmsg("OLE2 [handler_writefile]: property name too long: %d\n", prop->name_size);
608
+		return CL_SUCCESS;
631 609
 	}
632 610
 
633
-	sprintf(newname, "%s/%s", dir, name);
634
-	free(name);
611
+	name = get_property_name2(prop->name, prop->name_size);
612
+	if (name) cnt = uniq_add(hdr->U, name, strlen(name), &hash);
613
+	else cnt = uniq_add(hdr->U, NULL, 0, &hash);
614
+	snprintf(newname, sizeof(newname), "%s/%u_%u", dir, hash, cnt);
615
+	newname[sizeof(newname)-1]='\0';
616
+	cli_dbgmsg("OLE2 [handler_writefile]: Dumping '%s' to '%s'\n", name ? name : "<empty>", newname);
617
+	if (name) free(name);
635 618
 
636 619
 	ofd = open(newname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
637 620
 	if (ofd < 0) {
638
-		cli_errmsg("ERROR: failed to create file: %s\n", newname);
639
-		free(newname);
640
-		return FALSE;
621
+		cli_errmsg("OLE2 [handler_writefile]: failed to create file: %s\n", newname);
622
+		return CL_SUCCESS;
641 623
 	}
642
-	free(newname);
643 624
 	current_block = prop->start_block;
644 625
 	len = prop->size;
645 626
 
646 627
 	buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
647 628
 	if (!buff) {
648 629
 		close(ofd);
649
-		return FALSE;
630
+		return CL_BREAK;
650 631
 	}
651 632
 	
652 633
 	blk_bitset = cli_bitset_init();
653 634
 	if (!blk_bitset) {
654
-		cli_errmsg("ERROR [handler_writefile]: init bitset failed\n");
635
+		cli_errmsg("OLE2 [handler_writefile]: init bitset failed\n");
655 636
 		close(ofd);
656
-		return FALSE;
637
+		return CL_BREAK;
657 638
 	}
658 639
 	while((current_block >= 0) && (len > 0)) {
659 640
 		if (current_block > (int32_t) hdr->max_block_no) {
660
-                        cli_dbgmsg("OLE2: Max block number for file size exceeded: %d\n", current_block);
641
+                        cli_dbgmsg("OLE2 [handler_writefile]: Max block number for file size exceeded: %d\n", current_block);
661 642
                         close(ofd);
662 643
                         free(buff);
663 644
                         cli_bitset_free(blk_bitset);
664
-                        return FALSE;
645
+                        return CL_SUCCESS;
665 646
                 }
666 647
 		/* Check we aren't in a loop */
667 648
 		if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) {
668 649
 			/* Loop in block list */
669
-			cli_dbgmsg("OLE2: Block list loop detected\n");
650
+			cli_dbgmsg("OLE2 [handler_writefile]: Block list loop detected\n");
670 651
 			close(ofd);
671 652
 			free(buff);
672 653
 			cli_bitset_free(blk_bitset);
673
-			return FALSE;
654
+			return CL_BREAK;
674 655
 		}
675 656
 		if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) {
676 657
 			close(ofd);
677 658
 			free(buff);
678 659
 			cli_bitset_free(blk_bitset);
679
-			return FALSE;
660
+			return CL_BREAK;
680 661
 		}			
681 662
 		if (prop->size < (int64_t)hdr->sbat_cutoff) {
682 663
 			/* Small block file */
683 664
 			if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) {
684
-				cli_dbgmsg("ole2_get_sbat_data_block failed\n");
665
+				cli_dbgmsg("OLE2 [handler_writefile]: ole2_get_sbat_data_block failed\n");
685 666
 				close(ofd);
686 667
 				free(buff);
687 668
 				cli_bitset_free(blk_bitset);
688
-				return FALSE;
669
+				return CL_SUCCESS;
689 670
 			}
690 671
 			/* buff now contains the block with 8 small blocks in it */
691 672
 			offset = 64 * (current_block % 8);
... ...
@@ -693,7 +703,7 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
693 693
 				close(ofd);
694 694
 				free(buff);
695 695
 				cli_bitset_free(blk_bitset);
696
-				return FALSE;
696
+				return CL_BREAK;
697 697
 			}
698 698
 
699 699
 			len -= MIN(len,64);
... ...
@@ -704,14 +714,14 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
704 704
 				close(ofd);
705 705
 				free(buff);
706 706
 				cli_bitset_free(blk_bitset);
707
-				return FALSE;
707
+				return CL_SUCCESS;
708 708
 			}
709 709
 			if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) !=
710 710
 							MIN(len,(1 << hdr->log2_big_block_size))) {
711 711
 				close(ofd);
712 712
 				free(buff);
713 713
 				cli_bitset_free(blk_bitset);
714
-				return FALSE;
714
+				return CL_BREAK;
715 715
 			}
716 716
 
717 717
 			current_block = ole2_get_next_block_number(fd, hdr, current_block);
... ...
@@ -721,7 +731,188 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
721 721
 	close(ofd);
722 722
 	free(buff);
723 723
 	cli_bitset_free(blk_bitset);
724
-	return TRUE;
724
+	return CL_SUCCESS;
725
+}
726
+
727
+/* enum file Handler - checks for VBA presence */
728
+static int handler_enum(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
729
+{
730
+  char *name;
731
+  
732
+  if (!hdr->has_vba) {
733
+    name = get_property_name2(prop->name, prop->name_size);
734
+    if (name) {
735
+      if (!strcmp(name, "_vba_project") || !strcmp(name, "powerpoint document") || !strcmp(name, "worddocument") || !strcmp(name, "_1_ole10native"))
736
+	hdr->has_vba = 1;
737
+      free(name);
738
+    }
739
+  }
740
+  return CL_SUCCESS;
741
+}
742
+
743
+
744
+static int handler_otf(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
745
+{
746
+  char *tempfile;
747
+  unsigned char *buff;
748
+  int32_t current_block, len, offset;
749
+  int ofd, ret;
750
+  bitset_t *blk_bitset;
751
+
752
+  if (prop->type != 2) {
753
+    /* Not a file */
754
+    return CL_SUCCESS;
755
+  }
756
+
757
+  print_ole2_property(prop);
758
+
759
+  if(!(tempfile = cli_gentemp(NULL)))
760
+    return CL_EMEM;
761
+
762
+  if((ofd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
763
+    cli_dbgmsg("OLE2: Can't create file %s\n", tempfile);
764
+    free(tempfile);
765
+    return CL_EIO;
766
+  }
767
+
768
+  current_block = prop->start_block;
769
+  len = prop->size;
770
+
771
+  buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
772
+  if (!buff) {
773
+    close(ofd);
774
+    cli_unlink(tempfile);
775
+    free(tempfile);
776
+    return CL_EMEM;
777
+  }
778
+
779
+  blk_bitset = cli_bitset_init();
780
+
781
+  if (!blk_bitset) {
782
+    cli_errmsg("OLE2: OTF handler init bitset failed\n");
783
+    free(buff);
784
+    close(ofd);
785
+    if (cli_unlink(tempfile)) {
786
+        free(tempfile);
787
+	return CL_EIO;
788
+    }
789
+    free(tempfile);
790
+    return CL_BREAK;
791
+  }
792
+  
793
+  while((current_block >= 0) && (len > 0)) {
794
+    if (current_block > (int32_t) hdr->max_block_no) {
795
+      cli_dbgmsg("OLE2: Max block number for file size exceeded: %d\n", current_block);
796
+      close(ofd);
797
+      free(buff);
798
+      cli_bitset_free(blk_bitset);
799
+      if (cli_unlink(tempfile)) {
800
+        free(tempfile);
801
+	return CL_EIO;
802
+      }
803
+      free(tempfile);
804
+      return CL_SUCCESS;
805
+    }
806
+    /* Check we aren't in a loop */
807
+    if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) {
808
+      /* Loop in block list */
809
+      cli_dbgmsg("OLE2: Block list loop detected\n");
810
+      close(ofd);
811
+      free(buff);
812
+      cli_bitset_free(blk_bitset);
813
+      if (cli_unlink(tempfile)) {
814
+        free(tempfile);
815
+	return CL_EIO;
816
+      }
817
+      free(tempfile);
818
+      return CL_BREAK;
819
+    }
820
+    if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) {
821
+      close(ofd);
822
+      free(buff);
823
+      cli_bitset_free(blk_bitset);
824
+      if (cli_unlink(tempfile)) {
825
+        free(tempfile);
826
+	return CL_EIO;
827
+      }
828
+      free(tempfile);
829
+      return CL_BREAK;
830
+    }			
831
+    if (prop->size < (int64_t)hdr->sbat_cutoff) {
832
+      /* Small block file */
833
+      if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) {
834
+	cli_dbgmsg("ole2_get_sbat_data_block failed\n");
835
+	close(ofd);
836
+	free(buff);
837
+	cli_bitset_free(blk_bitset);
838
+	if (cli_unlink(tempfile)) {
839
+	  free(tempfile);
840
+	  return CL_EIO;
841
+        }
842
+	free(tempfile);
843
+	return CL_SUCCESS;
844
+      }
845
+      /* buff now contains the block with 8 small blocks in it */
846
+      offset = 64 * (current_block % 8);
847
+      if (cli_writen(ofd, &buff[offset], MIN(len,64)) != MIN(len,64)) {
848
+	close(ofd);
849
+	free(buff);
850
+	cli_bitset_free(blk_bitset);
851
+	if (cli_unlink(tempfile)) {
852
+	  free(tempfile);
853
+	  return CL_EIO;
854
+        }
855
+	free(tempfile);
856
+	return CL_BREAK;
857
+      }
858
+
859
+      len -= MIN(len,64);
860
+      current_block = ole2_get_next_sbat_block(fd, hdr, current_block);
861
+    } else {
862
+      /* Big block file */
863
+      if (!ole2_read_block(fd, hdr, buff, current_block)) {
864
+	close(ofd);
865
+	free(buff);
866
+	cli_bitset_free(blk_bitset);
867
+	if (cli_unlink(tempfile)) {
868
+	  free(tempfile);
869
+	  return CL_EIO;
870
+        }
871
+	free(tempfile);
872
+	return CL_SUCCESS;
873
+      }
874
+      if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) !=
875
+	  MIN(len,(1 << hdr->log2_big_block_size))) {
876
+	close(ofd);
877
+	free(buff);
878
+	cli_bitset_free(blk_bitset);
879
+	if (cli_unlink(tempfile)) {
880
+	  free(tempfile);
881
+	  return CL_EIO;
882
+        }
883
+	free(tempfile);
884
+	return CL_BREAK;
885
+      }
886
+
887
+      current_block = ole2_get_next_block_number(fd, hdr, current_block);
888
+      len -= MIN(len,(1 << hdr->log2_big_block_size));
889
+    }
890
+  }
891
+
892
+  lseek(ofd, 0, SEEK_SET);
893
+  ret=cli_magic_scandesc(ofd, ctx);
894
+  close(ofd);
895
+  free(buff);
896
+  cli_bitset_free(blk_bitset);
897
+  if(!cli_leavetemps_flag) {
898
+    if (cli_unlink(tempfile)) {
899
+      free(tempfile);
900
+      return CL_EIO;
901
+    }
902
+  }
903
+  free(tempfile);
904
+  return ret==CL_VIRUS ? CL_VIRUS : CL_SUCCESS;
905
+
725 906
 }
726 907
 
727 908
 #if !defined(HAVE_ATTRIB_PACKED) && !defined(HAVE_PRAGMA_PACK) && !defined(HAVE_PRAGMA_PACK_HPPA)
... ...
@@ -786,13 +977,13 @@ static int ole2_read_header(int fd, ole2_header_t *hdr)
786 786
 }
787 787
 #endif
788 788
 
789
-int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
789
+int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx, struct uniq **vba)
790 790
 {
791 791
 	ole2_header_t hdr;
792
-	int hdr_size;
792
+	int hdr_size, ret=CL_CLEAN;
793 793
 	struct stat statbuf;
794 794
 	unsigned int file_count=0;
795
-	unsigned long scansize;
795
+	unsigned long scansize, scansize2;
796 796
 
797 797
 	cli_dbgmsg("in cli_ole2_extract()\n");
798 798
 
... ...
@@ -802,17 +993,19 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
802 802
 	  else
803 803
 	    return CL_EMAXSIZE;
804 804
 	} else scansize = -1;
805
+
806
+	scansize2 = scansize;
805 807
 	
806 808
 	/* size of header - size of other values in struct */
807
-	hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) -
809
+	hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) - sizeof(uint32_t) -
808 810
 			sizeof(unsigned char *) - sizeof(off_t) - sizeof(bitset_t *) -
809
-			sizeof(uint32_t);
811
+			sizeof(struct uniq *) - sizeof(int);
810 812
 
811 813
 	hdr.m_area = NULL;
812 814
 
813 815
 	if (fstat(fd, &statbuf) == 0) {
814 816
 		if (statbuf.st_size < hdr_size) {
815
-			return 0;
817
+			return CL_CLEAN;
816 818
 		}
817 819
 #ifdef HAVE_MMAP
818 820
 		hdr.m_length = statbuf.st_size;
... ...
@@ -827,13 +1020,14 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
827 827
 	}
828 828
 
829 829
 	if (hdr.m_area == NULL) {
830
+		hdr.bitset = NULL;
830 831
 #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
831 832
 		if (cli_readn(fd, &hdr, hdr_size) != hdr_size) {
832
-			return 0;
833
+			goto abort;
833 834
 		}
834 835
 #else
835 836
 		if (!ole2_read_header(fd, &hdr)) {
836
-			return 0;
837
+			goto abort;
837 838
 		}
838 839
 #endif
839 840
 	}
... ...
@@ -854,19 +1048,14 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
854 854
 	hdr.sbat_root_start = -1;
855 855
 
856 856
 	hdr.bitset = cli_bitset_init();
857
-	if (!hdr.bitset) {
857
+	if (!hdr.bitset) { /* FIXME: mmap leaks here */
858 858
 		return CL_EOLE2;
859 859
 	}
860 860
 
861 861
 	if (memcmp(hdr.magic, magic_id, 8) != 0) {
862 862
 		cli_dbgmsg("OLE2 magic failed!\n");
863
-#ifdef HAVE_MMAP
864
-		if (hdr.m_area != NULL) {
865
-			munmap(hdr.m_area, hdr.m_length);
866
-		}
867
-#endif
868
-		cli_bitset_free(hdr.bitset);
869
-		return CL_EOLE2;
863
+		ret=CL_EOLE2;
864
+		goto abort;
870 865
 	}
871 866
 
872 867
 	if (hdr.log2_big_block_size != 9) {
... ...
@@ -894,7 +1083,35 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
894 894
 	
895 895
 	/* OR */
896 896
 	
897
-	ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, ctx, &scansize);
897
+
898
+	/* PASS 1 : Count files and check for VBA */
899
+	//	__asm__ __volatile__("int3");
900
+	hdr.has_vba = 0;
901
+	ret = ole2_walk_property_tree(fd, &hdr, NULL, 0, handler_enum, 0, &file_count, ctx, &scansize);
902
+	cli_bitset_free(hdr.bitset);
903
+	hdr.bitset = NULL;
904
+	if (!file_count || !(hdr.bitset = cli_bitset_init()))
905
+	  goto abort;
906
+
907
+	/* If there's no VBA we scan OTF */
908
+	if (hdr.has_vba) {
909
+	  /* PASS 2/A : VBA scan */
910
+	  cli_dbgmsg("OLE2: VBA project found\n");
911
+	  if (!(hdr.U = uniq_init(file_count))) {
912
+	    cli_dbgmsg("OLE2: uniq_init() failed\n");
913
+	    ret = CL_EMEM;
914
+	    goto abort;
915
+	  }
916
+	  file_count = 0;
917
+	  ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, ctx, &scansize2);
918
+	  ret = CL_CLEAN;
919
+	  *vba = hdr.U;
920
+	} else {
921
+	  cli_dbgmsg("OLE2: no VBA projects found %d\n", ret);
922
+	  /* PASS 2/B : OTF scan */
923
+	  file_count = 0;
924
+	  ret = ole2_walk_property_tree(fd, &hdr, NULL, 0, handler_otf, 0, &file_count, ctx, &scansize2);
925
+	}
898 926
 
899 927
 abort:
900 928
 #ifdef HAVE_MMAP
... ...
@@ -902,6 +1119,8 @@ abort:
902 902
 		munmap(hdr.m_area, hdr.m_length);
903 903
 	}
904 904
 #endif
905
-	cli_bitset_free(hdr.bitset);
906
-	return 0;
905
+	if(hdr.bitset)
906
+	    cli_bitset_free(hdr.bitset);
907
+
908
+	return ret;
907 909
 }
... ...
@@ -24,7 +24,8 @@
24 24
 #define __OLE2_EXTRACT_H
25 25
 
26 26
 #include "others.h"
27
+#include "hashtab.h"
27 28
 
28
-int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx);
29
+int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx, struct uniq **);
29 30
 
30 31
 #endif
... ...
@@ -99,6 +99,7 @@ static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144,
99 99
 	int len = sizeof(x) - 1;			    \
100 100
 	char buff[BUFSIZ];				    \
101 101
     strncpy(buff, x, len);				    \
102
+    buff[BUFSIZ-1]='\0';				    \
102 103
     va_start(args, str);				    \
103 104
     vsnprintf(buff + len, sizeof(buff) - len, str, args);   \
104 105
     buff[sizeof(buff) - 1] = '\0';			    \
... ...
@@ -79,7 +79,7 @@ static	const	char	*cli_pmemstr(const char *haystack, size_t hs, const char *need
79 79
  * TODO: handle embedded URLs if (options&CL_SCAN_MAILURL)
80 80
  */
81 81
 int
82
-cli_pdf(const char *dir, int desc, cli_ctx *ctx)
82
+cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset)
83 83
 {
84 84
 	off_t size;	/* total number of bytes in the file */
85 85
 	off_t bytesleft, trailerlength;
... ...
@@ -99,12 +99,12 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx)
99 99
 		return CL_EOPEN;
100 100
 	}
101 101
 
102
-	size = statb.st_size;
102
+	size = statb.st_size - offset;
103 103
 
104 104
 	if(size <= 7)	/* doesn't even include the file header */
105 105
 		return CL_CLEAN;
106 106
 
107
-	p = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, 0);
107
+	p = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, offset);
108 108
 	if(buf == MAP_FAILED) {
109 109
 		cli_errmsg("cli_pdf: mmap() failed\n");
110 110
 		return CL_EMEM;
... ...
@@ -115,28 +115,24 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx)
115 115
 	/* Lines are terminated by \r, \n or both */
116 116
 
117 117
 	/* File Header */
118
-	if(memcmp(p, "%PDF-1.", 7) != 0) {
119
-		munmap(buf, size);
120
-		cli_dbgmsg("cli_pdf: file header not found\n");
121
-		return CL_CLEAN;
118
+	bytesleft = size - 5;
119
+	for(q = p; bytesleft; bytesleft--, q++) {
120
+	    if(!strncasecmp(q, "%PDF-", 5)) {
121
+		bytesleft = size - (off_t) (q - p);
122
+		p = q;
123
+		break;
124
+	    }
122 125
 	}
123 126
 
124
-#if	0
125
-	q = pdf_nextlinestart(&p[6], size - 6);
126
-	if(q == NULL) {
127
-		munmap(buf, size);
128
-		return CL_CLEAN;
127
+	if(!bytesleft) {
128
+	    munmap(buf, size);
129
+	    cli_dbgmsg("cli_pdf: file header not found\n");
130
+	    return CL_CLEAN;
129 131
 	}
130
-	bytesleft = size - (long)(q - p);
131
-	p = q;
132
-#else
133
-	p = &p[6];
134
-	bytesleft = size - 6;
135
-#endif
136 132
 
137 133
 	/* Find the file trailer */
138
-	for(q = &p[bytesleft - 6]; q > p; --q)
139
-		if(memcmp(q, "%%EOF", 5) == 0)
134
+	for(q = &p[bytesleft - 5]; q > p; --q)
135
+		if(strncasecmp(q, "%%EOF", 5) == 0)
140 136
 			break;
141 137
 
142 138
 	if(q <= p) {
... ...
@@ -868,7 +864,7 @@ cli_pmemstr(const char *haystack, size_t hs, const char *needle, size_t ns)
868 868
 #include "pdf.h"
869 869
 
870 870
 int
871
-cli_pdf(const char *dir, int desc, cli_ctx *ctx)
871
+cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset)
872 872
 {
873 873
 	cli_dbgmsg("File not decoded - PDF decoding needs mmap() (for now)\n");
874 874
 	return CL_CLEAN;
... ...
@@ -22,6 +22,6 @@
22 22
 
23 23
 #include "others.h"
24 24
 
25
-int cli_pdf(const char *dir, int desc, cli_ctx *ctx);
25
+int cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset);
26 26
 
27 27
 #endif
... ...
@@ -260,6 +260,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
260 260
 	}
261 261
 
262 262
 	strncpy(bm_new->virname, virname, virlen);
263
+	bm_new->virname[virlen]='\0';
263 264
 
264 265
 	if(offset) {
265 266
 	    bm_new->offset = cli_strdup(offset);
... ...
@@ -687,6 +688,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine **engine, unsigned int options
687 687
 	    if(!ftypes_int[line])
688 688
 		break;
689 689
 	    strncpy(buffer, ftypes_int[line], sizeof(buffer));
690
+	    buffer[sizeof(buffer)-1]='\0';
690 691
 	} else {
691 692
 	    if(!cli_dbgets(buffer, FILEBUFF, fs, dbio))
692 693
 		break;
... ...
@@ -137,14 +137,12 @@ static void init_rtf_state(struct rtf_state* state)
137 137
 
138 138
 static int compare_state(const struct rtf_state* a,const struct rtf_state* b)
139 139
 {
140
-	return (a->controlword_param == b->controlword_param && 
141
-			a->parse_state == b->parse_state &&
142
-			a->encounteredTopLevel == b->encounteredTopLevel &&
143
-			memcmp(a->controlword,b->controlword,33)==0 &&
144
-			a->cb_begin == b->cb_begin &&
145
-			a->cb_process == b->cb_process &&
146
-			a->cb_end == b->cb_end &&
147
-			a->cb_data == b->cb_data);
140
+	return (a->parse_state == b->parse_state &&
141
+		a->encounteredTopLevel == b->encounteredTopLevel &&
142
+		a->cb_begin == b->cb_begin &&
143
+		a->cb_process == b->cb_process &&
144
+		a->cb_end == b->cb_end &&
145
+		a->cb_data == b->cb_data);
148 146
 }
149 147
 
150 148
 
... ...
@@ -161,10 +159,12 @@ static int push_state(struct stack* stack,struct rtf_state* state)
161 161
 	}
162 162
 	if(stack->stack_cnt >= stack->stack_size) {
163 163
 		/* grow stack */
164
+		struct rtf_state *states;
164 165
 		stack->stack_size += 128;
165
-		stack->states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
166
-		if(!stack->states)
166
+		states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
167
+		if(!states)
167 168
 			return CL_EMEM;
169
+		stack->states = states;
168 170
 	}
169 171
 	stack->states[stack->stack_cnt++] = *state;
170 172
 	toplevel = state->encounteredTopLevel;
... ...
@@ -233,17 +233,12 @@ static int rtf_object_begin(struct rtf_state* state,cli_ctx* ctx,const char* tmp
233 233
 
234 234
 static int decode_and_scan(struct rtf_object_data* data, cli_ctx* ctx)
235 235
 {
236
-	int ofd, ret=0;
236
+	int ret=CL_CLEAN;
237 237
 
238 238
 	cli_dbgmsg("RTF:Scanning embedded object:%s\n",data->name);
239 239
 	if(data->bread == 1 && data->fd > 0) {
240 240
 		cli_dbgmsg("Decoding ole object\n");
241
-		lseek(data->fd,0,SEEK_SET);
242
-		ofd = cli_decode_ole_object(data->fd,data->tmpdir);
243
-		if (ofd >= 0) {
244
-			ret = cli_magic_scandesc(ofd, ctx);
245
-			close(ofd);
246
-		}
241
+		ret = cli_scan_ole10(data->fd, ctx);
247 242
 	}
248 243
 	else if(data->fd > 0)
249 244
 		ret = cli_magic_scandesc(data->fd,ctx);
... ...
@@ -483,6 +478,8 @@ static void rtf_action(struct rtf_state* state,long action)
483 483
 
484 484
 static void cleanup_stack(struct stack* stack,struct rtf_state* state,cli_ctx* ctx)
485 485
 {
486
+	if(!stack || !stack->states)
487
+		return;
486 488
 	while(stack && stack->stack_cnt /* && state->default_elements*/) {
487 489
 		pop_state(stack,state);
488 490
 		if(state->cb_data && state->cb_end)
... ...
@@ -722,9 +722,9 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
722 722
     return ret;
723 723
 }
724 724
 
725
-static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
725
+static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
726 726
 {
727
-	int ret = CL_CLEAN, i, fd, ofd, data_len;
727
+    int ret = CL_CLEAN, i, j, fd, ofd, data_len;
728 728
 	vba_project_t *vba_project;
729 729
 	DIR *dd;
730 730
 	struct dirent *dent;
... ...
@@ -735,84 +735,88 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
735 735
 	} result;
736 736
 #endif
737 737
 	struct stat statbuf;
738
-	char *fname, *fullname;
738
+	char *fullname, vbaname[1024];
739 739
 	unsigned char *data;
740
+	uint32_t hash, hashcnt;
740 741
 
741 742
 
742 743
     cli_dbgmsg("VBADir: %s\n", dirname);
743
-    if((vba_project = (vba_project_t *)cli_vba_readdir(dirname))) {
744
+    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
745
+    while(hashcnt--) {
746
+	if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
744 747
 
745 748
 	for(i = 0; i < vba_project->count; i++) {
746
-	    fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
747
-	    if(!fullname) {
748
-		ret = CL_EMEM;
749
-		break;
750
-	    }
751
-	    sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
752
-	    fd = open(fullname, O_RDONLY|O_BINARY);
753
-	    if(fd == -1) {
754
-		cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
755
-		free(fullname);
756
-		ret = CL_EOPEN;
757
-		break;
758
-	    }
759
-	    free(fullname);
760
-            cli_dbgmsg("VBADir: Decompress VBA project '%s'\n", vba_project->name[i]);
761
-	    data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
762
-	    close(fd);
763
-
764
-	    if(!data) {
765
-		cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
766
-	    } else {
767
-		if(ctx->scanned)
768
-		    *ctx->scanned += data_len / CL_COUNT_PRECISION;
749
+	    for(j = 0; j < vba_project->colls[i]; j++) {
750
+		snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
751
+		vbaname[sizeof(vbaname)-1] = '\0';
752
+		fd = open(vbaname, O_RDONLY|O_BINARY);
753
+		if(fd == -1) continue;
754
+		cli_dbgmsg("VBADir: Decompress VBA project '%u_%u'\n", vba_project->name[i], j);
755
+		data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
756
+		close(fd);
769 757
 
770
-		if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
758
+		if(!data) {
759
+		    cli_dbgmsg("VBADir: WARNING: VBA project '%u_%u' decompressed to NULL\n", vba_project->name[i], j);
760
+		} else {
761
+		    /* cli_dbgmsg("Project content:\n%s", data); */
762
+		    if(ctx->scanned)
763
+			*ctx->scanned += data_len / CL_COUNT_PRECISION;
764
+		    if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
765
+			free(data);
766
+			ret = CL_VIRUS;
767
+			break;
768
+		    }
771 769
 		    free(data);
772
-		    ret = CL_VIRUS;
773
-		    break;
774 770
 		}
775
-
776
-		free(data);
777 771
 	    }
778 772
 	}
779 773
 
780
-	for(i = 0; i < vba_project->count; i++)
781
-	    free(vba_project->name[i]);
782 774
 	free(vba_project->name);
775
+	free(vba_project->colls);
783 776
 	free(vba_project->dir);
784 777
 	free(vba_project->offset);
785 778
 	free(vba_project);
786
-    } else if ((fullname = cli_ppt_vba_read(dirname))) {
787
-    	if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) {
788
-	    ret = CL_VIRUS;
789
-	}
790
-	if(!cli_leavetemps_flag)
791
-	    cli_rmdirs(fullname);
792
-    	free(fullname);
793
-    } else if ((vba_project = (vba_project_t *)cli_wm_readdir(dirname))) {
794
-    	for (i = 0; i < vba_project->count; i++) {
795
-		fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
796
-		if(!fullname) {
797
-		    ret = CL_EMEM;
798
-		    break;
799
-		}
800
-		sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
801
-		fd = open(fullname, O_RDONLY|O_BINARY);
802
-		if(fd == -1) {
803
-			cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
804
-			free(fullname);
805
-			ret = CL_EOPEN;
806
-			break;
779
+	if (ret == CL_VIRUS) break;
780
+    }
781
+
782
+    if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
783
+	while(hashcnt--) {
784
+	    snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
785
+	    vbaname[sizeof(vbaname)-1] = '\0';
786
+	    fd = open(vbaname, O_RDONLY|O_BINARY);
787
+	    if (fd == -1) continue;
788
+	    if ((fullname = cli_ppt_vba_read(fd))) {
789
+		if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) {
790
+		    ret = CL_VIRUS;
807 791
 		}
792
+		if(!cli_leavetemps_flag)
793
+		    cli_rmdirs(fullname);
808 794
 		free(fullname);
809
-		cli_dbgmsg("VBADir: Decompress WM project '%s' macro:%d key:%d length:%d\n", vba_project->name[i], i, vba_project->key[i], vba_project->length[i]);
810
-		data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
795
+	    }
796
+	    close(fd);
797
+	}
798
+    }
799
+
800
+    if (ret == CL_CLEAN && (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
801
+	while(hashcnt--) {
802
+	    snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
803
+	    vbaname[sizeof(vbaname)-1] = '\0';
804
+	    fd = open(vbaname, O_RDONLY|O_BINARY);
805
+	    if (fd == -1) continue;
806
+	    
807
+	    if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
811 808
 		close(fd);
809
+		continue;
810
+	    }
811
+
812
+	    for (i = 0; i < vba_project->count; i++) {
813
+		cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
814
+		data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
812 815
 		
813 816
 		if(!data) {
814 817
 			cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
815 818
 		} else {
819
+			cli_dbgmsg("Project content:\n%s", data);
816 820
 			if(ctx->scanned)
817 821
 			    *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
818 822
 			if(cli_scanbuff(data, vba_project->length[i], ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
... ...
@@ -822,39 +826,43 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
822 822
 			}
823 823
 			free(data);
824 824
 		}
825
+	    }
826
+
827
+	    close(fd);
828
+	    free(vba_project->name);
829
+	    free(vba_project->colls);
830
+	    free(vba_project->dir);
831
+	    free(vba_project->offset);
832
+	    free(vba_project->key);
833
+	    free(vba_project->length);
834
+	    free(vba_project);
835
+	    if(ret == CL_VIRUS) break;
825 836
 	}
826
-	for(i = 0; i < vba_project->count; i++)
827
-	    free(vba_project->name[i]);
828
-	free(vba_project->key);
829
-	free(vba_project->length);
830
-	free(vba_project->offset);
831
-	free(vba_project->name);
832
-	free(vba_project->dir);
833
-	free(vba_project);
834 837
     }
835 838
 
836 839
     if(ret != CL_CLEAN)
837 840
     	return ret;
838 841
 
839 842
     /* Check directory for embedded OLE objects */
840
-    fullname = (char *) cli_malloc(strlen(dirname) + 16);
841
-    if(!fullname)
842
-	return CL_EMEM;
843
-
844
-    sprintf(fullname, "%s/_1_Ole10Native", dirname);
845
-    fd = open(fullname, O_RDONLY|O_BINARY);
846
-    free(fullname);
847
-    if (fd >= 0) {
848
-    	ofd = cli_decode_ole_object(fd, dirname);
849
-	if (ofd >= 0) {
850
-		ret = cli_scandesc(ofd, ctx, 0, 0, NULL, AC_SCAN_VIR);
851
-		close(ofd);
843
+    hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
844
+    while(hashcnt--) {
845
+	snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
846
+	vbaname[sizeof(vbaname)-1] = '\0';
847
+
848
+	fd = open(vbaname, O_RDONLY|O_BINARY);
849
+	if (fd >= 0) {
850
+	    ret = cli_scan_ole10(fd, ctx);
851
+	    close(fd);
852
+	    if(ret != CL_CLEAN)
853
+		return ret;
852 854
 	}
853
-	close(fd);
854
-	if(ret != CL_CLEAN)
855
-	    return ret;
856 855
     }
857 856
 
857
+
858
+    /* ACAB: since we now hash filenames and handle collisions we
859
+     * could avoid recursion by removing the block below and by
860
+     * flattening the paths in ole2_walk_property_tree (case 1) */
861
+
858 862
     if((dd = opendir(dirname)) != NULL) {
859 863
 #ifdef HAVE_READDIR_R_3
860 864
 	while(!readdir_r(dd, &result.d, &dent) && dent) {
... ...
@@ -869,23 +877,23 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
869 869
 	    {
870 870
 		if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
871 871
 		    /* build the full name */
872
-		    fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
873
-		    if(!fname) {
872
+		    fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
873
+		    if(!fullname) {
874 874
 			ret = CL_EMEM;
875 875
 			break;
876 876
 		    }
877
-		    sprintf(fname, "%s/%s", dirname, dent->d_name);
877
+		    sprintf(fullname, "%s/%s", dirname, dent->d_name);
878 878
 
879 879
 		    /* stat the file */
880
-		    if(lstat(fname, &statbuf) != -1) {
880
+		    if(lstat(fullname, &statbuf) != -1) {
881 881
 			if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
882
-			    if (cli_vba_scandir(fname, ctx) == CL_VIRUS) {
882
+			  if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
883 883
 			    	ret = CL_VIRUS;
884
-				free(fname);
884
+				free(fullname);
885 885
 				break;
886 886
 			    }
887 887
 		    }
888
-		    free(fname);
888
+		    free(fullname);
889 889
 		}
890 890
 	    }
891 891
 	}
... ...
@@ -1086,7 +1094,7 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
1086 1086
 {
1087 1087
 	char *dir;
1088 1088
 	int ret = CL_CLEAN;
1089
-
1089
+	struct uniq *vba = NULL;
1090 1090
 
1091 1091
     cli_dbgmsg("in cli_scanole2()\n");
1092 1092
 
... ...
@@ -1103,25 +1111,26 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
1103 1103
 	return CL_ETMPDIR;
1104 1104
     }
1105 1105
 
1106
-    if((ret = cli_ole2_extract(desc, dir, ctx))) {
1106
+    ret = cli_ole2_extract(desc, dir, ctx, &vba);
1107
+    if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
1107 1108
 	cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
1108 1109
 	if(!cli_leavetemps_flag)
1109 1110
 	    cli_rmdirs(dir);
1110 1111
 	free(dir);
1111
-	ctx->recursion--;
1112 1112
 	return ret;
1113 1113
     }
1114 1114
 
1115
-    ctx->recursion++;
1115
+    if (vba) {
1116
+        ctx->recursion++;
1116 1117
 
1117
-    if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
1118
-	if(cli_scandir(dir, ctx, 0) == CL_VIRUS) {
1119
-	    ret = CL_VIRUS;
1120
-	}
1118
+	ret = cli_vba_scandir(dir, ctx, vba);
1119
+	free(vba);
1120
+	if(ret != CL_VIRUS)
1121
+	    if(cli_scandir(dir, ctx, 0) == CL_VIRUS)
1122
+	        ret = CL_VIRUS;
1123
+	ctx->recursion--;
1121 1124
     }
1122 1125
 
1123
-    ctx->recursion--;
1124
-
1125 1126
     if(!cli_leavetemps_flag)
1126 1127
 	cli_rmdirs(dir);
1127 1128
     free(dir);
... ...
@@ -1380,7 +1389,7 @@ static int cli_scancryptff(int desc, cli_ctx *ctx)
1380 1380
     return ret;
1381 1381
 }
1382 1382
 
1383
-static int cli_scanpdf(int desc, cli_ctx *ctx)
1383
+static int cli_scanpdf(int desc, cli_ctx *ctx, off_t offset)
1384 1384
 {
1385 1385
 	int ret;
1386 1386
 	char *dir = cli_gentemp(NULL);
... ...
@@ -1394,7 +1403,7 @@ static int cli_scanpdf(int desc, cli_ctx *ctx)
1394 1394
 	return CL_ETMPDIR;
1395 1395
     }
1396 1396
 
1397
-    ret = cli_pdf(dir, desc, ctx);
1397
+    ret = cli_pdf(dir, desc, ctx, offset);
1398 1398
 
1399 1399
     if(!cli_leavetemps_flag)
1400 1400
 	cli_rmdirs(dir);
... ...
@@ -1717,6 +1726,13 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg,
1717 1717
 			}
1718 1718
 			break;
1719 1719
 
1720
+		    case CL_TYPE_PDF:
1721
+			if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
1722
+			    cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
1723
+			    nret = cli_scanpdf(desc, ctx, fpt->offset);
1724
+			}
1725
+			break;
1726
+
1720 1727
 		    case CL_TYPE_MSEXE:
1721 1728
 			if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
1722 1729
 			    cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
... ...
@@ -1969,7 +1985,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
1969 1969
 
1970 1970
         case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
1971 1971
 	    if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
1972
-		ret = cli_scanpdf(desc, ctx);
1972
+		ret = cli_scanpdf(desc, ctx, 0);
1973 1973
 	    break;
1974 1974
 
1975 1975
 	case CL_TYPE_CRYPTFF:
... ...
@@ -2105,3 +2121,9 @@ int cl_scanfile(const char *filename, const char **virname, unsigned long int *s
2105 2105
 
2106 2106
     return ret;
2107 2107
 }
2108
+
2109
+/*
2110
+Local Variables:
2111
+   c-basic-offset: 4
2112
+End:
2113
+*/
... ...
@@ -37,6 +37,7 @@
37 37
 #include "clamav.h"
38 38
 
39 39
 #include "others.h"
40
+#include "scanners.h"
40 41
 #include "vba_extract.h"
41 42
 #ifdef	CL_DEBUG
42 43
 #include "mbox.h"
... ...
@@ -71,29 +72,11 @@ typedef struct {
71 71
 	int	big_endian;	/* e.g. MAC Office */
72 72
 } vba_version_t;
73 73
 
74
-static const vba_version_t vba_versions[] = {
75
-	{ 0x0100005e, "97",             FALSE },
76
-	{ 0x0100005f, "97 SR1",         FALSE },
77
-	{ 0x01000065, "2000 alpha",	FALSE },
78
-	{ 0x0100006b, "2000 beta",	FALSE },
79
-	{ 0x0100006d, "2000",           FALSE },
80
-	{ 0x0100006f, "2000",           FALSE },
81
-	{ 0x01000070, "XP beta 1/2",	FALSE },
82
-	{ 0x01000073, "XP",             FALSE },
83
-	{ 0x01000073, "2003",           FALSE },
84
-	{ 0x01000079, "2003",           FALSE },
85
-	{ 0x0e000060, "98",		TRUE  },
86
-	{ 0x0e000062, "2001",		TRUE  },
87
-	{ 0x0e000063, "X",		TRUE  },
88
-	{ 0x0e000064, "2004",		TRUE  },
89
-	{ 0x00000000, NULL,		FALSE },
90
-};
91
-
92 74
 static	int	skip_past_nul(int fd);
93 75
 static	int	read_uint16(int fd, uint16_t *u, int big_endian);
94 76
 static	int	read_uint32(int fd, uint32_t *u, int big_endian);
95 77
 static	int	seekandread(int fd, off_t offset, int whence, void *data, size_t len);
96
-static	vba_project_t	*create_vba_project(int record_count, const char *dir);
78
+static	vba_project_t	*create_vba_project(int record_count, const char *dir, struct uniq *U);
97 79
 
98 80
 static uint16_t
99 81
 vba_endian_convert_16(uint16_t value, int big_endian)
... ...
@@ -114,6 +97,7 @@ vba_endian_convert_32(uint32_t value, int big_endian)
114 114
 		return le32_to_host(value);
115 115
 }
116 116
 
117
+
117 118
 static char *
118 119
 get_unicode_name(const char *name, int size, int big_endian)
119 120
 {
... ...
@@ -136,9 +120,9 @@ get_unicode_name(const char *name, int size, int big_endian)
136 136
 	ret = newname;
137 137
 
138 138
 	for(i = 0; i < size; i += increment) {
139
-		if(isprint(name[i]))
140
-			*ret++ = name[i];
141
-		else {
139
+		if((!(name[i]&0x80)) && isprint(name[i])) {
140
+		        *ret++ = tolower(name[i]);
141
+		} else {
142 142
 			if((name[i] < 10) && (name[i] >= 0)) {
143 143
 				*ret++ = '_';
144 144
 				*ret++ = (char)(name[i] + '0');
... ...
@@ -195,17 +179,16 @@ vba_read_project_strings(int fd, int big_endian)
195 195
 {
196 196
 	unsigned char *buf = NULL;
197 197
 	uint16_t buflen = 0;
198
+	int ret = 0;
198 199
 
199 200
 	for(;;) {
200 201
 		off_t offset;
201 202
 		uint16_t length;
202 203
 		char *name;
203 204
 
204
-		if(!read_uint16(fd, &length, big_endian)) {
205
-			if(buf)
206
-				free(buf);
207
-			return FALSE;
208
-		}
205
+		if(!read_uint16(fd, &length, big_endian))
206
+			break;
207
+
209 208
 		if (length < 6) {
210 209
 			lseek(fd, -2, SEEK_CUR);
211 210
 			break;
... ...
@@ -215,7 +198,7 @@ vba_read_project_strings(int fd, int big_endian)
215 215
 			if(newbuf == NULL) {
216 216
 				if(buf)
217 217
 					free(buf);
218
-				return FALSE;
218
+				return 0;
219 219
 			}
220 220
 			buflen = length;
221 221
 			buf = newbuf;
... ...
@@ -232,7 +215,7 @@ vba_read_project_strings(int fd, int big_endian)
232 232
 		cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]");
233 233
 
234 234
 		if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
235
-		   (strchr("GCHD", name[2]) == NULL)) {
235
+		   (strchr("ghcd", name[2]) == NULL)) {
236 236
 			/* Not a string */
237 237
 			lseek(fd, -(length+2), SEEK_CUR);
238 238
 			if(name)
... ...
@@ -244,9 +227,11 @@ vba_read_project_strings(int fd, int big_endian)
244 244
 		if(!read_uint16(fd, &length, big_endian)) {
245 245
 			if(buf)
246 246
 				free(buf);
247
-			return FALSE;
247
+			break;
248 248
 		}
249 249
 
250
+		ret++;
251
+
250 252
 		if ((length != 0) && (length != 65535)) {
251 253
 			lseek(fd, -2, SEEK_CUR);
252 254
 			continue;
... ...
@@ -257,21 +242,22 @@ vba_read_project_strings(int fd, int big_endian)
257 257
 	}
258 258
 	if(buf)
259 259
 		free(buf);
260
-	return TRUE;
260
+	return ret;
261 261
 }
262 262
 
263 263
 vba_project_t *
264
-cli_vba_readdir(const char *dir)
264
+cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
265 265
 {
266 266
 	unsigned char *buf;
267 267
 	const unsigned char vba56_signature[] = { 0xcc, 0x61 };
268 268
 	uint16_t record_count, buflen, ffff, byte_count;
269
-	uint32_t offset, sig;
270
-	int i, fd, big_endian;
269
+	uint32_t offset, sig, hash, colls;
270
+	int i, j, fd, big_endian = FALSE;
271 271
 	vba_project_t *vba_project;
272 272
 	const vba_version_t *v;
273 273
 	struct vba56_header v56h;
274
-	char fullname[NAME_MAX + 1];
274
+	off_t seekback;
275
+	char fullname[1024];
275 276
 
276 277
 	cli_dbgmsg("in cli_vba_readdir()\n");
277 278
 
... ...
@@ -281,13 +267,15 @@ cli_vba_readdir(const char *dir)
281 281
 	/*
282 282
 	 * _VBA_PROJECT files are embedded within office documents (OLE2)
283 283
 	 */
284
-	snprintf(fullname, sizeof(fullname) - 1, "%s/_VBA_PROJECT", dir);
284
+	
285
+	if (!uniq_get(U, "_vba_project", 12, &hash))
286
+		return NULL;
287
+	snprintf(fullname, sizeof(fullname), "%s/%u_%u", dir, hash, which);
288
+	fullname[sizeof(fullname)-1] = '\0';
285 289
 	fd = open(fullname, O_RDONLY|O_BINARY);
286 290
 
287
-	if(fd == -1) {
288
-		cli_dbgmsg("Can't open %s\n", fullname);
291
+	if(fd == -1)
289 292
 		return NULL;
290
-	}
291 293
 
292 294
 	if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
293 295
 		close(fd);
... ...
@@ -298,38 +286,23 @@ cli_vba_readdir(const char *dir)
298 298
 		return NULL;
299 299
 	}
300 300
 
301
-	sig = cli_readint32(v56h.version);
302
-	for(v = vba_versions; v->sig; v++)
303
-		if(v->sig == sig)
304
-			break;
305
-
306
-	if(!v->sig) {
307
-		cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
308
-			v56h.version[0], v56h.version[1],
309
-			v56h.version[2], v56h.version[3]);
310
-		switch(v56h.version[3]) {
311
-			case 0x01:
312
-				cli_warnmsg("Guessing little-endian\n");
313
-				big_endian = FALSE;
314
-				break;
315
-			case 0x0E:
316
-				cli_warnmsg("Guessing big-endian\n");
317
-				big_endian = TRUE;
318
-				break;
319
-			default:
320
-				cli_warnmsg("Unable to guess VBA type\n");
321
-				close(fd);
322
-				return NULL;
323
-		}
324
-	} else {
325
-		cli_dbgmsg("VBA Project: %s %s\n", v->big_endian ? "MacOffice" : "Office",  v->ver);
326
-		big_endian = v->big_endian;
327
-	}
328
-
329
-	if (!vba_read_project_strings(fd, big_endian)) {
301
+	i = vba_read_project_strings(fd, TRUE);
302
+	seekback = lseek(fd, 0, SEEK_CUR);
303
+	if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1)
304
+		return NULL;
305
+	j = vba_read_project_strings(fd, FALSE);
306
+	if(!i && !j) {
330 307
 		close(fd);
308
+		cli_warnmsg("vba_readdir: Unable to guess VBA type\n");
331 309
 		return NULL;
332 310
 	}
311
+	if (i > j) {
312
+		big_endian = TRUE;
313
+		lseek(fd, seekback, SEEK_SET);
314
+		cli_dbgmsg("vba_readdir: Guessing big-endian\n");
315
+	} else {
316
+		cli_dbgmsg("vba_readdir: Guessing little-endian\n");
317
+	}
333 318
 
334 319
 	/* junk some more stuff */
335 320
 	do
... ...
@@ -369,7 +342,7 @@ cli_vba_readdir(const char *dir)
369 369
 		close(fd);
370 370
 		return NULL;
371 371
 	}
372
-	cli_dbgmsg("VBA Record count: %d\n", record_count);
372
+	cli_dbgmsg("vba_readdir: VBA Record count %d\n", record_count);
373 373
 	if (record_count == 0) {
374 374
 		/* No macros, assume clean */
375 375
 		close(fd);
... ...
@@ -377,12 +350,12 @@ cli_vba_readdir(const char *dir)
377 377
 	}
378 378
 	if (record_count > MAX_VBA_COUNT) {
379 379
 		/* Almost certainly an error */
380
-		cli_dbgmsg("VBA Record count too big\n");
380
+		cli_dbgmsg("vba_readdir: VBA Record count too big\n");
381 381
 		close(fd);
382 382
 		return NULL;
383 383
 	}
384 384
 
385
-	vba_project = create_vba_project(record_count, dir);
385
+	vba_project = create_vba_project(record_count, dir, U);
386 386
 	if(vba_project == NULL) {
387 387
 		close(fd);
388 388
 		return NULL;
... ...
@@ -393,11 +366,12 @@ cli_vba_readdir(const char *dir)
393 393
 		uint16_t length;
394 394
 		char *ptr;
395 395
 
396
+		vba_project->colls[i] = 0;
396 397
 		if(!read_uint16(fd, &length, big_endian))
397 398
 			break;
398 399
 
399 400
 		if (length == 0) {
400
-			cli_dbgmsg("zero name length\n");
401
+			cli_dbgmsg("vba_readdir: zero name length\n");
401 402
 			break;
402 403
 		}
403 404
 		if(length > buflen) {
... ...
@@ -408,51 +382,39 @@ cli_vba_readdir(const char *dir)
408 408
 			buf = newbuf;
409 409
 		}
410 410
 		if (cli_readn(fd, buf, length) != length) {
411
-			cli_dbgmsg("read name failed\n");
411
+			cli_dbgmsg("vba_readdir: read name failed\n");
412 412
 			break;
413 413
 		}
414 414
 		ptr = get_unicode_name((const char *)buf, length, big_endian);
415
-		if(ptr == NULL) {
416
-			offset = lseek(fd, 0, SEEK_CUR);
417
-			ptr = (char *)cli_malloc(18);
418
-			if(ptr == NULL)
419
-				break;
420
-			sprintf(ptr, "clamav-%.10d", (int)offset);
421
-		}
422
-		cli_dbgmsg("project name: %s\n", ptr);
423
-
424
-		if(!read_uint16(fd, &length, big_endian)) {
425
-			free(ptr);
415
+		if(ptr == NULL) break;
416
+		if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
417
+			cli_dbgmsg("vba_readdir: cannot find project %s (%u)\n", ptr, hash);
426 418
 			break;
427 419
 		}
420
+		cli_dbgmsg("vba_readdir: project name: %s (%u)\n", ptr, hash);
421
+		free(ptr);
422
+		vba_project->name[i] = hash;
423
+		if(!read_uint16(fd, &length, big_endian))
424
+			break;
428 425
 		lseek(fd, length, SEEK_CUR);
429 426
 
430
-		if(!read_uint16(fd, &ffff, big_endian)) {
431
-			free(ptr);
427
+		if(!read_uint16(fd, &ffff, big_endian))
432 428
 			break;
433
-		}
434 429
 		if (ffff == 0xFFFF) {
435 430
 			lseek(fd, 2, SEEK_CUR);
436
-			if(!read_uint16(fd, &ffff, big_endian)) {
437
-				free(ptr);
431
+			if(!read_uint16(fd, &ffff, big_endian))
438 432
 				break;
439
-			}
440 433
 			lseek(fd, ffff + 8, SEEK_CUR);
441 434
 		} else
442 435
 			lseek(fd, ffff + 10, SEEK_CUR);
443 436
 
444
-		if(!read_uint16(fd, &byte_count, big_endian)) {
445
-			free(ptr);
437
+		if(!read_uint16(fd, &byte_count, big_endian))
446 438
 			break;
447
-		}
448 439
 		lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
449
-		if(!read_uint32(fd, &offset, big_endian)) {
450
-			free(ptr);
440
+		if(!read_uint32(fd, &offset, big_endian))
451 441
 			break;
452
-		}
453
-		cli_dbgmsg("offset: %u\n", (unsigned int)offset);
442
+		cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset);
454 443
 		vba_project->offset[i] = offset;
455
-		vba_project->name[i] = ptr;
456 444
 		lseek(fd, 2, SEEK_CUR);
457 445
 	}
458 446
 
... ...
@@ -462,10 +424,8 @@ cli_vba_readdir(const char *dir)
462 462
 	close(fd);
463 463
 
464 464
 	if(i < record_count) {
465
-		while(--i >= 0)
466
-			free(vba_project->name[i]);
467
-
468 465
 		free(vba_project->name);
466
+		free(vba_project->colls);
469 467
 		free(vba_project->dir);
470 468
 		free(vba_project->offset);
471 469
 		free(vba_project);
... ...
@@ -585,66 +545,68 @@ ole_copy_file_data(int s, int d, uint32_t len)
585 585
 }
586 586
 
587 587
 int
588
-cli_decode_ole_object(int fd, const char *dir)
588
+cli_scan_ole10(int fd, cli_ctx *ctx)
589 589
 {
590
-	int ofd;
590
+	int ofd, ret;
591 591
 	uint32_t object_size;
592 592
 	struct stat statbuf;
593 593
 	char *fullname;
594 594
 
595
-	if(dir == NULL)
596
-		return -1;
597
-
598 595
 	if(fd < 0)
599
-		return -1;
596
+		return CL_CLEAN;
600 597
 
598
+	lseek(fd, 0, SEEK_SET);
601 599
 	if(!read_uint32(fd, &object_size, FALSE))
602
-		return -1;
600
+		return CL_CLEAN;
603 601
 
604 602
 	if(fstat(fd, &statbuf) == -1)
605
-		return -1;
603
+		return CL_EIO;
606 604
 
607 605
 	if ((statbuf.st_size - object_size) >= 4) {
608 606
 		/* Probably the OLE type id */
609 607
 		if (lseek(fd, 2, SEEK_CUR) == -1) {
610
-			return -1;
608
+			return CL_CLEAN;
611 609
 		}
612 610
 
613 611
 		/* Attachment name */
614 612
 		if(!skip_past_nul(fd))
615
-			return -1;
613
+			return CL_CLEAN;
616 614
 
617 615
 		/* Attachment full path */
618 616
 		if(!skip_past_nul(fd))
619
-			return -1;
617
+			return CL_CLEAN;
620 618
 
621 619
 		/* ??? */
622 620
 		if(lseek(fd, 8, SEEK_CUR) == -1)
623
-			return -1;
621
+			return CL_CLEAN;
624 622
 
625 623
 		/* Attachment full path */
626 624
 		if(!skip_past_nul(fd))
627
-			return -1;
625
+			return CL_CLEAN;
628 626
 
629 627
 		if(!read_uint32(fd, &object_size, FALSE))
630
-			return -1;
628
+			return CL_CLEAN;
631 629
 	}
632
-	if(!(fullname = cli_gentemp(dir))) {
633
-		return -1;
630
+	if(!(fullname = cli_gentemp(NULL))) {
631
+		return CL_EMEM;
634 632
 	}
635 633
 	ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
636 634
 		S_IWUSR|S_IRUSR);
637 635
 	if (ofd < 0) {
638 636
 		cli_warnmsg("cli_decode_ole_object: can't create %s\n",	fullname);
639 637
 		free(fullname);
640
-		return -1;
641
-	} else {
642
-		cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
638
+		return CL_EIO;
643 639
 	}
644
-	free(fullname);
640
+	cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
645 641
 	ole_copy_file_data(fd, ofd, object_size);
646 642
 	lseek(ofd, 0, SEEK_SET);
647
-	return ofd;
643
+	ret = cli_magic_scandesc(ofd, ctx);
644
+	close(ofd);
645
+	if(!cli_leavetemps_flag)
646
+	  if (cli_unlink(fullname))
647
+	    ret = CL_EIO;
648
+	free(fullname);
649
+	return ret;
648 650
 }
649 651
 
650 652
 /*
... ...
@@ -797,23 +759,10 @@ ppt_stream_iter(int fd, const char *dir)
797 797
 }
798 798
 
799 799
 char *
800
-cli_ppt_vba_read(const char *filename)
800
+cli_ppt_vba_read(int ifd)
801 801
 {
802 802
 	char *dir;
803 803
 	const char *ret;
804
-	int fd;
805
-	char fullname[NAME_MAX + 1];
806
-
807
-	if(filename == NULL)
808
-		return NULL;
809
-
810
-	snprintf(fullname, sizeof(fullname) - 1, "%s/PowerPoint Document",
811
-		filename);
812
-	fd = open(fullname, O_RDONLY|O_BINARY);
813
-	if (fd == -1) {
814
-		cli_dbgmsg("Open PowerPoint Document failed\n");
815
-		return NULL;
816
-	}
817 804
 
818 805
 	/* Create a directory to store the extracted OLE2 objects */
819 806
 	dir = cli_gentemp(NULL);
... ...
@@ -824,8 +773,7 @@ cli_ppt_vba_read(const char *filename)
824 824
 		free(dir);
825 825
 		return NULL;
826 826
 	}
827
-	ret = ppt_stream_iter(fd, dir);
828
-	close(fd);
827
+	ret = ppt_stream_iter(ifd, dir);
829 828
 	if(ret == NULL) {
830 829
 		cli_rmdirs(dir);
831 830
 		free(dir);
... ...
@@ -1083,43 +1031,32 @@ word_skip_macro_intnames(int fd)
1083 1083
 }
1084 1084
 
1085 1085
 vba_project_t *
1086
-cli_wm_readdir(const char *dir)
1086
+cli_wm_readdir(int fd)
1087 1087
 {
1088
-	int fd, done;
1088
+	int done;
1089 1089
 	off_t end_offset;
1090 1090
 	unsigned char info_id;
1091 1091
 	macro_info_t macro_info;
1092 1092
 	vba_project_t *vba_project;
1093 1093
 	mso_fib_t fib;
1094
-	char fullname[NAME_MAX + 1];
1094
+	uint32_t hash, hashcnt;
1095
+	char fullname[1024];
1095 1096
 
1096
-	if(dir == NULL)
1097
-		return NULL;
1098 1097
 
1099
-	snprintf(fullname, sizeof(fullname) - 1, "%s/WordDocument", dir);
1100
-	fd = open(fullname, O_RDONLY|O_BINARY);
1101
-	if (fd == -1) {
1102
-		cli_dbgmsg("Open WordDocument failed\n");
1098
+	if (!word_read_fib(fd, &fib))
1103 1099
 		return NULL;
1104
-	}
1105 1100
 
1106
-	if (!word_read_fib(fd, &fib)) {
1107
-		close(fd);
1108
-		return NULL;
1109
-	}
1110 1101
 	if(fib.macro_len == 0) {
1111
-		cli_dbgmsg("No macros detected\n");
1102
+		cli_dbgmsg("wm_readdir: No macros detected\n");
1112 1103
 		/* Must be clean */
1113
-		close(fd);
1114 1104
 		return NULL;
1115 1105
 	}
1116
-	cli_dbgmsg("macro offset: 0x%.4x\n", (int)fib.macro_offset);
1117
-	cli_dbgmsg("macro len: 0x%.4x\n\n", (int)fib.macro_len);
1106
+	cli_dbgmsg("wm_readdir: macro offset: 0x%.4x\n", (int)fib.macro_offset);
1107
+	cli_dbgmsg("wm_readdir: macro len: 0x%.4x\n\n", (int)fib.macro_len);
1118 1108
 
1119 1109
 	/* Go one past the start to ignore start_id */
1120 1110
 	if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
1121
-		cli_dbgmsg("lseek macro_offset failed\n");
1122
-		close(fd);
1111
+		cli_dbgmsg("wm_readdir: lseek macro_offset failed\n");
1123 1112
 		return NULL;
1124 1113
 	}
1125 1114
 
... ...
@@ -1129,7 +1066,7 @@ cli_wm_readdir(const char *dir)
1129 1129
 
1130 1130
 	while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
1131 1131
 		if (cli_readn(fd, &info_id, 1) != 1) {
1132
-			cli_dbgmsg("read macro_info failed\n");
1132
+			cli_dbgmsg("wm_readdir: read macro_info failed\n");
1133 1133
 			break;
1134 1134
 		}
1135 1135
 		switch (info_id) {
... ...
@@ -1160,17 +1097,16 @@ cli_wm_readdir(const char *dir)
1160 1160
 				done = TRUE;
1161 1161
 				break;
1162 1162
 			default:
1163
-				cli_dbgmsg("unknown type: 0x%x\n", info_id);
1163
+				cli_dbgmsg("wm_readdir: unknown type: 0x%x\n", info_id);
1164 1164
 				done = TRUE;
1165 1165
 		}
1166 1166
 	}
1167 1167
 
1168
-	close(fd);
1169 1168
 
1170 1169
 	if(macro_info.count == 0)
1171 1170
 		return NULL;
1172 1171
 
1173
-	vba_project = create_vba_project(macro_info.count, dir);
1172
+	vba_project = create_vba_project(macro_info.count, "", NULL);
1174 1173
 
1175 1174
 	if(vba_project) {
1176 1175
 		vba_project->length = (uint32_t *)cli_malloc(sizeof(uint32_t) *
... ...
@@ -1183,7 +1119,6 @@ cli_wm_readdir(const char *dir)
1183 1183
 			const macro_entry_t *m = macro_info.entries;
1184 1184
 
1185 1185
 			for(i = 0; i < macro_info.count; i++) {
1186
-				vba_project->name[i] = cli_strdup("WordDocument");
1187 1186
 				vba_project->offset[i] = m->offset;
1188 1187
 				vba_project->length[i] = m->len;
1189 1188
 				vba_project->key[i] = m->key;
... ...
@@ -1191,6 +1126,7 @@ cli_wm_readdir(const char *dir)
1191 1191
 			}
1192 1192
 		} else {
1193 1193
 			free(vba_project->name);
1194
+			free(vba_project->colls);
1194 1195
 			free(vba_project->dir);
1195 1196
 			free(vba_project->offset);
1196 1197
 			if(vba_project->length)
... ...
@@ -1295,7 +1231,7 @@ seekandread(int fd, off_t offset, int whence, void *data, size_t len)
1295 1295
  * Create and initialise a vba_project structure
1296 1296
  */
1297 1297
 static vba_project_t *
1298
-create_vba_project(int record_count, const char *dir)
1298
+create_vba_project(int record_count, const char *dir, struct uniq *U)
1299 1299
 {
1300 1300
 	vba_project_t *ret;
1301 1301
 
... ...
@@ -1304,13 +1240,16 @@ create_vba_project(int record_count, const char *dir)
1304 1304
 	if(ret == NULL)
1305 1305
 		return NULL;
1306 1306
 
1307
-	ret->name = (char **)cli_malloc(sizeof(char *) * record_count);
1307
+	ret->name = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
1308
+	ret->colls = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
1308 1309
 	ret->dir = cli_strdup(dir);
1309 1310
 	ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
1310 1311
 
1311 1312
 	if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
1312 1313
 		if(ret->dir)
1313 1314
 			free(ret->dir);
1315
+		if(ret->colls)
1316
+			free(ret->colls);
1314 1317
 		if(ret->name)
1315 1318
 			free(ret->name);
1316 1319
 		if(ret->offset)
... ...
@@ -1319,6 +1258,7 @@ create_vba_project(int record_count, const char *dir)
1319 1319
 		return NULL;
1320 1320
 	}
1321 1321
 	ret->count = record_count;
1322
+	ret->U = U;
1322 1323
 
1323 1324
 	return ret;
1324 1325
 }
... ...
@@ -23,22 +23,26 @@
23 23
 #ifndef __VBA_EXTRACT_H
24 24
 #define __VBA_EXTRACT_H
25 25
 
26
+#include "others.h"
26 27
 #include "cltypes.h"
28
+#include "hashtab.h"
27 29
 
28 30
 typedef struct vba_project_tag {
29
-	char **name;
31
+	uint32_t *name;
32
+	uint32_t *colls;
30 33
 	uint32_t *offset;
31 34
 	uint32_t *length;	/* for Word 6 macros */
32 35
 	unsigned char *key;	/* for Word 6 macros */
33 36
 	char *dir;
37
+	struct uniq *U;
34 38
 	int count;
35 39
 } vba_project_t;
36 40
 
37
-vba_project_t	*cli_vba_readdir(const char *dir);
41
+vba_project_t	*cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which);
42
+vba_project_t	*cli_wm_readdir(int fd);
38 43
 unsigned char	*cli_vba_inflate(int fd, off_t offset, int *size);
39
-int	cli_decode_ole_object(int fd, const char *dir);
40
-char	*cli_ppt_vba_read(const char *filename);
41
-vba_project_t	*cli_wm_readdir(const char *dir);
44
+int	cli_scan_ole10(int fd, cli_ctx *ctx);
45
+char	*cli_ppt_vba_read(int fd);
42 46
 unsigned char	*cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len,
43 47
 					unsigned char key);
44 48
 
... ...
@@ -293,6 +293,7 @@ struct cfgstruct *getcfg(const char *cfgfile, int verbose)
293 293
 				if(ctype == 'm' || ctype == 'k') {
294 294
 				    char *cpy = (char *) calloc(strlen(arg), 1);
295 295
 				    strncpy(cpy, arg, strlen(arg) - 1);
296
+				    cpy[strlen(arg)-1]='\0';
296 297
 				    if(!cli_isnumber(cpy)) {
297 298
 					if(verbose)
298 299
 					    fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
... ...
@@ -72,6 +72,7 @@ int tar_addfile(int fd, gzFile *gzs, const char *file)
72 72
 
73 73
     memset(&hdr, 0, TARBLK);
74 74
     strncpy(hdr.name, file, 100);
75
+    hdr.name[99]='\0';
75 76
     snprintf(hdr.size, 12, "%o", (unsigned int) sb.st_size);
76 77
     pt = (unsigned char *) &hdr;
77 78
     for(i = 0; i < TARBLK; i++)
... ...
@@ -258,6 +258,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
258 258
 
259 259
     if((pt = getenv("SIGNDPASS"))) {
260 260
 	strncpy(pass, pt, sizeof(pass));
261
+	pass[sizeof(pass)-1]='\0';
261 262
     } else {
262 263
 	mprintf("Password: ");
263 264
 
... ...
@@ -281,12 +282,13 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
281 281
 	    return NULL;
282 282
 	}
283 283
 	strncpy(pass, pt, sizeof(pass));
284
+	pass[sizeof(pass)-1]='\0';
284 285
 	free(pt);
285 286
 
286 287
 #ifdef HAVE_TERMIOS_H
287 288
 	if(tcsetattr(0, TCSAFLUSH, &old)) {
288 289
 	    mprintf("!getdsig: tcsetattr() failed\n");
289
-	    memset(pass, 0, strlen(pass));
290
+	    memset(pass, 0, sizeof(pass));
290 291
 	    return NULL;
291 292
 	}
292 293
 #endif
... ...
@@ -300,7 +302,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
300 300
 #endif
301 301
 	perror("socket()");
302 302
 	mprintf("!getdsig: Can't create socket\n");
303
-	memset(pass, 0, strlen(pass));
303
+	memset(pass, 0, sizeof(pass));
304 304
 	return NULL;
305 305
     }
306 306
 
... ...
@@ -312,7 +314,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
312 312
         close(sockd);
313 313
 	perror("connect()");
314 314
 	mprintf("!getdsig: Can't connect to ClamAV Signing Service at %s\n", host);
315
-	memset(pass, 0, strlen(pass));
315
+	memset(pass, 0, sizeof(pass));
316 316
 	return NULL;
317 317
     }
318 318
     memset(cmd, 0, sizeof(cmd));
... ...
@@ -330,13 +332,13 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
330 330
     if(write(sockd, cmd, len) < 0) {
331 331
 	mprintf("!getdsig: Can't write to socket\n");
332 332
 	close(sockd);
333
-	memset(cmd, 0, len);
334
-	memset(pass, 0, strlen(pass));
333
+	memset(cmd, 0, sizeof(cmd));
334
+	memset(pass, 0, sizeof(pass));
335 335
 	return NULL;
336 336
     }
337 337
 
338
-    memset(cmd, 0, len);
339
-    memset(pass, 0, strlen(pass));
338
+    memset(cmd, 0, sizeof(cmd));
339
+    memset(pass, 0, sizeof(pass));
340 340
     memset(buff, 0, sizeof(buff));
341 341
 
342 342
     if((bread = cli_readn(sockd, buff, sizeof(buff))) > 0) {
... ...
@@ -587,6 +589,7 @@ static int build(struct optstruct *opt)
587 587
     if(opt->filename) {
588 588
 	if(cli_strbcasestr(opt->filename, ".cvd") || cli_strbcasestr(opt->filename, ".cld")) {
589 589
 	    strncpy(olddb, opt->filename, sizeof(olddb));
590
+	    olddb[sizeof(olddb)-1]='\0';
590 591
 	} else {
591 592
 	    mprintf("!build: Not a CVD/CLD file\n");
592 593
 	    return -1;
... ...
@@ -655,6 +658,7 @@ static int build(struct optstruct *opt)
655 655
 
656 656
     if((pt = getenv("SIGNDUSER"))) {
657 657
 	strncpy(builder, pt, sizeof(builder));
658
+	builder[sizeof(builder)-1]='\0';
658 659
     } else {
659 660
 	mprintf("Builder name: ");
660 661
 	if(scanf("%as", &pt) == EOF) {
... ...
@@ -662,6 +666,7 @@ static int build(struct optstruct *opt)
662 662
 	    return -1;
663 663
 	}
664 664
 	strncpy(builder, pt, sizeof(builder));
665
+	builder[sizeof(builder)-1]='\0';
665 666
 	free(pt);
666 667
     }
667 668
 
... ...
@@ -816,6 +821,7 @@ static int build(struct optstruct *opt)
816 816
 	return -1;
817 817
     }
818 818
     strncpy(olddb, pt, sizeof(olddb));
819
+    olddb[sizeof(olddb)-1]='\0';
819 820
     free(pt);
820 821
 
821 822
     if(!(pt = cli_gentemp(NULL))) {
... ...
@@ -896,6 +902,7 @@ static int unpack(struct optstruct *opt)
896 896
 
897 897
     } else {
898 898
 	strncpy(name, opt_arg(opt, "unpack"), sizeof(name));
899
+	name[sizeof(name)-1]='\0';
899 900
     }
900 901
 
901 902
     if(cvd_unpack(name, ".") == -1) {
... ...
@@ -1171,6 +1178,7 @@ static int vbadump(struct optstruct *opt)
1171 1171
 	int fd, hex_output;
1172 1172
 	char *dir;
1173 1173
 	const char *pt;
1174
+	struct uniq *vba;
1174 1175
 
1175 1176
 
1176 1177
     if(opt_check(opt, "vba-hex")) {
... ...
@@ -1200,15 +1208,15 @@ static int vbadump(struct optstruct *opt)
1200 1200
         return -1;
1201 1201
     }
1202 1202
 
1203
-    if(cli_ole2_extract(fd, dir, NULL)) {
1203
+    if(cli_ole2_extract(fd, dir, NULL, &vba)) {
1204 1204
 	cli_rmdirs(dir);
1205 1205
         free(dir);
1206 1206
 	close(fd);
1207 1207
         return -1;
1208 1208
     }
1209
-
1210 1209
     close(fd);
1211
-    sigtool_vba_scandir(dir, hex_output);
1210
+    if (vba) 
1211
+      sigtool_vba_scandir(dir, hex_output, vba);
1212 1212
     cli_rmdirs(dir);
1213 1213
     free(dir);
1214 1214
     return 0;
... ...
@@ -1305,6 +1313,7 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
1305 1305
 
1306 1306
 		    if(found) {
1307 1307
 			strncpy(tbuff, obuff, sizeof(tbuff));
1308
+			tbuff[sizeof(tbuff)-1]='\0';
1308 1309
 			for(i = 0; i < tline; i++) {
1309 1310
 			    tbuff[16] = 0;
1310 1311
 			    if((pt = strchr(tbuff, ' ')))
... ...
@@ -33,6 +33,10 @@
33 33
 #include "libclamav/cltypes.h"
34 34
 #include "libclamav/ole2_extract.h"
35 35
 
36
+#ifndef	O_BINARY
37
+#define	O_BINARY	0
38
+#endif
39
+
36 40
 typedef struct mac_token_tag
37 41
 {
38 42
     unsigned char token;
... ...
@@ -46,7 +50,7 @@ typedef struct mac_token2_tag
46 46
 
47 47
 } mac_token2_t;
48 48
 
49
-int sigtool_vba_scandir(const char *dirname, int hex_output);
49
+int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
50 50
 
51 51
 static char *get_unicode_name (char *name, int size)
52 52
 {
... ...
@@ -979,6 +983,7 @@ static int sigtool_scandir (const char *dirname, int hex_output)
979 979
 			    }
980 980
 			} else {
981 981
 			    if (S_ISREG (statbuf.st_mode)) {
982
+			        struct uniq *vba;
982 983
 				tmpdir = getenv ("TMPDIR");
983 984
 
984 985
 				if (tmpdir == NULL)
... ...
@@ -1000,14 +1005,14 @@ static int sigtool_scandir (const char *dirname, int hex_output)
1000 1000
 				    return 1;
1001 1001
 				}
1002 1002
 
1003
-				if ((ret = cli_ole2_extract (desc, dir, NULL))) {
1003
+				if ((ret = cli_ole2_extract (desc, dir, NULL, &vba))) {
1004 1004
 				    printf ("ERROR %s\n", cl_strerror (ret));
1005 1005
 				    cli_rmdirs (dir);
1006 1006
 				    free (dir);
1007 1007
 				    return ret;
1008 1008
 				}
1009 1009
 
1010
-				sigtool_vba_scandir (dir, hex_output);
1010
+				sigtool_vba_scandir (dir, hex_output, vba);
1011 1011
 
1012 1012
 				cli_rmdirs (dir);
1013 1013
 				free (dir);
... ...
@@ -1028,94 +1033,93 @@ static int sigtool_scandir (const char *dirname, int hex_output)
1028 1028
     return 0;
1029 1029
 }
1030 1030
 
1031
-int sigtool_vba_scandir (const char *dirname, int hex_output)
1031
+int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U)
1032 1032
 {
1033
-    int ret = CL_CLEAN, i, fd, data_len;
1033
+    int ret = CL_CLEAN, i, j, fd, data_len;
1034 1034
     vba_project_t *vba_project;
1035 1035
     DIR *dd;
1036 1036
     struct dirent *dent;
1037 1037
     struct stat statbuf;
1038
-    char *fname, *fullname;
1038
+    char *fullname, vbaname[1024];
1039 1039
     unsigned char *data;
1040
+    uint32_t hashcnt, hash;
1040 1041
 
1041
-    cli_dbgmsg ("VBA scan dir: %s\n", dirname);
1042
-    if ((vba_project = (vba_project_t *)cli_vba_readdir(dirname))) {
1043
-
1044
-	for (i = 0; i < vba_project->count; i++) {
1045
-	    fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2);
1046
-	    sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
1047
-	    fd = open (fullname, O_RDONLY);
1048
-	    if (fd == -1) {
1049
-		cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname);
1050
-		free (fullname);
1051
-		ret = CL_EOPEN;
1052
-		break;
1053
-	    }
1054
-	    free (fullname);
1055
-	    cli_dbgmsg ("decompress VBA project '%s'\n", vba_project->name[i]);
1056
-	    printf ("-------------- start of %s ------------------\n", vba_project->name[i]);
1057
-	    data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
1058
-	    close (fd);
1042
+    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
1043
+    while(hashcnt--) {
1044
+	if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
1059 1045
 
1060
-	    if (!data) {
1061
-		cli_dbgmsg ("WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
1062
-	    } else {
1063
-		data = (unsigned char *) realloc (data, data_len + 1);
1064
-		data[data_len] = '\0';
1065
-		printf ("%s", data);
1066
-		free (data);
1046
+	for(i = 0; i < vba_project->count; i++) {
1047
+	    for(j = 0; j < vba_project->colls[i]; j++) {
1048
+		snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
1049
+		vbaname[sizeof(vbaname)-1] = '\0';
1050
+		fd = open(vbaname, O_RDONLY|O_BINARY);
1051
+		if(fd == -1) continue;
1052
+		data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
1053
+		close(fd);
1067 1054
 
1055
+		if(data) {
1056
+		    data = (unsigned char *) realloc (data, data_len + 1);
1057
+		    data[data_len]='\0';
1058
+		    printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
1059
+		    free(data);
1060
+		}
1068 1061
 	    }
1069
-	    printf ("-------------- end of %s ------------------\n", vba_project->name[i]);
1070 1062
 	}
1071 1063
 
1072
-	for (i = 0; i < vba_project->count; i++)
1073
-	    free (vba_project->name[i]);
1074
-	free (vba_project->name);
1075
-	free (vba_project->dir);
1076
-	free (vba_project->offset);
1077
-	free (vba_project);
1078
-    } else if ((fullname = cli_ppt_vba_read(dirname))) {
1079
-	if (sigtool_scandir (fullname, hex_output) == CL_VIRUS) {
1080
-	    ret = CL_VIRUS;
1064
+	free(vba_project->name);
1065
+	free(vba_project->colls);
1066
+	free(vba_project->dir);
1067
+	free(vba_project->offset);
1068
+	free(vba_project);
1069
+    }
1070
+
1071
+
1072
+    if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
1073
+	while(hashcnt--) {
1074
+	    snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
1075
+	    vbaname[sizeof(vbaname)-1] = '\0';
1076
+	    fd = open(vbaname, O_RDONLY|O_BINARY);
1077
+	    if (fd == -1) continue;
1078
+	    if ((fullname = cli_ppt_vba_read(fd)))
1079
+	      sigtool_scandir(fullname, hex_output);
1080
+	    cli_rmdirs(fullname);
1081
+	    free(fullname);
1082
+	    close(fd);
1081 1083
 	}
1082
-	cli_rmdirs (fullname);
1083
-	free (fullname);
1084
-    } else if ((vba_project = (vba_project_t *)cli_wm_readdir(dirname))) {
1085
-	for (i = 0; i < vba_project->count; i++) {
1086
-	    fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2);
1087
-	    sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
1088
-	    fd = open (fullname, O_RDONLY);
1089
-	    if (fd == -1) {
1090
-		cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname);
1091
-		free (fullname);
1092
-		ret = CL_EOPEN;
1093
-		break;
1084
+    }
1085
+
1086
+
1087
+    if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
1088
+	while(hashcnt--) {
1089
+	    snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
1090
+	    vbaname[sizeof(vbaname)-1] = '\0';
1091
+	    fd = open(vbaname, O_RDONLY|O_BINARY);
1092
+	    if (fd == -1) continue;
1093
+	    
1094
+	    if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
1095
+		close(fd);
1096
+		continue;
1094 1097
 	    }
1095
-	    free (fullname);
1096
-	    cli_dbgmsg ("decompress WM project '%s' macro %d\n", vba_project->name[i], i);
1097
-	    printf ("\n\n-------------- start of macro:%d key:%d length:%d ------------------\n", i,
1098
-		    vba_project->key[i], vba_project->length[i]);
1099
-	    data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i],
1100
-						    vba_project->key[i]);
1101
-	    close (fd);
1102 1098
 
1103
-	    if (!data) {
1104
-		cli_dbgmsg ("WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
1105
-	    } else {
1106
-		wm_decode_macro (data, vba_project->length[i], hex_output);
1107
-		free (data);
1099
+	    for (i = 0; i < vba_project->count; i++) {
1100
+		data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
1101
+		if(data) {
1102
+		    data = (unsigned char *) realloc (data, data_len + 1);
1103
+		    data[data_len]='\0';
1104
+		    printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
1105
+		    free(data);
1106
+		}
1108 1107
 	    }
1109
-	    printf ("\n-------------- end of macro %d ------------------\n\n", i);
1108
+
1109
+	    close(fd);
1110
+	    free(vba_project->name);
1111
+	    free(vba_project->colls);
1112
+	    free(vba_project->dir);
1113
+	    free(vba_project->offset);
1114
+	    free(vba_project->key);
1115
+	    free(vba_project->length);
1116
+	    free(vba_project);
1110 1117
 	}
1111
-	for (i = 0; i < vba_project->count; i++)
1112
-	    free (vba_project->name[i]);
1113
-	free (vba_project->key);
1114
-	free (vba_project->length);
1115
-	free (vba_project->offset);
1116
-	free (vba_project->name);
1117
-	free (vba_project->dir);
1118
-	free (vba_project);
1119 1118
     }
1120 1119
 
1121 1120
     if ((dd = opendir (dirname)) != NULL) {
... ...
@@ -1123,15 +1127,15 @@ int sigtool_vba_scandir (const char *dirname, int hex_output)
1123 1123
 	    if (dent->d_ino) {
1124 1124
 		if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) {
1125 1125
 		    /* build the full name */
1126
-		    fname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char));
1127
-		    sprintf (fname, "%s/%s", dirname, dent->d_name);
1126
+		    fullname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char));
1127
+		    sprintf (fullname, "%s/%s", dirname, dent->d_name);
1128 1128
 
1129 1129
 		    /* stat the file */
1130
-		    if (lstat (fname, &statbuf) != -1) {
1130
+		    if (lstat (fullname, &statbuf) != -1) {
1131 1131
 			if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode))
1132
-			    sigtool_vba_scandir (fname, hex_output);
1132
+			    sigtool_vba_scandir (fullname, hex_output, U); 
1133 1133
 		    }
1134
-		    free (fname);
1134
+		    free (fullname);
1135 1135
 		}
1136 1136
 	    }
1137 1137
 	}
... ...
@@ -20,6 +20,7 @@
20 20
 #ifndef __VBA_H
21 21
 #define __VBA_H
22 22
 
23
-int sigtool_vba_scandir(const char *dirname, int hex_output);
23
+#include "libclamav/hashtab.h"
24
+int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
24 25
 
25 26
 #endif