fileblob * textToFileblob(text *t, fileblob *fb, int destroy) { assert(fb != NULL); assert(t != NULL); if(fb == NULL) { cli_dbgmsg("textToFileBlob, destroy = %d\n", destroy); fb = fileblobCreate(); if(fb == NULL) return NULL; } else { cli_dbgmsg("textToFileBlob to %s, destroy = %d\n", fileblobGetFilename(fb), destroy); fb->ctx = NULL; /* no need to scan */ } fb = textIterate(t, addToFileblob, fb, destroy); if(destroy && t->t_next) { textDestroy(t->t_next); t->t_next = NULL; } return fb; }
int cli_tnef(const char *dir, cli_ctx *ctx) { uint32_t i32; uint16_t i16; fileblob *fb; int ret, alldone; off_t fsize, pos = 0; STATBUF statb; fsize = ctx->fmap[0]->len; if(fsize < (off_t) MIN_SIZE) { cli_dbgmsg("cli_tngs: file too small, ignoring\n"); return CL_CLEAN; } if (fmap_readn(*ctx->fmap, &i32, pos, sizeof(uint32_t)) != sizeof(uint32_t)) { /* The file is at least MIN_SIZE bytes, so it "can't" fail */ return CL_EREAD; } pos += sizeof(uint32_t); if(host32(i32) != TNEF_SIGNATURE) { return CL_EFORMAT; } if(fmap_readn(*ctx->fmap, &i16, pos, sizeof(uint16_t)) != sizeof(uint16_t)) { /* The file is at least MIN_SIZE bytes, so it "can't" fail */ return CL_EREAD; } pos += sizeof(uint16_t); fb = NULL; ret = CL_CLEAN; /* we don't know if it's clean or not :-) */ alldone = 0; do { uint8_t part = 0; uint16_t type = 0, tag = 0; int32_t length = 0; switch(tnef_header(*ctx->fmap, &pos, &part, &type, &tag, &length)) { case 0: alldone = 1; break; case 1: break; default: /* * Assume truncation, not file I/O error */ cli_warnmsg("cli_tnef: file truncated, returning CLEAN\n"); ret = CL_CLEAN; alldone = 1; break; } if(length == 0) continue; if(length < 0) { cli_warnmsg("Corrupt TNEF header detected - length %d\n", (int)length); ret = CL_EFORMAT; break; } if(alldone) break; switch(part) { case LVL_MESSAGE: cli_dbgmsg("TNEF - found message\n"); if(fb != NULL) { fileblobDestroy(fb); fb = NULL; } fb = fileblobCreate(); if(tnef_message(*ctx->fmap, &pos, type, tag, length, fsize) != 0) { cli_dbgmsg("TNEF: Error reading TNEF message\n"); ret = CL_EFORMAT; alldone = 1; } break; case LVL_ATTACHMENT: cli_dbgmsg("TNEF - found attachment\n"); if(tnef_attachment(*ctx->fmap, &pos, type, tag, length, dir, &fb, fsize) != 0) { cli_dbgmsg("TNEF: Error reading TNEF attachment\n"); ret = CL_EFORMAT; alldone = 1; } break; case 0: break; default: cli_warnmsg("TNEF - unknown level %d tag 0x%x\n", (int)part, (int)tag); /* * Dump the file incase it was part of an * email that's about to be deleted */ if(cli_debug_flag) { int fout = -1; char *filename = cli_gentemp(ctx->engine->tmpdir); char buffer[BUFSIZ]; if(filename) fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600); if(fout >= 0) { int count; cli_warnmsg("Saving dump to %s: refer to http://www.clamav.net/bugs\n", filename); pos = 0; while ((count = fmap_readn(*ctx->fmap, buffer, pos, sizeof(buffer))) > 0) { pos += count; cli_writen(fout, buffer, count); } close(fout); } free(filename); } ret = CL_EFORMAT; alldone = 1; break; } } while(!alldone); if(fb) { cli_dbgmsg("cli_tnef: flushing final data\n"); if(fileblobGetFilename(fb) == NULL) { cli_dbgmsg("Saving TNEF portion with an unknown name\n"); fileblobSetFilename(fb, dir, "tnef"); } fileblobDestroy(fb); fb = NULL; } cli_dbgmsg("cli_tnef: returning %d\n", ret); return ret; }
int cli_binhex(const char *dir, int desc) { #ifndef HAVE_MMAP cli_warnmsg("File not decoded - binhex decoding needs mmap() (for now)\n"); return CL_CLEAN; #else struct stat statb; char *buf, *start, *line; size_t size; long bytesleft; message *m; fileblob *fb; if(fstat(desc, &statb) < 0) return CL_EOPEN; size = (size_t)statb.st_size; if(size == 0) return CL_CLEAN; m = messageCreate(); if(m == NULL) return CL_EMEM; start = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, 0); if(buf == MAP_FAILED) { messageDestroy(m); return CL_EMEM; } cli_dbgmsg("mmap'ed binhex file\n"); bytesleft = (long)size; line = NULL; while(bytesleft > 0) { int length = 0; char *ptr, *newline; /*printf("%d: ", bytesleft);*/ for(ptr = buf; bytesleft && (*ptr != '\n') && (*ptr != '\r'); ptr++) { length++; --bytesleft; } /*printf("%d: ", length);*/ newline = cli_realloc(line, (size_t)(length + 1)); if(newline == NULL) break; line = newline; memcpy(line, buf, length); line[length] = '\0'; /*puts(line);*/ if(messageAddStr(m, line) < 0) break; if((bytesleft > 0) && (*ptr == '\r')) { ptr++; bytesleft--; } buf = ++ptr; bytesleft--; } munmap(start, size); if(line) free(line); if(binhexBegin(m) == NULL) { messageDestroy(m); cli_errmsg("No binhex line found\n"); return CL_EFORMAT; } /* similar to binhexMessage */ messageSetEncoding(m, "x-binhex"); fb = messageToFileblob(m, dir, 1); if(fb) { cli_dbgmsg("Binhex file decoded to %s\n", fileblobGetFilename(fb)); fileblobDestroy(fb); } else cli_errmsg("Couldn't decode binhex file to %s\n", dir); messageDestroy(m); if(fb) return CL_CLEAN; /* a lie - but it gets things going */ return CL_EIO; /* probably CL_EMEM, but we can't tell at this layer */ #endif }