/* * Save the uuencoded part of the file as it is read in since there's no need * to include it in the parse tree. Saves memory and parse time. * Return < 0 for failure */ int uudecodeFile(message *m, const char *firstline, const char *dir, fmap_t *map, size_t *at) { fileblob *fb; char buffer[RFC2821LENGTH + 1]; char *filename = cli_strtok(firstline, 2, " "); if(filename == NULL) return -1; fb = fileblobCreate(); if(fb == NULL) { free(filename); return -1; } fileblobSetFilename(fb, dir, filename); cli_dbgmsg("uudecode %s\n", filename); free(filename); while(fmap_gets(map, buffer, at, sizeof(buffer) - 1)) { unsigned char data[1024]; const unsigned char *uptr; size_t len; cli_chomp(buffer); if(strcasecmp(buffer, "end") == 0) break; if(buffer[0] == '\0') break; uptr = decodeLine(m, UUENCODE, buffer, data, sizeof(data)); if(uptr == NULL) break; len = (size_t)(uptr - data); if((len > 62) || (len == 0)) break; if(fileblobAddData(fb, data, len) < 0) break; } fileblobDestroy(fb); return 1; }
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; }
static int tnef_attachment(fmap_t *map, off_t *pos, uint16_t type, uint16_t tag, int32_t length, const char *dir, fileblob **fbref, off_t fsize) { uint32_t todo; uint16_t i16; off_t offset; char *string; cli_dbgmsg("attachment tag 0x%x, type 0x%x, length %d\n", tag, type, (int)length); offset = *pos; switch(tag) { case attATTACHTITLE: if(length <= 0) return -1; string = cli_malloc(length + 1); if(string == NULL) { cli_errmsg("tnef_attachment: Unable to allocate memory for string\n"); return -1; } if(fmap_readn(map, string, *pos, (uint32_t)length) != (uint32_t)length) { free(string); return -1; } (*pos) += (uint32_t)length; string[length] = '\0'; cli_dbgmsg("TNEF filename %s\n", string); if(*fbref == NULL) { *fbref = fileblobCreate(); if(*fbref == NULL) { free(string); return -1; } } fileblobSetFilename(*fbref, dir, string); free(string); break; case attATTACHDATA: if(*fbref == NULL) { *fbref = fileblobCreate(); if(*fbref == NULL) return -1; } todo = length; while(todo) { unsigned char buf[BUFSIZ]; int32_t got = fmap_readn(map, buf, *pos, MIN(sizeof(buf), todo)); if (got <= 0) break; (*pos) += got; fileblobAddData(*fbref, buf, got); todo -= got; } break; default: cli_dbgmsg("TNEF - unsupported attachment tag 0x%x type 0x%d length %d\n", tag, type, (int)length); break; } /*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/ if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) { cli_dbgmsg("TNEF: Incorrect length field in tnef_attachment\n"); return -1; } (*pos) = (long)(offset + length); /* shouldn't be needed */ (*pos) += 2; return 0; }