diff --git a/clamav-devel/ChangeLog b/clamav-devel/ChangeLog index 38cd66ea0..e5f6094d4 100644 --- a/clamav-devel/ChangeLog +++ b/clamav-devel/ChangeLog @@ -1,3 +1,8 @@ +Mon Dec 4 01:04:30 CET 2006 (tk) +--------------------------------- + * libclamav: commit experimental code from Edvin for extracting embedded + objects from RTF files + Sat Dec 2 17:46:31 GMT 2006 (njh) ---------------------------------- * libclamav/pst.c: Fix compilation errors diff --git a/clamav-devel/libclamav/Makefile.am b/clamav-devel/libclamav/Makefile.am index 6dcf955a8..4effc84a3 100644 --- a/clamav-devel/libclamav/Makefile.am +++ b/clamav-devel/libclamav/Makefile.am @@ -52,6 +52,8 @@ libclamav_la_SOURCES = \ scanners.h \ filetypes.c \ filetypes.h \ + rtf.c \ + rtf.h \ blob.c \ blob.h \ mbox.c \ diff --git a/clamav-devel/libclamav/Makefile.in b/clamav-devel/libclamav/Makefile.in index 4084a09f5..1ec3210a8 100644 --- a/clamav-devel/libclamav/Makefile.in +++ b/clamav-devel/libclamav/Makefile.in @@ -79,7 +79,7 @@ LTLIBRARIES = $(lib_LTLIBRARIES) libclamav_la_DEPENDENCIES = am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher-ncore.lo \ matcher.lo md5.lo others.lo readdb.lo cvd.lo dsig.lo str.lo \ - scanners.lo filetypes.lo blob.lo mbox.lo message.lo \ + scanners.lo filetypes.lo rtf.lo blob.lo mbox.lo message.lo \ snprintf.lo table.lo text.lo ole2_extract.lo vba_extract.lo \ msexpand.lo pe.lo cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo \ upx.lo htmlnorm.lo chmunpack.lo rebuildpe.lo petite.lo \ @@ -253,6 +253,8 @@ libclamav_la_SOURCES = \ scanners.h \ filetypes.c \ filetypes.h \ + rtf.c \ + rtf.h \ blob.c \ blob.h \ mbox.c \ @@ -466,6 +468,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rebuildpe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex_list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rtf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scanners.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha256.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sis.Plo@am__quote@ diff --git a/clamav-devel/libclamav/filetypes.c b/clamav-devel/libclamav/filetypes.c index 1e4ebdced..25463d299 100644 --- a/clamav-devel/libclamav/filetypes.c +++ b/clamav-devel/libclamav/filetypes.c @@ -123,6 +123,9 @@ static const struct cli_magic_s cli_magic[] = { {0, "\%PDF-", 5, "PDF document", CL_TYPE_PDF}, {0, "\266\271\254\256\376\377\377\377", 8, "CryptFF", CL_TYPE_CRYPTFF}, +#ifdef CL_EXPERIMENTAL + {0, "{\\rtf", 5, "RTF", CL_TYPE_RTF}, +#endif /* Ignored types */ {0, "\000\000\001\263", 4, "MPEG video stream", CL_TYPE_DATA}, diff --git a/clamav-devel/libclamav/filetypes.h b/clamav-devel/libclamav/filetypes.h index 0bac5ed18..4eb3abc76 100644 --- a/clamav-devel/libclamav/filetypes.h +++ b/clamav-devel/libclamav/filetypes.h @@ -54,7 +54,9 @@ typedef enum { CL_TYPE_UUENCODED, CL_TYPE_PST, /* Microsoft Outlook binary email folder (.pst file) */ CL_TYPE_HTML_UTF16, - +#ifdef CL_EXPERIMENTAL + CL_TYPE_RTF, +#endif /* bigger numbers have higher priority (in o-t-f detection) */ CL_TYPE_HTML, /* on the fly */ CL_TYPE_MAIL, /* magic + on the fly */ diff --git a/clamav-devel/libclamav/rtf.c b/clamav-devel/libclamav/rtf.c new file mode 100644 index 000000000..9f2e734a6 --- /dev/null +++ b/clamav-devel/libclamav/rtf.c @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2006 Török Edwin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#if HAVE_CONFIG_H +#include "clamav-config.h" +#endif + +#ifdef CL_EXPERIMENTAL + +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "others.h" +#include "rtf.h" +#include "clamav.h" +#include "table.h" +#include "scanners.h" +#include "vba_extract.h" + +enum parse_state { PARSE_MAIN, PARSE_CONTROL_, PARSE_CONTROL_WORD, PARSE_CONTROL_SYMBOL, PARSE_CONTROL_WORD_PARAM, PARSE_INTERPRET_CONTROLWORD }; + +enum rtf_action +{ + RTF_OBJECT, + RTF_OBJECT_DATA +}; + +struct rtf_state; +typedef int (*rtf_callback_begin)(struct rtf_state*, cli_ctx* ctx,const char* tmpdir); +typedef int (*rtf_callback_process)(struct rtf_state*, const unsigned char* data,const size_t len); +typedef int (*rtf_callback_end)(struct rtf_state*, cli_ctx*); + +struct rtf_state { + size_t default_elements; + size_t controlword_cnt; + ssize_t controlword_param; + enum parse_state parse_state; + int controlword_param_sign; + int encounteredTopLevel;/* encountered top-level control words that we care about */ + char controlword[33]; + rtf_callback_begin cb_begin;/* must be non-null if you want cb_process, and cb_end to be called, also it must change cb_data to non-null */ + rtf_callback_process cb_process; + rtf_callback_end cb_end; + void* cb_data;/* data set up by cb_begin, used by cb_process, and cleaned up by cb_end. typically state data */ +}; + +static const struct rtf_state base_state = { + 0,0,0,PARSE_MAIN,0,0," ",NULL,NULL,NULL,NULL +}; + +struct stack { + struct rtf_state* states; + size_t elements; + size_t stack_cnt; + size_t stack_size; +}; + +static const struct rtf_action_mapping { + const char* controlword; + const enum rtf_action action; +} rtf_action_mapping [] = +{ + {"object", RTF_OBJECT}, + {"objdata ",RTF_OBJECT_DATA} +}; + +static const size_t rtf_action_mapping_cnt = sizeof(rtf_action_mapping)/sizeof(rtf_action_mapping[0]); + +enum rtf_objdata_state {WAIT_MAGIC, WAIT_DESC_LEN, WAIT_DESC, WAIT_ZERO, WAIT_DATA_SIZE, DUMP_DATA, DUMP_DISCARD}; +static const unsigned char rtf_data_magic[] = {0x01, 0x05, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};/* is this a magic number, or does it mean something */ +static const size_t rtf_data_magic_len = sizeof(rtf_data_magic); + +struct rtf_object_data { + char* name; + int fd; + int partial; + int has_partial; + enum rtf_objdata_state internal_state; + char* desc_name; + const char* tmpdir; + cli_ctx* ctx; + size_t desc_len; + size_t bread; +}; + +#define BUFF_SIZE 8192 +/* generated by contrib/phishing/generate_tables.c */ +static const short int hextable[256] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +extern int short cli_leavetemps_flag; + +static void init_rtf_state(struct rtf_state* state) +{ + *state = base_state; + state->parse_state = PARSE_MAIN; + state->controlword_cnt = 0; +} + +static int compare_state(const struct rtf_state* a,const struct rtf_state* b) +{ + return (a->controlword_param == b->controlword_param && + a->parse_state == b->parse_state && + a->encounteredTopLevel == b->encounteredTopLevel && + memcmp(a->controlword,b->controlword,33)==0 && + a->cb_begin == b->cb_begin && + a->cb_process == b->cb_process && + a->cb_end == b->cb_end && + a->cb_data == b->cb_data); +} + + +static int push_state(struct stack* stack,struct rtf_state* state) +{ + int toplevel; + size_t defelements; + + stack->elements++; + if( compare_state(state,&base_state)) { + state->default_elements++; + return 0;/* this is default state, don't push it, we'll know when we pop it that it was the default one, + we store in the state how many default elements we have on the stack */ + } + if(stack->stack_cnt >= stack->stack_size) { + /* grow stack */ + stack->stack_size += 128; + stack->states = cli_realloc(stack->states, stack->stack_size*sizeof(*stack->states)); + if(!stack->states) + return CL_EMEM; + } + stack->states[stack->stack_cnt++] = *state; + toplevel = state->encounteredTopLevel; + defelements = state->default_elements; + + *state = base_state; + + state->encounteredTopLevel = toplevel; + state->default_elements = defelements; + return 0; +} + + +static int pop_state(struct stack* stack,struct rtf_state* state) +{ + stack->elements--; + if(state->default_elements) { + const size_t default_elements = state->default_elements-1; + const int toplevel = state->encounteredTopLevel; + *state = base_state; + state->default_elements = default_elements; + state->encounteredTopLevel = toplevel; + return 0;/* this is a default 'state'*/ + } + if(!stack->stack_cnt) { + cli_dbgmsg("Warning: attempt to pop from empty stack!\n"); + *state = base_state;/* lets assume we give it a base state */ + return 0; + } + *state = stack->states[--stack->stack_cnt]; + return 0; +} + + +static int load_actions(table_t* t) +{ + size_t i; + for(i=0; ifd = -1; + data->partial = 0; + data->has_partial = 0; + data->bread = 0; + data->internal_state = WAIT_MAGIC; + data->tmpdir = tmpdir; + data->ctx = ctx; + + state->cb_data = data; + return 0; +} + + +static int decode_and_scan(struct rtf_object_data* data, cli_ctx* ctx) +{ + int ofd, ret=0; + + cli_dbgmsg("Scanning embedded object:%s\n",data->name); + if(data->bread == 1) { + cli_dbgmsg("Decoding ole object\n"); + lseek(data->fd,0,SEEK_SET); + ofd = cli_decode_ole_object(data->fd,data->tmpdir); + if (ofd >= 0) { + ret = cli_magic_scandesc(ofd, ctx); + close(ofd); + } + } + else + ret = cli_magic_scandesc(data->fd,ctx); + close(data->fd); + data->fd = 0; + if(data->name) { + if(!cli_leavetemps_flag) + unlink(data->name); + free(data->name); + data->name = NULL; + } + + if(ret != CL_CLEAN) + return ret; + return 0; +} + +static int rtf_object_process(struct rtf_state* state, const unsigned char* input,const size_t len) +{ + struct rtf_object_data* data = state->cb_data; + unsigned char outdata[BUFF_SIZE]; + const unsigned char* out_data; + size_t out_cnt = 0; + size_t i; + + if(!data || !len) + return 0; + + if(data->has_partial) { + outdata[out_cnt++] = data->partial | input[0]; + } + + data->has_partial = 0; + for(i=0;ipartial = byte; + data->has_partial = 1; + break; + } + outdata[out_cnt++] = byte | hextable[ input[i] ]; + } + } + + out_data = outdata; + while(out_data && out_cnt) { + switch(data->internal_state) { + case WAIT_MAGIC: { + for(i=0; ibread < rtf_data_magic_len; i++, data->bread++) + if(rtf_data_magic[data->bread] != out_data[i]) { + cli_dbgmsg("Warning: rtf objdata magic number not matched, expected:%d, got: %d, at pos:%d\n",rtf_data_magic[i],out_data[i],data->bread); + } + out_cnt -= i; + if(data->bread == rtf_data_magic_len) { + out_data += i; + data->bread = 0; + data->internal_state = WAIT_DESC_LEN; + } + break; + } + case WAIT_DESC_LEN: { + if(data->bread == 0) + data->desc_len = 0; + for(i=0; ibread < 4; i++,data->bread++) + data->desc_len |= ((size_t)out_data[i]) << (data->bread*8); + out_cnt -= i; + if(data->bread == 4) { + out_data += i; + data->bread=0; + if(data->desc_len > 64) { + cli_dbgmsg("Description length too big (%d), showing only 64 bytes of it\n",data->desc_len); + data->desc_name = cli_malloc(65); + } + else + data->desc_name = cli_malloc(data->desc_len+1); + if(!data->desc_name) { + return CL_EMEM; + } + data->internal_state = WAIT_DESC; + } + break; + } + case WAIT_DESC:{ + for(i=0;ibread < data->desc_len && data->bread < 64;i++, data->bread++) + data->desc_name[data->bread] = out_data[i]; + /*FIXME: sanity check here, to avoid segfault */ + if(i+data->desc_len-data->bread > out_cnt) { + cli_dbgmsg("Can't interpret length in wait_desc\n"); + return 0;/* bail out */ + } + out_cnt -= i + data->desc_len - data->bread; + if(data->bread <= data->desc_len) { + out_data += i + data->desc_len - data->bread; + data->desc_name[data->bread] = '\0'; + data->bread = 0; + cli_dbgmsg("Preparing to dump rtf embedded object, description:%s\n",data->desc_name); + free(data->desc_name); + data->desc_name = NULL; + data->internal_state = WAIT_ZERO; + } + break; + } + case WAIT_ZERO:{ + if(out_cnt < 8-data->bread) { + out_cnt = 0; + data->bread += out_cnt; + } + else { + out_cnt -= 8-data->bread; + data->bread = 8; + } + if(data->bread == 8) { + out_data += 8; + data->bread = 0; + data->internal_state = WAIT_DATA_SIZE; + } + break; + } + + case WAIT_DATA_SIZE: { + if(data->bread == 0) + data->desc_len = 0; + for(i=0; ibread < 4; i++,data->bread++) + data->desc_len |= ((size_t)out_data[i]) << (8*data->bread); + out_cnt -= i; + if(data->bread == 4) { + out_data += i; + data->bread=0; + cli_dbgmsg("Dumping rtf embedded object of size:%ld\n",data->desc_len); + data->name = cli_gentempdesc(data->tmpdir, &data->fd); + if(!data->name) + return CL_ETMPFILE; + data->internal_state = DUMP_DATA; + } + break; + } + case DUMP_DATA: { + ssize_t out_want = out_cnt < data->desc_len ? out_cnt : data->desc_len; + if(!data->bread) { + if(out_data[0] != 0xd0 || out_data[1]!=0xcf) { + /* this is not an ole2 doc, but some ole (stream?) to be + * decoded by cli_decode_ole_object*/ + char out[4]; + data->bread = 1;/* flag to indicate this needs to be scanned with cli_decode_ole_object*/ + cli_writeint32(out,data->desc_len); + if(cli_writen(data->fd,out,4)!=4) + return CL_EIO; + } + else + data->bread = 2; + } + + data->desc_len -= out_want; + if(cli_writen(data->fd,out_data,out_want) != out_want) { + return CL_EIO; + } + out_data += out_want; + out_cnt -= out_want; + if(!data->desc_len) { + int rc; + if(( rc = decode_and_scan(data, data->ctx) )) + return rc; + data->bread=0; + data->internal_state = WAIT_MAGIC; + } + break; + } + case DUMP_DISCARD: + default: + out_cnt = 0; + ; + } + } + return 0; +} + + + +static int rtf_object_end(struct rtf_state* state,cli_ctx* ctx) +{ + struct rtf_object_data* data = state->cb_data; + int rc = 0; + if(!data) + return 0; + if(data->fd) { + rc = decode_and_scan(data, ctx); + } + if(data->name) + free(data->name); + if(data->desc_name) + free(data->desc_name); + free(data); + state->cb_data = NULL; + return rc; +} + + +static void rtf_action(struct rtf_state* state,long action, const char* tempname,cli_ctx* ctx) +{ + switch(action) { + case RTF_OBJECT: + state->encounteredTopLevel |= 1<encounteredTopLevel & (1<cb_begin = rtf_object_begin; + state->cb_process = rtf_object_process; + state->cb_end = rtf_object_end; + } + break; + }; +} + +static void cleanup_stack(struct stack* stack,struct rtf_state* state,cli_ctx* ctx) +{ + while(stack && stack->stack_cnt && state->default_elements) { + pop_state(stack,state); + if(state->cb_begin) + state->cb_end(state,ctx); + } +} + + +#define SCAN_CLEANUP \ + tableDestroy(actiontable);\ + cleanup_stack(&stack,&state,ctx);\ + free(buff);\ + if(!cli_leavetemps_flag)\ + cli_rmdirs(tempname);\ + free(tempname);\ + free(stack.states); + +int cli_scanrtf(int desc, cli_ctx *ctx) +{ + char* tempname; + const unsigned char* ptr; + const unsigned char* ptr_end; + unsigned char* buff; + int ret = CL_CLEAN; + struct rtf_state state; + struct stack stack; + size_t bread; + table_t* actiontable; + uint8_t main_symbols[256]; + + cli_dbgmsg("in cli_scanrtf()\n"); + + memset(main_symbols, 0, 256); + main_symbols['{']=1; + main_symbols['}']=1; + main_symbols['\\']=1; + + stack.stack_cnt = 0; + stack.stack_size = 16; + stack.elements = 0; + stack.states = cli_malloc(stack.stack_size*sizeof(*stack.states)); + + if(!stack.states) + return CL_EMEM; + + buff = cli_malloc(BUFF_SIZE); + if(!buff) { + free(stack.states); + return CL_EMEM; + } + + tempname = cli_gentemp(NULL); + + if(mkdir(tempname, 0700)) { + cli_dbgmsg("ScanRTF -> Can't create temporary directory %s\n", tempname); + free(stack.states); + free(buff); + free(tempname); + return CL_ETMPDIR; + } + + actiontable = tableCreate(); + if((ret = load_actions(actiontable))) { + cli_dbgmsg("RTF: Unable to load rtf action table\n"); + free(stack.states); + free(buff); + if(!cli_leavetemps_flag) + cli_rmdirs(tempname); + free(tempname); + return ret; + } + + init_rtf_state(&state); + + while(( bread = cli_readn(desc, buff, BUFF_SIZE) )) { + ptr = buff; + ptr_end = buff + bread; + while(ptr < ptr_end) { + switch(state.parse_state) { + case PARSE_MAIN: + switch(*ptr++) { + case '{': + if(( ret = push_state(&stack,&state) )) { + cli_dbgmsg("RTF:Push failure!\n"); + SCAN_CLEANUP; + return ret; + } + break; + case '}': + if(state.cb_data) + if(( ret = state.cb_end(&state, ctx) )) { + SCAN_CLEANUP; + return ret; + } + if(( ret = pop_state(&stack,&state) )) { + cli_dbgmsg("RTF:pop failure!\n"); + SCAN_CLEANUP; + return ret; + } + break; + case '\\': + state.parse_state = PARSE_CONTROL_; + break; + default: + ptr--; + { + size_t i; + size_t left = ptr_end - ptr; + size_t use = left; + for(i = 1;i < left; i++) + if(main_symbols[ptr[i]]) { + use = i; + break; + } + if(state.cb_begin) { + if(!state.cb_data) + if(( ret = state.cb_begin(&state, ctx,tempname) )) { + SCAN_CLEANUP; + return ret; + } + if(( ret = state.cb_process(&state, ptr, use) )) { + state.cb_end(&state,ctx); + SCAN_CLEANUP; + return ret; + } + } + ptr += use; + } + } + break; + case PARSE_CONTROL_: + if(isalpha(*ptr)) { + state.parse_state = PARSE_CONTROL_WORD; + state.controlword_cnt = 0; + } + else + state.parse_state = PARSE_CONTROL_SYMBOL; + break; + case PARSE_CONTROL_SYMBOL: + ptr++; /* Do nothing */ + state.parse_state = PARSE_MAIN; + break; + case PARSE_CONTROL_WORD: + if(state.controlword_cnt == 32) { + cli_dbgmsg("Invalid control word: maximum size exceeded:%s\n",state.controlword); + state.parse_state = PARSE_MAIN; + } + else if(isalpha(*ptr)) + state.controlword[state.controlword_cnt++] = *ptr++; + else { + if(isspace(*ptr)) { + state.controlword[state.controlword_cnt++] = *ptr++; + state.parse_state = PARSE_INTERPRET_CONTROLWORD; + } + else if (isdigit(*ptr)) { + state.parse_state = PARSE_CONTROL_WORD_PARAM; + state.controlword_param = 0; + state.controlword_param_sign = 1; + } + else if(*ptr == '-') { + ptr++; + state.parse_state = PARSE_CONTROL_WORD_PARAM; + state.controlword_param = 0; + state.controlword_param_sign = -1; + } + else { + state.parse_state = PARSE_INTERPRET_CONTROLWORD; + } + } + break; + case PARSE_CONTROL_WORD_PARAM: + if(isdigit(*ptr)) { + state.controlword_param = state.controlword_param*10 + *ptr++ - '0'; + } + else if(isalpha(*ptr)) { + ptr++; + } + else { + if(state.controlword_param_sign < 0) + state.controlword_param = -state.controlword_param; + state.parse_state = PARSE_INTERPRET_CONTROLWORD; + } + break; + case PARSE_INTERPRET_CONTROLWORD: + { + int action; + + state.controlword[state.controlword_cnt] = '\0'; + action = tableFind(actiontable, state.controlword); + if(action != -1) + rtf_action(&state,action, tempname, ctx); + state.parse_state = PARSE_MAIN; + break; + } + } + } + } + + SCAN_CLEANUP; + return ret; +} + +#endif diff --git a/clamav-devel/libclamav/rtf.h b/clamav-devel/libclamav/rtf.h new file mode 100644 index 000000000..8489f918e --- /dev/null +++ b/clamav-devel/libclamav/rtf.h @@ -0,0 +1,11 @@ +#ifndef _RTF_H +#define _RTF_H +#include +#ifdef CL_EXPERIMENTAL + + +int cli_scanrtf(int desc, cli_ctx *ctx); + +#endif + +#endif diff --git a/clamav-devel/libclamav/scanners.c b/clamav-devel/libclamav/scanners.c index 4957477d1..b98f86ab4 100644 --- a/clamav-devel/libclamav/scanners.c +++ b/clamav-devel/libclamav/scanners.c @@ -80,6 +80,10 @@ extern short cli_leavetemps_flag; #include "pdf.h" #include "str.h" +#ifdef CL_EXPERIMENTAL +#include "rtf.h" +#endif + #ifdef HAVE_ZLIB_H #include #include "unzip.h" @@ -1775,6 +1779,12 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx) ret = cli_scanhtml_utf16(desc, ctx); break; +#ifdef CL_EXPERIMENTAL + case CL_TYPE_RTF: + ret = cli_scanrtf(desc, ctx); + break; +#endif + case CL_TYPE_MAIL: if(SCAN_MAIL) ret = cli_scanmail(desc, ctx);