git-svn: trunk@3862
Tomasz Kojm authored on 2008/05/28 01:30:47... | ... |
@@ -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); |
... | ... |
@@ -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(®, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1; |
163 | 166 |
cli_regfree(®); |
... | ... |
@@ -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 |
} |
... | ... |
@@ -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; |
... | ... |
@@ -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 |
} |
... | ... |
@@ -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; |
... | ... |
@@ -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 |
} |