[llvm-commits] [test-suite] r46573 [3/3] - in /test-suite/trunk/MultiSource/Applications: ./ ClamAV/ ClamAV/dbdir/ ClamAV/inputs/ ClamAV/inputs/rtf-test/ ClamAV/scripts/
Evan Cheng
evan.cheng at apple.com
Wed Jan 30 13:17:12 PST 2008
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_list.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1942 @@
+/*
+ * Match a string against a list of patterns/regexes.
+ *
+ * Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#ifndef CL_DEBUG
+#define NDEBUG
+#endif
+
+#ifdef CL_THREAD_SAFE
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+#endif
+
+
+/* TODO: when implementation of new version is complete, enable it in CL_EXPERIMENTAL */
+#ifdef CL_EXPERIMENTAL
+/*#define USE_NEW_VERSION*/
+#endif
+
+#ifndef USE_NEW_VERSION
+/*this is the old version of regex_list.c
+ *reason for redesign: there is only one node type that has to handle all the cases: binary search among children, alternatives list, match.
+ * This design is very error-prone.*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <limits.h>
+#include <sys/types.h>
+
+#include "regex.h"
+
+
+#include "clamav.h"
+#include "others.h"
+#include "regex_list.h"
+#include "matcher-ac.h"
+#include "str.h"
+
+/*Tree*/
+enum token_op_t {OP_CHAR,OP_STDCLASS,OP_CUSTOMCLASS,OP_DOT,OP_LEAF,OP_ROOT,OP_PARCLOSE};
+typedef unsigned char* char_bitmap_p;
+/*
+ *
+ * OP_CHAR: 1 character, c = character
+ * complex stuff:
+ * OP_STDCLASS: standard character class, c = char class, class: 1<<(index into std_class of class name)
+ * OP_CUSTOMCLASS: custom character class, first pointer in ptr array is a pointer to the bitmap table for this class
+ * OP_DOT: single . matching any character except \n
+ * OP_LEAF: this is a leaf node, reinterpret structure
+ */
+struct tree_node {
+ struct tree_node* next;/* next regex/complex sibling, or parent, if no more siblings , can't be NULL except for root node*/
+ unsigned char c;
+ enum token_op_t op;
+ char alternatives;/* number of (non-regex) children of node, i.e. sizeof(children)*/
+ char listend;/* no more siblings, next pointer is pointer to parent*/
+ union {
+ struct tree_node** children;/* alternatives nr. of children, followed by (a null pointer terminated) regex leaf node pointers) */
+ char_bitmap_p* bitmap;
+ struct leaf_info* leaf;
+ } u;
+};
+
+struct leaf_info {
+ char* info;/* what does it mean that we reached the leaf...*/
+ regex_t* preg;/* this is NULL if leaf node, and non-regex*/
+};
+
+/* Character classes */
+static const char* std_class[] = {
+ "[:alnum:]",
+ "[:digit:]",
+ "[:punct:]",
+ "[:alpha:]",
+ "[:graph:]",
+ "[:space:]",
+ "[:blank:]",
+ "[:lower:]",
+ "[:upper:]",
+ "[:cntrl:]",
+ "[:print:]",
+ "[:xdigit:]"
+ /* don't change the order of these strings, unless you change them in generate_tables.c too, and regenerate the tables*/
+};
+
+
+#define STD_CLASS_CNT sizeof(std_class)/sizeof(std_class[0])
+
+/* generated by contrib/phishing/generate_tables.c */
+static const unsigned char char_class_bitmap[STD_CLASS_CNT][32] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+ 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0xfc,
+ 0x01, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x78,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0x07, 0xfe, 0xff, 0xff, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x07,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+ 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+};
+
+static const unsigned short int char_class[256] = {
+ 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x260, 0x220, 0x220, 0x220, 0x220, 0x200, 0x200,
+ 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200, 0x200,
+ 0x460, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414,
+ 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0xc13, 0x414, 0x414, 0x414, 0x414, 0x414, 0x414,
+ 0x414, 0xd19, 0xd19, 0xd19, 0xd19, 0xd19, 0xd19, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519,
+ 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x519, 0x414, 0x414, 0x414, 0x414, 0x414,
+ 0x414, 0xc99, 0xc99, 0xc99, 0xc99, 0xc99, 0xc99, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499,
+ 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x499, 0x414, 0x414, 0x414, 0x414, 0x200,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
+};
+
+static const size_t std_class_cnt = sizeof(std_class)/sizeof(std_class[0]);
+
+/* Prototypes */
+static int add_pattern(struct regex_matcher* matcher,const unsigned char* pat,const char* info,int hostOnly);
+static int match_node(struct tree_node* node,const unsigned char* c,size_t len,const char** info);
+static void destroy_tree(struct regex_matcher* matcher);
+static struct tree_node* tree_root_alloc(void);
+static int build_regex_list(struct regex_matcher* matcher);
+static void stack_destroy(struct node_stack* stack);
+
+#ifndef NDEBUG
+void dump_tree(struct tree_node* root);
+#endif
+
+#define MATCH_SUCCESS 0
+#define MATCH_FAILED -1
+
+/*
+ * Call this function when an unrecoverable error has occured, (instead of exit).
+ */
+static void fatal_error(struct regex_matcher* matcher)
+{
+ regex_list_done(matcher);
+ matcher->list_inited = -1;/* the phishing module will know we tried to load a whitelist, and failed, so it will disable itself too*/
+}
+
+
+static inline size_t get_char_at_pos_with_skip(const struct pre_fixup_info* info, const char* buffer, size_t pos)
+{
+ const char* str;
+ size_t realpos = 0;
+ if(!info) {
+ return (pos <= strlen(buffer)) ? buffer[pos>0 ? pos-1:0] : '\0';
+ }
+ str = info->pre_displayLink.data;
+ cli_dbgmsg("calc_pos_with_skip: skip:%lu, %lu - %lu \"%s\",\"%s\"\n", pos, info->host_start, info->host_end, str, buffer);
+ pos += info->host_start;
+ while(str[realpos] && !isalnum(str[realpos])) realpos++;
+ for(; str[realpos] && (pos>0); pos--) {
+ while(str[realpos]==' ') realpos++;
+ realpos++;
+ }
+ while(str[realpos]==' ') realpos++;
+ cli_dbgmsg("calc_pos_with_skip:%s\n",str+realpos);
+ return (pos>0 && !str[realpos]) ? '\0' : str[realpos>0?realpos-1:0];
+}
+
+/*
+ * @matcher - matcher structure to use
+ * @real_url - href target
+ * @display_url - <a> tag contents
+ * @hostOnly - if you want to match only the host part
+ * @is_whitelist - is this a lookup in whitelist?
+ *
+ * @return - CL_SUCCESS - url doesn't match
+ * - CL_VIRUS - url matches list
+ *
+ * Do not send NULL pointers to this function!!
+ *
+ */
+int regex_list_match(struct regex_matcher* matcher,char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup,int hostOnly,const char** info,int is_whitelist)
+{
+ massert(matcher);
+ massert(real_url);
+ massert(display_url);
+ massert(info);
+ if(!matcher->list_inited)
+ return 0;
+ massert(matcher->list_built);
+ {
+ size_t real_len = strlen(real_url);
+ size_t display_len = strlen(display_url);
+ size_t buffer_len = (hostOnly && !is_whitelist) ? real_len : real_len + display_len + 1 + (is_whitelist ? 1 : 0);
+ char* buffer = cli_malloc(buffer_len+1);
+ size_t i;
+ int rc = 0;
+ struct cli_ac_data mdata;
+
+ if(!buffer)
+ return CL_EMEM;
+
+ strncpy(buffer,real_url,real_len);
+ buffer[real_len]= (!is_whitelist && hostOnly) ? '\0' : ':';
+ if(!hostOnly || is_whitelist) {
+ strncpy(buffer+real_len+1,display_url,display_len);
+ if(is_whitelist)
+ buffer[buffer_len - 1] = '/';
+ buffer[buffer_len]=0;
+ }
+ cli_dbgmsg("Looking up in regex_list: %s\n", buffer);
+
+ if(hostOnly) {
+ if((rc = cli_ac_initdata(&mdata, 0, AC_DEFAULT_TRACKLEN)))
+ return rc;
+ rc = 0;
+
+ for(i = 0; i < matcher->root_hosts_cnt; i++) {
+ /* doesn't need to match terminating \0*/
+ rc = cli_ac_scanbuff((unsigned char*)buffer,buffer_len,info, &matcher->root_hosts[i] ,&mdata,0,0,0,-1,NULL);
+ cli_ac_freedata(&mdata);
+ if(rc) {
+ char c;
+ const char* matched = strchr(*info,':');
+ const size_t match_len = matched ? strlen(matched+1) : 0;
+ if(((c=get_char_at_pos_with_skip(pre_fixup,buffer,buffer_len+1))==' ' || c=='\0' || c=='/' || c=='?') &&
+ (match_len == buffer_len || /* full match */
+ (match_len < buffer_len &&
+ ((c=get_char_at_pos_with_skip(pre_fixup,buffer,buffer_len-match_len))=='.' || (c==' ')) )
+ /* subdomain matched*/)) {
+
+ cli_dbgmsg("Got a match: %s with %s\n",buffer,*info);
+ cli_dbgmsg("Before inserting .: %s\n",real_url);
+ if(real_len >= match_len + 1) {
+ real_url[real_len-match_len-1]='.';
+ cli_dbgmsg("After inserting .: %s\n",real_url);
+ }
+ break;
+ }
+ cli_dbgmsg("Ignoring false match: %s with %s,%c\n",buffer,*info,c);
+ rc=0;
+ }
+ }
+ } else
+ rc = 0;
+
+ if(!rc)
+ rc = match_node(hostOnly ? matcher->root_regex_hostonly : matcher->root_regex,(unsigned char*)buffer,buffer_len,info) == MATCH_SUCCESS ? CL_VIRUS : CL_SUCCESS;
+ free(buffer);
+ if(!rc)
+ cli_dbgmsg("Lookup result: not in regex list\n");
+ else
+ cli_dbgmsg("Lookup result: in regex list\n");
+ return rc;
+ }
+}
+
+/* node stack */
+#define NODE_STACK_INITIAL 1024
+#define NODE_STACK_GROW 4096
+/* Initialize @stack */
+static int stack_init(struct node_stack* stack)
+{
+ massert(stack);
+
+ stack->cnt = 0;
+ stack->capacity = NODE_STACK_INITIAL;
+ stack->data = cli_malloc(stack->capacity * sizeof(*stack->data));
+ if(!stack->data)
+ return CL_EMEM;
+ else
+ return CL_SUCCESS;
+}
+
+/* Reset @stack pointer, but don't realloc */
+static void stack_reset(struct node_stack* stack)
+{
+ massert(stack);
+
+ stack->cnt = 0;
+}
+
+/* Push @node on @stack, growing it if necessarry */
+static int stack_push(struct node_stack* stack,struct tree_node* node)
+{
+ massert(stack);
+ massert(stack->data);
+
+ if(stack->cnt == stack->capacity) {
+ stack->capacity += NODE_STACK_GROW;
+ stack->data = cli_realloc2(stack->data,stack->capacity*sizeof(*stack->data));
+ if(!stack->data)
+ return CL_EMEM;
+ }
+ stack->data[stack->cnt++] = node;
+ return CL_SUCCESS;
+}
+
+/* Pops node from @stack, doesn't realloc */
+static struct tree_node* stack_pop(struct node_stack* stack)
+{
+ massert(stack);
+ massert(stack->data);
+ massert(stack->cnt);/*don't pop from empty stack */
+
+ return stack->cnt ? stack->data[--stack->cnt] : NULL;
+}
+
+/* Initialization & loading */
+/* Initializes @matcher, allocating necesarry substructures */
+int init_regex_list(struct regex_matcher* matcher)
+{
+ int rc;
+
+ massert(matcher);
+ matcher->list_inited = 0;
+ matcher->root_hosts_cnt = 0;
+ matcher->root_hosts = NULL;
+ matcher->root_hosts_cnt = 0;
+
+ matcher->root_regex = tree_root_alloc();
+ if(!matcher->root_regex) {
+ return CL_EMEM;
+ }
+
+ matcher->root_regex_hostonly = tree_root_alloc();
+ if(!matcher->root_regex_hostonly) {
+ free(matcher->root_regex);
+ return CL_EMEM;
+ }
+
+ if(( rc = stack_init(&matcher->node_stack) )) {
+ free(matcher->root_regex_hostonly);
+ free(matcher->root_regex);
+ return rc;
+ }
+ if(( rc = stack_init(&matcher->node_stack_alt) )) {
+ free(matcher->root_regex_hostonly);
+ free(matcher->root_regex);
+ stack_destroy(&matcher->node_stack);
+ return rc;
+ }
+
+ matcher->list_inited=1;
+ matcher->list_built=1;/* its empty, but pretend its built, so that load_ will realloc root_hosts */
+ matcher->list_loaded=0;
+
+ return CL_SUCCESS;
+}
+
+/* inserts @pattern into @root, using ac-matcher
+ * although the name might be confusing, @pattern is not a regex!*/
+static int add_regex_list_element(struct cli_matcher* root,const char* pattern,char* info)
+{
+ int ret;
+ struct cli_ac_patt *new = cli_calloc(1,sizeof(*new));
+ size_t len,i;
+
+ if(!new)
+ return CL_EMEM;
+ massert(root);
+ massert(pattern);
+
+ len = strlen(pattern);
+ /* need not to match \0 too */
+ new->type = 0;
+ new->sigid = 0;
+ new->parts = 0;
+ new->partno = 0;
+ new->mindist = 0;
+ new->maxdist = 0;
+ new->offset = 0;
+ new->target = 0;
+ new->length = len;
+ if(new->length > root->maxpatlen)
+ root->maxpatlen = new->length;
+
+ new->pattern = cli_malloc(sizeof(new->pattern[0])*len);
+ if(!new->pattern) {
+ free(new);
+ return CL_EMEM;
+ }
+ for(i=0;i<len;i++)
+ new->pattern[i]=pattern[i];/*new->pattern is short int* */
+
+
+ new->virname = cli_strdup(info);
+ if((ret = cli_ac_addpatt(root,new))) {
+ free(new->virname);
+ free(new->pattern);
+ free(new);
+ return ret;
+ }
+ return CL_SUCCESS;
+}
+
+static int functionality_level_check(char* line)
+{
+ char* ptmin;
+ char* ptmax;
+ size_t j;
+
+ ptmin = strrchr(line,':');
+ if(!ptmin)
+ return CL_SUCCESS;
+
+ ptmin++;
+
+ ptmax = strchr(ptmin,'-');
+ if(!ptmax)
+ return CL_SUCCESS;/* there is no functionality level specified, so we're ok */
+ else {
+ size_t min, max;
+ ptmax++;
+ for(j=0;j+ptmin+1 < ptmax;j++)
+ if(!isdigit(ptmin[j]))
+ return CL_SUCCESS;/* not numbers, not functionality level */
+ for(j=0;j<strlen(ptmax);j++)
+ if(!isdigit(ptmax[j]))
+ return CL_SUCCESS;/* see above */
+ ptmax[-1]='\0';
+ min = atoi(ptmin);
+ if(strlen(ptmax)==0)
+ max = INT_MAX;
+ else
+ max = atoi(ptmax);
+
+ if(min > cl_retflevel()) {
+ cli_dbgmsg("regex list line %s not loaded (required f-level: %u)\n",line,(unsigned int)min);
+ return CL_EMALFDB;
+ }
+
+ if(max < cl_retflevel())
+ return CL_EMALFDB;
+ ptmin[-1]='\0';
+ return CL_SUCCESS;
+ }
+}
+
+
+/* Load patterns/regexes from file */
+int load_regex_matcher(struct regex_matcher* matcher,FILE* fd,unsigned int options,int is_whitelist)
+{
+ int rc,line=0;
+ char buffer[FILEBUFF];
+
+ massert(matcher);
+ massert(fd);
+
+ if(matcher->list_inited==-1)
+ return CL_EMALFDB; /* already failed to load */
+/* if(matcher->list_loaded) {
+ cli_warnmsg("Regex list has already been loaded, ignoring further requests for load\n");
+ return CL_SUCCESS;
+ }*/
+ if(!fd) {
+ cli_errmsg("Unable to load regex list (null file)\n");
+ return CL_EIO;
+ }
+
+ cli_dbgmsg("Loading regex_list\n");
+ if(!matcher->list_inited) {
+ rc = init_regex_list(matcher);
+ if (!matcher->list_inited) {
+ cli_errmsg("Regex list failed to initialize!\n");
+ fatal_error(matcher);
+ return rc;
+ }
+ /*atexit(regex_list_done); TODO: destroy this in manager.c */
+ }
+ /*
+ * Regexlist db format (common to .wdb(whitelist) and .pdb(domainlist) files:
+ * Multiple lines of form, (empty lines are skipped):
+ * Flags RealURL DisplayedURL
+ * Where:
+ * Flags:
+ *
+ * .pdb files:
+ * R - regex, H - host-only, followed by (optional) 3-digit hexnumber representing
+ * flags that should be filtered.
+ * [i.e. phishcheck urls.flags that we don't want to be done for this particular host]
+ *
+ * .wdb files:
+ * X - full URL regex
+ * Y - host-only regex
+ * M - host simple pattern
+ *
+ * If a line in the file doesn't conform to this format, loading fails
+ *
+ */
+ while(fgets(buffer,FILEBUFF,fd)) {
+ char* pattern;
+ char* flags;
+ cli_chomp(buffer);
+ if(!*buffer)
+ continue;/* skip empty lines */
+
+ if(functionality_level_check(buffer))
+ continue;
+
+ line++;
+ pattern = strchr(buffer,':');
+ if(!pattern) {
+ cli_errmsg("Malformed regex list line %d\n",line);
+ fatal_error(matcher);
+ return CL_EMALFDB;
+ }
+ /*pattern[0]='\0';*/
+ flags = buffer+1;
+ pattern++;
+
+ if(is_whitelist) {
+ const size_t pattern_len = strlen(pattern);
+ if(pattern_len < FILEBUFF) {
+ pattern[pattern_len] = '/';
+ pattern[pattern_len+1] = '\0';
+ }
+ else {
+ cli_errmsg("Overlong regex line %d\n",line);
+ fatal_error(matcher);
+ return CL_EMALFDB;
+ }
+ }
+
+ if((buffer[0] == 'R' && !is_whitelist) || ((buffer[0] == 'X' || buffer[0] == 'Y') && is_whitelist)) {/*regex*/
+ if(( rc = add_pattern(matcher,(const unsigned char*)pattern,flags, buffer[0] == 'Y') ))
+ return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;
+ }
+ else if( ( buffer[0] == 'H' && !is_whitelist) || (buffer[0] == 'M' && is_whitelist)) {/*matches displayed host*/
+ struct cli_matcher* root;
+ if(matcher->list_built) {
+ struct cli_matcher* old_hosts = matcher->root_hosts;
+ matcher->root_hosts_cnt++;
+
+ matcher->root_hosts = cli_realloc(matcher->root_hosts, matcher->root_hosts_cnt * sizeof(*matcher->root_hosts));
+ if(!matcher->root_hosts) {
+ matcher->root_hosts = old_hosts;/* according to manpage this must still be valid*/
+ return CL_EMEM;
+ }
+
+ root = &matcher->root_hosts[matcher->root_hosts_cnt-1];
+ memset(root, 0, sizeof(struct cli_matcher));
+
+ cli_dbgmsg("regex_list: Initialising AC pattern matcher\n");
+ if((rc = cli_ac_init(root, cli_ac_mindepth, cli_ac_maxdepth))) {
+ /* no need to free previously allocated memory here */
+ cli_errmsg("regex_list: Can't initialise AC pattern matcher\n");
+ return rc;
+ }
+ matcher->list_built = 0;
+ }
+ else {
+ root = &matcher->root_hosts[matcher->root_hosts_cnt-1];
+ }
+ if(( rc = add_regex_list_element(root,pattern,flags) ))
+ return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;
+ }
+ else {
+ return CL_EMALFDB;
+ /* this is useless, we have host, and regex matches
+ if(( rc = add_regex_list_element(matcher->root_urls,pattern,flags) ))
+ return rc==CL_EMEM ? CL_EMEM : CL_EMALFDB;*/
+ }
+ }
+ matcher->list_loaded = 1;
+ if(( rc = build_regex_list(matcher) ))
+ return rc;
+
+#ifndef NDEBUG
+/* dump_tree(matcher->root_regex);*/
+#endif
+ if(!matcher->list_built) {
+ cli_errmsg("Regex list not loaded: build failed!\n");
+ fatal_error(matcher);
+ return CL_EMALFDB;
+ }
+ regex_list_cleanup(matcher);
+ return CL_SUCCESS;
+}
+
+
+static struct tree_node ** tree_node_get_children(const struct tree_node* node)
+{
+ return node->op==OP_CUSTOMCLASS ? (node->u.children[1] ? node->u.children+1 : NULL) :node->u.children;
+}
+
+/* Build the matcher list */
+static int build_regex_list(struct regex_matcher* matcher)
+{
+ int rc;
+ if(!matcher->list_inited || !matcher->list_loaded) {
+ cli_errmsg("Regex list not loaded!\n");
+ return -1;/*TODO: better error code */
+ }
+ cli_dbgmsg("Building regex list\n");
+ if(matcher->root_hosts)
+ if(( rc = cli_ac_buildtrie(&matcher->root_hosts[matcher->root_hosts_cnt-1]) ))
+ return rc;
+ matcher->list_built=1;
+
+ return CL_SUCCESS;
+}
+
+/* Done with this matcher, free resources */
+void regex_list_done(struct regex_matcher* matcher)
+{
+ massert(matcher);
+
+ regex_list_cleanup(matcher);
+ if(matcher->list_loaded) {
+ if(matcher->root_hosts) {
+ size_t i;
+ for(i=0;i<matcher->root_hosts_cnt;i++)
+ cli_ac_free(&matcher->root_hosts[i]);
+ free(matcher->root_hosts);
+ matcher->root_hosts=NULL;
+ }
+
+ matcher->root_hosts_cnt=0;
+ matcher->list_built=0;
+ destroy_tree(matcher);
+ matcher->list_loaded=0;
+ }
+ if(matcher->list_inited) {
+ matcher->list_inited=0;
+ }
+ stack_destroy(&matcher->node_stack);
+ stack_destroy(&matcher->node_stack_alt);
+}
+
+/* Tree matcher algorithm */
+struct token_t
+{
+ union {
+ const unsigned char* start;
+ char_bitmap_p bitmap;
+ unsigned char c;
+ } u;
+ size_t len;
+ char type;
+};
+
+enum {TOKEN_CHAR,TOKEN_DOT,TOKEN_PAR_OPEN,TOKEN_PAR_CLOSE,TOKEN_BRACKET,TOKEN_ALT,TOKEN_REGEX,TOKEN_DONE};
+
+static const unsigned char* getNextToken(const unsigned char* pat,struct token_t* token)
+{
+ massert(pat);
+ massert(token);
+
+ switch(*pat) {
+ case '\\':
+ token->type=TOKEN_CHAR;
+ token->u.c = *(++pat);
+ if(islower(token->u.c)) {
+ /* handle \n, \t, etc. */
+ char fmt[3] = {'\\', '\0', '\0'};
+ char c;
+
+ fmt[1] = token->u.c;
+ if(snprintf(&c,1,fmt)!=1) {
+ token->type=TOKEN_REGEX;
+ token->u.start = pat;
+ }
+ else
+ token->u.c=c;
+ }
+ token->len = 1;
+ break;
+ case '|':
+ token->type=TOKEN_ALT;
+ break;
+ case '*':
+ case '+':
+ case '?':
+ case '{':
+ case '}':
+ token->type=TOKEN_REGEX;
+ break;
+ case '[':
+ {
+ /*TODO: implement*/
+ /*see if it is something simple like a list of characters, a range, or negated ...*/
+ const unsigned char* old=pat++;/* save this in case we change our mind and decide this is too complicated for us to handle*/
+ unsigned char range_start=0;
+ int hasprev = 0;
+ char_bitmap_p bitmap = cli_malloc(32);
+ if(!bitmap)
+ return NULL;
+ if (*pat=='^') {
+ memset(bitmap,0xFF,32);/*match chars not in brackets*/
+ pat++;
+ }
+ else
+ memset(bitmap,0x00,32);
+ do {
+ /* literal ] can be first character, so test for it at the end of the loop, for example: []] */
+ if (*pat=='-' && hasprev) {
+ /* it is a range*/
+ unsigned char range_end;
+ unsigned int c;
+ massert(range_start);
+ pat++;
+ if (pat[0]=='[')
+ if (pat[1]=='.') {
+ if(pat[2]=='-' && pat[3]=='.' && pat[4]==']')
+ range_end = '-';
+ else {
+ /* this is getting complicated, bail out */
+ cli_warnmsg("confused about collating sequences in regex,bailing out");
+ pat=old;
+ token->type=TOKEN_REGEX;
+ break;
+ }
+ }
+ else
+ range_end = *pat;
+ else
+ range_end = *pat;
+ for(c=range_start+1;c<=range_end;c++)
+ bitmap[c>>3] ^= 1<<(c&0x7);
+ hasprev = 0;
+ }
+ else if (pat[0]=='[' && pat[1]==':') {
+ const unsigned char* end;
+ int len,found=-1;
+ size_t i;
+
+ pat+=2;
+ end=(unsigned char*)strstr((const char*)pat,":]");
+ if(!end) {
+ cli_warnmsg("confused about std char class syntax regex,bailing out");
+ pat=old;
+ token->type=TOKEN_REGEX;
+ break;
+ }
+
+ len = end-pat;
+ for(i=0;i<std_class_cnt;i++)
+ if(!strncmp((const char*)pat,std_class[i],len)) {
+ found=i;
+ break;
+ }
+ if(found!=-1) {
+ for(i=0;i<256;i++)
+ if(char_class[i]&(1<<found))
+ bitmap[i>>3] ^= 1<<(i&0x7);
+ }
+ else {
+ /*unknown class*/
+ cli_warnmsg("confused about regex bracket expression, bailing out");
+ pat=old;
+ token->type=TOKEN_REGEX;
+ break;
+ }
+ }
+ else {
+ bitmap[*pat>>3] ^= 1<<(*pat&0x7);
+ pat++;
+ range_start = *pat;
+ hasprev = 1;
+ }
+ } while(*pat!=']');
+ /*TODO: see if this bitmap already exists, then reuse*/
+ token->type = TOKEN_BRACKET;
+ token->u.bitmap = bitmap;
+ break;
+ }
+ case ']':
+ massert(0 && "Encountered ] without matching [");
+ /* bad state */
+ break;
+ case '.':
+ token->type=TOKEN_DOT;
+ break;
+ case '(':
+ token->type=TOKEN_PAR_OPEN;
+ break;
+ case ')':
+ token->type=TOKEN_PAR_CLOSE;
+ break;
+ default:
+ token->type=TOKEN_CHAR;
+ token->u.c = *pat;
+ token->len=1;
+ break;
+ }
+ return ++pat;
+}
+
+#define INITIAL_ALT_STACK 10
+#define ALT_STACK_GROW 20
+
+static const unsigned char* find_regex_start(const unsigned char* pat)
+{
+ struct token_t token;
+ /*TODO: find where the regex part begins, for ex:
+ * abcd+, regex begins at 'd'
+ * */
+ const unsigned char* last=NULL;
+ const unsigned char* tmp=NULL;
+ const unsigned char** altpositions = cli_malloc(INITIAL_ALT_STACK*sizeof(*altpositions));
+ size_t altpositions_capacity = INITIAL_ALT_STACK;
+ size_t altpositions_cnt = 0;
+ char lasttype = -1;
+ if(!altpositions)
+ return NULL;
+ massert(pat);
+
+ /* Try to parse pattern till special regex chars are encountered, that the tree-matcher doesn't handle, like: +,*,{}.
+ * The tricky part is that once we encounter these, the previous 'atom' has to be passed on to the regex matcher, so we have to
+ * back up to the last known good position
+ * Example, if we have: abc(defg)+, then only abc can be handled by tree parser, so we have to return the position of (.
+ * Another example: abc(defg|xyz|oz+|pdo), the last known good position is |, after xyz
+ * TODO: what about open parantheses? maybe once we found a special char, we have top back out before the first (?
+ * */
+ do {
+ tmp = pat;
+ pat = getNextToken(pat,&token);
+ if(token.type!=TOKEN_REGEX) {
+ last = tmp;
+ lasttype = token.type;
+ if(token.type==TOKEN_BRACKET && token.u.bitmap)
+ free(token.u.bitmap);
+ if(token.type==TOKEN_ALT || token.type==TOKEN_PAR_OPEN) {
+ /* save this position on stack, succesfully parsed till here*/
+ if(altpositions_cnt && altpositions[altpositions_cnt-1][0]=='|')
+ /* encountered another alternate (|) operator, override previous | position stored */
+ altpositions[altpositions_cnt-1]=last;
+ else {
+ altpositions[altpositions_cnt++] = last;
+ if(altpositions_cnt == altpositions_capacity) {
+ altpositions_capacity += ALT_STACK_GROW;
+ altpositions = cli_realloc2(altpositions,altpositions_capacity*sizeof(*altpositions));
+ if(!altpositions)
+ return NULL;
+ }
+ }
+ } else if (lasttype==TOKEN_PAR_CLOSE) {
+ /* remove last stored position from stack, succesfully this last group */
+ altpositions_cnt--;
+ massert(altpositions_cnt>0);
+ }
+ }
+ else {
+ if(altpositions_cnt)
+ last = altpositions[0 /*altpositions_cnt-1*/];/*TODO: which index here?, see above TODO... */
+ /*last stored 'safe' position where no special (+,*,{}) regex chars were encountered*/
+ }
+ } while(*pat && token.type!=TOKEN_REGEX);
+ free(altpositions);
+ return *pat ? last : last+1;
+}
+
+static struct tree_node* tree_node_alloc(struct tree_node* next,char listend)
+{
+ struct tree_node* node = cli_malloc(sizeof(*node));
+ if(node) {
+ node->alternatives=0;
+ node->next=next;
+ node->listend=listend;
+ node->u.children=NULL;
+ }
+ return node;
+}
+
+static struct tree_node* tree_root_alloc(void)
+{
+ struct tree_node* root=tree_node_alloc(NULL,1);
+ if(root) {
+ root->op=OP_ROOT;
+ root->c=0;
+ root->next=NULL;
+ root->listend=1;
+ }
+ return root;
+}
+
+static struct tree_node* tree_node_char_binsearch(const struct tree_node* node,const char csearch,int* left)
+{
+ int right;
+ struct tree_node **children;
+ massert(node);
+ massert(left);
+
+ children = tree_node_get_children(node);
+ right = node->alternatives-1;
+ *left = 0;
+ if(!node->alternatives)
+ return NULL;
+ massert(children);
+ while(*left<=right) {
+ int mid = *left+(right-*left)/2;
+ if(children[mid]->c == csearch)
+ return children[mid];
+ else if(children[mid]->c < csearch)
+ *left=mid+1;
+ else
+ right=mid-1;
+ }
+ return NULL;
+}
+
+static struct tree_node* tree_get_next(struct tree_node* node)
+{
+ struct tree_node** children;
+ massert(node);
+ children = tree_node_get_children(node);
+
+ if(!node->alternatives && children && children[0])
+ return children[0];
+ else if(node->alternatives<=1)
+ return node;
+ else
+ return children[0]->next;
+}
+
+static size_t tree_node_get_array_size(const struct tree_node* node)
+{
+ massert(node);
+ /* if op is CUSTOMCLASS, then first pointer is pointer to bitmap, so array size is +1 */
+ return (node->alternatives + (node->op==OP_CUSTOMCLASS ? 1 : 0)) * sizeof(node->u.children[0]);
+}
+
+static struct tree_node* tree_node_char_insert(struct tree_node* node,const char c,int left)
+{
+ struct tree_node* new, *alt = tree_get_next(node);
+ struct tree_node **children;
+ node->alternatives++;
+ node->u.children = cli_realloc2(node->u.children,tree_node_get_array_size(node));
+ if(!node->u.children)
+ return NULL;
+
+ children = node->op==OP_CUSTOMCLASS ? node->u.children+1 : node->u.children;
+
+ new = tree_node_alloc(alt , node == alt );
+ if(new) {
+ new->op=OP_CHAR;
+ new->c=c;
+ }
+
+ if(node->alternatives-left-1>0)
+ memmove(&children[left+1],&children[left],(node->alternatives-left-1)*sizeof(node->u.children[0]));
+ children[left] = new;
+
+ return new;
+}
+
+static void tree_node_insert_nonbin(struct tree_node* node, struct tree_node* new)
+{
+ struct tree_node **children;
+ massert(node);
+ massert(new);
+
+ children = tree_node_get_children(node);
+ if(node->alternatives) {
+ massert(children);
+ if(children[0]->next == node) {
+ int i;
+ new->listend = 1;
+ for(i=0;i<node->alternatives;i++) {
+ children[i]->next = new;
+ children[i]->listend = 0;
+ }
+ }
+ else {
+ struct tree_node* p;
+ for(p = children[0]->next ; p->next != node ; p = p->next)
+ massert(!p->listend);
+ new->listend = 1;
+ p->listend = 0;
+ p->next = new;
+ }
+ }
+ else {
+ int idx = node->op==OP_CUSTOMCLASS ? 1 : 0;
+ if(node->u.children)
+ if(node->u.children[idx]) {
+ node = node->u.children[idx];
+ while(node->next && !node->listend)
+ node = node->next;
+ node->listend = 0;
+ new->next = node->next;
+ node->next = new;
+ new->listend=1;
+ return;
+ }
+ node->u.children = cli_realloc2(node->u.children,sizeof(node->u.children[0])*(2));
+ if(node->u.children) {
+ node->u.children[idx] = new;
+ }
+ }
+}
+
+static unsigned char char_getclass(const unsigned char* bitmap)
+{
+ size_t i;
+ massert(bitmap);
+
+ for(i=0;i<std_class_cnt;i++)
+ if(!memcmp(bitmap,char_class_bitmap[i],256>>3))
+ return i;
+ return std_class_cnt;
+}
+
+static void stack_destroy(struct node_stack* stack)
+{
+ massert(stack);
+ if(stack->data)
+ free(stack->data);
+ stack->data = NULL;
+ stack->capacity = 0;
+}
+
+/* call this after whitelist load is complete, and the tree is no longer going to be modified */
+void regex_list_cleanup(struct regex_matcher* matcher)
+{
+ massert(matcher);
+
+ stack_destroy(&matcher->node_stack);
+ stack_destroy(&matcher->node_stack_alt);
+ stack_init(&matcher->node_stack);
+ stack_init(&matcher->node_stack_alt);
+}
+
+int is_regex_ok(struct regex_matcher* matcher)
+{
+ massert(matcher);
+ return (!matcher->list_inited || matcher->list_inited!=-1);/* either we don't have a regexlist, or we initialized it successfully */
+}
+
+/* returns 0 on success, regexec error code otherwise */
+static int add_pattern(struct regex_matcher* matcher,const unsigned char* pat,const char* info, int hostonly)
+{
+ int bol=1;
+ const unsigned char* pat_end = find_regex_start(pat);
+ struct token_t token;
+ struct tree_node* node;
+
+ massert(matcher);
+
+ node = hostonly ? matcher->root_regex_hostonly : matcher->root_regex;
+
+ stack_reset(&matcher->node_stack);
+ stack_reset(&matcher->node_stack_alt);
+ stack_push(&matcher->node_stack,node);
+
+ for(;node->op!=OP_LEAF;){
+ if(pat<pat_end)
+ pat = getNextToken(pat,&token);
+ else if(*pat) {
+ token.type = TOKEN_REGEX;
+ token.u.start=pat;
+ }
+ else
+ token.type = TOKEN_DONE;
+
+ switch(token.type) {
+ case TOKEN_CHAR:
+ {
+ /* search for char in tree */
+ int left;
+ struct tree_node* newnode = tree_node_char_binsearch(node,token.u.c,&left);
+ if(newnode)
+ node = newnode;
+ else {
+ /* not found, insert it */
+ node = tree_node_char_insert(node,token.u.c,left);
+ }
+ break;
+ }
+
+ case TOKEN_PAR_OPEN:
+ stack_push(&matcher->node_stack_alt,NULL);/* marker */
+ stack_push(&matcher->node_stack,node);
+ break;
+
+ case TOKEN_PAR_CLOSE: {
+ /*TODO: test this!!!*/
+ struct tree_node* node_alt = node;
+ node = tree_node_alloc(NULL,1);
+ node->op=OP_PARCLOSE;
+ node->c=0;
+ node->listend=1;
+ tree_node_insert_nonbin(node_alt,node);
+ while (( node_alt = stack_pop(&matcher->node_stack_alt) )) {
+ tree_node_insert_nonbin(node_alt,node);
+ }
+ stack_pop(&matcher->node_stack);
+ break;
+ }
+
+ case TOKEN_ALT:
+ stack_push(&matcher->node_stack_alt,node);
+ node = stack_pop(&matcher->node_stack);
+ stack_push(&matcher->node_stack,node);
+ break;
+
+ case TOKEN_BRACKET:
+ {
+ struct tree_node* new = tree_node_alloc(tree_get_next(node),1);
+ unsigned char charclass = char_getclass(token.u.bitmap);
+ if(charclass == std_class_cnt) {/*not a std char class*/
+ new->op = OP_CUSTOMCLASS;
+ new->u.children = cli_malloc(sizeof(new->u.children[0])*2);
+ if(!new->u.children)
+ return CL_EMEM;
+ new->u.bitmap[0] = token.u.bitmap;
+ new->u.bitmap[1] = NULL;
+ tree_node_insert_nonbin(node,new);
+ node = new;
+ }
+ else {
+ new->op = OP_STDCLASS;
+ new->c = charclass;
+ tree_node_insert_nonbin(node,new);
+ node=new;
+ }
+ break;
+ }
+
+ case TOKEN_DOT:
+ {
+ struct tree_node* new = tree_node_alloc(tree_get_next(node),1);
+ new->op = OP_DOT;
+ tree_node_insert_nonbin(node,new);
+ node=new;
+ break;
+ }
+
+ case TOKEN_REGEX:
+ case TOKEN_DONE: {
+ struct leaf_info* leaf=cli_malloc(sizeof(*leaf));
+ if(!leaf)
+ return CL_EMEM;
+ leaf->info = cli_strdup(info);
+ if(token.type==TOKEN_REGEX) {
+ int rc;
+ struct tree_node* new;
+ regex_t* preg;
+ preg=cli_malloc(sizeof(*preg));
+ if(!preg)
+ return CL_EMEM;
+ rc = cli_regcomp(preg,(const char*)token.u.start,REG_EXTENDED|(bol?0:REG_NOTBOL));
+ leaf->preg=preg;
+ if(rc)
+ return rc;
+ new=cli_malloc(sizeof(*new));
+ if(!new)
+ return CL_EMEM;
+ new->op=OP_LEAF;
+ new->next=node;
+ new->alternatives=0;
+ new->u.leaf=leaf;
+ new->listend=1;
+ tree_node_insert_nonbin(node,new);
+ }
+ else {
+ leaf->preg=NULL;
+ node->alternatives=0;
+ node->u.leaf=leaf;
+ node->op=OP_LEAF;
+ }
+ return 0;
+ }
+ }
+
+ bol=0;
+ }
+ return 0;
+}
+
+/* c has to be unsigned char here!! */
+static int match_node(struct tree_node* node,const unsigned char* c,size_t len,const char** info)
+{
+ struct tree_node** children;
+ int rc;
+
+ massert(node);
+ massert(c);
+ massert(info);
+
+ if(!node->u.children)
+ return MATCH_FAILED;/* tree empty */
+ *info = NULL;
+ len++;
+ c--;
+ for(;;) {
+ massert(node);
+ children = node->u.children;
+ switch(node->op) {
+ case OP_ROOT:
+ rc=1;
+ break;
+ case OP_PARCLOSE:
+ /*this isn't a real character, so don't move*/
+ c--;
+ len++;
+ rc=1;
+ break;
+ case OP_CHAR:
+ massert(*c==node->c && "We know this has to match");
+ rc = 1;/* *c==node->c;- we know it has matched */
+ break;
+ case OP_DOT:
+ rc = *c!='\n';
+ break;
+ case OP_STDCLASS:
+ rc = char_class[*c]&(node->c);
+ break;
+ case OP_CUSTOMCLASS:
+ {
+ char_bitmap_p bitmap;
+ massert(children);
+ bitmap = (char_bitmap_p)node->u.bitmap[0];
+ children++;
+ rc = bitmap[*c>>3]&(1<<(*c&0x7));
+ break;
+ }
+ case OP_LEAF:
+ {
+ const struct leaf_info* leaf = node->u.leaf;
+ /*isleaf = 1;*/
+ if(leaf->preg) {
+ rc = !cli_regexec(leaf->preg,(const char*)c,0,NULL,0);
+ }
+ else {
+ massert(*c==node->c && "We know this has to match[2]");
+ rc = 1;
+ }
+ if(rc) {
+ *info = leaf->info;
+ return MATCH_SUCCESS;
+ }
+ break;
+ }
+ default:
+ /* impossible */
+ cli_errmsg("Encountered invalid operator in tree:%d\n",node->op);
+ exit(1);
+ }
+ len--;
+ if(!len) rc=0;
+ c++;
+ if(rc) {
+ const char csearch = *c;
+ int left = 0,right = node->alternatives-1;
+ int mid;
+ /*matched so far, go deeper*/
+ /*do a binary search between children */
+ massert(children);
+ while(left<=right) {
+ mid = left+(right-left)/2;
+ if (children[mid]->c == csearch)
+ break;
+ else if(children[mid]->c < csearch)
+ left=mid+1;
+ else
+ right=mid-1;
+ }
+ if(left<=right) {
+ node = children[mid];
+ massert(node);
+ }
+ else {
+ if(node->alternatives) {
+ if(!children[0]->listend) {
+ node = children[0];
+ c++;
+ len--;
+ }
+ while(node && node->listend) {
+ node = node->next;/* climb up */
+ c--;
+ len++;
+ }
+ if(!node || !node->next)
+ return MATCH_FAILED;/* reached root node */
+ node=node->next;
+ c--;
+ len++;
+ }
+ else if(node->u.children) {
+ struct tree_node* rewrite_next = NULL;
+ if(node->op==OP_PARCLOSE)
+ rewrite_next = node;
+ node = children[0];
+ massert(node);
+ massert(node->op!=OP_CHAR);
+ if(rewrite_next)
+ node->next = rewrite_next;/* this node is pointed to by several parent nodes,
+ we need to know
+ from which one we came, so we can find out way back
+ should we fail to match somewhere deeper*/
+ }
+ }
+ }
+ else {
+ /* this node didn't match, try sibling, or parent (if no more siblings) */
+ while(node && node->listend) {
+ node = node->next;/* sibling of parent */
+ c--;
+ len++;
+ }
+ if(!node || !node->next) /* reached root node, it has no next */
+ return MATCH_FAILED;
+ else {
+ c--;
+ len++;
+ node=node->next;
+ }
+ }
+ }
+ return MATCH_FAILED;
+}
+
+/* push node on stack, only if it isn't there already */
+static void stack_push_once(struct node_stack* stack,struct tree_node* node)
+{
+ size_t i;
+ massert(stack);
+ massert(node);
+
+ for(i=0;i < stack->cnt;i++)
+ if(stack->data[i]==node)
+ return;
+ stack_push(stack,node);
+}
+
+static void destroy_tree_internal(struct regex_matcher* matcher,struct tree_node* node)
+{
+ struct tree_node **children;
+ massert(matcher);
+ massert(node);
+
+ children = tree_node_get_children(node);
+ if(node->op==OP_LEAF) {
+ struct leaf_info* leaf = node->u.leaf;
+ if(node->next && !node->listend)
+ destroy_tree_internal(matcher,node->next);
+ stack_push_once(&matcher->node_stack,(struct tree_node*)node->u.leaf);/* cast to make compiler happy, and to not make another stack implementation for storing void* */
+ stack_push_once(&matcher->node_stack,node);
+ if(leaf->preg) {
+ cli_regfree(leaf->preg);
+ free(leaf->preg);
+ leaf->preg=NULL;
+ }
+ if(leaf->info) {
+ free(leaf->info);
+ leaf->info=NULL;
+ }
+ /* return;*/
+ }
+ if(node->alternatives) {
+ int i;
+ struct tree_node* p;
+ massert(children);
+ p = children[0]->op==OP_LEAF ? NULL : children[0]->next;
+ for(i=0;i<node->alternatives;i++)
+ destroy_tree_internal(matcher,children[i]);
+ if(p && p!=node)
+ destroy_tree_internal(matcher,p);/*?? is this ok, or without _internal?*/
+ }
+ else {
+ if(children) {
+ if(children[0])
+ destroy_tree_internal(matcher,children[0]);
+ }
+ }
+ if(node->op!=OP_LEAF && node->next && !node->listend)
+ destroy_tree_internal(matcher,node->next);
+ if(node->u.children)
+ stack_push_once(&matcher->node_stack,(struct tree_node*)node->u.children);/* cast to make compiler happy, it isn't really a tree_node* */
+ if(node->op==OP_CUSTOMCLASS && node->u.children[0]) {
+ free(node->u.children[0]);
+ node->u.children[0]=NULL;
+ }
+ stack_push_once(&matcher->node_stack,node);
+}
+
+static void destroy_tree(struct regex_matcher* matcher)
+{
+ /* we might have the same node linked by different nodes, so a recursive walk&free doesn't work in all situations,
+ * i.e. it might double-free, so instead of freeing, just push the nodes on a stack, and later free the nodes in that stack,
+ * (and push to stack only if it doesn't contain it already*/
+ massert(matcher);
+
+ stack_reset(&matcher->node_stack);
+ destroy_tree_internal(matcher,matcher->root_regex);
+ destroy_tree_internal(matcher,matcher->root_regex_hostonly);
+ while (matcher->node_stack.cnt) {
+ struct tree_node* node = stack_pop(&matcher->node_stack);
+ if(node)
+ free(node);
+ }
+}
+#ifndef NDEBUG
+static void dump_node(struct tree_node* node)
+{
+ int i;
+ struct tree_node* p,**children;
+ massert(node);
+ if(node->op==OP_LEAF) {
+ if(node->u.leaf->preg)
+ printf("n%p [label=\"regex\\nleaf\"]",(void*)node);
+ else
+ printf("n%p [label=\"%c\\nleaf\"];\n",(void*)node,node->c);
+ if(node->next && !node->listend) {
+ printf("n%p -> n%p;\n",(void*)node,(void*)node->next);
+ dump_node(node->next);
+ }
+ return;
+ }
+ printf("n%p [label=\"%c\\n%d\\nlistend:%d\"];\n",(void*)node,(node->op==OP_ROOT||node->op==OP_PARCLOSE) ?'@' :node->c,node->op,node->listend);
+ if(node->next)
+ printf("n%p -> n%p;\n",(void*)node,(void*)node->next);
+ printf("n%p -> {",(void*)node);/*using address of node as id*/
+ children = tree_node_get_children(node);
+ if(node->alternatives)
+ massert(children);
+ for(i=0;i<node->alternatives;i++)
+ printf("n%p ",(void*)children[i]);
+ if(node->alternatives && children[0]->op!=OP_LEAF)
+ for(p=children[0]->next;p!=node;p=p->next)
+ {
+ massert(p);
+ printf("n%p ",(void*)p);
+ if(p->op==OP_LEAF || p->listend)
+ break;
+ }
+ if(!node->alternatives && children && children[0])
+ printf("n%p ",(void*)children[0]);
+ printf("};\n");
+ printf("{rank=same;");
+ for(i=0;i<node->alternatives;i++)
+ printf("n%p ",(void*)node->u.children[i]);
+ if(node->alternatives && children[0]->op!=OP_LEAF)
+ for(p=children[0]->next;p!=node;p=p->next)
+ {
+ printf("n%p ",(void*)p);
+ if(p->op==OP_LEAF || p->listend)
+ break;
+ }
+ if(!node->alternatives && children && children[0])
+ printf("n%p ",(void*)children[0]);
+ printf("};\n");
+ for(i=0;i<node->alternatives;i++)
+ dump_node(children[i]);
+ if(node->alternatives && children[0]->op!=OP_LEAF)
+ for(p=children[0]->next;p!=node;p=p->next)
+ {
+ dump_node(p);
+ if(p->op==OP_LEAF || p->listend)
+ break;
+ }
+ if(!node->alternatives && children && children[0])
+ dump_node(children[0]);
+}
+
+void dump_tree(struct tree_node* root)
+{
+ /*use dot/dotty from graphviz to view it*/
+ massert(root);
+ printf("digraph tree {\n");
+ dump_node(root);
+ printf("}\n");
+}
+#endif
+
+
+#else
+/*------------------------New version of regex_list.c------------------------*/
+
+/* Regex_list.c:
+ * A scalable, trie-based implementation for matching against
+ * a list of regular expressions.
+ *
+ * A trivial way to implement matching against a list of regular expressions
+ * would have been to construct a single regular expression, by concatenating
+ * the list with the alternate (|) operator.
+ * BUT a usual DFA implementation of regular expression matching (eg.: GNU libc)
+ * leads to "state explosion" when there are many (5000+) alternate (|) operators.
+ * This is the reason for using a trie-based implementation.
+ *
+ *
+ * Design considerations:
+ *
+ * Recursive call points: there are situations when match has to be retried on a different sub-trie, or with a different repeat count.
+ * Alternate operators, and repeat/range operators (+,*,{}) are recursiv call points. When a failure is encountered during a match,
+ * the function simply returns from the recursive call, and ends up at a failure point (recursive call point).
+ *
+ * "go to parent" below actually means, return from recursive call.
+ *
+ * fail_action: we need to return to closest failure point (recursive call point),
+ * and switch current node to node pointed by fail_action
+ *
+ * Node types:
+ * OP_ROOT: contains information that applies to the entire trie.
+ * it can only appear as root node, and not as child node.
+ * On child fail: match has failed
+ * This is NOT a recursive call point
+ * OP_CHAR_BINARY_SEARCH: chooses a sub-trie, based on current character;
+ * using binary-search
+ * On fail: go to node indicated by fail_action, or if
+ * fail_action is NULL, to parent
+ * On child fail: execute fail of current node
+ * OP_ALTERNATIVES: try matching each sub-trie, if all fails execute fail
+ * action of current node. This is a recursive call point
+ * OP_CHAR_REPEAT: repeat specified character a number of times in range:
+ * [min_range, max_range];
+ * min_range: 0 for * operator
+ * 1 for + operator
+ * max_range: remaining length of current string for *,+ operator
+ * OR: min_range, max_range as specified by the {min,max} operator
+ * On fail: fail_action, or parent if NULL
+ * On child fail: reduce match repeat count, try again on child, if
+ * repeat count<min_range, execute fail of current node
+ * Also has a bitmap on what characters are accepted beyond it,
+ * as an optimizations for the case, when a maximum match isn't possible
+ * Not recomended to use this when min_range=max_range=1
+ * This is a recursive call point
+ * OP_DOT_REPEAT: like OP_CHAR_REPEAT but accept any character
+ * Not recomended to use this when min_range=max_range=1
+ * This is a recursive call point
+ * OP_GROUP_START: start of a group "(", also specifies group flags:
+ * repeat: is_repeat, min_range, max_range
+ * This is a recursive call point if is_repeat
+ * OP_GROUP_END: end of group ")"
+ * OP_STRCMP: compare with specified string,
+ * it has an array of fail actions, one for each character
+ * default fail action: go to parent
+ * This was introduced from memory- and speed-efficiency
+ * considerations.
+ * OP_CHAR_CLASS_REPEAT: match character with character class
+ * min_range, max_range
+ * For a single character class min_range=max_range=1
+ * OP_MATCH_OK: match has succeeded
+ *
+ * TODO: maybe we'll need a more efficient way to choose between character classes.
+ * OP_DOT_REPEAT/OP_CHAR_REPEAT needs a more efficient specification of its failure function, instead of using
+ * backtracking approach.
+ *
+ * The failure function/action is just for optimization, the match algorithms works even without it.
+ * TODO:In this first draft fail action will always be NULL, in a later version I'll implement fail actions too.
+ *
+ *
+ */
+
+#include <string.h>
+#include "cltypes.h"
+#include "others.h"
+
+/* offsetof is not ANSI C */
+#ifndef offsetof
+# define offsetof(type,memb) ((size_t)&((type*)0)->memb)
+#endif
+
+#define container_of(ptr, type, member) ( (type *) ((char *)ptr - offsetof(type, member)) )
+#define container_of_const(ptr, type, member) ( (type *) ((const char *)ptr - offsetof(type, member)) )
+
+enum trie_node_type {
+ OP_ROOT,
+ OP_CHAR_BINARY_SEARCH,
+ OP_ALTERNATIVES,
+ OP_CHAR_REPEAT,
+ OP_DOT_REPEAT,
+ OP_CHAR_CLASS_REPEAT,
+ OP_STRCMP,
+ OP_GROUP_START,
+ OP_GROUP_END,
+ OP_MATCH_OK
+};
+
+
+/* the comon definition of a trie node */
+struct trie_node
+{
+ enum trie_node_type type;
+};
+
+struct trie_node_match {
+ struct trie_node node;
+ /* additional match info */
+};
+
+struct trie_node_root
+{
+ struct trie_node node;
+ struct trie_node* child;
+};
+
+struct trie_node_binary_search
+{
+ struct trie_node node;
+ uint8_t children_count;/* number of children to search among -1! 255 = 256 children*/
+ struct trie_node* fail_action;
+ unsigned char* char_choices;/* children_count elements */
+ struct trie_node** children;/*children_count elements */
+};
+
+struct trie_node_alternatives
+{
+ struct trie_node node;
+ uint32_t alternatives_count;
+ /* need to support node with lots of alternatives,
+ * for a worst-case scenario where each line ends up as a sub-trie of OP_ALTERNATIVES*/
+ struct trie_node* fail_action;
+ struct trie_node** children;
+};
+
+struct trie_node_char_repeat
+{
+ struct trie_node node;
+ unsigned char character;
+ uint8_t range_min, range_max;/* according to POSIX we need not support more than 255 repetitions*/
+ struct char_bitmap* bitmap_accept_after;/* bitmap of characters accepted after this,
+ to optimize repeat < max_range case; if its NULL
+ there is no optimization*/
+ struct trie_node* child;
+ struct trie_node* fail_action;
+};
+
+struct trie_node_dot_repeat
+{
+ struct trie_node node;
+ uint8_t range_min, range_max;/* according to POSIX we need not support more than 255 repetitions*/
+ struct char_bitmap* bitmap_accept_after;/* bitmap of characters accepted after this,
+ to optimize repeat < max_range case; if its NULL
+ there is no optimization*/
+ struct trie_node* child;
+ struct trie_node* fail_action;
+};
+
+struct trie_node_group_start
+{
+ struct trie_node node;
+ uint8_t range_min, range_max;/* if range_min==range_max==1, then this is NOT a repeat, thus not a recursive call point*/
+ struct trie_node* child;
+ struct trie_node* fail_action;
+};
+
+struct trie_node_group_end
+{
+ struct trie_node node;
+ struct trie_node* child;
+};
+
+struct trie_node_strcmp
+{
+ struct trie_node node;
+ uint8_t string_length;/* for longer strings a sequence of node_strcmp should be used */
+ unsigned char* string;
+ struct trie_node* child;
+ struct trie_node** fail_actions;/* this has string_length elements, or NULL if no fail_actions are computed */
+};
+
+struct trie_node_char_class_repeat
+{
+ struct trie_node node;
+ struct char_bitmap* bitmap;
+ struct char_bitmap* bitmap_accept_after;
+ uint8_t range_min, range_max;
+ struct trie_node* child;
+ struct trie_node* fail_action;
+};
+
+static inline int bitmap_accepts(const struct char_bitmap* bitmap, const char c)
+{
+ /* TODO: check if c is accepted by bitmap */
+ return 0;
+}
+
+#define MATCH_FAILED 0
+#define MATCH_OK 1
+
+#define FAIL_ACTION( fail_node ) (*fail_action = (fail_node), MATCH_FAILED)
+
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b) ? (a) : (b))
+#endif
+
+static int match_node(const struct trie_node* node, const unsigned char* text, const unsigned char* text_end, const struct trie_node** fail_action);
+
+static int match_repeat(const unsigned char* text, const unsigned char* text_end, const size_t range_min, const size_t repeat_start,
+ const struct char_bitmap* bitmap_accept_after, const struct trie_node* child, const struct trie_node** fail_action,
+ const struct trie_node* this_fail_action)
+{
+ size_t i;
+ for(i = repeat_start;i > range_min;i--) {
+ if(!bitmap_accept_after || bitmap_accepts( bitmap_accept_after, text[i-1])) {
+ int rc = match_node(child, &text[i], text_end, fail_action);
+ /* ignore fail_action for now, we have the bitmap_accepts_after optimization */
+ if(rc) {
+ return MATCH_OK;
+ }
+ }
+ }
+ if(!range_min) {
+ /* this match is optional, try child only */
+ int rc = match_node(child, text, text_end, fail_action);
+ if(rc) {
+ return MATCH_OK;
+ }
+ }
+ return FAIL_ACTION(this_fail_action);
+}
+
+/* text_end points to \0 in text */
+static int match_node(const struct trie_node* node, const unsigned char* text, const unsigned char* text_end, const struct trie_node** fail_action)
+{
+ while(node && text < text_end) {
+ switch(node->type) {
+ case OP_ROOT:
+ {
+ const struct trie_node_root* root_node = container_of_const(node, const struct trie_node_root, node);
+ node = root_node->child;
+ break;
+ }
+ case OP_CHAR_BINARY_SEARCH:
+ {
+ const struct trie_node_binary_search* bin_node = container_of_const(node, const struct trie_node_binary_search, node);
+ const unsigned char csearch = *text;
+ size_t mid, left = 0, right = bin_node->children_count-1;
+ while(left<=right) {
+ mid = left+(right-left)/2;
+ if(bin_node->char_choices[mid] == csearch)
+ break;
+ else if(bin_node->char_choices[mid] < csearch)
+ left = mid+1;
+ else
+ right = mid-1;
+ }
+ if(left <= right) {
+ /* match successful */
+ node = bin_node->children[mid];
+ ++text;
+ }
+ else {
+ return FAIL_ACTION( bin_node->fail_action );
+ }
+ break;
+ }
+ case OP_ALTERNATIVES:
+ {
+ const struct trie_node_alternatives* alt_node = container_of_const(node, const struct trie_node_alternatives, node);
+ size_t i;
+ *fail_action = NULL;
+ for(i=0;i < alt_node->alternatives_count;i++) {
+ int rc = match_node(alt_node->children[i], text, text_end, fail_action);
+ if(rc) {
+ return MATCH_OK;
+ }
+ /* supporting fail_actions is tricky,
+ * if we just go to the node specified, what happens if the match fails, and no
+ * further fail_action is specified? We should know where to continue the search.
+ * For now fail_action isn't supported for OP_ALTERNATIVES*/
+ }
+ break;
+ }
+ case OP_CHAR_REPEAT:
+ {
+ const struct trie_node_char_repeat* char_rep_node = container_of_const(node, const struct trie_node_char_repeat, node);
+ const size_t max_len = MIN( text_end - text, char_rep_node->range_max-1);
+ /* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+ const char caccept = char_rep_node->character;
+ size_t rep;
+
+ if(max_len < char_rep_node->range_min)
+ return FAIL_ACTION(char_rep_node->fail_action);
+
+ for(rep=0;rep < max_len;rep++) {
+ if(text[rep] != caccept) {
+ break;
+ }
+ }
+
+ return match_repeat(text, text_end, char_rep_node->range_min, rep,
+ char_rep_node->bitmap_accept_after, char_rep_node->child, fail_action,
+ char_rep_node->fail_action);
+ }
+ case OP_DOT_REPEAT:
+ {
+ const struct trie_node_dot_repeat* dot_rep_node = container_of_const(node, const struct trie_node_dot_repeat, node);
+ const size_t max_len = MIN( text_end - text, dot_rep_node->range_max-1);
+ /* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+
+ if(max_len < dot_rep_node->range_min)
+ return FAIL_ACTION(dot_rep_node->fail_action);
+
+ return match_repeat(text, text_end, dot_rep_node->range_min, max_len,
+ dot_rep_node->bitmap_accept_after, dot_rep_node->child, fail_action,
+ dot_rep_node->fail_action);
+ }
+ case OP_CHAR_CLASS_REPEAT:
+ {
+ const struct trie_node_char_class_repeat* class_rep_node = container_of_const(node, const struct trie_node_char_class_repeat, node);
+ const size_t max_len = MIN( text_end - text, class_rep_node->range_max-1);
+ /* todo: what about the 8 bit limitation of range_max, and what about inf (+,*)? */
+ size_t rep;
+
+ if(max_len < class_rep_node->range_min)
+ return FAIL_ACTION(class_rep_node->fail_action);
+
+ for(rep=0;rep < max_len;rep++) {
+ if(!bitmap_accepts( class_rep_node->bitmap, text[rep])) {
+ break;
+ }
+ }
+
+ return match_repeat(text, text_end, class_rep_node->range_min, rep,
+ class_rep_node->bitmap_accept_after, class_rep_node->child, fail_action,
+ class_rep_node->fail_action);
+ break;
+ }
+ case OP_STRCMP:
+ {
+ const struct trie_node_strcmp* strcmp_node = container_of_const(node, const struct trie_node_strcmp, node);
+ size_t i;
+ if(strcmp_node->fail_actions) {
+ const size_t max_len = MIN(strcmp_node->string_length, text_end-text);
+ /* we don't use strncmp, because we need the exact match-fail point */
+ for(i=0;i < max_len;i++) {
+ if(text[i] != strcmp_node->string[i]) {
+ return FAIL_ACTION( strcmp_node->fail_actions[i] );
+ }
+ }
+ if(max_len < strcmp_node->string_length) {
+ /* failed, because text was shorter */
+ return FAIL_ACTION( strcmp_node->fail_actions[max_len] );
+ }
+ }
+ else {
+ /* no fail_actions computed, some shortcuts possible on compare */
+ if((text_end - text < strcmp_node->string_length) ||
+ strncmp((const char*)text, (const char*)strcmp_node->string, strcmp_node->string_length)) {
+
+ return FAIL_ACTION( NULL );
+ }
+ }
+ /* match successful */
+ node = strcmp_node->child;
+ text += strcmp_node->string_length;
+ break;
+ }
+ case OP_GROUP_START:
+ {
+ const struct trie_node_group_start* group_start_node = container_of_const(node, const struct trie_node_group_start, node);
+ /* TODO: implement */
+ break;
+ }
+ case OP_GROUP_END:
+ {
+ const struct trie_node_group_end* group_end_node = container_of_const(node, const struct trie_node_group_end, node);
+ /* TODO: implement */
+ break;
+ }
+ case OP_MATCH_OK:
+ {
+ return MATCH_OK;
+ }
+ }
+ }
+ /* if fail_action was NULL, or text ended*/
+ return MATCH_FAILED;
+}
+
+#endif
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regcomp.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1525 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regcomp.c 8.5 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+#include "cclass.h"
+#include "cname.h"
+
+/*
+ * parse structure, passed up and down to avoid global variables and
+ * other clumsinesses
+ */
+struct parse {
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
+ struct re_guts *g;
+# define NPAREN 10 /* we need to remember () 1-9 for back refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
+};
+
+static void p_ere(struct parse *, int);
+static void p_ere_exp(struct parse *);
+static void p_str(struct parse *);
+static void p_bre(struct parse *, int, int);
+static int p_simp_re(struct parse *, int);
+static int p_count(struct parse *);
+static void p_bracket(struct parse *);
+static void p_b_term(struct parse *, cset *);
+static void p_b_cclass(struct parse *, cset *);
+static void p_b_eclass(struct parse *, cset *);
+static char p_b_symbol(struct parse *);
+static char p_b_coll_elem(struct parse *, int);
+static char othercase(int);
+static void bothcases(struct parse *, int);
+static void ordinary(struct parse *, int);
+static void nonnewline(struct parse *);
+static void repeat(struct parse *, sopno, int, int);
+static int seterr(struct parse *, int);
+static cset *allocset(struct parse *);
+static void freeset(struct parse *, cset *);
+static int freezeset(struct parse *, cset *);
+static int firstch(struct parse *, cset *);
+static int nch(struct parse *, cset *);
+static void mcadd(struct parse *, cset *, const char *);
+static void mcinvert(struct parse *, cset *);
+static void mccase(struct parse *, cset *);
+static int isinsets(struct re_guts *, int);
+static int samesets(struct re_guts *, int, int);
+static void categorize(struct parse *, struct re_guts *);
+static sopno dupl(struct parse *, sopno, sopno);
+static void doemit(struct parse *, sop, size_t);
+static void doinsert(struct parse *, sop, size_t, sopno);
+static void dofwd(struct parse *, sopno, sop);
+static void enlarge(struct parse *, sopno);
+static void stripsnug(struct parse *, struct re_guts *);
+static void findmust(struct parse *, struct re_guts *);
+static sopno pluscount(struct parse *, struct re_guts *);
+
+static char nuls[10]; /* place to point scanner in event of error */
+
+/*
+ * macros for use with parse structure
+ * BEWARE: these know that the parse structure is named `p' !!!
+ */
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) (void)((co) || SETERROR(e))
+#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
+#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
+#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
+
+#ifdef _POSIX2_RE_DUP_MAX
+#define DUPMAX _POSIX2_RE_DUP_MAX
+#else
+#define DUPMAX 255
+#endif
+
+#ifndef NDEBUG
+static int never = 0; /* for use in asserts; shuts lint up */
+#else
+#define never 0 /* some <assert.h>s have bugs too */
+#endif
+
+/*
+ - cli_regcomp - interface for parser and compilation
+ */
+int /* 0 success, otherwise REG_something */
+cli_regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+ struct parse pa;
+ struct re_guts *g;
+ struct parse *p = &pa;
+ int i;
+ size_t len;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#endif
+
+ cflags = GOODFLAGS(cflags);
+ if ((cflags®_EXTENDED) && (cflags®_NOSPEC))
+ return(REG_INVARG);
+
+ if (cflags®_PEND) {
+ if (preg->re_endp < pattern)
+ return(REG_INVARG);
+ len = preg->re_endp - pattern;
+ } else
+ len = strlen((const char *)pattern);
+
+ /* do the mallocs early so failure handling is easy */
+ g = (struct re_guts *)cli_malloc(sizeof(struct re_guts) +
+ (NC-1)*sizeof(cat_t));
+ if (g == NULL)
+ return(REG_ESPACE);
+ p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
+ p->strip = (sop *)cli_calloc(p->ssize, sizeof(sop));
+ p->slen = 0;
+ if (p->strip == NULL) {
+ free((char *)g);
+ return(REG_ESPACE);
+ }
+
+ /* set things up */
+ p->g = g;
+ p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->end = p->next + len;
+ p->error = 0;
+ p->ncsalloc = 0;
+ for (i = 0; i < NPAREN; i++) {
+ p->pbegin[i] = 0;
+ p->pend[i] = 0;
+ }
+ g->csetsize = NC;
+ g->sets = NULL;
+ g->setbits = NULL;
+ g->ncsets = 0;
+ g->cflags = cflags;
+ g->iflags = 0;
+ g->nbol = 0;
+ g->neol = 0;
+ g->must = NULL;
+ g->mlen = 0;
+ g->nsub = 0;
+ g->ncategories = 1; /* category 0 is "everything else" */
+ g->categories = &g->catspace[-(CHAR_MIN)];
+ (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ g->backrefs = 0;
+
+ /* do it */
+ EMIT(OEND, 0);
+ g->firststate = THERE();
+ if (cflags®_EXTENDED)
+ p_ere(p, OUT);
+ else if (cflags®_NOSPEC)
+ p_str(p);
+ else
+ p_bre(p, OUT, OUT);
+ EMIT(OEND, 0);
+ g->laststate = THERE();
+
+ /* tidy up loose ends and fill things in */
+ categorize(p, g);
+ stripsnug(p, g);
+ findmust(p, g);
+ g->nplus = pluscount(p, g);
+ g->magic = MAGIC2;
+ preg->re_nsub = g->nsub;
+ preg->re_g = g;
+ preg->re_magic = MAGIC1;
+#ifndef REDEBUG
+ /* not debugging, so can't rely on the assert() in cli_regexec() */
+ if (g->iflags&BAD)
+ SETERROR(REG_ASSERT);
+#endif
+
+ /* win or lose, we're done */
+ if (p->error != 0) /* lose */
+ cli_regfree(preg);
+ return(p->error);
+}
+
+/*
+ - p_ere - ERE parser top level, concatenation and alternation
+ */
+static void
+p_ere(struct parse *p, int stop) /* character this ERE should end at */
+{
+ char c;
+ sopno prevback;
+ sopno prevfwd;
+ sopno conc;
+ int first = 1; /* is this the first alternative? */
+
+ for (;;) {
+ /* do a bunch of concatenated expressions */
+ conc = HERE();
+ while (MORE() && (c = PEEK()) != '|' && c != stop)
+ p_ere_exp(p);
+ REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+
+ if (!EAT('|'))
+ break; /* NOTE BREAK OUT */
+
+ if (first) {
+ INSERT(OCH_, conc); /* offset is wrong */
+ prevfwd = conc;
+ prevback = conc;
+ first = 0;
+ }
+ ASTERN(OOR1, prevback);
+ prevback = THERE();
+ AHEAD(prevfwd); /* fix previous offset */
+ prevfwd = HERE();
+ EMIT(OOR2, 0); /* offset is very wrong */
+ }
+
+ if (!first) { /* tail-end fixups */
+ AHEAD(prevfwd);
+ ASTERN(O_CH, prevback);
+ }
+
+ assert(!MORE() || SEE(stop));
+}
+
+/*
+ - p_ere_exp - parse one subERE, an atom possibly followed by a repetition op
+ */
+static void
+p_ere_exp(struct parse *p)
+{
+ char c;
+ sopno pos;
+ int count;
+ int count2;
+ sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+
+ pos = HERE();
+ switch (c) {
+ case '(':
+ REQUIRE(MORE(), REG_EPAREN);
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ if (!SEE(')'))
+ p_ere(p, ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ MUSTEAT(')', REG_EPAREN);
+ break;
+#ifndef POSIX_MISTAKE
+ case ')': /* happens only if no current unmatched ( */
+ /*
+ * You may ask, why the ifndef? Because I didn't notice
+ * this until slightly too late for 1003.2, and none of the
+ * other 1003.2 regular-expression reviewers noticed it at
+ * all. So an unmatched ) is legal POSIX, at least until
+ * we can get it fixed.
+ */
+ SETERROR(REG_EPAREN);
+ break;
+#endif
+ case '^':
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ wascaret = 1;
+ break;
+ case '$':
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ break;
+ case '|':
+ SETERROR(REG_EMPTY);
+ break;
+ case '*':
+ case '+':
+ case '?':
+ SETERROR(REG_BADRPT);
+ break;
+ case '.':
+ if (p->g->cflags®_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case '\\':
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = GETNEXT();
+ ordinary(p, c);
+ break;
+ case '{': /* okay as ordinary except if digit follows */
+ REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, c);
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ /* we call { a repetition if followed by a digit */
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit((uch)PEEK2())) ))
+ return; /* no repetition, we're done */
+ NEXT();
+
+ REQUIRE(!wascaret, REG_BADRPT);
+ switch (c) {
+ case '*': /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ break;
+ case '+':
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ break;
+ case '?':
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, pos); /* offset slightly wrong */
+ ASTERN(OOR1, pos); /* this one's right */
+ AHEAD(pos); /* fix the OCH_ */
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case '{':
+ count = p_count(p);
+ if (EAT(',')) {
+ if (isdigit((uch)PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EAT('}')) { /* error heuristics */
+ while (MORE() && PEEK() != '}')
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ break;
+ }
+
+ if (!MORE())
+ return;
+ c = PEEK();
+ if (!( c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
+ return;
+ SETERROR(REG_BADRPT);
+}
+
+/*
+ - p_str - string (no metacharacters) "parser"
+ */
+static void
+p_str(struct parse *p)
+{
+ REQUIRE(MORE(), REG_EMPTY);
+ while (MORE())
+ ordinary(p, GETNEXT());
+}
+
+/*
+ - p_bre - BRE parser top level, anchoring and concatenation
+ * Giving end1 as OUT essentially eliminates the end1/end2 check.
+ *
+ * This implementation is a bit of a kludge, in that a trailing $ is first
+ * taken as an ordinary character and then revised to be an anchor. The
+ * only undesirable side effect is that '$' gets included as a character
+ * category in such cases. This is fairly harmless; not worth fixing.
+ * The amount of lookahead needed to avoid this kludge is excessive.
+ */
+static void
+p_bre(struct parse *p,
+ int end1, /* first terminating character */
+ int end2) /* second terminating character */
+{
+ sopno start = HERE();
+ int first = 1; /* first subexpression? */
+ int wasdollar = 0;
+
+ if (EAT('^')) {
+ EMIT(OBOL, 0);
+ p->g->iflags |= USEBOL;
+ p->g->nbol++;
+ }
+ while (MORE() && !SEETWO(end1, end2)) {
+ wasdollar = p_simp_re(p, first);
+ first = 0;
+ }
+ if (wasdollar) { /* oops, that was a trailing anchor */
+ DROP(1);
+ EMIT(OEOL, 0);
+ p->g->iflags |= USEEOL;
+ p->g->neol++;
+ }
+
+ REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+}
+
+/*
+ - p_simp_re - parse a simple RE, an atom possibly followed by a repetition
+ */
+static int /* was the simple RE an unbackslashed $? */
+p_simp_re(struct parse *p,
+ int starordinary) /* is a leading * an ordinary character? */
+{
+ int c;
+ int count;
+ int count2;
+ sopno pos;
+ int i;
+ sopno subno;
+# define BACKSL (1<<CHAR_BIT)
+
+ pos = HERE(); /* repetion op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
+ c = GETNEXT();
+ if (c == '\\') {
+ REQUIRE(MORE(), REG_EESCAPE);
+ c = BACKSL | GETNEXT();
+ }
+ switch (c) {
+ case '.':
+ if (p->g->cflags®_NEWLINE)
+ nonnewline(p);
+ else
+ EMIT(OANY, 0);
+ break;
+ case '[':
+ p_bracket(p);
+ break;
+ case BACKSL|'{':
+ SETERROR(REG_BADRPT);
+ break;
+ case BACKSL|'(':
+ p->g->nsub++;
+ subno = p->g->nsub;
+ if (subno < NPAREN)
+ p->pbegin[subno] = HERE();
+ EMIT(OLPAREN, subno);
+ /* the MORE here is an error heuristic */
+ if (MORE() && !SEETWO('\\', ')'))
+ p_bre(p, '\\', ')');
+ if (subno < NPAREN) {
+ p->pend[subno] = HERE();
+ assert(p->pend[subno] != 0);
+ }
+ EMIT(ORPAREN, subno);
+ REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
+ break;
+ case BACKSL|')': /* should not get here -- must be user */
+ case BACKSL|'}':
+ SETERROR(REG_EPAREN);
+ break;
+ case BACKSL|'1':
+ case BACKSL|'2':
+ case BACKSL|'3':
+ case BACKSL|'4':
+ case BACKSL|'5':
+ case BACKSL|'6':
+ case BACKSL|'7':
+ case BACKSL|'8':
+ case BACKSL|'9':
+ i = (c&~BACKSL) - '0';
+ assert(i < NPAREN);
+ if (p->pend[i] != 0) {
+ assert(i <= p->g->nsub);
+ EMIT(OBACK_, i);
+ assert(p->pbegin[i] != 0);
+ assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
+ assert(OP(p->strip[p->pend[i]]) == ORPAREN);
+ (void) dupl(p, p->pbegin[i]+1, p->pend[i]);
+ EMIT(O_BACK, i);
+ } else
+ SETERROR(REG_ESUBREG);
+ p->g->backrefs = 1;
+ break;
+ case '*':
+ REQUIRE(starordinary, REG_BADRPT);
+ /* FALLTHROUGH */
+ default:
+ ordinary(p, (char)c);
+ break;
+ }
+
+ if (EAT('*')) { /* implemented as +? */
+ /* this case does not require the (y|) trick, noKLUDGE */
+ INSERT(OPLUS_, pos);
+ ASTERN(O_PLUS, pos);
+ INSERT(OQUEST_, pos);
+ ASTERN(O_QUEST, pos);
+ } else if (EATTWO('\\', '{')) {
+ count = p_count(p);
+ if (EAT(',')) {
+ if (MORE() && isdigit((uch)PEEK())) {
+ count2 = p_count(p);
+ REQUIRE(count <= count2, REG_BADBR);
+ } else /* single number with comma */
+ count2 = INFINITY;
+ } else /* just a single number */
+ count2 = count;
+ repeat(p, pos, count, count2);
+ if (!EATTWO('\\', '}')) { /* error heuristics */
+ while (MORE() && !SEETWO('\\', '}'))
+ NEXT();
+ REQUIRE(MORE(), REG_EBRACE);
+ SETERROR(REG_BADBR);
+ }
+ } else if (c == '$') /* $ (but not \$) ends it */
+ return(1);
+
+ return(0);
+}
+
+/*
+ - p_count - parse a repetition count
+ */
+static int /* the value */
+p_count(struct parse *p)
+{
+ int count = 0;
+ int ndigits = 0;
+
+ while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
+ count = count*10 + (GETNEXT() - '0');
+ ndigits++;
+ }
+
+ REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
+ return(count);
+}
+
+/*
+ - p_bracket - parse a bracketed character list
+ *
+ * Note a significant property of this code: if the allocset() did SETERROR,
+ * no set operations are done.
+ */
+static void
+p_bracket(struct parse *p)
+{
+ cset *cs;
+ int invert = 0;
+
+ /* Dept of Truly Sickening Special-Case Kludges */
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ EMIT(OBOW, 0);
+ NEXTn(6);
+ return;
+ }
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ EMIT(OEOW, 0);
+ NEXTn(6);
+ return;
+ }
+
+ if ((cs = allocset(p)) == NULL) {
+ /* allocset did set error status in p */
+ return;
+ }
+
+ if (EAT('^'))
+ invert++; /* make note to invert set at end */
+ if (EAT(']'))
+ CHadd(cs, ']');
+ else if (EAT('-'))
+ CHadd(cs, '-');
+ while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
+ p_b_term(p, cs);
+ if (EAT('-'))
+ CHadd(cs, '-');
+ MUSTEAT(']', REG_EBRACK);
+
+ if (p->error != 0) { /* don't mess things up further */
+ freeset(p, cs);
+ return;
+ }
+
+ if (p->g->cflags®_ICASE) {
+ int i;
+ int ci;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i) && isalpha(i)) {
+ ci = othercase(i);
+ if (ci != i)
+ CHadd(cs, ci);
+ }
+ if (cs->multis != NULL)
+ mccase(p, cs);
+ }
+ if (invert) {
+ int i;
+
+ for (i = p->g->csetsize - 1; i >= 0; i--)
+ if (CHIN(cs, i))
+ CHsub(cs, i);
+ else
+ CHadd(cs, i);
+ if (p->g->cflags®_NEWLINE)
+ CHsub(cs, '\n');
+ if (cs->multis != NULL)
+ mcinvert(p, cs);
+ }
+
+ assert(cs->multis == NULL); /* xxx */
+
+ if (nch(p, cs) == 1) { /* optimize singleton sets */
+ ordinary(p, firstch(p, cs));
+ freeset(p, cs);
+ } else
+ EMIT(OANYOF, freezeset(p, cs));
+}
+
+/*
+ - p_b_term - parse one term of a bracketed character list
+ */
+static void
+p_b_term(struct parse *p, cset *cs)
+{
+ char c;
+ char start, finish;
+ int i;
+
+ /* classify what we've got */
+ switch ((MORE()) ? PEEK() : '\0') {
+ case '[':
+ c = (MORE2()) ? PEEK2() : '\0';
+ break;
+ case '-':
+ SETERROR(REG_ERANGE);
+ return; /* NOTE RETURN */
+ break;
+ default:
+ c = '\0';
+ break;
+ }
+
+ switch (c) {
+ case ':': /* character class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECTYPE);
+ p_b_cclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
+ break;
+ case '=': /* equivalence class */
+ NEXT2();
+ REQUIRE(MORE(), REG_EBRACK);
+ c = PEEK();
+ REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
+ p_b_eclass(p, cs);
+ REQUIRE(MORE(), REG_EBRACK);
+ REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
+ break;
+ default: /* symbol, ordinary character, or range */
+/* xxx revision needed for multichar stuff */
+ start = p_b_symbol(p);
+ if (SEE('-') && MORE2() && PEEK2() != ']') {
+ /* range */
+ NEXT();
+ if (EAT('-'))
+ finish = '-';
+ else
+ finish = p_b_symbol(p);
+ } else
+ finish = start;
+/* xxx what about signed chars here... */
+ REQUIRE(start <= finish, REG_ERANGE);
+ for (i = start; i <= finish; i++)
+ CHadd(cs, i);
+ break;
+ }
+}
+
+/*
+ - p_b_cclass - parse a character-class name and deal with it
+ */
+static void
+p_b_cclass(struct parse *p, cset *cs)
+{
+ char *sp = p->next;
+ struct cclass *cp;
+ size_t len;
+ const char *u;
+ char c;
+
+ while (MORE() && isalpha(PEEK()))
+ NEXT();
+ len = p->next - sp;
+ for (cp = cclasses; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ break;
+ if (cp->name == NULL) {
+ /* oops, didn't find it */
+ SETERROR(REG_ECTYPE);
+ return;
+ }
+
+ u = cp->chars;
+ while ((c = *u++) != '\0')
+ CHadd(cs, c);
+ for (u = cp->multis; *u != '\0'; u += strlen(u) + 1)
+ MCadd(p, cs, u);
+}
+
+/*
+ - p_b_eclass - parse an equivalence-class name and deal with it
+ *
+ * This implementation is incomplete. xxx
+ */
+static void
+p_b_eclass(struct parse *p, cset *cs)
+{
+ char c;
+
+ c = p_b_coll_elem(p, '=');
+ CHadd(cs, c);
+}
+
+/*
+ - p_b_symbol - parse a character or [..]ed multicharacter collating symbol
+ */
+static char /* value of symbol */
+p_b_symbol(struct parse *p)
+{
+ char value;
+
+ REQUIRE(MORE(), REG_EBRACK);
+ if (!EATTWO('[', '.'))
+ return(GETNEXT());
+
+ /* collating symbol */
+ value = p_b_coll_elem(p, '.');
+ REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
+ return(value);
+}
+
+/*
+ - p_b_coll_elem - parse a collating-element name and look it up
+ */
+static char /* value of collating element */
+p_b_coll_elem(struct parse *p,
+ int endc) /* name ended by endc,']' */
+{
+ char *sp = p->next;
+ struct cname *cp;
+ int len;
+
+ while (MORE() && !SEETWO(endc, ']'))
+ NEXT();
+ if (!MORE()) {
+ SETERROR(REG_EBRACK);
+ return(0);
+ }
+ len = p->next - sp;
+ for (cp = cnames; cp->name != NULL; cp++)
+ if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
+ return(cp->code); /* known name */
+ if (len == 1)
+ return(*sp); /* single character */
+ SETERROR(REG_ECOLLATE); /* neither */
+ return(0);
+}
+
+/*
+ - othercase - return the case counterpart of an alphabetic
+ */
+static char /* if no counterpart, return ch */
+othercase(int ch)
+{
+ ch = (uch)ch;
+ assert(isalpha(ch));
+ if (isupper(ch))
+ return ((uch)tolower(ch));
+ else if (islower(ch))
+ return ((uch)toupper(ch));
+ else /* peculiar, but could happen */
+ return(ch);
+}
+
+/*
+ - bothcases - emit a dualcase version of a two-case character
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+bothcases(struct parse *p, int ch)
+{
+ char *oldnext = p->next;
+ char *oldend = p->end;
+ char bracket[3];
+
+ ch = (uch)ch;
+ assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ p->next = bracket;
+ p->end = bracket+2;
+ bracket[0] = ch;
+ bracket[1] = ']';
+ bracket[2] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+2);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - ordinary - emit an ordinary character
+ */
+static void
+ordinary(struct parse *p, int ch)
+{
+ cat_t *cap = p->g->categories;
+
+ if ((p->g->cflags®_ICASE) && isalpha((uch)ch) && othercase(ch) != ch)
+ bothcases(p, ch);
+ else {
+ EMIT(OCHAR, (uch)ch);
+ if (cap[ch] == 0)
+ cap[ch] = p->g->ncategories++;
+ }
+}
+
+/*
+ - nonnewline - emit REG_NEWLINE version of OANY
+ *
+ * Boy, is this implementation ever a kludge...
+ */
+static void
+nonnewline(struct parse *p)
+{
+ char *oldnext = p->next;
+ char *oldend = p->end;
+ char bracket[4];
+
+ p->next = bracket;
+ p->end = bracket+3;
+ bracket[0] = '^';
+ bracket[1] = '\n';
+ bracket[2] = ']';
+ bracket[3] = '\0';
+ p_bracket(p);
+ assert(p->next == bracket+3);
+ p->next = oldnext;
+ p->end = oldend;
+}
+
+/*
+ - repeat - generate code for a bounded repetition, recursively if needed
+ */
+static void
+repeat(struct parse *p,
+ sopno start, /* operand from here to end of strip */
+ int from, /* repeated from this number */
+ int to) /* to this number of times (maybe INFINITY) */
+{
+ sopno finish = HERE();
+# define N 2
+# define INF 3
+# define REP(f, t) ((f)*8 + (t))
+# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+ sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
+ return;
+
+ assert(from <= to);
+
+ switch (REP(MAP(from), MAP(to))) {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish-start); /* drop the operand */
+ break;
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start+1, 1, to);
+ ASTERN(OOR1, start);
+ AHEAD(start); /* ... fix it */
+ EMIT(OOR2, 0);
+ AHEAD(THERE());
+ ASTERN(O_CH, THERETHERE());
+ break;
+ case REP(1, 1): /* trivial case */
+ /* done */
+ break;
+ case REP(1, N): /* as x?x{1,n-1} */
+ /* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
+ INSERT(OCH_, start);
+ ASTERN(OOR1, start);
+ AHEAD(start);
+ EMIT(OOR2, 0); /* offset very wrong... */
+ AHEAD(THERE()); /* ...so fix it */
+ ASTERN(O_CH, THERETHERE());
+ copy = dupl(p, start+1, finish+1);
+ assert(copy == finish+4);
+ repeat(p, copy, 1, to-1);
+ break;
+ case REP(1, INF): /* as x+ */
+ INSERT(OPLUS_, start);
+ ASTERN(O_PLUS, start);
+ break;
+ case REP(N, N): /* as xx{m-1,n-1} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to-1);
+ break;
+ case REP(N, INF): /* as xx{n-1,INF} */
+ copy = dupl(p, start, finish);
+ repeat(p, copy, from-1, to);
+ break;
+ default: /* "can't happen" */
+ SETERROR(REG_ASSERT); /* just in case */
+ break;
+ }
+}
+
+/*
+ - seterr - set an error condition
+ */
+static int /* useless but makes type checking happy */
+seterr(struct parse *p, int e)
+{
+ if (p->error == 0) /* keep earliest error condition */
+ p->error = e;
+ p->next = nuls; /* try to bring things to a halt */
+ p->end = nuls;
+ return(0); /* make the return value well-defined */
+}
+
+/*
+ - allocset - allocate a set of characters for []
+ */
+static cset *
+allocset(struct parse *p)
+{
+ int no = p->g->ncsets++;
+ size_t nc;
+ size_t nbytes;
+ cset *cs;
+ size_t css = (size_t)p->g->csetsize;
+ int i;
+
+ if (no >= p->ncsalloc) { /* need another column of space */
+ void *ptr;
+
+ p->ncsalloc += CHAR_BIT;
+ nc = p->ncsalloc;
+ assert(nc % CHAR_BIT == 0);
+ nbytes = nc / CHAR_BIT * css;
+
+ ptr = (cset *)cli_realloc((char *)p->g->sets, nc * sizeof(cset));
+ if (ptr == NULL)
+ goto nomem;
+ p->g->sets = ptr;
+
+ ptr = (uch *)cli_realloc((char *)p->g->setbits, nbytes);
+ if (ptr == NULL)
+ goto nomem;
+ p->g->setbits = ptr;
+
+ for (i = 0; i < no; i++)
+ p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+
+ (void) memset((char *)p->g->setbits + (nbytes - css), 0, css);
+ }
+
+ cs = &p->g->sets[no];
+ cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+ cs->mask = 1 << ((no) % CHAR_BIT);
+ cs->hash = 0;
+ cs->smultis = 0;
+ cs->multis = NULL;
+
+ return(cs);
+nomem:
+ free(p->g->sets);
+ p->g->sets = NULL;
+ free(p->g->setbits);
+ p->g->setbits = NULL;
+
+ SETERROR(REG_ESPACE);
+ /* caller's responsibility not to do set ops */
+ return(NULL);
+}
+
+/*
+ - freeset - free a now-unused set
+ */
+static void
+freeset(struct parse *p, cset *cs)
+{
+ size_t i;
+ cset *top = &p->g->sets[p->g->ncsets];
+ size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ CHsub(cs, i);
+ if (cs == top-1) /* recover only the easy case */
+ p->g->ncsets--;
+}
+
+/*
+ - freezeset - final processing on a set of characters
+ *
+ * The main task here is merging identical sets. This is usually a waste
+ * of time (although the hash code minimizes the overhead), but can win
+ * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
+ * is done using addition rather than xor -- all ASCII [aA] sets xor to
+ * the same value!
+ */
+static int /* set number */
+freezeset(struct parse *p, cset *cs)
+{
+ uch h = cs->hash;
+ size_t i;
+ cset *top = &p->g->sets[p->g->ncsets];
+ cset *cs2;
+ size_t css = (size_t)p->g->csetsize;
+
+ /* look for an earlier one which is the same */
+ for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
+ if (cs2->hash == h && cs2 != cs) {
+ /* maybe */
+ for (i = 0; i < css; i++)
+ if (!!CHIN(cs2, i) != !!CHIN(cs, i))
+ break; /* no */
+ if (i == css)
+ break; /* yes */
+ }
+
+ if (cs2 < top) { /* found one */
+ freeset(p, cs);
+ cs = cs2;
+ }
+
+ return((int)(cs - p->g->sets));
+}
+
+/*
+ - firstch - return first character in a set (which must have at least one)
+ */
+static int /* character; there is no "none" value */
+firstch(struct parse *p, cset *cs)
+{
+ size_t i;
+ size_t css = (size_t)p->g->csetsize;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ return((char)i);
+ assert(never);
+ return(0); /* arbitrary */
+}
+
+/*
+ - nch - number of characters in a set
+ */
+static int
+nch(struct parse *p, cset *cs)
+{
+ size_t i;
+ size_t css = (size_t)p->g->csetsize;
+ int n = 0;
+
+ for (i = 0; i < css; i++)
+ if (CHIN(cs, i))
+ n++;
+ return(n);
+}
+
+/*
+ - mcadd - add a collating element to a cset
+ */
+static void
+mcadd( struct parse *p, cset *cs, const char *cp)
+{
+ size_t oldend = cs->smultis;
+ void *np;
+
+ cs->smultis += strlen(cp) + 1;
+ if (cs->multis == NULL)
+ np = cli_malloc(cs->smultis);
+ else
+ np = cli_realloc(cs->multis, cs->smultis);
+ if (np == NULL) {
+ if (cs->multis)
+ free(cs->multis);
+ cs->multis = NULL;
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ cs->multis = np;
+
+ cli_strlcpy(cs->multis + oldend - 1, cp, cs->smultis - oldend + 1);
+}
+
+/*
+ - mcinvert - invert the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mcinvert(struct parse *p, cset *cs)
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - mccase - add case counterparts of the list of collating elements in a cset
+ *
+ * This would have to know the set of possibilities. Implementation
+ * is deferred.
+ */
+/* ARGSUSED */
+static void
+mccase(struct parse *p, cset *cs)
+{
+ assert(cs->multis == NULL); /* xxx */
+}
+
+/*
+ - isinsets - is this character in any sets?
+ */
+static int /* predicate */
+isinsets(struct re_guts *g, int c)
+{
+ uch *col;
+ int i;
+ int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ unsigned uc = (uch)c;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc] != 0)
+ return(1);
+ return(0);
+}
+
+/*
+ - samesets - are these two characters in exactly the same sets?
+ */
+static int /* predicate */
+samesets(struct re_guts *g, int c1, int c2)
+{
+ uch *col;
+ int i;
+ int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
+ unsigned uc1 = (uch)c1;
+ unsigned uc2 = (uch)c2;
+
+ for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
+ if (col[uc1] != col[uc2])
+ return(0);
+ return(1);
+}
+
+/*
+ - categorize - sort out character categories
+ */
+static void
+categorize(struct parse *p, struct re_guts *g)
+{
+ cat_t *cats = g->categories;
+ int c;
+ int c2;
+ cat_t cat;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ for (c = CHAR_MIN; c <= CHAR_MAX; c++)
+ if (cats[c] == 0 && isinsets(g, c)) {
+ cat = g->ncategories++;
+ cats[c] = cat;
+ for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+ if (cats[c2] == 0 && samesets(g, c, c2))
+ cats[c2] = cat;
+ }
+}
+
+/*
+ - dupl - emit a duplicate of a bunch of sops
+ */
+static sopno /* start of duplicate */
+dupl(struct parse *p,
+ sopno start, /* from here */
+ sopno finish) /* to this less one */
+{
+ sopno ret = HERE();
+ sopno len = finish - start;
+
+ assert(finish >= start);
+ if (len == 0)
+ return(ret);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
+ assert(p->ssize >= p->slen + len);
+ (void) memmove((char *)(p->strip + p->slen),
+ (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ p->slen += len;
+ return(ret);
+}
+
+/*
+ - doemit - emit a strip operator
+ *
+ * It might seem better to implement this as a macro with a function as
+ * hard-case backup, but it's just too big and messy unless there are
+ * some changes to the data structures. Maybe later.
+ */
+static void
+doemit(struct parse *p, sop op, size_t opnd)
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* deal with oversize operands ("can't happen", more or less) */
+ assert(opnd < 1<<OPSHIFT);
+
+ /* deal with undersized strip */
+ if (p->slen >= p->ssize)
+ enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ assert(p->slen < p->ssize);
+
+ /* finally, it's all reduced to the easy case */
+ p->strip[p->slen++] = SOP(op, opnd);
+}
+
+/*
+ - doinsert - insert a sop into the strip
+ */
+static void
+doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
+{
+ sopno sn;
+ sop s;
+ int i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ sn = HERE();
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn+1);
+ s = p->strip[sn];
+
+ /* adjust paren pointers */
+ assert(pos > 0);
+ for (i = 1; i < NPAREN; i++) {
+ if (p->pbegin[i] >= pos) {
+ p->pbegin[i]++;
+ }
+ if (p->pend[i] >= pos) {
+ p->pend[i]++;
+ }
+ }
+
+ memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
+ (HERE()-pos-1)*sizeof(sop));
+ p->strip[pos] = s;
+}
+
+/*
+ - dofwd - complete a forward reference
+ */
+static void
+dofwd(struct parse *p, sopno pos, sop value)
+{
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ assert(value < 1<<OPSHIFT);
+ p->strip[pos] = OP(p->strip[pos]) | value;
+}
+
+/*
+ - enlarge - enlarge the strip
+ */
+static void
+enlarge(struct parse *p, sopno size)
+{
+ sop *sp;
+
+ if (p->ssize >= size)
+ return;
+
+ sp = (sop *)cli_realloc(p->strip, size*sizeof(sop));
+ if (sp == NULL) {
+ SETERROR(REG_ESPACE);
+ return;
+ }
+ p->strip = sp;
+ p->ssize = size;
+}
+
+/*
+ - stripsnug - compact the strip
+ */
+static void
+stripsnug(struct parse *p, struct re_guts *g)
+{
+ g->nstates = p->slen;
+ g->strip = (sop *)cli_realloc((char *)p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL) {
+ SETERROR(REG_ESPACE);
+ g->strip = p->strip;
+ }
+}
+
+/*
+ - findmust - fill in must and mlen with longest mandatory literal string
+ *
+ * This algorithm could do fancy things like analyzing the operands of |
+ * for common subsequences. Someday. This code is simple and finds most
+ * of the interesting cases.
+ *
+ * Note that must and mlen got initialized during setup.
+ */
+static void
+findmust(struct parse *p, struct re_guts *g)
+{
+ sop *scan;
+ sop *start;
+ sop *newstart;
+ sopno newlen;
+ sop s;
+ char *cp;
+ sopno i;
+
+ /* avoid making error situations worse */
+ if (p->error != 0)
+ return;
+
+ /* find the longest OCHAR sequence in strip */
+ newlen = 0;
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) /* new sequence */
+ newstart = scan - 1;
+ newlen++;
+ break;
+ case OPLUS_: /* things that don't break one */
+ case OLPAREN:
+ case ORPAREN:
+ break;
+ case OQUEST_: /* things that must be skipped */
+ case OCH_:
+ scan--;
+ do {
+ scan += OPND(s);
+ s = *scan;
+ /* assert() interferes w debug printouts */
+ if (OP(s) != O_QUEST && OP(s) != O_CH &&
+ OP(s) != OOR2) {
+ g->iflags |= BAD;
+ return;
+ }
+ } while (OP(s) != O_QUEST && OP(s) != O_CH);
+ /* fallthrough */
+ default: /* things that break a sequence */
+ if (newlen > g->mlen) { /* ends one */
+ start = newstart;
+ g->mlen = newlen;
+ }
+ newlen = 0;
+ break;
+ }
+ } while (OP(s) != OEND);
+
+ if (g->mlen == 0) /* there isn't one */
+ return;
+
+ /* turn it into a character string */
+ g->must = cli_malloc((size_t)g->mlen + 1);
+ if (g->must == NULL) { /* argh; just forget it */
+ g->mlen = 0;
+ return;
+ }
+ cp = g->must;
+ scan = start;
+ for (i = g->mlen; i > 0; i--) {
+ while (OP(s = *scan++) != OCHAR)
+ continue;
+ assert(cp < g->must + g->mlen);
+ *cp++ = (char)OPND(s);
+ }
+ assert(cp == g->must + g->mlen);
+ *cp++ = '\0'; /* just on general principles */
+}
+
+/*
+ - pluscount - count + nesting
+ */
+static sopno /* nesting depth */
+pluscount(struct parse *p, struct re_guts *g)
+{
+ sop *scan;
+ sop s;
+ sopno plusnest = 0;
+ sopno maxnest = 0;
+
+ if (p->error != 0)
+ return(0); /* there may not be an OEND */
+
+ scan = g->strip + 1;
+ do {
+ s = *scan++;
+ switch (OP(s)) {
+ case OPLUS_:
+ plusnest++;
+ break;
+ case O_PLUS:
+ if (plusnest > maxnest)
+ maxnest = plusnest;
+ plusnest--;
+ break;
+ }
+ } while (OP(s) != OEND);
+ if (plusnest != 0)
+ g->iflags |= BAD;
+ return(maxnest);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regerror.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,132 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regerror.c 8.4 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+
+static const char *regatoi(const regex_t *, char *, int);
+
+static struct rerr {
+ int code;
+ const char *name;
+ const char *explain;
+} rerrs[] = {
+ { REG_NOMATCH, "REG_NOMATCH", "cli_regexec() failed to match" },
+ { REG_BADPAT, "REG_BADPAT", "invalid regular expression" },
+ { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" },
+ { REG_ECTYPE, "REG_ECTYPE", "invalid character class" },
+ { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" },
+ { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" },
+ { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" },
+ { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" },
+ { REG_EBRACE, "REG_EBRACE", "braces not balanced" },
+ { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" },
+ { REG_ERANGE, "REG_ERANGE", "invalid character range" },
+ { REG_ESPACE, "REG_ESPACE", "out of memory" },
+ { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" },
+ { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" },
+ { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" },
+ { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" },
+ { 0, "", "*** unknown regexp error code ***" }
+};
+
+/*
+ - cli_regerror - the interface to error numbers
+ = extern size_t cli_regerror(int, const regex_t *, char *, size_t);
+ */
+/* ARGSUSED */
+size_t
+cli_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+ struct rerr *r;
+ size_t len;
+ int target = errcode &~ REG_ITOA;
+ const char *s;
+ char convbuf[50];
+
+ if (errcode == REG_ATOI)
+ s = regatoi(preg, convbuf, sizeof convbuf);
+ else {
+ for (r = rerrs; r->code != 0; r++)
+ if (r->code == target)
+ break;
+
+ if (errcode®_ITOA) {
+ if (r->code != 0) {
+ assert(strlen(r->name) < sizeof(convbuf));
+ (void) cli_strlcpy(convbuf, r->name, sizeof convbuf);
+ } else
+ (void)snprintf(convbuf, sizeof convbuf,
+ "REG_0x%x", target);
+ s = convbuf;
+ } else
+ s = r->explain;
+ }
+
+ len = strlen(s) + 1;
+ if (errbuf_size > 0) {
+ cli_strlcpy(errbuf, s, errbuf_size);
+ }
+
+ return(len);
+}
+
+/*
+ - regatoi - internal routine to implement REG_ATOI
+ */
+static const char *
+regatoi(const regex_t *preg, char *localbuf, int localbufsize)
+{
+ struct rerr *r;
+
+ for (r = rerrs; r->code != 0; r++)
+ if (strcmp(r->name, preg->re_endp) == 0)
+ break;
+ if (r->code == 0)
+ return("0");
+
+ (void)snprintf(localbuf, localbufsize, "%d", r->code);
+ return(localbuf);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regexec.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,162 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regexec.c 8.3 (Berkeley) 3/20/94
+ */
+
+/*
+ * the outer shell of cli_regexec()
+ *
+ * This file includes engine.c *twice*, after muchos fiddling with the
+ * macros that code uses. This lets the same code operate on two different
+ * representations for state sets.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+/* macros for manipulating states, small version */
+#define states long
+#define states1 states /* for later use in cli_regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~((unsigned long)1 << (n)))
+#define SET1(v, n) ((v) |= (unsigned long)1 << (n))
+#define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0)
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS long dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate long
+#define INIT(o, n) ((o) = (unsigned long)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) (((v) & (o)) != 0)
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0)
+/* function names */
+#define SNAMES /* engine.c looks after details */
+
+#include "engine.c"
+
+/* now undo things */
+#undef states
+#undef CLEAR
+#undef SET0
+#undef SET1
+#undef ISSET
+#undef ASSIGN
+#undef EQ
+#undef STATEVARS
+#undef STATESETUP
+#undef STATETEARDOWN
+#undef SETUP
+#undef onestate
+#undef INIT
+#undef INC
+#undef ISSTATEIN
+#undef FWD
+#undef BACK
+#undef ISSETBACK
+#undef SNAMES
+
+/* macros for manipulating states, large version */
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memmove(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS long vn; char *space
+#define STATESETUP(m, nv) { (m)->space = cli_malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate long
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
+/* some abbreviations; note that some of these know variable names! */
+/* do "if I'm here, I can also be there" etc without branches */
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
+/* function names */
+#define LNAMES /* flag */
+
+#include "engine.c"
+
+/*
+ - cli_regexec - interface for matching
+ *
+ * We put this here so we can exploit knowledge of the state representation
+ * when choosing which matcher to call. Also, by this point the matchers
+ * have been prototyped.
+ */
+int /* 0 success, REG_NOMATCH failure */
+cli_regexec(const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ struct re_guts *g = preg->re_g;
+#ifdef REDEBUG
+# define GOODFLAGS(f) (f)
+#else
+# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#endif
+
+ if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
+ return(REG_BADPAT);
+ assert(!(g->iflags&BAD));
+ if (g->iflags&BAD) /* backstop for no-debug case */
+ return(REG_BADPAT);
+ eflags = GOODFLAGS(eflags);
+
+ if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE))
+ return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+ else
+ return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_regfree.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,73 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regfree.c 8.3 (Berkeley) 3/20/94
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "others.h"
+#include "regex.h"
+
+#include "utils.h"
+#include "regex2.h"
+
+/*
+ - cli_regfree - free everything
+ */
+void
+cli_regfree(regex_t *preg)
+{
+ struct re_guts *g;
+
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
+
+ g = preg->re_g;
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
+ return;
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
+
+ if (g->strip != NULL)
+ free((char *)g->strip);
+ if (g->sets != NULL)
+ free((char *)g->sets);
+ if (g->setbits != NULL)
+ free((char *)g->setbits);
+ if (g->must != NULL)
+ free(g->must);
+ free((char *)g);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_regex_strlcpy.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,52 @@
+/*
+ * This code is derived from OpenBSD's libc, original license follows:
+ *
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "regex.h"
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+cli_strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0) {
+ while (--n != 0) {
+ if ((*d++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_rtf.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2006 Török Edwin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#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;
+ int warned;
+};
+
+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
+};
+
+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_realloc2(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) {
+ if(!stack->warned) {
+ cli_dbgmsg("Warning: attempt to pop from empty stack!\n");
+ stack->warned = 1;
+ }
+ *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; i<rtf_action_mapping_cnt; i++)
+ if(tableInsert(t, rtf_action_mapping[i].controlword, rtf_action_mapping[i].action) == -1)
+ return -1;
+ return 0;
+}
+
+static int rtf_object_begin(struct rtf_state* state,cli_ctx* ctx,const char* tmpdir)
+{
+ struct rtf_object_data* data = cli_malloc(sizeof(*data));
+ if(!data)
+ return CL_EMEM;
+ data->fd = -1;
+ data->partial = 0;
+ data->has_partial = 0;
+ data->bread = 0;
+ data->internal_state = WAIT_MAGIC;
+ data->tmpdir = tmpdir;
+ data->ctx = ctx;
+ data->name = NULL;
+ data->desc_name = NULL;
+
+ 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("RTF:Scanning embedded object:%s\n",data->name);
+ if(data->bread == 1 && data->fd > 0) {
+ 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 if(data->fd > 0)
+ ret = cli_magic_scandesc(data->fd,ctx);
+ if(data->fd > 0)
+ close(data->fd);
+ data->fd = -1;
+ 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;
+ int ret;
+
+ if(!data || !len)
+ return 0;
+
+ if(data->has_partial) {
+ for(i=0;i<len && !isxdigit(input[i]);i++)
+ ;
+ if(i<len) {
+ outdata[out_cnt++] = data->partial | hextable[input[i++]];
+ data->has_partial = 0;
+ }
+ else
+ return 0;
+ }
+ else
+ i = 0;
+
+ for(;i<len;i++) {
+ if(isxdigit(input[i])) {
+ const unsigned char byte = hextable[ input[i++] ] << 4;
+ while(i<len && !isxdigit(input[i]))
+ i++;
+ if(i == len) {
+ data->partial = 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: {
+ cli_dbgmsg("RTF: waiting for magic\n");
+ for(i=0; i<out_cnt && data->bread < 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:%lu\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; i<out_cnt && data->bread < 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 (%lu), 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;
+ cli_dbgmsg("RTF: description length:%lu\n",data->desc_len);
+ }
+ break;
+ }
+ case WAIT_DESC:{
+ cli_dbgmsg("RTF: in WAIT_DESC\n");
+ for(i=0;i<out_cnt && data->bread < data->desc_len && data->bread < 64;i++, data->bread++)
+ data->desc_name[data->bread] = out_data[i];
+ out_cnt -= i;
+ out_data += i;
+ if(data->bread < data->desc_len && data->bread < 64) {
+ cli_dbgmsg("RTF: waiting for more data(1)\n");
+ return 0;/* wait for more data */
+ }
+ data->desc_name[data->bread] = '\0';
+ if(data->desc_len - data->bread > out_cnt) {
+ data->desc_len -= out_cnt;
+ cli_dbgmsg("RTF: waiting for more data(2)\n");
+ return 0;/* wait for more data */
+ }
+ out_cnt -= data->desc_len - data->bread;
+ if(data->bread >= data->desc_len) {
+ out_data += data->desc_len - data->bread;
+ 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;
+ cli_dbgmsg("RTF: next state: wait_data_size\n");
+ data->internal_state = WAIT_DATA_SIZE;
+ }
+ break;
+ }
+
+ case WAIT_DATA_SIZE: {
+ cli_dbgmsg("RTF: in WAIT_DATA_SIZE\n");
+ if(data->bread == 0)
+ data->desc_len = 0;
+ for(i=0; i<out_cnt && data->bread < 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:%lu\n",data->desc_len);
+ if((ret = cli_gentempfd(data->tmpdir, &data->name, &data->fd)))
+ return ret;
+ data->internal_state = DUMP_DATA;
+ cli_dbgmsg("RTF: next state: DUMP_DATA\n");
+ }
+ 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 > 0) {
+ 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)
+{
+ switch(action) {
+ case RTF_OBJECT:
+ state->encounteredTopLevel |= 1<<RTF_OBJECT;
+ break;
+ case RTF_OBJECT_DATA:
+ if(state->encounteredTopLevel & (1<<RTF_OBJECT) ) {
+ state->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_data && state->cb_end)
+ state->cb_end(state,ctx);
+ }
+}
+
+
+#define SCAN_CLEANUP \
+ if(state.cb_data && state.cb_end)\
+ state.cb_end(&state,ctx);\
+ 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;
+ ssize_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.warned = 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);
+ tableDestroy(actiontable);
+ return ret;
+ }
+
+ init_rtf_state(&state);
+
+ while(( bread = cli_readn(desc, buff, BUFF_SIZE) ) > 0) {
+ 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 && state.cb_end)
+ 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) )) {
+ if(state.cb_end) {
+ 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) {
+ if(state.cb_data && state.cb_end) {/* premature end of previous block */
+ state.cb_end(&state,ctx);
+ state.cb_begin = NULL;
+ state.cb_end = NULL;
+ state.cb_data = NULL;
+ }
+ rtf_action(&state,action);
+ }
+ state.parse_state = PARSE_MAIN;
+ break;
+ }
+ }
+ }
+ }
+
+ SCAN_CLEANUP;
+ return ret;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_scanners.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,2326 @@
+/*
+ * Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+#ifndef C_WINDOWS
+#include <dirent.h>
+#include <netinet/in.h>
+#endif
+
+#if HAVE_MMAP
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#else /* HAVE_SYS_MMAN_H */
+#undef HAVE_MMAP
+#endif
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+#define DCONF_ARCH ctx->dconf->archive
+#define DCONF_DOC ctx->dconf->doc
+#define DCONF_MAIL ctx->dconf->mail
+#define DCONF_OTHER ctx->dconf->other
+
+#include "clamav.h"
+#include "others.h"
+#include "dconf.h"
+#include "scanners.h"
+#include "matcher-ac.h"
+#include "matcher-bm.h"
+#include "matcher.h"
+#include "ole2_extract.h"
+#include "vba_extract.h"
+#include "msexpand.h"
+#include "mbox.h"
+#include "chmunpack.h"
+#include "pe.h"
+#include "elf.h"
+#include "filetypes.h"
+#include "htmlnorm.h"
+#include "untar.h"
+#include "special.h"
+#include "binhex.h"
+/* #include "uuencode.h" */
+#include "tnef.h"
+#include "pst.h"
+#include "sis.h"
+#include "pdf.h"
+#include "str.h"
+#include "mspack.h"
+#include "cab.h"
+#include "rtf.h"
+#include "unarj.h"
+#include "nulsft.h"
+#include "autoit.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#include "unzip.h"
+#endif
+
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+
+#ifdef ENABLE_UNRAR
+#include "unrar_iface.h"
+#endif
+
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+#include <limits.h>
+#include <stddef.h>
+#endif
+
+#define MAX_MAIL_RECURSION 15
+
+
+static int cli_scanfile(const char *filename, cli_ctx *ctx);
+
+#ifdef ENABLE_UNRAR
+static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx *ctx, unsigned int files, uint32_t* sfx_check)
+{
+ int ret = CL_SUCCESS;
+ struct cli_meta_node* mdata;
+
+
+ if(files == 1 && sfx_check) {
+ if(*sfx_check == metadata->crc)
+ return CL_BREAK;/* break extract loop */
+ else
+ *sfx_check = metadata->crc;
+ }
+
+ cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u (max: %u)\n",
+ metadata->filename, metadata->crc, metadata->encrypted, (unsigned int) metadata->pack_size,
+ (unsigned int) metadata->unpack_size, metadata->method,
+ metadata->pack_size ? (unsigned int) (metadata->unpack_size / metadata->pack_size) : 0, ctx->limits ? ctx->limits->maxratio : 0);
+
+ /* Scan metadata */
+ mdata = ctx->engine->rar_mlist;
+ if(mdata) do {
+ if(mdata->encrypted != metadata->encrypted)
+ continue;
+
+ if(mdata->crc32 && (unsigned int) mdata->crc32 != metadata->crc)
+ continue;
+
+ if(mdata->csize > 0 && (unsigned int) mdata->csize != metadata->pack_size)
+ continue;
+
+ if(mdata->size >= 0 && (unsigned int) mdata->size != metadata->unpack_size)
+ continue;
+
+ if(mdata->method >= 0 && mdata->method != metadata->method)
+ continue;
+
+ if(mdata->fileno && mdata->fileno != files)
+ continue;
+
+ if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
+ continue;
+
+ /* TODO add support for regex */
+ /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
+ if(mdata->filename && strcmp((char *) metadata->filename, mdata->filename))
+ continue;
+
+ break; /* matched */
+
+ } while((mdata = mdata->next));
+
+ if(mdata) {
+ *ctx->virname = mdata->virname;
+ return CL_VIRUS;
+ }
+
+ if(DETECT_ENCRYPTED && metadata->encrypted) {
+ cli_dbgmsg("RAR: Encrypted files found in archive.\n");
+ lseek(desc, 0, SEEK_SET);
+ ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
+ if(ret != CL_VIRUS) {
+ *ctx->virname = "Encrypted.RAR";
+ return CL_VIRUS;
+ }
+ }
+
+/*
+ TROG - TODO: multi-volume files
+ if((rarlist->item.Flags & 0x03) != 0) {
+ cli_dbgmsg("RAR: Skipping %s (split)\n", rarlist->item.Name);
+ rarlist = rarlist->next;
+ continue;
+ }
+*/
+ return ret;
+}
+
+static int cli_unrar_checklimits(const cli_ctx *ctx, const unrar_metadata_t *metadata, unsigned int files)
+{
+ if(ctx->limits) {
+ if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) {
+ if(metadata->unpack_size / metadata->pack_size >= ctx->limits->maxratio) {
+ cli_dbgmsg("RAR: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->unpack_size / metadata->pack_size), ctx->limits->maxratio);
+ if(BLOCKMAX) {
+ *ctx->virname = "Oversized.RAR";
+ return CL_VIRUS;
+ }
+ return CL_EMAXSIZE;
+ }
+ }
+
+ if(ctx->limits->maxfilesize && (metadata->unpack_size > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("RAR: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename, (unsigned long int) metadata->unpack_size, ctx->limits->maxfilesize);
+ if(BLOCKMAX) {
+ *ctx->virname = "RAR.ExceededFileSize";
+ return CL_VIRUS;
+ }
+ return CL_EMAXSIZE;
+ }
+
+ if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+ cli_dbgmsg("RAR: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+ if(BLOCKMAX) {
+ *ctx->virname = "RAR.ExceededFilesLimit";
+ return CL_VIRUS;
+ }
+ return CL_EMAXFILES;
+ }
+ }
+
+ return CL_SUCCESS;
+}
+
+static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+ int ret = CL_CLEAN;
+ unrar_metadata_t *metadata, *metadata_tmp;
+ char *dir;
+ unrar_state_t rar_state;
+
+
+ cli_dbgmsg("in scanrar()\n");
+
+ /* generate the temporary directory */
+ dir = cli_gentemp(NULL);
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ if(sfx_offset)
+ lseek(desc, sfx_offset, SEEK_SET);
+
+ if((ret = unrar_open(desc, dir, &rar_state)) != UNRAR_OK) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ if(ret == UNRAR_EMEM)
+ return CL_EMEM;
+ else
+ return CL_ERAR;
+ }
+
+ do {
+ int rc;
+ rar_state.ofd = -1;
+ ret = unrar_extract_next_prepare(&rar_state,dir);
+ if(ret != UNRAR_OK) {
+ if(ret == UNRAR_BREAK)
+ ret = CL_BREAK;
+ else if(ret == UNRAR_EMEM)
+ ret = CL_EMEM;
+ else
+ ret = CL_ERAR;
+ break;
+ }
+ ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count);
+ if(ret && ret != CL_VIRUS) {
+ free(rar_state.file_header->filename);
+ free(rar_state.file_header);
+ ret = CL_CLEAN;
+ continue;
+ } else if(ret == CL_VIRUS) {
+ /* needed since we didn't reach unrar_extract_next to clean this up*/
+ free(rar_state.file_header->filename);
+ free(rar_state.file_header);
+ break;
+ }
+ ret = unrar_extract_next(&rar_state,dir);
+ if(ret == UNRAR_OK)
+ ret = CL_SUCCESS;
+ else if(ret == UNRAR_EMEM)
+ ret = CL_EMEM;
+ else
+ ret = CL_ERAR;
+
+ if(rar_state.ofd > 0) {
+ lseek(rar_state.ofd,0,SEEK_SET);
+ rc = cli_magic_scandesc(rar_state.ofd,ctx);
+ close(rar_state.ofd);
+ if(!cli_leavetemps_flag)
+ unlink(rar_state.filename);
+ if(rc == CL_VIRUS ) {
+ cli_dbgmsg("RAR: infected with %s\n",*ctx->virname);
+ ret = CL_VIRUS;
+ break;
+ }
+ }
+
+ if(ret == CL_SUCCESS)
+ ret = cli_unrar_scanmetadata(desc,rar_state.metadata_tail, ctx, rar_state.file_count, sfx_check);
+
+ } while(ret == CL_SUCCESS);
+
+ if(ret == CL_BREAK)
+ ret = CL_CLEAN;
+
+ metadata = metadata_tmp = rar_state.metadata;
+
+ if(cli_scandir(rar_state.comment_dir, ctx) == CL_VIRUS)
+ ret = CL_VIRUS;
+
+ unrar_close(&rar_state);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+
+ metadata = metadata_tmp;
+ while (metadata) {
+ metadata_tmp = metadata->next;
+ free(metadata->filename);
+ free(metadata);
+ metadata = metadata_tmp;
+ }
+ cli_dbgmsg("RAR: Exit code: %d\n", ret);
+
+ return ret;
+}
+#endif /* ENABLE_UNRAR */
+
+static int cli_unarj_checklimits(const cli_ctx *ctx, const arj_metadata_t *metadata, unsigned int files)
+{
+ if (ctx->limits) {
+ if (ctx->limits->maxfilesize && (metadata->orig_size > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("ARJ: %s: Size exceeded (%lu, max: %lu)\n", metadata->filename ? metadata->filename : "(none)",
+ (unsigned long int) metadata->orig_size, ctx->limits->maxfilesize);
+ if (BLOCKMAX) {
+ *ctx->virname = "ARJ.ExceededFileSize";
+ return CL_VIRUS;
+ }
+ return CL_EMAXSIZE;
+ }
+
+ if (ctx->limits->maxratio && metadata->orig_size && metadata->comp_size) {
+ if (metadata->orig_size / metadata->comp_size >= ctx->limits->maxratio) {
+ cli_dbgmsg("ARJ: Max ratio reached (%u, max: %u)\n", (unsigned int) (metadata->orig_size / metadata->comp_size), ctx->limits->maxratio);
+ if (ctx->limits->maxfilesize && (metadata->orig_size <= ctx->limits->maxfilesize)) {
+ cli_dbgmsg("ARJ: Ignoring ratio limit (file size doesn't hit limits)\n");
+ } else {
+ if(BLOCKMAX) {
+ *ctx->virname = "Oversized.ARJ";
+ return CL_VIRUS;
+ }
+ }
+ }
+ }
+
+ if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+ cli_dbgmsg("ARJ: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+ if (BLOCKMAX) {
+ *ctx->virname = "ARJ.ExceededFilesLimit";
+ return CL_VIRUS;
+ }
+ return CL_EMAXFILES;
+ }
+ }
+
+ return CL_SUCCESS;
+}
+
+static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+ int ret = CL_CLEAN, rc;
+ arj_metadata_t metadata;
+ char *dir;
+ unsigned int file_count = 1;
+
+ cli_dbgmsg("in cli_scanarj()\n");
+
+ /* generate the temporary directory */
+ dir = cli_gentemp(NULL);
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ if(sfx_offset)
+ lseek(desc, sfx_offset, SEEK_SET);
+
+ ret = cli_unarj_open(desc, dir);
+ if (ret != CL_SUCCESS) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ cli_dbgmsg("ARJ: Error: %s\n", cl_strerror(ret));
+ return ret;
+ }
+
+ metadata.filename = NULL;
+
+ do {
+ ret = cli_unarj_prepare_file(desc, dir, &metadata);
+ if (ret != CL_SUCCESS) {
+ break;
+ }
+ ret = cli_unarj_checklimits(ctx, &metadata, file_count);
+ if (ret == CL_VIRUS) {
+ break;
+ }
+ ret = cli_unarj_extract_file(desc, dir, &metadata);
+ if (metadata.ofd >= 0) {
+ lseek(metadata.ofd, 0, SEEK_SET);
+ rc = cli_magic_scandesc(metadata.ofd, ctx);
+ close(metadata.ofd);
+ if (rc == CL_VIRUS) {
+ cli_dbgmsg("ARJ: infected with %s\n",*ctx->virname);
+ ret = CL_VIRUS;
+ break;
+ }
+ }
+ if (metadata.filename) {
+ free(metadata.filename);
+ metadata.filename = NULL;
+ }
+
+ } while(ret == CL_SUCCESS);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ if (metadata.filename) {
+ free(metadata.filename);
+ }
+
+ cli_dbgmsg("ARJ: Exit code: %d\n", ret);
+ if (ret == CL_BREAK)
+ ret = CL_CLEAN;
+
+ return ret;
+}
+#ifdef HAVE_ZLIB_H
+static int cli_scanzip(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
+{
+ zip_dir *zdir;
+ zip_dirent zdirent;
+ zip_file *zfp;
+ char *tmpname = NULL, *buff;
+ int fd = -1, bytes, ret = CL_CLEAN;
+ unsigned long int size = 0;
+ unsigned int files = 0, encrypted, bfcnt;
+ struct stat source;
+ struct cli_meta_node *mdata;
+ int err;
+ uint8_t swarning = 0, fail, success;
+
+
+ cli_dbgmsg("in scanzip()\n");
+
+ if((zdir = zip_dir_open(desc, sfx_offset, &err)) == NULL) {
+ cli_dbgmsg("Zip: zip_dir_open() return code: %d\n", err);
+ /* no return with CL_EZIP due to password protected zips */
+ return CL_CLEAN;
+ }
+
+ fstat(desc, &source);
+
+ if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+ cli_dbgmsg("Zip: unable to malloc(%u)\n", FILEBUFF);
+ zip_dir_close(zdir);
+ return CL_EMEM;
+ }
+
+ while(zip_dir_read(zdir, &zdirent)) {
+ files++;
+
+ if(files == 1 && sfx_check) {
+ if(*sfx_check == zdirent.d_crc32)
+ break;
+ else
+ *sfx_check = zdirent.d_crc32;
+ }
+
+ if(!zdirent.d_name) {
+ cli_dbgmsg("Zip: zdirent.d_name == NULL\n");
+ *ctx->virname = "Suspect.Zip";
+ ret = CL_VIRUS;
+ break;
+ }
+
+ /* Bit 0: file is encrypted
+ * Bit 6: Strong encryption was used
+ * Bit 13: Encrypted central directory
+ */
+ encrypted = ((zdirent.d_flags & 0x2041) != 0);
+
+ cli_dbgmsg("Zip: %s, crc32: 0x%x, offset: %u, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u (max: %u)\n", zdirent.d_name, zdirent.d_crc32, zdirent.d_off, encrypted, zdirent.d_csize, zdirent.st_size, zdirent.d_compr, zdirent.d_csize ? (zdirent.st_size / zdirent.d_csize) : 0, ctx->limits ? ctx->limits->maxratio : 0);
+
+ if(!zdirent.st_size) {
+ if(zdirent.d_crc32) {
+ cli_dbgmsg("Zip: Broken file or modified information in local header part of archive\n");
+ *ctx->virname = "Exploit.Zip.ModifiedHeaders";
+ ret = CL_VIRUS;
+ break;
+ }
+ continue;
+ }
+
+ /* Scan metadata */
+ mdata = ctx->engine->zip_mlist;
+ if(mdata) do {
+ if(mdata->encrypted != encrypted)
+ continue;
+
+ if(mdata->crc32 && mdata->crc32 != zdirent.d_crc32)
+ continue;
+
+ if(mdata->csize > 0 && (uint32_t) mdata->csize != zdirent.d_csize)
+ continue;
+
+ if(mdata->size >= 0 && (uint32_t) mdata->size != zdirent.st_size)
+ continue;
+
+ if(mdata->method >= 0 && (uint16_t) mdata->method != zdirent.d_compr)
+ continue;
+
+ if(mdata->fileno && mdata->fileno != files)
+ continue;
+
+ if(mdata->maxdepth && ctx->arec > mdata->maxdepth)
+ continue;
+
+ /* TODO add support for regex */
+ /*if(mdata->filename && !strstr(zdirent.d_name, mdata->filename))*/
+ if(mdata->filename && strcmp(zdirent.d_name, mdata->filename))
+ continue;
+
+ break; /* matched */
+
+ } while((mdata = mdata->next));
+
+ if(mdata) {
+ *ctx->virname = mdata->virname;
+ ret = CL_VIRUS;
+ break;
+ }
+
+ /*
+ * Workaround for archives created with ICEOWS.
+ * ZZIP_DIRENT does not contain information on file type
+ * so we try to determine a directory via a filename
+ */
+ if(zdirent.d_name[strlen(zdirent.d_name) - 1] == '/') {
+ cli_dbgmsg("Zip: Directory entry with st_size != 0\n");
+ continue;
+ }
+
+ if(!zdirent.d_csize) {
+ cli_dbgmsg("Zip: Malformed file (d_csize == 0 but st_size != 0)\n");
+ *ctx->virname = "Suspect.Zip";
+ ret = CL_VIRUS;
+ break;
+ }
+
+ if(ctx->limits && ctx->limits->maxratio > 0 && ((unsigned) zdirent.st_size / (unsigned) zdirent.d_csize) >= ctx->limits->maxratio) {
+ *ctx->virname = "Oversized.Zip";
+ ret = CL_VIRUS;
+ break;
+ }
+
+ if(encrypted) {
+ if(DETECT_ENCRYPTED) {
+ cli_dbgmsg("Zip: Encrypted files found in archive.\n");
+ lseek(desc, 0, SEEK_SET);
+ ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL);
+ if(ret < 0) {
+ break;
+ } else if(ret != CL_VIRUS) {
+ *ctx->virname = "Encrypted.Zip";
+ ret = CL_VIRUS;
+ }
+ break;
+ } else continue;
+ }
+
+ if(ctx->limits) {
+ if(ctx->limits->maxfilesize && ((unsigned int) zdirent.st_size > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("Zip: %s: Size exceeded (%u, max: %lu)\n", zdirent.d_name, zdirent.st_size, ctx->limits->maxfilesize);
+ /* ret = CL_EMAXSIZE; */
+ if(BLOCKMAX) {
+ *ctx->virname = "Zip.ExceededFileSize";
+ ret = CL_VIRUS;
+ break;
+ }
+ continue; /* continue scanning */
+ }
+
+ if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+ cli_dbgmsg("Zip: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+ if(BLOCKMAX) {
+ *ctx->virname = "Zip.ExceededFilesLimit";
+ ret = CL_VIRUS;
+ break;
+ }
+ break;
+ }
+ }
+
+ if((zfp = zip_file_open(zdir, zdirent.d_name, zdirent.d_off)) == NULL) {
+ if(zdir->errcode == CL_ESUPPORT) {
+ ret = CL_ESUPPORT;
+ if(!swarning) {
+ cli_warnmsg("Not supported compression method in one or more files\n");
+ swarning = 1;
+ }
+ continue;
+ } else {
+ cli_dbgmsg("Zip: Can't open file %s\n", zdirent.d_name);
+ ret = CL_EZIP;
+ break;
+ }
+ }
+
+ bfcnt = 0;
+ success = 0;
+ while(1) {
+ fail = 0;
+
+ if((ret = cli_gentempfd(NULL, &tmpname, &fd)))
+ break;
+
+ size = 0;
+ while((bytes = zip_file_read(zfp, buff, FILEBUFF)) > 0) {
+ size += bytes;
+ if(cli_writen(fd, buff, bytes) != bytes) {
+ cli_dbgmsg("Zip: Can't write to file.\n");
+ ret = CL_EIO;
+ break;
+ }
+ }
+
+ if(!encrypted) {
+ if(size != zdirent.st_size) {
+ cli_dbgmsg("Zip: Incorrectly decompressed (%lu != %lu)\n", size, (unsigned long int) zdirent.st_size);
+ if(zfp->bf[0] == -1) {
+ ret = CL_EZIP;
+ break;
+ } else {
+ fail = 1;
+ }
+ } else {
+ cli_dbgmsg("Zip: File decompressed to %s\n", tmpname);
+ success = 1;
+ }
+ }
+
+ if(!fail) {
+ if(fsync(fd) == -1) {
+ cli_dbgmsg("Zip: fsync() failed\n");
+ ret = CL_EFSYNC;
+ break;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+ cli_dbgmsg("Zip: Infected with %s\n", *ctx->virname);
+ ret = CL_VIRUS;
+ break;
+ }
+ }
+
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ fd = -1;
+
+ if(zfp->bf[bfcnt] == -1)
+ break;
+
+ zfp->method = (uint16_t) zfp->bf[bfcnt];
+ cli_dbgmsg("Zip: Brute force mode - checking compression method %u\n", zfp->method);
+ bfcnt++;
+ }
+ zip_file_close(zfp);
+
+
+ if(!ret && !encrypted && !success) { /* brute-force decompression failed */
+ cli_dbgmsg("Zip: All attempts to decompress file failed\n");
+ ret = CL_EZIP;
+ }
+
+ if(ret)
+ break;
+ }
+
+ zip_dir_close(zdir);
+ if(fd != -1) {
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ }
+
+ free(buff);
+ return ret;
+}
+
+static int cli_scangzip(int desc, cli_ctx *ctx)
+{
+ int fd, bytes, ret = CL_CLEAN;
+ unsigned long int size = 0;
+ char *buff;
+ char *tmpname;
+ gzFile gd;
+
+
+ cli_dbgmsg("in cli_scangzip()\n");
+
+ if((gd = gzdopen(dup(desc), "rb")) == NULL) {
+ cli_dbgmsg("GZip: Can't open descriptor %d\n", desc);
+ return CL_EGZIP;
+ }
+
+ if((ret = cli_gentempfd(NULL, &tmpname, &fd))) {
+ cli_dbgmsg("GZip: Can't generate temporary file.\n");
+ gzclose(gd);
+ return ret;
+ }
+
+ if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+ cli_dbgmsg("GZip: Unable to malloc %u bytes.\n", FILEBUFF);
+ gzclose(gd);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EMEM;
+ }
+
+ while((bytes = gzread(gd, buff, FILEBUFF)) > 0) {
+ size += bytes;
+
+ if(ctx->limits)
+ if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("GZip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
+ if(BLOCKMAX) {
+ *ctx->virname = "GZip.ExceededFileSize";
+ ret = CL_VIRUS;
+ }
+ break;
+ }
+
+ if(cli_writen(fd, buff, bytes) != bytes) {
+ cli_dbgmsg("GZip: Can't write to file.\n");
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ gzclose(gd);
+ free(buff);
+ return CL_EGZIP;
+ }
+ }
+
+ free(buff);
+ gzclose(gd);
+
+ if(ret == CL_VIRUS) {
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return ret;
+ }
+
+ if(fsync(fd) == -1) {
+ cli_dbgmsg("GZip: Can't synchronise descriptor %d\n", fd);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EFSYNC;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+ cli_dbgmsg("GZip: Infected with %s\n", *ctx->virname);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_VIRUS;
+ }
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+
+ return ret;
+}
+#endif
+
+#ifdef HAVE_BZLIB_H
+
+#ifdef NOBZ2PREFIX
+#define BZ2_bzReadOpen bzReadOpen
+#define BZ2_bzReadClose bzReadClose
+#define BZ2_bzRead bzRead
+#endif
+
+static int cli_scanbzip(int desc, cli_ctx *ctx)
+{
+ int fd, bytes, ret = CL_CLEAN, bzerror = 0;
+ short memlim = 0;
+ unsigned long int size = 0;
+ char *buff;
+ FILE *fs;
+ char *tmpname;
+ BZFILE *bfd;
+
+
+ if((fs = fdopen(dup(desc), "rb")) == NULL) {
+ cli_dbgmsg("Bzip: Can't open descriptor %d.\n", desc);
+ return CL_EBZIP;
+ }
+
+ if(ctx->limits)
+ if(ctx->limits->archivememlim)
+ memlim = 1;
+
+ if((bfd = BZ2_bzReadOpen(&bzerror, fs, 0, memlim, NULL, 0)) == NULL) {
+ cli_dbgmsg("Bzip: Can't initialize bzip2 library (descriptor: %d).\n", desc);
+ fclose(fs);
+ return CL_EBZIP;
+ }
+
+ if((ret = cli_gentempfd(NULL, &tmpname, &fd))) {
+ cli_dbgmsg("Bzip: Can't generate temporary file.\n");
+ BZ2_bzReadClose(&bzerror, bfd);
+ fclose(fs);
+ return ret;
+ }
+
+ if(!(buff = (char *) cli_malloc(FILEBUFF))) {
+ cli_dbgmsg("Bzip: Unable to malloc %u bytes.\n", FILEBUFF);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ fclose(fs);
+ BZ2_bzReadClose(&bzerror, bfd);
+ return CL_EMEM;
+ }
+
+ while((bytes = BZ2_bzRead(&bzerror, bfd, buff, FILEBUFF)) > 0) {
+ size += bytes;
+
+ if(ctx->limits)
+ if(ctx->limits->maxfilesize && (size + FILEBUFF > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("Bzip: Size exceeded (stopped at %ld, max: %ld)\n", size, ctx->limits->maxfilesize);
+ if(BLOCKMAX) {
+ *ctx->virname = "BZip.ExceededFileSize";
+ ret = CL_VIRUS;
+ }
+ break;
+ }
+
+ if(cli_writen(fd, buff, bytes) != bytes) {
+ cli_dbgmsg("Bzip: Can't write to file.\n");
+ BZ2_bzReadClose(&bzerror, bfd);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ free(buff);
+ fclose(fs);
+ return CL_EGZIP;
+ }
+ }
+
+ free(buff);
+ BZ2_bzReadClose(&bzerror, bfd);
+
+ if(ret == CL_VIRUS) {
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ fclose(fs);
+ return ret;
+ }
+
+ if(fsync(fd) == -1) {
+ cli_dbgmsg("Bzip: Synchronisation failed for descriptor %d\n", fd);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ fclose(fs);
+ return CL_EFSYNC;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS ) {
+ cli_dbgmsg("Bzip: Infected with %s\n", *ctx->virname);
+ }
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ fclose(fs);
+
+ return ret;
+}
+#endif
+
+/*
+static int cli_scanszdd(int desc, cli_ctx *ctx)
+{
+ int fd, ret = CL_CLEAN, dcpy;
+ FILE *tmp = NULL, *in;
+ char *tmpname;
+
+
+ cli_dbgmsg("in cli_scanszdd()\n");
+
+ if((dcpy = dup(desc)) == -1) {
+ cli_dbgmsg("SZDD: Can't duplicate descriptor %d\n", desc);
+ return CL_EIO;
+ }
+
+ if((in = fdopen(dcpy, "rb")) == NULL) {
+ cli_dbgmsg("SZDD: Can't open descriptor %d\n", desc);
+ close(dcpy);
+ return CL_EMSCOMP;
+ }
+
+ if((tmpname = cli_gentempstream(NULL, &tmp)) == NULL) {
+ cli_dbgmsg("SZDD: Can't generate temporary file.\n");
+ fclose(in);
+ return CL_ETMPFILE;
+ }
+
+ if(cli_msexpand(in, tmp) == -1) {
+ cli_dbgmsg("SZDD: msexpand failed.\n");
+ fclose(in);
+ fclose(tmp);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EMSCOMP;
+ }
+
+ fclose(in);
+ if(fflush(tmp)) {
+ cli_dbgmsg("SZDD: fflush() failed.\n");
+ fclose(tmp);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EFSYNC;
+ }
+
+ fd = fileno(tmp);
+ lseek(fd, 0, SEEK_SET);
+ if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
+ cli_dbgmsg("SZDD: Infected with %s\n", *ctx->virname);
+ fclose(tmp);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_VIRUS;
+ }
+
+ fclose(tmp);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return ret;
+}
+*/
+
+static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
+{
+ char *tempname;
+ int ret;
+ unsigned int files = 0;
+ struct cab_archive cab;
+ struct cab_file *file;
+
+
+ cli_dbgmsg("in cli_scanmscab()\n");
+
+ if((ret = cab_open(desc, sfx_offset, &cab)))
+ return ret;
+
+ for(file = cab.files; file; file = file->next) {
+ files++;
+
+ if(ctx->limits && ctx->limits->maxfilesize && (file->length > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("CAB: %s: Size exceeded (%u, max: %lu)\n", file->name, file->length, ctx->limits->maxfilesize);
+ if(BLOCKMAX) {
+ *ctx->virname = "CAB.ExceededFileSize";
+ cab_free(&cab);
+ return CL_VIRUS;
+ }
+ continue;
+ }
+
+ if(ctx->limits && ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
+ cli_dbgmsg("CAB: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
+ cab_free(&cab);
+ if(BLOCKMAX) {
+ *ctx->virname = "CAB.ExceededFilesLimit";
+ return CL_VIRUS;
+ }
+ return CL_CLEAN;
+ }
+
+ tempname = cli_gentemp(NULL);
+ cli_dbgmsg("CAB: Extracting file %s to %s, size %u\n", file->name, tempname, file->length);
+ if((ret = cab_extract(file, tempname)))
+ cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret));
+ else
+ ret = cli_scanfile(tempname, ctx);
+
+ if(!cli_leavetemps_flag)
+ unlink(tempname);
+ free(tempname);
+ if(ret == CL_VIRUS)
+ break;
+ }
+
+ cab_free(&cab);
+ return ret;
+}
+
+int cli_scandir(const char *dirname, cli_ctx *ctx)
+{
+ DIR *dd;
+ struct dirent *dent;
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+ union {
+ struct dirent d;
+ char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+ } result;
+#endif
+ struct stat statbuf;
+ char *fname;
+
+
+ if((dd = opendir(dirname)) != NULL) {
+#ifdef HAVE_READDIR_R_3
+ while(!readdir_r(dd, &result.d, &dent) && dent) {
+#elif defined(HAVE_READDIR_R_2)
+ while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+#else
+ while((dent = readdir(dd))) {
+#endif
+#if (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+ if(dent->d_ino)
+#endif
+ {
+ if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
+ /* build the full name */
+ fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+ if(!fname) {
+ closedir(dd);
+ return CL_EMEM;
+ }
+
+ sprintf(fname, "%s/%s", dirname, dent->d_name);
+
+ /* stat the file */
+ if(lstat(fname, &statbuf) != -1) {
+ if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
+ if (cli_scandir(fname, ctx) == CL_VIRUS) {
+ free(fname);
+ closedir(dd);
+ return CL_VIRUS;
+ }
+ } else
+ if(S_ISREG(statbuf.st_mode))
+ if(cli_scanfile(fname, ctx) == CL_VIRUS) {
+ free(fname);
+ closedir(dd);
+ return CL_VIRUS;
+ }
+
+ }
+ free(fname);
+ }
+ }
+ }
+ } else {
+ cli_dbgmsg("ScanDir: Can't open directory %s.\n", dirname);
+ return CL_EOPEN;
+ }
+
+ closedir(dd);
+ return 0;
+}
+
+static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
+{
+ int ret = CL_CLEAN, i, fd, ofd, data_len;
+ vba_project_t *vba_project;
+ DIR *dd;
+ struct dirent *dent;
+#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
+ union {
+ struct dirent d;
+ char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+ } result;
+#endif
+ struct stat statbuf;
+ char *fname, *fullname;
+ unsigned char *data;
+
+
+ cli_dbgmsg("VBADir: %s\n", dirname);
+ if((vba_project = (vba_project_t *) vba56_dir_read(dirname))) {
+
+ for(i = 0; i < vba_project->count; i++) {
+ fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
+ if(!fullname) {
+ ret = CL_EMEM;
+ break;
+ }
+ sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if(fd == -1) {
+ cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
+ free(fullname);
+ ret = CL_EOPEN;
+ break;
+ }
+ free(fullname);
+ cli_dbgmsg("VBADir: Decompress VBA project '%s'\n", vba_project->name[i]);
+ data = (unsigned char *) vba_decompress(fd, vba_project->offset[i], &data_len);
+ close(fd);
+
+ if(!data) {
+ cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
+ } else {
+ if(ctx->scanned)
+ *ctx->scanned += data_len / CL_COUNT_PRECISION;
+
+ if(cli_scanbuff(data, data_len, ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
+ free(data);
+ ret = CL_VIRUS;
+ break;
+ }
+
+ free(data);
+ }
+ }
+
+ for(i = 0; i < vba_project->count; i++)
+ free(vba_project->name[i]);
+ free(vba_project->name);
+ free(vba_project->dir);
+ free(vba_project->offset);
+ free(vba_project);
+ } else if ((fullname = ppt_vba_read(dirname))) {
+ if(cli_scandir(fullname, ctx) == CL_VIRUS) {
+ ret = CL_VIRUS;
+ }
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(fullname);
+ free(fullname);
+ } else if ((vba_project = (vba_project_t *) wm_dir_read(dirname))) {
+ for (i = 0; i < vba_project->count; i++) {
+ fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
+ if(!fullname) {
+ ret = CL_EMEM;
+ break;
+ }
+ sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if(fd == -1) {
+ cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
+ free(fullname);
+ ret = CL_EOPEN;
+ break;
+ }
+ free(fullname);
+ 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]);
+ if(vba_project->length[i])
+ data = (unsigned char *) wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
+ else
+ data = NULL;
+ close(fd);
+
+ if(!data) {
+ cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
+ } else {
+ if(ctx->scanned)
+ *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
+ if(cli_scanbuff(data, vba_project->length[i], ctx->virname, ctx->engine, CL_TYPE_MSOLE2) == CL_VIRUS) {
+ free(data);
+ ret = CL_VIRUS;
+ break;
+ }
+ free(data);
+ }
+ }
+ for(i = 0; i < vba_project->count; i++)
+ free(vba_project->name[i]);
+ free(vba_project->key);
+ free(vba_project->length);
+ free(vba_project->offset);
+ free(vba_project->name);
+ free(vba_project->dir);
+ free(vba_project);
+ }
+
+ if(ret != CL_CLEAN)
+ return ret;
+
+ /* Check directory for embedded OLE objects */
+ fullname = (char *) cli_malloc(strlen(dirname) + 16);
+ if(!fullname)
+ return CL_EMEM;
+
+ sprintf(fullname, "%s/_1_Ole10Native", dirname);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ free(fullname);
+ if (fd >= 0) {
+ ofd = cli_decode_ole_object(fd, dirname);
+ if (ofd >= 0) {
+ ret = cli_scandesc(ofd, ctx, 0, 0, 0, NULL);
+ close(ofd);
+ }
+ close(fd);
+ if(ret != CL_CLEAN)
+ return ret;
+ }
+
+ if((dd = opendir(dirname)) != NULL) {
+#ifdef HAVE_READDIR_R_3
+ while(!readdir_r(dd, &result.d, &dent) && dent) {
+#elif defined(HAVE_READDIR_R_2)
+ while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+#else
+ while((dent = readdir(dd))) {
+#endif
+#if (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+ if(dent->d_ino)
+#endif
+ {
+ if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
+ /* build the full name */
+ fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+ if(!fname) {
+ ret = CL_EMEM;
+ break;
+ }
+ sprintf(fname, "%s/%s", dirname, dent->d_name);
+
+ /* stat the file */
+ if(lstat(fname, &statbuf) != -1) {
+ if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
+ if (cli_vba_scandir(fname, ctx) == CL_VIRUS) {
+ ret = CL_VIRUS;
+ free(fname);
+ break;
+ }
+ }
+ free(fname);
+ }
+ }
+ }
+ } else {
+ cli_dbgmsg("VBADir: Can't open directory %s.\n", dirname);
+ return CL_EOPEN;
+ }
+
+ closedir(dd);
+ return ret;
+}
+
+static int cli_scanhtml(int desc, cli_ctx *ctx)
+{
+ char *tempname, fullname[1024];
+ int ret=CL_CLEAN, fd;
+ struct stat sb;
+
+
+ cli_dbgmsg("in cli_scanhtml()\n");
+
+ if(fstat(desc, &sb) == -1) {
+ cli_errmsg("cli_scanhtml: fstat() failed for descriptor %d\n", desc);
+ return CL_EIO;
+ }
+
+ /* Because HTML detection is FP-prone and html_normalise_fd() needs to
+ * mmap the file don't normalise files larger than 10 MB.
+ */
+ if(sb.st_size > 10485760) {
+ cli_dbgmsg("cli_scanhtml: exiting (file larger than 10 MB)\n");
+ return CL_CLEAN;
+ }
+
+ tempname = cli_gentemp(NULL);
+ if(mkdir(tempname, 0700)) {
+ cli_errmsg("cli_scanhtml: Can't create temporary directory %s\n", tempname);
+ free(tempname);
+ return CL_ETMPDIR;
+ }
+
+ html_normalise_fd(desc, tempname, NULL, ctx->dconf);
+ snprintf(fullname, 1024, "%s/comment.html", tempname);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if (fd >= 0) {
+ ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+ close(fd);
+ }
+
+ if(ret < 0 || ret == CL_VIRUS) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+ free(tempname);
+ return ret;
+ }
+
+ if (ret == CL_CLEAN) {
+ snprintf(fullname, 1024, "%s/nocomment.html", tempname);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if (fd >= 0) {
+ ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+ close(fd);
+ }
+ }
+
+ if(ret < 0 || ret == CL_VIRUS) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+ free(tempname);
+ return ret;
+ }
+
+ if (ret == CL_CLEAN) {
+ snprintf(fullname, 1024, "%s/script.html", tempname);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if (fd >= 0) {
+ ret = cli_scandesc(fd, ctx, 0, CL_TYPE_HTML, 0, NULL);
+ close(fd);
+ }
+ }
+
+ if(ret < 0 || ret == CL_VIRUS) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+ free(tempname);
+ return ret;
+ }
+
+ if (ret == CL_CLEAN) {
+ snprintf(fullname, 1024, "%s/rfc2397", tempname);
+ ret = cli_scandir(fullname, ctx);
+ }
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+
+ free(tempname);
+ return ret;
+}
+
+static int cli_scanhtml_utf16(int desc, cli_ctx *ctx)
+{
+ char *tempname, buff[512], *decoded;
+ int ret = CL_CLEAN, fd, bytes;
+
+
+ cli_dbgmsg("in cli_scanhtml_utf16()\n");
+
+ tempname = cli_gentemp(NULL);
+ if((fd = open(tempname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+ cli_errmsg("cli_scanhtml_utf16: Can't create file %s\n", tempname);
+ free(tempname);
+ return CL_EIO;
+ }
+
+ while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+ decoded = cli_utf16toascii(buff, bytes);
+ if(decoded) {
+ if(write(fd, decoded, strlen(decoded)) == -1) {
+ cli_errmsg("cli_scanhtml_utf16: Can't write to file %s\n", tempname);
+ free(decoded);
+ unlink(tempname);
+ free(tempname);
+ close(fd);
+ return CL_EIO;
+ }
+ free(decoded);
+ }
+ }
+
+ fsync(fd);
+ lseek(fd, 0, SEEK_SET);
+ ret = cli_scanhtml(fd, ctx);
+ close(fd);
+
+ if(!cli_leavetemps_flag)
+ unlink(tempname);
+ else
+ cli_dbgmsg("cli_scanhtml_utf16: Decoded HTML data saved in %s\n", tempname);
+ free(tempname);
+
+ return ret;
+}
+
+static int cli_scanole2(int desc, cli_ctx *ctx)
+{
+ char *dir;
+ int ret = CL_CLEAN;
+
+
+ cli_dbgmsg("in cli_scanole2()\n");
+
+ /* generate the temporary directory */
+ dir = cli_gentemp(NULL);
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("OLE2: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ if((ret = cli_ole2_extract(desc, dir, ctx->limits))) {
+ cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return ret;
+ }
+
+ if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
+ if(cli_scandir(dir, ctx) == CL_VIRUS) {
+ ret = CL_VIRUS;
+ }
+ }
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return ret;
+}
+
+static int cli_scantar(int desc, cli_ctx *ctx, unsigned int posix)
+{
+ char *dir;
+ int ret = CL_CLEAN;
+
+
+ cli_dbgmsg("in cli_scantar()\n");
+
+ /* generate temporary directory */
+ dir = cli_gentemp(NULL);
+ if(mkdir(dir, 0700)) {
+ cli_errmsg("Tar: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ if((ret = cli_untar(dir, desc, posix, ctx->limits)))
+ cli_dbgmsg("Tar: %s\n", cl_strerror(ret));
+ else
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scanbinhex(int desc, cli_ctx *ctx)
+{
+ char *dir;
+ int ret = CL_CLEAN;
+
+
+ cli_dbgmsg("in cli_scanbinhex()\n");
+
+ /* generate temporary directory */
+ dir = cli_gentemp(NULL);
+
+ if(mkdir(dir, 0700)) {
+ cli_errmsg("Binhex: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ if((ret = cli_binhex(dir, desc)))
+ cli_dbgmsg("Binhex: %s\n", cl_strerror(ret));
+ else
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scanmschm(int desc, cli_ctx *ctx)
+{
+ char *tempname;
+ int ret = CL_CLEAN;
+
+
+ cli_dbgmsg("in cli_scanmschm()\n");
+
+ tempname = cli_gentemp(NULL);
+ if(mkdir(tempname, 0700)) {
+ cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
+ free(tempname);
+ return CL_ETMPDIR;
+ }
+
+ if(chm_unpack(desc, tempname))
+ ret = cli_scandir(tempname, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+
+ free(tempname);
+ return ret;
+}
+
+static int cli_scanscrenc(int desc, cli_ctx *ctx)
+{
+ char *tempname;
+ int ret = CL_CLEAN;
+
+ cli_dbgmsg("in cli_scanscrenc()\n");
+
+ tempname = cli_gentemp(NULL);
+ if(mkdir(tempname, 0700)) {
+ cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
+ free(tempname);
+ return CL_ETMPDIR;
+ }
+
+ if (html_screnc_decode(desc, tempname))
+ ret = cli_scandir(tempname, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(tempname);
+
+ free(tempname);
+ return ret;
+}
+
+static int cli_scanriff(int desc, const char **virname)
+{
+ int ret = CL_CLEAN;
+
+ if(cli_check_riff_exploit(desc) == 2) {
+ ret = CL_VIRUS;
+ *virname = "Exploit.W32.MS05-002";
+ }
+
+ return ret;
+}
+
+static int cli_scanjpeg(int desc, const char **virname)
+{
+ int ret = CL_CLEAN;
+
+ if(cli_check_jpeg_exploit(desc) == 1) {
+ ret = CL_VIRUS;
+ *virname = "Exploit.W32.MS04-028";
+ }
+
+ return ret;
+}
+
+static int cli_scancryptff(int desc, cli_ctx *ctx)
+{
+ int ret = CL_CLEAN, ndesc;
+ unsigned int length, i;
+ unsigned char *src = NULL, *dest = NULL;
+ char *tempfile;
+ struct stat sb;
+
+
+ if(fstat(desc, &sb) == -1) {
+ cli_errmsg("CryptFF: Can't fstat descriptor %d\n", desc);
+ return CL_EIO;
+ }
+
+ /* Skip the CryptFF file header */
+ if(lseek(desc, 0x10, SEEK_SET) < 0) {
+ cli_errmsg("CryptFF: Can't lseek descriptor %d\n", desc);
+ return ret;
+ }
+
+ length = sb.st_size - 0x10;
+
+ if((dest = (unsigned char *) cli_malloc(length)) == NULL) {
+ cli_dbgmsg("CryptFF: Can't allocate memory\n");
+ return CL_EMEM;
+ }
+
+ if((src = (unsigned char *) cli_malloc(length)) == NULL) {
+ cli_dbgmsg("CryptFF: Can't allocate memory\n");
+ free(dest);
+ return CL_EMEM;
+ }
+
+ if((unsigned int) read(desc, src, length) != length) {
+ cli_dbgmsg("CryptFF: Can't read from descriptor %d\n", desc);
+ free(dest);
+ free(src);
+ return CL_EIO;
+ }
+
+ for(i = 0; i < length; i++)
+ dest[i] = src[i] ^ (unsigned char) 0xff;
+
+ free(src);
+
+ tempfile = cli_gentemp(NULL);
+ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+ cli_errmsg("CryptFF: Can't create file %s\n", tempfile);
+ free(dest);
+ free(tempfile);
+ return CL_EIO;
+ }
+
+ if(write(ndesc, dest, length) == -1) {
+ cli_dbgmsg("CryptFF: Can't write to descriptor %d\n", ndesc);
+ free(dest);
+ close(ndesc);
+ free(tempfile);
+ return CL_EIO;
+ }
+
+ free(dest);
+
+ if(fsync(ndesc) == -1) {
+ cli_errmsg("CryptFF: Can't fsync descriptor %d\n", ndesc);
+ close(ndesc);
+ free(tempfile);
+ return CL_EIO;
+ }
+
+ lseek(ndesc, 0, SEEK_SET);
+
+ cli_dbgmsg("CryptFF: Scanning decrypted data\n");
+
+ if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS)
+ cli_dbgmsg("CryptFF: Infected with %s\n", *ctx->virname);
+
+ close(ndesc);
+
+ if(cli_leavetemps_flag)
+ cli_dbgmsg("CryptFF: Decompressed data saved in %s\n", tempfile);
+ else
+ unlink(tempfile);
+
+ free(tempfile);
+ return ret;
+}
+
+static int cli_scanpdf(int desc, cli_ctx *ctx)
+{
+ int ret;
+ char *dir = cli_gentemp(NULL);
+
+
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("Can't create temporary directory for PDF file %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ ret = cli_pdf(dir, desc, ctx);
+
+ if(ret == CL_CLEAN)
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scantnef(int desc, cli_ctx *ctx)
+{
+ int ret;
+ char *dir = cli_gentemp(NULL);
+
+
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("Can't create temporary directory for tnef file %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ ret = cli_tnef(dir, desc);
+
+ if(ret == CL_CLEAN)
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scanuuencoded(int desc, cli_ctx *ctx)
+{
+ int ret;
+ char *dir = cli_gentemp(NULL);
+
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("Can't create temporary directory for uuencoded file %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ ret = cli_uuencode(dir, desc);
+
+ if(ret == CL_CLEAN)
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+/* Outlook PST file */
+static int cli_scanpst(int desc, cli_ctx *ctx)
+{
+ int ret;
+ char *dir = cli_gentemp(NULL);
+
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("Can't create temporary directory for PST file %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ ret = cli_pst(dir, desc);
+
+ if(ret == CL_SUCCESS)
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scanmail(int desc, cli_ctx *ctx)
+{
+ char *dir;
+ int ret;
+
+
+ cli_dbgmsg("Starting cli_scanmail(), mrec == %u, arec == %u\n", ctx->mrec, ctx->arec);
+
+ /* generate the temporary directory */
+ dir = cli_gentemp(NULL);
+ if(mkdir(dir, 0700)) {
+ cli_dbgmsg("Mail: Can't create temporary directory %s\n", dir);
+ free(dir);
+ return CL_ETMPDIR;
+ }
+
+ /*
+ * Extract the attachments into the temporary directory
+ */
+ if((ret = cli_mbox(dir, desc, ctx))) {
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return ret;
+ }
+
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ return ret;
+}
+
+static int cli_scanembpe(int desc, cli_ctx *ctx)
+{
+ int fd, bytes, ret = CL_CLEAN;
+ unsigned long int size = 0;
+ char buff[512];
+ char *tmpname;
+
+
+ tmpname = cli_gentemp(NULL);
+ if(!tmpname)
+ return CL_EMEM;
+
+ if((fd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
+ cli_errmsg("cli_scanembpe: Can't create file %s\n", tmpname);
+ free(tmpname);
+ return CL_EIO;
+ }
+
+ while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+ size += bytes;
+
+ if(ctx->limits && ctx->limits->maxfilesize && (size + sizeof(buff) > ctx->limits->maxfilesize)) {
+ cli_dbgmsg("cli_scanembpe: Size exceeded (stopped at %lu, max: %lu)\n", size, ctx->limits->maxfilesize);
+ /* BLOCKMAX should be ignored here */
+ break;
+ }
+
+ if(cli_writen(fd, buff, bytes) != bytes) {
+ cli_dbgmsg("cli_scanembpe: Can't write to temporary file\n");
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EIO;
+ }
+ }
+
+ if(fsync(fd) == -1) {
+ cli_dbgmsg("cli_scanembpe: Can't synchronise descriptor %d\n", fd);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_EFSYNC;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+ if((ret = cli_magic_scandesc(fd, ctx)) == CL_VIRUS) {
+ cli_dbgmsg("cli_scanembpe: Infected with %s\n", *ctx->virname);
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+ return CL_VIRUS;
+ }
+
+ close(fd);
+ if(!cli_leavetemps_flag)
+ unlink(tmpname);
+ free(tmpname);
+
+ /* intentionally ignore possible errors from cli_magic_scandesc */
+ return CL_CLEAN;
+}
+
+static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg)
+{
+ int ret = CL_CLEAN, nret = CL_CLEAN;
+ uint8_t ftrec = 0, break_loop = 0;
+ struct cli_matched_type *ftoffset = NULL, *fpt;
+ uint32_t lastzip, lastrar;
+ struct cli_exe_info peinfo;
+
+
+ if(typercg) switch(type) {
+ case CL_TYPE_UNKNOWN_TEXT:
+ case CL_TYPE_MSEXE:
+ case CL_TYPE_ZIP:
+ ftrec = 1;
+ break;
+ default:
+ ftrec = 0;
+ }
+
+ if(lseek(desc, 0, SEEK_SET) < 0) {
+ cli_errmsg("cli_scanraw: lseek() failed\n");
+ return CL_EIO;
+ }
+
+ ret = cli_scandesc(desc, ctx, ftrec, type, 0, &ftoffset);
+
+ if(ret >= CL_TYPENO) {
+
+ if(type == CL_TYPE_UNKNOWN_TEXT) {
+ lseek(desc, 0, SEEK_SET);
+
+ nret = cli_scandesc(desc, ctx, 0, ret, 1, NULL);
+ if(nret == CL_VIRUS)
+ cli_dbgmsg("%s found in descriptor %d when scanning file type %u\n", *ctx->virname, desc, ret);
+ }
+
+ if(nret != CL_VIRUS && (type == CL_TYPE_MSEXE || type == CL_TYPE_ZIP)) {
+ lastzip = lastrar = 0xdeadbeef;
+ fpt = ftoffset;
+ while(fpt) {
+ switch(fpt->type) {
+ case CL_TYPE_RARSFX:
+#ifdef ENABLE_UNRAR
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_RAR)) {
+ cli_dbgmsg("RAR-SFX signature found at %u\n", (unsigned int) fpt->offset);
+ nret = cli_scanrar(desc, ctx, fpt->offset, &lastrar);
+ }
+#endif
+ break;
+
+ case CL_TYPE_ZIPSFX:
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ZIP) && fpt->offset) {
+ cli_dbgmsg("ZIP-SFX signature found at %u\n", (unsigned int) fpt->offset);
+ nret = cli_scanzip(desc, ctx, fpt->offset, &lastzip);
+ }
+ break;
+
+ case CL_TYPE_CABSFX:
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_CAB)) {
+ cli_dbgmsg("CAB-SFX signature found at %u\n", (unsigned int) fpt->offset);
+ nret = cli_scanmscab(desc, ctx, fpt->offset);
+ }
+ break;
+ case CL_TYPE_ARJSFX:
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_ARJ)) {
+ cli_dbgmsg("ARJ-SFX signature found at %u\n", (unsigned int) fpt->offset);
+ nret = cli_scanarj(desc, ctx, fpt->offset, &lastrar);
+ }
+ break;
+
+ case CL_TYPE_NULSFT:
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_NSIS) && fpt->offset > 4) {
+ cli_dbgmsg("NSIS signature found at %u\n", (unsigned int) fpt->offset-4);
+ nret = cli_scannulsft(desc, ctx, fpt->offset - 4);
+ }
+ break;
+
+ case CL_TYPE_AUTOIT:
+ if(SCAN_ARCHIVE && type == CL_TYPE_MSEXE && (DCONF_ARCH & ARCH_CONF_AUTOIT)) {
+ cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
+ nret = cli_scanautoit(desc, ctx, fpt->offset + 23);
+ }
+ break;
+
+ case CL_TYPE_MSEXE:
+ if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
+ cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
+ memset(&peinfo, 0, sizeof(struct cli_exe_info));
+ peinfo.offset = fpt->offset;
+ lseek(desc, fpt->offset, SEEK_SET);
+ if(cli_peheader(desc, &peinfo) == 0) {
+ cli_dbgmsg("*** Detected embedded PE file ***\n");
+ if(peinfo.section)
+ free(peinfo.section);
+
+ lseek(desc, fpt->offset, SEEK_SET);
+ nret = cli_scanembpe(desc, ctx);
+ break_loop = 1; /* we can stop here and other
+ * embedded executables will
+ * be found recursively
+ * through the above call
+ */
+ }
+ }
+ break;
+
+ default:
+ cli_warnmsg("cli_scanraw: Type %u not handled in fpt loop\n", fpt->type);
+ }
+
+ if(nret == CL_VIRUS || break_loop)
+ break;
+
+ fpt = fpt->next;
+ }
+ }
+
+ ret == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
+
+ if(nret != CL_VIRUS) switch(ret) {
+ case CL_TYPE_HTML:
+ if(SCAN_HTML && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_DOC & DOC_CONF_HTML))
+ nret = cli_scanhtml(desc, ctx);
+ break;
+
+ case CL_TYPE_MAIL:
+ if(SCAN_MAIL && type == CL_TYPE_UNKNOWN_TEXT && (DCONF_MAIL & MAIL_CONF_MBOX))
+ nret = cli_scanmail(desc, ctx);
+ break;
+
+ default:
+ break;
+ }
+ ret == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
+ ret = nret;
+ }
+
+ while(ftoffset) {
+ fpt = ftoffset;
+ ftoffset = ftoffset->next;
+ free(fpt);
+ }
+
+ if(ret == CL_VIRUS)
+ cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+
+ return ret;
+}
+
+int cli_magic_scandesc(int desc, cli_ctx *ctx)
+{
+ int ret = CL_CLEAN;
+ cli_file_t type;
+ struct stat sb;
+ uint8_t typercg = 1;
+
+
+ if(fstat(desc, &sb) == -1) {
+ cli_errmsg("Can't fstat descriptor %d\n", desc);
+ return CL_EIO;
+ }
+
+ if(sb.st_size <= 5) {
+ cli_dbgmsg("Small data (%u bytes)\n", (unsigned int) sb.st_size);
+ return CL_CLEAN;
+ }
+
+ if(!ctx->engine) {
+ cli_errmsg("CRITICAL: engine == NULL\n");
+ return CL_EMALFDB;
+ }
+
+ if(!ctx->options) { /* raw mode (stdin, etc.) */
+ cli_dbgmsg("Raw mode: No support for special files\n");
+ if((ret = cli_scandesc(desc, ctx, 0, 0, 0, NULL)) == CL_VIRUS)
+ cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
+ return ret;
+ }
+
+ if(SCAN_ARCHIVE && ctx->limits && ctx->limits->maxreclevel)
+ if(ctx->arec > ctx->limits->maxreclevel) {
+ cli_dbgmsg("Archive recursion limit exceeded (arec == %u).\n", ctx->arec);
+ if(BLOCKMAX) {
+ *ctx->virname = "Archive.ExceededRecursionLimit";
+ return CL_VIRUS;
+ }
+ return CL_CLEAN;
+ }
+
+ if(SCAN_MAIL)
+ if(ctx->mrec > MAX_MAIL_RECURSION) {
+ cli_dbgmsg("Mail recursion level exceeded (mrec == %u).\n", ctx->mrec);
+ /* return CL_EMAXREC; */
+ return CL_CLEAN;
+ }
+
+ lseek(desc, 0, SEEK_SET);
+ type = cli_filetype2(desc, ctx->engine);
+ lseek(desc, 0, SEEK_SET);
+
+ if(type != CL_TYPE_DATA && ctx->engine->sdb) {
+ if((ret = cli_scanraw(desc, ctx, type, 0)) == CL_VIRUS)
+ return CL_VIRUS;
+ lseek(desc, 0, SEEK_SET);
+ }
+
+ type == CL_TYPE_MAIL ? ctx->mrec++ : ctx->arec++;
+
+ switch(type) {
+ case CL_TYPE_RAR:
+#ifdef ENABLE_UNRAR
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_RAR))
+ ret = cli_scanrar(desc, ctx, 0, NULL);
+#else
+ cli_warnmsg("RAR code not compiled-in\n");
+#endif
+ break;
+
+ case CL_TYPE_ZIP:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP))
+ ret = cli_scanzip(desc, ctx, 0, NULL);
+ break;
+
+ case CL_TYPE_GZ:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_GZ))
+ ret = cli_scangzip(desc, ctx);
+ break;
+
+ case CL_TYPE_BZ:
+#ifdef HAVE_BZLIB_H
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BZ))
+ ret = cli_scanbzip(desc, ctx);
+#endif
+ break;
+ case CL_TYPE_ARJ:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ARJ))
+ ret = cli_scanarj(desc, ctx, 0, NULL);
+ break;
+
+ case CL_TYPE_NULSFT:
+ if(SCAN_ARCHIVE)
+ ret = cli_scannulsft(desc, ctx, 0);
+ break;
+
+ case CL_TYPE_AUTOIT:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
+ ret = cli_scanautoit(desc, ctx, 23);
+ break;
+/*
+ case CL_TYPE_MSSZDD:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SZDD))
+ ret = cli_scanszdd(desc, ctx);
+ break;
+*/
+ case CL_TYPE_MSCAB:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CAB))
+ ret = cli_scanmscab(desc, ctx, 0);
+ break;
+
+ case CL_TYPE_HTML:
+ if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
+ ret = cli_scanhtml(desc, ctx);
+ break;
+
+ case CL_TYPE_HTML_UTF16:
+ if(SCAN_HTML && (DCONF_DOC & DOC_CONF_HTML))
+ ret = cli_scanhtml_utf16(desc, ctx);
+ break;
+
+ case CL_TYPE_RTF:
+ if(DCONF_DOC & DOC_CONF_RTF)
+ ret = cli_scanrtf(desc, ctx);
+ break;
+
+ case CL_TYPE_MAIL:
+ if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_MBOX))
+ ret = cli_scanmail(desc, ctx);
+ break;
+
+ case CL_TYPE_TNEF:
+ if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_TNEF))
+ ret = cli_scantnef(desc, ctx);
+ break;
+
+ case CL_TYPE_UUENCODED:
+ if(DCONF_OTHER & OTHER_CONF_UUENC)
+ ret = cli_scanuuencoded(desc, ctx);
+ break;
+
+ case CL_TYPE_PST:
+ if(SCAN_MAIL && (DCONF_MAIL & MAIL_CONF_PST))
+ ret = cli_scanpst(desc, ctx);
+ break;
+
+ case CL_TYPE_MSCHM:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_CHM))
+ ret = cli_scanmschm(desc, ctx);
+ break;
+
+ case CL_TYPE_MSOLE2:
+ if(SCAN_OLE2 && (DCONF_ARCH & ARCH_CONF_OLE2))
+ ret = cli_scanole2(desc, ctx);
+ break;
+
+ case CL_TYPE_POSIX_TAR:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
+ ret = cli_scantar(desc, ctx, 1);
+ break;
+
+ case CL_TYPE_OLD_TAR:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_TAR))
+ ret = cli_scantar(desc, ctx, 0);
+ break;
+
+ case CL_TYPE_BINHEX:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_BINHEX))
+ ret = cli_scanbinhex(desc, ctx);
+ break;
+
+ case CL_TYPE_SCRENC:
+ if(DCONF_OTHER & OTHER_CONF_SCRENC)
+ ret = cli_scanscrenc(desc, ctx);
+ break;
+
+ case CL_TYPE_RIFF:
+ if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_RIFF))
+ ret = cli_scanriff(desc, ctx->virname);
+ break;
+
+ case CL_TYPE_GRAPHICS:
+ if(SCAN_ALGO && (DCONF_OTHER & OTHER_CONF_JPEG))
+ ret = cli_scanjpeg(desc, ctx->virname);
+ break;
+
+ case CL_TYPE_PDF:
+ if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
+ ret = cli_scanpdf(desc, ctx);
+ break;
+
+ case CL_TYPE_CRYPTFF:
+ if(DCONF_OTHER & OTHER_CONF_CRYPTFF)
+ ret = cli_scancryptff(desc, ctx);
+ break;
+
+ case CL_TYPE_ELF:
+ if(SCAN_ELF && ctx->dconf->elf)
+ ret = cli_scanelf(desc, ctx);
+ break;
+
+ case CL_TYPE_SIS:
+ if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_SIS))
+ ret = cli_scansis(desc, ctx);
+ break;
+
+ case CL_TYPE_DATA:
+ /* it could be a false positive and a standard DOS .COM file */
+ {
+ struct stat s;
+ if(fstat(desc, &s) == 0 && S_ISREG(s.st_mode) && s.st_size < 65536)
+ type = CL_TYPE_UNKNOWN_DATA;
+ }
+
+ case CL_TYPE_UNKNOWN_DATA:
+ ret = cli_check_mydoom_log(desc, ctx->virname);
+ break;
+
+ default:
+ break;
+ }
+
+ type == CL_TYPE_MAIL ? ctx->mrec-- : ctx->arec--;
+
+ if(type == CL_TYPE_ZIP && SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_ZIP)) {
+ if(sb.st_size > 1048576) {
+ cli_dbgmsg("cli_magic_scandesc: Not checking for embedded PEs (zip file > 1 MB)\n");
+ typercg = 0;
+ }
+ }
+
+ if(type != CL_TYPE_DATA && ret != CL_VIRUS && !ctx->engine->sdb) {
+ if(cli_scanraw(desc, ctx, type, typercg) == CL_VIRUS)
+ return CL_VIRUS;
+ }
+
+ ctx->arec++;
+ lseek(desc, 0, SEEK_SET);
+ switch(type) {
+ /* Due to performance reasons all executables were first scanned
+ * in raw mode. Now we will try to unpack them
+ */
+ case CL_TYPE_MSEXE:
+ if(SCAN_PE && ctx->dconf->pe)
+ ret = cli_scanpe(desc, ctx);
+ break;
+
+ default:
+ break;
+ }
+ ctx->arec--;
+
+ if(ret == CL_EFORMAT) {
+ cli_dbgmsg("Descriptor[%d]: %s\n", desc, cl_strerror(CL_EFORMAT));
+ return CL_CLEAN;
+ } else {
+ return ret;
+ }
+}
+
+int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
+{
+ cli_ctx ctx;
+ int rc;
+
+ memset(&ctx, '\0', sizeof(cli_ctx));
+ ctx.engine = engine;
+ ctx.virname = virname;
+ ctx.limits = limits;
+ ctx.scanned = scanned;
+ ctx.options = options;
+ ctx.found_possibly_unwanted = 0;
+ ctx.dconf = (struct cli_dconf *) engine->dconf;
+
+ rc = cli_magic_scandesc(desc, &ctx);
+ if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
+ rc = CL_VIRUS;
+ return rc;
+}
+
+static int cli_scanfile(const char *filename, cli_ctx *ctx)
+{
+ int fd, ret;
+
+ /* internal version of cl_scanfile with arec/mrec preserved */
+ if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
+ return CL_EOPEN;
+
+ ret = cli_magic_scandesc(fd, ctx);
+
+ close(fd);
+ return ret;
+}
+
+int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options)
+{
+ int fd, ret;
+
+
+ if((fd = open(filename, O_RDONLY|O_BINARY)) == -1)
+ return CL_EOPEN;
+
+ ret = cl_scandesc(fd, virname, scanned, engine, limits, options);
+ close(fd);
+
+ return ret;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_sis.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by Tomasz Kojm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#if HAVE_MMAP
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <zlib.h>
+
+#include "others.h"
+
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#else /* HAVE_SYS_MMAN_H */
+#undef HAVE_MMAP
+#endif
+
+#include "clamav.h"
+#include "scanners.h"
+#include "cltypes.h"
+#include "sis.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x) /* Convert little endian to host */
+
+static const char *langcodes[] = {
+ "", "EN", "FR", "GE", "SP", "IT", "SW", "DA", "NO", "FI", "AM",
+ "SF", "SG", "PO", "TU", "IC", "RU", "HU", "DU", "BL", "AU", "BG",
+ "AS", "NZ", "IF", "CS", "SK", "PL", "SL", "TC", "HK", "ZH", "JA",
+ "TH", "AF", "SQ", "AH", "AR", "HY", "TL", "BE", "BN", "BG", "MY",
+ "CA", "HR", "CE", "IE", "SF", "ET", "FA", "CF", "GD", "KA", "EL",
+ "CG", "GU", "HE", "HI", "IN", "GA", "SZ", "KN", "KK", "KM", "KO",
+ "LO", "LV", "LT", "MK", "MS", "ML", "MR", "MO", "MN", "NN", "BP",
+ "PA", "RO", "SR", "SI", "SO", "OS", "LS", "SH", "FS", "TA", "TE",
+ "BO", "TI", "CT", "TK", "UK", "UR", "", "VI", "CY", "ZU"
+};
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define SIS_MAX_NAME 512
+#define SIS_MAX_SIZE 134217728
+
+static char *sis_utf16_decode(const char *str, uint32_t length)
+{
+ char *decoded;
+ uint32_t i, j;
+
+
+ if(!length || length % 2) {
+ cli_dbgmsg("SIS: sis_utf16_decode: Broken filename (length == %d)\n", length);
+ return NULL;
+ }
+
+ if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
+ return NULL;
+
+ for(i = 0, j = 0; i < length; i += 2, j++) {
+ decoded[j] = str[i + 1] << 4;
+ decoded[j] += str[i];
+ if(decoded[j] == '%')
+ decoded[j] = '_';
+ }
+
+ return decoded;
+}
+
+static int sis_extract_simple(int fd, char *mfile, uint32_t length, uint32_t offset, uint16_t nlangs, uint8_t compressed, uint8_t *ifile, const char *dir, cli_ctx *ctx)
+{
+ const char *typedir = NULL;
+ char *sname = NULL, *dname = NULL, *subdir, *fname, *buff;
+ int desc, i;
+ uint8_t get_dname = 1;
+ uint32_t namelen, nameoff, filelen, fileoff, val;
+ struct stat sb;
+ uLong osize = 0;
+ uLongf csize = 0;
+
+
+ if(offset + 24 + 8 * nlangs >= length) {
+ cli_errmsg("SIS: sis_extract_simple: Broken file record\n");
+ return CL_EFORMAT;
+ }
+
+ switch(cli_readint32(mfile + offset)) {
+ case 0x00:
+ cli_dbgmsg("SIS: File type: Standard file\n");
+ typedir = "standard";
+ break;
+ case 0x01:
+ cli_dbgmsg("SIS: File type: Text file\n");
+ typedir = "text";
+ get_dname = 0;
+ break;
+ case 0x02:
+ cli_dbgmsg("SIS: File type: Component file\n");
+ typedir = "component";
+ get_dname = 0;
+ break;
+ case 0x03:
+ cli_dbgmsg("SIS: File type: Run file\n");
+ typedir = "run";
+ val = cli_readint32(mfile + offset + 4);
+ switch(val & 0xff) {
+ case 0x00:
+ cli_dbgmsg("SIS: * During installation only\n");
+ break;
+ case 0x01:
+ cli_dbgmsg("SIS: * During removal only\n");
+ break;
+ case 0x02:
+ cli_dbgmsg("SIS: * During installation and removal\n");
+ break;
+ default:
+ cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details (0x%x)\n", cli_readint32(mfile + offset + 4));
+ }
+ switch(val & 0xff00) {
+ case 0x0000:
+ break;
+ case 0x0100:
+ cli_dbgmsg("SIS: * Ends when installation finished\n");
+ break;
+ case 0x0200:
+ cli_dbgmsg("SIS: * Waits until closed before continuing\n");
+ break;
+ default:
+ cli_warnmsg("SIS: sis_extract_simple: Unknown value in file details (0x%x)\n", cli_readint32(mfile + offset + 4));
+ }
+ break;
+ case 0x04:
+ cli_dbgmsg("SIS: File type: Null file\n");
+ return CL_CLEAN;
+ case 0x05:
+ cli_dbgmsg("SIS: File type: MIME file\n");
+ return CL_CLEAN;
+ default:
+ cli_warnmsg("SIS: Unknown file type in file record\n");
+ }
+
+ /* Source name */
+ namelen = (uint32_t) cli_readint32(mfile + offset + 8);
+ if(namelen > SIS_MAX_NAME) {
+ cli_warnmsg("SIS: sis_extract_simple: Source name too long and will not be decoded\n");
+ } else {
+ nameoff = cli_readint32(mfile + offset + 12);
+ if(nameoff >= length || nameoff + namelen >= length) {
+ cli_errmsg("SIS: sis_extract_simple: Broken source name data\n");
+ return CL_EFORMAT;
+ }
+
+ if((sname = sis_utf16_decode(mfile + nameoff, namelen)))
+ cli_dbgmsg("SIS: Source name: %s\n", sname);
+ else
+ cli_warnmsg("SIS: Source name not decoded\n");
+ }
+
+ /* Destination name */
+ if(get_dname) {
+ namelen = (uint32_t) cli_readint32(mfile + offset + 16);
+ if(namelen > SIS_MAX_NAME) {
+ cli_warnmsg("SIS: sis_extract_simple: Destination name too long and will not be decoded\n");
+ } else {
+ nameoff = cli_readint32(mfile + offset + 20);
+ if(nameoff >= length || nameoff + namelen >= length) {
+ cli_errmsg("SIS: sis_extract_simple: Broken destination name data\n");
+ if(sname)
+ free(sname);
+ return CL_EFORMAT;
+ }
+
+ if((dname = sis_utf16_decode(mfile + nameoff, namelen)))
+ cli_dbgmsg("SIS: Destination name: %s\n", dname);
+ else
+ cli_warnmsg("SIS: Destination name not decoded\n");
+ }
+ }
+
+ if(!cli_leavetemps_flag) {
+ if(sname)
+ free(sname);
+ if(dname)
+ free(dname);
+ }
+
+ /* Files */
+ if(typedir) {
+ if(!(subdir = cli_malloc(strlen(dir) + strlen(typedir) + 2)))
+ return CL_EMEM;
+ sprintf(subdir, "%s/%s", dir, typedir);
+ } else {
+ if(!(subdir = cli_strdup(dir)))
+ return CL_EMEM;
+ }
+
+ if(stat(subdir, &sb) == -1) {
+ if(mkdir(subdir, 0700) == -1) {
+ free(subdir);
+ return CL_EIO;
+ }
+ }
+
+ for(i = 0; i < nlangs; i++) {
+ filelen = cli_readint32(mfile + offset + 24 + 4 * i);
+ fileoff = cli_readint32(mfile + offset + 24 + 4 * i + 4 * nlangs);
+
+ if(fileoff == length) {
+ cli_dbgmsg("SIS: Null file (installation record)\n");
+ *ifile = 1;
+ continue;
+ } else if (fileoff > length) {
+ if(!*ifile) {
+ cli_errmsg("SIS: sis_extract_simple: Broken file data (fileoff)\n");
+ free(subdir);
+ return CL_EFORMAT;
+ } else {
+ cli_dbgmsg("SIS: Null file (installation track)\n");
+ continue;
+ }
+ }
+
+ if(filelen >= length || filelen + fileoff > length) {
+ cli_errmsg("SIS: sis_extract_simple: Broken file data (filelen, fileoff)\n");
+ free(subdir);
+ return CL_EFORMAT;
+ }
+
+ if(!(fname = cli_gentemp(subdir))) {
+ free(subdir);
+ return CL_EMEM;
+ }
+
+ if(compressed) {
+ csize = (uLong) filelen;
+ filelen = cli_readint32(mfile + offset + 24 + 4 * i + 8 * nlangs);
+ osize = (uLongf) filelen;
+
+ if(!osize) {
+ cli_dbgmsg("SIS: Empty file, skipping\n");
+ free(fname);
+ continue;
+ }
+
+ cli_dbgmsg("SIS: Compressed size: %u\n", (unsigned int) csize);
+ cli_dbgmsg("SIS: Original size: %u\n", (unsigned int) osize);
+
+ if(ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize) {
+ cli_dbgmsg("SIS: Size exceeded (%u, max: %lu)\n", (unsigned int) osize, ctx->limits->maxfilesize);
+ if(BLOCKMAX) {
+ *ctx->virname = "SIS.ExceededFileSize";
+ free(subdir);
+ free(fname);
+ return CL_VIRUS;
+ }
+ /* osize is not reliable so continue */
+ }
+
+ if((osize <= 3 * csize) || (ctx->limits && ctx->limits->maxfilesize && osize > ctx->limits->maxfilesize))
+ osize = 3 * csize;
+
+ if(!(buff = cli_malloc((size_t) osize))) {
+ cli_errmsg("SIS: sis_extract_simple: Can't allocate decompression buffer\n");
+ free(subdir);
+ free(fname);
+ return CL_EIO;
+ }
+
+ if(uncompress((Bytef *) buff, &osize , (Bytef *) mfile + fileoff, csize) != Z_OK) {
+ cli_dbgmsg("SIS: sis_extract_simple: File decompression failed\n");
+ free(buff);
+ free(subdir);
+ free(fname);
+ return CL_EIO;
+ }
+
+ if(osize != (uLongf) filelen) {
+ cli_dbgmsg("SIS: WARNING: Real original size: %u\n", (unsigned int) osize);
+ filelen = (uint32_t) osize;
+ }
+
+ } else {
+ buff = mfile + fileoff;
+ }
+
+ if((desc = open(fname, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR)) == -1) {
+ cli_errmsg("SIS: sis_extract_simple: Can't create new file %s\n", fname);
+ free(subdir);
+ free(fname);
+ if(compressed)
+ free(buff);
+ return CL_EIO;
+ }
+
+ if((uint32_t) cli_writen(desc, buff, filelen) != filelen) {
+ cli_errmsg("SIS: sis_extract_simple: Can't write %d bytes to %s\n", filelen, fname);
+ free(subdir);
+ free(fname);
+ if(compressed)
+ free(buff);
+ close(desc);
+ return CL_EIO;
+ } else {
+ if(compressed)
+ cli_dbgmsg("SIS: File decompressed into %s\n", fname);
+ else
+ cli_dbgmsg("SIS: File saved into %s\n", fname);
+ }
+
+ if(close(desc) == -1) {
+ cli_errmsg("SIS: sis_extract_simple: Can't close descriptor %d\n", desc);
+ free(subdir);
+ free(fname);
+ if(compressed)
+ free(buff);
+ return CL_EIO;
+ }
+
+ free(fname);
+
+ if(compressed)
+ free(buff);
+ }
+
+ free(subdir);
+ return CL_SUCCESS;
+}
+
+int cli_scansis(int desc, cli_ctx *ctx)
+{
+ struct sis_file_hdr file_hdr;
+ struct sis_file_hdr6 file_hdr6;
+ uint8_t release = 0, compressed, ifile = 0;
+ uint16_t opts, nlangs, *langrecs, nfiles;
+ uint32_t frecord, n;
+ size_t length;
+ char *mfile = NULL, *langs, *dir;
+ struct stat sb;
+ int i, ret;
+
+
+ if(fstat(desc, &sb) == -1) {
+ cli_errmsg("SIS: fstat() failed\n");
+ return CL_EIO;
+ }
+
+ if(sb.st_size < (off_t) sizeof(struct sis_file_hdr)) {
+ cli_dbgmsg("SIS: Broken or not a SIS file (too small)\n");
+ return CL_CLEAN;
+ }
+
+ length = sb.st_size;
+
+ if(length <= SIS_MAX_SIZE) {
+ mfile = (char *) mmap(NULL, length, PROT_READ, MAP_PRIVATE, desc, 0);
+ if(mfile == MAP_FAILED) {
+ cli_errmsg("SIS: mmap() failed\n");
+ return CL_EMEM;
+ } else {
+ cli_dbgmsg("SIS: mmap'ed file\n");
+ memcpy(&file_hdr, mfile, sizeof(struct sis_file_hdr));
+ }
+ } else {
+ cli_warnmsg("SIS: File too large (> %d)\n", SIS_MAX_SIZE);
+ return CL_CLEAN;
+ }
+
+ if(EC32(file_hdr.uid3) != 0x10000419) {
+ cli_dbgmsg("SIS: Not a SIS file\n");
+ munmap(mfile, length);
+ return CL_CLEAN;
+ }
+
+ switch(EC32(file_hdr.uid2)) {
+ case 0x1000006d:
+ cli_dbgmsg("SIS: EPOC release 3, 4 or 5\n");
+ release = 3;
+ break;
+ case 0x10003a12:
+ cli_dbgmsg("SIS: EPOC release 6\n");
+ release = 6;
+ break;
+ case 0x100039ce:
+ case 0x10003a38:
+ cli_dbgmsg("SIS: Application(?)\n");
+ return CL_CLEAN;
+ default:
+ cli_warnmsg("SIS: Unknown value of UID 2 (EPOC release == 0x%x) -> not a real SIS file??\n", EC32(file_hdr.uid2));
+ munmap(mfile, length);
+ return CL_CLEAN;
+ }
+
+ /* TODO: Verify checksums (uid4 and checksum) */
+
+ /* Languages */
+ nlangs = EC16(file_hdr.nlangs);
+ cli_dbgmsg("SIS: Number of languages: %d\n", nlangs);
+
+ if(nlangs && nlangs < 100) {
+
+ if(EC32(file_hdr.plangs) >= length || EC32(file_hdr.plangs) + nlangs * 2 >= (uint32_t) sb.st_size) {
+ cli_errmsg("SIS: Broken file structure (language records)\n");
+ munmap(mfile, length);
+ return CL_EFORMAT;
+ }
+
+ if(!(langrecs = (uint16_t *) cli_malloc(nlangs * 2))) {
+ munmap(mfile, length);
+ return CL_EMEM;
+ }
+
+ memcpy(langrecs, mfile + EC32(file_hdr.plangs), nlangs * 2);
+
+ if(!(langs = (char *) cli_calloc(nlangs * 3 + 1, sizeof(char)))) {
+ munmap(mfile, length);
+ free(langrecs);
+ return CL_EMEM;
+ }
+
+ for(i = 0; i < nlangs; i++) {
+ strncat(langs, langcodes[EC16(langrecs[i]) % 98], 2);
+ if(i != nlangs - 1)
+ strncat(langs, " ", 1);
+ }
+ cli_dbgmsg("SIS: Supported languages: %s\n", langs);
+ free(langrecs);
+ free(langs);
+
+ } else {
+ cli_errmsg("SIS: Incorrect number of languages (%d)\n", nlangs);
+ munmap(mfile, length);
+ return CL_EFORMAT;
+ }
+
+ cli_dbgmsg("SIS: Offset of languages records: %d\n", EC32(file_hdr.plangs));
+
+ if(EC16(file_hdr.ilang))
+ cli_dbgmsg("SIS: Installation language: %d\n", EC16(file_hdr.ilang));
+
+ /* Requisites */
+ cli_dbgmsg("SIS: Number of requisites: %d\n", EC16(file_hdr.nreqs));
+ cli_dbgmsg("SIS: Offset of requisites records: %d\n", EC32(file_hdr.preqs));
+
+ /* Options flags */
+ opts = EC16(file_hdr.options);
+ cli_dbgmsg("SIS: Options:\n");
+ if(opts & 0x0001)
+ cli_dbgmsg("SIS: * File is in Unicode format\n");
+ if(opts & 0x0002)
+ cli_dbgmsg("SIS: * File is distributable\n");
+ if(opts & 0x0008) {
+ cli_dbgmsg("SIS: * Archived files are not compressed\n");
+ compressed = 0;
+ } else {
+ cli_dbgmsg("SIS: * Archived files are compressed\n");
+ compressed = 1;
+ }
+ if(opts & 0x0010)
+ cli_dbgmsg("SIS: * File installation shuts down all applications\n");
+
+ /* Type flags */
+ switch(EC16(file_hdr.type)) {
+ case 0x0000:
+ cli_dbgmsg("SIS: Type: Contains an application\n");
+ break;
+ case 0x0001:
+ cli_dbgmsg("SIS: Type: Contains a shared/system component\n");
+ break;
+ case 0x0002:
+ cli_dbgmsg("SIS: Type: Contains an optional (selectable) component\n");
+ break;
+ case 0x0003:
+ cli_dbgmsg("SIS: Type: Configures an existing application or service\n");
+ break;
+ case 0x0004:
+ cli_dbgmsg("SIS: Type: Patches an existing component\n");
+ break;
+ case 0x0005:
+ cli_dbgmsg("SIS: Type: Upgrades an existing component\n");
+ break;
+ default:
+ cli_warnmsg("SIS: Unknown value of type\n");
+ }
+
+ cli_dbgmsg("SIS: Major version: %d\n", EC16(file_hdr.majorver));
+ cli_dbgmsg("SIS: Minor version: %d\n", EC16(file_hdr.minorver));
+
+ if(release == 6) {
+
+ if(sizeof(struct sis_file_hdr) + sizeof(struct sis_file_hdr6) >= length) {
+ cli_errmsg("SIS: Broken file structure (language records)\n");
+ munmap(mfile, length);
+ return CL_EFORMAT;
+ }
+
+ memcpy(&file_hdr6, mfile + sizeof(struct sis_file_hdr), sizeof(struct sis_file_hdr6));
+ cli_dbgmsg("SIS: Maximum space required: %d\n", EC32(file_hdr6.maxispace));
+ }
+
+ /* Files */
+ nfiles = EC16(file_hdr.nfiles);
+
+ if(ctx->limits && ctx->limits->maxfiles && nfiles > ctx->limits->maxfiles) {
+ cli_dbgmsg("SIS: Files limit reached (max: %d)\n", ctx->limits->maxfiles);
+ if(BLOCKMAX) {
+ *ctx->virname = "SIS.ExceededFilesLimit";
+ munmap(mfile, length);
+ return CL_VIRUS;
+ }
+ return CL_CLEAN;
+ }
+
+ cli_dbgmsg("SIS: Number of files: %d\n", nfiles);
+ cli_dbgmsg("SIS: Offset of files records: %d\n", EC32(file_hdr.pfiles));
+
+ if((frecord = EC32(file_hdr.pfiles)) >= length) {
+ cli_errmsg("SIS: Broken file structure (frecord)\n");
+ munmap(mfile, length);
+ return CL_EFORMAT;
+ }
+
+ dir = cli_gentemp(NULL);
+ if(!dir || mkdir(dir, 0700) == -1) {
+ cli_errmsg("SIS: Can't create temporary directory %s\n", dir ? dir : "");
+ munmap(mfile, length);
+ return CL_ETMPDIR;
+ }
+
+ for(i = 0; i < nfiles; i++) {
+
+ cli_dbgmsg("SIS: -----\n");
+
+ if(frecord + 4 >= length) {
+ cli_errmsg("SIS: Broken file structure (frecord)\n");
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return CL_EFORMAT;
+ }
+
+ switch(cli_readint32(mfile + frecord)) {
+ case 0x00000000:
+ cli_dbgmsg("SIS: Simple file record\n");
+ if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, 1, compressed, &ifile, dir, ctx))) {
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return ret;
+ }
+
+ if(release == 6)
+ frecord += 32 + 12 + 4;
+ else
+ frecord += 28 + 4 + 4;
+
+ break;
+ case 0x00000001:
+ cli_dbgmsg("SIS: Multiple languages file record\n");
+ /* TODO: Pass language strings into sis_extract */
+ if((ret = sis_extract_simple(desc, mfile, sb.st_size, frecord + 4, nlangs, compressed, &ifile, dir, ctx))) {
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return ret;
+ }
+
+ if(release == 6)
+ frecord += 32 + 12 * nlangs + 4;
+ else
+ frecord += 28 + 4 * nlangs + 4;
+
+ break;
+ case 0x00000002:
+ cli_dbgmsg("SIS: Options record\n");
+ if(frecord + 8 >= length) {
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return CL_EFORMAT;
+ }
+
+ n = cli_readint32(mfile + frecord + 4);
+ cli_dbgmsg("SIS: Number of options: %d\n", n);
+
+ if(n > 128 || frecord + 8 * n * nlangs >= length) {
+ cli_errmsg("SIS: Incorrect number of options\n");
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return CL_EFORMAT;
+ }
+
+ frecord += 8 + 8 * n * nlangs + 16;
+
+ break;
+ case 0x00000003:
+ case 0x00000004:
+ cli_dbgmsg("SIS: If/ElseIf record\n");
+ if(frecord + 8 >= length) {
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return CL_EFORMAT;
+ }
+
+ n = cli_readint32(mfile + frecord + 4);
+ cli_dbgmsg("SIS: Size of conditional expression: %d\n", n);
+
+ if(n >= length) {
+ cli_errmsg("SIS: Incorrect size of conditional expression\n");
+ munmap(mfile, length);
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+ free(dir);
+ return CL_EFORMAT;
+ }
+
+ frecord += 8 + n;
+ break;
+ case 0x00000005:
+ cli_dbgmsg("SIS: Else record\n");
+ frecord += 4;
+ break;
+ case 0x00000006:
+ cli_dbgmsg("SIS: EndIf record\n");
+ frecord += 4;
+ break;
+ default:
+ cli_warnmsg("SIS: Unknown file record type\n");
+ }
+ }
+
+ /* scan extracted files */
+ cli_dbgmsg("SIS: ****** Scanning extracted files ******\n");
+ ret = cli_scandir(dir, ctx);
+
+ if(!cli_leavetemps_flag)
+ cli_rmdirs(dir);
+
+ free(dir);
+ munmap(mfile, length);
+
+ return ret;
+}
+
+#else /* HAVE_MMAP */
+
+#include "clamav.h"
+#include "others.h"
+#include "sis.h"
+
+int cli_scansis(int desc, cli_ctx *ctx)
+{
+ cli_warnmsg("Support for SIS files not compiled in!\n");
+ return CL_CLEAN;
+}
+
+#endif /* HAVE_MMAP */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_snprintf.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,658 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell at astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * Original:
+ * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
+ * A bombproof version of doprnt (dopr) included.
+ * Sigh. This sort of thing is always nasty do deal with. Note that
+ * the version here does not include floating point...
+ *
+ * snprintf() is used instead of sprintf() as it does limit checks
+ * for string length. This covers a nasty loophole.
+ *
+ * The other functions are there to prevent NULL pointers from
+ * causing nast effects.
+ *
+ * More Recently:
+ * Brandon Long <blong at fiction.net> 9/15/96 for mutt 0.43
+ * This was ugly. It is still ugly. I opted out of floating point
+ * numbers, but the formatter understands just about everything
+ * from the normal C string format, at least as far as I can tell from
+ * the Solaris 2.5 printf(3S) man page.
+ *
+ * Brandon Long <blong at fiction.net> 10/22/97 for mutt 0.87.1
+ * Ok, added some minimal floating point support, which means this
+ * probably requires libm on most operating systems. Don't yet
+ * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
+ * was pretty badly broken, it just wasn't being exercised in ways
+ * which showed it, so that's been fixed. Also, formated the code
+ * to mutt conventions, and removed dead code left over from the
+ * original. Also, there is now a builtin-test, just compile with:
+ * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
+ * and run snprintf for results.
+ *
+ * Thomas Roessler <roessler at guug.de> 01/27/98 for mutt 0.89i
+ * The PGP code was using unsigned hexadecimal formats.
+ * Unfortunately, unsigned formats simply didn't work.
+ *
+ * Michael Elkins <me at cs.hmc.edu> 03/05/98 for mutt 0.90.8
+ * The original code assumed that both snprintf() and vsnprintf() were
+ * missing. Some systems only have snprintf() but not vsnprintf(), so
+ * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
+ *
+ * Ben Lindstrom <mouring at eviladmin.org> 09/27/00 for OpenSSH
+ * Welcome to the world of %lld and %qd support. With other
+ * long long support. This is needed for sftp-server to work
+ * right.
+ *
+ * Ben Lindstrom <mouring at eviladmin.org> 02/12/01 for OpenSSH
+ * Removed all hint of VARARGS stuff and banished it to the void,
+ * and did a bit of KNF style work to make things a bit more
+ * acceptable. Consider stealing from mutt or enlightenment.
+ **************************************************************/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <sys/types.h>
+#include <stdarg.h>
+
+static void
+dopr(char *buffer, size_t maxlen, const char *format, va_list args);
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags,
+ int min, int max);
+
+static void
+fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base,
+ int min, int max, int flags);
+
+static void
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
+ int min, int max, int flags);
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);
+
+/*
+ * dopr(): poor man's version of doprintf
+ */
+
+/* format read states */
+#define DP_S_DEFAULT 0
+#define DP_S_FLAGS 1
+#define DP_S_MIN 2
+#define DP_S_DOT 3
+#define DP_S_MAX 4
+#define DP_S_MOD 5
+#define DP_S_CONV 6
+#define DP_S_DONE 7
+
+/* format flags - Bits */
+#define DP_F_MINUS (1 << 0)
+#define DP_F_PLUS (1 << 1)
+#define DP_F_SPACE (1 << 2)
+#define DP_F_NUM (1 << 3)
+#define DP_F_ZERO (1 << 4)
+#define DP_F_UP (1 << 5)
+#define DP_F_UNSIGNED (1 << 6)
+
+/* Conversion Flags */
+#define DP_C_SHORT 1
+#define DP_C_LONG 2
+#define DP_C_LDOUBLE 3
+#define DP_C_LONG_LONG 4
+
+#define char_to_int(p) (p - '0')
+#define abs_val(p) (p < 0 ? -p : p)
+
+#ifndef MAX
+#define MAX(a,b) ((a > b) ? a : b)
+#endif
+
+static void
+dopr(char *buffer, size_t maxlen, const char *format, va_list args)
+{
+ char *strvalue, ch;
+ long value;
+ long double fvalue;
+ int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0;
+ size_t currlen = 0;
+
+ ch = *format++;
+
+ while (state != DP_S_DONE) {
+ if ((ch == '\0') || (currlen >= maxlen))
+ state = DP_S_DONE;
+
+ switch(state) {
+ case DP_S_DEFAULT:
+ if (ch == '%')
+ state = DP_S_FLAGS;
+ else
+ dopr_outch(buffer, &currlen, maxlen, ch);
+ ch = *format++;
+ break;
+ case DP_S_FLAGS:
+ switch (ch) {
+ case '-':
+ flags |= DP_F_MINUS;
+ ch = *format++;
+ break;
+ case '+':
+ flags |= DP_F_PLUS;
+ ch = *format++;
+ break;
+ case ' ':
+ flags |= DP_F_SPACE;
+ ch = *format++;
+ break;
+ case '#':
+ flags |= DP_F_NUM;
+ ch = *format++;
+ break;
+ case '0':
+ flags |= DP_F_ZERO;
+ ch = *format++;
+ break;
+ default:
+ state = DP_S_MIN;
+ break;
+ }
+ break;
+ case DP_S_MIN:
+ if (isdigit((unsigned char)ch)) {
+ min = 10 * min + char_to_int (ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ min = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_DOT;
+ } else
+ state = DP_S_DOT;
+ break;
+ case DP_S_DOT:
+ if (ch == '.') {
+ state = DP_S_MAX;
+ ch = *format++;
+ } else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MAX:
+ if (isdigit((unsigned char)ch)) {
+ if (max < 0)
+ max = 0;
+ max = 10 * max + char_to_int(ch);
+ ch = *format++;
+ } else if (ch == '*') {
+ max = va_arg (args, int);
+ ch = *format++;
+ state = DP_S_MOD;
+ } else
+ state = DP_S_MOD;
+ break;
+ case DP_S_MOD:
+ switch (ch) {
+ case 'h':
+ cflags = DP_C_SHORT;
+ ch = *format++;
+ break;
+ case 'l':
+ cflags = DP_C_LONG;
+ ch = *format++;
+ if (ch == 'l') {
+ cflags = DP_C_LONG_LONG;
+ ch = *format++;
+ }
+ break;
+ case 'q':
+ cflags = DP_C_LONG_LONG;
+ ch = *format++;
+ break;
+ case 'L':
+ cflags = DP_C_LDOUBLE;
+ ch = *format++;
+ break;
+ default:
+ break;
+ }
+ state = DP_S_CONV;
+ break;
+ case DP_S_CONV:
+ switch (ch) {
+ case 'd':
+ case 'i':
+ if (cflags == DP_C_SHORT)
+ value = va_arg(args, int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg(args, long int);
+ else if (cflags == DP_C_LONG_LONG)
+ value = va_arg (args, long long);
+ else
+ value = va_arg (args, int);
+ fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'o':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg(args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg(args, unsigned long int);
+ else if (cflags == DP_C_LONG_LONG)
+ value = va_arg(args, unsigned long long);
+ else
+ value = va_arg(args, unsigned int);
+ fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
+ break;
+ case 'u':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg(args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg(args, unsigned long int);
+ else if (cflags == DP_C_LONG_LONG)
+ value = va_arg(args, unsigned long long);
+ else
+ value = va_arg(args, unsigned int);
+ fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
+ break;
+ case 'X':
+ flags |= DP_F_UP;
+ case 'x':
+ flags |= DP_F_UNSIGNED;
+ if (cflags == DP_C_SHORT)
+ value = va_arg(args, unsigned int);
+ else if (cflags == DP_C_LONG)
+ value = va_arg(args, unsigned long int);
+ else if (cflags == DP_C_LONG_LONG)
+ value = va_arg(args, unsigned long long);
+ else
+ value = va_arg(args, unsigned int);
+ fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
+ break;
+ case 'f':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg(args, long double);
+ else
+ fvalue = va_arg(args, double);
+ /* um, floating point? */
+ fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
+ break;
+ case 'E':
+ flags |= DP_F_UP;
+ case 'e':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg(args, long double);
+ else
+ fvalue = va_arg(args, double);
+ break;
+ case 'G':
+ flags |= DP_F_UP;
+ case 'g':
+ if (cflags == DP_C_LDOUBLE)
+ fvalue = va_arg(args, long double);
+ else
+ fvalue = va_arg(args, double);
+ break;
+ case 'c':
+ dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
+ break;
+ case 's':
+ strvalue = va_arg(args, char *);
+ if (max < 0)
+ max = maxlen; /* ie, no max */
+ fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
+ break;
+ case 'p':
+ strvalue = va_arg(args, void *);
+ fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
+ break;
+ case 'n':
+ if (cflags == DP_C_SHORT) {
+ short int *num;
+ num = va_arg(args, short int *);
+ *num = currlen;
+ } else if (cflags == DP_C_LONG) {
+ long int *num;
+ num = va_arg(args, long int *);
+ *num = currlen;
+ } else if (cflags == DP_C_LONG_LONG) {
+ long long *num;
+ num = va_arg(args, long long *);
+ *num = currlen;
+ } else {
+ int *num;
+ num = va_arg(args, int *);
+ *num = currlen;
+ }
+ break;
+ case '%':
+ dopr_outch(buffer, &currlen, maxlen, ch);
+ break;
+ case 'w': /* not supported yet, treat as next char */
+ ch = *format++;
+ break;
+ default: /* Unknown, skip */
+ break;
+ }
+ ch = *format++;
+ state = DP_S_DEFAULT;
+ flags = cflags = min = 0;
+ max = -1;
+ break;
+ case DP_S_DONE:
+ break;
+ default: /* hmm? */
+ break; /* some picky compilers need this */
+ }
+ }
+ if (currlen < maxlen - 1)
+ buffer[currlen] = '\0';
+ else
+ buffer[maxlen - 1] = '\0';
+}
+
+static void
+fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+ char *value, int flags, int min, int max)
+{
+ int cnt = 0, padlen, strln; /* amount to pad */
+
+ if (value == 0)
+ value = "<NULL>";
+
+ for (strln = 0; value[strln]; ++strln); /* strlen */
+ padlen = min - strln;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justify */
+
+ while ((padlen > 0) && (cnt < max)) {
+ dopr_outch(buffer, currlen, maxlen, ' ');
+ --padlen;
+ ++cnt;
+ }
+ while (*value && (cnt < max)) {
+ dopr_outch(buffer, currlen, maxlen, *value++);
+ ++cnt;
+ }
+ while ((padlen < 0) && (cnt < max)) {
+ dopr_outch(buffer, currlen, maxlen, ' ');
+ ++padlen;
+ ++cnt;
+ }
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static void
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+ long value, int base, int min, int max, int flags)
+{
+ unsigned long uvalue;
+ char convert[20];
+ int signvalue = 0, place = 0, caps = 0;
+ int spadlen = 0; /* amount to space pad */
+ int zpadlen = 0; /* amount to zero pad */
+
+ if (max < 0)
+ max = 0;
+
+ uvalue = value;
+
+ if (!(flags & DP_F_UNSIGNED)) {
+ if (value < 0) {
+ signvalue = '-';
+ uvalue = -value;
+ } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+ }
+
+ if (flags & DP_F_UP)
+ caps = 1; /* Should characters be upper case? */
+ do {
+ convert[place++] =
+ (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+ [uvalue % (unsigned)base];
+ uvalue = (uvalue / (unsigned)base );
+ } while (uvalue && (place < 20));
+ if (place == 20)
+ place--;
+ convert[place] = 0;
+
+ zpadlen = max - place;
+ spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
+ if (zpadlen < 0)
+ zpadlen = 0;
+ if (spadlen < 0)
+ spadlen = 0;
+ if (flags & DP_F_ZERO) {
+ zpadlen = MAX(zpadlen, spadlen);
+ spadlen = 0;
+ }
+ if (flags & DP_F_MINUS)
+ spadlen = -spadlen; /* Left Justifty */
+
+ /* Spaces */
+ while (spadlen > 0) {
+ dopr_outch(buffer, currlen, maxlen, ' ');
+ --spadlen;
+ }
+
+ /* Sign */
+ if (signvalue)
+ dopr_outch(buffer, currlen, maxlen, signvalue);
+
+ /* Zeros */
+ if (zpadlen > 0) {
+ while (zpadlen > 0) {
+ dopr_outch(buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+ }
+
+ /* Digits */
+ while (place > 0)
+ dopr_outch(buffer, currlen, maxlen, convert[--place]);
+
+ /* Left Justified spaces */
+ while (spadlen < 0) {
+ dopr_outch (buffer, currlen, maxlen, ' ');
+ ++spadlen;
+ }
+}
+
+static long double
+pow10(int exp)
+{
+ long double result = 1;
+
+ while (exp) {
+ result *= 10;
+ exp--;
+ }
+
+ return result;
+}
+
+static long
+round(long double value)
+{
+ long intpart = value;
+
+ value -= intpart;
+ if (value >= 0.5)
+ intpart++;
+
+ return intpart;
+}
+
+static void
+fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue,
+ int min, int max, int flags)
+{
+ char iconvert[20], fconvert[20];
+ int signvalue = 0, iplace = 0, fplace = 0;
+ int padlen = 0; /* amount to pad */
+ int zpadlen = 0, caps = 0;
+ long intpart, fracpart;
+ long double ufvalue;
+
+ /*
+ * AIX manpage says the default is 0, but Solaris says the default
+ * is 6, and sprintf on AIX defaults to 6
+ */
+ if (max < 0)
+ max = 6;
+
+ ufvalue = abs_val(fvalue);
+
+ if (fvalue < 0)
+ signvalue = '-';
+ else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
+ signvalue = '+';
+ else if (flags & DP_F_SPACE)
+ signvalue = ' ';
+
+ intpart = ufvalue;
+
+ /*
+ * Sorry, we only support 9 digits past the decimal because of our
+ * conversion method
+ */
+ if (max > 9)
+ max = 9;
+
+ /* We "cheat" by converting the fractional part to integer by
+ * multiplying by a factor of 10
+ */
+ fracpart = round((pow10 (max)) * (ufvalue - intpart));
+
+ if (fracpart >= pow10 (max)) {
+ intpart++;
+ fracpart -= pow10 (max);
+ }
+
+ /* Convert integer part */
+ do {
+ iconvert[iplace++] =
+ (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+ [intpart % 10];
+ intpart = (intpart / 10);
+ } while(intpart && (iplace < 20));
+ if (iplace == 20)
+ iplace--;
+ iconvert[iplace] = 0;
+
+ /* Convert fractional part */
+ do {
+ fconvert[fplace++] =
+ (caps ? "0123456789ABCDEF" : "0123456789abcdef")
+ [fracpart % 10];
+ fracpart = (fracpart / 10);
+ } while(fracpart && (fplace < 20));
+ if (fplace == 20)
+ fplace--;
+ fconvert[fplace] = 0;
+
+ /* -1 for decimal point, another -1 if we are printing a sign */
+ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
+ zpadlen = max - fplace;
+ if (zpadlen < 0)
+ zpadlen = 0;
+ if (padlen < 0)
+ padlen = 0;
+ if (flags & DP_F_MINUS)
+ padlen = -padlen; /* Left Justifty */
+
+ if ((flags & DP_F_ZERO) && (padlen > 0)) {
+ if (signvalue) {
+ dopr_outch(buffer, currlen, maxlen, signvalue);
+ --padlen;
+ signvalue = 0;
+ }
+ while (padlen > 0) {
+ dopr_outch(buffer, currlen, maxlen, '0');
+ --padlen;
+ }
+ }
+ while (padlen > 0) {
+ dopr_outch(buffer, currlen, maxlen, ' ');
+ --padlen;
+ }
+ if (signvalue)
+ dopr_outch(buffer, currlen, maxlen, signvalue);
+
+ while (iplace > 0)
+ dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
+
+ /*
+ * Decimal point. This should probably use locale to find the
+ * correct char to print out.
+ */
+ dopr_outch(buffer, currlen, maxlen, '.');
+
+ while (fplace > 0)
+ dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
+
+ while (zpadlen > 0) {
+ dopr_outch(buffer, currlen, maxlen, '0');
+ --zpadlen;
+ }
+
+ while (padlen < 0) {
+ dopr_outch(buffer, currlen, maxlen, ' ');
+ ++padlen;
+ }
+}
+
+static void
+dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
+{
+ if (*currlen < maxlen)
+ buffer[(*currlen)++] = c;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#ifndef HAVE_VSNPRINTF
+int
+vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+ str[0] = 0;
+ dopr(str, count, fmt, args);
+
+ return(strlen(str));
+}
+#endif /* !HAVE_VSNPRINTF */
+
+#ifndef HAVE_SNPRINTF
+int
+snprintf(char *str,size_t count,const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(str, count, fmt, ap);
+ va_end(ap);
+
+ return(strlen(str));
+}
+
+#endif /* !HAVE_SNPRINTF */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_special.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2004-2005 trog at uncon.org
+ *
+ * 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.
+ */
+
+#ifdef _MSC_VER
+#include <windows.h>
+#endif
+
+#include "clamav-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef C_WINDOWS
+#include <netinet/in.h>
+#endif
+#include <string.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "cltypes.h"
+#include "special.h"
+
+/* NOTE: Photoshop stores data in BIG ENDIAN format, this is the opposite
+ to virtually everything else */
+
+#define special_endian_convert_16(v) be16_to_host(v)
+#define special_endian_convert_32(v) be32_to_host(v)
+
+int cli_check_mydoom_log(int desc, const char **virname)
+{
+ int32_t record[8], check;
+ int i, retval=CL_VIRUS, j;
+
+ cli_dbgmsg("in cli_check_mydoom_log()\n");
+
+ /* Check upto the first five records in the file */
+ for (j=0 ; j<5 ; j++) {
+ if (cli_readn(desc, &record, 32) != 32) {
+ break;
+ }
+
+ /* Decode the key */
+ record[0] = ~ntohl(record[0]);
+ cli_dbgmsg("Mydoom: key: %d\n", record[0]);
+ check = 0;
+ for (i=1 ; i<8; i++) {
+ record[i] = ntohl(record[i]) ^ record[0];
+ check += record[i];
+ }
+ cli_dbgmsg("Mydoom: check: %d\n", ~check);
+ if ((~check) != record[0]) {
+ return CL_CLEAN;
+ }
+ }
+
+ if (j < 2) {
+ retval = CL_CLEAN;
+ } else if (retval==CL_VIRUS) {
+ if(virname)
+ *virname = "Worm.Mydoom.M.log";
+ }
+
+ return retval;
+}
+
+static int jpeg_check_photoshop_8bim(int fd)
+{
+ unsigned char bim[5];
+ uint16_t id, ntmp;
+ uint8_t nlength;
+ uint32_t size;
+ off_t offset;
+ int retval;
+
+ if (cli_readn(fd, bim, 4) != 4) {
+ cli_dbgmsg("read bim failed\n");
+ return -1;
+ }
+
+ if (memcmp(bim, "8BIM", 4) != 0) {
+ bim[4] = '\0';
+ cli_dbgmsg("missed 8bim: %s\n", bim);
+ return -1;
+ }
+
+ if (cli_readn(fd, &id, 2) != 2) {
+ return -1;
+ }
+ id = special_endian_convert_16(id);
+ cli_dbgmsg("ID: 0x%.4x\n", id);
+ if (cli_readn(fd, &nlength, 1) != 1) {
+ return -1;
+ }
+ ntmp = nlength + ((((uint16_t)nlength)+1) & 0x01);
+ lseek(fd, ntmp, SEEK_CUR);
+
+ if (cli_readn(fd, &size, 4) != 4) {
+ return -1;
+ }
+ size = special_endian_convert_32(size);
+ if (size == 0) {
+ return -1;
+ }
+ if ((size & 0x01) == 1) {
+ size++;
+ }
+ /* Is it a thumbnail image */
+ if ((id != 0x0409) && (id != 0x040c)) {
+ /* No - Seek past record */
+ lseek(fd, size, SEEK_CUR);
+ return 0;
+ }
+
+ cli_dbgmsg("found thumbnail\n");
+ /* Check for thumbmail image */
+ offset = lseek(fd, 0, SEEK_CUR);
+
+ /* Jump past header */
+ lseek(fd, 28, SEEK_CUR);
+
+ retval = cli_check_jpeg_exploit(fd);
+ if (retval == 1) {
+ cli_dbgmsg("Exploit found in thumbnail\n");
+ }
+ lseek(fd, offset+size, SEEK_SET);
+
+ return retval;
+}
+
+static int jpeg_check_photoshop(int fd)
+{
+ int retval;
+ unsigned char buffer[14];
+ off_t old, new;
+
+ if (cli_readn(fd, buffer, 14) != 14) {
+ return 0;
+ }
+
+ if (memcmp(buffer, "Photoshop 3.0", 14) != 0) {
+ return 0;
+ }
+
+ cli_dbgmsg("Found Photoshop segment\n");
+ do {
+ old = lseek(fd, 0, SEEK_CUR);
+ retval = jpeg_check_photoshop_8bim(fd);
+ new = lseek(fd, 0, SEEK_CUR);
+ if(new <= old)
+ break;
+ } while (retval == 0);
+
+ if (retval == -1) {
+ retval = 0;
+ }
+ return retval;
+}
+
+int cli_check_jpeg_exploit(int fd)
+{
+ unsigned char buffer[4];
+ off_t offset;
+ int retval;
+
+
+ cli_dbgmsg("in cli_check_jpeg_exploit()\n");
+
+ if (cli_readn(fd, buffer, 2) != 2) {
+ return 0;
+ }
+
+ if ((buffer[0] != 0xff) || (buffer[1] != 0xd8)) {
+ return 0;
+ }
+
+ for (;;) {
+ if ((retval=cli_readn(fd, buffer, 4)) != 4) {
+ return 0;
+ }
+ /* Check for multiple 0xFF values, we need to skip them */
+ if ((buffer[0] == 0xff) && (buffer[1] == 0xff)) {
+ lseek(fd, -3, SEEK_CUR);
+ continue;
+ }
+
+ if ((buffer[0] == 0xff) && (buffer[1] == 0xfe)) {
+ if (buffer[2] == 0x00) {
+ if ((buffer[3] == 0x00) || (buffer[3] == 0x01)) {
+ return 1;
+ }
+ }
+ }
+ if (buffer[0] != 0xff) {
+ return -1;
+ }
+ if (buffer[1] == 0xda) {
+ /* End of Image marker */
+ return 0;
+ }
+
+ offset = ((unsigned int) buffer[2] << 8) + buffer[3];
+ if (offset < 2) {
+ return 1;
+ }
+ offset -= 2;
+ offset += lseek(fd, 0, SEEK_CUR);
+
+ if (buffer[1] == 0xed) {
+ /* Possible Photoshop file */
+ if ((retval=jpeg_check_photoshop(fd)) != 0) {
+ return retval;
+ }
+ }
+
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ return -1;
+ }
+ }
+}
+
+static uint32_t riff_endian_convert_32(uint32_t value, int big_endian)
+{
+ if (big_endian)
+ return be32_to_host(value);
+ else
+ return le32_to_host(value);
+}
+
+static int riff_read_chunk(int fd, int big_endian, int rec_level)
+{
+ uint32_t chunk_id;
+ uint32_t chunk_size;
+ int length;
+ uint32_t list_type;
+ off_t offset, cur_offset;
+
+ if (rec_level > 1000) {
+ cli_dbgmsg("riff_read_chunk: recursion level exceeded\n");
+ return 0;
+ }
+
+ length = sizeof(uint32_t);
+ if (cli_readn(fd, &chunk_id, length) != length) {
+ return 0;
+ }
+ if (cli_readn(fd, &chunk_size, length) != length) {
+ return 0;
+ }
+ chunk_size = riff_endian_convert_32(chunk_size, big_endian);
+
+ if (memcmp(&chunk_id, "RIFF", 4) == 0) {
+ return 0;
+ } else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
+ return 0;
+ }
+
+ if ((memcmp(&chunk_id, "LIST", 4) == 0) ||
+ (memcmp(&chunk_id, "PROP", 4) == 0) ||
+ (memcmp(&chunk_id, "FORM", 4) == 0) ||
+ (memcmp(&chunk_id, "CAT ", 4) == 0)) {
+ if (cli_readn(fd, &list_type, sizeof(list_type)) != sizeof(list_type)) {
+ cli_dbgmsg("riff_read_chunk: read list type failed\n");
+ return 0;
+ }
+ return riff_read_chunk(fd, big_endian, ++rec_level);
+ }
+
+ cur_offset = lseek(fd, 0, SEEK_CUR);
+ offset = cur_offset + chunk_size;
+ /* Check for odd alignment */
+ if ((offset & 0x01) == 1) {
+ offset++;
+ }
+ if (offset < cur_offset) {
+ return 0;
+ }
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ return 2;
+ }
+ return 1;
+}
+
+int cli_check_riff_exploit(int fd)
+{
+ uint32_t chunk_id;
+ uint32_t chunk_size;
+ uint32_t form_type;
+ int length, big_endian, retval;
+ off_t offset;
+
+ cli_dbgmsg("in cli_check_riff_exploit()\n");
+
+ length = sizeof(uint32_t);
+ if (cli_readn(fd, &chunk_id, length) != length) {
+ return 0;
+ }
+ if (cli_readn(fd, &chunk_size, length) != length) {
+ return 0;
+ }
+ if (cli_readn(fd, &form_type, length) != length) {
+ return 0;
+ }
+
+ if (memcmp(&chunk_id, "RIFF", 4) == 0) {
+ big_endian = FALSE;
+ } else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
+ big_endian = TRUE;
+ } else {
+ /* Not a RIFF file */
+ return 0;
+ }
+
+ if (memcmp(&form_type, "ACON", 4) != 0) {
+ /* Only scan MS animated icon files */
+ /* There is a *lot* of broken software out there that produces bad RIFF files */
+ return 0;
+ }
+
+ chunk_size = riff_endian_convert_32(chunk_size, big_endian);
+
+ do {
+ retval = riff_read_chunk(fd, big_endian, 1);
+ } while (retval == 1);
+
+ offset = lseek(fd, 0, SEEK_CUR);
+
+ if (offset < (int64_t)chunk_size) {
+ retval = 2;
+ }
+ return retval;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_spin.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+** spin.c
+**
+** 19/07/2k5 - Finally started coding something
+** 21/07/2k5 - Works, started clearing the mess
+** 31/07/2k5 - Porting to libclamav
+*/
+
+/*
+** Unpacks pespin v1.1
+**
+** Funny thing to reverse
+**
+** [ A big fat thank to christoph for not letting me give up ]
+*/
+
+
+/*
+** TODO ( a fat one ):
+**
+** OEP restore and unhijacking
+** code redir handling (at least near OEP)
+** passwd protection (didn't really look at it)
+**
+** All this stuff really needs a way better emu and a hell of unlaming
+** ATM not worth the effort... and pespin v1.3 is out :@
+**
+*/
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "pe.h"
+#include "rebuildpe.h"
+#include "execs.h"
+#include "others.h"
+#include "packlibs.h"
+#include "spin.h"
+
+
+static char exec86(uint8_t aelle, uint8_t cielle, char *curremu, int *retval) {
+ int len = 0;
+ *retval=0;
+ while (len <0x24) {
+ uint8_t opcode = curremu[len], support;
+ len++;
+ switch (opcode) {
+ case 0xeb:
+ len++;
+ case 0x0a:
+ len++;
+ case 0x90:
+ case 0xf8:
+ case 0xf9:
+ break;
+
+ case 0x02: /* add al, cl */
+ aelle+=cielle;
+ len++;
+ break;
+ case 0x2a: /* sub al, cl */
+ aelle-=cielle;
+ len++;
+ break;
+ case 0x04: /* add al, ?? */
+ aelle+=curremu[len];
+ len++;
+ break;
+ case 0x2c: /* sub al, ?? */
+ aelle-=curremu[len];
+ len++;
+ break;
+ case 0x32: /* xor al, cl */
+ aelle^=cielle;
+ len++;
+ break;
+ case 0x34: /* xor al, ?? */
+ aelle^=curremu[len];
+ len++;
+ break;
+
+ case 0xfe: /* inc/dec al */
+ if ( curremu[len] == '\xc0' ) aelle++;
+ else aelle--;
+ len++;
+ break;
+
+ case 0xc0: /* ror/rol al, ?? */
+ support = curremu[len];
+ len++;
+ if ( support == 0xc0 ) CLI_ROL(aelle, curremu[len]);
+ else CLI_ROR(aelle, curremu[len]);
+ len++;
+ break;
+
+ default:
+ cli_dbgmsg("spin: bogus opcode %x\n", opcode);
+ *retval=1;
+ return aelle;
+ }
+ }
+ if ( len!=0x24 || curremu[len]!='\xaa' ) {
+ cli_dbgmsg("spin: bad emucode\n");
+ *retval=1;
+ }
+ return aelle;
+}
+
+
+static uint32_t summit (char *src, int size)
+{
+ uint32_t eax=0xffffffff, ebx=0xffffffff;
+ int i;
+
+ while(size) {
+ eax ^= *src++<<8 & 0xff00;
+ eax = eax>>3 & 0x1fffffff;
+ for (i=0; i<4; i++) {
+ uint32_t swap;
+ eax ^= ebx>>8 & 0xff;
+ eax += 0x7801a108;
+ eax ^= ebx;
+ CLI_ROR(eax, ebx&0xff);
+ swap = eax;
+ eax = ebx;
+ ebx = swap;
+ }
+ size--;
+ }
+ return ebx;
+}
+
+
+int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt, uint32_t nep, int desc, cli_ctx *ctx) {
+ char *curr, *emu, *ep, *spinned;
+ char **sects;
+ int blobsz=0, j;
+ uint32_t key32, bitmap, bitman;
+ uint32_t len;
+ uint8_t key8;
+
+ cli_dbgmsg("in unspin\n");
+
+ if ((spinned = (char *) cli_malloc(sections[sectcnt].rsz)) == NULL )
+ return 1;
+
+ memcpy(spinned, src + sections[sectcnt].raw, sections[sectcnt].rsz);
+ ep = spinned + nep - sections[sectcnt].rva;
+
+ curr = ep+0xdb;
+ if ( *curr != '\xbb' ) {
+ free(spinned);
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ key8 = (uint8_t)*++curr;
+ curr+=4;
+ if ( *curr != '\xb9' ) {
+ free(spinned);
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ if ( (len = cli_readint32(curr+1)) != 0x11fe ) {
+ free(spinned);
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len);
+
+ if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep, len+0x1fe5-1) || !CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep+0x3217, 4)) {
+ free(spinned);
+ cli_dbgmsg("spin: len or key out of bounds, giving up\n");
+ return 1;
+ }
+
+ if ( ep[0x1e0]!='\xb8' )
+ cli_dbgmsg("spin: prolly not spinned, expect failure\n");
+
+ if ( (cli_readint32(ep+0x1e1) & 0x00200000) )
+ cli_dbgmsg("spin: password protected, expect failure\n");
+
+ curr = ep+0x1fe5+len-1;
+ while ( len-- ) {
+ *curr=(*curr)^(key8--);
+ curr--;
+ }
+
+ curr = ep+0x26eb;
+ key32 = cli_readint32(curr);
+ if ( (len = cli_readint32(curr+5)) != 0x5a0) {
+ free(spinned);
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ curr = ep+0x2d5;
+ cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len);
+
+ while ( len-- ) {
+ if ( key32 & 1 ) {
+ key32 = key32>>1;
+ key32 ^= 0x8c328834;
+ } else {
+ key32 = key32>>1;
+ }
+ *curr = *curr ^ (key32 & 0xff);
+ curr++;
+ }
+
+ len = ssize - cli_readint32(ep+0x429); /* sub size, value */
+ if ( len >= (uint32_t)ssize ) {
+ free(spinned);
+ cli_dbgmsg("spin: crc out of bounds, giving up\n");
+ return 1;
+ }
+ key32 = cli_readint32(ep+0x3217) - summit(src,len);
+
+ memcpy(src + sections[sectcnt].raw, spinned, sections[sectcnt].rsz);
+ free(spinned); /* done CRC'ing - can have a dirty buffer now */
+ ep = src + nep + sections[sectcnt].raw - sections[sectcnt].rva; /* Fix the helper */
+
+ if (!CLI_ISCONTAINED(src, ssize, ep+0x3207, 4)) { /* this one holds all ep based checks */
+ cli_dbgmsg("spin: key out of bounds, giving up\n");
+ return 1;
+ }
+ bitmap = cli_readint32(ep+0x3207);
+ cli_dbgmsg("spin: Key32 is %x - XORbitmap is %x\n", key32, bitmap);
+
+ cli_dbgmsg("spin: Decrypting sects (xor)\n");
+ for (j=0; j<sectcnt; j++) {
+
+ if (bitmap&1) {
+ uint32_t size = sections[j].rsz;
+ char *ptr = src + sections[j].raw;
+ uint32_t keydup = key32;
+
+ if (!CLI_ISCONTAINED(src, (unsigned int)ssize, ptr, size)) {
+ cli_dbgmsg("spin: sect %d out of file, giving up\n", j);
+ return 1; /* FIXME: Already checked in pe.c? */
+ }
+
+ while (size--) {
+ if (! (keydup & 1)) {
+ keydup = keydup>>1;
+ keydup ^= 0xed43af31;
+ } else {
+ keydup = keydup>>1;
+ }
+ *ptr = *ptr ^ (keydup & 0xff);
+ ptr++;
+ }
+ }
+ bitmap = bitmap >>1;
+ }
+
+ cli_dbgmsg("spin: done\n");
+
+
+ curr = ep+0x644;
+ if ( (len = cli_readint32(curr)) != 0x180) {
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ key32 = cli_readint32(curr+0x0c);
+ cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len);
+ curr = ep+0x28d3;
+
+ if (!CLI_ISCONTAINED(src, (unsigned int)ssize, curr, len)) { /* always true but i may decide to remove the previous check */
+ cli_dbgmsg("spin: key out of bounds, giving up\n");
+ return 1;
+ }
+ while ( len-- ) {
+ if ( key32 & 1 ) {
+ key32 = key32>>1;
+ key32 ^= 0xed43af32;
+ } else {
+ key32 = key32>>1;
+ }
+ *curr = *curr ^ (key32 & 0xff);
+ curr++;
+ }
+
+
+ curr = ep+0x28dd;
+ if ( (len = cli_readint32(curr)) != 0x1a1 ) {
+ cli_dbgmsg("spin: Not spinned or bad version\n");
+ return 1;
+ }
+
+ cli_dbgmsg("spin: POLY1 len is %x\n", len);
+ curr+=0xf; /* POLY1 */
+ emu = ep+0x6d4;
+ if (!CLI_ISCONTAINED(src, (unsigned int)ssize, emu, len)) {
+ cli_dbgmsg("spin: poly1 out of bounds\n");
+ return 1;
+ }
+ while (len) {
+ int xcfailure=0;
+ *emu=exec86(*emu, len-- & 0xff, curr, &xcfailure); /* unlame POLY1 */
+ if (xcfailure) {
+ cli_dbgmsg("spin: cannot exec poly1\n");
+ return 1;
+ }
+ emu++;
+ }
+
+
+ bitmap = cli_readint32(ep+0x6f1);
+ cli_dbgmsg("spin: POLYbitmap is %x - decrypting sects (poly)\n", bitmap);
+ curr = ep+0x755;
+
+ for (j=0; j<sectcnt; j++) {
+ if (bitmap&1) {
+ uint32_t notthesamelen = sections[j].rsz;
+
+ emu = src + sections[j].raw;
+
+ if (!CLI_ISCONTAINED(src,ssize,curr,0x24)) { /* section bounds already checked twice now */
+ cli_dbgmsg("spin: poly1 emucode is out of file?\n");
+ return 1;
+ }
+
+ while (notthesamelen) {
+ int xcfailure=0;
+ *emu=exec86(*emu, notthesamelen-- & 0xff, curr, &xcfailure);
+ if (xcfailure) {
+ cli_dbgmsg("spin: cannot exec section\n");
+ return 1;
+ }
+ emu++;
+ }
+ }
+ bitmap = bitmap >>1;
+ }
+
+ cli_dbgmsg("spin: done\n");
+
+ bitmap = cli_readint32(ep+0x3061);
+ bitman = bitmap;
+
+ cli_dbgmsg("spin: Compression bitmap is %x\n", bitmap);
+ if ( (sects= (char **) cli_malloc(sectcnt*sizeof(char *))) == NULL )
+ return 1;
+
+ key8 = 0;
+ for (j=0; j<sectcnt; j++) {
+ uint32_t thissize = (bitmap&1) ? sections[j].vsz : sections[j].rsz;
+ if(ctx->limits && ctx->limits->maxfilesize && ((unsigned long int)thissize > ctx->limits->maxfilesize || (unsigned long int)blobsz > ctx->limits->maxfilesize - thissize)) {
+ key8++;
+ cli_dbgmsg("spin: section %d size exceeded (%u, %lu)\n", j, thissize, ctx->limits->maxfilesize);
+ break;
+ }
+ if (bitmap&1) {
+ if ( (sects[j] = (char *) cli_calloc(thissize, sizeof(char)) ) == NULL ) {
+ cli_dbgmsg("spin: malloc(%d) failed\n", thissize);
+ key8++;
+ break;
+ }
+ blobsz+=thissize;
+ cli_dbgmsg("spin: Growing sect%d: was %x will be %x\n", j, sections[j].rsz, thissize);
+ if ( cli_unfsg(src + sections[j].raw, sects[j], sections[j].rsz, thissize, NULL, NULL) == -1 ) {
+ key8++;
+ j++;
+ cli_dbgmsg("spin: Unpack failure\n");
+ break;
+ }
+ } else {
+ blobsz+=thissize;
+ sects[j] = src + sections[j].raw;
+ cli_dbgmsg("spin: Not growing sect%d\n", j);
+ }
+ bitmap>>=1;
+ }
+
+ cli_dbgmsg("spin: decompression complete\n");
+
+ if ( key8 ) {
+ int t;
+ for (t=0 ; t<j ; t++) {
+ if (bitman&1)
+ free(sects[t]);
+ bitman = bitman >>1;
+ }
+ free(sects);
+ return 1;
+ }
+
+
+ key32 = cli_readint32(ep+0x2fee);
+ if (key32) {
+ /* len = cli_readint32(ep+0x2fc8); -- Using vsizes instead */
+
+ for (j=0; j<sectcnt; j++) {
+ if (sections[j].rva <= key32 && sections[j].rva+sections[j].rsz > key32)
+ break;
+ }
+
+ if (j!=sectcnt && ((bitman & (1<<j)) == 0)) { /* FIXME: not really sure either the res sect is lamed or just compressed, but this'll save some major headakes */
+ cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n\tuncompressed offset %x, len %x\n\tcompressed offset %x, len %x\n", j, sections[j].rva, key32 - sections[j].rva, key32, sections[j].vsz - (key32 - sections[j].rva));
+
+ if ( (curr=(char *)cli_malloc(sections[j].vsz)) != NULL ) {
+ memcpy(curr, src + sections[j].raw, key32 - sections[j].rva); /* Uncompressed part */
+ memset(curr + key32 - sections[j].rva, 0, sections[j].vsz - (key32 - sections[j].rva)); /* bzero */
+ if ( cli_unfsg(src + sections[j].raw + key32 - sections[j].rva, curr + key32 - sections[j].rva, sections[j].rsz - (key32 - sections[j].rva), sections[j].vsz - (key32 - sections[j].rva), NULL, NULL) ) {
+
+ free(curr);
+ cli_dbgmsg("spin: Failed to grow resources, continuing anyway\n");
+ blobsz+=sections[j].rsz;
+ } else {
+ sects[j]=curr;
+ bitman|=1<<j;
+ cli_dbgmsg("spin: Resources grown\n");
+ blobsz+=sections[j].vsz;
+ }
+ } else {
+ /* malloc failed but i'm too deep into this crap to quit without leaking more :( */
+ blobsz+=sections[j].rsz;
+ }
+ } else {
+ cli_dbgmsg("spin: No res?!\n");
+ }
+ }
+
+
+ bitmap=bitman; /* save as a free() bitmap */
+
+ if ( (ep = (char *) cli_malloc(blobsz)) != NULL ) {
+ struct cli_exe_section *rebhlp;
+ if ( (rebhlp = (struct cli_exe_section *) cli_malloc(sizeof(struct cli_exe_section)*(sectcnt))) != NULL ) {
+ char *to = ep;
+ int retval = 0;
+
+ for (j = 0; j < sectcnt; j++) {
+ rebhlp[j].raw = (j>0)?(rebhlp[j-1].raw + rebhlp[j-1].rsz):0;
+ rebhlp[j].rsz = (bitmap &1) ? sections[j].vsz : sections[j].rsz;
+ rebhlp[j].rva = sections[j].rva;
+ rebhlp[j].vsz = sections[j].vsz;
+
+ memcpy(to, sects[j], rebhlp[j].rsz);
+ to+=rebhlp[j].rsz;
+ if ( bitmap & 1 ) free(sects[j]);
+ bitmap = bitmap >>1;
+ }
+
+ if (! cli_rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0, desc)) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */
+ cli_dbgmsg("spin: Cannot write unpacked file\n");
+ retval = 1;
+ }
+ free(rebhlp);
+ free(ep);
+ free(sects);
+ return retval;
+ }
+ free(ep);
+ }
+
+ cli_dbgmsg ("spin: free bitmap is %x\n", bitman);
+ for (j=0; j<sectcnt; j++) {
+ if (bitmap&1) free(sects[j]);
+ bitman = bitman >>1;
+ }
+ free(sects);
+ return 1; /* :( */
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_str.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ * cli_strrcpy(): Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ * cli_strtokenize(): Copyright (C) 2007 Edwin Torok <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include "str.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "matcher.h"
+#include "cltypes.h"
+
+static int cli_hex2int(int c)
+{
+ int l;
+
+ if(!isascii(c))
+ return -1;
+
+ if(isdigit(c))
+ return c - '0';
+
+ l = tolower(c);
+ if((l >= 'a') && (l <= 'f'))
+ return l + 10 - 'a';
+
+ cli_errmsg("hex2int() translation problem (%d)\n", l);
+ return -1;
+}
+
+uint16_t *cli_hex2ui(const char *hex)
+{
+ uint16_t *str, *ptr, val;
+ unsigned int i, len;
+ int c;
+
+
+ len = strlen(hex);
+
+ if(len % 2 != 0) {
+ cli_errmsg("cli_hex2si(): Malformed hexstring: %s (length: %u)\n", hex, len);
+ return NULL;
+ }
+
+ str = cli_calloc((len / 2) + 1, sizeof(uint16_t));
+ if(!str)
+ return NULL;
+
+ ptr = str;
+
+ for(i = 0; i < len; i += 2) {
+ val = 0;
+
+ if(hex[i] == '?' && hex[i + 1] == '?') {
+ val |= CLI_MATCH_IGNORE;
+
+ } else if(hex[i + 1] == '?') {
+ if((c = cli_hex2int(hex[i])) >= 0) {
+ val = c << 4;
+ } else {
+ free(str);
+ return NULL;
+ }
+ val |= CLI_MATCH_NIBBLE_HIGH;
+
+ } else if(hex[i] == '?') {
+ if((c = cli_hex2int(hex[i + 1])) >= 0) {
+ val = c;
+ } else {
+ free(str);
+ return NULL;
+ }
+ val |= CLI_MATCH_NIBBLE_LOW;
+
+ } else if(hex[i] == '(') {
+ val |= CLI_MATCH_ALTERNATIVE;
+
+ } else {
+ if((c = cli_hex2int(hex[i])) >= 0) {
+ val = c;
+ if((c = cli_hex2int(hex[i+1])) >= 0) {
+ val = (val << 4) + c;
+ } else {
+ free(str);
+ return NULL;
+ }
+ } else {
+ free(str);
+ return NULL;
+ }
+ }
+
+ *ptr++ = val;
+ }
+
+ return str;
+}
+
+char *cli_hex2str(const char *hex)
+{
+ char *str, *ptr, val, c;
+ int i, len;
+
+
+ len = strlen(hex);
+
+ if(len % 2 != 0) {
+ cli_errmsg("cli_hex2str(): Malformed hexstring: %s (length: %d)\n", hex, len);
+ return NULL;
+ }
+
+ str = cli_calloc((len / 2) + 1, sizeof(char));
+ if(!str)
+ return NULL;
+
+ ptr = str;
+
+ for(i = 0; i < len; i += 2) {
+ if((c = cli_hex2int(hex[i])) >= 0) {
+ val = c;
+ if((c = cli_hex2int(hex[i+1])) >= 0) {
+ val = (val << 4) + c;
+ } else {
+ free(str);
+ return NULL;
+ }
+ } else {
+ free(str);
+ return NULL;
+ }
+
+ *ptr++ = val;
+ }
+
+ return str;
+}
+
+int cli_hex2num(const char *hex)
+{
+ int hexval, ret = 0, len, i;
+
+
+ len = strlen(hex);
+
+ if(len % 2 != 0) {
+ cli_errmsg("cli_hex2num(): Malformed hexstring: %s (length: %d)\n", hex, len);
+ return -1;
+ }
+
+ for(i = 0; i < len; i++) {
+ if((hexval = cli_hex2int(hex[i])) < 0)
+ break;
+ ret = (ret << 4) | hexval;
+ }
+
+ return ret;
+}
+
+char *cli_str2hex(const char *string, unsigned int len)
+{
+ char *hexstr;
+ char HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+ unsigned int i, j;
+
+ if((hexstr = (char *) cli_calloc(2 * len + 1, sizeof(char))) == NULL)
+ return NULL;
+
+ for(i = 0, j = 0; i < len; i++, j += 2) {
+ hexstr[j] = HEX[(string[i] >> 4) & 0xf];
+ hexstr[j + 1] = HEX[string[i] & 0xf];
+ }
+
+ return hexstr;
+}
+
+char *cli_utf16toascii(const char *str, unsigned int length)
+{
+ char *decoded;
+ unsigned int i, j;
+
+
+ if(length < 2) {
+ cli_warnmsg("cli_utf16toascii: length < 2\n");
+ return NULL;
+ }
+
+ if(length % 2)
+ length--;
+
+ if(!(decoded = cli_calloc(length / 2 + 1, sizeof(char))))
+ return NULL;
+
+ for(i = 0, j = 0; i < length; i += 2, j++) {
+ decoded[j] = str[i + 1] << 4;
+ decoded[j] += str[i];
+ }
+
+ return decoded;
+}
+
+int cli_strbcasestr(const char *haystack, const char *needle)
+{
+ const char *pt = haystack;
+ int i, j;
+
+ i = strlen(haystack);
+ j = strlen(needle);
+
+ if(i < j)
+ return 0;
+
+ pt += i - j;
+
+ return !strcasecmp(pt, needle);
+}
+
+/*
+ * Remove trailing NL and CR characters from the end of the given string.
+ * Return the new length of the string (ala strlen)
+ */
+int
+cli_chomp(char *string)
+{
+ int l;
+
+ if(string == NULL)
+ return -1;
+
+ l = strlen(string);
+
+ if(l == 0)
+ return 0;
+
+ --l;
+
+ while((l >= 0) && ((string[l] == '\n') || (string[l] == '\r')))
+ string[l--] = '\0';
+
+ return l + 1;
+}
+
+/*
+ * char *cli_strok(const char *line, int fieldno, char *delim)
+ * Return a copy of field <fieldno> from the string <line>, where
+ * fields are delimited by any char from <delim>, or NULL if <line>
+ * doesn't have <fieldno> fields or not enough memory is available.
+ * The caller has to free() the result afterwards.
+ */
+char *cli_strtok(const char *line, int fieldno, const char *delim)
+{
+ int counter = 0, i, j;
+ char *buffer = NULL;
+
+
+ /* step to arg # <fieldno> */
+ for (i=0; line[i] && counter != fieldno; i++) {
+ if (strchr(delim, line[i])) {
+ counter++;
+ while(line[i+1] && strchr(delim, line[i+1])) {
+ i++;
+ }
+ }
+ }
+ if (!line[i]) {
+ /* end of buffer before field reached */
+ return NULL;
+ }
+
+ for (j=i; line[j]; j++) {
+ if (strchr(delim, line[j])) {
+ break;
+ }
+ }
+ if (i == j) {
+ return NULL;
+ }
+ buffer = cli_malloc(j-i+1);
+ if(!buffer)
+ return NULL;
+ strncpy(buffer, line+i, j-i);
+ buffer[j-i] = '\0';
+
+ return buffer;
+}
+
+/*
+ * Like cli_strtok, but this puts the output into a given argument, rather
+ * than allocating fresh memory
+ * Returns NULL for error, or a pointer to output
+ * njh at bandsman.co.uk
+ */
+char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output)
+{
+ int counter = 0, i, j;
+
+ /* step to arg # <fieldno> */
+ for (i=0; input[i] && counter != fieldno; i++) {
+ if (strchr(delim, input[i])) {
+ counter++;
+ while(input[i+1] && strchr(delim, input[i+1])) {
+ i++;
+ }
+ }
+ }
+ if (input[i] == '\0') {
+ /* end of buffer before field reached */
+ return NULL;
+ }
+
+ for (j=i; input[j]; j++) {
+ if (strchr(delim, input[j])) {
+ break;
+ }
+ }
+ if (i == j) {
+ return NULL;
+ }
+ strncpy(output, input+i, j-i);
+ output[j-i] = '\0';
+
+ return output;
+}
+
+const char *cli_memstr(const char *haystack, int hs, const char *needle, int ns)
+{
+ const char *pt, *hay;
+ int n;
+
+
+ if(hs < ns)
+ return NULL;
+
+ if(haystack == needle)
+ return haystack;
+
+ if(!memcmp(haystack, needle, ns))
+ return haystack;
+
+ pt = hay = haystack;
+ n = hs;
+
+ while((pt = memchr(hay, needle[0], n)) != NULL) {
+ n -= (int) (pt - hay);
+ if(n < ns)
+ break;
+
+ if(!memcmp(pt, needle, ns))
+ return pt;
+
+ if(hay == pt) {
+ n--;
+ hay++;
+ } else {
+ hay = pt;
+ }
+ }
+
+ return NULL;
+}
+
+char *cli_strrcpy(char *dest, const char *source) /* by NJH */
+{
+
+ if(!dest || !source) {
+ cli_errmsg("cli_strrcpy: NULL argument\n");
+ return NULL;
+ }
+
+ while((*dest++ = *source++));
+
+ return --dest;
+}
+
+void cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens)
+{
+ size_t tokens_found;
+
+
+ for(tokens_found = 0; tokens_found < token_count; ) {
+ tokens[tokens_found++] = buffer;
+ buffer = strchr(buffer, delim);
+ if(buffer) {
+ *buffer++ = '\0';
+ } else {
+ while(tokens_found < token_count)
+ tokens[tokens_found++] = NULL;
+
+ return;
+ }
+ }
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_suecrypt.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by aCaB <acab at clamav.net>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+/*
+** suecrypt.c
+**
+** 05/08/2k6 - Quick RCE, started coding.
+** 06/08/2k6 - There were large drops of black rain.
+** 07/08/2k6 - Found more versions, back to reversing.
+** 11/08/2k6 - Generic and special cases handler. Release.
+**
+*/
+
+/*
+** Unpacks and rebuilds suecrypt(*)
+**
+** Not sure at all what this stuff is, couldn't find any reference to it
+** Seems to be popular in dialers, can't say more except...
+** Christoph asked for it and that's enough :)
+**
+** (*) some versions or maybe only some samples
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "pe.h"
+#include "suecrypt.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x)
+
+char *sudecrypt(int desc, size_t fsize, struct cli_exe_section *sections, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) {
+ char *file, *hunk;
+ uint32_t va,sz,key;
+ int i, j;
+
+ cli_dbgmsg("in suecrypt\n");
+
+ if (!(file=cli_calloc(fsize, 1))) return 0;
+ lseek(desc, 0, SEEK_SET);
+ if((size_t) cli_readn(desc, file, fsize) != fsize) {
+ cli_dbgmsg("SUE: Can't read %d bytes\n", fsize);
+ free(file);
+ return 0;
+ }
+
+ va=(bkey>>16)|(bkey<<16);
+ key=((sz=cli_readint32(buff+0x3e))^va);
+ if (!key || key==0x208 || key==0x3bc) key=((sz=cli_readint32(buff+0x46))^va); /* FIXME: black magic */
+
+ if (key!=pkey) {
+ cli_dbgmsg("SUE: Key seems not (entirely) encrypted\n\tpossible key: 0%08x\n\tcrypted key: 0%08x\n\tplain key: 0%08x\n", pkey, key, sz);
+ va=0;
+ for (i=0; i<4; i++) {
+ va=(va<<8)|0xff;
+ if (((key&va)|(sz&(~va)))==pkey) {
+ key=pkey;
+ break;
+ }
+ }
+ if (i==4) cli_dbgmsg("SUE: let's roll the dice...\n");
+ }
+ cli_dbgmsg("SUE: Decrypting with 0%08x\n", key);
+
+ i=0;
+ while(1) {
+ if (!CLI_ISCONTAINED(buff-0x74, 0xbe, buff-0x58+i*8, 8)) {
+ free(file);
+ return 0;
+ }
+ va=(cli_readint32(buff-0x58+i*8)^bkey);
+ sz=(cli_readint32(buff-0x58+4+i*8)^bkey);
+ if (!va) break;
+ cli_dbgmsg("SUE: Hunk #%d RVA:%x size:%d\n", i, va, sz);
+ for (j=0; j<sects; j++) {
+ if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue;
+ hunk=file+sections[j].rva-va+sections[j].raw;
+ while(sz>=4) {
+ cli_writeint32(hunk, cli_readint32(hunk)^key);
+ hunk+=4;
+ sz-=4;
+ }
+ break;
+ }
+ if (j==sects) {
+ cli_dbgmsg("SUE: Hunk out of file or cross sections\n");
+ free(file);
+ return 0;
+ }
+ i++;
+ }
+ va=(cli_readint32(buff-0x74)^bkey);
+ cli_dbgmsg("SUE: found OEP: @%x\n", va);
+
+ hunk=file+e_lfanew;
+ hunk[6]=sects&0xff;
+ hunk[7]=sects>>8;
+ cli_writeint32(hunk+0x28, va);
+ hunk+=0x18+(cli_readint32(hunk+0x14)&0xffff); /* size of PE + size of OPT */
+ memset(hunk+0x28*sects, 0, 0x28);
+
+ return file;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_table.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * TODO: Allow individual items to be updated or removed
+ *
+ * It is up to the caller to create a mutex for the table if needed
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifndef CL_DEBUG
+#define NDEBUG /* map CLAMAV debug onto standard */
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include <assert.h>
+
+#include "table.h"
+#include "others.h"
+
+struct table *
+tableCreate(void)
+{
+ return (struct table *)cli_calloc(1, sizeof(struct table));
+}
+
+void
+tableDestroy(table_t *table)
+{
+ tableEntry *tableItem;
+
+ assert(table != NULL);
+
+ tableItem = table->tableHead;
+
+ while(tableItem) {
+ tableEntry *tableNext = tableItem->next;
+
+ if(tableItem->key)
+ free(tableItem->key);
+ free(tableItem);
+
+ tableItem = tableNext;
+ }
+
+ free(table);
+}
+
+/*
+ * Returns the value, or -1 for failure
+ */
+int
+tableInsert(table_t *table, const char *key, int value)
+{
+ const int v = tableFind(table, key);
+
+ if(v > 0) /* duplicate key */
+ return (v == value) ? value : -1; /* allow real dups */
+
+ assert(value != -1); /* that would confuse us */
+
+ if(table->tableHead == NULL)
+ table->tableLast = table->tableHead = (tableEntry *)cli_malloc(sizeof(tableEntry));
+ else {
+ /*
+ * Re-use deleted items
+ */
+ if(table->flags&TABLE_HAS_DELETED_ENTRIES) {
+ tableEntry *tableItem;
+
+ assert(table->tableHead != NULL);
+
+ for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+ if(tableItem->key == NULL) {
+ /* This item has been deleted */
+ tableItem->key = cli_strdup(key);
+ tableItem->value = value;
+ return value;
+ }
+
+ table->flags &= ~TABLE_HAS_DELETED_ENTRIES;
+ }
+
+ table->tableLast = table->tableLast->next =
+ (tableEntry *)cli_malloc(sizeof(tableEntry));
+ }
+
+ if(table->tableLast == NULL)
+ return -1;
+
+ table->tableLast->next = NULL;
+ table->tableLast->key = cli_strdup(key);
+ table->tableLast->value = value;
+
+ return value;
+}
+
+/*
+ * Returns the value - -1 for not found. This means the value of a valid key
+ * can't be -1 :-(
+ */
+int
+tableFind(const table_t *table, const char *key)
+{
+ const tableEntry *tableItem;
+#ifdef CL_DEBUG
+ int cost;
+#endif
+
+ assert(table != NULL);
+
+ if(key == NULL)
+ return -1; /* not treated as a fatal error */
+
+#ifdef CL_DEBUG
+ cost = 0;
+#endif
+
+ for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) {
+#ifdef CL_DEBUG
+ cost++;
+#endif
+ if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+#ifdef CL_DEBUG
+ cli_dbgmsg("tableFind: Cost of '%s' = %d\n", key, cost);
+#endif
+ return tableItem->value;
+ }
+ }
+
+ return -1; /* not found */
+}
+
+/*
+ * Change a value in the table. If the key isn't in the table insert it
+ * Returns -1 for error, otherwise the new value
+ */
+int
+tableUpdate(table_t *table, const char *key, int new_value)
+{
+ tableEntry *tableItem;
+
+ assert(table != NULL);
+
+ if(key == NULL)
+ return -1; /* not treated as a fatal error */
+
+ for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+ if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+ tableItem->value = new_value;
+ return new_value;
+ }
+
+ /* not found */
+ return tableInsert(table, key, new_value);
+}
+
+/*
+ * Remove an item from the table
+ */
+void
+tableRemove(table_t *table, const char *key)
+{
+ tableEntry *tableItem;
+
+ assert(table != NULL);
+
+ if(key == NULL)
+ return; /* not treated as a fatal error */
+
+ for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+ if(tableItem->key && (strcasecmp(tableItem->key, key) == 0)) {
+ free(tableItem->key);
+ tableItem->key = NULL;
+ table->flags |= TABLE_HAS_DELETED_ENTRIES;
+ /* don't break, duplicate keys are allowed */
+ }
+}
+
+void
+tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg)
+{
+ tableEntry *tableItem;
+
+ if(table == NULL)
+ return;
+
+ for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next)
+ if(tableItem->key) /* check node has not been deleted */
+ (*callback)(tableItem->key, tableItem->value, arg);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_text.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * $Log: text.c,v $
+ * Revision 1.25 2007/02/12 20:46:09 njh
+ * Various tidy
+ *
+ * Revision 1.24 2006/09/13 20:53:50 njh
+ * Added debug
+ *
+ * Revision 1.23 2006/07/14 12:13:08 njh
+ * Typo
+ *
+ * Revision 1.22 2006/07/01 21:03:36 njh
+ * Better use of destroy mode
+ *
+ * Revision 1.21 2006/07/01 16:17:35 njh
+ * Added destroy flag
+ *
+ * Revision 1.20 2006/07/01 03:47:50 njh
+ * Don't loop if binhex runs out of memory
+ *
+ * Revision 1.19 2006/05/19 11:02:12 njh
+ * Just include mbox.h
+ *
+ * Revision 1.18 2006/05/04 10:37:03 nigelhorne
+ * Speed up scanning of clean files
+ *
+ * Revision 1.17 2006/05/03 09:36:40 nigelhorne
+ * Pass full ctx into the mbox code
+ *
+ * Revision 1.16 2006/04/09 19:59:28 kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.15 2005/03/10 08:50:49 nigelhorne
+ * Tidy
+ *
+ * Revision 1.14 2005/01/19 05:31:55 nigelhorne
+ * Added textIterate
+ *
+ * Revision 1.13 2004/12/08 19:03:41 nigelhorne
+ * Fix compilation error on Solaris
+ *
+ * Revision 1.12 2004/12/04 16:03:55 nigelhorne
+ * Text/plain now handled as no encoding
+ *
+ * Revision 1.11 2004/11/27 21:54:26 nigelhorne
+ * Tidy
+ *
+ * Revision 1.10 2004/08/22 10:34:24 nigelhorne
+ * Use fileblob
+ *
+ * Revision 1.9 2004/08/21 11:57:57 nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.8 2004/07/20 14:35:29 nigelhorne
+ * Some MYDOOM.I were getting through
+ *
+ * Revision 1.7 2004/06/22 04:08:02 nigelhorne
+ * Optimise empty lines
+ *
+ * Revision 1.6 2004/05/05 09:37:52 nigelhorne
+ * Removed textClean - not needed in clamAV
+ *
+ * Revision 1.5 2004/03/25 22:40:46 nigelhorne
+ * Removed even more calls to realloc and some duplicated code
+ *
+ * Revision 1.4 2004/02/26 13:26:34 nigelhorne
+ * Handle spaces at the end of uuencoded lines
+ *
+ */
+
+static char const rcsid[] = "$Id: text.c,v 1.25 2007/02/12 20:46:09 njh Exp $";
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifndef CL_DEBUG
+#define NDEBUG /* map CLAMAV debug onto standard */
+#endif
+
+#include <stdlib.h>
+#ifdef C_DARWIN
+#include <sys/types.h>
+#include <sys/malloc.h>
+#else
+#ifdef HAVE_MALLOC_H /* tk: FreeBSD-CURRENT doesn't support malloc.h */
+#ifndef C_BSD /* BSD now uses stdlib.h */
+#include <malloc.h>
+#endif
+#endif
+#endif
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdio.h>
+
+#include "others.h"
+
+#include "mbox.h"
+
+static text *textCopy(const text *t_head);
+static text *textAdd(text *t_head, const text *t);
+static void addToFileblob(const line_t *line, void *arg);
+static void getLength(const line_t *line, void *arg);
+static void addToBlob(const line_t *line, void *arg);
+static void *textIterate(text *t_text, void (*cb)(const line_t *line, void *arg), void *arg, int destroy);
+
+void
+textDestroy(text *t_head)
+{
+ while(t_head) {
+ text *t_next = t_head->t_next;
+ if(t_head->t_line)
+ (void)lineUnlink(t_head->t_line);
+ free(t_head);
+ t_head = t_next;
+ }
+}
+
+/* Clone the current object */
+static text *
+textCopy(const text *t_head)
+{
+ text *first = NULL, *last = NULL;
+
+ while(t_head) {
+ if(first == NULL)
+ last = first = (text *)cli_malloc(sizeof(text));
+ else {
+ last->t_next = (text *)cli_malloc(sizeof(text));
+ last = last->t_next;
+ }
+
+ if(last == NULL) {
+ if(first)
+ textDestroy(first);
+ return NULL;
+ }
+
+ if(t_head->t_line)
+ last->t_line = lineLink(t_head->t_line);
+ else
+ last->t_line = NULL;
+
+ t_head = t_head->t_next;
+ }
+
+ if(first)
+ last->t_next = NULL;
+
+ return first;
+}
+
+/* Add a copy of a text to the end of the current object */
+static text *
+textAdd(text *t_head, const text *t)
+{
+ text *ret;
+ int count;
+
+ if(t_head == NULL) {
+ if(t == NULL) {
+ cli_errmsg("textAdd fails sanity check\n");
+ return NULL;
+ }
+ return textCopy(t);
+ }
+
+ if(t == NULL)
+ return t_head;
+
+ ret = t_head;
+
+ count = 0;
+ while(t_head->t_next) {
+ count++;
+ t_head = t_head->t_next;
+ }
+
+ cli_dbgmsg("textAdd: count = %d\n", count);
+
+ while(t) {
+ t_head->t_next = (text *)cli_malloc(sizeof(text));
+ t_head = t_head->t_next;
+
+ assert(t_head != NULL);
+
+ if(t->t_line)
+ t_head->t_line = lineLink(t->t_line);
+ else
+ t_head->t_line = NULL;
+
+ t = t->t_next;
+ }
+
+ t_head->t_next = NULL;
+
+ return ret;
+}
+
+/*
+ * Add a message's content to the end of the current object
+ */
+text *
+textAddMessage(text *aText, message *aMessage)
+{
+ assert(aMessage != NULL);
+
+ if(messageGetEncoding(aMessage) == NOENCODING)
+ return textAdd(aText, messageGetBody(aMessage));
+ else {
+ text *anotherText = messageToText(aMessage);
+
+ if(aText)
+ return textMove(aText, anotherText);
+ return anotherText;
+ }
+}
+
+/*
+ * Put the contents of the given text at the end of the current object.
+ * The given text emptied; it can be used again if needed, though be warned that
+ * it will have an empty line at the start.
+ */
+text *
+textMove(text *t_head, text *t)
+{
+ text *ret;
+
+ if(t_head == NULL) {
+ if(t == NULL) {
+ cli_errmsg("textMove fails sanity check\n");
+ return NULL;
+ }
+ t_head = (text *)cli_malloc(sizeof(text));
+ if(t_head == NULL)
+ return NULL;
+ t_head->t_line = t->t_line;
+ t_head->t_next = t->t_next;
+ t->t_line = NULL;
+ t->t_next = NULL;
+ return t_head;
+ }
+
+ if(t == NULL)
+ return t_head;
+
+ ret = t_head;
+
+ while(t_head->t_next)
+ t_head = t_head->t_next;
+
+ /*
+ * Move the first line manually so that the caller is left clean but
+ * empty, the rest is moved by a simple pointer reassignment
+ */
+ t_head->t_next = (text *)cli_malloc(sizeof(text));
+ if(t_head->t_next == NULL)
+ return NULL;
+ t_head = t_head->t_next;
+
+ assert(t_head != NULL);
+
+ if(t->t_line) {
+ t_head->t_line = t->t_line;
+ t->t_line = NULL;
+ } else
+ t_head->t_line = NULL;
+
+ t_head->t_next = t->t_next;
+ t->t_next = NULL;
+
+ return ret;
+}
+
+/*
+ * Transfer the contents of the text into a blob
+ * The caller must free the returned blob if b is NULL
+ */
+blob *
+textToBlob(text *t, blob *b, int destroy)
+{
+ size_t s;
+ blob *bin;
+
+ if(t == NULL)
+ return NULL;
+
+ s = 0;
+
+ (void)textIterate(t, getLength, &s, 0);
+
+ if(s == 0)
+ return b;
+
+ /*
+ * copy b. If b is NULL and an error occurs we know we need to free
+ * before returning
+ */
+ bin = b;
+ if(b == NULL) {
+ b = blobCreate();
+
+ if(b == NULL)
+ return NULL;
+ }
+
+ if(blobGrow(b, s) != CL_SUCCESS) {
+ cli_warnmsg("Couldn't grow the blob: we may be low on memory\n");
+#if 0
+ if(!destroy) {
+ if(bin == NULL)
+ blobDestroy(b);
+ return NULL;
+ }
+ /*
+ * We may be able to recover enough memory as we destroy to
+ * create the blob
+ */
+#else
+ if(bin == NULL)
+ blobDestroy(b);
+ return NULL;
+#endif
+ }
+
+ (void)textIterate(t, addToBlob, b, destroy);
+
+ if(destroy && t->t_next) {
+ textDestroy(t->t_next);
+ t->t_next = NULL;
+ }
+
+ blobClose(b);
+
+ return b;
+}
+
+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;
+}
+
+static void
+getLength(const line_t *line, void *arg)
+{
+ size_t *length = (size_t *)arg;
+
+ if(line)
+ *length += strlen(lineGetData(line)) + 1;
+ else
+ (*length)++;
+}
+
+static void
+addToBlob(const line_t *line, void *arg)
+{
+ blob *b = (blob *)arg;
+
+ if(line) {
+ const char *l = lineGetData(line);
+
+ blobAddData(b, (const unsigned char *)l, strlen(l));
+ }
+ blobAddData(b, (const unsigned char *)"\n", 1);
+}
+
+static void
+addToFileblob(const line_t *line, void *arg)
+{
+ fileblob *fb = (fileblob *)arg;
+
+ if(line) {
+ const char *l = lineGetData(line);
+
+ fileblobAddData(fb, (const unsigned char *)l, strlen(l));
+ }
+ fileblobAddData(fb, (const unsigned char *)"\n", 1);
+}
+
+static void *
+textIterate(text *t_text, void (*cb)(const line_t *item, void *arg), void *arg, int destroy)
+{
+ /*
+ * Have two loops rather than one, so that we're not checking the
+ * value of "destroy" lots and lots of times
+ */
+#if 0
+ while(t_text) {
+ (*cb)(t_text->t_line, arg);
+
+ if(destroy && t_text->t_line) {
+ lineUnlink(t_text->t_line);
+ t_text->t_line = NULL;
+ }
+
+ t_text = t_text->t_next;
+ }
+#else
+ if(destroy)
+ while(t_text) {
+ (*cb)(t_text->t_line, arg);
+
+ if(t_text->t_line) {
+ lineUnlink(t_text->t_line);
+ t_text->t_line = NULL;
+ }
+
+ t_text = t_text->t_next;
+ }
+ else
+ while(t_text) {
+ (*cb)(t_text->t_line, arg);
+
+ t_text = t_text->t_next;
+ }
+#endif
+ return arg;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_tnef.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * The algorithm is based on kdepim/ktnef/lib/ktnefparser.cpp from
+ * KDE, rewritten in C by NJH. That algorithm is released under the GPL and is
+ * Copyright (C) 2002 Michael Goffioul <kdeprint at swing.be>
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+static char const rcsid[] = "$Id: tnef.c,v 1.41 2007/02/12 22:22:27 njh Exp $";
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "cltypes.h"
+#include "clamav.h"
+#include "others.h"
+
+#include "mbox.h"
+#include "tnef.h"
+
+static int tnef_message(FILE *fp, uint16_t type, uint16_t tag, int32_t length, off_t fsize);
+static int tnef_attachment(FILE *fp, uint16_t type, uint16_t tag, int32_t length, const char *dir, fileblob **fbref, off_t fsize);
+static int tnef_header(FILE *fp, uint8_t *part, uint16_t *type, uint16_t *tag, int32_t *length);
+
+#define TNEF_SIGNATURE 0x223E9f78
+#define LVL_MESSAGE 0x01
+#define LVL_ATTACHMENT 0x02
+
+#define attMSGCLASS 0x8008
+#define attBODY 0x800c
+#define attATTACHDATA 0x800f /* Attachment Data */
+#define attATTACHTITLE 0x8010 /* Attachment File Name */
+#define attDATEMODIFIED 0x8020
+#define attTNEFVERSION 0x9006
+#define attOEMCODEPAGE 0x9007
+
+#define host16(v) le16_to_host(v)
+#define host32(v) le32_to_host(v)
+
+
+int
+cli_tnef(const char *dir, int desc)
+{
+ uint32_t i32;
+ uint16_t i16;
+ fileblob *fb;
+ int i, ret, alldone;
+ FILE *fp;
+ off_t fsize;
+ struct stat statb;
+
+ lseek(desc, 0L, SEEK_SET);
+
+ if(fstat(desc, &statb) < 0) {
+ cli_errmsg("Can't fstat descriptor %d\n", desc);
+ return CL_EIO;
+ }
+ fsize = statb.st_size;
+
+ i = dup(desc);
+ if((fp = fdopen(i, "rb")) == NULL) {
+ cli_errmsg("Can't open descriptor %d\n", desc);
+ close(i);
+ return CL_EOPEN;
+ }
+
+ if(fread(&i32, sizeof(uint32_t), 1, fp) != 1) {
+ fclose(fp);
+ return CL_EIO;
+ }
+ if(host32(i32) != TNEF_SIGNATURE) {
+ fclose(fp);
+ return CL_EFORMAT;
+ }
+
+ if(fread(&i16, sizeof(uint16_t), 1, fp) != 1) {
+ fclose(fp);
+ return CL_EIO;
+ }
+
+ 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(fp, &part, &type, &tag, &length)) {
+ case 0:
+ if(ferror(fp)) {
+ perror("read");
+ ret = CL_EIO;
+ }
+ alldone = 1;
+ break;
+ case 1:
+ break;
+ default:
+ ret = CL_EIO;
+ 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(fp, type, tag, length, fsize) != 0) {
+ cli_errmsg("Error reading TNEF message\n");
+ ret = CL_EFORMAT;
+ alldone = 1;
+ }
+ break;
+ case LVL_ATTACHMENT:
+ cli_dbgmsg("TNEF - found attachment\n");
+ if(tnef_attachment(fp, type, tag, length, dir, &fb, fsize) != 0) {
+ cli_errmsg("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;
+ char *filename = cli_gentemp(NULL);
+ char buffer[BUFSIZ];
+
+#ifdef O_BINARY
+ fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
+#else
+ fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600);
+#endif
+
+ if(fout >= 0) {
+ int count;
+
+ cli_warnmsg("Saving dump to %s: refer to http://www.clamav.net/bugs\n", filename);
+
+ lseek(desc, 0L, SEEK_SET);
+ while((count = cli_readn(desc, buffer, sizeof(buffer))) > 0)
+ cli_writen(fout, buffer, count);
+ close(fout);
+ }
+ free(filename);
+ }
+ ret = CL_EFORMAT;
+ alldone = 1;
+ break;
+ }
+ } while(!alldone);
+
+ fclose(fp);
+
+ 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_message(FILE *fp, uint16_t type, uint16_t tag, int32_t length, off_t fsize)
+{
+ uint16_t i16;
+ off_t offset;
+#ifdef CL_DEBUG
+ uint32_t i32;
+ char *string;
+#endif
+
+ cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n", tag, type,
+ (int)length);
+
+ offset = ftell(fp);
+
+ /*
+ * a lot of this stuff should be only discovered in debug mode...
+ */
+ switch(tag) {
+ case attBODY:
+ cli_warnmsg("TNEF body not being scanned - if you believe this file contains a virus, submit it to www.clamav.net\n");
+ break;
+#ifdef CL_DEBUG
+ case attTNEFVERSION:
+ /*assert(length == sizeof(uint32_t))*/
+ if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+ return -1;
+ i32 = host32(i32);
+ cli_dbgmsg("TNEF version %d\n", i32);
+ break;
+ case attOEMCODEPAGE:
+ /* 8 bytes, but just print the first 4 */
+ /*assert(length == sizeof(uint32_t))*/
+ if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+ return -1;
+ i32 = host32(i32);
+ cli_dbgmsg("TNEF codepage %d\n", i32);
+ break;
+ case attDATEMODIFIED:
+ /* 14 bytes, long */
+ break;
+ case attMSGCLASS:
+ if(length <= 0)
+ return -1;
+ string = cli_malloc(length + 1);
+ if(string == NULL)
+ return -1;
+ if(fread(string, 1, (uint32_t)length, fp) != (uint32_t)length) {
+ free(string);
+ return -1;
+ }
+ string[length] = '\0';
+ cli_dbgmsg("TNEF class %s\n", string);
+ free(string);
+ break;
+ default:
+ cli_dbgmsg("TNEF - unsupported message tag 0x%x type 0x%d length %d\n", tag, type, length);
+ break;
+#endif
+ }
+
+ /*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/
+
+ if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) {
+ cli_errmsg("TNEF: Incorrect length field in tnef_message\n");
+ return -1;
+ }
+ if(fseek(fp, offset + length, SEEK_SET) < 0)
+ return -1;
+
+ /* Checksum - TODO, verify */
+ if(fread(&i16, sizeof(uint16_t), 1, fp) != 1)
+ return -1;
+
+ return 0;
+}
+
+static int
+tnef_attachment(FILE *fp, 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 = ftell(fp);
+
+ switch(tag) {
+ case attATTACHTITLE:
+ if(length <= 0)
+ return -1;
+ string = cli_malloc(length + 1);
+ if(string == NULL)
+ return -1;
+ if(fread(string, 1, (uint32_t)length, fp) != (uint32_t)length) {
+ free(string);
+ return -1;
+ }
+ 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;
+ }
+ for(todo = length; todo; todo--) {
+#if WORDS_BIGENDIAN == 1
+ int c;
+ unsigned char c2;
+
+ if((c = fgetc(fp)) == EOF)
+ break;
+ c2 = (unsigned char)c;
+ fileblobAddData(*fbref, (const unsigned char *)&c2, 1);
+#else
+ int c;
+
+ if((c = fgetc(fp)) == EOF)
+ break;
+ fileblobAddData(*fbref, (const unsigned char *)&c, 1);
+#endif
+ }
+ 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_errmsg("TNEF: Incorrect length field in tnef_attachment\n");
+ return -1;
+ }
+ if(fseek(fp, (long)(offset + length), SEEK_SET) < 0) /* shouldn't be needed */
+ return -1;
+
+ /* Checksum - TODO, verify */
+ if(fread(&i16, sizeof(uint16_t), 1, fp) != 1)
+ return -1;
+
+ return 0;
+}
+
+static int
+tnef_header(FILE *fp, uint8_t *part, uint16_t *type, uint16_t *tag, int32_t *length)
+{
+ uint32_t i32;
+
+ if(fread(part, sizeof(uint8_t), 1, fp) != 1)
+ return 0;
+
+ if(*part == (uint8_t)0)
+ return 0;
+
+ if(fread(&i32, sizeof(uint32_t), 1, fp) != 1) {
+ if((*part == '\n') && feof(fp)) {
+ /*
+ * trailing newline in the file, could be caused by
+ * broken quoted-printable encoding in the source
+ * message missing a final '='
+ */
+ cli_dbgmsg("tnef_header: ignoring trailing newline\n");
+ return 0;
+ }
+ return -1;
+ }
+
+ i32 = host32(i32);
+ *tag = (uint16_t)(i32 & 0xFFFF);
+ *type = (uint16_t)((i32 & 0xFFFF0000) >> 16);
+
+ if(fread(&i32, sizeof(uint32_t), 1, fp) != 1)
+ return -1;
+ *length = (int32_t)host32(i32);
+
+ cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n",
+ *tag, *type, (int)*length);
+
+ return 1;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unarj.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,991 @@
+/*
+ * Extract component parts of ARJ archives.
+ *
+ * Copyright (C) 2007 trog at uncon.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <clamav.h>
+#include <ctype.h>
+
+#include "clamav.h"
+#include "cltypes.h"
+#include "others.h"
+#include "unarj.h"
+
+#define FIRST_HDR_SIZE 30
+#define COMMENT_MAX 2048
+#define FNAME_MAX 512
+#define HEADERSIZE_MAX (FIRST_HDR_SIZE + 10 + FNAME_MAX + COMMENT_MAX)
+#define MAXDICBIT 16
+#define DDICSIZ 26624
+#define THRESHOLD 3
+#ifndef UCHAR_MAX
+#define UCHAR_MAX (255)
+#endif
+#ifndef CHAR_BIT
+#define CHAR_BIT (8)
+#endif
+#define MAXMATCH 256
+#ifndef FALSE
+#define FALSE (0)
+#define TRUE (1)
+#endif
+
+#define CODE_BIT 16
+#define NT (CODE_BIT + 3)
+#define PBIT 5
+#define TBIT 5
+#define NC (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
+#define NP (MAXDICBIT + 1)
+#define CBIT 9
+#define CTABLESIZE 4096
+#define PTABLESIZE 256
+#define STRTP 9
+#define STOPP 13
+
+#define STRTL 0
+#define STOPL 7
+
+#if NT > NP
+#define NPT NT
+#else
+#define NPT NP
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a < b) ? a : b)
+#endif
+
+#define GARBLE_FLAG 0x01
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+typedef struct arj_main_hdr_tag {
+ uint8_t first_hdr_size; /* must be 30 bytes */
+ uint8_t version;
+ uint8_t min_version;
+ uint8_t host_os;
+ uint8_t flags;
+ uint8_t security_version;
+ uint8_t file_type;
+ uint8_t pad;
+ uint32_t time_created __attribute__ ((packed));
+ uint32_t time_modified __attribute__ ((packed));
+ uint32_t archive_size __attribute__ ((packed));
+ uint32_t sec_env_file_position __attribute__ ((packed));
+ uint16_t entryname_pos __attribute__ ((packed));
+ uint16_t sec_trail_size __attribute__ ((packed));
+ uint16_t host_data __attribute__ ((packed));
+} arj_main_hdr_t;
+
+typedef struct arj_file_hdr_tag {
+ uint8_t first_hdr_size; /* must be 30 bytes */
+ uint8_t version;
+ uint8_t min_version;
+ uint8_t host_os;
+ uint8_t flags;
+ uint8_t method;
+ uint8_t file_type;
+ uint8_t password_mod;
+ uint32_t time_modified __attribute__ ((packed));
+ uint32_t comp_size __attribute__ ((packed));
+ uint32_t orig_size __attribute__ ((packed));
+ uint32_t orig_crc __attribute__ ((packed));
+ uint16_t entryname_pos __attribute__ ((packed));
+ uint16_t file_mode __attribute__ ((packed));
+ uint16_t host_data __attribute__ ((packed));
+} arj_file_hdr_t;
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+typedef struct arj_decode_tag {
+ int fd;
+ unsigned char *text;
+ uint16_t blocksize;
+ uint16_t bit_buf;
+ unsigned char sub_bit_buf;
+ int bit_count;
+ uint32_t comp_size;
+ int16_t getlen, getbuf;
+ uint16_t left[2 * NC - 1];
+ uint16_t right[2 * NC - 1];
+ unsigned char c_len[NC];
+ uint16_t c_table[CTABLESIZE];
+ unsigned char pt_len[NPT];
+ uint16_t pt_table[PTABLESIZE];
+} arj_decode_t;
+
+static int fill_buf(arj_decode_t *decode_data, int n)
+{
+ decode_data->bit_buf = (decode_data->bit_buf << n) & 0xFFFF;
+ while (n > decode_data->bit_count) {
+ decode_data->bit_buf |= decode_data->sub_bit_buf << (n -= decode_data->bit_count);
+ if (decode_data->comp_size != 0) {
+ decode_data->comp_size--;
+ if (cli_readn(decode_data->fd, &decode_data->sub_bit_buf, 1) != 1) {
+ return CL_EIO;
+ }
+ } else {
+ decode_data->sub_bit_buf = 0;
+ }
+ decode_data->bit_count = CHAR_BIT;
+ }
+ decode_data->bit_buf |= decode_data->sub_bit_buf >> (decode_data->bit_count -= n);
+ return CL_SUCCESS;
+}
+
+static int init_getbits(arj_decode_t *decode_data)
+{
+ decode_data->bit_buf = 0;
+ decode_data->sub_bit_buf = 0;
+ decode_data->bit_count = 0;
+ return fill_buf(decode_data, 2 * CHAR_BIT);
+}
+
+static unsigned short arj_getbits(arj_decode_t *decode_data, int n)
+{
+ unsigned short x;
+
+ x = decode_data->bit_buf >> (2 * CHAR_BIT - n);
+ fill_buf(decode_data, n);
+ return x;
+}
+
+static int decode_start(arj_decode_t *decode_data)
+{
+ decode_data->blocksize = 0;
+ return init_getbits(decode_data);
+}
+
+static int write_text(int ofd, unsigned char *data, int length)
+{
+ int count;
+
+ count = cli_writen(ofd, data, length);
+ if (count != length) {
+ return CL_EIO;
+ } else {
+ return CL_SUCCESS;
+ }
+}
+
+static int make_table(arj_decode_t *decode_data, int nchar, unsigned char *bitlen, int tablebits,
+ unsigned short *table, int tablesize)
+{
+ unsigned short count[17], weight[17], start[18], *p;
+ unsigned int i, k, len, ch, jutbits, avail, nextcode, mask;
+
+ for (i = 1; i <=16; i++) {
+ count[i] = 0;
+ }
+ for (i = 0; (int)i < nchar; i++) {
+ count[bitlen[i]]++;
+ }
+
+ start[1] = 0;
+ for (i = 1; i <= 16; i++) {
+ start[i+1] = start[i] + (count[i] << (16 - i));
+ }
+ if (start[17] != (unsigned short) (1 << 16)) {
+ return CL_EARJ;
+ }
+
+ jutbits = 16 - tablebits;
+ for (i = 1; (int)i <= tablebits; i++) {
+ start[i] >>= jutbits;
+ weight[i] = 1 << (tablebits - i);
+ }
+ while (i <= 16) {
+ weight[i] = 1 << (16 - i);
+ i++;
+ }
+
+ i = start[tablebits + 1] >> jutbits;
+ if (i != (unsigned short) (1 << 16)) {
+ k = 1 << tablebits;
+ while (i != k) {
+ table[i++] = 0;
+ }
+ }
+
+ avail = nchar;
+ mask = 1 << (15 - tablebits);
+ for (ch = 0; (int)ch < nchar; ch++) {
+ if ((len = bitlen[ch]) == 0) {
+ continue;
+ }
+ k = start[len];
+ nextcode = k + weight[len];
+ if ((int)len <= tablebits) {
+ if (nextcode > (unsigned int) tablesize) {
+ return CL_EARJ;
+ }
+ for (i = start[len]; i < nextcode; i++) {
+ table[i] = ch;
+ }
+ } else {
+ p = &table[k >> jutbits];
+ i = len - tablebits;
+ while (i != 0) {
+ if (*p == 0) {
+ decode_data->right[avail] = decode_data->left[avail] = 0;
+ *p = avail++;
+ }
+ if (k & mask) {
+ p = &decode_data->right[*p];
+ } else {
+ p = &decode_data->left[*p];
+ }
+ k <<= 1;
+ i--;
+ }
+ *p = ch;
+ }
+ start[len] = nextcode;
+ }
+ return CL_SUCCESS;
+}
+
+static void read_pt_len(arj_decode_t *decode_data, int nn, int nbit, int i_special)
+{
+ int i, n;
+ short c;
+ unsigned short mask;
+
+ n = arj_getbits(decode_data, nbit);
+ if (n == 0) {
+ c = arj_getbits(decode_data, nbit);
+ for (i = 0; i < nn; i++) {
+ decode_data->pt_len[i] = 0;
+ }
+ for (i = 0; i < 256; i++) {
+ decode_data->pt_table[i] = c;
+ }
+ } else {
+ i = 0;
+ while ((i < n) && (i < NPT)) {
+ c = decode_data->bit_buf >> 13;
+ if (c == 7) {
+ mask = 1 << 12;
+ while (mask & decode_data->bit_buf) {
+ mask >>= 1;
+ c++;
+ }
+ }
+ fill_buf(decode_data, (c < 7) ? 3 : (int)(c - 3));
+ decode_data->pt_len[i++] = (unsigned char) c;
+ if (i == i_special) {
+ c = arj_getbits(decode_data, 2);
+ while ((--c >= 0) && (i < NPT)) {
+ decode_data->pt_len[i++] = 0;
+ }
+ }
+ }
+ while ((i < nn) && (i < NPT)) {
+ decode_data->pt_len[i++] = 0;
+ }
+ make_table(decode_data, nn, decode_data->pt_len, 8, decode_data->pt_table, PTABLESIZE);
+ }
+}
+
+static int read_c_len(arj_decode_t *decode_data)
+{
+ short i, c, n;
+ unsigned short mask;
+
+ n = arj_getbits(decode_data, CBIT);
+ if (n == 0) {
+ c = arj_getbits(decode_data, CBIT);
+ for (i = 0; i < NC; i++) {
+ decode_data->c_len[i] = 0;
+ }
+ for (i = 0; i < CTABLESIZE; i++) {
+ decode_data->c_table[i] = c;
+ }
+ } else {
+ i = 0;
+ while (i < n) {
+ c = decode_data->pt_table[decode_data->bit_buf >> 8];
+ if (c >= NT) {
+ mask = 1 << 7;
+ do {
+ if (c >= (2 * NC - 1)) {
+ cli_warnmsg("ERROR: bounds exceeded\n");
+ return CL_EFORMAT;
+ }
+ if (decode_data->bit_buf & mask) {
+ c = decode_data->right[c];
+ } else {
+ c = decode_data->left[c];
+ }
+ mask >>= 1;
+ } while (c >= NT);
+ }
+ fill_buf(decode_data, (int)(decode_data->pt_len[c]));
+ if (c <= 2) {
+ if (c == 0) {
+ c = 1;
+ } else if (c == 1) {
+ c = arj_getbits(decode_data, 4) + 3;
+ } else {
+ c = arj_getbits(decode_data, CBIT) + 20;
+ }
+ while (--c >= 0) {
+ if (i >= NC) {
+ cli_warnmsg("ERROR: bounds exceeded\n");
+ return CL_EFORMAT;
+ }
+ decode_data->c_len[i++] = 0;
+ }
+ } else {
+ if (i >= NC) {
+ cli_warnmsg("ERROR: bounds exceeded\n");
+ return CL_EFORMAT;
+ }
+ decode_data->c_len[i++] = (unsigned char) (c - 2);
+ }
+ }
+ while (i < NC) {
+ decode_data->c_len[i++] = 0;
+ }
+ make_table(decode_data, NC, decode_data->c_len, 12, decode_data->c_table, CTABLESIZE);
+ }
+ return CL_SUCCESS;
+}
+
+
+static uint16_t decode_c(arj_decode_t *decode_data)
+{
+ uint16_t j, mask;
+
+ if (decode_data->blocksize == 0) {
+ decode_data->blocksize = arj_getbits(decode_data, 16);
+ read_pt_len(decode_data, NT, TBIT, 3);
+ read_c_len(decode_data);
+ read_pt_len(decode_data, NT, PBIT, -1);
+ }
+ decode_data->blocksize--;
+ j = decode_data->c_table[decode_data->bit_buf >> 4];
+ if (j >= NC) {
+ mask = 1 << 3;
+ do {
+ if (j >= (2 * NC - 1)) {
+ cli_warnmsg("ERROR: bounds exceeded\n");
+ return 0;
+ }
+ if (decode_data->bit_buf & mask) {
+ j = decode_data->right[j];
+ } else {
+ j = decode_data->left[j];
+ }
+ mask >>= 1;
+ } while (j >= NC);
+ }
+ fill_buf(decode_data, (int)(decode_data->c_len[j]));
+ return j;
+}
+
+static uint16_t decode_p(arj_decode_t *decode_data)
+{
+ unsigned short j, mask;
+
+ j = decode_data->pt_table[decode_data->bit_buf >> 8];
+ if (j >= NP) {
+ mask = 1 << 7;
+ do {
+ if (j >= (2 * NC - 1)) {
+ cli_warnmsg("ERROR: bounds exceeded\n");
+ return 0;
+ }
+ if (decode_data->bit_buf & mask) {
+ j = decode_data->right[j];
+ } else {
+ j = decode_data->left[j];
+ }
+ mask >>= 1;
+ } while (j >= NP);
+ }
+ fill_buf(decode_data, (int)(decode_data->pt_len[j]));
+ if (j != 0) {
+ j--;
+ j = (1 << j) + arj_getbits(decode_data, (int)j);
+ }
+ return j;
+}
+
+static int decode(int fd, arj_metadata_t *metadata)
+{
+ int ret;
+
+ arj_decode_t decode_data;
+ uint32_t count=0, out_ptr=0;
+ int16_t chr, i, j;
+
+ decode_data.text = (unsigned char *) cli_malloc(DDICSIZ);
+ if (!decode_data.text) {
+ return CL_EMEM;
+ }
+ decode_data.fd = fd;
+ decode_data.comp_size = metadata->comp_size;
+ ret = decode_start(&decode_data);
+ if (ret != CL_SUCCESS) {
+ return ret;
+ }
+
+ while (count < metadata->orig_size) {
+ if ((chr = decode_c(&decode_data)) <= UCHAR_MAX) {
+ decode_data.text[out_ptr] = (unsigned char) chr;
+ count++;
+ if (++out_ptr >= DDICSIZ) {
+ out_ptr = 0;
+ write_text(metadata->ofd, decode_data.text, DDICSIZ);
+ }
+ } else {
+ j = chr - (UCHAR_MAX + 1 - THRESHOLD);
+ count += j;
+ i = decode_p(&decode_data);
+ if ((i = out_ptr - i - 1) < 0) {
+ i += DDICSIZ;
+ }
+ if ((i >= DDICSIZ) || (i < 0)) {
+ cli_warnmsg("UNARJ: bounds exceeded - probably a corrupted file.\n");
+ break;
+ }
+ if (out_ptr > i && out_ptr < DDICSIZ - MAXMATCH - 1) {
+ while ((--j >= 0) && (i < DDICSIZ) && (out_ptr < DDICSIZ)) {
+ decode_data.text[out_ptr++] = decode_data.text[i++];
+ }
+ } else {
+ while (--j >= 0) {
+ decode_data.text[out_ptr] = decode_data.text[i];
+ if (++out_ptr >= DDICSIZ) {
+ out_ptr = 0;
+ write_text(metadata->ofd, decode_data.text, DDICSIZ);
+ }
+ if (++i >= DDICSIZ) {
+ i = 0;
+ }
+ }
+ }
+ }
+ }
+ if (out_ptr != 0) {
+ write_text(metadata->ofd, decode_data.text, out_ptr);
+ }
+
+ free(decode_data.text);
+ return CL_SUCCESS;
+}
+
+#define ARJ_BFIL(dd) {dd->getbuf|=dd->bit_buf>>dd->getlen;fill_buf(dd,CODE_BIT-dd->getlen);dd->getlen=CODE_BIT;}
+#define ARJ_GETBIT(dd,c) {if(dd->getlen<=0)ARJ_BFIL(dd) c=(dd->getbuf&0x8000)!=0;dd->getbuf<<=1;dd->getlen--;}
+#define ARJ_BPUL(dd,l) {dd->getbuf<<=l;dd->getlen-=l;}
+#define ARJ_GETBITS(dd,c,l) {if(dd->getlen<l)ARJ_BFIL(dd) c=(uint16_t)dd->getbuf>>(CODE_BIT-l);ARJ_BPUL(dd,l)}
+
+static uint16_t decode_ptr(arj_decode_t *decode_data)
+{
+ uint16_t c, width, plus, pwr;
+
+ plus = 0;
+ pwr = 1 << STRTP;
+ for (width = STRTP; width < STOPP; width++) {
+ ARJ_GETBIT(decode_data, c);
+ if (c == 0) {
+ break;
+ }
+ plus += pwr;
+ pwr <<= 1;
+ }
+ if (width != 0) {
+ ARJ_GETBITS(decode_data, c, width);
+ }
+ c += plus;
+ return c;
+}
+
+static uint16_t decode_len(arj_decode_t *decode_data)
+{
+ uint16_t c, width, plus, pwr;
+
+ plus = 0;
+ pwr = 1 << STRTL;
+ for (width = STRTL; width < STOPL; width++) {
+ ARJ_GETBIT(decode_data, c);
+ if (c == 0) {
+ break;
+ }
+ plus += pwr;
+ pwr <<= 1;
+ }
+ if (width != 0) {
+ ARJ_GETBITS(decode_data, c, width);
+ }
+ c += plus;
+ return c;
+}
+
+static int decode_f(int fd, arj_metadata_t *metadata)
+{
+ int ret;
+
+ arj_decode_t decode_data, *dd;
+ uint32_t count=0, out_ptr=0;
+ int16_t chr, i, j, pos;
+
+ dd = &decode_data;
+ decode_data.text = (unsigned char *) cli_malloc(DDICSIZ);
+ if (!decode_data.text) {
+ return CL_EMEM;
+ }
+ decode_data.fd = fd;
+ decode_data.comp_size = metadata->comp_size;
+ ret = init_getbits(&decode_data);
+ if (ret != CL_SUCCESS) {
+ return ret;
+ }
+ decode_data.getlen = decode_data.getbuf = 0;
+
+ while (count < metadata->orig_size) {
+ chr = decode_len(&decode_data);
+ if (chr == 0) {
+ ARJ_GETBITS(dd, chr, CHAR_BIT);
+ decode_data.text[out_ptr] = (unsigned char) chr;
+ count++;
+ if (++out_ptr >= DDICSIZ) {
+ out_ptr = 0;
+ write_text(metadata->ofd, decode_data.text, DDICSIZ);
+ }
+ } else {
+ j = chr - 1 + THRESHOLD;
+ count += j;
+ pos = decode_ptr(&decode_data);
+ if ((i = out_ptr - pos - 1) < 0) {
+ i += DDICSIZ;
+ }
+ if ((i >= DDICSIZ) || (i < 0)) {
+ cli_warnmsg("UNARJ: bounds exceeded - probably a corrupted file.\n");
+ break;
+ }
+ while (j-- > 0) {
+ decode_data.text[out_ptr] = decode_data.text[i];
+ if (++out_ptr >= DDICSIZ) {
+ out_ptr = 0;
+ write_text(metadata->ofd, decode_data.text, DDICSIZ);
+ }
+ if (++i >= DDICSIZ) {
+ i = 0;
+ }
+ }
+ }
+ }
+ if (out_ptr != 0) {
+ write_text(metadata->ofd, decode_data.text, out_ptr);
+ }
+
+ free(decode_data.text);
+ return CL_SUCCESS;
+}
+
+static uint32_t arj_unstore(int ifd, int ofd, uint32_t len)
+{
+ unsigned char data[8192];
+ uint32_t count, rem;
+ unsigned int todo;
+
+ cli_dbgmsg("in arj_unstore\n");
+ rem = len;
+
+ while (rem > 0) {
+ todo = (unsigned int) MIN(8192, rem);
+ count = cli_readn(ifd, data, todo);
+ if (count != todo) {
+ return len-rem;
+ }
+ if (cli_writen(ofd, data, count) != count) {
+ return len-rem-count;
+ }
+ rem -= count;
+ }
+ return len;
+}
+
+static int is_arj_archive(int fd)
+{
+ const char header_id[2] = {0x60, 0xea};
+ char mark[2];
+
+ if (cli_readn(fd, &mark[0], 2) != 2) {
+ return FALSE;
+ }
+ if (memcmp(&mark[0], &header_id[0], 2) == 0) {
+ return TRUE;
+ }
+ cli_dbgmsg("Not an ARJ archive\n");
+ return FALSE;
+}
+
+static int arj_read_main_header(int fd)
+{
+ uint16_t header_size, count;
+ uint32_t crc;
+ arj_main_hdr_t main_hdr;
+ char *filename, *comment;
+ off_t header_offset;
+
+ if (cli_readn(fd, &header_size, 2) != 2) {
+ return FALSE;
+ }
+ header_offset = lseek(fd, 0, SEEK_CUR);
+ header_size = le16_to_host(header_size);
+ cli_dbgmsg("Header Size: %d\n", header_size);
+ if (header_size == 0) {
+ /* End of archive */
+ return FALSE;
+ }
+ if (header_size > HEADERSIZE_MAX) {
+ cli_dbgmsg("arj_read_header: invalid header_size: %u\n ", header_size);
+ return FALSE;
+ }
+
+ if (cli_readn(fd, &main_hdr, 30) != 30) {
+ return FALSE;
+ }
+
+ cli_dbgmsg("ARJ Main File Header\n");
+ cli_dbgmsg("First Header Size: %d\n", main_hdr.first_hdr_size);
+ cli_dbgmsg("Version: %d\n", main_hdr.version);
+ cli_dbgmsg("Min version: %d\n", main_hdr.min_version);
+ cli_dbgmsg("Host OS: %d\n", main_hdr.host_os);
+ cli_dbgmsg("Flags: 0x%x\n", main_hdr.flags);
+ cli_dbgmsg("Security version: %d\n", main_hdr.security_version);
+ cli_dbgmsg("File type: %d\n", main_hdr.file_type);
+
+ if (main_hdr.first_hdr_size < 30) {
+ cli_dbgmsg("Format error. First Header Size < 30\n");
+ return FALSE;
+ }
+ if (main_hdr.first_hdr_size > 30) {
+ if (lseek(fd, main_hdr.first_hdr_size - 30, SEEK_CUR) == -1) {
+ return FALSE;
+ }
+ }
+
+ filename = (char *) cli_malloc(header_size);
+ if (!filename) {
+ return FALSE;
+ }
+ for (count=0 ; count < header_size ; count++) {
+ if (cli_readn(fd, &filename[count], 1) != 1) {
+ free(filename);
+ return FALSE;
+ }
+ if (filename[count] == '\0') {
+ break;
+ }
+ }
+ if (count == header_size) {
+ free(filename);
+ return FALSE;
+ }
+ comment = (char *) cli_malloc(header_size);
+ if (!comment) {
+ free(filename);
+ return FALSE;
+ }
+ for (count=0 ; count < header_size ; count++) {
+ if (cli_readn(fd, &comment[count], 1) != 1) {
+ free(filename);
+ free(comment);
+ return FALSE;
+ }
+ if (comment[count] == '\0') {
+ break;
+ }
+ }
+ if (count == header_size) {
+ free(filename);
+ free(comment);
+ return FALSE;
+ }
+ cli_dbgmsg("Filename: %s\n", filename);
+ cli_dbgmsg("Comment: %s\n", comment);
+
+ free(filename);
+ free(comment);
+
+ if (cli_readn(fd, &crc, 4) != 4) {
+ return FALSE;
+ }
+
+ /* Skip past any extended header data */
+ for (;;) {
+ if (cli_readn(fd, &count, 2) != 2) {
+ return FALSE;
+ }
+ count = le16_to_host(count);
+ cli_dbgmsg("Extended header size: %d\n", count);
+ if (count == 0) {
+ break;
+ }
+ /* Skip extended header + 4byte CRC */
+ if (lseek(fd, (off_t) (count + 4), SEEK_CUR) == -1) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int arj_read_file_header(int fd, arj_metadata_t *metadata)
+{
+ uint16_t header_size, count;
+ char *filename, *comment;
+ arj_file_hdr_t file_hdr;
+
+ if (cli_readn(fd, &header_size, 2) != 2) {
+ return CL_EFORMAT;
+ }
+ header_size = le16_to_host(header_size);
+ cli_dbgmsg("Header Size: %d\n", header_size);
+ if (header_size == 0) {
+ /* End of archive */
+ return CL_BREAK;
+ }
+ if (header_size > HEADERSIZE_MAX) {
+ cli_dbgmsg("arj_read_file_header: invalid header_size: %u\n ", header_size);
+ return CL_EFORMAT;
+ }
+
+ if (cli_readn(fd, &file_hdr, 30) != 30) {
+ return CL_EFORMAT;
+ }
+ file_hdr.comp_size = le32_to_host(file_hdr.comp_size);
+ file_hdr.orig_size = le32_to_host(file_hdr.orig_size);
+
+ cli_dbgmsg("ARJ File Header\n");
+ cli_dbgmsg("First Header Size: %d\n", file_hdr.first_hdr_size);
+ cli_dbgmsg("Version: %d\n", file_hdr.version);
+ cli_dbgmsg("Min version: %d\n", file_hdr.min_version);
+ cli_dbgmsg("Host OS: %d\n", file_hdr.host_os);
+ cli_dbgmsg("Flags: 0x%x\n", file_hdr.flags);
+ cli_dbgmsg("Method: %d\n", file_hdr.method);
+ cli_dbgmsg("File type: %d\n", file_hdr.file_type);
+ cli_dbgmsg("File type: %d\n", file_hdr.password_mod);
+ cli_dbgmsg("Compressed size: %u\n", file_hdr.comp_size);
+ cli_dbgmsg("Original size: %u\n", file_hdr.orig_size);
+
+ if (file_hdr.first_hdr_size < 30) {
+ cli_dbgmsg("Format error. First Header Size < 30\n");
+ return CL_EFORMAT;
+ }
+
+ /* Note: this skips past any extended file start position data (multi-volume) */
+ if (file_hdr.first_hdr_size > 30) {
+ if (lseek(fd, file_hdr.first_hdr_size - 30, SEEK_CUR) == -1) {
+ return CL_EFORMAT;
+ }
+ }
+
+ filename = (char *) cli_malloc(header_size);
+ if (!filename) {
+ return CL_EMEM;
+ }
+ for (count=0 ; count < header_size ; count++) {
+ if (cli_readn(fd, &filename[count], 1) != 1) {
+ free(filename);
+ return CL_EFORMAT;
+ }
+ if (filename[count] == '\0') {
+ break;
+ }
+ }
+ if (count == header_size) {
+ free(filename);
+ return CL_EFORMAT;
+ }
+
+ comment = (char *) cli_malloc(header_size);
+ if (!comment) {
+ free(filename);
+ return CL_EFORMAT;
+ }
+ for (count=0 ; count < header_size ; count++) {
+ if (cli_readn(fd, &comment[count], 1) != 1) {
+ free(filename);
+ free(comment);
+ return CL_EFORMAT;
+ }
+ if (comment[count] == '\0') {
+ break;
+ }
+ }
+ if (count == header_size) {
+ free(filename);
+ free(comment);
+ return CL_EFORMAT;
+ }
+ cli_dbgmsg("Filename: %s\n", filename);
+ cli_dbgmsg("Comment: %s\n", comment);
+ metadata->filename = cli_strdup(filename);
+
+ free(filename);
+ free(comment);
+
+ /* Skip CRC */
+ if (lseek(fd, (off_t) 4, SEEK_CUR) == -1) {
+ return CL_EFORMAT;
+ }
+
+ /* Skip past any extended header data */
+ for (;;) {
+ if (cli_readn(fd, &count, 2) != 2) {
+ return CL_EFORMAT;
+ }
+ count = le16_to_host(count);
+ cli_dbgmsg("Extended header size: %d\n", count);
+ if (count == 0) {
+ break;
+ }
+ /* Skip extended header + 4byte CRC */
+ if (lseek(fd, (off_t) (count + 4), SEEK_CUR) == -1) {
+ return CL_EFORMAT;
+ }
+ }
+ metadata->comp_size = file_hdr.comp_size;
+ metadata->orig_size = file_hdr.orig_size;
+ metadata->method = file_hdr.method;
+ metadata->encrypted = ((file_hdr.flags & GARBLE_FLAG) != 0) ? TRUE : FALSE;
+ metadata->ofd = -1;
+ if (!metadata->filename) {
+ return CL_EMEM;
+ }
+
+ return CL_SUCCESS;
+}
+
+int cli_unarj_open(int fd, const char *dirname)
+{
+
+ cli_dbgmsg("in cli_unarj_open\n");
+
+ if (!is_arj_archive(fd)) {
+ cli_dbgmsg("Not in ARJ format\n");
+ return CL_EFORMAT;
+ }
+ if (!arj_read_main_header(fd)) {
+ cli_dbgmsg("Failed to read main header\n");
+ return CL_EFORMAT;
+ }
+ return CL_SUCCESS;
+}
+
+int cli_unarj_prepare_file(int fd, const char *dirname, arj_metadata_t *metadata)
+{
+ cli_dbgmsg("in cli_unarj_prepare_file\n");
+ if (!metadata || !dirname || (fd < 0)) {
+ return CL_ENULLARG;
+ }
+ /* Each file is preceeded by the ARJ file marker */
+ if (!is_arj_archive(fd)) {
+ cli_dbgmsg("Not in ARJ format\n");
+ return CL_EFORMAT;
+ }
+ return arj_read_file_header(fd, metadata);
+}
+
+int cli_unarj_extract_file(int fd, const char *dirname, arj_metadata_t *metadata)
+{
+ off_t offset;
+ int ret = CL_SUCCESS;
+ char filename[1024];
+
+ cli_dbgmsg("in cli_unarj_extract_file\n");
+ if (!metadata || !dirname || (fd < 0)) {
+ return CL_ENULLARG;
+ }
+
+ if (metadata->encrypted) {
+ cli_dbgmsg("PASSWORDed file (skipping)\n");
+ offset = lseek(fd, 0, SEEK_CUR) + metadata->comp_size;
+ cli_dbgmsg("Target offset: %ld\n", offset);
+ if (lseek(fd, offset, SEEK_SET) != offset) {
+ return CL_EARJ;
+ }
+ return CL_SUCCESS;
+ }
+
+ snprintf(filename, 1024, "%s/file.uar", dirname);
+ cli_dbgmsg("Filename: %s\n", filename);
+ metadata->ofd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
+ if (metadata->ofd < 0) {
+ return CL_EOPEN;
+ }
+ switch (metadata->method) {
+ case 0:
+ ret = arj_unstore(fd, metadata->ofd, metadata->comp_size);
+ if (ret != metadata->comp_size) {
+ ret = CL_EIO;
+ } else {
+ ret = CL_SUCCESS;
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ decode(fd, metadata);
+ break;
+ case 4:
+ decode_f(fd, metadata);
+ break;
+ default:
+ ret = CL_EFORMAT;
+ break;
+ }
+ return ret;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unsp.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2006 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+** unsp.c
+**
+** 11/10/2k6 - Merge started.
+**
+*/
+
+/*
+** Plays around with NsPack compressed executables
+**
+** This piece of code is dedicated to Damian Put
+** who I made a successful and wealthy man.
+**
+** Damian, you owe me a pint!
+*/
+
+/*
+** TODO:
+**
+** - Investigate the "unused" code in NsPack
+** - Fetch all the nspacked samples from the zoo and run extensive testing
+** - Add bound checks
+** - Test against the zoo again
+** - Perform regression testing against the full zoo
+** - check nested
+** - look at the 64bit version (one of these days)
+**
+*/
+
+/*
+
+ FIXME: clean this rubbish
+
+
+init_and_check_dll_loadflags();
+
+nsp1:004359FE add edi, [ebp-28Dh]
+nsp1:00435A04 mov ebx, edi
+nsp1:00435A06 cmp dword ptr [edi], 0
+nsp1:00435A09 jnz short loc_435A15
+nsp1:00435A0B add edi, 4
+nsp1:00435A0E mov ecx, 0
+nsp1:00435A13 jmp short loc_435A2B
+nsp1:00435A15 ; ---------------------------------------------------------------------------
+nsp1:00435A15
+nsp1:00435A15 loc_435A15: ; CODE XREF: start+349EEj
+nsp1:00435A15 mov ecx, 1
+nsp1:00435A1A add edi, [ebx]
+nsp1:00435A1C add ebx, 4
+nsp1:00435A1F
+nsp1:00435A1F loc_435A1F: ; CODE XREF: start+34A3Dj
+nsp1:00435A1F cmp dword ptr [ebx], 0
+nsp1:00435A22 jz short loc_435A5A
+nsp1:00435A24 add [ebx], edx
+nsp1:00435A26 mov esi, [ebx]
+nsp1:00435A28 add edi, [ebx+4]
+nsp1:00435A2B
+nsp1:00435A2B loc_435A2B: ; CODE XREF: start+349F8j
+nsp1:00435A2B push edi
+nsp1:00435A2C push ecx
+nsp1:00435A2D push edx
+nsp1:00435A2E push ebx
+nsp1:00435A2F push dword ptr [ebp-1D1h] ; VirtualFree
+nsp1:00435A35 push dword ptr [ebp-1D5h] ; alloc
+nsp1:00435A3B mov edx, esi
+nsp1:00435A3D mov ecx, edi
+nsp1:00435A3F mov eax, offset get_byte
+nsp1:00435A44 int 3 ; Trap to Debugger
+nsp1:00435A45 add eax, 5A9h
+nsp1:00435A4A call eax ; real_unpack ; edx=401000
+nsp1:00435A4A ; ecx=436282
+nsp1:00435A4C pop ebx
+nsp1:00435A4D pop edx
+nsp1:00435A4E pop ecx
+nsp1:00435A4F pop edi
+nsp1:00435A50 cmp ecx, 0
+nsp1:00435A53 jz short loc_435A5A
+nsp1:00435A55 add ebx, 8
+nsp1:00435A58 jmp short loc_435A1F
+nsp1:00435A5A ; ---------------------------------------------------------------------------
+nsp1:00435A5A
+nsp1:00435A5A loc_435A5A: ; CODE XREF: start+34A07j
+nsp1:00435A5A ; start+34A38j
+nsp1:00435A5A push 8000h
+
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "cltypes.h"
+#include "clamav.h"
+#include "others.h"
+#include "rebuildpe.h"
+#include "execs.h"
+#include "unsp.h"
+
+
+/* real_unpack(start_of_stuff, dest, malloc, free); */
+uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, uint32_t base, uint32_t ep, int file) {
+ uint8_t c = *start_of_stuff;
+ uint32_t i,firstbyte,tre,allocsz,tablesz,dsize,ssize;
+ uint16_t *table;
+ char *dst = dest;
+ char *src = start_of_stuff+0xd;
+ struct cli_exe_section section;
+
+ if (c>=0xe1) return 1;
+
+ if (c>=0x2d) {
+ firstbyte = i = c/0x2d;
+ do {c+=0xd3;} while (--i);
+ } else firstbyte = 0;
+
+ if (c>=9) {
+ allocsz = i = c/9;
+ do {c+=0xf7;} while (--i);
+ } else allocsz = 0;
+
+ tre = c;
+ i = allocsz;
+ c = (tre+i)&0xff;
+ tablesz = ((0x300<<c)+0x736)*sizeof(uint16_t);
+ if(ctx->limits && ctx->limits->maxfilesize && tablesz > ctx->limits->maxfilesize) {
+ return 1; /* Should be ~15KB, if it's so big it's prolly just not nspacked */
+ }
+
+ cli_dbgmsg("unsp: table size = %d\n", tablesz);
+ if (!(table = cli_malloc(tablesz))) return 1;
+
+ dsize = cli_readint32(start_of_stuff+9);
+ ssize = cli_readint32(start_of_stuff+5);
+ if (ssize <= 13) {
+ free(table);
+ return 1;
+ }
+
+ tre = very_real_unpack(table,tablesz,tre,allocsz,firstbyte,src,ssize,dst,dsize);
+ free(table);
+ if (tre) return 1;
+
+ section.raw=0;
+ section.rsz = dsize;
+ section.vsz = dsize;
+ section.rva = rva;
+ return !cli_rebuildpe(dest, §ion, 1, base, ep, 0, 0, file);
+}
+
+
+uint32_t very_real_unpack(uint16_t *table, uint32_t tablesz, uint32_t tre, uint32_t allocsz, uint32_t firstbyte, char *src, uint32_t ssize, char *dst, uint32_t dsize) {
+ struct UNSP read_struct;
+ uint32_t i = (0x300<<((allocsz+tre)&0xff)) + 0x736;
+
+ uint32_t previous_bit = 0;
+ uint32_t unpacked_so_far = 0;
+ uint32_t backbytes = 1;
+ uint32_t oldbackbytes = 1;
+ uint32_t old_oldbackbytes = 1;
+ uint32_t old_old_oldbackbytes = 1;
+
+ uint32_t damian = 0;
+ uint32_t put = (1<<(allocsz&0xff))-1;
+
+ uint32_t bielle = 0;
+
+ firstbyte = (1<<(firstbyte&0xff))-1;
+
+ if (tablesz < i*sizeof(uint16_t)) return 2;
+
+ /* init table */
+ while (i) table[--i]=0x400;
+
+ /* table noinit */
+
+ /* get_five - inlined */
+ read_struct.error = 0;
+ read_struct.oldval = 0;
+ read_struct.src_curr = src;
+ read_struct.bitmap = 0xffffffff;
+ read_struct.src_end = src + ssize - 13;
+ read_struct.table = (char *)table;
+ read_struct.tablesz = tablesz;
+
+ for ( i = 0; i<5 ; i++) read_struct.oldval = (read_struct.oldval<<8) | get_byte(&read_struct);
+ if (read_struct.error) return 1;
+ /* if (!dsize) return 0; - checked in pe.c */
+
+
+ /* very_unpacking_loop */
+
+ while (1) {
+ uint32_t backsize = firstbyte&unpacked_so_far;
+ uint32_t tpos;
+ uint32_t temp = damian;
+
+ if (read_struct.error) return 1; /* checked once per mainloop, keeps the code readable and it's still safe */
+
+ if (!getbit_from_table(&table[(damian<<4) + backsize], &read_struct)) { /* no_mainbit */
+
+ uint32_t shft = 8 - (tre&0xff);
+ shft &= 0xff;
+ tpos = (bielle>>shft) + ((put&unpacked_so_far)<<(tre&0xff));
+ tpos *=3;
+ tpos<<=8;
+
+ if ((int32_t)damian>=4) { /* signed */
+ if ((int32_t)damian>=0xa) { /* signed */
+ damian -= 6;
+ } else {
+ damian -= 3;
+ }
+ } else {
+ damian=0;
+ }
+
+ /* 44847E */
+ if (previous_bit) {
+ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
+ ssize = (ssize&0xffffff00) | (uint8_t)dst[unpacked_so_far - backbytes]; /* FIXME! ssize is not static */
+ bielle = get_100_bits_from_tablesize(&table[tpos+0x736], &read_struct, ssize);
+ previous_bit=0;
+ } else {
+ bielle = get_100_bits_from_table(&table[tpos+0x736], &read_struct);
+ }
+
+ /* unpack_one_byte - duplicated */
+ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], 1)) return 1;
+ dst[unpacked_so_far] = bielle;
+ unpacked_so_far++;
+ if (unpacked_so_far>=dsize) return 0;
+ continue;
+
+ } else { /* got_mainbit */
+
+ bielle = previous_bit = 1;
+
+ if (getbit_from_table(&table[damian+0xc0], &read_struct)) {
+ if (!getbit_from_table(&table[damian+0xcc], &read_struct)) {
+ tpos = damian+0xf;
+ tpos <<=4;
+ tpos += backsize;
+ if (!getbit_from_table(&table[tpos], &read_struct)) {
+ if (!unpacked_so_far) return bielle; /* FIXME: WTF?! */
+
+ damian = 2*((int32_t)damian>=7)+9; /* signed */
+ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
+ bielle = (uint8_t)dst[unpacked_so_far - backbytes];
+ /* unpack_one_byte - real */
+ dst[unpacked_so_far] = bielle;
+ unpacked_so_far++;
+ if (unpacked_so_far>=dsize) return 0;
+ continue;
+
+ } else { /* gotbit_tre */
+ backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
+ damian = ((int32_t)damian>=7); /* signed */
+ damian = ((damian-1) & 0xfffffffd)+0xb;
+ /* jmp checkloop_and_backcopy (uses edx) */
+ } /* gotbit_uno ends */
+ } else { /* gotbit_due */
+ if (!getbit_from_table(&table[damian+0xd8], &read_struct)) {
+ tpos = oldbackbytes;
+ } else {
+ if (!getbit_from_table(&table[damian+0xe4], &read_struct)) {
+ tpos = old_oldbackbytes;
+ } else {
+ /* set_old_old_oldback */
+ tpos = old_old_oldbackbytes;
+ old_old_oldbackbytes = old_oldbackbytes;
+ }
+ /* set_old_oldback */
+ old_oldbackbytes = oldbackbytes;
+ }
+ /* set_oldback */
+ oldbackbytes = backbytes;
+ backbytes = tpos;
+
+ backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
+ damian = ((int32_t)damian>=7); /* signed */
+ damian = ((damian-1) & 0xfffffffd)+0xb;
+ /* jmp checkloop_and_backcopy (uses edx) */
+ } /* gotbit_due ends */
+ } else { /* gotbit_uno */
+
+ old_old_oldbackbytes = old_oldbackbytes;
+ old_oldbackbytes = oldbackbytes;
+ oldbackbytes = backbytes;
+
+ damian = ((int32_t)damian>=7); /* signed */
+ damian = ((damian-1) & 0xfffffffd)+0xa;
+
+ backsize = get_n_bits_from_tablesize(&table[0x332], &read_struct, backsize);
+
+ tpos = ((int32_t)backsize>=4)?3:backsize; /* signed */
+ tpos<<=6;
+ tpos = get_n_bits_from_table(&table[0x1b0+tpos], 6, &read_struct);
+
+ if (tpos>=4) { /* signed */
+
+ uint32_t s = tpos;
+ s>>=1;
+ s--;
+
+ temp = (tpos & bielle) | 2;
+ temp<<=(s&0xff);
+
+
+ if ((int32_t)tpos<0xe) {
+ temp += get_bb(&table[(temp-tpos)+0x2af], s, &read_struct);
+ } else {
+ s += 0xfffffffc;
+ tpos = get_bitmap(&read_struct, s);
+ tpos <<=4;
+ temp += tpos;
+ temp += get_bb(&table[0x322], 4, &read_struct);
+ }
+ } else {
+ /* gotbit_uno_out1 */
+ backbytes = temp = tpos;
+ }
+ /* gotbit_uno_out2 */
+ backbytes = temp+1;
+ /* jmp checkloop_and_backcopy (uses edx) */
+ } /* gotbit_uno ends */
+
+ /* checkloop_and_backcopy */
+ if (!backbytes) return 0; /* very_real_unpack_end */
+ if (backbytes > unpacked_so_far) return bielle; /* FIXME: WTF?! */
+
+ backsize +=2;
+
+ if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], backsize) ||
+ !CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], backsize)
+ ) {
+ cli_dbgmsg("%x %x %x %x\n", dst, dsize, &dst[unpacked_so_far], backsize);
+ return 1;
+ }
+
+ do {
+ dst[unpacked_so_far] = dst[unpacked_so_far - backbytes];
+ unpacked_so_far++;
+ } while (--backsize && unpacked_so_far<dsize);
+ bielle = (uint8_t)dst[unpacked_so_far - 1];
+
+ if (unpacked_so_far>=dsize) return 0;
+
+ } /* got_mainbit ends */
+
+ } /* while true ends */
+}
+
+
+
+uint32_t get_byte(struct UNSP *read_struct) {
+
+ uint32_t ret;
+
+ if (read_struct->src_curr >= read_struct->src_end) {
+ read_struct->error = 1;
+ return 0xff;
+ }
+ ret = *(read_struct->src_curr);
+ read_struct->src_curr++;
+ return ret&0xff;
+}
+
+
+int getbit_from_table(uint16_t *intable, struct UNSP *read_struct) {
+
+ uint32_t nval;
+ if (!CLI_ISCONTAINED((char *)read_struct->table, read_struct->tablesz, (char *)intable, sizeof(uint16_t))) {
+ read_struct->error = 1;
+ return 0xff;
+ }
+ nval = *intable * (read_struct->bitmap>>0xb);
+
+ if (read_struct->oldval<nval) { /* unsigned */
+ uint32_t sval;
+ read_struct->bitmap = nval;
+ nval = *intable;
+ sval = 0x800 - nval;
+ sval = CLI_SRS((int32_t)sval,5); /* signed */
+ sval += nval;
+ *intable=sval;
+ if (read_struct->bitmap<0x1000000) { /* unsigned */
+ read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+ read_struct->bitmap<<=8;
+ }
+ return 0;
+ }
+
+ read_struct->bitmap -= nval;
+ read_struct->oldval -= nval;
+
+ nval = *intable;
+ nval -= (nval>>5); /* word, unsigned */
+ *intable=nval;
+
+ if (read_struct->bitmap<0x1000000) { /* unsigned */
+ read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+ read_struct->bitmap<<=8;
+ }
+
+ return 1;
+}
+
+
+uint32_t get_100_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t ssize) {
+
+ uint32_t count = 1;
+
+ while (count<0x100) {
+ uint32_t lpos, tpos;
+ lpos = ssize&0xff;
+ ssize=(ssize&0xffffff00)|((lpos<<1)&0xff);
+ lpos>>=7;
+ tpos = lpos+1;
+ tpos<<=8;
+ tpos+=count;
+ tpos = getbit_from_table(&intable[tpos], read_struct);
+ count=(count*2)|tpos;
+ if (lpos!=tpos) {
+ /* second loop */
+ while (count<0x100)
+ count = (count*2)|getbit_from_table(&intable[count], read_struct);
+ }
+ }
+ return count&0xff;
+}
+
+
+uint32_t get_100_bits_from_table(uint16_t *intable, struct UNSP *read_struct) {
+ uint32_t count = 1;
+
+ while (count<0x100)
+ count = (count*2)|getbit_from_table(&intable[count], read_struct);
+ return count&0xff;
+}
+
+
+uint32_t get_n_bits_from_table(uint16_t *intable, uint32_t bits, struct UNSP *read_struct) {
+ uint32_t count = 1;
+ uint32_t bitcounter;
+
+ /* if (bits) { always set! */
+ bitcounter = bits;
+ while (bitcounter--)
+ count = count*2 + getbit_from_table(&intable[count], read_struct);
+ /* } */
+
+ return count-(1<<(bits&0xff));
+}
+
+
+uint32_t get_n_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t backsize) {
+
+ if (!getbit_from_table(intable, read_struct))
+ return get_n_bits_from_table(&intable[(backsize<<3)+2], 3, read_struct);
+
+ if (!getbit_from_table(&intable[1], read_struct))
+ return 8+get_n_bits_from_table(&intable[(backsize<<3)+0x82], 3, read_struct);
+
+ return 0x10+get_n_bits_from_table(&intable[0x102], 8, read_struct);
+}
+
+
+uint32_t get_bb(uint16_t *intable, uint32_t back, struct UNSP *read_struct) {
+ uint32_t pos = 1;
+ uint32_t bb = 0;
+ uint32_t i;
+
+ if ((int32_t)back<=0) /* signed */
+ return 0;
+
+ for (i=0;i<back;i++) {
+ uint32_t bit = getbit_from_table(&intable[pos], read_struct);
+ pos=(pos*2) + bit;
+ bb|=(bit<<i);
+ }
+ return bb;
+}
+
+
+uint32_t get_bitmap(struct UNSP *read_struct, uint32_t bits) {
+ uint32_t retv = 0;
+
+ if ((int32_t)bits<=0) return 0; /* signed */
+
+ while (bits--) {
+ read_struct->bitmap>>=1; /* unsigned */
+ retv<<=1;
+ if (read_struct->oldval>=read_struct->bitmap) { /* unsigned */
+ read_struct->oldval-=read_struct->bitmap;
+ retv|=1;
+ }
+ if (read_struct->bitmap<0x1000000) {
+ read_struct->bitmap<<=8;
+ read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
+ }
+ }
+ return retv;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_untar.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2000-2007 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * Much of this code is based on minitar.c which is in the public domain.
+ * Author: Charles G. Waldman (cgw at pgt.com), Aug 4 1998
+ * There are many tar files that this code cannot decode.
+ */
+static char const rcsid[] = "$Id: untar.c,v 1.35 2007/02/12 20:46:09 njh Exp $";
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h> /* for NAME_MAX */
+#endif
+
+#include "clamav.h"
+#include "others.h"
+#include "untar.h"
+#include "mbox.h"
+#include "blob.h"
+
+#define BLOCKSIZE 512
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static int
+octal(const char *str)
+{
+ int ret;
+
+ if(sscanf(str, "%o", (unsigned int *)&ret) != 1)
+ return -1;
+ return ret;
+}
+
+int
+cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits)
+{
+ int size = 0;
+ int in_block = 0;
+ unsigned int files = 0;
+ char fullname[NAME_MAX + 1];
+ FILE *outfile = NULL;
+
+ cli_dbgmsg("In untar(%s, %d)\n", dir ? dir : "", desc);
+
+ for(;;) {
+ char block[BLOCKSIZE];
+ const int nread = cli_readn(desc, block, (unsigned int)sizeof(block));
+
+ if(!in_block && nread == 0)
+ break;
+
+ if(nread < 0) {
+ if(outfile)
+ fclose(outfile);
+ cli_errmsg("cli_untar: block read error\n");
+ return CL_EIO;
+ }
+
+ if(!in_block) {
+ char type;
+ const char *suffix;
+ size_t suffixLen = 0;
+ int fd, directory, skipEntry = 0;
+ char magic[7], name[101], osize[13];
+
+ if(outfile) {
+ if(fclose(outfile)) {
+ cli_errmsg("cli_untar: cannot close file %s\n",
+ fullname);
+ return CL_EIO;
+ }
+ outfile = (FILE*)0;
+ }
+
+ if(block[0] == '\0') /* We're done */
+ break;
+
+ if(limits && limits->maxfiles && (files >= limits->maxfiles)) {
+ cli_dbgmsg("cli_untar: number of files exceeded %u\n", limits->maxfiles);
+ return CL_CLEAN;
+ }
+
+ /* Notice assumption that BLOCKSIZE > 262 */
+ if(posix) {
+ strncpy(magic, block+257, 5);
+ magic[5] = '\0';
+ if(strcmp(magic, "ustar") != 0) {
+ cli_dbgmsg("Incorrect magic string '%s' in tar header\n", magic);
+ return CL_EFORMAT;
+ }
+ }
+
+ type = block[156];
+
+ /*
+ * Extra types from djgardner at users.sourceforge.net
+ */
+ switch(type) {
+ default:
+ cli_warnmsg("cli_untar: unknown type flag %c\n", type);
+ case '0': /* plain file */
+ case '\0': /* plain file */
+ case '7': /* contiguous file */
+ case 'M': /* continuation of a file from another volume; might as well scan it. */
+ files++;
+ directory = 0;
+ break;
+ case '1': /* Link to already archived file */
+ case '5': /* directory */
+ case '2': /* sym link */
+ case '3': /* char device */
+ case '4': /* block device */
+ case '6': /* fifo special */
+ case 'V': /* Volume header */
+ directory = 1;
+ break;
+ case 'K':
+ case 'L':
+ /* GNU extension - ././@LongLink
+ * Discard the blocks with the extended filename,
+ * the last header will contain parts of it anyway
+ */
+ case 'N': /* Old GNU format way of storing long filenames. */
+ case 'A': /* Solaris ACL */
+ case 'E': /* Solaris Extended attribute s*/
+ case 'I': /* Inode only */
+ case 'g': /* Global extended header */
+ case 'x': /* Extended attributes */
+ case 'X': /* Extended attributes (POSIX) */
+ directory = 0;
+ skipEntry = 1;
+ break;
+ }
+
+ if(directory) {
+ in_block = 0;
+ continue;
+ }
+
+ strncpy(osize, block+124, 12);
+ osize[12] = '\0';
+ size = octal(osize);
+ if(size < 0) {
+ cli_errmsg("Invalid size in tar header\n");
+ if(outfile)
+ fclose(outfile);
+ return CL_EFORMAT;
+ }
+ cli_dbgmsg("cli_untar: size = %d\n", size);
+ if(limits && limits->maxfilesize && ((unsigned int)size > limits->maxfilesize)) {
+ cli_dbgmsg("cli_untar: size exceeded %d bytes\n", size);
+ skipEntry++;
+ }
+
+ if(skipEntry) {
+ const int nskip = (size % BLOCKSIZE || !size) ? size + BLOCKSIZE - (size % BLOCKSIZE) : size;
+
+ cli_dbgmsg("cli_untar: skipping entry\n");
+ lseek(desc, nskip, SEEK_CUR);
+ continue;
+ }
+
+ strncpy(name, block, 100);
+ name[100] = '\0';
+
+ /*
+ * see also fileblobSetFilename()
+ * TODO: check if the suffix needs to be put back
+ */
+ sanitiseName(name);
+ suffix = strrchr(name, '.');
+ if(suffix == NULL)
+ suffix = "";
+ else {
+ suffixLen = strlen(suffix);
+ if(suffixLen > 4) {
+ /* Found a full stop which isn't a suffix */
+ suffix = "";
+ suffixLen = 0;
+ }
+ }
+ snprintf(fullname, sizeof(fullname) - 1 - suffixLen, "%s/%.*sXXXXXX", dir,
+ (int)(sizeof(fullname) - 9 - suffixLen - strlen(dir)), name);
+#if defined(C_LINUX) || defined(C_BSD) || defined(HAVE_MKSTEMP) || defined(C_SOLARIS) || defined(C_CYGWIN)
+ fd = mkstemp(fullname);
+#else
+ (void)mktemp(fullname);
+ fd = open(fullname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
+#endif
+
+ if(fd < 0) {
+ cli_errmsg("Can't create temporary file %s: %s\n", fullname, strerror(errno));
+ cli_dbgmsg("%lu %lu %lu\n",
+ (unsigned long)suffixLen,
+ (unsigned long)sizeof(fullname),
+ (unsigned long)strlen(fullname));
+ return CL_ETMPFILE;
+ }
+
+ cli_dbgmsg("cli_untar: extracting %s\n", fullname);
+
+ in_block = 1;
+ if((outfile = fdopen(fd, "wb")) == NULL) {
+ cli_errmsg("cli_untar: cannot create file %s\n",
+ fullname);
+ close(fd);
+ return CL_ETMPFILE;
+ }
+ } else { /* write or continue writing file contents */
+ const int nbytes = size>512? 512:size;
+ const int nwritten = (int)fwrite(block, 1, (size_t)nbytes, outfile);
+
+ if(nwritten != nbytes) {
+ cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n",
+ nwritten, fullname);
+ if(outfile)
+ fclose(outfile);
+ return CL_EIO;
+ }
+ size -= nbytes;
+ }
+ if (size == 0)
+ in_block = 0;
+ }
+ if(outfile)
+ return fclose(outfile);
+
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_unzip.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2003 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ * (C) 2006 Sensory Networks, Inc.
+ *
+ * The code of this module was based on zziplib 0.12.83:
+ * (c) 1999 - 2002 Guido Draheim <guidod at gmx.de>, published under
+ * the Lesser GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#include "clamav.h"
+#include "others.h"
+#include "unzip.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define EC16(x) le16_to_host(x)
+
+#define __sizeof(X) ((ssize_t)(sizeof(X)))
+
+#define ZIPBUFSIZ 1024
+#define ZIP32K 32768
+
+inline static void __fixup_rootseek(off_t offset_of_trailer, struct zip_disk_trailer *trailer)
+{
+ if((off_t) EC32(trailer->z_rootseek) >
+ offset_of_trailer - (off_t) EC32(trailer->z_rootsize) &&
+ offset_of_trailer > (off_t) EC32(trailer->z_rootsize))
+ trailer->z_rootseek = (uint32_t) (offset_of_trailer - EC32(trailer->z_rootsize));
+}
+
+static int __zip_find_disk_trailer(int fd, off_t filesize, struct zip_disk_trailer *trailer, off_t *start)
+{
+ char *buf, *end, *tail;
+ off_t offset = 0, bufsize;
+ struct zip_root_dirent dirent;
+ uint32_t u_rootseek, shift = 0;
+ int i;
+
+
+ if(!trailer) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: trailer == NULL\n");
+ return CL_ENULLARG;
+ }
+
+ if(filesize < __sizeof(struct zip_disk_trailer)) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: File too short\n");
+ return CL_EFORMAT;
+ }
+
+ if(!(buf = cli_malloc(ZIPBUFSIZ)))
+ return CL_EMEM;
+
+ offset = filesize;
+ while(1) {
+
+ if(offset <= 0) {
+ cli_dbgmsg("Unzip: __zip_find_disk_trailer: Central directory not found\n");
+ free(buf);
+ return CL_EFORMAT;
+ }
+
+ if(offset >= ZIPBUFSIZ) {
+ if(offset == filesize)
+ offset -= ZIPBUFSIZ;
+ else
+ offset -= ZIPBUFSIZ - sizeof(struct zip_disk_trailer);
+
+ bufsize = ZIPBUFSIZ;
+ } else {
+ if(filesize < ZIPBUFSIZ)
+ bufsize = offset;
+ else
+ bufsize = ZIPBUFSIZ;
+
+ offset = 0;
+ }
+
+ if(lseek(fd, offset, SEEK_SET) < 0) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd);
+ free(buf);
+ return CL_EIO;
+ }
+
+ if(cli_readn(fd, buf, (size_t) bufsize) < (ssize_t) bufsize) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize);
+ free(buf);
+ return CL_EIO;
+ }
+
+ end = buf + bufsize;
+ for(tail = end - 1; tail >= buf; tail--) {
+ if((*tail == 'P') && (end - tail >= __sizeof(struct zip_disk_trailer) - 2) && cli_readint32(tail) == ZIP_DISK_TRAILER_MAGIC) {
+ if(end - tail >= __sizeof(struct zip_disk_trailer)) {
+ memcpy(trailer, tail, sizeof(struct zip_disk_trailer));
+ } else {
+ memcpy(trailer, tail, sizeof(struct zip_disk_trailer) - 2);
+ trailer->z_comment = 0;
+ }
+ __fixup_rootseek(offset + tail - buf, trailer);
+
+ u_rootseek = EC32(trailer->z_rootseek);
+ if(u_rootseek > (uint32_t) filesize) {
+ cli_dbgmsg("Unzip: __zip_find_disk_trailer: u_rootseek > filesize, continue search\n");
+ continue;
+ }
+
+ for(i = 0; i < 2; i++) {
+ if(u_rootseek + shift + sizeof(dirent) < (uint32_t) filesize) {
+ if(lseek(fd, u_rootseek + shift, SEEK_SET) < 0) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd);
+ free(buf);
+ return CL_EIO;
+ }
+
+ if(cli_readn(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) {
+ cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize);
+ free(buf);
+ return CL_EIO;
+ }
+
+ if(EC32(dirent.z_magic) == ZIP_ROOT_DIRENT_MAGIC) {
+ cli_dbgmsg("Unzip: __zip_find_disk_trailer: found file header at %u, shift %u\n", u_rootseek + shift, shift);
+ free(buf);
+ *start = shift;
+ return CL_SUCCESS;
+ }
+
+ shift = *start;
+ }
+ }
+ }
+ }
+ }
+
+ /* this should never be reached */
+ free(buf);
+ return CL_EFORMAT;
+}
+
+static int __zip_parse_root_directory(int fd, struct zip_disk_trailer *trailer, zip_dir_hdr **hdr_return, off_t start)
+{
+ struct zip_root_dirent dirent, *d;
+ zip_dir_hdr *hdr, *hdr0, *prev_hdr;
+ uint16_t *p_reclen = NULL, entries;
+ uint32_t offset;
+ struct stat sb;
+ uint16_t u_entries = EC16(trailer->z_entries);
+ uint32_t u_rootsize = EC32(trailer->z_rootsize);
+ uint32_t u_rootseek = EC32(trailer->z_rootseek) + start;
+ uint16_t u_extras, u_comment, u_namlen, u_flags;
+ unsigned int bfcnt;
+ char *pt;
+
+
+ if(fstat(fd, &sb) == -1) {
+ cli_errmsg("Unzip: __zip_parse_root_directory: Can't fstat file descriptor %d\n", fd);
+ return CL_EIO;
+ }
+
+ if(!u_entries) {
+ cli_errmsg("Unzip: __zip_parse_root_directory: File contains no entries\n");
+ return CL_EFORMAT;
+ }
+
+ if(u_rootsize > (uint32_t) sb.st_size) {
+ cli_errmsg("Unzip: __zip_parse_root_directory: Incorrect root size\n");
+ return CL_EFORMAT;
+ }
+
+ hdr0 = (zip_dir_hdr*) cli_malloc(u_rootsize);
+ if (!hdr0)
+ return CL_EMEM;
+
+ hdr = hdr0;
+
+ for(entries = u_entries, offset = 0; entries > 0; entries--) {
+
+ if(lseek(fd, u_rootseek + offset, SEEK_SET) < 0) {
+ free(hdr0);
+ cli_errmsg("Unzip: __zip_parse_root_directory: Can't lseek descriptor %d\n", fd);
+ return CL_EIO;
+ }
+
+ if(cli_readn(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) {
+ if(entries != u_entries) {
+ entries = 0;
+ break;
+ } else {
+ free(hdr0);
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Can't read %d bytes\n", sizeof(dirent));
+ return CL_EIO;
+ }
+ }
+ d = &dirent;
+
+ if(offset + sizeof(struct zip_root_dirent) > u_rootsize) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Entry %d outside of root directory\n", entries);
+ break;
+ }
+
+ u_extras = EC16(d->z_extras);
+ u_comment = EC16(d->z_comment);
+
+ u_namlen = EC16(d->z_namlen);
+ if(u_namlen > 1024) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Entry %d name too long\n", entries);
+ break;
+ }
+
+ u_flags = EC16(d->z_flags);
+
+ hdr->d_crc32 = EC32(d->z_crc32);
+ hdr->d_csize = EC32(d->z_csize);
+ hdr->d_usize = EC32(d->z_usize);
+ hdr->d_off = EC32(d->z_off) + start;
+
+ hdr->d_compr = EC16(d->z_compr);
+
+ bfcnt = 0;
+ if(!hdr->d_compr && hdr->d_csize != hdr->d_usize) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: File claims to be stored but csize != usize\n");
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Also checking for method 'deflated'\n");
+ hdr->d_bf[bfcnt] = ZIP_METHOD_DEFLATED;
+ bfcnt++;
+ } else if(hdr->d_compr && hdr->d_csize == hdr->d_usize) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: File claims to be deflated but csize == usize\n");
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Also checking for method 'stored'\n");
+ hdr->d_bf[bfcnt] = ZIP_METHOD_STORED;
+ bfcnt++;
+ }
+ hdr->d_bf[bfcnt] = -1;
+
+ hdr->d_flags = u_flags;
+
+ if(offset + sizeof(struct zip_root_dirent) + u_namlen > u_rootsize) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Name of entry %d outside of root directory\n", entries);
+ break;
+ }
+
+ if(cli_readn(fd, hdr->d_name, u_namlen) != u_namlen) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: Can't read name of entry %d\n", entries);
+ break;
+ }
+
+ hdr->d_name[u_namlen] = '\0';
+ hdr->d_namlen = u_namlen;
+
+ offset += sizeof(struct zip_root_dirent) + u_namlen + u_extras + u_comment;
+
+ if(offset > u_rootsize) {
+ cli_dbgmsg("Unzip: __zip_parse_root_directory: End of entry %d outside of root directory\n", entries);
+ break;
+ }
+
+ pt = (char *) hdr + sizeof(zip_dir_hdr) + u_namlen + 1;
+ pt += ((long) pt) & 1;
+ pt += ((long) pt) & 2;
+ hdr->d_reclen = (uint16_t) (pt - (char *) hdr);
+ p_reclen = &hdr->d_reclen;
+
+ prev_hdr = hdr;
+ hdr = (zip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
+ }
+
+ if(p_reclen) {
+ *p_reclen = 0;
+ if(hdr_return)
+ *hdr_return = hdr0;
+ } else {
+ free(hdr0);
+ }
+
+ return entries ? CL_EFORMAT : CL_SUCCESS;
+}
+
+int zip_dir_close(zip_dir *dir)
+{
+ if(dir->hdr0)
+ free(dir->hdr0);
+
+ if(dir->cache.fp)
+ free(dir->cache.fp);
+
+ if(dir->cache.buf32k)
+ free(dir->cache.buf32k);
+
+ free(dir);
+ return CL_SUCCESS;
+}
+
+static int __zip_dir_parse(zip_dir *dir, off_t start)
+{
+ int ret;
+ struct zip_disk_trailer trailer;
+ struct stat sb;
+
+
+ if(fstat(dir->fd, &sb) == -1) {
+ cli_errmsg("Unzip: __zip_dir_parse: Can't fstat file descriptor %d\n", dir->fd);
+ return CL_EIO;
+ }
+
+ if((ret = __zip_find_disk_trailer(dir->fd, sb.st_size, &trailer, &start)))
+ return ret;
+
+ if((ret = __zip_parse_root_directory(dir->fd, &trailer, &dir->hdr0, start)))
+ return ret;
+
+ return CL_SUCCESS;
+}
+
+zip_dir *zip_dir_open(int fd, off_t start, int *errcode_p)
+{
+ int ret;
+ zip_dir * dir;
+
+
+ dir = (zip_dir *) cli_calloc(1, sizeof(zip_dir));
+ if(!dir) {
+ if(errcode_p)
+ *errcode_p = CL_EMEM;
+ return NULL;
+ }
+
+ if(start) {
+ if(lseek(fd, start, SEEK_SET) == -1) {
+ cli_errmsg("Unzip: zip_dir_open: Can't lseek descriptor %d\n", fd);
+ if(errcode_p)
+ *errcode_p = CL_EIO;
+ return NULL;
+ }
+ }
+
+ dir->fd = fd;
+
+ if((ret = __zip_dir_parse(dir, start))) {
+ zip_dir_close(dir);
+ if(errcode_p)
+ *errcode_p = CL_EMEM;
+ return NULL;
+ }
+
+ dir->hdr = dir->hdr0;
+
+ if(errcode_p)
+ *errcode_p = CL_SUCCESS;
+
+ return dir;
+}
+
+int zip_dir_read(zip_dir *dir, zip_dirent *d)
+{
+
+ if(!dir || !dir->hdr || !d)
+ return 0;
+
+ d->d_compr = dir->hdr->d_compr;
+ d->d_csize = dir->hdr->d_csize;
+ d->st_size = dir->hdr->d_usize;
+ d->d_name = dir->hdr->d_name;
+ d->d_flags = dir->hdr->d_flags;
+ d->d_off = dir->hdr->d_off;
+ d->d_crc32 = dir->hdr->d_crc32;
+
+ if(!dir->hdr->d_reclen)
+ dir->hdr = NULL;
+ else
+ dir->hdr = (zip_dir_hdr *) ((char *) dir->hdr + dir->hdr->d_reclen);
+
+ return 1;
+}
+
+int zip_file_close(zip_file *fp)
+{
+ zip_dir *dir;
+
+
+ if(!fp) {
+ cli_errmsg("Unzip: zip_file_close: fp == NULL\n");
+ return CL_ENULLARG;
+ }
+
+ inflateEnd(&fp->d_stream);
+
+ dir = fp->dir;
+ if(fp->buf32k) {
+ if(!dir->cache.buf32k)
+ dir->cache.buf32k = fp->buf32k;
+ else
+ free(fp->buf32k);
+ }
+
+ memset(fp, 0, sizeof(zip_file));
+
+ if(!dir->cache.fp)
+ dir->cache.fp = fp;
+ else
+ free(fp);
+
+ return CL_SUCCESS;
+}
+
+static int __zip_inflate_init(zip_file *fp, zip_dir_hdr *hdr)
+{
+ int ret;
+ fp->method = hdr->d_compr;
+ fp->restlen = hdr->d_usize;
+
+
+ if(fp->method) {
+ memset(&fp->d_stream, 0, sizeof(fp->d_stream));
+
+ ret = inflateInit2(&fp->d_stream, -MAX_WBITS);
+
+ if(ret != Z_OK) {
+ cli_errmsg("Unzip: __zip_inflate_init: inflateInit2 failed\n");
+ return CL_EZIP;
+ }
+
+ fp->crestlen = hdr->d_csize;
+ }
+
+ return CL_SUCCESS;
+}
+
+zip_file *zip_file_open(zip_dir *dir, const char *name, int d_off)
+{
+ int ret;
+ zip_file *fp = NULL;
+ zip_dir_hdr *hdr = dir->hdr0;
+ const char *hdr_name;
+ ssize_t dataoff;
+ struct zip_file_header *hp;
+
+
+ if(!dir || dir->fd < 0) {
+ cli_errmsg("Unzip: zip_file_open: dir == NULL || dir->fd <= 0\n");
+ return NULL;
+ }
+
+ if(!hdr) {
+ cli_errmsg("Unzip: zip_file_open: hdr == NULL\n");
+ dir->errcode = CL_ENULLARG;
+ return NULL;
+ }
+
+ while(1) {
+ hdr_name = hdr->d_name;
+
+ if(!strcmp(hdr_name, name) && (d_off == -1 || (uint32_t) d_off == hdr->d_off)) {
+ switch (hdr->d_compr) {
+ case ZIP_METHOD_STORED:
+ case ZIP_METHOD_DEFLATED:
+ case ZIP_METHOD_DEFLATED64:
+ break;
+
+ case ZIP_METHOD_SHRUNK:
+ case ZIP_METHOD_REDUCEDx1:
+ case ZIP_METHOD_REDUCEDx2:
+ case ZIP_METHOD_REDUCEDx3:
+ case ZIP_METHOD_REDUCEDx4:
+ case ZIP_METHOD_IMPLODED:
+ case ZIP_METHOD_TOKENIZED:
+ case ZIP_METHOD_IMPLODED_DCL:
+ case ZIP_METHOD_BZIP2:
+ case ZIP_METHOD_AES:
+ cli_dbgmsg("Unzip: zip_file_open: Not supported compression method (%d)\n", hdr->d_compr);
+ dir->errcode = CL_ESUPPORT;
+ return NULL;
+
+ default:
+ cli_errmsg("Unzip: zip_file_read: Unknown compression method (%d)\n", hdr->d_compr);
+ dir->errcode = CL_EFORMAT;
+ return NULL;
+ }
+
+ if(dir->cache.fp) {
+ fp = dir->cache.fp;
+ dir->cache.fp = NULL;
+ } else {
+ fp = (zip_file *) cli_calloc(1, sizeof(zip_file));
+ if(!fp) {
+ dir->errcode = CL_EMEM;
+ return NULL;
+ }
+ }
+
+ fp->dir = dir;
+
+ if(dir->cache.buf32k) {
+ fp->buf32k = dir->cache.buf32k;
+ dir->cache.buf32k = NULL;
+ } else {
+ fp->buf32k = (char *) cli_malloc(ZIP32K);
+ if(!fp->buf32k) {
+ dir->errcode = CL_EMEM;
+ zip_file_close(fp);
+ return NULL;
+ }
+ }
+
+ if(lseek(dir->fd, hdr->d_off, SEEK_SET) < 0) {
+ cli_errmsg("Unzip: zip_file_open: Can't lseek descriptor %d\n", dir->fd);
+ dir->errcode = CL_EIO;
+ zip_file_close(fp);
+ return NULL;
+ }
+
+ hp = (void *) fp->buf32k;
+ dataoff = cli_readn(dir->fd, (void *) hp, sizeof(struct zip_file_header));
+
+ if(dataoff < __sizeof(struct zip_file_header)) {
+ cli_errmsg("Unzip: zip_file_open: Can't read zip header (only read %d bytes)\n", dataoff);
+ dir->errcode = CL_EIO;
+ zip_file_close(fp);
+ return NULL;
+ }
+
+ dataoff = EC16(hp->z_namlen) + EC16(hp->z_extras);
+
+ if(lseek(dir->fd, dataoff, SEEK_CUR) < 0) {
+ cli_errmsg("Unzip: zip_file_open: Can't lseek descriptor %d\n", dir->fd);
+ dir->errcode = CL_EIO;
+ zip_file_close(fp);
+ return NULL;
+ }
+
+ fp->usize = hdr->d_usize;
+ fp->csize = hdr->d_csize;
+
+ fp->bf = hdr->d_bf;
+
+ ret = __zip_inflate_init(fp, hdr);
+
+ if(ret) {
+ dir->errcode = CL_EIO;
+ zip_file_close(fp);
+ return NULL;
+ }
+
+ return fp;
+
+ } else {
+ if(!hdr->d_reclen)
+ break;
+
+ hdr = (zip_dir_hdr *) ((char *) hdr + hdr->d_reclen);
+ }
+ }
+
+ dir->errcode = CL_EOPEN;
+ if(fp)
+ zip_file_close(fp);
+ return NULL;
+}
+
+ssize_t zip_file_read(zip_file *fp, char *buf, size_t len)
+{
+ zip_dir *dir;
+ size_t l;
+ ssize_t bread;
+
+
+ if(!fp || !fp->dir) {
+ cli_errmsg("Unzip: zip_file_read: fp == NULL || fp->dir == NULL\n");
+ return -1;
+ }
+
+ dir = fp->dir;
+ l = fp->restlen > len ? len : fp->restlen;
+ if(!fp->restlen)
+ return 0;
+
+ switch(fp->method) {
+
+ case ZIP_METHOD_STORED:
+ bread = cli_readn(dir->fd, buf, l);
+ if(bread > 0) {
+ fp->restlen -= bread;
+ } else if(bread < 0) {
+ cli_errmsg("Unzip: zip_file_read: Can't read %d bytes\n", l);
+ dir->errcode = CL_EIO;
+ }
+ return bread;
+
+ case ZIP_METHOD_DEFLATED:
+ case ZIP_METHOD_DEFLATED64:
+ fp->d_stream.avail_out = l;
+ fp->d_stream.next_out = (unsigned char *) buf;
+ do {
+ int ret;
+ size_t startlen;
+
+ if(fp->crestlen > 0 && fp->d_stream.avail_in == 0) {
+ size_t cl = (fp->crestlen < ZIP32K ? fp->crestlen : ZIP32K);
+ ssize_t i = cli_readn(dir->fd, fp->buf32k, cl);
+ if(i <= 0) {
+ dir->errcode = CL_EIO;
+ cli_errmsg("Unzip: zip_file_read: Can't read %d bytes (read %d)\n", cl, i);
+ return -1;
+ }
+ fp->crestlen -= i;
+ fp->d_stream.avail_in = i;
+ fp->d_stream.next_in = (unsigned char *) fp->buf32k;
+ }
+
+ startlen = fp->d_stream.total_out;
+ ret = inflate(&fp->d_stream, Z_NO_FLUSH);
+
+ if(ret == Z_STREAM_END) {
+ fp->restlen = 0;
+ } else {
+ if(ret == Z_OK) {
+ fp->restlen -= (fp->d_stream.total_out - startlen);
+ } else {
+ if(fp->method == ZIP_METHOD_DEFLATED64) {
+ cli_dbgmsg("Unzip: zip_file_read: Not supported compression method (%u)\n", fp->method);
+ dir->errcode = CL_ESUPPORT;
+ } else {
+ dir->errcode = CL_EZIP;
+ }
+ return -1;
+ }
+ }
+ } while(fp->restlen && fp->d_stream.avail_out);
+
+ return l - fp->d_stream.avail_out;
+
+ default:
+ /* this should not be reached because of the previous check in
+ * zip_file_open
+ */
+ cli_errmsg("Unzip: zip_file_read: Unknown compression method (%d)\n", fp->method);
+ dir->errcode = CL_EZIP;
+ return -1;
+ }
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upack.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ * 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.
+ */
+
+/*
+ * upack.c
+ *
+ *
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "cltypes.h"
+#include "pe.h"
+#include "rebuildpe.h"
+#include "others.h"
+#include "upack.h"
+#include "mew.h"
+
+#define EC32(x) le32_to_host(x) /* Convert little endian to host */
+#define CE32(x) be32_to_host(x) /* Convert big endian to host */
+
+int unupack399(char *, uint32_t, uint32_t, char *, uint32_t, char *, char *, uint32_t, char *);
+
+enum { UPACK_399, UPACK_11_12, UPACK_0151477, UPACK_0297729 };
+
+int unupack(int upack, char *dest, uint32_t dsize, char *buff, uint32_t vma, uint32_t ep, uint32_t base, uint32_t va, int file)
+{
+ int j, searchval;
+ char *loc_esi, *loc_edi, *loc_ebx, *end_edi, *save_edi, *rpeb, *alvalue;
+ char *paddr, *pushed_esi, *save2;
+ uint32_t save1, save3, loc_ecx, count, shlsize, original_ep, ret, loc_ebx_u;
+ struct cli_exe_section section;
+ int upack_version = UPACK_399;
+
+ /* buff [168 bytes] doesn't have to be checked, since it was checked in pe.c */
+ if (upack)
+ {
+ uint32_t aljump, shroff, lngjmpoff;
+
+ /* dummy characteristics ;/ */
+ if (buff[5] == '\xff' && buff[6] == '\x36')
+ upack_version = UPACK_0297729;
+ loc_esi = dest + (cli_readint32(buff + 1) - vma);
+
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12))
+ return -1;
+ original_ep = cli_readint32(loc_esi);
+ loc_esi += 4;
+ /*cli_readint32(loc_esi);*/
+ loc_esi += 4;
+
+ original_ep -= vma;
+ cli_dbgmsg("Upack: EP: %08x original: %08X || %08x\n", ep, original_ep, cli_readint32(loc_esi-8));
+
+ if (upack_version == UPACK_399)
+ {
+ /* jmp 1 */
+ loc_edi = dest + (cli_readint32(loc_esi) - vma);
+ if (!CLI_ISCONTAINED(dest, dsize, dest+ep+0xa, 2) || dest[ep+0xa] != '\xeb')
+ return -1;
+ loc_esi = dest + *(dest + ep + 0xb) + ep + 0xc;
+
+ /* use this as a temp var */
+ /* jmp 2 + 0xa */
+ alvalue = loc_esi+0x1a;
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xeb')
+ return -1;
+ alvalue++;
+ alvalue += (*alvalue&0xff) + 1 + 0xa;
+ lngjmpoff = 8;
+ } else {
+ if (!CLI_ISCONTAINED(dest, dsize, dest+ep+7, 5) || dest[ep+7] != '\xe9')
+ return -1;
+ loc_esi = dest + cli_readint32(dest + ep + 8) + ep + 0xc;
+ alvalue = loc_esi + 0x25;
+ lngjmpoff = 10;
+ }
+
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xb5')
+ return -1;
+ alvalue++;
+ count = *alvalue&0xff;
+
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue, lngjmpoff+5) || *(alvalue+lngjmpoff) != '\xe9')
+ return -1;
+ /* use this as a temp to make a long jmp to head of unpacking proc */
+ shlsize = cli_readint32(alvalue + lngjmpoff+1);
+ /* upack_399 + upack_0151477 */
+ if (upack_version == UPACK_399)
+ shlsize = shlsize + (loc_esi - dest) + *(loc_esi+0x1b) + 0x1c + 0x018; /* read checked above */
+ else
+ /* there is no additional jump in upack_0297729 */
+ shlsize = shlsize + (loc_esi - dest) + 0x035;
+ /* do the jump, 43 - point to jecxz */
+ alvalue = dest+shlsize+43;
+
+ /* 0.39 */
+ aljump = 8;
+ shroff = 24;
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3')
+ {
+ /* in upack_0297729 and upack_0151477 jecxz is at offset: 46 */
+ alvalue = dest+shlsize+46;
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3')
+ return -1;
+ else {
+ if (upack_version != UPACK_0297729)
+ upack_version = UPACK_0151477;
+ aljump = 7;
+ shroff = 26;
+ }
+
+ }
+ /* do jecxz */
+ alvalue += (*alvalue&0xff) + 1;
+ /* is there a long jump ? */
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue, aljump+5) || *(alvalue+aljump) != '\xe9')
+ return -1;
+ /* do jmp, 1+4 - size of jmp instruction, aljump - instruction offset, 27 offset to cmp al,xx*/
+ ret = cli_readint32(alvalue+aljump+1);
+ alvalue += ret + aljump+1+4 + 27;
+ if (upack_version == UPACK_0297729)
+ alvalue += 2;
+ /* shr ebp */
+ if (!CLI_ISCONTAINED(dest, dsize, dest+shlsize+shroff, 3) || *(dest+shlsize+shroff) != '\xc1' || *(dest+shlsize+shroff+1) != '\xed')
+ return -1;
+ shlsize = (*(dest + shlsize + shroff+2))&0xff;
+ count *= 0x100;
+ if (shlsize < 2 || shlsize > 8)
+ {
+ cli_dbgmsg ("Upack: context bits out of bounds\n");
+ return -1;
+ }
+ cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count);
+ /* check if loc_esi + .. == 0xbe -> mov esi */
+ /* upack_0297729 has mov esi, .. + mov edi, .., in upack_0151477 and upack_399 EDI has been already set before */
+ if (upack_version == UPACK_0297729)
+ {
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi+6, 10) || *(loc_esi+6) != '\xbe' || *(loc_esi+11) != '\xbf')
+ return -1;
+ if ((uint32_t)cli_readint32(loc_esi + 7) < base || (uint32_t)cli_readint32(loc_esi+7) > vma)
+ return -1;
+ loc_edi = dest + (cli_readint32(loc_esi + 12) - vma);
+ loc_esi = dest + (cli_readint32(loc_esi + 7) - base);
+ } else {
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi+7, 5) || *(loc_esi+7) != '\xbe')
+ return -1;
+ loc_esi = dest + (cli_readint32(loc_esi + 8) - vma);
+ }
+
+ if (upack_version == UPACK_0297729)
+ {
+ /* 0x16*4=0x58, 6longs*4 = 24, 0x64-last loc_esi read location */
+ if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x58 + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x58 + 0x64 + 4)))
+ return -1;
+
+ /* XXX I don't know if this [0x16] is constant number, not enough samples provided */
+ for (j=0; j<0x16; j++, loc_esi+=4, loc_edi+=4)
+ cli_writeint32(loc_edi, cli_readint32(loc_esi));
+ } else {
+ /* 0x27*4=0x9c, 6longs*4 = 24, 0x34-last loc_esi read location */
+ if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x9c + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x9c + 0x34 + 4)))
+ return -1;
+ for (j=0; j<0x27; j++, loc_esi+=4, loc_edi+=4)
+ cli_writeint32(loc_edi, cli_readint32(loc_esi));
+ }
+ save3 = cli_readint32(loc_esi + 4);
+ paddr = dest + ((uint32_t)cli_readint32(loc_edi - 4)) - vma;
+ loc_ebx = loc_edi;
+ cli_writeint32(loc_edi, 0xffffffff);
+ loc_edi+=4;
+ cli_writeint32(loc_edi, 0);
+ loc_edi+=4;
+ for (j=0; j<4; j++, loc_edi+=4)
+ cli_writeint32(loc_edi, (1));
+
+ for (j=0; (unsigned int)j<count; j++, loc_edi+=4)
+ cli_writeint32(loc_edi, 0x400);
+
+ loc_edi = dest + cli_readint32(loc_esi + 0xc) - vma;
+ if (upack_version == UPACK_0297729)
+ loc_edi = dest+vma-base; /* XXX not enough samples provided to be sure of it! */
+
+ pushed_esi = loc_edi;
+ end_edi = dest + cli_readint32(loc_esi + 0x34) - vma;
+ if (upack_version == UPACK_0297729)
+ {
+ end_edi = dest + cli_readint32(loc_esi + 0x64) - vma;
+ save3 = cli_readint32(loc_esi + 0x40);
+ }
+ /* begin end */
+ cli_dbgmsg("Upack: data initialized, before upack lzma call!\n");
+ if ((ret = (uint32_t)unupack399(dest, dsize, 0, loc_ebx, 0, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff)
+ return -1;
+ /* alternative begin */
+ } else {
+ int ep_jmp_offs, rep_stosd_count_offs, context_bits_offs;
+ loc_esi = dest + vma + ep;
+ /* yet another dummy characteristics ;/ */
+ if (buff[0] == '\xbe' && buff[5] == '\xad' && buff[6] == '\x8b' && buff[7] == '\xf8')
+ upack_version = UPACK_11_12;
+
+ if (upack_version == UPACK_11_12)
+ {
+ ep_jmp_offs = 0x1a4;
+ rep_stosd_count_offs = 0x1b;
+ context_bits_offs = 0x41;
+ alvalue = loc_esi + 0x184;
+ } else {
+ ep_jmp_offs = 0x217;
+ rep_stosd_count_offs = 0x3a;
+ context_bits_offs = 0x5f;
+ alvalue = loc_esi + 0x1c1;
+ }
+
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi, ep_jmp_offs+4))
+ return -1;
+ save1 = cli_readint32(loc_esi + ep_jmp_offs);
+ original_ep = (loc_esi - dest) + ep_jmp_offs + 4;
+ original_ep += (int32_t)save1;
+ cli_dbgmsg("Upack: EP: %08x original %08x\n", ep, original_ep);
+
+ /* this are really ugly hacks,
+ * rep_stosd_count_offs & context_bits_offs are < ep_jmp_offs,
+ * so checked in CLI_ISCONTAINED above */
+ count = (*(loc_esi + rep_stosd_count_offs))&0xff;
+ shlsize = (*(loc_esi + context_bits_offs))&0xff;
+ shlsize = 8 - shlsize;
+ if (shlsize < 2 || shlsize > 8)
+ {
+ cli_dbgmsg ("Upack: context bits out of bounds\n");
+ return -1;
+ }
+ count *= 0x100;
+ cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count);
+ if (upack_version == UPACK_399)
+ {
+ loc_esi += 4;
+ loc_ecx = cli_readint32(loc_esi+2);
+ cli_writeint32(loc_esi+2,0);
+ if (!loc_ecx)
+ {
+ cli_dbgmsg("Upack: something's wrong, report back\n");
+ return -1;/* XXX XXX XXX XXX */
+ }
+ loc_esi -= (loc_ecx - 2);
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12))
+ return -1;
+
+ cli_dbgmsg("Upack: %08x %08x %08x %08x\n", loc_esi, dest, cli_readint32(loc_esi), base);
+ loc_ebx_u = loc_esi - (dest + cli_readint32(loc_esi) - base);
+ cli_dbgmsg("Upack: EBX: %08x\n", loc_ebx_u);
+ loc_esi += 4;
+ save2 = loc_edi = dest + cli_readint32(loc_esi) - base;
+ cli_dbgmsg("Upack: DEST: %08x, %08x\n", cli_readint32(loc_esi), cli_readint32(loc_esi) - base);
+ loc_esi += 4;
+ /* 2vGiM: j is signed. Is that really what you want? Will it cause problems with the following checks?
+ * yes! this is wrong! how did you notice that?!
+ */
+ j = cli_readint32(loc_esi);
+ if (j<0)
+ {
+ cli_dbgmsg("Upack: probably hand-crafted data, report back\n");
+ return -1;
+ }
+ loc_esi += 4;
+ cli_dbgmsg("Upack: ecx counter: %08x\n", j);
+
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi, (j*4)) || !CLI_ISCONTAINED(dest, dsize, loc_edi, ((j+count)*4)))
+ return -1;
+ for (;j--; loc_edi+=4, loc_esi+=4)
+ cli_writeint32(loc_edi, cli_readint32(loc_esi));
+ if (!CLI_ISCONTAINED(dest, dsize, save2, 8))
+ return -1;
+ loc_ecx = cli_readint32(save2);
+ save2 += 4;
+ loc_esi = save2;
+ /* I could probably do simple loc_esi+= (0xe<<2),
+ * but I'm not sure if there is always 0xe and is always ebx =0
+ */
+ do {
+ loc_esi += loc_ebx_u;
+ loc_esi += 4;
+ } while (--loc_ecx);
+ if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 4))
+ return -1;
+ save1 = cli_readint32(loc_esi); /* loc_eax = 0x400 */
+ loc_esi += 4;
+
+ for (j=0; j<count; j++, loc_edi+=4) /* checked above */
+ cli_writeint32(loc_edi, (save1));
+
+ if (!CLI_ISCONTAINED(dest, dsize, (loc_esi+0x10), 4))
+ return -1;
+ cli_writeint32(loc_esi+0x10, (uint32_t)cli_readint32(loc_esi+0x10)+loc_ebx_u);
+ loc_ebx = loc_esi+0x14;
+ loc_esi = save2;
+ /* loc_ebx_u gets saved */
+ /* checked above, (...save2, 8) */
+ save_edi = loc_edi = dest + ((uint32_t)cli_readint32(loc_esi) - base);
+ loc_esi +=4;
+ cli_dbgmsg("Upack: before_fixing\n");
+ /* fix values */
+ if (!CLI_ISCONTAINED(dest, dsize, loc_ebx-4, (12 + 4*4)) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x24, 4) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x40, 4))
+ return -1;
+ for (j=2; j<6; j++)
+ cli_writeint32(loc_ebx+(j<<2), cli_readint32(loc_ebx+(j<<2)));
+ paddr = dest + cli_readint32(loc_ebx - 4) - base;
+ save1 = loc_ecx;
+ pushed_esi = loc_edi;
+ end_edi = dest + cli_readint32(loc_esi+0x24) - base;
+ vma = cli_readint32(loc_ebx); cli_writeint32(loc_ebx, cli_readint32(loc_ebx + 4)); cli_writeint32((loc_ebx + 4), vma);
+ /* Upack 1.1/1.2 is something between 0.39 2-section and 0.39 3-section */
+ } else if (upack_version == UPACK_11_12) {
+ cli_dbgmsg("Upack v 1.1/1.2\n");
+ loc_esi = dest + 0x148; /* always constant? */
+ loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */
+ loc_esi += 4;
+ save_edi = loc_edi;
+ /* movsd */
+ paddr = dest + ((uint32_t)cli_readint32(loc_esi)) - base;
+ loc_esi += 4;
+ loc_edi += 4;
+ loc_ebx = loc_edi;
+
+ if (!CLI_ISCONTAINED(dest, dsize, loc_edi, ((6+count)*4)))
+ return -1;
+ cli_writeint32(loc_edi, 0xffffffff);
+ loc_edi += 4;
+ cli_writeint32(loc_edi, 0);
+ loc_edi += 4;
+ for (j=0; j<4; j++, loc_edi+=4)
+ cli_writeint32(loc_edi, (1));
+
+ for (j=0; j<count; j++, loc_edi+=4)
+ cli_writeint32(loc_edi, 0x400);
+
+ loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */
+ pushed_esi = loc_edi;
+ loc_esi += 4;
+ loc_ecx = 0;
+
+ loc_esi += 4;
+
+ end_edi = dest + cli_readint32(loc_esi-0x28) - base; /* read checked above */
+ loc_esi = save_edi;
+ }
+ cli_dbgmsg("Upack: data initialized, before upack lzma call!\n");
+ if ((ret = (uint32_t)unupack399(dest, dsize, loc_ecx, loc_ebx, loc_ecx, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff)
+ return -1;
+ if (upack_version == UPACK_399)
+ save3 = cli_readint32(loc_esi + 0x40);
+ else if (upack_version == UPACK_11_12)
+ save3 = cli_readint32(dest + vma + ep + 0x174);
+ }
+
+ /* let's fix calls */
+ loc_ecx = 0;
+ if (!CLI_ISCONTAINED(dest, dsize, alvalue, 1)) {
+ cli_dbgmsg("Upack: alvalue out of bounds\n");
+ return -1;
+ }
+
+ searchval = *alvalue&0xff;
+ cli_dbgmsg("Upack: loops: %08x search value: %02x\n", save3, searchval);
+ while(save3) {
+ if (!CLI_ISCONTAINED(dest, dsize, pushed_esi + loc_ecx, 1))
+ {
+ cli_dbgmsg("Upack: callfixerr %08x %08x = %08x, %08x\n", dest, dsize, dest+dsize, pushed_esi+loc_ecx);
+ return -1;
+ }
+ if (pushed_esi[loc_ecx] == '\xe8' || pushed_esi[loc_ecx] == '\xe9')
+ {
+ char *adr = (pushed_esi + loc_ecx + 1);
+ loc_ecx++;
+ if (!CLI_ISCONTAINED(dest, dsize, adr, 4))
+ {
+ cli_dbgmsg("Upack: callfixerr\n");
+ return -1;
+ }
+ if ((cli_readint32(adr)&0xff) != searchval)
+ continue;
+ cli_writeint32(adr, EC32(CE32((uint32_t)(cli_readint32(adr)&0xffffff00)))-loc_ecx-4);
+ loc_ecx += 4;
+ save3--;
+ } else
+ loc_ecx++;
+ }
+
+ section.raw = 0;
+ section.rva = va;
+ section.rsz = end_edi-loc_edi;
+ section.vsz = end_edi-loc_edi;
+
+ if (!cli_rebuildpe(dest + (upack?0:va), §ion, 1, base, original_ep, 0, 0, file)) {
+ cli_dbgmsg("Upack: Rebuilding failed\n");
+ return 0;
+ }
+ return 1;
+}
+
+
+int unupack399(char *bs, uint32_t bl, uint32_t init_eax, char *init_ebx, uint32_t init_ecx, char *init_edi, char *end_edi, uint32_t shlsize, char *paddr)
+{
+ struct lzmastate p;
+ uint32_t loc_eax, ret, loc_al, loc_ecx = init_ecx, loc_ebp, eax_copy = init_eax, temp, i, jakas_kopia;
+ uint32_t state[6], temp_ebp;
+ char *loc_edx, *loc_ebx = init_ebx, *loc_edi = init_edi, *loc_ebp8, *edi_copy;
+ p.p0 = paddr;
+ p.p1 = cli_readint32(init_ebx);
+ p.p2 = cli_readint32(init_ebx + 4);
+
+ cli_dbgmsg("\n\tp0: %08x\n\tp1: %08x\n\tp2: %08x\n", p.p0, p.p1, p.p2);
+ for (i = 0; i<6; i++)
+ state[i] = cli_readint32(loc_ebx + (i<<2)),
+ cli_dbgmsg("state[%d] = %08x\n", i, state[i]);
+ do {
+ loc_eax = eax_copy;
+ loc_edx = loc_ebx + (loc_eax<<2) + 0x58;
+
+ if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl)))
+ {
+ /* loc_483927 */
+ loc_al = loc_eax&0xff;
+ loc_al = ((loc_al + 0xf9) > 0xff)?(3+8):8;
+ loc_eax = (loc_eax&0xffffff00)|(loc_al&0xff);
+ loc_ebp = state[2];
+ loc_ecx = (loc_ecx&0xffffff00)|0x30;
+ loc_edx += loc_ecx;
+ /* *(uint32_t *)(loc_ebx + 14) = loc_ebp; ???? */
+ if (!(ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+ /* loc_48397c */
+ loc_eax--;
+ /*
+ temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x0c); cli_writeint32(loc_ebx+0x0c, temp_ebp);
+ temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x10); cli_writeint32(loc_ebx+0x10, temp_ebp);
+ */
+ temp_ebp = loc_ebp;
+ loc_ebp = state[4];
+ state[4] = state[3];
+ state[3] = temp_ebp;
+ eax_copy = loc_eax;
+ loc_edx = loc_ebx + 0xbc0;
+ state[5] = loc_ebp;
+ if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff)
+ return -1;
+ loc_ecx = 3;
+ jakas_kopia = temp;
+ loc_eax = temp-1;
+ if (loc_eax >= loc_ecx)
+ loc_eax = loc_ecx;
+ loc_ecx = 0x40;
+ loc_eax <<= 6; /* ecx=0x40, mul cl */
+ loc_ebp8 = loc_ebx + ((loc_eax<<2) + 0x378);
+ if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+ return -1;
+ loc_ebp = loc_eax;
+ if ((loc_eax&0xff) >= 4)
+ {
+ /* loc_4839af */
+ loc_ebp = 2 + (loc_eax&1);
+ loc_eax >>= 1;
+ loc_eax--;
+ temp_ebp = loc_eax; loc_eax = loc_ecx; loc_ecx = temp_ebp;
+ loc_ebp <<= (loc_ecx&0xff);
+ loc_edx = loc_ebx + (loc_ebp<<2) + 0x178;
+ if ((loc_ecx&0xff) > 5)
+ {
+ /* loc_4839c6 */
+ loc_ecx = (loc_ecx&0xffffff00)|(((loc_ecx&0xff)-4)&0xff);
+ loc_eax = 0;
+ do {
+ uint32_t temp_edx;
+ /* compare with lzma_upack_esi_00 */
+ /* do not put in one statment because of difference in signedness */
+ if (!CLI_ISCONTAINED(bs, bl, p.p0, 4))
+ return -1;
+ temp_edx = cli_readint32((char *)p.p0);
+ temp_edx = EC32(CE32(temp_edx));
+ p.p1 >>= 1;
+ temp_edx -= p.p2;
+ loc_eax <<= 1;
+ if (temp_edx >= p.p1)
+ {
+ temp_edx = p.p1;
+ loc_eax++;
+ p.p2 += temp_edx;
+ }
+ if(((p.p1)&0xff000000) == 0)
+ {
+ p.p2 <<= 8;
+ p.p1 <<= 8;
+ p.p0++;
+ }
+ } while (--loc_ecx);
+ /* loc_4839e8 */
+ loc_ecx = (loc_ecx&0xffffff00)|4;
+ loc_eax <<= 4;
+ loc_ebp += loc_eax;
+ loc_edx = loc_ebx + 0x18;
+ }
+ /* loc4839f1 */
+ loc_eax = 1;
+ loc_eax <<= (loc_ecx&0xff);
+ loc_ebp8 = loc_edx;
+ temp_ebp = loc_ecx; loc_ecx = loc_eax; loc_eax = temp_ebp;
+ if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+ return -1;
+ /* cdq, loc_edx = (loc_eax&0x80000000)?0xffffffff:0; */
+ loc_ecx = temp_ebp;
+ temp_ebp = CLI_SRS((int32_t)loc_eax, 31); /* thx, desp */
+ /* loc_483a00 */
+ do {
+ temp_ebp += temp_ebp;
+ temp_ebp += (loc_eax&1);
+ loc_eax >>= 1;
+ } while (--loc_ecx);
+ loc_ebp += temp_ebp;
+ /* loc_483a06 */
+ }
+ /* loc_483a09 */
+ loc_ebp++;
+ loc_ecx = jakas_kopia;
+ } else {
+ /* loc_48393a */
+ loc_edx += loc_ecx;
+ if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+ /* loc_483954 */
+ loc_edx += 0x60;
+ if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+ /* loc_48395e */
+ loc_edx += loc_ecx;
+ ret = lzma_upack_esi_00(&p, loc_edx, bs, bl);
+ temp_ebp = loc_ebp;
+ loc_ebp = state[4];
+ state[4] = state[3];
+ state[3] = temp_ebp;
+ if (ret)
+ {
+ temp_ebp = loc_ebp; loc_ebp = state[5]; state[5] = temp_ebp;
+ }
+ } else {
+ temp_ebp = loc_ebp; loc_ebp = state[3]; state[3] = temp_ebp;
+ }
+ } else {
+ /* loc_483940 */
+ loc_edx += loc_ecx;
+ if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) {
+ } else {
+ /* loc_483946 */
+ loc_eax |= 1;
+ eax_copy = loc_eax;
+ edi_copy = loc_edi;
+ edi_copy -= state[2];
+ loc_ecx = (loc_ecx&0xffffff00)|0x80;
+ if (!CLI_ISCONTAINED(bs, bl, edi_copy, 1) || !CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+ return -1;
+ loc_al = (*(uint8_t *)edi_copy)&0xff;
+ /* loc_483922 */
+ /* ok jmp to 483a19 */
+ /* loc_483a19 */
+ *loc_edi++ = loc_al;
+ continue;
+ }
+ }
+ /* loc_48396a */
+ eax_copy = loc_eax;
+ loc_edx = loc_ebx + 0x778;
+ if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff)
+ return -1;
+ loc_eax = loc_ecx;
+ loc_ecx = temp;
+ }
+ /* loc_483a0b */
+ if (!CLI_ISCONTAINED(bs, bl, loc_edi, loc_ecx) || !CLI_ISCONTAINED(bs, bl, loc_edi-loc_ebp, loc_ecx+1))
+ return -1;
+ state[2] = loc_ebp;
+ for (i=0; i<loc_ecx; i++, loc_edi++)
+ *loc_edi = *(loc_edi - loc_ebp);
+ loc_eax = (loc_eax&0xffffff00)|*(uint8_t *)(loc_edi - loc_ebp);
+ loc_ecx = 0x80;
+ } else {
+ /* loc_4838d8 */
+ do {
+ if ( (loc_al = (loc_eax&0xff)) + 0xfd > 0xff)
+ loc_al -= 3; /* 0x100 - 0xfd = 3 */
+ else
+ loc_al = 0;
+ loc_eax = (loc_eax&0xffffff00)|loc_al;
+ } while (loc_al >= 7);
+ /* loc_4838e2 */
+ eax_copy = loc_eax;
+ if (loc_edi > init_edi && loc_edi < bl+bs)
+ {
+ loc_ebp = (*(uint8_t *)(loc_edi - 1)) >> shlsize;
+ } else {
+ loc_ebp = 0;
+ }
+ loc_ebp *= (int)0x300; /* XXX */
+ loc_ebp8 = loc_ebx + ((loc_ebp<<2) + 0x1008);
+ /* XXX save edi */
+ edi_copy = loc_edi;
+
+ loc_eax = (loc_eax&0xffffff00)|1;
+ if (loc_ecx) {
+ uint8_t loc_cl = loc_ecx&0xff;
+ loc_edi -= state[2];
+ if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+ return -1;
+ do {
+ loc_eax = (loc_eax&0xffff00ff)|((*loc_edi & loc_cl)?0x200:0x100);
+
+ loc_edx = loc_ebp8 + (loc_eax<<2);
+ ret = lzma_upack_esi_00(&p, loc_edx, bs, bl);
+ loc_al = loc_eax&0xff;
+ loc_al += loc_al;
+ loc_al += ret;
+ loc_al &= 0xff;
+ loc_eax = (loc_eax&0xffffff00)|loc_al;
+ loc_cl >>= 1;
+ if (loc_cl) {
+ uint8_t loc_ah = (loc_eax>>8)&0xff;
+ loc_ah -= loc_al;
+ loc_ah &= 1;
+ if (!loc_ah)
+ {
+ loc_eax = (loc_eax&0xffff0000)|(loc_ah<<8)|loc_al;
+ /* loc_483918, loc_48391a */
+ if (lzma_upack_esi_50(&p, loc_eax, 0x100, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+ return -1;
+ break;
+ }
+ } else
+ break;
+ } while(1);
+ } else {
+ /* loc_48391a */
+ loc_ecx = (loc_ecx&0xffff00ff)|0x100;
+ if (lzma_upack_esi_50(&p, loc_eax, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff)
+ return -1;
+ }
+ /* loc_48391f */
+ loc_ecx = 0;
+ loc_edi = edi_copy;
+ }
+ /* loc_483a19 */
+ /* 2GiM: i think this one is not properly checked, 2aCaB: true */
+ if (!CLI_ISCONTAINED(bs, bl, loc_edi, 1))
+ return -1;
+ *loc_edi++ = (loc_eax&0xff);
+ } while (loc_edi < end_edi);
+
+ return 1;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_upx.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+** upxdec.c
+**
+** 05/05/2k4 - 1st attempt
+** 08/05/2k4 - Now works as a charm :D
+** 09/05/2k4 - Moved code outta main(), got rid of globals for thread safety, added bound checking, minor cleaning
+** 04/06/2k4 - Now we handle 2B, 2D and 2E :D
+** 28/08/2k4 - PE rebuild for nested packers
+** 12/12/2k4 - Improved PE rebuild code and added some debug info on failure
+** 23/03/2k7 - New approach for rebuilding:
+ o Get imports via magic
+ o Get imports via leascan
+ o if (!pe) pe=scan4pe();
+ o if (!pe) forgepe();
+*/
+
+/*
+** This code unpacks a dumped UPX1 section to a file.
+** It was written reversing the loader found on some Win32 UPX compressed trojans; while porting
+** it to C i've kinda followed the asm flow so it will probably be a bit hard to read.
+** This code DOES NOT revert the uncompressed section to its original state as no E8/E9 fixup and
+** of cause no IAT rebuild are performed.
+**
+** The Win32 asm unpacker is really a little programming jewel, pretty damn rare in these days of
+** bloatness. My gratitude to whoever wrote it.
+*/
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "upx.h"
+#include "str.h"
+
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
+
+#define HEADERS "\
+\x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\
+\xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00\
+\x0E\x1F\xB4\x09\xBA\x0D\x00\xCD\x21\xB4\x4C\xCD\x21\x54\x68\x69\
+\x73\x20\x66\x69\x6C\x65\x20\x77\x61\x73\x20\x63\x72\x65\x61\x74\
+\x65\x64\x20\x62\x79\x20\x43\x6C\x61\x6D\x41\x56\x20\x66\x6F\x72\
+\x20\x69\x6E\x74\x65\x72\x6E\x61\x6C\x20\x75\x73\x65\x20\x61\x6E\
+\x64\x20\x73\x68\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x62\x65\x20\
+\x72\x75\x6E\x2E\x0D\x0A\x43\x6C\x61\x6D\x41\x56\x20\x2D\x20\x41\
+\x20\x47\x50\x4C\x20\x76\x69\x72\x75\x73\x20\x73\x63\x61\x6E\x6E\
+\x65\x72\x20\x2D\x20\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\
+\x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
+"
+#define FAKEPE "\
+\x50\x45\x00\x00\x4C\x01\x01\x00\x43\x4C\x41\x4D\x00\x00\x00\x00\
+\x00\x00\x00\x00\xE0\x00\x83\x8F\x0B\x01\x00\x00\x00\x10\x00\x00\
+\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\
+\x00\x10\x00\x00\x00\x00\x40\x00\x00\x10\x00\x00\x00\x02\x00\x00\
+\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x0A\x00\x00\x00\x00\x00\
+\xFF\xFF\xFF\xFF\x00\x02\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\
+\x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\
+\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x2e\x63\x6c\x61\x6d\x30\x31\x00\
+\xFF\xFF\xFF\xFF\x00\x10\x00\x00\xFF\xFF\xFF\xFF\x00\x02\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\
+"
+
+static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, unsigned int *sectcnt)
+{
+ char *sections;
+ if (!CLI_ISCONTAINED(dst, dsize, pehdr, 0xf8)) return NULL;
+
+ if (cli_readint32(pehdr) != 0x4550 ) return NULL;
+
+ if (!(*valign=cli_readint32(pehdr+0x38))) return NULL;
+
+ sections = pehdr+0xf8;
+ if (!(*sectcnt = (unsigned char)pehdr[6] + (unsigned char)pehdr[7]*256)) return NULL;
+
+ if (!CLI_ISCONTAINED(dst, dsize, sections, *sectcnt*0x28)) return NULL;
+
+ return sections;
+}
+
+/* PE from UPX */
+
+static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend)
+{
+ char *imports, *sections, *pehdr=NULL, *newbuf;
+ unsigned int sectcnt=0, upd=1;
+ uint32_t realstuffsz=0, valign=0;
+ uint32_t foffset=0xd0+0xf8;
+
+ if((dst == NULL) || (src == NULL))
+ return 0;
+
+ while ((valign=magic[sectcnt++])) {
+ if ( ep - upx1 + valign <= ssize-5 && /* Wondering how we got so far?! */
+ src[ep - upx1 + valign - 2] == '\x8d' && /* lea edi, ... */
+ src[ep - upx1 + valign - 1] == '\xbe' ) /* ... [esi + offset] */
+ break;
+ }
+
+ if (!valign && ep - upx1 + 0x80 < ssize-8) {
+ char *pt = &src[ep - upx1 + 0x80];
+ cli_dbgmsg("UPX: bad magic - scanning for imports\n");
+
+ while ((pt=(char *)cli_memstr(pt, ssize - (pt-src) - 8, "\x8d\xbe", 2))) {
+ if (pt[6] == '\x8b' && pt[7] == '\x07') { /* lea edi, [esi+imports] / mov eax, [edi] */
+ valign=pt-src+2-ep+upx1;
+ break;
+ }
+ pt++;
+ }
+ }
+
+ if (valign && CLI_ISCONTAINED(src, ssize, src + ep - upx1 + valign, 4)) {
+ imports = dst + cli_readint32(src + ep - upx1 + valign);
+
+ realstuffsz = imports-dst;
+
+ if (realstuffsz >= *dsize ) {
+ cli_dbgmsg("UPX: wrong realstuff size\n");
+ /* fallback and eventually craft */
+ } else {
+ pehdr = imports;
+ while (CLI_ISCONTAINED(dst, *dsize, pehdr, 8) && cli_readint32(pehdr)) {
+ pehdr+=8;
+ while(CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr) {
+ pehdr++;
+ while (CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr)
+ pehdr++;
+ pehdr++;
+ }
+ pehdr++;
+ }
+
+ pehdr+=4;
+ if (!(sections=checkpe(dst, *dsize, pehdr, &valign, §cnt))) pehdr=NULL;
+ }
+ }
+
+ if (!pehdr && dend>0xf8+0x28) {
+ cli_dbgmsg("UPX: no luck - scanning for PE\n");
+ pehdr = &dst[dend-0xf8-0x28];
+ while (pehdr>dst) {
+ if ((sections=checkpe(dst, *dsize, pehdr, &valign, §cnt)))
+ break;
+ pehdr--;
+ }
+ if (!(realstuffsz = pehdr-dst)) pehdr=NULL;
+ }
+
+ if (!pehdr) {
+ uint32_t rebsz = PESALIGN(dend, 0x1000);
+ cli_dbgmsg("UPX: no luck - brutally crafing a reasonable PE\n");
+ if (!(newbuf = (char *)cli_calloc(rebsz+0x200, sizeof(char)))) {
+ cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
+ return 0;
+ }
+ memcpy(newbuf, HEADERS, 0xd0);
+ memcpy(newbuf+0xd0, FAKEPE, 0x120);
+ memcpy(newbuf+0x200, dst, dend);
+ memcpy(dst, newbuf, dend+0x200);
+ free(newbuf);
+ cli_writeint32(dst+0xd0+0x50, rebsz+0x1000);
+ cli_writeint32(dst+0xd0+0x100, rebsz);
+ cli_writeint32(dst+0xd0+0x108, rebsz);
+ *dsize=rebsz+0x200;
+ cli_dbgmsg("UPX: PE structure added to uncompressed data\n");
+ return 1;
+ }
+
+ foffset = PESALIGN(foffset+0x28*sectcnt, valign);
+
+ for (upd = 0; upd <sectcnt ; upd++) {
+ uint32_t vsize=PESALIGN((uint32_t)cli_readint32(sections+8), valign);
+ uint32_t urva=PEALIGN((uint32_t)cli_readint32(sections+12), valign);
+
+ /* Within bounds ? */
+ if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) {
+ cli_dbgmsg("UPX: Sect %d out of bounds - giving up rebuild\n", upd);
+ return 0;
+ }
+
+ cli_writeint32(sections+8, vsize);
+ cli_writeint32(sections+12, urva);
+ cli_writeint32(sections+16, vsize);
+ cli_writeint32(sections+20, foffset);
+ foffset+=vsize;
+
+ sections+=0x28;
+ }
+
+ cli_writeint32(pehdr+8, 0x4d414c43);
+ cli_writeint32(pehdr+0x3c, valign);
+
+ if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) {
+ cli_dbgmsg("UPX: malloc failed - giving up rebuild\n");
+ return 0;
+ }
+
+ memcpy(newbuf, HEADERS, 0xd0);
+ memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt);
+ sections = pehdr+0xf8;
+ for (upd = 0; upd <sectcnt ; upd++) {
+ memcpy(newbuf+cli_readint32(sections+20), dst+cli_readint32(sections+12)-upx0, cli_readint32(sections+16));
+ sections+=0x28;
+ }
+
+ /* CBA restoring the imports they'll look different from the originals anyway... */
+ /* ...and yeap i miss the icon too :P */
+
+ if (foffset > *dsize + 8192) {
+ cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n");
+ free(newbuf);
+ return 0;
+ }
+ memcpy(dst, newbuf, foffset);
+ *dsize = foffset;
+ free(newbuf);
+
+ cli_dbgmsg("UPX: PE structure rebuilt from compressed file\n");
+ return 1;
+}
+
+
+/* [doubleebx] */
+
+static int doubleebx(char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize)
+{
+ uint32_t oldebx = *myebx;
+
+ *myebx*=2;
+ if ( !(oldebx & 0x7fffffff)) {
+ if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
+ return -1;
+ oldebx = cli_readint32(src+*scur);
+ *myebx = oldebx*2+1;
+ *scur+=4;
+ }
+ return (oldebx>>31);
+}
+
+/* [inflate] */
+
+int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+ int32_t backbytes, unp_offset = -1;
+ uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x108,0x110,0xd5,0};
+ int oob;
+
+ while (1) {
+ while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
+ if (scur>=ssize || dcur>=*dsize)
+ return -1;
+ dst[dcur++] = src[scur++];
+ }
+
+ if ( oob == -1 )
+ return -1;
+
+ backbytes = 1;
+
+ while (1) {
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backbytes = backbytes*2+oob;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ if (oob)
+ break;
+ }
+
+ backbytes-=3;
+
+ if ( backbytes >= 0 ) {
+
+ if (scur>=ssize)
+ return -1;
+ backbytes<<=8;
+ backbytes+=(unsigned char)(src[scur++]);
+ backbytes^=0xffffffff;
+
+ if (!backbytes)
+ break;
+ unp_offset = backbytes;
+ }
+
+ if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff)
+ return -1;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+ return -1;
+ backsize = backsize*2 + oob;
+ if (!backsize) {
+ backsize++;
+ do {
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+ return -1;
+ backsize = backsize*2 + oob;
+ } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+ if ( oob == -1 )
+ return -1;
+ backsize+=2;
+ }
+
+ if ( (uint32_t)unp_offset < 0xfffff300 )
+ backsize++;
+
+ backsize++;
+
+ if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0)
+ return -1;
+ for (i = 0; i < backsize; i++)
+ dst[dcur + i] = dst[dcur + unp_offset + i];
+ dcur+=backsize;
+ }
+
+ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}
+
+int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+ int32_t backbytes, unp_offset = -1;
+ uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x11c,0x124,0};
+ int oob;
+
+ while (1) {
+ while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 1) {
+ if (scur>=ssize || dcur>=*dsize)
+ return -1;
+ dst[dcur++] = src[scur++];
+ }
+
+ if ( oob == -1 )
+ return -1;
+
+ backbytes = 1;
+
+ while (1) {
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backbytes = backbytes*2+oob;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ if (oob)
+ break;
+ backbytes--;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backbytes=backbytes*2+oob;
+ }
+
+ backsize = 0;
+ backbytes-=3;
+
+ if ( backbytes >= 0 ) {
+
+ if (scur>=ssize)
+ return -1;
+ backbytes<<=8;
+ backbytes+=(unsigned char)(src[scur++]);
+ backbytes^=0xffffffff;
+
+ if (!backbytes)
+ break;
+ backsize = backbytes & 1;
+ CLI_SAR(backbytes,1);
+ unp_offset = backbytes;
+ } else {
+ if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+ return -1;
+ }
+
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backsize = backsize*2 + oob;
+ if (!backsize) {
+ backsize++;
+ do {
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backsize = backsize*2 + oob;
+ } while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+ if ( oob == -1 )
+ return -1;
+ backsize+=2;
+ }
+
+ if ( (uint32_t)unp_offset < 0xfffffb00 )
+ backsize++;
+
+ backsize++;
+ if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
+ return -1;
+ for (i = 0; i < backsize; i++)
+ dst[dcur + i] = dst[dcur + unp_offset + i];
+ dcur+=backsize;
+ }
+
+ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}
+
+int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
+{
+ int32_t backbytes, unp_offset = -1;
+ uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x128,0x130,0};
+ int oob;
+
+ for(;;) {
+ while ( (oob = doubleebx(src, &myebx, &scur, ssize)) ) {
+ if (oob == -1)
+ return -1;
+ if (scur>=ssize || dcur>=*dsize)
+ return -1;
+ dst[dcur++] = src[scur++];
+ }
+
+ backbytes = 1;
+
+ for(;;) {
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backbytes = backbytes*2+oob;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ if ( oob )
+ break;
+ backbytes--;
+ if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
+ return -1;
+ backbytes=backbytes*2+oob;
+ }
+
+ backbytes-=3;
+
+ if ( backbytes >= 0 ) {
+
+ if (scur>=ssize)
+ return -1;
+ backbytes<<=8;
+ backbytes+=(unsigned char)(src[scur++]);
+ backbytes^=0xffffffff;
+
+ if (!backbytes)
+ break;
+ backsize = backbytes & 1; /* Using backsize to carry on the shifted out bit (UPX uses CF) */
+ CLI_SAR(backbytes,1);
+ unp_offset = backbytes;
+ } else {
+ if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+ return -1;
+ } /* Using backsize to carry on the doubleebx result (UPX uses CF) */
+
+ if (backsize) { /* i.e. IF ( last sar shifted out 1 bit || last doubleebx()==1 ) */
+ if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
+ return -1;
+ } else {
+ backsize = 1;
+ if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+ return -1;
+ if (oob) {
+ if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+ return -1;
+ backsize = 2 + oob;
+ } else {
+ do {
+ if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
+ return -1;
+ backsize = backsize * 2 + oob;
+ } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
+ if (oob == -1)
+ return -1;
+ backsize+=2;
+ }
+ }
+
+ if ( (uint32_t)unp_offset < 0xfffffb00 )
+ backsize++;
+
+ backsize+=2;
+
+ if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
+ return -1;
+ for (i = 0; i < backsize; i++)
+ dst[dcur + i] = dst[dcur + unp_offset + i];
+ dcur+=backsize;
+ }
+
+ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_uuencode.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+static char const rcsid[] = "$Id: uuencode.c,v 1.8 2006/12/11 11:55:11 njh Exp $";
+
+#include "clamav.h"
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <memory.h>
+#include <sys/stat.h>
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#include "others.h"
+#include "str.h"
+
+#ifdef C_WINDOWS
+#include <io.h>
+#endif
+
+#include "mbox.h"
+#include "uuencode.h"
+
+/* Maximum line length according to RFC821 */
+#define RFC2821LENGTH 1000
+
+int
+cli_uuencode(const char *dir, int desc)
+{
+ FILE *fin;
+ int i;
+ message *m;
+ char buffer[RFC2821LENGTH + 1];
+
+ i = dup(desc);
+ if((fin = fdopen(i, "rb")) == NULL) {
+ cli_errmsg("Can't open descriptor %d\n", desc);
+ close(i);
+ return CL_EOPEN;
+ }
+ if(fgets(buffer, sizeof(buffer) - 1, fin) == NULL) {
+ /* empty message */
+ fclose(fin);
+ return CL_CLEAN;
+ }
+ if(!isuuencodebegin(buffer)) {
+ fclose(fin);
+ cli_errmsg("Message is not in uuencoded format\n");
+ return CL_EFORMAT;
+ }
+
+ m = messageCreate();
+ if(m == NULL) {
+ fclose(fin);
+ return CL_EMEM;
+ }
+
+ cli_dbgmsg("found uuencode file\n");
+
+ if(uudecodeFile(m, buffer, dir, fin) < 0) {
+ messageDestroy(m);
+ fclose(fin);
+ cli_errmsg("Message is not in uuencoded format\n");
+ return CL_EFORMAT;
+ }
+ messageDestroy(m);
+
+ fclose(fin);
+
+ return CL_CLEAN; /* a lie - but it gets things going */
+}
+
+/*
+ * 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, FILE *fin)
+{
+ 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(fgets(buffer, sizeof(buffer) - 1, fin) != NULL) {
+ 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;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_vba_extract.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1344 @@
+/*
+ * Extract VBA source code for component MS Office Documents
+ *
+ * Copyright (C) 2004-2005 trog at uncon.org
+ *
+ * This code is based on the OpenOffice and libgsf sources.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <zlib.h>
+
+#include "clamav.h"
+
+#include "vba_extract.h"
+#include "others.h"
+#ifdef CL_DEBUG
+#include "mbox.h"
+#endif
+#include "blob.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#define PPT_LZW_BUFFSIZE 8192
+#define NUM_VBA_VERSIONS 14
+#define VBA_COMPRESSION_WINDOW 4096
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+struct vba56_header {
+ unsigned char magic[2];
+ unsigned char version[4];
+ uint16_t ooff __attribute__ ((packed)); /* 0x00FF */
+ uint32_t LidA __attribute__ ((packed)); /* Language identifiers */
+ uint32_t LidB __attribute__ ((packed));
+ uint16_t CharSet __attribute__ ((packed));
+ uint16_t LenA __attribute__ ((packed));
+ uint32_t UnknownB __attribute__ ((packed));
+ uint32_t UnknownC __attribute__ ((packed));
+ uint16_t LenB __attribute__ ((packed));
+ uint16_t LenC __attribute__ ((packed));
+ uint16_t LenD __attribute__ ((packed));
+};
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+typedef struct vba_version_tag {
+ unsigned char signature[4];
+ const char *name;
+ int is_mac;
+} vba_version_t;
+
+static uint16_t vba_endian_convert_16(uint16_t value, int is_mac)
+{
+ if (is_mac)
+ return (uint16_t)be16_to_host(value);
+ else
+ return le16_to_host(value);
+}
+
+static uint32_t vba_endian_convert_32(uint32_t value, int is_mac)
+{
+ if (is_mac)
+ return be32_to_host(value);
+ else
+ return le32_to_host(value);
+}
+
+static const vba_version_t vba_version[NUM_VBA_VERSIONS] = {
+ { { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", FALSE},
+ { { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", FALSE },
+ { { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", FALSE },
+ { { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?", FALSE },
+ { { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000", FALSE },
+ { { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000", FALSE },
+ { { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2", FALSE },
+ { { 0x73, 0x00, 0x00, 0x01 }, "Office XP", FALSE },
+ { { 0x76, 0x00, 0x00, 0x01 }, "Office 2003", FALSE },
+ { { 0x79, 0x00, 0x00, 0x01 }, "Office 2003", FALSE },
+ { { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98", TRUE },
+ { { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001", TRUE },
+ { { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X", TRUE },
+ { { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004", TRUE },
+};
+
+static char *
+get_unicode_name(const char *name, int size, int is_mac)
+{
+ int i, increment;
+ char *newname, *ret;
+
+ if((name == NULL) || (*name == '\0') || (size <= 0))
+ return NULL;
+
+ newname = (char *)cli_malloc(size * 7);
+ if(newname == NULL)
+ return NULL;
+
+ if((!is_mac) && (size & 0x1)) {
+ cli_dbgmsg("get_unicode_name: odd number of bytes %d\n", size);
+ --size;
+ }
+
+ increment = (is_mac) ? 1 : 2;
+ ret = newname;
+
+ for(i = 0; i < size; i += increment) {
+ if(isprint(name[i]))
+ *ret++ = name[i];
+ else {
+ if(name[i] < 10 && name[i] >= 0) {
+ *ret++ = '_';
+ *ret++ = (char)(name[i] + '0');
+ } else {
+ const uint16_t x = (uint16_t)(((name[i]) << 8) | name[i + 1]);
+
+ *ret++ = '_';
+ *ret++ = (char)('a'+((x&0xF)));
+ *ret++ = (char)('a'+((x>>4)&0xF));
+ *ret++ = (char)('a'+((x>>8)&0xF));
+#if 0
+ *ret++ = (char)('a'+((x>>16)&0xF)); /* FIXME: x>>16 MUST == 0 */
+ *ret++ = (char)('a'+((x>>24)&0xF)); /* FIXME: x>>24 MUST == 0 */
+#endif
+ }
+ *ret++ = '_';
+ }
+ }
+
+ *ret = '\0';
+ return newname;
+}
+
+static void vba56_test_middle(int fd)
+{
+ char test_middle[20];
+
+ /* MacOffice middle */
+ static const uint8_t middle1_str[20] = {
+ 0x00, 0x01, 0x0d, 0x45, 0x2e, 0xe1, 0xe0, 0x8f, 0x10, 0x1a,
+ 0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
+ };
+ /* MS Office middle */
+ static const uint8_t middle2_str[20] = {
+ 0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10,
+ 0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
+ };
+
+ if(cli_readn(fd, &test_middle, 20) != 20) {
+ return;
+ }
+
+ if ((memcmp(test_middle, middle1_str, 20) != 0) &&
+ (memcmp(test_middle, middle2_str, 20) != 0)) {
+ cli_dbgmsg("middle not found\n");
+ lseek(fd, -20, SEEK_CUR);
+ } else {
+ cli_dbgmsg("middle found\n");
+ }
+ return;
+}
+
+static int
+vba_read_project_strings(int fd, int is_mac)
+{
+ for (;;) {
+ uint32_t offset;
+ uint16_t length;
+ unsigned char *buff;
+ char *name;
+
+ if (cli_readn(fd, &length, 2) != 2) {
+ return FALSE;
+ }
+ length = vba_endian_convert_16(length, is_mac);
+ if (length < 6) {
+ lseek(fd, -2, SEEK_CUR);
+ break;
+ }
+ buff = (unsigned char *) cli_malloc(length);
+ if (!buff) {
+ cli_errmsg("cli_malloc failed\n");
+ return FALSE;
+ }
+ offset = lseek(fd, 0, SEEK_CUR);
+
+ if (cli_readn(fd, buff, length) != (int)length) {
+ cli_dbgmsg("read name failed - rewinding\n");
+ lseek(fd, offset, SEEK_SET);
+ free(buff);
+ break;
+ }
+ name = get_unicode_name((const char *)buff, length, is_mac);
+ if (name)
+ cli_dbgmsg("length: %d, name: %s\n", length, name);
+ else
+ cli_dbgmsg("length: %d, name: [null]\n", length);
+ free(buff);
+
+ /* Ignore twelve bytes from entries of type 'G'.
+ Type 'C' entries come in pairs, the second also
+ having a 12 byte trailer */
+ /* TODO: Need to check if types H(same as G) and D(same as C) exist */
+ if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
+ (strchr("GCHD", name[2]) == NULL)) {
+ /* Unknown type - probably ran out of strings - rewind */
+ lseek(fd, -(length+2), SEEK_CUR);
+ if(name)
+ free(name);
+ break;
+ }
+ free(name);
+
+ if (cli_readn(fd, &length, 2) != 2)
+ return FALSE;
+
+ length = vba_endian_convert_16(length, is_mac);
+ if ((length != 0) && (length != 65535)) {
+ lseek(fd, -2, SEEK_CUR);
+ continue;
+ }
+ offset = lseek(fd, 10, SEEK_CUR);
+ cli_dbgmsg("offset: %u\n", offset);
+ vba56_test_middle(fd);
+ }
+ return TRUE;
+}
+
+vba_project_t *vba56_dir_read(const char *dir)
+{
+ unsigned char *buff;
+ const unsigned char vba56_signature[] = { 0xcc, 0x61 };
+ uint16_t record_count, length;
+ uint16_t ffff;
+ uint16_t byte_count;
+ uint32_t offset;
+ int i, fd, is_mac;
+ vba_project_t *vba_project;
+ struct vba56_header v56h;
+ char fullname[NAME_MAX + 1];
+
+ cli_dbgmsg("in vba56_dir_read()\n");
+
+ snprintf(fullname, sizeof(fullname) - 1, "%s/_VBA_PROJECT", dir);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+
+ if (fd == -1) {
+ cli_dbgmsg("Can't open %s\n", fullname);
+ /* vba56_old_dir_read(dir); */
+ return NULL;
+ }
+
+ if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
+ close(fd);
+ return NULL;
+ }
+ if (memcmp(v56h.magic, vba56_signature, sizeof(v56h.magic)) != 0) {
+ close(fd);
+ return NULL;
+ }
+
+ for(i = 0; i < NUM_VBA_VERSIONS; i++)
+ if(memcmp(v56h.version, vba_version[i].signature, sizeof(vba_version[i].signature)) == 0)
+ break;
+
+ if (i == NUM_VBA_VERSIONS) {
+ cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
+ v56h.version[0], v56h.version[1],
+ v56h.version[2], v56h.version[3]);
+ switch(v56h.version[3]) {
+ case 0x01:
+ cli_warnmsg("Guessing little-endian\n");
+ is_mac = FALSE;
+ break;
+ case 0x0E:
+ cli_warnmsg("Guessing big-endian\n");
+ is_mac = TRUE;
+ break;
+ default:
+ cli_warnmsg("Unable to guess VBA type\n");
+ close(fd);
+ return NULL;
+ }
+ } else {
+ cli_dbgmsg("VBA Project: %s\n", vba_version[i].name);
+ is_mac = vba_version[i].is_mac;
+ }
+
+ if (!vba_read_project_strings(fd, is_mac)) {
+ close(fd);
+ return NULL;
+ }
+
+ /* junk some more stuff */
+ do {
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ close(fd);
+ return NULL;
+ }
+ } while(ffff != 0xFFFF);
+
+ /* check for alignment error */
+ lseek(fd, -3, SEEK_CUR);
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ close(fd);
+ return NULL;
+ }
+ if (ffff != 0xFFFF) {
+ lseek(fd, 1, SEEK_CUR);
+ }
+
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ close(fd);
+ return NULL;
+ }
+
+ /* no idea what this stuff is */
+ if (ffff != 0xFFFF) {
+ ffff = vba_endian_convert_16(ffff, is_mac);
+ lseek(fd, ffff, SEEK_CUR);
+ }
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ close(fd);
+ return NULL;
+ }
+ if (ffff != 0xFFFF) {
+ ffff = vba_endian_convert_16(ffff, is_mac);
+ lseek(fd, ffff, SEEK_CUR);
+ }
+ lseek(fd, 100, SEEK_CUR);
+
+ if (cli_readn(fd, &record_count, 2) != 2) {
+ close(fd);
+ return NULL;
+ }
+ record_count = vba_endian_convert_16(record_count, is_mac);
+ cli_dbgmsg("\nVBA Record count: %d\n", record_count);
+ if (record_count == 0) {
+ close(fd);
+ return NULL;
+ }
+ if (record_count > 1000) {
+ /* Almost certainly an error */
+ cli_dbgmsg("\nVBA Record count too big");
+ close(fd);
+ return NULL;
+ }
+
+ vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+ if (!vba_project) {
+ close(fd);
+ return NULL;
+ }
+ vba_project->name = (char **) cli_malloc(sizeof(char *) * record_count);
+ if (!vba_project->name) {
+ free(vba_project);
+ close(fd);
+ return NULL;
+ }
+ vba_project->dir = cli_strdup(dir);
+ vba_project->offset = (uint32_t *) cli_malloc (sizeof(uint32_t) *
+ record_count);
+ if (!vba_project->offset) {
+ free(vba_project->dir);
+ free(vba_project->name);
+ free(vba_project);
+ close(fd);
+ return NULL;
+ }
+ vba_project->count = record_count;
+ for(i = 0; i < record_count; i++) {
+ if(cli_readn(fd, &length, 2) != 2)
+ break;
+
+ length = vba_endian_convert_16(length, is_mac);
+ if (length == 0) {
+ cli_dbgmsg("zero name length\n");
+ break;
+ }
+ buff = (unsigned char *) cli_malloc(length);
+ if (!buff) {
+ cli_dbgmsg("cli_malloc failed\n");
+ break;
+ }
+ if (cli_readn(fd, buff, length) != length) {
+ cli_dbgmsg("read name failed\n");
+ free(buff);
+ break;
+ }
+ vba_project->name[i] = get_unicode_name((const char *)buff, length, is_mac);
+ free(buff);
+ if (!vba_project->name[i]) {
+ offset = lseek(fd, 0, SEEK_CUR);
+ vba_project->name[i] = (char *) cli_malloc(18);
+ if(vba_project->name[i] == NULL) {
+ break;
+ }
+ snprintf(vba_project->name[i], 18, "clamav-%.10d", (int)offset);
+ }
+ cli_dbgmsg("project name: %s, ", vba_project->name[i]);
+
+ /* some kind of string identifier ?? */
+ if (cli_readn(fd, &length, 2) != 2) {
+ free(vba_project->name[i]);
+ break;
+ }
+ length = vba_endian_convert_16(length, is_mac);
+ lseek(fd, length, SEEK_CUR);
+
+ /* unknown stuff */
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ free(vba_project->name[i]);
+ break;
+ }
+ ffff = vba_endian_convert_16(ffff, is_mac);
+ if (ffff == 0xFFFF) {
+ lseek(fd, 2, SEEK_CUR);
+ if (cli_readn(fd, &ffff, 2) != 2) {
+ free(vba_project->name[i]);
+ break;
+ }
+ ffff = vba_endian_convert_16(ffff, is_mac);
+ lseek(fd, ffff, SEEK_CUR);
+ } else {
+ lseek(fd, 2 + ffff, SEEK_CUR);
+ }
+
+ lseek(fd, 8, SEEK_CUR);
+ if (cli_readn(fd, &byte_count, 2) != 2) {
+ free(vba_project->name[i]);
+ break;
+ }
+ byte_count = vba_endian_convert_16(byte_count, is_mac);
+ lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
+ if (cli_readn(fd, &offset, 4) != 4) {
+ free(vba_project->name[i]);
+ break;
+ }
+ offset = vba_endian_convert_32(offset, is_mac);
+ vba_project->offset[i] = offset;
+ cli_dbgmsg("offset:%u\n", offset);
+ lseek(fd, 2, SEEK_CUR);
+ }
+
+ close(fd);
+
+ if(i < record_count) {
+ /* above loop failed */
+ while(--i >= 0)
+ free(vba_project->name[i]);
+
+ free(vba_project->name);
+ free(vba_project->dir);
+ free(vba_project->offset);
+ free(vba_project);
+ return NULL;
+ }
+
+ return vba_project;
+}
+
+unsigned char *vba_decompress(int fd, uint32_t offset, int *size)
+{
+ unsigned int i, pos=0, shift, win_pos, clean=TRUE, mask, distance;
+ uint8_t flag;
+ uint16_t token, len;
+ size_t s;
+ blob *b;
+ unsigned char *ret;
+ unsigned char buffer[VBA_COMPRESSION_WINDOW];
+
+ b = blobCreate();
+
+ if(b == NULL)
+ return NULL;
+
+ lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */
+
+ while (cli_readn(fd, &flag, 1) == 1) {
+ for (mask = 1; mask < 0x100; mask<<=1) {
+ if (flag & mask) {
+ if (cli_readn(fd, &token, 2) != 2) {
+ blobDestroy(b);
+ if (size) {
+ *size = 0;
+ }
+ return NULL;
+ }
+ token = vba_endian_convert_16(token, FALSE);
+ win_pos = pos % VBA_COMPRESSION_WINDOW;
+ if (win_pos <= 0x80) {
+ if (win_pos <= 0x20) {
+ shift = (win_pos <= 0x10) ? 12:11;
+ } else {
+ shift = (win_pos <= 0x40) ? 10:9;
+ }
+ } else {
+ if (win_pos <= 0x200) {
+ shift = (win_pos <= 0x100) ? 8:7;
+ } else if (win_pos <= 0x800) {
+ shift = (win_pos <= 0x400) ? 6:5;
+ } else {
+ shift = 4;
+ }
+ }
+ len = (uint16_t)((token & ((1 << shift) -1)) + 3);
+ distance = token >> shift;
+ clean = TRUE;
+
+ for (i=0 ; i < len; i++) {
+ unsigned int srcpos;
+ unsigned char c;
+
+ srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
+ c = buffer[srcpos];
+ buffer[pos++ % VBA_COMPRESSION_WINDOW]= c;
+ }
+ } else {
+ if ((pos != 0) &&
+ ((pos % VBA_COMPRESSION_WINDOW) == 0) && clean) {
+
+ if (cli_readn(fd, &token, 2) != 2) {
+ blobDestroy(b);
+ if(size)
+ *size = 0;
+ return NULL;
+ }
+ clean = FALSE;
+ (void)blobAddData(b, buffer, VBA_COMPRESSION_WINDOW);
+ break;
+ }
+ if (cli_readn(fd, buffer+(pos%VBA_COMPRESSION_WINDOW), 1) == 1){
+ pos++;
+ }
+ clean = TRUE;
+ }
+ }
+ }
+
+ if (pos % VBA_COMPRESSION_WINDOW)
+ if(blobAddData(b, buffer, pos%VBA_COMPRESSION_WINDOW) < 0) {
+ if(size)
+ *size = 0;
+ blobDestroy(b);
+ return NULL;
+ }
+ s = blobGetDataSize(b);
+ ret = cli_malloc(s);
+ if(ret == NULL) {
+ blobDestroy(b);
+ if(size)
+ *size = 0;
+ return NULL;
+ }
+ if(size)
+ *size = (int)s;
+ memcpy(ret, blobGetData(b), s);
+ blobDestroy(b);
+ return ret;
+}
+
+static uint32_t ole_copy_file_data(int ifd, int ofd, uint32_t len)
+{
+ unsigned int count, rem;
+ unsigned char data[FILEBUFF];
+
+ rem = len;
+
+ while (rem > 0) {
+ unsigned int todo = MIN(sizeof(data), rem);
+
+ count = cli_readn(ifd, data, todo);
+ if (count != todo) {
+ return len-rem;
+ }
+ if((unsigned int)cli_writen(ofd, data, count) != count)
+ return len-rem-count;
+ rem -= count;
+ }
+ return len;
+}
+
+int cli_decode_ole_object(int fd, const char *dir)
+{
+ int ofd;
+ struct stat statbuf;
+ char ch;
+ uint32_t object_size;
+ char fullname[NAME_MAX + 1];
+
+ if (fstat(fd, &statbuf) == -1) {
+ return -1;
+ }
+
+ if (cli_readn(fd, &object_size, 4) != 4) {
+ return -1;
+ }
+ object_size = vba_endian_convert_32(object_size, FALSE);
+
+ if ((statbuf.st_size - object_size) >= 4) {
+ /* Probably the OLE type id */
+ if (lseek(fd, 2, SEEK_CUR) == -1) {
+ return -1;
+ }
+
+ /* Skip attachment name */
+ do {
+ if (cli_readn(fd, &ch, 1) != 1) {
+ return -1;
+ }
+ } while (ch);
+
+ /* Skip attachment full path */
+ do {
+ if (cli_readn(fd, &ch, 1) != 1) {
+ return -1;
+ }
+ } while (ch);
+
+ /* Skip unknown data */
+ if (lseek(fd, 8, SEEK_CUR) == -1) {
+ return -1;
+ }
+
+ /* Skip attachment full path */
+ do {
+ if (cli_readn(fd, &ch, 1) != 1) {
+ return -1;
+ }
+ } while (ch);
+
+ if (cli_readn(fd, &object_size, 4) != 4) {
+ return -1;
+ }
+ object_size = vba_endian_convert_32(object_size, FALSE);
+ }
+ snprintf(fullname, sizeof(fullname) - 1, "%s/_clam_ole_object", dir);
+ ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
+ if (ofd < 0) {
+ return -1;
+ }
+ ole_copy_file_data(fd, ofd, object_size);
+ lseek(ofd, 0, SEEK_SET);
+ return ofd;
+}
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/* Code to extract Power Point Embedded OLE2 Objects */
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+
+typedef struct atom_header_tag {
+ off_t foffset;
+ uint16_t ver_inst;
+ uint8_t version;
+ uint16_t instance;
+ uint16_t type;
+ uint32_t length;
+} atom_header_t;
+
+static int ppt_read_atom_header(int fd, atom_header_t *atom_header)
+{
+ atom_header->foffset = lseek(fd, 0, SEEK_CUR);
+ if (cli_readn(fd, &atom_header->ver_inst, 2) != 2) {
+ cli_dbgmsg("read ppt_current_user failed\n");
+ return FALSE;
+ }
+ atom_header->ver_inst = vba_endian_convert_16(atom_header->ver_inst, FALSE);
+ atom_header->version = (uint8_t)(atom_header->ver_inst & 0x000f);
+ atom_header->instance = (uint16_t)(atom_header->ver_inst >> 4);
+ if(cli_readn(fd, &atom_header->type, sizeof(uint16_t)) != sizeof(uint16_t)) {
+ cli_dbgmsg("read ppt_current_user failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, &atom_header->length, 4) != 4) {
+ cli_dbgmsg("read ppt_current_user failed\n");
+ return FALSE;
+ }
+ atom_header->type = vba_endian_convert_16(atom_header->type, FALSE);
+ atom_header->length = vba_endian_convert_32(atom_header->length, FALSE);
+ return TRUE;
+}
+
+static void ppt_print_atom_header(atom_header_t *atom_header)
+{
+ cli_dbgmsg("Atom Hdr:\n");
+ cli_dbgmsg(" Version: 0x%.2x\n", atom_header->version);
+ cli_dbgmsg(" Instance: 0x%.4x\n", atom_header->instance);
+ cli_dbgmsg(" Type: 0x%.4x\n", atom_header->type);
+ cli_dbgmsg(" Length: 0x%.8x\n", atom_header->length);
+}
+
+static int ppt_unlzw(const char *dir, int fd, uint32_t length)
+{
+ int ofd, retval;
+ unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
+ uint32_t bufflen;
+ z_stream stream;
+ char fullname[NAME_MAX + 1];
+
+ snprintf(fullname, sizeof(fullname) - 1, "%s/ppt%.8lx.doc",
+ dir, (long)lseek(fd, 0L, SEEK_CUR));
+
+ ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
+ if (ofd == -1) {
+ cli_dbgmsg("ppt_unlzw Open outfile failed\n");
+ return FALSE;
+ }
+
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = (void *)0;
+
+ stream.next_in = inbuff;
+ bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
+
+ if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
+ close(ofd);
+ unlink(fullname);
+ return FALSE;
+ }
+ length -= stream.avail_in;
+
+ retval = inflateInit(&stream);
+ if (retval != Z_OK) {
+ cli_dbgmsg(" ppt_unlzw !Z_OK: %d\n", retval);
+ }
+
+ stream.next_out = outbuff;
+ stream.avail_out = PPT_LZW_BUFFSIZE;
+
+ do {
+ if (stream.avail_out == 0) {
+ if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE)
+ != PPT_LZW_BUFFSIZE) {
+ close(ofd);
+ inflateEnd(&stream);
+ return FALSE;
+ }
+ stream.next_out = outbuff;
+ stream.avail_out = PPT_LZW_BUFFSIZE;
+ }
+ if (stream.avail_in == 0) {
+ stream.next_in = inbuff;
+ bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
+ if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
+ close(ofd);
+ inflateEnd(&stream);
+ return FALSE;
+ }
+ length -= stream.avail_in;
+ }
+ retval = inflate(&stream, Z_NO_FLUSH);
+ } while (retval == Z_OK);
+
+ if (cli_writen(ofd, outbuff, bufflen) != (int64_t)bufflen) {
+ close(ofd);
+ inflateEnd(&stream);
+ return FALSE;
+ }
+ inflateEnd(&stream);
+ return close(ofd);
+}
+
+static char *ppt_stream_iter(int fd)
+{
+ uint32_t ole_id;
+ char *out_dir;
+ off_t offset;
+ atom_header_t atom_header;
+
+ /* Create a directory to store the extracted OLE2 objects */
+ out_dir = cli_gentemp(NULL);
+ if(mkdir(out_dir, 0700)) {
+ cli_errmsg("ScanOLE2 -> Can't create temporary directory %s\n", out_dir);
+ free(out_dir);
+ return NULL;
+ }
+
+ while(ppt_read_atom_header(fd, &atom_header)) {
+ ppt_print_atom_header(&atom_header);
+
+ if (atom_header.length == 0) {
+ cli_rmdirs(out_dir);
+ free(out_dir);
+ return NULL;
+ }
+
+ if (atom_header.type == 0x1011) {
+ if (cli_readn(fd, &ole_id, 4) != 4) {
+ cli_dbgmsg("read ole_id failed\n");
+ cli_rmdirs(out_dir);
+ free(out_dir);
+ return NULL;
+ }
+ ole_id = vba_endian_convert_32(ole_id, FALSE);
+ cli_dbgmsg("OleID: %d, length: %d\n",
+ (int)ole_id, (int)atom_header.length-4);
+ if (!ppt_unlzw(out_dir, fd, atom_header.length-4)) {
+ cli_dbgmsg("ppt_unlzw failed\n");
+ cli_rmdirs(out_dir);
+ free(out_dir);
+ return NULL;
+ }
+
+ } else {
+ offset = lseek(fd, 0, SEEK_CUR);
+ /* Check we don't wrap */
+ if ((offset + (off_t)atom_header.length) < offset) {
+ break;
+ }
+ offset += atom_header.length;
+ if (lseek(fd, offset, SEEK_SET) != offset ) {
+ break;
+ }
+ }
+ }
+ return out_dir;
+}
+
+char *ppt_vba_read(const char *dir)
+{
+ char *out_dir;
+ int fd;
+ char fullname[NAME_MAX + 1];
+
+ snprintf(fullname, sizeof(fullname) - 1, "%s/PowerPoint Document", dir);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if (fd == -1) {
+ cli_dbgmsg("Open PowerPoint Document failed\n");
+ return NULL;
+ }
+
+ out_dir = ppt_stream_iter(fd);
+ close(fd);
+ return out_dir;
+}
+
+
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/* Code to extract Word6 macros */
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+
+typedef struct mso_fib_tag {
+ char ununsed[sizeof(uint16_t) + sizeof(uint16_t) +
+ sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) +
+ sizeof(uint16_t)];
+ uint32_t macro_offset;
+ uint32_t macro_len;
+} mso_fib_t;
+
+typedef struct macro_entry_tag {
+ unsigned char version;
+ unsigned char key;
+ uint16_t intname_i;
+ uint16_t extname_i;
+ uint16_t xname_i;
+ uint32_t unknown;
+ uint32_t len;
+ uint32_t state;
+ uint32_t offset;
+} macro_entry_t;
+
+typedef struct macro_info_tag {
+ uint16_t count;
+ struct macro_entry_tag *macro_entry;
+} macro_info_t;
+
+static void wm_free_macro_info(macro_info_t *macro_info);
+
+static void wm_print_fib(mso_fib_t *fib)
+{
+ cli_dbgmsg("macro offset: 0x%.4x\n", fib->macro_offset);
+ cli_dbgmsg("macro len: 0x%.4x\n\n", fib->macro_len);
+}
+
+static int wm_read_fib(int fd, mso_fib_t *fib)
+{
+ /* don't need the information is this block, so seek forward */
+ if (lseek(fd, 0x118, SEEK_SET) != 0x118) {
+ cli_dbgmsg("lseek wm_fib failed\n");
+ return FALSE;
+ }
+
+ if (cli_readn(fd, &fib->macro_offset, 4) != 4) {
+ cli_dbgmsg("read wm_fib failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, &fib->macro_len, 4) != 4) {
+ cli_dbgmsg("read wm_fib failed\n");
+ return FALSE;
+ }
+ fib->macro_offset = vba_endian_convert_32(fib->macro_offset, FALSE);
+ fib->macro_len = vba_endian_convert_32(fib->macro_len, FALSE);
+
+ return TRUE;
+}
+
+static int wm_read_macro_entry(int fd, macro_entry_t *macro_entry)
+{
+ if (cli_readn(fd, ¯o_entry->version, 1) != 1) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->key, 1) != 1) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->intname_i, 2) != 2) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->extname_i, 2) != 2) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->xname_i, 2) != 2) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->unknown, 4) != 4) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->len, 4) != 4) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->state, 4) != 4) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+ if (cli_readn(fd, ¯o_entry->offset, 4) != 4) {
+ cli_dbgmsg("read macro_entry failed\n");
+ return FALSE;
+ }
+
+ macro_entry->intname_i = vba_endian_convert_16(macro_entry->intname_i, FALSE);
+ macro_entry->extname_i = vba_endian_convert_16(macro_entry->extname_i, FALSE);
+ macro_entry->xname_i = vba_endian_convert_16(macro_entry->xname_i, FALSE);
+ macro_entry->len = vba_endian_convert_32(macro_entry->len, FALSE);
+ macro_entry->state = vba_endian_convert_32(macro_entry->state, FALSE);
+ macro_entry->offset = vba_endian_convert_32(macro_entry->offset, FALSE);
+ return TRUE;
+}
+
+static macro_info_t *wm_read_macro_info(int fd)
+{
+ int i;
+ macro_info_t *macro_info;
+
+ macro_info = (macro_info_t *) cli_malloc(sizeof(macro_info_t));
+ if (!macro_info) {
+ return NULL;
+ }
+ if (cli_readn(fd, ¯o_info->count, 2) != 2) {
+ cli_dbgmsg("read macro_info failed\n");
+ free(macro_info);
+ return NULL;
+ }
+ macro_info->count = vba_endian_convert_16(macro_info->count, FALSE);
+ cli_dbgmsg("macro count: %d\n", macro_info->count);
+ macro_info->macro_entry = (macro_entry_t *)
+ cli_malloc(sizeof(macro_entry_t) * macro_info->count);
+ if (!macro_info->macro_entry) {
+ free(macro_info);
+ return NULL;
+ }
+ for (i=0 ; i < macro_info->count ; i++) {
+ if (!wm_read_macro_entry(fd,
+ ¯o_info->macro_entry[i])) {
+ wm_free_macro_info(macro_info);
+ return NULL;
+ }
+ }
+ return macro_info;
+}
+
+static void
+wm_free_macro_info(macro_info_t *macro_info)
+{
+ if (macro_info) {
+ free(macro_info->macro_entry);
+ free(macro_info);
+ }
+}
+
+static int wm_read_oxo3(int fd)
+{
+ uint8_t count;
+
+ if (cli_readn(fd, &count, 1) != 1) {
+ cli_dbgmsg("read oxo3 record1 failed\n");
+ return FALSE;
+ }
+ if (lseek(fd, count*14, SEEK_CUR) == -1) {
+ cli_dbgmsg("lseek oxo3 record1 failed\n");
+ return FALSE;
+ }
+ cli_dbgmsg("oxo3 records1: %d\n", count);
+
+ if (cli_readn(fd, &count, 1) != 1) {
+ cli_dbgmsg("read oxo3 record2 failed\n");
+ return FALSE;
+ }
+ if (count == 0) {
+ if (cli_readn(fd, &count, 1) != 1) {
+ cli_dbgmsg("read oxo3 failed\n");
+ return FALSE;
+ }
+ if (count != 2) {
+ lseek(fd, -1, SEEK_CUR);
+ return TRUE;
+ }
+ if (cli_readn(fd, &count, 1) != 1) {
+ cli_dbgmsg("read oxo3 failed\n");
+ return FALSE;
+ }
+ }
+ if (count > 0) {
+ if (lseek(fd, (count*4)+1, SEEK_CUR) == -1) {
+ cli_dbgmsg("lseek oxo3 failed\n");
+ return FALSE;
+ }
+ }
+ cli_dbgmsg("oxo3 records2: %d\n", count);
+ return TRUE;
+}
+
+static int
+wm_skip_menu_info(int fd)
+{
+ uint16_t count;
+
+ if (cli_readn(fd, &count, sizeof(uint16_t)) != sizeof(uint16_t)) {
+ cli_dbgmsg("read menu_info failed\n");
+ return FALSE;
+ }
+ count = vba_endian_convert_16(count, FALSE);
+ cli_dbgmsg("menu_info count: %d\n", count);
+
+ if(count)
+ if(lseek(fd, count * 12, SEEK_CUR) == -1)
+ return FALSE;
+ return TRUE;
+}
+
+static int
+wm_skip_macro_extnames(int fd)
+{
+ int is_unicode;
+ int16_t size;
+ off_t offset_end = lseek(fd, 0, SEEK_CUR);
+
+ if(cli_readn(fd, &size, sizeof(int16_t)) != sizeof(int16_t)) {
+ cli_dbgmsg("read macro_extnames failed\n");
+ return FALSE;
+ }
+ size = vba_endian_convert_16(size, FALSE);
+ if (size == -1) { /* Unicode flag */
+ if(cli_readn(fd, &size, sizeof(int16_t)) != sizeof(int16_t)) {
+ cli_dbgmsg("read macro_extnames failed\n");
+ return FALSE;
+ }
+ size = vba_endian_convert_16(size, FALSE);
+ is_unicode = 1;
+ } else
+ is_unicode = 0;
+
+ cli_dbgmsg("ext names size: 0x%x\n", size);
+
+ offset_end += size;
+ while(lseek(fd, 0, SEEK_CUR) < offset_end) {
+ uint8_t length;
+ off_t offset;
+
+ if (cli_readn(fd, &length, 1) != 1) {
+ cli_dbgmsg("read macro_extnames failed\n");
+ return FALSE;
+ }
+
+ if(is_unicode)
+ offset = (off_t)length * 2 + 1;
+ else
+ offset = (off_t)length;
+
+ offset += sizeof(uint16_t); /* numref */
+ if(lseek(fd, offset, SEEK_CUR) == -1) {
+ cli_dbgmsg("read macro_extnames failed to seek\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int
+wm_skip_macro_intnames(int fd)
+{
+ uint16_t i, count;
+
+ if (cli_readn(fd, &count, sizeof(uint16_t)) != sizeof(uint16_t)) {
+ cli_dbgmsg("read macro_intnames failed\n");
+ return FALSE;
+ }
+ count = vba_endian_convert_16(count, FALSE);
+ cli_dbgmsg("int names count: %u\n", count);
+
+ for(i = 0; i < count; i++) {
+ uint8_t length;
+
+ /* id */
+ if(lseek(fd, sizeof(uint16_t), SEEK_CUR) == -1) {
+ cli_dbgmsg("skip_macro_intnames failed\n");
+ return FALSE;
+ }
+
+ if(cli_readn(fd, &length, sizeof(uint8_t)) != sizeof(uint8_t)) {
+ cli_dbgmsg("skip_macro_intnames failed\n");
+ return FALSE;
+ }
+
+ /* Internal name, plus one byte of unknown data */
+ if(lseek(fd, length + 1, SEEK_CUR) == -1) {
+ cli_dbgmsg("skip_macro_intnames failed\n");
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+vba_project_t *wm_dir_read(const char *dir)
+{
+ int fd, done;
+ off_t end_offset;
+ unsigned char info_id;
+ macro_info_t *macro_info=NULL;
+ vba_project_t *vba_project;
+ mso_fib_t fib;
+ char fullname[NAME_MAX + 1];
+
+ snprintf(fullname, sizeof(fullname) - 1, "%s/WordDocument", dir);
+ fd = open(fullname, O_RDONLY|O_BINARY);
+ if (fd == -1) {
+ cli_dbgmsg("Open WordDocument failed\n");
+ return NULL;
+ }
+
+ if (!wm_read_fib(fd, &fib)) {
+ close(fd);
+ return NULL;
+ }
+ if(fib.macro_len == 0) {
+ cli_dbgmsg("No macros detected\n");
+ /* Must be clean */
+ close(fd);
+ return NULL;
+ }
+ wm_print_fib(&fib);
+
+ /* Go one past the start to ignore start_id */
+ if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
+ cli_dbgmsg("lseek macro_offset failed\n");
+ close(fd);
+ return NULL;
+ }
+
+ end_offset = fib.macro_offset + fib.macro_len;
+ done = FALSE;
+
+ while ((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
+ if (cli_readn(fd, &info_id, 1) != 1) {
+ cli_dbgmsg("read macro_info failed\n");
+ close(fd);
+ return NULL;
+ }
+ switch (info_id) {
+ case 0x01:
+ if(macro_info)
+ wm_free_macro_info(macro_info);
+ macro_info = wm_read_macro_info(fd);
+ if(macro_info == NULL)
+ done = TRUE;
+ break;
+ case 0x03:
+ if(!wm_read_oxo3(fd))
+ done = TRUE;
+ break;
+ case 0x05:
+ if(!wm_skip_menu_info(fd))
+ done = TRUE;
+ break;
+ case 0x10:
+ if(!wm_skip_macro_extnames(fd))
+ done = TRUE;
+ break;
+ case 0x11:
+ if(!wm_skip_macro_intnames(fd))
+ done = TRUE;
+ break;
+ case 0x12:
+ /* No sure about these, always seems to
+ come after the macros though, so finish
+ */
+ done = TRUE;
+ break;
+ case 0x40:
+ /* end marker */
+ done = TRUE;
+ break;
+ default:
+ cli_dbgmsg("unknown type: 0x%x\n", info_id);
+ done = TRUE;
+ }
+ }
+
+ close(fd);
+
+ if (macro_info) {
+ vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+ if (!vba_project) {
+ goto abort;
+ }
+ vba_project->name = (char **) cli_malloc(sizeof(char *) *macro_info->count);
+ if (!vba_project->name) {
+ free(vba_project);
+ vba_project = NULL;
+ goto abort;
+ }
+ vba_project->dir = cli_strdup(dir);
+ vba_project->offset = (uint32_t *) cli_malloc(sizeof(uint32_t) *
+ macro_info->count);
+ if (!vba_project->offset) {
+ free(vba_project->name);
+ if(vba_project->dir)
+ free(vba_project->dir);
+ free(vba_project);
+ vba_project = NULL;
+ goto abort;
+ }
+ vba_project->length = (uint32_t *) cli_malloc(sizeof(uint32_t) *
+ macro_info->count);
+ if (!vba_project->length) {
+ free(vba_project->offset);
+ free(vba_project->name);
+ free(vba_project->dir);
+ free(vba_project);
+ vba_project = NULL;
+ goto abort;
+ }
+ vba_project->key = (unsigned char *) cli_malloc(sizeof(unsigned char) *
+ macro_info->count);
+ if (!vba_project->key) {
+ free(vba_project->length);
+ free(vba_project->offset);
+ free(vba_project->name);
+ free(vba_project->dir);
+ free(vba_project);
+ vba_project = NULL;
+ } else {
+ int i;
+
+ vba_project->count = macro_info->count;
+ for(i = 0; i < macro_info->count; i++) {
+ vba_project->name[i] = cli_strdup("WordDocument");
+ vba_project->offset[i] = macro_info->macro_entry[i].offset;
+ vba_project->length[i] = macro_info->macro_entry[i].len;
+ vba_project->key[i] = macro_info->macro_entry[i].key;
+ }
+ }
+abort:
+ wm_free_macro_info(macro_info);
+ /* Fall through */
+ } else
+ vba_project = NULL;
+
+ return vba_project;
+}
+
+unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
+ unsigned char key)
+{
+ unsigned char *buff;
+ uint32_t i;
+
+ if (lseek(fd, offset, SEEK_SET) != (int64_t)offset) {
+ return NULL;
+ }
+ buff = (unsigned char *) cli_malloc(len);
+ if (!buff) {
+ return NULL;
+ }
+
+ if (cli_readn(fd, buff, len) != (int)len) {
+ free(buff);
+ return NULL;
+ }
+ if (key != 0)
+ for (i=0 ; i < len; i++)
+ buff[i] ^= key;
+ return buff;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_wwunpack.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by aCaB <acab at clamav.net>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+** wwunpack.c
+**
+** 09/07/2k6 - Campioni del mondo!!!
+** 14/07/2k6 - RCE'ed + standalone sect unpacker
+** 15/07/2k6 - Merge started
+** 17/07/2k6 - Rebuild
+** 18/07/2k6 - Secured (well, hopefully...)
+**
+*/
+
+/*
+** Unpacks+rebuilds WWPack32 1.20
+**
+** Just boooooring stuff, blah.
+**
+*/
+
+
+/*
+** TODO:
+**
+** review
+** check eax vs al
+** (check for dll's)
+** (have a look at older versions)
+**
+*/
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "others.h"
+#include "wwunpack.h"
+
+#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000)
+#define FIXVS(v, r) (VAALIGN((r>v)?r:v))
+
+
+static int getbitmap(uint32_t *bitmap, char **src, uint8_t *bits, char *buf, unsigned int size) {
+ if (! CLI_ISCONTAINED(buf, size, *src, 4)) return 1;
+ *bitmap=cli_readint32(*src);
+ *src+=4;
+ *bits=32;
+ return 0;
+}
+
+static int getbits(uint8_t X, uint32_t *eax, uint32_t *bitmap, uint8_t *bits, char **src, char *buf, unsigned int size) {
+ *eax=*bitmap>>(32-X);
+ if (*bits>X) {
+ *bitmap<<=X;
+ *bits-=X;
+ } else if (*bits<X) {
+ X-=*bits;
+ *eax>>=X;
+ if (getbitmap(bitmap, src, bits, buf, size)) return 1;
+ *eax<<=X;
+ *eax|=*bitmap>>(32-X);
+ *bitmap<<=X;
+ *bits-=X;
+ } else {
+ if (getbitmap(bitmap, src, bits, buf, size)) return 1;
+ }
+ return 0;
+}
+
+static int wunpsect(char *packed, char *unpacked, unsigned int psize, unsigned int usize) {
+ char *src=packed, *dst=unpacked;
+ uint32_t bitmap, eax;
+ uint8_t bits;
+ unsigned int lostbit, getmorestuff;
+ uint16_t backbytes;
+ uint16_t backsize;
+ uint8_t oal;
+
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ eax=bitmap;
+
+ while (1) {
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!lostbit && bits) {
+ if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
+ *dst++=*src++;
+ continue;
+ }
+
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ eax=bitmap;
+ if (!lostbit) {
+ if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
+ *dst++=*src++;
+ continue;
+ }
+ }
+
+ if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+
+ if ((eax&0xff)>=3) {
+ /* 50ff - two_bytes */
+ uint8_t fetchbits;
+
+ if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ fetchbits=(eax&0xff)+5;
+ eax--;
+ if ((int16_t)(eax&0xffff)<=0) {
+ /* 5113 */
+ backbytes=1<<fetchbits;
+ backbytes=(backbytes&0xff00)|((backbytes-31)&0xff);
+ } else {
+ /* 511b */
+ fetchbits++;
+ backbytes=1<<fetchbits;
+ backbytes-=0x9f;
+ }
+ /* 5125 */
+ if (getbits(fetchbits, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ if ((eax&0xffff)==0x1ff) break;
+ eax&=0xffff;
+ backbytes+=eax;
+ if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, 2) && CLI_ISCONTAINED(unpacked, usize, dst, 2))) return 1;
+ *dst=*(dst-backbytes);
+ dst++;
+ *dst=*(dst-backbytes);
+ dst++;
+ continue;
+ }
+
+ /* 5143 - more_backbytes */
+ oal=eax&0xff;
+ getmorestuff=1;
+
+
+ if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ if ((eax&0xff)<=3) {
+ lostbit=0;
+ if ((eax&0xff)==3) {
+ /* next_bit_or_reseed */
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ }
+ }
+ eax=eax+lostbit+5;
+ /* jmp more_bb_commondock */
+ } else { /* >3 */
+ /* 5160 - more_bb_morethan3 */
+ if ((eax&0xff)==4) {
+ /* next_bit_or_reseed */
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ }
+ eax=eax+lostbit+6;
+ /* jmp more_bb_commondock */
+ } else { /* !=4 */
+ eax+=7;
+ if ((eax&0xff)>=0x0d) {
+ getmorestuff=0; /* jmp more_bb_PASTcommondock */
+ if ((eax&0xff)==0x0d) {
+ /* 5179 */
+ if (getbits(0x0e, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ eax+=0x1fe1;
+ } else {
+ /* 516c */
+ if (getbits(0x0f, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ eax+=0x5fe1;
+ }
+ /* jmp more_bb_PASTcommondock */
+ } /* al >= 0d */
+ } /* al != 4 */
+ } /* >3 */
+
+ if (getmorestuff) {
+ /* 5192 - more_bb_commondock */
+ uint16_t bk=(1<<(eax&0xff))-0x1f;
+ if (getbits((eax&0xff), &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ eax+=bk;
+ }
+
+ /* 51a7 - more_bb_pastcommondock */
+ eax&=0xffff;
+ backbytes=eax;
+ backsize=3+(oal!=1);
+
+ if (oal<1) { /* overrides backsize */
+ /* 51bb - more_bb_again */
+
+ /* next_bit_or_reseed */
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ }
+ if (!lostbit) {
+ /* 51c2 */
+ /* next_bit_or_reseed */
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ }
+ eax=5+lostbit;
+ /* jmp setsize_and_backcopy */
+ } else {
+ /* 51ce - more_bb_again_and_again */
+ if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ if (eax&0xff) {
+ /* 51e6 */
+ eax+=6;
+ /* jmp setsize_and_backcopy */
+ } else {
+ if (getbits(4, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ if (eax&0xff) {
+ /* 51e4 */
+ eax+=7+6;
+ /* jmp setsize_and_backcopy */
+ } else {
+ /* 51ea - OMGWTF */
+ uint8_t c=4;
+ uint16_t d=0x0d;
+
+ while ( 1 ) {
+ if (c!=7){
+ d+=2;
+ d<<=1;
+ d--;
+
+ /* next_bit_or_reseed */
+ lostbit=bitmap>>31;
+ bitmap<<=1;
+ bits--;
+ if (!bits) {
+ if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
+ }
+ c++;
+ if (!lostbit) continue;
+ if (getbits(c, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ d+=eax&0xff;
+ eax&=0xffffff00;
+ eax|=d&0xff;
+ } else {
+ if (getbits(14, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
+ }
+ break;
+ } /* while */
+ } /* OMGWTF */
+ } /* eax&0xff */
+ } /* lostbit */
+ /* 521b - setsize_and_backcopy */
+ backsize=eax&0xffff;
+ }
+
+ /* 521e - backcopy */
+ if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, backsize) && CLI_ISCONTAINED(unpacked, usize, dst, backsize))) return 1;
+ while(backsize--){
+ *dst=*(dst-backbytes);
+ dst++;
+ }
+
+ } /* while true */
+
+ return 0;
+}
+
+int wwunpack(char *exe, uint32_t exesz, uint32_t headsize, uint32_t min, uint32_t wwprva, uint32_t e_lfanew, char *wwp, uint32_t wwpsz, uint16_t sects) {
+ char *stuff=wwp+0x2a1, *packed, *unpacked;
+ uint32_t rva, csize;
+
+ cli_dbgmsg("in wwunpack\n");
+
+
+ while(1) {
+ if (!CLI_ISCONTAINED(wwp, wwpsz, stuff, 17)) {
+ cli_dbgmsg("WWPack: next chunk out ouf file, giving up.\n");
+ return 1;
+ }
+ if ((csize=cli_readint32(stuff+8)*4)!=(uint32_t)cli_readint32(stuff+12)+4) {
+ cli_dbgmsg("WWPack: inconsistent/hacked data, go figure!\n");
+ return 1;
+ }
+ rva = wwprva-cli_readint32(stuff);
+ if((packed = (char *) cli_calloc(csize, sizeof(char))) == NULL) {
+ cli_dbgmsg("WWPack: Can't allocate %d bytes\n", csize);
+ return 1;
+ }
+ unpacked=exe+headsize+rva-min;
+ if (!CLI_ISCONTAINED(exe, exesz, unpacked, csize)) {
+ free(packed);
+ cli_dbgmsg("WWPack: packed data out of bounds, giving up.\n");
+ return 1;
+ }
+ memcpy(packed, unpacked, csize);
+ if (wunpsect(packed, unpacked, csize, exesz-(unpacked-exe))) {
+ free(packed);
+ cli_dbgmsg("WWPack: unpacking failed.\n");
+ return 1;
+ }
+ free(packed);
+ if (!stuff[16]) break;
+ stuff+=17;
+ }
+
+ stuff=exe+e_lfanew;
+ stuff[6]=sects&0xff;
+ stuff[7]=sects>>8;
+
+ csize=cli_readint32(wwp+0x295)+wwprva+0x299;
+ cli_dbgmsg("WWPack: found OEP @%x\n", csize);
+ cli_writeint32(stuff+0x28, csize);
+
+ csize=cli_readint32(stuff+0x50)-VAALIGN(wwpsz);
+ cli_writeint32(stuff+0x50, csize);
+
+
+ stuff+=0x18+(cli_readint32(stuff+0x14)&0xffff);
+ while (sects--) {
+ uint32_t v=cli_readint32(stuff+8);
+ uint32_t r=cli_readint32(stuff+16);
+ csize=FIXVS(v, r);
+ cli_writeint32(stuff+8, csize);
+ cli_writeint32(stuff+16, csize);
+ cli_writeint32(stuff+20, cli_readint32(stuff+12)-min+headsize);
+ stuff+=0x28;
+ }
+ memset(stuff, 0, 0x28);
+
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/libclamav_yc.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2005 Ivan Zlatev <pumqara at gmail.com>
+ *
+ * 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.
+ */
+
+/* Decrypts files, protected by Y0da Cryptor 1.3 */
+
+/* aCaB:
+ * 13/01/2006 - merged standalone unpacker into libclamav
+ * 14/01/2006 - major rewrite and bugfix
+ */
+
+
+#include <string.h>
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+#include "pe.h"
+#include "others.h"
+#include "yc.h"
+
+#define EC16(x) le16_to_host(x) /* Convert little endian to host */
+
+/* ========================================================================== */
+/* "Emulates" the poly decryptors */
+
+static int yc_poly_emulator(char* decryptor_offset, char* code, unsigned int ecx)
+{
+
+ /*
+ This is the instruction set of the poly code.
+ Numbers stand for example only.
+
+ 2C 05 SUB AL,5
+ 2AC1 SUB AL,CL
+ 34 10 XOR AL,10
+ 32C1 XOR AL,CL
+ FEC8 DEC AL
+ 04 10 ADD AL,10
+ 02C1 ADD AL,CL
+ C0C0 06 ROL AL,6
+ C0C8 05 ROR AL,5
+ D2C8 ROR AL,CL
+ D2C0 ROL AL,CL
+
+ */
+ unsigned char al;
+ unsigned char cl = ecx & 0xff;
+ unsigned int j,i;
+
+ for(i=0;i<ecx;i++) /* Byte looper - Decrypts every byte and write it back */
+ {
+ al = code[i];
+
+ for(j=0;j<0x30;j++) /* Poly Decryptor "Emulator" */
+ {
+ switch(decryptor_offset[j])
+ {
+
+ case '\xEB': /* JMP short */
+ j++;
+ j = j + decryptor_offset[j];
+ break;
+
+ case '\xFE': /* DEC AL */
+ al--;
+ j++;
+ break;
+
+ case '\x2A': /* SUB AL,CL */
+ al = al - cl;
+ j++;
+ break;
+
+ case '\x02': /* ADD AL,CL */
+ al = al + cl;
+ j++;
+ break
+ ;
+ case '\x32': /* XOR AL,CL */
+ al = al ^ cl;
+ j++;
+ break;
+ ;
+ case '\x04': /* ADD AL,num */
+ j++;
+ al = al + decryptor_offset[j];
+ break;
+ ;
+ case '\x34': /* XOR AL,num */
+ j++;
+ al = al ^ decryptor_offset[j];
+ break;
+
+ case '\x2C': /* SUB AL,num */
+ j++;
+ al = al - decryptor_offset[j];
+ break;
+
+
+ case '\xC0':
+ j++;
+ if(decryptor_offset[j]=='\xC0') /* ROL AL,num */
+ {
+ j++;
+ CLI_ROL(al,decryptor_offset[j]);
+ }
+ else /* ROR AL,num */
+ {
+ j++;
+ CLI_ROR(al,decryptor_offset[j]);
+ }
+ break;
+
+ case '\xD2':
+ j++;
+ if(decryptor_offset[j]=='\xC8') /* ROR AL,CL */
+ {
+ j++;
+ CLI_ROR(al,cl);
+ }
+ else /* ROL AL,CL */
+ {
+ j++;
+ CLI_ROL(al,cl);
+ }
+ break;
+
+ case '\x90':
+ case '\xf8':
+ case '\xf9':
+ break;
+
+ default:
+ cli_dbgmsg("yC: Unhandled opcode %x\n", (unsigned char)decryptor_offset[j]);
+ return 1;
+ }
+ }
+ cl--;
+ code[i] = al;
+ }
+ return 0;
+
+}
+
+
+/* ========================================================================== */
+/* Main routine which calls all others */
+
+int yc_decrypt(char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc)
+{
+ uint32_t ycsect = sections[sectcount].raw;
+ unsigned int i;
+ struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset);
+ char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;
+
+ /*
+
+ First layer (decryptor of the section decryptor) in last section
+
+ Start offset for analyze: Start of yC Section + 0x93
+ End offset for analyze: Start of yC Section + 0xC3
+ Lenght to decrypt - ECX = 0xB97
+
+ */
+ cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount);
+ if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6 ,0xB97))
+ return 1;
+ filesize-=sections[sectcount].ursz;
+
+ /*
+
+ Second layer (decryptor of the sections) in last section
+
+ Start offset for analyze: Start of yC Section + 0x457
+ End offset for analyze: Start of yC Section + 0x487
+ Lenght to decrypt - ECX = Raw Size of Section
+
+ */
+
+
+ /* Loop through all sections and decrypt them... */
+ for(i=0;i<sectcount;i++)
+ {
+ uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
+ if ( !sections[i].raw ||
+ !sections[i].rsz ||
+ name == 0x63727372 || /* rsrc */
+ name == 0x7273722E || /* .rsr */
+ name == 0x6F6C6572 || /* relo */
+ name == 0x6C65722E || /* .rel */
+ name == 0x6164652E || /* .eda */
+ name == 0x6164722E || /* .rda */
+ name == 0x6164692E || /* .ida */
+ name == 0x736C742E || /* .tls */
+ (name&0xffff) == 0x4379 /* yC */
+ ) continue;
+ cli_dbgmsg("yC: decrypting sect%d\n",i);
+ if (yc_poly_emulator(fbuf + ycsect + 0x457, fbuf + sections[i].raw, sections[i].ursz))
+ return 1;
+ }
+
+ /* Remove yC section */
+ pe->NumberOfSections=EC16(sectcount);
+
+ /* Remove IMPORT_DIRECTORY information */
+ memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8);
+
+ /* OEP resolving */
+ /* OEP = DWORD PTR [ Start of yC section+ A0F] */
+ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f));
+
+ /* Fix SizeOfImage */
+ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz);
+
+ if (cli_writen(desc, fbuf, filesize)==-1) {
+ cli_dbgmsg("yC: Cannot write unpacked file\n");
+ return 1;
+ }
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/line.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/line.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/line.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/line.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2004 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * $Log: line.h,v $
+ * Revision 1.5 2006/04/09 19:59:27 kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.4 2004/10/14 17:45:55 nigelhorne
+ * Try to reclaim some memory if it becomes low when decoding
+ *
+ * Revision 1.3 2004/08/21 11:57:57 nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.2 2004/08/20 19:06:45 kojm
+ * add line.[ch]
+ *
+ * Revision 1.1 2004/08/20 11:58:20 nigelhorne
+ * First draft
+ *
+ */
+
+#ifndef __LINE_H
+#define __LINE_H
+
+typedef char line_t; /* first byte is the ref count */
+
+line_t *lineCreate(const char *data);
+line_t *lineLink(line_t *line);
+line_t *lineUnlink(line_t *line);
+const char *lineGetData(const line_t *line);
+
+#define lineGetRefCount(line) ((unsigned char)line[0])
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/lockdb.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 Mark Pizzolato <clamav-devel at subscriptions.pizzolato.net>
+ *
+ * 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.
+ */
+
+#ifndef __LOCKDB_H
+#define __LOCKDB_H
+
+int cli_writelockdb(const char *dbdirpath, int wait);
+int cli_readlockdb(const char *dbdirpath, int wait);
+int cli_unlockdb(const char *dbdirpath);
+int cli_freelocks(void);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/manager.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/manager.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/manager.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/manager.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2002, 2003 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MANAGER_H
+#define __MANAGER_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "clamav.h"
+#include "options.h"
+
+int scanmanager(const struct optstruct *opt);
+
+int scanfile(const char *filename, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher-ac.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MATCHER_AC_H
+#define __MATCHER_AC_H
+
+#include <sys/types.h>
+
+#include "filetypes.h"
+#include "cltypes.h"
+
+#define AC_DEFAULT_MIN_DEPTH 2
+#define AC_DEFAULT_MAX_DEPTH 3
+#define AC_DEFAULT_TRACKLEN 8
+extern uint8_t cli_ac_mindepth, cli_ac_maxdepth;
+
+struct cli_ac_data {
+ uint32_t partsigs;
+ int32_t ***offmatrix;
+};
+
+struct cli_ac_alt {
+ uint8_t chmode;
+ unsigned char *str;
+ uint16_t len, num;
+ struct cli_ac_alt *next;
+};
+
+struct cli_ac_patt {
+ uint16_t *pattern, *prefix, length, prefix_length;
+ uint8_t depth;
+ uint32_t mindist, maxdist;
+ char *virname, *offset;
+ uint32_t sigid;
+ uint16_t parts, partno, alt, alt_pattern;
+ struct cli_ac_alt **alttable;
+ uint8_t target;
+ uint16_t type;
+ struct cli_ac_patt *next, *next_same;
+};
+
+struct cli_ac_node {
+ uint8_t leaf, final;
+ struct cli_ac_patt *list;
+ struct cli_ac_node **trans, *fail;
+};
+
+#include "matcher.h"
+
+int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern);
+int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t tracklen);
+void cli_ac_freedata(struct cli_ac_data *data);
+int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, struct cli_ac_data *mdata, uint8_t otfrec, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset);
+int cli_ac_buildtrie(struct cli_matcher *root);
+int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth);
+void cli_ac_free(struct cli_matcher *root);
+int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target);
+void cli_ac_setdepth(uint8_t mindepth, uint8_t maxdepth);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher-bm.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MATCHER_BM_H
+#define __MATCHER_BM_H
+
+#include "matcher.h"
+#include "filetypes.h"
+#include "cltypes.h"
+
+struct cli_bm_patt {
+ unsigned char *pattern, *prefix;
+ uint16_t length, prefix_length;
+ char *virname, *offset;
+ uint8_t target;
+ struct cli_bm_patt *next;
+ uint16_t cnt;
+};
+
+int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern);
+int cli_bm_init(struct cli_matcher *root);
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, cli_file_t ftype, int fd);
+void cli_bm_free(struct cli_matcher *root);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/matcher.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MATCHER_H
+#define __MATCHER_H
+
+#include <sys/types.h>
+
+#include "clamav.h"
+#include "filetypes.h"
+#include "others.h"
+#include "execs.h"
+#include "cltypes.h"
+#include "md5.h"
+
+#include "matcher-ac.h"
+#include "matcher-bm.h"
+
+#define CLI_MATCH_WILDCARD 0xff00
+#define CLI_MATCH_CHAR 0x0000
+#define CLI_MATCH_IGNORE 0x0100
+#define CLI_MATCH_ALTERNATIVE 0x0200
+#define CLI_MATCH_NIBBLE_HIGH 0x0300
+#define CLI_MATCH_NIBBLE_LOW 0x0400
+
+struct cli_matcher {
+ uint16_t maxpatlen;
+ uint8_t ac_only;
+
+ /* Extended Boyer-Moore */
+ uint8_t *bm_shift;
+ struct cli_bm_patt **bm_suffix;
+ uint32_t *soff, soff_len; /* for PE section sigs */
+
+ /* Extended Aho-Corasick */
+ uint8_t ac_mindepth, ac_maxdepth;
+ struct cli_ac_node *ac_root, **ac_nodetable;
+ struct cli_ac_patt **ac_pattable;
+ uint32_t ac_partsigs, ac_nodes, ac_patterns;
+};
+
+struct cli_md5_node {
+ char *virname;
+ unsigned char *md5;
+ unsigned int size;
+ unsigned short fp;
+ struct cli_md5_node *next;
+};
+
+struct cli_meta_node {
+ int csize, size, method;
+ unsigned int crc32, fileno, encrypted, maxdepth;
+ char *filename, *virname;
+ struct cli_meta_node *next;
+};
+
+#define CL_TARGET_TABLE_SIZE 7
+
+struct cli_target_info {
+ off_t fsize;
+ struct cli_exe_info exeinfo;
+ int8_t status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
+};
+
+int cli_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cl_engine *engine, cli_file_t ftype);
+
+int cli_scandesc(int desc, cli_ctx *ctx, uint8_t otfrec, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset);
+
+int cli_validatesig(cli_file_t ftype, const char *offstr, off_t fileoff, struct cli_target_info *info, int desc, const char *virname);
+
+struct cli_md5_node *cli_vermd5(const unsigned char *md5, const struct cl_engine *engine);
+
+off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_file_t ftype, int *ret, unsigned int *maxshift);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mbox.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+/* See RFC1521 */
+typedef enum {
+ NOMIME, APPLICATION, AUDIO, IMAGE, MESSAGE, MULTIPART, TEXT, VIDEO, MEXTENSION
+} mime_type;
+
+typedef enum {
+ NOENCODING, QUOTEDPRINTABLE, BASE64, EIGHTBIT, BINARY, UUENCODE, YENCODE, EEXTENSION, BINHEX
+} encoding_type;
+
+/* tk: shut up manager.c warning */
+#include "clamav.h"
+
+/* classes supported by this system */
+typedef enum {
+ INVALIDCLASS, BLOBCLASS
+} object_type;
+
+#ifdef C_BSD
+#define UNIX
+#endif
+
+#include "table.h"
+#include "blob.h"
+#include "line.h"
+#include "text.h"
+#include "message.h"
+#include "uuencode.h"
+
+size_t strstrip(char *s); /* remove trailing white space */
+int cli_mbox(const char *dir, int desc, cli_ctx *ctx);
Added: test-suite/trunk/MultiSource/Applications/ClamAV/md5.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/md5.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/md5.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/md5.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security,
+ * Inc. MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Written by Solar Designer <solar at openwall.com> in 2001, and placed
+ * in the public domain. There's absolutely no warranty.
+ *
+ * See md5.c for more information.
+ */
+
+#ifndef __MD5_H
+#define __MD5_H
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+ MD5_u32plus lo, hi;
+ MD5_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ MD5_u32plus block[16];
+} cli_md5_ctx;
+
+extern void cli_md5_init(cli_md5_ctx *ctx);
+extern void cli_md5_update(cli_md5_ctx *ctx, void *data, unsigned long size);
+extern void cli_md5_final(unsigned char *result, cli_md5_ctx *ctx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/message.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/message.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/message.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/message.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef _MESSAGE_H
+#define _MESSAGE_H
+
+/* The contents could change, ONLY access in message.c */
+typedef struct message {
+ mime_type mimeType;
+ encoding_type *encodingTypes;
+ int numberOfEncTypes; /* size of encodingTypes */
+ char *mimeSubtype;
+ int numberOfArguments; /* count of mimeArguments */
+ char **mimeArguments;
+ char *mimeDispositionType; /* probably attachment */
+ text *body_first, *body_last;
+ cli_ctx *ctx;
+
+ char base64_1, base64_2, base64_3;
+ int base64chars;
+ unsigned int isInfected : 1;
+
+ /*
+ * Markers for the start of various non MIME messages that could
+ * be included within this message
+ */
+ text *bounce; /* start of a bounced message */
+ text *binhex; /* start of a binhex message */
+ text *yenc; /* start of a yEnc message */
+ text *encoding; /* is the non MIME message encoded? */
+ const text *dedupedThisFar;
+} message;
+
+message *messageCreate(void);
+void messageDestroy(message *m);
+void messageReset(message *m);
+int messageSetMimeType(message *m, const char *type);
+mime_type messageGetMimeType(const message *m);
+void messageSetMimeSubtype(message *m, const char *subtype);
+const char *messageGetMimeSubtype(const message *m);
+void messageSetDispositionType(message *m, const char *disptype);
+const char *messageGetDispositionType(const message *m);
+void messageAddArgument(message *m, const char *arg);
+void messageAddArguments(message *m, const char *arg);
+char *messageFindArgument(const message *m, const char *variable);
+char *messageGetFilename(const message *m);
+int messageHasFilename(const message *m);
+void messageSetEncoding(message *m, const char *enctype);
+encoding_type messageGetEncoding(const message *m);
+int messageAddLine(message *m, line_t *line);
+int messageAddStr(message *m, const char *data);
+int messageAddStrAtTop(message *m, const char *data);
+int messageMoveText(message *m, text *t, message *old_message);
+text *messageGetBody(message *m);
+unsigned char *base64Flush(message *m, unsigned char *buf);
+fileblob *messageToFileblob(message *m, const char *dir, int destroy);
+blob *messageToBlob(message *m, int destroy);
+text *messageToText(message *m);
+text *binhexBegin(message *m);
+text *yEncBegin(message *m);
+text *bounceBegin(message *m);
+text *encodingLine(message *m);
+void messageClearMarkers(message *m);
+unsigned char *decodeLine(message *m, encoding_type enctype, const char *line, unsigned char *buf, size_t buflen);
+int isuuencodebegin(const char *line);
+void messageSetCTX(message *m, cli_ctx *ctx);
+int messageContainsVirus(const message *m);
+
+#endif /*_MESSAGE_H*/
Added: test-suite/trunk/MultiSource/Applications/ClamAV/mew.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mew.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mew.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mew.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ * 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.
+ */
+
+#ifndef __MEW_H
+#define __MEW_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+
+struct lzmastate {
+ char *p0;
+ uint32_t p1, p2;
+};
+
+int mew_lzma(char *, char *, uint32_t, uint32_t, uint32_t);
+
+uint32_t lzma_upack_esi_00(struct lzmastate *, char *, char *, uint32_t);
+uint32_t lzma_upack_esi_50(struct lzmastate *, uint32_t, uint32_t, char **, char *, uint32_t *, char *, uint32_t);
+uint32_t lzma_upack_esi_54(struct lzmastate *, uint32_t, uint32_t *, char **, uint32_t *, char *, uint32_t);
+int unmew11(int, char *, int, int, int, uint32_t, uint32_t, int, char **, char **, int);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/misc.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/misc.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/misc.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/misc.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __MISC_H
+#define __MISC_H
+
+/* Maximum filenames under various systems - njh */
+#ifndef NAME_MAX /* e.g. Linux */
+# ifdef MAXNAMELEN /* e.g. Solaris */
+# define NAME_MAX MAXNAMELEN
+# else
+# ifdef FILENAME_MAX /* e.g. SCO */
+# define NAME_MAX FILENAME_MAX
+# endif
+# endif
+#endif
+
+#include "cfgparser.h"
+
+char *freshdbdir(void);
+void print_version(void);
+int filecopy(const char *src, const char *dest);
+int isnumb(const char *str);
+int dircopy(const char *src, const char *dest);
+int cvd_unpack(const char *cvd, const char *destdir);
+void daemonize(void);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/msexpand.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * 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.
+ */
+
+#ifndef __MSEXPAND_H
+#define __MSEXPAND_H
+
+#include <stdio.h>
+
+int cli_msexpand(FILE *in, FILE *out);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/mspack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,292 @@
+/*
+ * This file includes code from libmspack adapted for libclamav by
+ * tkojm at clamav.net
+ *
+ * Copyright (C) 2003-2004 Stuart Caie
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef __MSPACK_H
+#define __MSPACK_H
+
+#include <sys/types.h>
+#include "cab.h"
+
+
+/***************************************************************************
+ * MS-ZIP decompression definitions *
+ ***************************************************************************/
+
+#define MSZIP_FRAME_SIZE (32768) /* size of LZ history window */
+#define MSZIP_MAX_HUFFBITS (16) /* maximum huffman code length */
+#define MSZIP_LITERAL_MAXSYMBOLS (288) /* literal/length huffman tree */
+#define MSZIP_LITERAL_TABLEBITS (9)
+#define MSZIP_DISTANCE_MAXSYMBOLS (32) /* distance huffman tree */
+#define MSZIP_DISTANCE_TABLEBITS (6)
+
+/* if there are less direct lookup entries than symbols, the longer
+ * code pointers will be <= maxsymbols. This must not happen, or we
+ * will decode entries badly */
+#if (1 << MSZIP_LITERAL_TABLEBITS) < (MSZIP_LITERAL_MAXSYMBOLS * 2)
+# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
+#else
+# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
+ (MSZIP_LITERAL_MAXSYMBOLS * 2))
+#endif
+
+#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
+# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
+#else
+# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
+ (MSZIP_DISTANCE_MAXSYMBOLS * 2))
+#endif
+
+struct mszip_stream {
+ int fd; /* input file descriptor */
+ int ofd; /* output file descriptor */
+ unsigned char wflag; /* write flag */
+
+ unsigned int window_posn; /* offset within window */
+
+ /* inflate() will call this whenever the window should be emptied. */
+ int (*flush_window)(struct mszip_stream *, unsigned int);
+
+ int error, repair_mode, bytes_output, input_end;
+
+ /* I/O buffering */
+ unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+ unsigned int bit_buffer, bits_left, inbuf_size;
+
+ /* huffman code lengths */
+ unsigned char LITERAL_len[MSZIP_LITERAL_MAXSYMBOLS];
+ unsigned char DISTANCE_len[MSZIP_DISTANCE_MAXSYMBOLS];
+
+ /* huffman decoding tables */
+ unsigned short LITERAL_table [MSZIP_LITERAL_TABLESIZE];
+ unsigned short DISTANCE_table[MSZIP_DISTANCE_TABLESIZE];
+
+ /* 32kb history window */
+ unsigned char window[MSZIP_FRAME_SIZE];
+
+ /* cabinet related stuff */
+ struct cab_file *file;
+ int (*read)(struct cab_file *, unsigned char *, int);
+};
+
+struct mszip_stream *mszip_init(int fd,
+ int ofd,
+ int input_buffer_size,
+ int repair_mode,
+ struct cab_file *file,
+ int (*read)(struct cab_file *, unsigned char *, int));
+
+extern int mszip_decompress(struct mszip_stream *zip, off_t out_bytes);
+
+void mszip_free(struct mszip_stream *zip);
+
+
+/***************************************************************************
+ * Quantum decompression definitions *
+ ***************************************************************************/
+
+/* Quantum compression / decompression definitions */
+
+#define QTM_FRAME_SIZE (32768)
+
+struct qtm_modelsym {
+ unsigned short sym, cumfreq;
+};
+
+struct qtm_model {
+ int shiftsleft, entries;
+ struct qtm_modelsym *syms;
+};
+
+struct qtm_stream {
+ int fd; /* input file descriptor */
+ int ofd; /* output file descriptor */
+ unsigned char wflag; /* write flag */
+
+ unsigned char *window; /* decoding window */
+ unsigned int window_size; /* window size */
+ unsigned int window_posn; /* decompression offset within window */
+ unsigned int frame_start; /* start of current frame within window */
+
+ unsigned short H, L, C; /* high/low/current: arith coding state */
+ unsigned char header_read; /* have we started decoding a new frame? */
+
+ int error;
+
+ /* I/O buffers */
+ unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+ unsigned int bit_buffer, inbuf_size;
+ unsigned char bits_left;
+
+ /* data tables */
+ unsigned int position_base[42];
+ unsigned char extra_bits[42], length_base[27], length_extra[27];
+
+ /* four literal models, each representing 64 symbols
+ * model0 for literals from 0 to 63 (selector = 0)
+ * model1 for literals from 64 to 127 (selector = 1)
+ * model2 for literals from 128 to 191 (selector = 2)
+ * model3 for literals from 129 to 255 (selector = 3) */
+ struct qtm_model model0, model1, model2, model3;
+
+ /* three match models.
+ * model4 for match with fixed length of 3 bytes
+ * model5 for match with fixed length of 4 bytes
+ * model6 for variable length match, encoded with model6len model */
+ struct qtm_model model4, model5, model6, model6len;
+
+ /* selector model. 0-6 to say literal (0,1,2,3) or match (4,5,6) */
+ struct qtm_model model7;
+
+ /* symbol arrays for all models */
+ struct qtm_modelsym m0sym[64 + 1];
+ struct qtm_modelsym m1sym[64 + 1];
+ struct qtm_modelsym m2sym[64 + 1];
+ struct qtm_modelsym m3sym[64 + 1];
+ struct qtm_modelsym m4sym[24 + 1];
+ struct qtm_modelsym m5sym[36 + 1];
+ struct qtm_modelsym m6sym[42 + 1], m6lsym[27 + 1];
+ struct qtm_modelsym m7sym[7 + 1];
+
+ /* cabinet related stuff */
+ struct cab_file *file;
+ int (*read)(struct cab_file *, unsigned char *, int);
+
+};
+
+extern struct qtm_stream *qtm_init(int fd,
+ int ofd,
+ int window_bits,
+ int input_buffer_size,
+ struct cab_file *file,
+ int (*read)(struct cab_file *, unsigned char *, int));
+
+extern int qtm_decompress(struct qtm_stream *qtm, off_t out_bytes);
+
+void qtm_free(struct qtm_stream *qtm);
+
+/***************************************************************************
+ * LZX decompression definitions *
+ ***************************************************************************/
+
+/* some constants defined by the LZX specification */
+#define LZX_MIN_MATCH (2)
+#define LZX_MAX_MATCH (257)
+#define LZX_NUM_CHARS (256)
+#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
+#define LZX_BLOCKTYPE_VERBATIM (1)
+#define LZX_BLOCKTYPE_ALIGNED (2)
+#define LZX_BLOCKTYPE_UNCOMPRESSED (3)
+#define LZX_PRETREE_NUM_ELEMENTS (20)
+#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
+#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
+#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
+
+/* LZX huffman defines: tweak tablebits as desired */
+#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
+#define LZX_PRETREE_TABLEBITS (6)
+#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
+#define LZX_MAINTREE_TABLEBITS (12)
+#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
+#define LZX_LENGTH_TABLEBITS (12)
+#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
+#define LZX_ALIGNED_TABLEBITS (7)
+#define LZX_LENTABLE_SAFETY (64) /* table decoding overruns are allowed */
+
+#define LZX_FRAME_SIZE (32768) /* the size of a frame in LZX */
+
+struct lzx_stream {
+ int fd; /* input file descriptor */
+ int ofd; /* output file descriptor */
+ unsigned char wflag; /* write flag */
+
+ off_t offset; /* number of bytes actually output */
+ off_t length; /* overall decompressed length of stream */
+
+ unsigned char *window; /* decoding window */
+ unsigned int window_size; /* window size */
+ unsigned int window_posn; /* decompression offset within window */
+ unsigned int frame_posn; /* current frame offset within in window */
+ unsigned int frame; /* the number of 32kb frames processed */
+ unsigned int reset_interval; /* which frame do we reset the compressor? */
+
+ unsigned int R0, R1, R2; /* for the LRU offset system */
+ unsigned int block_length; /* uncompressed length of this LZX block */
+ unsigned int block_remaining; /* uncompressed bytes still left to decode */
+
+ signed int intel_filesize; /* magic header value used for transform */
+ signed int intel_curpos; /* current offset in transform space */
+
+ unsigned char intel_started; /* has intel E8 decoding started? */
+ unsigned char block_type; /* type of the current block */
+ unsigned char header_read; /* have we started decoding at all yet? */
+ unsigned char posn_slots; /* how many posn slots in stream? */
+ unsigned char input_end; /* have we reached the end of input? */
+
+ int error;
+
+ /* I/O buffering */
+ unsigned char *inbuf, *i_ptr, *i_end, *o_ptr, *o_end;
+ unsigned int bit_buffer, bits_left, inbuf_size;
+
+ /* huffman code lengths */
+ unsigned char PRETREE_len [LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
+ unsigned char MAINTREE_len [LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
+ unsigned char LENGTH_len [LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
+ unsigned char ALIGNED_len [LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY];
+
+ /* huffman decoding tables */
+ unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
+ (LZX_PRETREE_MAXSYMBOLS * 2)];
+ unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
+ (LZX_MAINTREE_MAXSYMBOLS * 2)];
+ unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
+ (LZX_LENGTH_MAXSYMBOLS * 2)];
+ unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
+ (LZX_ALIGNED_MAXSYMBOLS * 2)];
+
+ unsigned int position_base[51];
+ unsigned char extra_bits[51];
+
+ /* this is used purely for doing the intel E8 transform */
+ unsigned char e8_buf[LZX_FRAME_SIZE];
+
+ /* cabinet related stuff */
+ struct cab_file *file;
+ int (*read)(struct cab_file *, unsigned char *, int);
+};
+
+struct lzx_stream *lzx_init(int fd,
+ int ofd,
+ int window_bits,
+ int reset_interval,
+ int input_buffer_size,
+ off_t output_length,
+ struct cab_file *file,
+ int (*read)(struct cab_file *, unsigned char *, int));
+
+extern void lzx_set_output_length(struct lzx_stream *lzx,
+ off_t output_length);
+
+extern int lzx_decompress(struct lzx_stream *lzx, off_t out_bytes);
+
+void lzx_free(struct lzx_stream *lzx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/network.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/network.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/network.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/network.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __NETWORK_H
+#define __NETWORK_H
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef C_WINDOWS
+#include <netdb.h>
+#endif
+
+int r_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_bzlib.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,264 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library. ---*/
+/*--- bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+ This file is part of bzip2/libbzip2, a program and library for
+ lossless, block-sorting data compression.
+
+ bzip2/libbzip2 version 1.0.4 of 20 December 2006
+ Copyright (C) 1996-2006 Julian Seward <jseward at bzip.org>
+ This file was modified for ClamAV by aCaB <acab at clamav.net>
+
+ This program is released under the terms of the license contained
+ in the file COPYING.nsis.
+ ------------------------------------------------------------------ */
+
+
+#ifndef _NSIS_BZLIB_H
+#define _NSIS_BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN 0
+#define BZ_FLUSH 1
+#define BZ_FINISH 2
+
+#define BZ_OK 0
+#define BZ_RUN_OK 1
+#define BZ_FLUSH_OK 2
+#define BZ_FINISH_OK 3
+#define BZ_STREAM_END 4
+#define BZ_SEQUENCE_ERROR (-1)
+#define BZ_PARAM_ERROR (-2)
+#define BZ_MEM_ERROR (-3)
+#define BZ_DATA_ERROR (-4)
+#define BZ_DATA_ERROR_MAGIC (-5)
+#define BZ_IO_ERROR (-6)
+#define BZ_UNEXPECTED_EOF (-7)
+#define BZ_OUTBUFF_FULL (-8)
+#define BZ_CONFIG_ERROR (-9)
+
+typedef
+ struct {
+ unsigned char *next_in;
+ unsigned int avail_in;
+ unsigned int total_in_lo32;
+ unsigned int total_in_hi32;
+
+ unsigned char *next_out;
+ unsigned int avail_out;
+ unsigned int total_out_lo32;
+ unsigned int total_out_hi32;
+
+ void *state;
+
+ void *(*bzalloc)(void *,int,int);
+ void (*bzfree)(void *,void *);
+ void *opaque;
+ }
+ nsis_bzstream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include <stdio.h>
+#endif
+
+
+#define BZ_API(func) func
+#define BZ_EXTERN extern
+
+
+/*-- Core (low-level) library functions --*/
+/* aCaB
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) (
+ nsis_bzstream* strm,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) (
+ nsis_bzstream* strm,
+ int action
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) (
+ nsis_bzstream* strm
+ );
+*/
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompressInit) (
+ nsis_bzstream *strm,
+ int verbosity,
+ int small
+ );
+
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompress) (
+ nsis_bzstream* strm
+ );
+
+BZ_EXTERN int BZ_API(nsis_BZ2_bzDecompressEnd) (
+ nsis_bzstream *strm
+ );
+
+
+
+/*-- High(er) level library functions --*/
+/* aCaB
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) (
+ int* bzerror,
+ FILE* f,
+ int verbosity,
+ int small,
+ void* unused,
+ int nUnused
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) (
+ int* bzerror,
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) (
+ int* bzerror,
+ BZFILE* b,
+ void** unused,
+ int* nUnused
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) (
+ int* bzerror,
+ FILE* f,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) (
+ int* bzerror,
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in,
+ unsigned int* nbytes_out
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) (
+ int* bzerror,
+ BZFILE* b,
+ int abandon,
+ unsigned int* nbytes_in_lo32,
+ unsigned int* nbytes_in_hi32,
+ unsigned int* nbytes_out_lo32,
+ unsigned int* nbytes_out_hi32
+ );
+#endif
+*/
+/*-- Utility functions --*/
+/* aCaB
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int blockSize100k,
+ int verbosity,
+ int workFactor
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) (
+ char* dest,
+ unsigned int* destLen,
+ char* source,
+ unsigned int sourceLen,
+ int small,
+ int verbosity
+ );
+*/
+
+/*--
+ Code contributed by Yoshioka Tsuneo (tsuneo at rr.iij4u.or.jp)
+ to support better zlib compatibility.
+ This code is not _officially_ part of libbzip2 (yet);
+ I haven't tested it, documented it, or considered the
+ threading-safeness of it.
+ If this code breaks, please contact both Yoshioka and me.
+--*/
+/* aCaB
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+ void
+ );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+ const char *path,
+ const char *mode
+ );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+ int fd,
+ const char *mode
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+ BZFILE* b,
+ void* buf,
+ int len
+ );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+ BZFILE* b
+ );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+ BZFILE* b
+ );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+ BZFILE *b,
+ int *errnum
+ );
+#endif
+*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end bzlib.h ---*/
+/*-------------------------------------------------------------*/
Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zconf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,58 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in COPYING.nsis.
+ */
+
+/* @(#) $Id: ZCONF.H,v 1.3 2007/01/13 17:28:23 kichik Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+
+#define MAX_MEM_LEVEL 9
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+#define OF(args) args
+
+
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+typedef unsigned char Byte; /* 8 bits */
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+typedef void FAR *voidpf;
+typedef void *voidp;
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+
+#endif /* _ZCONF_H */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zlib.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,220 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.1.3, July 9th, 1998
+
+ Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup at gzip.org madler at alumni.caltech.edu
+
+
+*/
+
+#ifndef _NSIS_ZLIB_H
+#define _NSIS_ZLIB_H
+
+#include "nsis_zconf.h"
+#include "nsis_zutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+
+
+typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+ CODES_START, /* x: set up for LEN */
+ CODES_LEN, /* i: get length/literal/eob next */
+ CODES_LENEXT, /* i: getting length extra (have base) */
+ CODES_DIST, /* i: get distance next */
+ CODES_DISTEXT, /* i: getting distance extra */
+ CODES_COPY, /* o: copying bytes in window, waiting for space */
+ CODES_LIT, /* o: got literal, waiting for output space */
+ CODES_WASH, /* o: got eob, possibly still output waiting */
+ /* CODES_END, x: got eob and all data flushed */
+ /* CODES_BADCODE, x: got error */
+
+ TYPE, /* get type bits (3, including end bit) */
+ LENS, /* get lengths for stored */
+ STORED, /* processing stored block */
+ TABLE, /* get table lengths */
+ BTREE, /* get bit lengths tree for a dynamic block */
+ DTREE, /* get length, distance trees for a dynamic block */
+ CODES, /* processing fixed or dynamic block */
+ DRY, /* output remaining window bytes */
+ DONE, /* finished last block, done */
+ NZ_BAD /* got a data error--stuck here */
+} inflate_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+ /* mode */
+ /* inflate_mode mode; current inflate_codes mode */
+
+ /* mode dependent information */
+ uInt len;
+ union {
+ struct {
+ inflate_huft *tree; /* pointer into tree */
+ uInt need; /* bits needed */
+ } code; /* if LEN or DIST, where in tree */
+ uInt lit; /* if LIT, literal */
+ struct {
+ uInt get; /* bits to get for extra */
+ uInt dist; /* distance back to copy from */
+ } copy; /* if EXT or COPY, where and how much */
+ } sub; /* submode */
+
+ /* mode independent information */
+ Byte lbits; /* ltree bits decoded per branch */
+ Byte dbits; /* dtree bits decoder per branch */
+ inflate_huft *ltree; /* literal/length/eob tree */
+ inflate_huft *dtree; /* distance tree */
+
+};
+
+struct inflate_huft_s {
+ union {
+ struct {
+ Byte Exop; /* number of extra bits or operation */
+ Byte Bits; /* number of bits in this code or subcode */
+ } what;
+ } word;
+ unsigned short base; /* literal, length base, distance base,
+ or table offset */
+};
+
+#define MANY 1440
+
+typedef struct inflate_codes_state inflate_codes_statef;
+
+struct inflate_blocks_state {
+
+ /* mode */
+ inflate_mode mode; /* current inflate_block mode */
+
+ /* mode dependent information */
+ union {
+ uInt left; /* if STORED, bytes left to copy */
+ struct {
+ uInt table; /* table lengths (14 bits) */
+ uInt index; /* index into blens (or border) */
+ uIntf t_blens[258+31+31]; /* bit lengths of codes */
+ uInt bb; /* bit length tree depth */
+ inflate_huft *tb; /* bit length decoding tree */
+ } trees; /* if DTREE, decoding info for trees */
+ struct {
+ inflate_codes_statef t_codes;
+ } decode; /* if CODES, current state */
+ } sub; /* submode */
+
+ uInt last; /* DRY if this block is the last block, TYPE otherwise */
+
+ /* mode independent information */
+ uInt bitk; /* bits in bit buffer */
+ uLong bitb; /* bit buffer */
+ inflate_huft hufts[MANY]; /* single malloc for tree space */
+ Bytef window[1 << MAX_WBITS]; /* sliding window */
+ Bytef *end; /* one byte after sliding window */
+ Bytef *read; /* window read pointer */
+ Bytef *write; /* window write pointer */
+ uLong check; /* check on output */
+
+};
+
+typedef struct nsis_z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+
+ /* char *msg; last error message, NULL if no error */
+ /* struct internal_state FAR *state; not visible by applications */
+ struct inflate_blocks_state blocks;
+
+} nsis_z_stream;
+
+typedef nsis_z_stream FAR *nsis_z_streamp;
+
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+
+/* EXEHEAD doesn't need a specific return code, just < 0 */
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_ASCII 1
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+
+#define nsis_inflateInit(x) inflateReset(x)
+int ZEXPORT nsis_inflate(nsis_z_streamp z);
+#define inflateReset(z) \
+{ \
+ (z)->blocks.mode = TYPE; \
+ (z)->blocks.bitk = (z)->blocks.bitb = 0; \
+ (z)->blocks.read = (z)->blocks.write = (z)->blocks.window; \
+ (z)->blocks.end = (z)->blocks.window + (1 << DEF_WBITS); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nsis_zutil.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,74 @@
+/*
+ * This file is a part of the zlib compression module for NSIS.
+ *
+ * Copyright and license information can be found below.
+ * Modifications Copyright (C) 1999-2007 Nullsoft and Contributors
+ *
+ * The original zlib source code is available at
+ * http://www.zlib.net/
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ */
+
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1998 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in COPYING.nsis.
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: ZUTIL.H,v 1.6 2007/01/25 18:07:40 kichik Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "nsis_zlib.h"
+
+#ifndef local
+# define local static
+#endif
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#define DEF_MEM_LEVEL MAX_MEM_LEVEL
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+
+#define zmemcpy memcpy
+
+#define Assert(cond,msg)
+#define Trace(x)
+#define Tracev(x)
+#define Tracevv(x)
+#define Tracec(c,x)
+#define Tracecv(c,x)
+
+#define ZALLOC(strm, items, size) malloc((items)*(size))
+#define ZFREE(strm, addr) { if (addr) free(addr); }
+#define TRY_FREE(s, p) { ZFREE(s, p); }
+#define ERR_RETURN(strm,err) return (err)
+
+#endif /* _Z_UTIL_H */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/nulsft.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2007 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __NSIS_H
+#define __NSIS_H
+
+#include "others.h"
+int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset);
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/ole2_extract.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,31 @@
+/*
+ * Extract component parts of OLE2 files (e.g. MS Office Documents)
+ *
+ * Copyright (C) 2004 trog at uncon.org
+ *
+ * This code is based on the OpenOffice and libgsf sources.
+ *
+ * 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.
+ */
+
+#ifndef __OLE2_EXTRACT_H
+#define __OLE2_EXTRACT_H
+
+#include "clamav.h"
+
+int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/options.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/options.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/options.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/options.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2002 - 2006 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __OPTIONS_H
+#define __OPTIONS_H
+
+#define _GNU_SOURCE
+#include "getopt.h"
+
+struct optnode {
+ char optshort;
+ char *optlong;
+ char *optarg;
+ struct optnode *next;
+};
+
+struct optstruct {
+ struct optnode *optlist;
+ char *filename;
+};
+
+void opt_free(struct optstruct *opt);
+
+struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long);
+
+int opt_check(const struct optstruct *opt, const char *optlong);
+
+char *opt_arg(const struct optstruct *opt, const char *optlong);
+
+char *opt_firstarg(const struct optstruct *opt, const char *optlong, const struct optnode **optnode);
+
+char *opt_nextarg(const struct optnode **optnode, const char *optlong);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/others.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/others.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/others.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/others.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 1999 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __OTHERS_H_LC
+#define __OTHERS_H_LC
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "cltypes.h"
+
+#include "clamav.h"
+#include "dconf.h"
+
+extern uint8_t cli_debug_flag, cli_leavetemps_flag;
+
+/*
+ * CLI_ISCONTAINED(buf1, size1, buf2, size2) checks if buf2 is contained
+ * within buf1.
+ *
+ * buf1 and buf2 are pointers (or offsets) for the main buffer and the
+ * sub-buffer respectively, and size1/2 are their sizes
+ *
+ * The macro can be used to protect against wraps.
+ */
+#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size) \
+ (bb_size > 0 && sb_size > 0 && sb_size <= bb_size \
+ && sb >= bb && sb + sb_size <= bb + bb_size && sb + sb_size > bb)
+
+#define CLI_ISCONTAINED2(bb, bb_size, sb, sb_size) \
+ (bb_size > 0 && sb_size >= 0 && sb_size <= bb_size \
+ && sb >= bb && sb + sb_size <= bb + bb_size && sb + sb_size >= bb)
+
+#define CLI_MAX_ALLOCATION 184549376
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h> /* for NAME_MAX */
+#endif
+
+/* Maximum filenames under various systems - njh */
+#ifndef NAME_MAX /* e.g. Linux */
+# ifdef MAXNAMELEN /* e.g. Solaris */
+# define NAME_MAX MAXNAMELEN
+# else
+# ifdef FILENAME_MAX /* e.g. SCO */
+# define NAME_MAX FILENAME_MAX
+# else
+# define NAME_MAX 256
+# endif
+# endif
+#endif
+
+#if NAME_MAX < 256
+#undef NAME_MAX
+#define NAME_MAX 256
+#endif
+
+/* internal clamav context */
+typedef struct {
+ const char **virname;
+ unsigned long int *scanned;
+ const struct cli_matcher *root;
+ const struct cl_engine *engine;
+ const struct cl_limits *limits;
+ unsigned int options;
+ unsigned int arec;
+ unsigned int mrec;
+ unsigned int found_possibly_unwanted;
+ struct cli_dconf *dconf;
+} cli_ctx;
+
+#define SCAN_ARCHIVE (ctx->options & CL_SCAN_ARCHIVE)
+#define SCAN_MAIL (ctx->options & CL_SCAN_MAIL)
+#define SCAN_OLE2 (ctx->options & CL_SCAN_OLE2)
+#define SCAN_PDF (ctx->options & CL_SCAN_PDF)
+#define SCAN_HTML (ctx->options & CL_SCAN_HTML)
+#define SCAN_PE (ctx->options & CL_SCAN_PE)
+#define SCAN_ELF (ctx->options & CL_SCAN_ELF)
+#define SCAN_ALGO (ctx->options & CL_SCAN_ALGORITHMIC)
+#define DETECT_ENCRYPTED (ctx->options & CL_SCAN_BLOCKENCRYPTED)
+#define BLOCKMAX (ctx->options & CL_SCAN_BLOCKMAX)
+#define DETECT_BROKEN (ctx->options & CL_SCAN_BLOCKBROKEN)
+
+#if WORDS_BIGENDIAN == 0
+/* new macros from A. Melnikoff */
+#define le16_to_host(v) (v)
+#define le32_to_host(v) (v)
+#define le64_to_host(v) (v)
+#define be16_to_host(v) ((v >> 8) | ((v & 0xFF) << 8))
+#define be32_to_host(v) ((v >> 24) | ((v & 0x00FF0000) >> 8) | \
+ ((v & 0x0000FF00) << 8) | (v << 24))
+#define be64_to_host(v) ((v >> 56) | ((v & 0x00FF000000000000LL) >> 40) | \
+ ((v & 0x0000FF0000000000LL) >> 24) | \
+ ((v & 0x000000FF00000000LL) >> 8) | \
+ ((v & 0x00000000FF000000LL) << 8) | \
+ ((v & 0x0000000000FF0000LL) << 24) | \
+ ((v & 0x000000000000FF00LL) << 40) | \
+ (v << 56))
+#else
+#define le16_to_host(v) ((v >> 8) | ((v & 0xFF) << 8))
+#define le32_to_host(v) ((v >> 24) | ((v & 0x00FF0000) >> 8) | \
+ ((v & 0x0000FF00) << 8) | (v << 24))
+#define le64_to_host(v) ((v >> 56) | ((v & 0x00FF000000000000LL) >> 40) | \
+ ((v & 0x0000FF0000000000LL) >> 24) | \
+ ((v & 0x000000FF00000000LL) >> 8) | \
+ ((v & 0x00000000FF000000LL) << 8) | \
+ ((v & 0x0000000000FF0000LL) << 24) | \
+ ((v & 0x000000000000FF00LL) << 40) | \
+ (v << 56))
+#define be16_to_host(v) (v)
+#define be32_to_host(v) (v)
+#define be64_to_host(v) (v)
+#endif
+
+/* used by: spin, yc (C) aCaB */
+#define CLI_ROL(a,b) a = ( a << (b % (sizeof(a)<<3) )) | (a >> ( (sizeof(a)<<3) - (b % (sizeof(a)<<3 )) ) )
+#define CLI_ROR(a,b) a = ( a >> (b % (sizeof(a)<<3) )) | (a << ( (sizeof(a)<<3) - (b % (sizeof(a)<<3 )) ) )
+
+/* Implementation independent sign-extended signed right shift */
+#ifdef HAVE_SAR
+#define CLI_SRS(n,s) ((n)>>(s))
+#else
+#define CLI_SRS(n,s) (((n)>>(s)) ^ (1<<(sizeof(n)*8-1-s)) - (1<<(sizeof(n)*8-1-s)))
+#endif
+#define CLI_SAR(n,s) n = CLI_SRS(n,s)
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+typedef struct bitset_tag
+{
+ unsigned char *bitset;
+ unsigned long length;
+} bitset_t;
+
+#ifdef __GNUC__
+void cli_warnmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_warnmsg(const char *str, ...);
+#endif
+
+#ifdef __GNUC__
+void cli_errmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_errmsg(const char *str, ...);
+#endif
+
+#ifdef __GNUC__
+void cli_dbgmsg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void cli_dbgmsg(const char *str, ...);
+#endif
+
+void *cli_malloc(size_t nmemb);
+void *cli_calloc(size_t nmemb, size_t size);
+void *cli_realloc(void *ptr, size_t size);
+void *cli_realloc2(void *ptr, size_t size);
+char *cli_strdup(const char *s);
+int cli_rmdirs(const char *dirname);
+unsigned char *cli_md5digest(int desc);
+char *cli_md5stream(FILE *fs, unsigned char *digcpy);
+char *cli_md5file(const char *filename);
+int cli_readn(int fd, void *buff, unsigned int count);
+int cli_writen(int fd, const void *buff, unsigned int count);
+char *cli_gentemp(const char *dir);
+int cli_gentempfd(const char *dir, char **name, int *fd);
+unsigned int cli_rndnum(unsigned int max);
+int cli_filecopy(const char *src, const char *dest);
+bitset_t *cli_bitset_init(void);
+void cli_bitset_free(bitset_t *bs);
+int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
+int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
+
+#if WORDS_BIGENDIAN == 0
+#define cli_readint32(buff) (*(const int32_t *)(buff))
+#define cli_writeint32(offset, value) (*(uint32_t *)(offset)=(uint32_t)(value))
+#else
+static inline int32_t cli_readint32(const char *buff)
+{
+ int32_t ret;
+ ret = buff[0] & 0xff;
+ ret |= (buff[1] & 0xff) << 8;
+ ret |= (buff[2] & 0xff) << 16;
+ ret |= (buff[3] & 0xff) << 24;
+ return ret;
+}
+
+static inline void cli_writeint32(char *offset, uint32_t value)
+{
+ offset[0] = value & 0xff;
+ offset[1] = (value & 0xff00) >> 8;
+ offset[2] = (value & 0xff0000) >> 16;
+ offset[3] = (value & 0xff000000) >> 24;
+}
+#endif /* WORDS_BIGENDIAN == 0 */
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/output.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/output.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/output.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/output.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __OUTPUT_H
+#define __OUTPUT_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdlib.h>
+#include "cfgparser.h"
+
+int mdprintf(int desc, const char *str, ...);
+
+#ifdef __GNUC__
+int logg(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+int logg(const char *str, ...);
+#endif
+
+void logg_close(void);
+extern short int logg_verbose, logg_lock, logg_time;
+extern unsigned int logg_size;
+extern const char *logg_file;
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+extern short logg_syslog;
+int logg_facility(const char *name);
+#endif
+
+#ifdef __GNUC__
+void mprintf(const char *str, ...) __attribute__((format(printf, 1, 2)));
+#else
+void mprintf(const char *str, ...);
+#endif
+
+extern short int mprintf_disabled, mprintf_verbose, mprintf_quiet, mprintf_stdout;
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/packlibs.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __PACKLIBS_H
+#define __PACKLIBS_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int cli_unfsg(char *, char *, int, int, char **, char **);
+
+int unmew(char *, char *, int, int, char **, char **);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pdf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef __PDF_H
+#define __PDF_H
+
+int cli_pdf(const char *dir, int desc, const cli_ctx *ctx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/pe.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pe.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pe.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pe.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * Implementation (header structures) based on the PE format description
+ * by B. Luevelsmeyer
+ *
+ * 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.
+ */
+
+#ifndef __PE_H
+#define __PE_H
+
+#include "clamav.h"
+#include "execs.h"
+#include "others.h"
+#include "cltypes.h"
+
+struct pe_image_file_hdr {
+ uint32_t Magic;
+ uint16_t Machine;
+ uint16_t NumberOfSections;
+ uint32_t TimeDateStamp; /* unreliable */
+ uint32_t PointerToSymbolTable; /* debug */
+ uint32_t NumberOfSymbols; /* debug */
+ uint16_t SizeOfOptionalHeader; /* == 224 */
+ uint16_t Characteristics;
+};
+
+struct pe_image_data_dir {
+ uint32_t VirtualAddress;
+ uint32_t Size;
+};
+
+struct pe_image_optional_hdr32 {
+ uint16_t Magic;
+ uint8_t MajorLinkerVersion; /* unreliable */
+ uint8_t MinorLinkerVersion; /* unreliable */
+ uint32_t SizeOfCode; /* unreliable */
+ uint32_t SizeOfInitializedData; /* unreliable */
+ uint32_t SizeOfUninitializedData; /* unreliable */
+ uint32_t AddressOfEntryPoint;
+ uint32_t BaseOfCode;
+ uint32_t BaseOfData;
+ uint32_t ImageBase; /* multiple of 64 KB */
+ uint32_t SectionAlignment; /* usually 32 or 4096 */
+ uint32_t FileAlignment; /* usually 32 or 512 */
+ uint16_t MajorOperatingSystemVersion; /* not used */
+ uint16_t MinorOperatingSystemVersion; /* not used */
+ uint16_t MajorImageVersion; /* unreliable */
+ uint16_t MinorImageVersion; /* unreliable */
+ uint16_t MajorSubsystemVersion;
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue; /* ? */
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum; /* NT drivers only */
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint32_t SizeOfStackReserve;
+ uint32_t SizeOfStackCommit;
+ uint32_t SizeOfHeapReserve;
+ uint32_t SizeOfHeapCommit;
+ uint32_t LoaderFlags; /* ? */
+ uint32_t NumberOfRvaAndSizes; /* unreliable */
+ struct pe_image_data_dir DataDirectory[16];
+};
+
+struct pe_image_optional_hdr64 {
+ uint16_t Magic;
+ uint8_t MajorLinkerVersion; /* unreliable */
+ uint8_t MinorLinkerVersion; /* unreliable */
+ uint32_t SizeOfCode; /* unreliable */
+ uint32_t SizeOfInitializedData; /* unreliable */
+ uint32_t SizeOfUninitializedData; /* unreliable */
+ uint32_t AddressOfEntryPoint;
+ uint32_t BaseOfCode;
+ uint64_t ImageBase; /* multiple of 64 KB */
+ uint32_t SectionAlignment; /* usually 32 or 4096 */
+ uint32_t FileAlignment; /* usually 32 or 512 */
+ uint16_t MajorOperatingSystemVersion; /* not used */
+ uint16_t MinorOperatingSystemVersion; /* not used */
+ uint16_t MajorImageVersion; /* unreliable */
+ uint16_t MinorImageVersion; /* unreliable */
+ uint16_t MajorSubsystemVersion;
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue; /* ? */
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum; /* NT drivers only */
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint64_t SizeOfStackReserve;
+ uint64_t SizeOfStackCommit;
+ uint64_t SizeOfHeapReserve;
+ uint64_t SizeOfHeapCommit;
+ uint32_t LoaderFlags; /* ? */
+ uint32_t NumberOfRvaAndSizes; /* unreliable */
+ struct pe_image_data_dir DataDirectory[16];
+};
+
+struct pe_image_section_hdr {
+ uint8_t Name[8]; /* may not end with NULL */
+ /*
+ union {
+ uint32_t PhysicalAddress;
+ uint32_t VirtualSize;
+ } AddrSize;
+ */
+ uint32_t VirtualSize;
+ uint32_t VirtualAddress;
+ uint32_t SizeOfRawData; /* multiple of FileAlignment */
+ uint32_t PointerToRawData; /* offset to the section's data */
+ uint32_t PointerToRelocations; /* object files only */
+ uint32_t PointerToLinenumbers; /* object files only */
+ uint16_t NumberOfRelocations; /* object files only */
+ uint16_t NumberOfLinenumbers; /* object files only */
+ uint32_t Characteristics;
+};
+
+int cli_scanpe(int desc, cli_ctx *ctx);
+
+int cli_peheader(int desc, struct cli_exe_info *peinfo);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/petite.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/petite.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/petite.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/petite.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __PETITE_H
+#define __PETITE_H
+
+#include "cltypes.h"
+#include "pe.h"
+
+int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct cli_exe_section *sections, unsigned int sectcount, uint32_t Imagebase, uint32_t pep, int desc, int version, uint32_t ResRva, uint32_t ResSize);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phish_domaincheck_db.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,34 @@
+/*
+ * Phishing module: domain list implementation.
+ *
+ * Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef _PHISH_DOMAINCHECK_DB_H
+#define _PHISH_DOMAINCHECK_DB_H
+#include "clamav.h"
+
+int init_domainlist(struct cl_engine* engine);
+void domainlist_done(struct cl_engine* engine);
+void domainlist_cleanup(const struct cl_engine* engine);
+int is_domainlist_ok(const struct cl_engine* engine);
+int domainlist_match(const struct cl_engine* engine,char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup, int hostOnly,unsigned short* flags);
+
+#endif
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phish_whitelist.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,35 @@
+/*
+ * Phishing module: whitelist implementation.
+ *
+ * Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef _PHISH_WHITELIST_H
+#define _PHISH_WHITELIST_H
+
+#include "clamav.h"
+
+int init_whitelist(struct cl_engine* engine);
+void whitelist_done(struct cl_engine* engine);
+void whitelist_cleanup(const struct cl_engine* engine);
+int is_whitelist_ok(const struct cl_engine* engine);
+int whitelist_match(const struct cl_engine* engine, char* real_url,const char* display_url,int hostOnly);
+
+#endif
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/phishcheck.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2006-2007 Török Edvin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+
+#ifndef _PHISH_CHECK_H
+#define _PHISH_CHECK_H
+
+#include "regex.h"
+
+#define CL_PHISH_BASE 100
+enum phish_status {CL_PHISH_NODECISION=0,CL_PHISH_CLEAN=CL_PHISH_BASE, CL_PHISH_CLEANUP_OK,CL_PHISH_HOST_OK, CL_PHISH_DOMAIN_OK,
+ CL_PHISH_HOST_NOT_LISTED,
+ CL_PHISH_REDIR_OK, CL_PHISH_HOST_REDIR_OK, CL_PHISH_DOMAIN_REDIR_OK,
+ CL_PHISH_HOST_REVERSE_OK,CL_PHISH_DOMAIN_REVERSE_OK,
+ CL_PHISH_WHITELISTED,CL_PHISH_HOST_WHITELISTED,
+ CL_PHISH_CLEAN_CID,
+ CL_PHISH_TEXTURL, CL_PHISH_MAILTO_OK,
+ CL_PHISH_CLOAKED_UIU, CL_PHISH_NUMERIC_IP,CL_PHISH_HEX_URL,CL_PHISH_CLOAKED_NULL,CL_PHISH_SSL_SPOOF, CL_PHISH_NOMATCH};
+
+#define HOST_SUFFICIENT 1
+#define DOMAIN_SUFFICIENT (HOST_SUFFICIENT | 2)
+#define DO_REVERSE_LOOKUP 4
+#define CHECK_REDIR 8
+#define CHECK_SSL 16
+#define CHECK_CLOAKING 32
+#define CLEANUP_URL 64
+#define CHECK_DOMAIN_REVERSE 128
+#define CHECK_IMG_URL 256
+#define DOMAINLIST_REQUIRED 512
+/* img checking disabled by default */
+
+#define LINKTYPE_IMAGE 1
+
+#define CL_PHISH_ALL_CHECKS (CLEANUP_URL|DOMAIN_SUFFICIENT|CHECK_SSL|CHECK_CLOAKING|CHECK_IMG_URL)
+
+struct string {
+ int refcount;
+ struct string* ref;
+ char* data;
+};
+
+struct phishcheck {
+ regex_t preg;
+ regex_t preg_realurl;
+ regex_t preg_tld;
+ regex_t preg_cctld;
+ regex_t preg_numeric;
+ regex_t preg_hexurl;
+ int is_disabled;
+};
+
+struct pre_fixup_info {
+ /* pre_* url before fixup_spaces */
+ struct string pre_displayLink;
+ size_t host_start;
+ size_t host_end;
+};
+
+struct url_check {
+ struct string realLink;
+ struct string displayLink;
+ struct pre_fixup_info pre_fixup;
+ unsigned short flags;
+ unsigned short always_check_flags;
+ unsigned short link_type;
+};
+
+#ifdef _MESSAGE_H
+int phishingScan(message* m,const char* dir,cli_ctx* ctx,tag_arguments_t* hrefs);
+#endif
+
+void phish_disable(struct cl_engine* engine,const char* reason);
+/* Global, non-thread-safe functions, call only once! */
+int phishing_init(struct cl_engine* engine);
+void phishing_done(struct cl_engine* engine);
+/* end of non-thread-safe functions */
+
+
+#endif
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/pst.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/pst.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/pst.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/pst.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * Based on libpst version 0.5.1, written by Dave Smith, dave.s at earthcorp.com
+ * http://alioth.debian.org/projects/libpst/
+ */
+
+#ifndef __PST_H
+#define __PST_H
+
+int cli_pst(const char *dir, int desc);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/readdb.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __READDB_H
+#define __READDB_H
+
+#include "clamav.h"
+#include "matcher.h"
+
+int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hexsig, unsigned short type, const char *offset, unsigned short target);
+
+int cli_initengine(struct cl_engine **engine, unsigned int options);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/rebuildpe.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __REBUILDPE_H
+#define __REBUILDPE_H
+
+#include "cltypes.h"
+#include "execs.h"
+
+int cli_rebuildpe(char *, struct cli_exe_section *, int, uint32_t, uint32_t, uint32_t, uint32_t, int);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,102 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992 Henry Spencer.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer of the University of Toronto.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regex.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _REGEX_H_
+#define _REGEX_H_
+
+#include <sys/types.h>
+
+/* types */
+typedef off_t regoff_t;
+
+typedef struct {
+ int re_magic;
+ size_t re_nsub; /* number of parenthesized subexpressions */
+ const char *re_endp; /* end pointer for REG_PEND */
+ struct re_guts *re_g; /* none of your business :-) */
+} regex_t;
+
+typedef struct {
+ regoff_t rm_so; /* start of match */
+ regoff_t rm_eo; /* end of match */
+} regmatch_t;
+
+/* cli_regcomp() flags */
+#define REG_BASIC 0000
+#define REG_EXTENDED 0001
+#define REG_ICASE 0002
+#define REG_NOSUB 0004
+#define REG_NEWLINE 0010
+#define REG_NOSPEC 0020
+#define REG_PEND 0040
+#define REG_DUMP 0200
+
+/* cli_regerror() flags */
+#define REG_NOMATCH 1
+#define REG_BADPAT 2
+#define REG_ECOLLATE 3
+#define REG_ECTYPE 4
+#define REG_EESCAPE 5
+#define REG_ESUBREG 6
+#define REG_EBRACK 7
+#define REG_EPAREN 8
+#define REG_EBRACE 9
+#define REG_BADBR 10
+#define REG_ERANGE 11
+#define REG_ESPACE 12
+#define REG_BADRPT 13
+#define REG_EMPTY 14
+#define REG_ASSERT 15
+#define REG_INVARG 16
+#define REG_ATOI 255 /* convert name to number (!) */
+#define REG_ITOA 0400 /* convert number to name (!) */
+
+/* cli_regexec() flags */
+#define REG_NOTBOL 00001
+#define REG_NOTEOL 00002
+#define REG_STARTEND 00004
+#define REG_TRACE 00400 /* tracing of execution */
+#define REG_LARGE 01000 /* force large representation */
+#define REG_BACKR 02000 /* force use of backref code */
+
+int cli_regcomp(regex_t *, const char *, int);
+size_t cli_regerror(int, const regex_t *, char *, size_t);
+int cli_regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
+void cli_regfree(regex_t *);
+size_t cli_strlcpy(char *dst, const char *src, size_t siz);
+
+#endif /* !_REGEX_H_ */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex2.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,157 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)regex2.h 8.4 (Berkeley) 3/20/94
+ */
+
+/*
+ * internals of regex_t
+ */
+#define MAGIC1 ((('r'^0200)<<8) | 'e')
+
+/*
+ * The internal representation is a *strip*, a sequence of
+ * operators ending with an endmarker. (Some terminology etc. is a
+ * historical relic of earlier versions which used multiple strips.)
+ * Certain oddities in the representation are there to permit running
+ * the machinery backwards; in particular, any deviation from sequential
+ * flow must be marked at both its source and its destination. Some
+ * fine points:
+ *
+ * - OPLUS_ and O_PLUS are *inside* the loop they create.
+ * - OQUEST_ and O_QUEST are *outside* the bypass they create.
+ * - OCH_ and O_CH are *outside* the multi-way branch they create, while
+ * OOR1 and OOR2 are respectively the end and the beginning of one of
+ * the branches. Note that there is an implicit OOR2 following OCH_
+ * and an implicit OOR1 preceding O_CH.
+ *
+ * In state representations, an operator's bit is on to signify a state
+ * immediately *preceding* "execution" of that operator.
+ */
+typedef unsigned long sop; /* strip operator */
+typedef long sopno;
+#define OPRMASK 0xf8000000LU
+#define OPDMASK 0x07ffffffLU
+#define OPSHIFT ((unsigned)27)
+#define OP(n) ((n)&OPRMASK)
+#define OPND(n) ((n)&OPDMASK)
+#define SOP(op, opnd) ((op)|(opnd))
+/* operators meaning operand */
+/* (back, fwd are offsets) */
+#define OEND (1LU<<OPSHIFT) /* endmarker - */
+#define OCHAR (2LU<<OPSHIFT) /* character unsigned char */
+#define OBOL (3LU<<OPSHIFT) /* left anchor - */
+#define OEOL (4LU<<OPSHIFT) /* right anchor - */
+#define OANY (5LU<<OPSHIFT) /* . - */
+#define OANYOF (6LU<<OPSHIFT) /* [...] set number */
+#define OBACK_ (7LU<<OPSHIFT) /* begin \d paren number */
+#define O_BACK (8LU<<OPSHIFT) /* end \d paren number */
+#define OPLUS_ (9LU<<OPSHIFT) /* + prefix fwd to suffix */
+#define O_PLUS (10LU<<OPSHIFT) /* + suffix back to prefix */
+#define OQUEST_ (11LU<<OPSHIFT) /* ? prefix fwd to suffix */
+#define O_QUEST (12LU<<OPSHIFT) /* ? suffix back to prefix */
+#define OLPAREN (13LU<<OPSHIFT) /* ( fwd to ) */
+#define ORPAREN (14LU<<OPSHIFT) /* ) back to ( */
+#define OCH_ (15LU<<OPSHIFT) /* begin choice fwd to OOR2 */
+#define OOR1 (16LU<<OPSHIFT) /* | pt. 1 back to OOR1 or OCH_ */
+#define OOR2 (17LU<<OPSHIFT) /* | pt. 2 fwd to OOR2 or O_CH */
+#define O_CH (18LU<<OPSHIFT) /* end choice back to OOR1 */
+#define OBOW (19LU<<OPSHIFT) /* begin word - */
+#define OEOW (20LU<<OPSHIFT) /* end word - */
+
+/*
+ * Structure for [] character-set representation. Character sets are
+ * done as bit vectors, grouped 8 to a byte vector for compactness.
+ * The individual set therefore has both a pointer to the byte vector
+ * and a mask to pick out the relevant bit of each byte. A hash code
+ * simplifies testing whether two sets could be identical.
+ *
+ * This will get trickier for multicharacter collating elements. As
+ * preliminary hooks for dealing with such things, we also carry along
+ * a string of multi-character elements, and decide the size of the
+ * vectors at run time.
+ */
+typedef struct {
+ uch *ptr; /* -> uch [csetsize] */
+ uch mask; /* bit within array */
+ uch hash; /* hash code */
+ size_t smultis;
+ char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */
+} cset;
+/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */
+#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c))
+#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c))
+#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask)
+#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* cli_regcomp() internal fns */
+#define MCsub(p, cs, cp) mcsub(p, cs, cp)
+#define MCin(p, cs, cp) mcin(p, cs, cp)
+
+/* stuff for character categories */
+typedef unsigned char cat_t;
+
+/*
+ * main compiled-expression structure
+ */
+struct re_guts {
+ int magic;
+# define MAGIC2 ((('R'^0200)<<8)|'E')
+ sop *strip; /* malloced area for strip */
+ int csetsize; /* number of bits in a cset vector */
+ int ncsets; /* number of csets in use */
+ cset *sets; /* -> cset [ncsets] */
+ uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */
+ int cflags; /* copy of cli_regcomp() cflags argument */
+ sopno nstates; /* = number of sops */
+ sopno firststate; /* the initial OEND (normally 0) */
+ sopno laststate; /* the final OEND */
+ int iflags; /* internal flags */
+# define USEBOL 01 /* used ^ */
+# define USEEOL 02 /* used $ */
+# define BAD 04 /* something wrong */
+ int nbol; /* number of ^ used */
+ int neol; /* number of $ used */
+ int ncategories; /* how many character categories */
+ cat_t *categories; /* ->catspace[-CHAR_MIN] */
+ char *must; /* match must contain this string */
+ int mlen; /* length of must */
+ size_t nsub; /* copy of re_nsub */
+ int backrefs; /* does it use back references? */
+ sopno nplus; /* how deep does it nest +s? */
+ /* catspace must be last */
+ cat_t catspace[1]; /* actually [NC] */
+};
+
+/* misc utilities */
+#define OUT (CHAR_MAX+1) /* a non-character value */
+#define ISWORD(c) (isalnum(c) || (c) == '_')
Added: test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/regex_list.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,63 @@
+/*
+ * Match a string against a list of patterns/regexes.
+ *
+ * Copyright (C) 2006 Török Edvin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef _REGEX_LIST_H
+#define _REGEX_LIST_H
+
+#ifdef NDEBUG
+#define massert(x) (void)(0)
+#else
+/*debug version, massert enabled*/
+
+#define __massert_fail(expr,file,line) (void)cli_errmsg("Assertion failed at %s:%d\n %s\n",file,line,expr)
+
+#define massert(expr) ((void) ((expr) ? (void)0 : (__massert_fail (#expr,__FILE__,__LINE__))))
+#endif
+
+#include "phishcheck.h"
+struct node_stack {
+ struct tree_node** data;
+ size_t capacity;
+ size_t cnt;
+};
+
+struct regex_matcher {
+ struct cli_matcher* root_hosts;
+ struct tree_node* root_regex;
+ struct tree_node* root_regex_hostonly;
+ size_t root_hosts_cnt;
+ int list_inited;
+ int list_loaded;
+ int list_built;
+ struct node_stack node_stack;
+ struct node_stack node_stack_alt;
+};
+
+int regex_list_match(struct regex_matcher* matcher, char* real_url,const char* display_url,const struct pre_fixup_info* pre_fixup, int hostOnly,const char** info,int is_whitelist);
+int init_regex_list(struct regex_matcher* matcher);
+int load_regex_matcher(struct regex_matcher* matcher,FILE* fd,unsigned int options,int is_whitelist);
+void regex_list_cleanup(struct regex_matcher* matcher);
+void regex_list_done(struct regex_matcher* matcher);
+int is_regex_ok(struct regex_matcher* matcher);
+
+#endif
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/rtf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Török Edwin <edwin at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _RTF_H
+#define _RTF_H
+
+#include "others.h"
+
+int cli_scanrtf(int desc, cli_ctx *ctx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scanners.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2002 - 2004 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __SCANNERS_H
+#define __SCANNERS_H
+
+#include "clamav.h"
+#include "others.h"
+
+int cli_magic_scandesc(int desc, cli_ctx *ctx);
+
+int cli_scandir(const char *dirname, cli_ctx *ctx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/header_rename.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,4 @@
+#!/bin/sh
+# usage: find svn -name \*.h -exec sh header_rename.sh {} include/ \;
+FILE=`basename "$1"`
+cp $1 $FILE
Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,46 @@
+#!/bin/sh
+BASEURL=http://svn.clamav.net/svn/clamav-devel/tags/clamav-0.92/
+if test $# != 1; then
+ echo "Usage: $0 <checkout|update|copy>"
+ exit 1
+fi
+if [ $1 = "checkout" ]; then
+ mkdir svn &&
+ echo "Checking out ClamAV from $BASEURL ... to directory svn" &&
+ cd svn && svn co $BASEURL/clamscan $BASEURL/libclamav $BASEURL/shared $BASEURL/test . &&
+ svn cat $BASEURL/COPYING >./COPYING &&
+ cd .. &&
+ echo "Checkout complete" &&
+ sh remove.sh &&
+ echo "done"
+elif [ $1 = "update" ]; then
+ echo "svn up" &&
+ svn up svn/clamscan svn/libclamav svn/shared svn/test &&
+ sh remove.sh &&
+ echo "done"
+elif [ $1 = "getdb" ]; then
+ wget http://database.clamav.net/main.cvd http://database.clamav.net/daily.cvd -P dbdir/
+elif [ $1 = "copy" ]; then
+ echo "Copying&renaming files ..." &&
+# special handling for clamscan/others.h, because we also have a libclamav/others.h
+ mv svn/clamscan/others.h clamscan_others.h &&
+ find svn -name '*.c' -exec sh rename.sh {} . \; &&
+ find svn -name '*.h' -exec sh header_rename.sh {} . \; &&
+ for i in clamscan_*.c; do
+ sed -ie "s/\"others.h\"/\"clamscan_others.h\"/" $i;
+ done &&
+#flatten hierarchy
+ for i in *.[ch]; do
+ sed -re 's/^(#include *")[^/]+\/([^"]+")/\1\2/g' -i $i;
+ done &&
+ cp svn/COPYING . &&
+ #special case, regexec.c #includes a .c file directly, preserve name
+ mv libclamav_regex_engine.c engine.c &&
+ sed -re 's/MSGCODE\("LibClamAV debug: "\)/puts\(str\)/g' -i libclamav_others.c &&
+ touch target.h &&
+ mkdir -p inputs &&
+ cp svn/test/* inputs/
+ echo "All files copied, you can now safely remove the directory svn"
+ # clamscan/ files must include others.h from clamscan/ and not from libclamav unless explicitly specified in #include!
+fi
+
Propchange: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/prepare.sh
------------------------------------------------------------------------------
svn:executable = *
Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/remove.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,15 @@
+#!/bin/sh
+echo "Removing unnecessary files" &&
+ pwd &&
+ rm -rf svn/libclamav/js svn/libclamav/pst.c &&
+ cat >svn/libclamav/pst.c <<EOF
+#include "clamav-config.h"
+#include "clamav.h"
+int
+cli_pst(const char *dir, int desc)
+{
+ cli_warnmsg("PST files not yet supported\n");
+ return CL_EFORMAT;
+}
+EOF
+# pst.c is huge, and is experimental, don't compile it
Added: test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/scripts/rename.sh Wed Jan 30 15:17:10 2008
@@ -0,0 +1,4 @@
+#!/bin/sh
+#usage: find svn -name *.c -exec sh rename.sh {} . \;
+FILE=`echo "$1" | sed -e 's/svn\///' | sed -e 's/\//_/g'`
+cp $1 $FILE
Added: test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/sha256.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2001 Niels Moller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef __SHA256_H
+#define __SHA256_H
+
+#include "cltypes.h"
+
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_DATA_SIZE 64
+
+/* Digest is kept internally as 8 32-bit words. */
+#define _SHA256_DIGEST_LENGTH 8
+
+typedef struct sha256_ctx
+{
+ uint32_t state[_SHA256_DIGEST_LENGTH]; /* State variables */
+ uint32_t count_low, count_high; /* 64-bit block count */
+ unsigned char block[SHA256_DATA_SIZE]; /* SHA256 data buffer */
+ uint32_t index; /* index into buffer */
+} SHA256_CTX;
+
+void
+sha256_init(struct sha256_ctx *ctx);
+
+void
+sha256_update(struct sha256_ctx *ctx, const unsigned char *data, uint32_t length);
+
+void
+sha256_final(struct sha256_ctx *ctx);
+
+void
+sha256_digest(const struct sha256_ctx *ctx, unsigned char *digest);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_cdiff.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * (C) 2007 Tomasz Kojm <tkojm at clamav.net>
+ * Written by Tomasz Kojm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "misc.h"
+#include "output.h"
+#include "cdiff.h"
+#include "sha256.h"
+
+#include "str.h"
+#include "others.h"
+#include "cvd.h"
+
+#include "zlib.h"
+
+#ifdef HAVE_GMP
+#include "dsig.h"
+
+#define PSS_NSTR "14783905874077467090262228516557917570254599638376203532031989214105552847269687489771975792123442185817287694951949800908791527542017115600501303394778618535864845235700041590056318230102449612217458549016089313306591388590790796515819654102320725712300822356348724011232654837503241736177907784198700834440681124727060540035754699658105895050096576226753008596881698828185652424901921668758326578462003247906470982092298106789657211905488986281078346361469524484829559560886227198091995498440676639639830463593211386055065360288422394053998134458623712540683294034953818412458362198117811990006021989844180721010947"
+#define PSS_ESTR "100002053"
+#define PSS_NBITS 2048
+#define PSS_DIGEST_LENGTH 32
+#endif /* HAVE_GMP */
+
+struct cdiff_node {
+ unsigned int lineno;
+ char *str, *str2;
+ struct cdiff_node *next;
+};
+
+struct cdiff_ctx {
+ char *open_db;
+ struct cdiff_node *add_start, *add_last;
+ struct cdiff_node *del_start;
+ struct cdiff_node *xchg_start;
+};
+
+struct cdiff_cmd {
+ const char *name;
+ unsigned short argc;
+ int (*handler)(const char *, struct cdiff_ctx *);
+};
+
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx);
+static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx);
+
+static struct cdiff_cmd commands[] = {
+ /* OPEN db_name */
+ { "OPEN", 1, &cdiff_cmd_open },
+
+ /* ADD newsig */
+ { "ADD", 1, &cdiff_cmd_add },
+
+ /* DEL line_no some_first_bytes */
+ { "DEL", 2, &cdiff_cmd_del },
+
+ /* XCHG line_no some_first_bytes_of_old_line new_line */
+ { "XCHG", 3, &cdiff_cmd_xchg },
+
+ /* CLOSE */
+ { "CLOSE", 0, &cdiff_cmd_close },
+
+ /* MOVE src_db dst_db start_line first_16b end_line first_16b */
+ { "MOVE", 6, &cdiff_cmd_move },
+
+ /* UNLINK db_name */
+ { "UNLINK", 1, &cdiff_cmd_unlink },
+
+ { NULL, 0, NULL }
+};
+
+static void cdiff_ctx_free(struct cdiff_ctx *ctx)
+{
+ struct cdiff_node *pt;
+
+
+ if(ctx->open_db) {
+ free(ctx->open_db);
+ ctx->open_db = NULL;
+ }
+
+ while(ctx->add_start) {
+ free(ctx->add_start->str);
+ pt = ctx->add_start;
+ ctx->add_start = ctx->add_start->next;
+ free(pt);
+ }
+ ctx->add_last = NULL;
+
+ while(ctx->del_start) {
+ free(ctx->del_start->str);
+ pt = ctx->del_start;
+ ctx->del_start = ctx->del_start->next;
+ free(pt);
+ }
+
+ while(ctx->xchg_start) {
+ free(ctx->xchg_start->str);
+ free(ctx->xchg_start->str2);
+ pt = ctx->xchg_start;
+ ctx->xchg_start = ctx->xchg_start->next;
+ free(pt);
+ }
+}
+
+static char *cdiff_token(const char *line, unsigned int token, unsigned int last)
+{
+ unsigned int counter = 0, i, j;
+ char *buffer;
+
+
+ for(i = 0; line[i] && counter != token; i++)
+ if(line[i] == ' ')
+ counter++;
+
+ if(!line[i])
+ return NULL;
+
+ if(last)
+ return strdup(&line[i]);
+
+ for(j = i; line[j]; j++)
+ if(line[j] == ' ')
+ break;
+
+ if(i == j)
+ return NULL;
+
+ buffer = malloc(j - i + 1);
+ if(!buffer)
+ return NULL;
+
+ strncpy(buffer, line + i, j - i);
+ buffer[j - i] = '\0';
+
+ return buffer;
+}
+
+static int cdiff_cmd_open(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *db;
+ unsigned int i;
+
+
+ if(!(db = cdiff_token(cmdstr, 1, 1))) {
+ logg("!cdiff_cmd_open: Can't get first argument\n");
+ return -1;
+ }
+
+ if(ctx->open_db) {
+ logg("!cdiff_cmd_open: %s not closed before opening %s\n", ctx->open_db, db);
+ free(db);
+ return -1;
+ }
+
+ for(i = 0; i < strlen(db); i++) {
+ if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
+ logg("!cdiff_cmd_open: Forbidden characters found in database name\n");
+ free(db);
+ return -1;
+ }
+ }
+
+ ctx->open_db = db;
+ return 0;
+}
+
+static int cdiff_cmd_add(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *sig;
+ struct cdiff_node *new;
+
+
+ if(!(sig = cdiff_token(cmdstr, 1, 1))) {
+ logg("!cdiff_cmd_add: Can't get first argument\n");
+ return -1;
+ }
+
+ new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+ if(!new) {
+ logg("!cdiff_cmd_add: Can't allocate memory for cdiff_node\n");
+ free(sig);
+ return -1;
+ }
+ new->str = sig;
+
+ if(!ctx->add_last) {
+ ctx->add_start = ctx->add_last = new;
+ } else {
+ ctx->add_last->next = new;
+ ctx->add_last = new;
+ }
+
+ return 0;
+}
+
+static int cdiff_cmd_del(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *arg;
+ struct cdiff_node *pt, *last, *new;
+ unsigned int lineno;
+
+
+ if(!(arg = cdiff_token(cmdstr, 1, 0))) {
+ logg("!cdiff_cmd_del: Can't get first argument\n");
+ return -1;
+ }
+ lineno = (unsigned int) atoi(arg);
+ free(arg);
+
+ if(!(arg = cdiff_token(cmdstr, 2, 1))) {
+ logg("!cdiff_cmd_del: Can't get second argument\n");
+ return -1;
+ }
+
+ new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+ if(!new) {
+ logg("!cdiff_cmd_del: Can't allocate memory for cdiff_node\n");
+ free(arg);
+ return -1;
+ }
+ new->str = arg;
+ new->lineno = lineno;
+
+ if(!ctx->del_start) {
+
+ ctx->del_start = new;
+
+ } else {
+
+ if(lineno < ctx->del_start->lineno) {
+ new->next = ctx->del_start;
+ ctx->del_start = new;
+
+ } else {
+ pt = ctx->del_start;
+
+ while(pt) {
+ last = pt;
+ if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
+ break;
+
+ pt = pt->next;
+ }
+
+ new->next = last->next;
+ last->next = new;
+ }
+ }
+
+ return 0;
+}
+
+static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *arg, *arg2;
+ struct cdiff_node *pt, *last, *new;
+ unsigned int lineno;
+
+
+ if(!(arg = cdiff_token(cmdstr, 1, 0))) {
+ logg("!cdiff_cmd_xchg: Can't get first argument\n");
+ return -1;
+ }
+ lineno = (unsigned int) atoi(arg);
+ free(arg);
+
+ if(!(arg = cdiff_token(cmdstr, 2, 0))) {
+ logg("!cdiff_cmd_xchg: Can't get second argument\n");
+ return -1;
+ }
+
+ if(!(arg2 = cdiff_token(cmdstr, 3, 1))) {
+ free(arg);
+ logg("!cdiff_cmd_xchg: Can't get second argument\n");
+ return -1;
+ }
+
+ new = (struct cdiff_node *) calloc(1, sizeof(struct cdiff_node));
+ if(!new) {
+ logg("!cdiff_cmd_xchg: Can't allocate memory for cdiff_node\n");
+ free(arg);
+ free(arg2);
+ return -1;
+ }
+ new->str = arg;
+ new->str2 = arg2;
+ new->lineno = lineno;
+
+ if(!ctx->xchg_start) {
+
+ ctx->xchg_start = new;
+
+ } else {
+
+ if(lineno < ctx->xchg_start->lineno) {
+ new->next = ctx->xchg_start;
+ ctx->xchg_start = new;
+
+ } else {
+ pt = ctx->xchg_start;
+
+ while(pt) {
+ last = pt;
+ if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
+ break;
+
+ pt = pt->next;
+ }
+
+ new->next = last->next;
+ last->next = new;
+ }
+ }
+
+ return 0;
+}
+
+static int cdiff_cmd_close(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ struct cdiff_node *add, *del, *xchg;
+ unsigned int lines = 0;
+ char *tmp, line[1024];
+ FILE *fh, *tmpfh;
+
+
+ if(!ctx->open_db) {
+ logg("!cdiff_cmd_close: No database to close\n");
+ return -1;
+ }
+
+ add = ctx->add_start;
+ del = ctx->del_start;
+ xchg = ctx->xchg_start;
+
+ if(del || xchg) {
+
+ if(!(fh = fopen(ctx->open_db, "r"))) {
+ logg("!cdiff_cmd_close: Can't open file %s for reading\n", ctx->open_db);
+ return -1;
+ }
+
+ if(!(tmp = cli_gentemp("."))) {
+ logg("!cdiff_cmd_close: Can't generate temporary name\n");
+ fclose(fh);
+ return -1;
+ }
+
+ if(!(tmpfh = fopen(tmp, "w"))) {
+ logg("!cdiff_cmd_close: Can't open file %s for writing\n", tmp);
+ fclose(fh);
+ free(tmp);
+ return -1;
+ }
+
+ while(fgets(line, sizeof(line), fh)) {
+ lines++;
+
+ if(del && del->lineno == lines) {
+ if(strncmp(line, del->str, strlen(del->str))) {
+ fclose(fh);
+ fclose(tmpfh);
+ unlink(tmp);
+ free(tmp);
+ logg("!cdiff_cmd_close: Can't apply DEL at line %d of %s\n", lines, ctx->open_db);
+ return -1;
+ }
+
+ del = del->next;
+ continue;
+ }
+
+ if(xchg && xchg->lineno == lines) {
+ if(strncmp(line, xchg->str, strlen(xchg->str))) {
+ fclose(fh);
+ fclose(tmpfh);
+ unlink(tmp);
+ free(tmp);
+ logg("!cdiff_cmd_close: Can't apply XCHG at line %d of %s\n", lines, ctx->open_db);
+ return -1;
+ }
+
+ if(fputs(xchg->str2, tmpfh) == EOF || fputc('\n', tmpfh) == EOF) {
+ fclose(fh);
+ fclose(tmpfh);
+ unlink(tmp);
+ logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
+ free(tmp);
+ return -1;
+ }
+ xchg = xchg->next;
+ continue;
+ }
+
+ if(fputs(line, tmpfh) == EOF) {
+ fclose(fh);
+ fclose(tmpfh);
+ unlink(tmp);
+ logg("!cdiff_cmd_close: Can't write to %s\n", tmp);
+ free(tmp);
+ return -1;
+ }
+ }
+
+ fclose(fh);
+ fclose(tmpfh);
+
+ if(del || xchg) {
+ logg("!cdiff_cmd_close: Not all DEL/XCHG have been executed\n");
+ unlink(tmp);
+ free(tmp);
+ return -1;
+ }
+
+ if(unlink(ctx->open_db) == -1) {
+ logg("!cdiff_cmd_close: Can't unlink %s\n", ctx->open_db);
+ unlink(tmp);
+ free(tmp);
+ return -1;
+ }
+
+ if(rename(tmp, ctx->open_db) == -1) {
+ logg("!cdiff_cmd_close: Can't rename %s to %s\n", tmp, ctx->open_db);
+ unlink(tmp);
+ free(tmp);
+ return -1;
+ }
+
+ free(tmp);
+ }
+
+ if(add) {
+
+ if(!(fh = fopen(ctx->open_db, "a"))) {
+ logg("!cdiff_cmd_close: Can't open file %s for appending\n", ctx->open_db);
+ return -1;
+ }
+
+ while(add) {
+ if(fputs(add->str, fh) == EOF || fputc('\n', fh) == EOF) {
+ fclose(fh);
+ logg("!cdiff_cmd_close: Can't write to %s\n", ctx->open_db);
+ return -1;
+ }
+ add = add->next;
+ }
+
+ fclose(fh);
+ }
+
+ cdiff_ctx_free(ctx);
+
+ return 0;
+}
+
+static int cdiff_cmd_move(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ unsigned int lines = 0, start_line, end_line;
+ char *arg, *srcdb, *dstdb, *tmpdb, line[1024], *start_str, *end_str;
+ FILE *src, *dst, *tmp;
+
+
+ if(ctx->open_db) {
+ logg("!cdiff_cmd_move: Database %s is still open\n", ctx->open_db);
+ return -1;
+ }
+
+ if(!(arg = cdiff_token(cmdstr, 3, 0))) {
+ logg("!cdiff_cmd_move: Can't get third argument\n");
+ return -1;
+ }
+ start_line = atoi(arg);
+ free(arg);
+
+ if(!(arg = cdiff_token(cmdstr, 5, 0))) {
+ logg("!cdiff_cmd_move: Can't get fifth argument\n");
+ return -1;
+ }
+ end_line = atoi(arg);
+ free(arg);
+
+ if(end_line < start_line) {
+ logg("!cdiff_cmd_move: end_line < start_line\n");
+ return -1;
+ }
+
+ if(!(start_str = cdiff_token(cmdstr, 4, 0))) {
+ logg("!cdiff_cmd_move: Can't get fourth argument\n");
+ return -1;
+ }
+
+ if(!(end_str = cdiff_token(cmdstr, 6, 0))) {
+ logg("!cdiff_cmd_move: Can't get sixth argument\n");
+ free(start_str);
+ return -1;
+ }
+
+ if(!(srcdb = cdiff_token(cmdstr, 1, 0))) {
+ logg("!cdiff_cmd_move: Can't get first argument\n");
+ free(start_str);
+ free(end_str);
+ return -1;
+ }
+
+ if(!(src = fopen(srcdb, "r"))) {
+ logg("!cdiff_cmd_move: Can't open %s for reading\n", srcdb);
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ return -1;
+ }
+
+ if(!(dstdb = cdiff_token(cmdstr, 2, 0))) {
+ logg("!cdiff_cmd_move: Can't get second argument\n");
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ return -1;
+ }
+
+ if(!(dst = fopen(dstdb, "a"))) {
+ logg("!cdiff_cmd_move: Can't open %s for appending\n", dstdb);
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ free(dstdb);
+ return -1;
+ }
+
+ if(!(tmpdb = cli_gentemp("."))) {
+ logg("!cdiff_cmd_move: Can't generate temporary name\n");
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ free(dstdb);
+ fclose(dst);
+ return -1;
+ }
+
+ if(!(tmp = fopen(tmpdb, "w"))) {
+ logg("!cdiff_cmd_move: Can't open file %s for writing\n", tmpdb);
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ free(dstdb);
+ fclose(dst);
+ free(tmpdb);
+ return -1;
+ }
+
+ while(fgets(line, sizeof(line), src)) {
+ lines++;
+
+ if(lines == start_line) {
+ if(strncmp(line, start_str, strlen(start_str))) {
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ free(dstdb);
+ fclose(dst);
+ fclose(tmp);
+ unlink(tmpdb);
+ free(tmpdb);
+ logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
+ return -1;
+ }
+
+ do {
+ if(fputs(line, dst) == EOF) {
+ free(start_str);
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ fclose(dst);
+ fclose(tmp);
+ unlink(tmpdb);
+ free(tmpdb);
+ logg("!cdiff_cmd_move: Can't write to %s\n", dstdb);
+ free(dstdb);
+ return -1;
+ }
+ } while((lines < end_line) && fgets(line, sizeof(line), src) && lines++);
+
+ fclose(dst);
+ free(dstdb);
+ dstdb = NULL;
+ free(start_str);
+
+ if(strncmp(line, end_str, strlen(end_str))) {
+ free(end_str);
+ free(srcdb);
+ fclose(src);
+ fclose(tmp);
+ unlink(tmpdb);
+ free(tmpdb);
+ logg("!cdiff_cmd_close: Can't apply MOVE due to conflict at line %d\n", lines);
+ return -1;
+ }
+
+ free(end_str);
+ continue;
+ }
+
+ if(fputs(line, tmp) == EOF) {
+ free(srcdb);
+ fclose(src);
+ fclose(tmp);
+ unlink(tmpdb);
+ logg("!cdiff_cmd_move: Can't write to %s\n", tmpdb);
+ free(tmpdb);
+ return -1;
+ }
+ }
+
+ fclose(src);
+ fclose(tmp);
+
+ if(dstdb) {
+ fclose(dst);
+ free(start_str);
+ free(end_str);
+ unlink(tmpdb);
+ free(tmpdb);
+ logg("!cdiff_cmd_move: No data was moved from %s to %s\n", srcdb, dstdb);
+ free(srcdb);
+ free(dstdb);
+ return -1;
+ }
+
+ if(unlink(srcdb) == -1) {
+ logg("!cdiff_cmd_move: Can't unlink %s\n", srcdb);
+ free(srcdb);
+ unlink(tmpdb);
+ free(tmpdb);
+ return -1;
+ }
+
+ if(rename(tmpdb, srcdb) == -1) {
+ logg("!cdiff_cmd_move: Can't rename %s to %s\n", tmpdb, srcdb);
+ free(srcdb);
+ unlink(tmpdb);
+ free(tmpdb);
+ return -1;
+ }
+
+ free(srcdb);
+ free(tmpdb);
+
+ return 0;
+}
+
+static int cdiff_cmd_unlink(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *db;
+ unsigned int i;
+
+
+ if(ctx->open_db) {
+ logg("!cdiff_cmd_unlink: Database %s is still open\n", ctx->open_db);
+ return -1;
+ }
+
+ if(!(db = cdiff_token(cmdstr, 1, 1))) {
+ logg("!cdiff_cmd_unlink: Can't get first argument\n");
+ return -1;
+ }
+
+ for(i = 0; i < strlen(db); i++) {
+ if((db[i] != '.' && !isalnum(db[i])) || strchr("/\\", db[i])) {
+ logg("!cdiff_cmd_unlink: Forbidden characters found in database name\n");
+ free(db);
+ return -1;
+ }
+ }
+
+ if(unlink(db) == -1) {
+ logg("!cdiff_cmd_unlink: Can't unlink %s\n", db);
+ free(db);
+ return -1;
+ }
+
+ free(db);
+ return 0;
+}
+
+static int cdiff_execute(const char *cmdstr, struct cdiff_ctx *ctx)
+{
+ char *cmd_name, *tmp;
+ int (*cmd_handler)(const char *, struct cdiff_ctx *) = NULL;
+ unsigned int i;
+
+
+ cmd_name = cdiff_token(cmdstr, 0, 0);
+ if(!cmd_name) {
+ logg("!cdiff_apply: Problem parsing line\n");
+ return -1;
+ }
+
+ for(i = 0; commands[i].name; i++) {
+ if(!strcmp(commands[i].name, cmd_name)) {
+ cmd_handler = commands[i].handler;
+ break;
+ }
+ }
+
+ if(!cmd_handler) {
+ logg("!cdiff_apply: Unknown command %s\n", cmd_name);
+ free(cmd_name);
+ return -1;
+ }
+
+ if(!(tmp = cdiff_token(cmdstr, commands[i].argc, 1))) {
+ logg("!cdiff_apply: Not enough arguments for %s\n", cmd_name);
+ free(cmd_name);
+ return -1;
+ }
+ free(tmp);
+
+ if(cmd_handler(cmdstr, ctx)) {
+ logg("!cdiff_apply: Can't execute command %s\n", cmd_name);
+ free(cmd_name);
+ return -1;
+ }
+
+ free(cmd_name);
+ return 0;
+}
+
+#ifdef HAVE_GMP
+static void pss_mgf(unsigned char *in, unsigned int inlen, unsigned char *out, unsigned int outlen)
+{
+ SHA256_CTX ctx;
+ unsigned int i, laps;
+ unsigned char cnt[4], digest[PSS_DIGEST_LENGTH];
+
+
+ laps = (outlen + PSS_DIGEST_LENGTH - 1) / PSS_DIGEST_LENGTH;
+
+ for(i = 0; i < laps; i++) {
+ cnt[0] = (unsigned char) 0;
+ cnt[1] = (unsigned char) 0;
+ cnt[2] = (unsigned char) (i / 256);
+ cnt[3] = (unsigned char) i;
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, in, inlen);
+ sha256_update(&ctx, cnt, sizeof(cnt));
+ sha256_final(&ctx);
+ sha256_digest(&ctx, digest);
+
+ if(i != laps - 1)
+ memcpy(&out[i * PSS_DIGEST_LENGTH], digest, PSS_DIGEST_LENGTH);
+ else
+ memcpy(&out[i * PSS_DIGEST_LENGTH], digest, outlen - i * PSS_DIGEST_LENGTH);
+ }
+}
+
+static int pss_versig(const unsigned char *sha256, const char *dsig)
+{
+ mpz_t n, e;
+ SHA256_CTX ctx;
+ unsigned char *pt, digest1[PSS_DIGEST_LENGTH], digest2[PSS_DIGEST_LENGTH], *salt;
+ unsigned int plen = PSS_NBITS / 8, hlen, slen, i;
+ unsigned char dblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
+ unsigned char mblock[PSS_NBITS / 8 - PSS_DIGEST_LENGTH - 1];
+ unsigned char fblock[8 + 2 * PSS_DIGEST_LENGTH];
+
+
+ hlen = slen = PSS_DIGEST_LENGTH;
+ mpz_init_set_str(n, PSS_NSTR, 10);
+ mpz_init_set_str(e, PSS_ESTR, 10);
+
+ if(!(pt = cli_decodesig(dsig, plen, e, n))) {
+ mpz_clear(n);
+ mpz_clear(e);
+ return -1;
+ }
+
+ mpz_clear(n);
+ mpz_clear(e);
+
+ if(pt[plen - 1] != 0xbc) {
+ /* cli_dbgmsg("cli_versigpss: Incorrect signature syntax (0xbc)\n"); */
+ free(pt);
+ return -1;
+ }
+
+ memcpy(mblock, pt, plen - hlen - 1);
+ memcpy(digest2, &pt[plen - hlen - 1], hlen);
+ free(pt);
+
+ pss_mgf(digest2, hlen, dblock, plen - hlen - 1);
+
+ for(i = 0; i < plen - hlen - 1; i++)
+ dblock[i] ^= mblock[i];
+
+ dblock[0] &= (0xff >> 1);
+
+ salt = memchr(dblock, 0x01, sizeof(dblock));
+ if(!salt) {
+ /* cli_dbgmsg("cli_versigpss: Can't find salt\n"); */
+ return -1;
+ }
+ salt++;
+
+ if((unsigned int) (dblock + sizeof(dblock) - salt) != slen) {
+ /* cli_dbgmsg("cli_versigpss: Bad salt size\n"); */
+ return -1;
+ }
+
+ memset(fblock, 0, 8);
+ memcpy(&fblock[8], sha256, hlen);
+ memcpy(&fblock[8 + hlen], salt, slen);
+
+ sha256_init(&ctx);
+ sha256_update(&ctx, fblock, sizeof(fblock));
+ sha256_final(&ctx);
+ sha256_digest(&ctx, digest1);
+
+ if(memcmp(digest1, digest2, hlen)) {
+ /* cli_dbgmsg("cli_versigpss: Signature doesn't match.\n"); */
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* HAVE_GMP */
+
+int cdiff_apply(int fd, unsigned short mode)
+{
+ struct cdiff_ctx ctx;
+ FILE *fh;
+ gzFile *gzh;
+ char line[1024], buff[FILEBUFF], *dsig = NULL;
+ unsigned int lines = 0, cmds = 0;
+ unsigned int difflen, diffremain;
+ int end, i, n;
+ struct stat sb;
+ int desc;
+#ifdef HAVE_GMP
+ SHA256_CTX sha256ctx;
+ unsigned char digest[32];
+ int sum, bread;
+#endif
+#define DSIGBUFF 350
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ if((desc = dup(fd)) == -1) {
+ logg("!cdiff_apply: Can't duplicate descriptor %d\n", fd);
+ return -1;
+ }
+
+ if(mode == 1) { /* .cdiff */
+
+ if(lseek(desc, -DSIGBUFF, SEEK_END) == -1) {
+ logg("!cdiff_apply: lseek(desc, %d, SEEK_END) failed\n", -DSIGBUFF);
+ close(desc);
+ return -1;
+ }
+
+ memset(line, 0, sizeof(line));
+ if(read(desc, line, DSIGBUFF) != DSIGBUFF) {
+ logg("!cdiff_apply: Can't read %d bytes\n", DSIGBUFF);
+ close(desc);
+ return -1;
+ }
+
+ for(i = DSIGBUFF - 1; i >= 0; i--) {
+ if(line[i] == ':') {
+ dsig = &line[i + 1];
+ break;
+ }
+ }
+
+ if(!dsig) {
+ logg("!cdiff_apply: No digital signature in cdiff file\n");
+ close(desc);
+ return -1;
+ }
+
+ if(fstat(desc, &sb) == -1) {
+ logg("!cdiff_apply: Can't fstat file\n");
+ close(desc);
+ return -1;
+ }
+
+ end = sb.st_size - (DSIGBUFF - i);
+ if(end < 0) {
+ logg("!cdiff_apply: compressed data end offset < 0\n");
+ close(desc);
+ return -1;
+ }
+
+ if(lseek(desc, 0, SEEK_SET) == -1) {
+ logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
+ close(desc);
+ return -1;
+ }
+
+#ifdef HAVE_GMP
+ sha256_init(&sha256ctx);
+ sum = 0;
+ while((bread = read(desc, buff, FILEBUFF)) > 0) {
+ if(sum + bread >= end) {
+ sha256_update(&sha256ctx, (unsigned char *) buff, end - sum);
+ break;
+ } else {
+ sha256_update(&sha256ctx, (unsigned char *) buff, bread);
+ }
+ sum += bread;
+ }
+ sha256_final(&sha256ctx);
+ sha256_digest(&sha256ctx, digest);
+
+ if(pss_versig(digest, dsig)) {
+ logg("!cdiff_apply: Incorrect digital signature\n");
+ close(desc);
+ return -1;
+ }
+#endif
+
+ if(lseek(desc, 0, SEEK_SET) == -1) {
+ logg("!cdiff_apply: lseek(desc, 0, SEEK_SET) failed\n");
+ close(desc);
+ return -1;
+ }
+
+ i = 0;
+ n = 0;
+ while(n < FILEBUFF - 1 && read(desc, &buff[n], 1) > 0) {
+ if(buff[n++] == ':')
+ if(++i == 3)
+ break;
+ }
+ buff[n] = 0;
+
+ if(sscanf(buff, "ClamAV-Diff:%*u:%u:", &difflen) != 1) {
+ logg("!cdiff_apply: Incorrect file format\n");
+ close(desc);
+ return -1;
+ }
+
+ if(!(gzh = gzdopen(desc, "rb"))) {
+ logg("!cdiff_apply: Can't gzdopen descriptor %d\n", desc);
+ close(desc);
+ return -1;
+ }
+
+ diffremain = difflen;
+ while(diffremain) {
+ unsigned int bufsize = diffremain < sizeof(line) ? diffremain + 1 : sizeof(line);
+
+ if(!gzgets(gzh, line, bufsize)) {
+ logg("!cdiff_apply: Premature EOF at line %d\n", lines + 1);
+ cdiff_ctx_free(&ctx);
+ gzclose(gzh);
+ return -1;
+ }
+ diffremain -= strlen(line);
+ lines++;
+ cli_chomp(line);
+
+ if(line[0] == '#' || !strlen(line))
+ continue;
+
+ if(cdiff_execute(line, &ctx) == -1) {
+ logg("!cdiff_apply: Error executing command at line %d\n", lines);
+ cdiff_ctx_free(&ctx);
+ gzclose(gzh);
+ return -1;
+ } else {
+ cmds++;
+ }
+ }
+ gzclose(gzh);
+
+ } else { /* .script */
+
+ if(!(fh = fdopen(desc, "r"))) {
+ logg("!cdiff_apply: fdopen() failed for descriptor %d\n", desc);
+ close(desc);
+ return -1;
+ }
+
+ while(fgets(line, sizeof(line), fh)) {
+ lines++;
+ cli_chomp(line);
+
+ if(line[0] == '#' || !strlen(line))
+ continue;
+
+ if(cdiff_execute(line, &ctx) == -1) {
+ logg("!cdiff_apply: Error executing command at line %d\n", lines);
+ cdiff_ctx_free(&ctx);
+ fclose(fh);
+ return -1;
+ } else {
+ cmds++;
+ }
+ }
+
+ fclose(fh);
+ }
+
+ if(ctx.open_db) {
+ logg("*cdiff_apply: File %s was not properly closed\n", ctx.open_db);
+ cdiff_ctx_free(&ctx);
+ return -1;
+ }
+
+ logg("*cdiff_apply: Parsed %d lines and executed %d commands\n", lines, cmds);
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_cfgparser.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2002 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "cfgparser.h"
+#include "misc.h"
+
+#include "str.h"
+
+struct cfgoption cfg_options[] = {
+ {"LogFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+ {"LogFileUnlock", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"LogFileMaxSize", OPT_COMPSIZE, 1048576, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"LogTime", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"LogClean", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"LogVerbose", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"LogSyslog", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"LogFacility", OPT_QUOTESTR, -1, "LOG_LOCAL6", 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"PidFile", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"TemporaryDirectory", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+ {"ScanPE", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"ScanELF", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"DetectBrokenExecutables", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"ScanMail", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"MailFollowURLs", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"MailMaxRecursion", OPT_NUM, 64, NULL, 0, OPT_CLAMD},
+ {"PhishingSignatures", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"PhishingScanURLs",OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ /* these are FP prone options, if default isn't used */
+ {"PhishingAlwaysBlockCloak", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"PhishingAlwaysBlockSSLMismatch", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"PhishingRestrictedScan", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ /* end of FP prone options */
+ {"DetectPUA", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"AlgorithmicDetection", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"ScanHTML", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"ScanOLE2", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"ScanPDF", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"ScanArchive", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"ArchiveMaxFileSize", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
+ {"ArchiveMaxRecursion", OPT_NUM, 8, NULL, 0, OPT_CLAMD},
+ {"ArchiveMaxFiles", OPT_NUM, 1000, NULL, 0, OPT_CLAMD},
+ {"ArchiveMaxCompressionRatio", OPT_NUM, 250, NULL, 0, OPT_CLAMD},
+ {"ArchiveLimitMemoryUsage", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"ArchiveBlockMax", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"DatabaseDirectory", OPT_QUOTESTR, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"TCPAddr", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+ {"TCPSocket", OPT_NUM, -1, NULL, 0, OPT_CLAMD},
+ {"LocalSocket", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+ {"MaxConnectionQueueLength", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
+ {"StreamMaxLength", OPT_COMPSIZE, 10485760, NULL, 0, OPT_CLAMD},
+ {"StreamMinPort", OPT_NUM, 1024, NULL, 0, OPT_CLAMD},
+ {"StreamMaxPort", OPT_NUM, 2048, NULL, 0, OPT_CLAMD},
+ {"MaxThreads", OPT_NUM, 10, NULL, 0, OPT_CLAMD},
+ {"ReadTimeout", OPT_NUM, 120, NULL, 0, OPT_CLAMD},
+ {"IdleTimeout", OPT_NUM, 30, NULL, 0, OPT_CLAMD},
+ {"MaxDirectoryRecursion", OPT_NUM, 15, NULL, 0, OPT_CLAMD},
+ {"FollowDirectorySymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"FollowFileSymlinks", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"ExitOnOOM", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"Foreground", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"Debug", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"LeaveTemporaryFiles", OPT_BOOL, 0, NULL, 0, OPT_CLAMD},
+ {"FixStaleSocket", OPT_BOOL, 1, NULL, 0, OPT_CLAMD},
+ {"User", OPT_QUOTESTR, -1, NULL, 0, OPT_CLAMD},
+ {"AllowSupplementaryGroups", OPT_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM},
+ {"SelfCheck", OPT_NUM, 1800, NULL, 0, OPT_CLAMD},
+ {"VirusEvent", OPT_FULLSTR, -1, NULL, 0, OPT_CLAMD},
+ {"ClamukoScanOnAccess", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+ {"ClamukoScanOnOpen", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+ {"ClamukoScanOnClose", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+ {"ClamukoScanOnExec", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+ {"ClamukoIncludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD},
+ {"ClamukoExcludePath", OPT_QUOTESTR, -1, NULL, 1, OPT_CLAMD},
+ {"ClamukoMaxFileSize", OPT_COMPSIZE, 5242880, NULL, 0, OPT_CLAMD},
+ {"DatabaseOwner", OPT_QUOTESTR, -1, CLAMAVUSER, 0, OPT_FRESHCLAM},
+ {"Checks", OPT_NUM, 12, NULL, 0, OPT_FRESHCLAM},
+ {"UpdateLogFile", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"DNSDatabaseInfo", OPT_QUOTESTR, -1, "current.cvd.clamav.net", 0, OPT_FRESHCLAM},
+ {"DatabaseMirror", OPT_QUOTESTR, -1, NULL, 1, OPT_FRESHCLAM},
+ {"MaxAttempts", OPT_NUM, 3, NULL, 0, OPT_FRESHCLAM},
+ {"ScriptedUpdates", OPT_BOOL, 1, NULL, 0, OPT_FRESHCLAM},
+ {"HTTPProxyServer", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"HTTPProxyPort", OPT_NUM, -1, NULL, 0, OPT_FRESHCLAM},
+ {"HTTPProxyUsername", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"HTTPProxyPassword", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"HTTPUserAgent", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"NotifyClamd", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"OnUpdateExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"OnErrorExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"OnOutdatedExecute", OPT_FULLSTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"LocalIPAddress", OPT_QUOTESTR, -1, NULL, 0, OPT_FRESHCLAM},
+ {"ConnectTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM},
+ {"ReceiveTimeout", OPT_NUM, 30, NULL, 0, OPT_FRESHCLAM},
+
+ {"DevACOnly", OPT_BOOL, -1, NULL, 0, OPT_CLAMD},
+ {"DevACDepth", OPT_NUM, -1, NULL, 0, OPT_CLAMD},
+
+ {NULL, 0, 0, NULL, 0, 0}
+};
+
+static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple);
+
+struct cfgstruct *getcfg(const char *cfgfile, int verbose)
+{
+ char buff[LINE_LENGTH], *name, *arg, *c;
+ FILE *fs;
+ int line = 0, i, found, ctype, calc, val;
+ struct cfgstruct *copt = NULL;
+ struct cfgoption *pt;
+
+
+ for(i = 0; ; i++) {
+ pt = &cfg_options[i];
+ if(!pt->name)
+ break;
+
+ if(regcfg(&copt, pt->name, pt->strarg ? strdup(pt->strarg) : NULL, pt->numarg, pt->multiple) < 0) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ freecfg(copt);
+ return NULL;
+ }
+ }
+
+ if((fs = fopen(cfgfile, "rb")) == NULL) {
+ /* do not print error message here! */
+ freecfg(copt);
+ return NULL;
+ }
+
+ while(fgets(buff, LINE_LENGTH, fs)) {
+ line++;
+
+ if(buff[0] == '#')
+ continue;
+
+ if(!strncmp("Example", buff, 7)) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile);
+ fclose(fs);
+ freecfg(copt);
+ return NULL;
+ }
+
+ if((name = cli_strtok(buff, 0, " \r\n"))) {
+ arg = cli_strtok(buff, 1, " \r\n");
+ found = 0;
+ for(i = 0; ; i++) {
+ pt = &cfg_options[i];
+ if(pt->name) {
+ if(!strcmp(name, pt->name)) {
+ found = 1;
+ switch(pt->argtype) {
+ case OPT_STR:
+ /* deprecated. Use OPT_QUOTESTR instead since it behaves like this, but supports quotes to allow values to contain whitespace */
+ if(!arg) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ freecfg(copt);
+ return NULL;
+ }
+ if(regcfg(&copt, name, arg, -1, pt->multiple) < 0) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ break;
+ case OPT_FULLSTR:
+ /* an ugly hack of the above case */
+ if(!arg) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ freecfg(copt);
+ return NULL;
+ }
+ free(arg);
+ arg = strstr(buff, " ");
+ arg = strdup(++arg);
+ if((arg) && (c = strpbrk(arg, "\n\r")))
+ *c = '\0';
+ if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ break;
+ case OPT_QUOTESTR:
+ /* an ugly hack of the above case */
+ if(!arg) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ freecfg(copt);
+ return NULL;
+ }
+ if((*arg == '\'') || (*arg == '"')) {
+ free(arg);
+ c = strstr(buff, " ");
+ arg = strdup(c+2);
+ if(arg) {
+ if((c = strchr(arg, c[1])))
+ *c = '\0';
+ else {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s missing closing quote.\n", line, name);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ }
+ }
+ if((!arg) || (regcfg(&copt, name, arg, -1, pt->multiple) < 0)) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ break;
+ case OPT_NUM:
+ if(!arg || !isnumb(arg)) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ if(regcfg(&copt, name, NULL, atoi(arg), pt->multiple) < 0) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ free(arg);
+ break;
+ case OPT_COMPSIZE:
+ if(!arg) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ freecfg(copt);
+ return NULL;
+ }
+ ctype = tolower(arg[strlen(arg) - 1]);
+ if(ctype == 'm' || ctype == 'k') {
+ char *cpy = (char *) calloc(strlen(arg), 1);
+ strncpy(cpy, arg, strlen(arg) - 1);
+ if(!isnumb(cpy)) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ if(ctype == 'm')
+ calc = atoi(cpy) * 1024 * 1024;
+ else
+ calc = atoi(cpy) * 1024;
+ free(cpy);
+ } else {
+ if(!isnumb(arg)) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ calc = atoi(arg);
+ }
+ free(arg);
+ if(regcfg(&copt, name, NULL, calc, pt->multiple) < 0) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ break;
+ case OPT_BOOL:
+
+ if(!arg) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ freecfg(copt);
+ return NULL;
+ }
+
+ if(!strcasecmp(arg, "yes") || !strcmp(arg, "1") || !strcasecmp(arg, "true")) {
+ val = 1;
+ } else if(!strcasecmp(arg, "no") || !strcmp(arg, "0") || !strcasecmp(arg, "false")) {
+ val = 0;
+ } else {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires boolean argument.\n", line, name);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ free(arg);
+ if(regcfg(&copt, name, NULL, val, pt->multiple) < 0) {
+ fprintf(stderr, "ERROR: Can't register new options (not enough memory)\n");
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ break;
+ default:
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Option %s is of unknown type %d\n", line, name, pt->argtype);
+ fclose(fs);
+ free(name);
+ free(arg);
+ freecfg(copt);
+ return NULL;
+ }
+ }
+ } else
+ break;
+ }
+
+ if(!found) {
+ if(verbose)
+ fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name);
+ free(name);
+ fclose(fs);
+ freecfg(copt);
+ return NULL;
+ }
+ free(name);
+ }
+ }
+
+ fclose(fs);
+ return copt;
+}
+
+void freecfg(struct cfgstruct *copt)
+{
+ struct cfgstruct *handler;
+ struct cfgstruct *arg;
+
+ while(copt) {
+ arg = copt->nextarg;
+ while(arg) {
+ if(arg->strarg) {
+ free(arg->optname);
+ free(arg->strarg);
+ handler = arg;
+ arg = arg->nextarg;
+ free(handler);
+ } else
+ arg = arg->nextarg;
+ }
+ if(copt->optname)
+ free(copt->optname);
+
+ if(copt->strarg)
+ free(copt->strarg);
+
+ handler = copt;
+ copt = copt->next;
+ free(handler);
+ }
+ return;
+}
+
+const struct cfgstruct *cfgopt(const struct cfgstruct *copt, const char *optname)
+{
+ while(copt) {
+ if(copt->optname && !strcmp(copt->optname, optname))
+ return copt;
+
+ copt = copt->next;
+ }
+
+ return NULL;
+}
+
+static struct cfgstruct *cfgopt_i(struct cfgstruct *copt, const char *optname)
+{
+ while(copt) {
+ if(copt->optname && !strcmp(copt->optname, optname))
+ return copt;
+
+ copt = copt->next;
+ }
+
+ return NULL;
+}
+
+static int regcfg(struct cfgstruct **copt, const char *optname, char *strarg, int numarg, short multiple)
+{
+ struct cfgstruct *newnode, *pt;
+
+
+ newnode = (struct cfgstruct *) malloc(sizeof(struct cfgstruct));
+
+ if(!newnode)
+ return -1;
+
+ newnode->optname = optname ? strdup(optname) : NULL;
+ newnode->nextarg = NULL;
+ newnode->next = NULL;
+ newnode->enabled = 0;
+ newnode->multiple = multiple;
+
+ if(strarg) {
+ newnode->strarg = strarg;
+ newnode->enabled = 1;
+ } else {
+ newnode->strarg = NULL;
+ }
+
+ newnode->numarg = numarg;
+ if(numarg != -1 && numarg != 0)
+ newnode->enabled = 1;
+
+ if((pt = cfgopt_i(*copt, optname))) {
+ if(pt->multiple) {
+
+ if(pt->enabled) {
+ while(pt->nextarg)
+ pt = pt->nextarg;
+
+ pt->nextarg = newnode;
+ } else {
+ if(pt->strarg)
+ free(pt->strarg);
+ pt->strarg = newnode->strarg;
+ pt->numarg = newnode->numarg;
+ pt->enabled = newnode->enabled;
+ if(newnode->optname)
+ free(newnode->optname);
+ free(newnode);
+ }
+ return 3; /* registered additional argument */
+
+ } else {
+ if(pt->strarg)
+ free(pt->strarg);
+ pt->strarg = newnode->strarg;
+ pt->numarg = newnode->numarg;
+ pt->enabled = newnode->enabled;
+ if(newnode->optname)
+ free(newnode->optname);
+ free(newnode);
+ return 2;
+ }
+
+ } else {
+ newnode->next = *copt;
+ *copt = newnode;
+ return 1;
+ }
+}
+
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_getopt.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,1022 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper at gnu.org
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+ Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <clamav-config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+# ifndef const
+# define const
+# endif
+#endif
+
+#include <stdio.h>
+
+#ifndef C_WINDOWS
+int strncmp(const char *s1, const char *s2, size_t n);
+#endif
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages. */
+# if defined HAVE_LIBINTL_H || defined _LIBC
+# include <libintl.h>
+# ifndef _
+# define _(msgid) gettext (msgid)
+# endif
+# else
+# define _(msgid) (msgid)
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+# include <string.h>
+# define my_index strchr
+#else
+
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ nonoption_flags_max_len),
+ '\0', top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', nonoption_flags_max_len - len);
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int print_errors = opterr;
+ if (optstring[0] == ':')
+ print_errors = 0;
+
+ if (argc < 1)
+ return -1;
+
+ optarg = NULL;
+
+ if (optind == 0 || !__getopt_initialized)
+ {
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc && NONOPTION_P)
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else if (long_only
+ || pfound->has_arg != p->has_arg
+ || pfound->flag != p->flag
+ || pfound->val != p->val)
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (print_errors)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (print_errors)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (print_errors)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (print_errors)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (print_errors)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (print_errors)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (print_errors)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+#endif /* Not ELIDE_CODE. */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_misc.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2004 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef C_WINDOWS
+#include <dirent.h>
+#endif
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "cfgparser.h"
+#include "output.h"
+
+#include "clamav.h"
+#include "cvd.h"
+#include "others.h" /* for cli_rmdirs() */
+#include "misc.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifdef CL_EXPERIMENTAL
+#define VERSION_EXP VERSION"-exp"
+#else
+#define VERSION_EXP VERSION
+#endif
+
+char *freshdbdir(void)
+{
+ struct cl_cvd *d1, *d2;
+ struct cfgstruct *copt;
+ const struct cfgstruct *cpt;
+ struct stat foo;
+ const char *dbdir;
+ char *retdir;
+
+
+ /* try to find fresh directory */
+ dbdir = cl_retdbdir();
+ if((copt = getcfg(CONFDIR"/clamd.conf", 0))) {
+ if((cpt = cfgopt(copt, "DatabaseDirectory"))->enabled || (cpt = cfgopt(copt, "DataDirectory"))->enabled) {
+ if(strcmp(dbdir, cpt->strarg)) {
+ char *daily = (char *) malloc(strlen(cpt->strarg) + strlen(dbdir) + 30);
+ sprintf(daily, "%s/daily.cvd", cpt->strarg);
+ if(stat(daily, &foo) == -1)
+ sprintf(daily, "%s/daily.inc/daily.info", cpt->strarg);
+
+ if((d1 = cl_cvdhead(daily))) {
+ sprintf(daily, "%s/daily.cvd", dbdir);
+ if(stat(daily, &foo) == -1)
+ sprintf(daily, "%s/daily.inc/daily.info", dbdir);
+
+ if((d2 = cl_cvdhead(daily))) {
+ free(daily);
+ if(d1->version > d2->version)
+ dbdir = cpt->strarg;
+ cl_cvdfree(d2);
+ } else {
+ free(daily);
+ dbdir = cpt->strarg;
+ }
+ cl_cvdfree(d1);
+ } else {
+ free(daily);
+ }
+ }
+ }
+ }
+
+ retdir = strdup(dbdir);
+
+ if(copt)
+ freecfg(copt);
+
+ return retdir;
+}
+
+void print_version(void)
+{
+ char *dbdir;
+ char *path;
+ struct cl_cvd *daily;
+ struct stat foo;
+
+
+ dbdir = freshdbdir();
+ if(!(path = malloc(strlen(dbdir) + 30))) {
+ free(dbdir);
+ return;
+ }
+
+ sprintf(path, "%s/daily.cvd", dbdir);
+ if(stat(path, &foo) == -1)
+ sprintf(path, "%s/daily.inc/daily.info", dbdir);
+ free(dbdir);
+
+ if((daily = cl_cvdhead(path))) {
+ time_t t = (time_t) daily->stime;
+
+ printf("ClamAV "VERSION_EXP"/%d/%s", daily->version, ctime(&t));
+ cl_cvdfree(daily);
+ } else {
+ printf("ClamAV "VERSION_EXP"\n");
+ }
+
+ free(path);
+}
+
+int filecopy(const char *src, const char *dest)
+{
+
+#ifdef C_DARWIN
+ pid_t pid;
+
+ /* On Mac OS X use ditto and copy resource fork, too. */
+ switch(pid = fork()) {
+ case -1:
+ return -1;
+ case 0:
+ execl("/usr/bin/ditto", "ditto", "--rsrc", src, dest, NULL);
+ perror("execl(ditto)");
+ break;
+ default:
+ wait(NULL);
+ return 0;
+ }
+
+ return -1;
+
+#else
+ char buffer[FILEBUFF];
+ int s, d, bytes, ret;
+ struct stat sb;
+
+
+ if((s = open(src, O_RDONLY|O_BINARY)) == -1)
+ return -1;
+
+ if((d = open(dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, 0644)) == -1) {
+ close(s);
+ return -1;
+ }
+
+ while((bytes = read(s, buffer, FILEBUFF)) > 0)
+ if(write(d, buffer, bytes) < bytes) {
+ close(s);
+ close(d);
+ return -1;
+ }
+
+ close(s);
+ /* njh at bandsman.co.uk: check result of close for NFS file */
+ ret = close(d);
+
+ stat(src, &sb);
+ chmod(dest, sb.st_mode);
+
+ return ret;
+
+#endif
+
+}
+
+int dircopy(const char *src, const char *dest)
+{
+ DIR *dd;
+ struct dirent *dent;
+ struct stat sb;
+ char spath[512], dpath[512];
+
+
+ if(stat(dest, &sb) == -1) {
+ if(mkdir(dest, 0755)) {
+ /* mprintf("!dircopy: Can't create temporary directory %s\n", dest); */
+ return -1;
+ }
+ }
+
+ if((dd = opendir(src)) == NULL) {
+ /* mprintf("!dircopy: Can't open directory %s\n", src); */
+ return -1;
+ }
+
+ while((dent = readdir(dd))) {
+#if (!defined(C_CYGWIN)) && (!defined(C_INTERIX)) && (!defined(C_WINDOWS))
+ if(dent->d_ino)
+#endif
+ {
+ if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
+
+ snprintf(spath, sizeof(spath), "%s/%s", src, dent->d_name);
+ snprintf(dpath, sizeof(dpath), "%s/%s", dest, dent->d_name);
+
+ if(filecopy(spath, dpath) == -1) {
+ /* mprintf("!dircopy: Can't copy %s to %s\n", spath, dpath); */
+ cli_rmdirs(dest);
+ closedir(dd);
+ return -1;
+ }
+ }
+ }
+
+ closedir(dd);
+ return 0;
+}
+
+int isnumb(const char *str)
+{
+ while(*str) {
+ if(!isdigit(*str & 0xff))
+ return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+int cvd_unpack(const char *cvd, const char *destdir)
+{
+ int fd;
+
+
+ if((fd = open(cvd, O_RDONLY|O_BINARY)) == -1)
+ return -1;
+
+ if(lseek(fd, 512, SEEK_SET) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ if(cli_untgz(fd, destdir) == -1) /* cli_untgz() will close fd */
+ return -1;
+
+ return 0;
+}
+
+void daemonize(void)
+{
+#if defined(C_OS2) || defined(C_WINDOWS)
+ fputs("Background mode is not supported on your operating system\n", stderr);
+ return;
+#else
+ int i;
+
+
+ if((i = open("/dev/null", O_RDWR)) == -1) {
+ for(i = 0; i <= 2; i++)
+ close(i);
+
+ } else {
+ dup2(i, 0);
+ dup2(i, 1);
+ dup2(i, 2);
+ if(i > 2)
+ close(i);
+ }
+
+ if(fork())
+ exit(0);
+
+ setsid();
+#endif
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_network.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ */
+
+#ifdef _MSC_VER
+#include <windows.h>
+#include <winsock.h>
+#endif
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifndef C_WINDOWS
+#include <netdb.h>
+#endif
+
+#ifdef CL_NOTHREADS
+#undef CL_THREAD_SAFE
+#endif
+
+#ifdef CL_THREAD_SAFE
+#include <pthread.h>
+#endif
+
+#include "network.h"
+
+/*
+ * TODO: gethostbyname_r is non-standard so different operating
+ * systems do it in different ways. Need more examples
+ * Perhaps we could use res_search()?
+ *
+ * Returns 0 for success
+ */
+int r_gethostbyname(const char *hostname, struct hostent *hp, char *buf, size_t len)
+{
+#if defined(HAVE_GETHOSTBYNAME_R_6)
+ /* e.g. Linux */
+ struct hostent *hp2;
+ int ret = -1;
+
+ if((hostname == NULL) || (hp == NULL))
+ return -1;
+ if(gethostbyname_r(hostname, hp, buf, len, &hp2, &ret) < 0)
+ return ret;
+#elif defined(HAVE_GETHOSTBYNAME_R_5)
+ /* e.g. BSD, Solaris, Cygwin */
+ int ret = -1;
+
+ if((hostname == NULL) || (hp == NULL))
+ return -1;
+ if(gethostbyname_r(hostname, hp, buf, len, &ret) == NULL)
+ return ret;
+#elif defined(HAVE_GETHOSTBYNAME_R_3)
+ /* e.g. HP/UX, AIX */
+ if((hostname == NULL) || (hp == NULL))
+ return -1;
+ if(gethostbyname_r(hostname, &hp, (struct hostent_data *)buf) < 0)
+ return h_errno;
+#else
+ /* Single thread the code e.g. VS2005 */
+ struct hostent *hp2;
+#ifdef CL_THREAD_SAFE
+ static pthread_mutex_t hostent_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+ if((hostname == NULL) || (hp == NULL))
+ return -1;
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_lock(&hostent_mutex);
+#endif
+ if((hp2 = gethostbyname(hostname)) == NULL) {
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&hostent_mutex);
+#endif
+ return h_errno;
+ }
+ memcpy(hp, hp2, sizeof(struct hostent));
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&hostent_mutex);
+#endif
+
+#endif
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_options.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2001 - 2007 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define _GNU_SOURCE
+#include "getopt.h"
+
+#include "options.h"
+#include "output.h"
+
+
+static int register_option(struct optstruct *opt, const char *optlong, char optshort, const struct option *options_long, const char * const *accepted_long)
+{
+ struct optnode *newnode;
+ int i, found = 0;
+ const char *longname = NULL;
+
+
+ if(optshort) {
+ for(i = 0; options_long[i].name; i++) {
+ if(options_long[i].val == optshort) {
+ longname = options_long[i].name;
+ break;
+ }
+ }
+ } else
+ longname = optlong;
+
+ if(!longname) {
+ mprintf("!register_option: No long option for -%c\n", optshort);
+ return -1;
+ }
+
+ if(accepted_long) {
+ for(i = 0; accepted_long[i]; i++)
+ if(!strcmp(accepted_long[i], longname))
+ found = 1;
+
+ if(!found) {
+ if(optshort)
+ mprintf("WARNING: Ignoring option --%s (-%c)\n", longname, optshort);
+ else
+ mprintf("WARNING: Ignoring option --%s\n", longname);
+
+ return 0;
+ }
+ }
+
+ newnode = (struct optnode *) malloc(sizeof(struct optnode));
+ if(!newnode) {
+ mprintf("!register_long_option: malloc failed\n");
+ return -1;
+ }
+
+ newnode->optshort = optshort;
+
+ if(optarg) {
+ newnode->optarg = (char *) malloc(strlen(optarg) + 1);
+ if(!newnode->optarg) {
+ mprintf("!register_long_option: malloc failed\n");
+ free(newnode);
+ return -1;
+ }
+ strcpy(newnode->optarg, optarg);
+ } else
+ newnode->optarg = NULL;
+
+ newnode->optlong = (char *) malloc(strlen(longname) + 1);
+ if(!newnode->optlong) {
+ mprintf("ERROR: register_long_option: malloc failed\n");
+ free(newnode->optarg);
+ free(newnode);
+ return -1;
+ }
+ strcpy(newnode->optlong, longname);
+
+ newnode->next = opt->optlist;
+ opt->optlist = newnode;
+ return 0;
+}
+
+void opt_free(struct optstruct *opt)
+{
+ struct optnode *handler, *prev;
+
+ if(!opt)
+ return;
+
+ handler = opt->optlist;
+ while(handler) {
+ if(handler->optarg)
+ free(handler->optarg);
+ if(handler->optlong)
+ free(handler->optlong);
+ prev = handler;
+ handler = handler->next;
+ free(prev);
+ }
+
+ if(opt->filename)
+ free(opt->filename);
+
+ free(opt);
+}
+
+struct optstruct *opt_parse(int argc, char * const *argv, const char *getopt_short, const struct option *options_long, const char * const *accepted_long)
+{
+ int ret, opt_index, i, len;
+ struct optstruct *opt;
+ const char *longname;
+
+
+ opt = (struct optstruct *) calloc(1, sizeof(struct optstruct));
+ if(!opt) {
+ mprintf("!opt_parse: calloc failed\n");
+ return NULL;
+ }
+
+ while(1) {
+ opt_index = 0;
+ ret = getopt_long(argc, argv, getopt_short, options_long, &opt_index);
+
+ if(ret == -1)
+ break;
+
+ switch(ret) {
+ case 0:
+ if(register_option(opt, options_long[opt_index].name, 0, options_long, accepted_long) == -1) {
+ opt_free(opt);
+ return NULL;
+ }
+ break;
+
+ default:
+ if(strchr(getopt_short, ret)) {
+ if(opt_index)
+ longname = options_long[opt_index].name;
+ else
+ longname = NULL;
+
+ if(register_option(opt, longname, ret, options_long, accepted_long) == -1) {
+ opt_free(opt);
+ return NULL;
+ }
+
+ } else {
+ mprintf("!Unknown option passed.\n");
+ opt_free(opt);
+ return NULL;
+ }
+ }
+ }
+
+ if(optind < argc) {
+ len = 0;
+
+ /* count length of non-option arguments */
+ for(i = optind; i < argc; i++)
+ len += strlen(argv[i]);
+
+ len += argc - optind - 1;
+ opt->filename = (char *) calloc(len + 64, sizeof(char));
+ if(!opt->filename) {
+ mprintf("!opt_parse: calloc failed\n");
+ opt_free(opt);
+ return NULL;
+ }
+
+ for(i = optind; i < argc; i++) {
+ strncat(opt->filename, argv[i], strlen(argv[i]));
+ if(i != argc - 1)
+ strncat(opt->filename, "\t", 1);
+ }
+ }
+
+ return opt;
+}
+
+int opt_check(const struct optstruct *opt, const char *optlong)
+{
+ struct optnode *handler;
+
+ if(!opt) {
+ mprintf("!opt_check: opt == NULL\n");
+ return 0;
+ }
+
+ handler = opt->optlist;
+
+ while(handler) {
+ if(handler->optlong && !strcmp(handler->optlong, optlong))
+ return 1;
+
+ handler = handler->next;
+ }
+
+ return 0;
+}
+
+char *opt_arg(const struct optstruct *opt, const char *optlong)
+{
+ struct optnode *handler;
+
+ if(!opt) {
+ mprintf("!opt_arg: opt == NULL\n");
+ return 0;
+ }
+
+ handler = opt->optlist;
+
+ while(handler) {
+ if(handler->optlong && !strcmp(handler->optlong, optlong))
+ return handler->optarg;
+
+ handler = handler->next;
+ }
+
+ return NULL;
+}
+
+char *opt_firstarg(const struct optstruct *opt, const char *optlong, const struct optnode **optnode)
+{
+ const struct optnode *handler;
+
+ if(!opt) {
+ mprintf("!opt_firstarg: opt == NULL\n");
+ return 0;
+ }
+
+ handler = opt->optlist;
+
+ while(handler) {
+ if(handler->optlong && !strcmp(handler->optlong, optlong)) {
+ *optnode = handler;
+ return handler->optarg;
+ }
+ handler = handler->next;
+ }
+
+ *optnode = NULL;
+ return NULL;
+}
+
+char *opt_nextarg(const struct optnode **optnode, const char *optlong)
+{
+ struct optnode *handler;
+
+ if(!optnode || !*optnode) {
+ mprintf("!opt_nextarg: *optnode == NULL\n");
+ return 0;
+ }
+
+ handler = (*optnode)->next;
+
+ while(handler) {
+ if(handler->optlong && !strcmp(handler->optlong, optlong)) {
+ *optnode = handler;
+ return handler->optarg;
+ }
+ handler = handler->next;
+ }
+
+ *optnode = NULL;
+ return NULL;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_output.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+#ifdef _MSC_VER
+#include <windows.h>
+#include <winsock.h>
+#endif
+
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <errno.h>
+#ifndef C_WINDOWS
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+#include <syslog.h>
+#endif
+
+#include "output.h"
+
+#ifdef CL_NOTHREADS
+#undef CL_THREAD_SAFE
+#endif
+
+#ifdef CL_THREAD_SAFE
+#include <pthread.h>
+pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+#ifdef C_LINUX
+#include <libintl.h>
+#include <locale.h>
+
+#define gettext_noop(s) s
+#define _(s) gettext(s)
+#define N_(s) gettext_noop(s)
+
+#else
+
+#define _(s) s
+#define N_(s) s
+
+#endif
+
+FILE *logg_fd = NULL;
+
+short int logg_verbose = 0, logg_lock = 1, logg_time = 0, logg_foreground = 1;
+unsigned int logg_size = 0;
+const char *logg_file = NULL;
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+short logg_syslog;
+#endif
+
+short int mprintf_disabled = 0, mprintf_verbose = 0, mprintf_quiet = 0,
+ mprintf_stdout = 0;
+
+int mdprintf(int desc, const char *str, ...)
+{
+ va_list args;
+ char buff[512];
+ int bytes;
+
+ va_start(args, str);
+ bytes = vsnprintf(buff, sizeof(buff), str, args);
+ va_end(args);
+
+ if(bytes == -1)
+ return bytes;
+
+ if(bytes >= (int) sizeof(buff))
+ bytes = sizeof(buff) - 1;
+
+ return send(desc, buff, bytes, 0);
+}
+
+void logg_close(void) {
+
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_lock(&logg_mutex);
+#endif
+ if (logg_fd) {
+ fclose(logg_fd);
+ logg_fd = NULL;
+ }
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&logg_mutex);
+#endif
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+ if(logg_syslog) {
+ closelog();
+ }
+#endif
+}
+
+int logg(const char *str, ...)
+{
+ va_list args, argscpy, argsout;
+#ifdef F_WRLCK
+ struct flock fl;
+#endif
+ char *pt, *timestr, vbuff[1025];
+ time_t currtime;
+ struct stat sb;
+ mode_t old_umask;
+
+
+ va_start(args, str);
+ /* va_copy is less portable so we just use va_start once more */
+ va_start(argscpy, str);
+ va_start(argsout, str);
+
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_lock(&logg_mutex);
+#endif
+ if(logg_file) {
+ if(!logg_fd) {
+ old_umask = umask(0037);
+ if((logg_fd = fopen(logg_file, "at")) == NULL) {
+ umask(old_umask);
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&logg_mutex);
+#endif
+ printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
+ return -1;
+ } else umask(old_umask);
+
+#ifdef F_WRLCK
+ if(logg_lock) {
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_WRLCK;
+ if(fcntl(fileno(logg_fd), F_SETLK, &fl) == -1) {
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&logg_mutex);
+#endif
+ return -1;
+ }
+ }
+#endif
+ }
+
+ if(logg_size) {
+ if(stat(logg_file, &sb) != -1) {
+ if((unsigned int) sb.st_size > logg_size) {
+ logg_file = NULL;
+ fprintf(logg_fd, "Log size = %u, max = %u\n", (unsigned int) sb.st_size, logg_size);
+ fprintf(logg_fd, "LOGGING DISABLED (Maximal log file size exceeded).\n");
+ fclose(logg_fd);
+ logg_fd = NULL;
+ }
+ }
+ }
+
+ if(logg_fd) {
+ /* Need to avoid logging time for verbose messages when logverbose
+ is not set or we get a bunch of timestamps in the log without
+ newlines... */
+ if(logg_time && ((*str != '*') || logg_verbose)) {
+ time(&currtime);
+ pt = ctime(&currtime);
+ timestr = calloc(strlen(pt), 1);
+ strncpy(timestr, pt, strlen(pt) - 1);
+ fprintf(logg_fd, "%s -> ", timestr);
+ free(timestr);
+ }
+
+ _(str);
+ if(*str == '!') {
+ fprintf(logg_fd, "ERROR: ");
+ vfprintf(logg_fd, str + 1, args);
+ } else if(*str == '^') {
+ fprintf(logg_fd, "WARNING: ");
+ vfprintf(logg_fd, str + 1, args);
+ } else if(*str == '*') {
+ if(logg_verbose)
+ vfprintf(logg_fd, str + 1, args);
+ } else if(*str == '#') {
+ vfprintf(logg_fd, str + 1, args);
+ } else vfprintf(logg_fd, str, args);
+
+
+ fflush(logg_fd);
+ }
+ }
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+ if(logg_syslog) {
+ _(str);
+ vsnprintf(vbuff, 1024, str, argscpy);
+ vbuff[1024] = 0;
+
+ if(vbuff[0] == '!') {
+ syslog(LOG_ERR, "%s", vbuff + 1);
+ } else if(vbuff[0] == '^') {
+ syslog(LOG_WARNING, "%s", vbuff + 1);
+ } else if(vbuff[0] == '*') {
+ if(logg_verbose) {
+ syslog(LOG_DEBUG, "%s", vbuff + 1);
+ }
+ } else if(vbuff[0] == '#') {
+ syslog(LOG_INFO, "%s", vbuff + 1);
+ } else syslog(LOG_INFO, "%s", vbuff);
+
+ }
+#endif
+
+ if(logg_foreground) {
+ _(str);
+ vsnprintf(vbuff, 1024, str, argsout);
+ vbuff[1024] = 0;
+ if(vbuff[0] != '#')
+ mprintf("%s", vbuff);
+ }
+
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&logg_mutex);
+#endif
+
+ va_end(args);
+ va_end(argscpy);
+ va_end(argsout);
+ return 0;
+}
+
+void mprintf(const char *str, ...)
+{
+ va_list args;
+ FILE *fd;
+ char buff[512];
+
+
+ if(mprintf_disabled)
+ return;
+
+ fd = stdout;
+
+/* legend:
+ * ! - error
+ * @ - error with logging
+ * ...
+ */
+
+/*
+ * ERROR WARNING STANDARD
+ * normal stderr stderr stdout
+ *
+ * verbose stderr stderr stdout
+ *
+ * quiet stderr no no
+ */
+
+ va_start(args, str);
+ vsnprintf(buff, sizeof(buff), str, args);
+ va_end(args);
+
+ if(buff[0] == '!') {
+ if(!mprintf_stdout)
+ fd = stderr;
+ fprintf(fd, "ERROR: %s", &buff[1]);
+ } else if(buff[0] == '@') {
+ if(!mprintf_stdout)
+ fd = stderr;
+ fprintf(fd, "ERROR: %s", &buff[1]);
+ } else if(!mprintf_quiet) {
+ if(buff[0] == '^') {
+ if(!mprintf_stdout)
+ fd = stderr;
+ fprintf(fd, "WARNING: %s", &buff[1]);
+ } else if(buff[0] == '*') {
+ if(mprintf_verbose)
+ fprintf(fd, "%s", &buff[1]);
+ } else fprintf(fd, "%s", buff);
+ }
+
+ if(fd == stdout)
+ fflush(stdout);
+}
+
+struct facstruct {
+ const char *name;
+ int code;
+};
+
+#if defined(USE_SYSLOG) && !defined(C_AIX)
+static const struct facstruct facilitymap[] = {
+#ifdef LOG_AUTH
+ { "LOG_AUTH", LOG_AUTH },
+#endif
+#ifdef LOG_AUTHPRIV
+ { "LOG_AUTHPRIV", LOG_AUTHPRIV },
+#endif
+#ifdef LOG_CRON
+ { "LOG_CRON", LOG_CRON },
+#endif
+#ifdef LOG_DAEMON
+ { "LOG_DAEMON", LOG_DAEMON },
+#endif
+#ifdef LOG_FTP
+ { "LOG_FTP", LOG_FTP },
+#endif
+#ifdef LOG_KERN
+ { "LOG_KERN", LOG_KERN },
+#endif
+#ifdef LOG_LPR
+ { "LOG_LPR", LOG_LPR },
+#endif
+#ifdef LOG_MAIL
+ { "LOG_MAIL", LOG_MAIL },
+#endif
+#ifdef LOG_NEWS
+ { "LOG_NEWS", LOG_NEWS },
+#endif
+#ifdef LOG_AUTH
+ { "LOG_AUTH", LOG_AUTH },
+#endif
+#ifdef LOG_SYSLOG
+ { "LOG_SYSLOG", LOG_SYSLOG },
+#endif
+#ifdef LOG_USER
+ { "LOG_USER", LOG_USER },
+#endif
+#ifdef LOG_UUCP
+ { "LOG_UUCP", LOG_UUCP },
+#endif
+#ifdef LOG_LOCAL0
+ { "LOG_LOCAL0", LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+ { "LOG_LOCAL1", LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+ { "LOG_LOCAL2", LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+ { "LOG_LOCAL3", LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+ { "LOG_LOCAL4", LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+ { "LOG_LOCAL5", LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+ { "LOG_LOCAL6", LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+ { "LOG_LOCAL7", LOG_LOCAL7 },
+#endif
+ { NULL, -1 }
+};
+
+int logg_facility(const char *name)
+{
+ int i;
+
+ for(i = 0; facilitymap[i].name; i++)
+ if(!strcmp(facilitymap[i].name, name))
+ return facilitymap[i].code;
+
+ return -1;
+}
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/shared_sha256.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2001 Niels Moller
+ *
+ * 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.
+ *
+ * The nettle library 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 Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/* Modelled after the sha1.c code by Peter Gutmann. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "cltypes.h"
+#include "sha256.h"
+
+/* A block, treated as a sequence of 32-bit words. */
+#define SHA256_DATA_LENGTH 16
+
+#define ROTR(n,x) ((x)>>(n) | ((x)<<(32-(n))))
+#define SHR(n,x) ((x)>>(n))
+
+#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) )
+#define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
+
+#define S0(x) (ROTR(2,(x)) ^ ROTR(13,(x)) ^ ROTR(22,(x)))
+#define S1(x) (ROTR(6,(x)) ^ ROTR(11,(x)) ^ ROTR(25,(x)))
+
+#define s0(x) (ROTR(7,(x)) ^ ROTR(18,(x)) ^ SHR(3,(x)))
+#define s1(x) (ROTR(17,(x)) ^ ROTR(19,(x)) ^ SHR(10,(x)))
+
+static const uint32_t K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+ 0xe49b69c1UL, 0xefbe4786UL, 0xfc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+ 0xc6e00bf3UL, 0xd5a79147UL, 0x6ca6351UL, 0x14292967UL,
+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
+};
+
+#define EXPAND(W,i) \
+( W[(i) & 15 ] += (s1(W[((i)-2) & 15]) + W[((i)-7) & 15] + s0(W[((i)-15) & 15])) )
+
+#define ROUND(a,b,c,d,e,f,g,h,k,data) do { \
+ uint32_t T1 = h + S1(e) + Choice(e,f,g) + k + data; \
+ uint32_t T2 = S0(a) + Majority(a,b,c); \
+ d += T1; \
+ h = T1 + T2; \
+} while (0)
+
+#ifndef EXTRACT_UCHAR
+#define EXTRACT_UCHAR(p) (*(const unsigned char *)(p))
+#endif
+
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8) \
+ | EXTRACT_UCHAR(s+1)) << 8) \
+ | EXTRACT_UCHAR(s+2)) << 8) \
+ | EXTRACT_UCHAR(s+3))
+
+#ifndef EXTRACT_UCHAR
+#define EXTRACT_UCHAR(p) (*(const mutils_word8 *)(p))
+#endif
+
+#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8) \
+ | EXTRACT_UCHAR(s+1)) << 8) \
+ | EXTRACT_UCHAR(s+2)) << 8) \
+ | EXTRACT_UCHAR(s+3))
+
+/* Initialize the SHA values */
+
+void sha256_init(struct sha256_ctx *ctx)
+{
+ /* Initial values, also generated by the shadata program. */
+ static const uint32_t H0[_SHA256_DIGEST_LENGTH] = {
+ 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL,
+ 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL,
+ };
+
+ memcpy(ctx->state, H0, sizeof(H0));
+
+ /* Initialize bit count */
+ ctx->count_low = ctx->count_high = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+/* Perform the SHA transformation. Note that this code, like MD5, seems to
+ break some optimizing compilers due to the complexity of the expressions
+ and the size of the basic block. It may be necessary to split it into
+ sections, e.g. based on the four subrounds
+
+ Note that this function destroys the data area */
+
+static void sha256_transform(uint32_t *state, uint32_t *data)
+{
+ uint32_t A, B, C, D, E, F, G, H; /* Local vars */
+ unsigned char i;
+ const uint32_t *k;
+ uint32_t *d;
+
+ /* Set up first buffer and local data buffer */
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+ F = state[5];
+ G = state[6];
+ H = state[7];
+
+ /* Heavy mangling */
+ /* First 16 subrounds that act on the original data */
+
+ for (i = 0, k = K, d = data; i < 16; i += 8, k += 8, d += 8) {
+ ROUND(A, B, C, D, E, F, G, H, k[0], d[0]);
+ ROUND(H, A, B, C, D, E, F, G, k[1], d[1]);
+ ROUND(G, H, A, B, C, D, E, F, k[2], d[2]);
+ ROUND(F, G, H, A, B, C, D, E, k[3], d[3]);
+ ROUND(E, F, G, H, A, B, C, D, k[4], d[4]);
+ ROUND(D, E, F, G, H, A, B, C, k[5], d[5]);
+ ROUND(C, D, E, F, G, H, A, B, k[6], d[6]);
+ ROUND(B, C, D, E, F, G, H, A, k[7], d[7]);
+ }
+
+ for (; i < 64; i += 16, k += 16) {
+ ROUND(A, B, C, D, E, F, G, H, k[0], EXPAND(data, 0));
+ ROUND(H, A, B, C, D, E, F, G, k[1], EXPAND(data, 1));
+ ROUND(G, H, A, B, C, D, E, F, k[2], EXPAND(data, 2));
+ ROUND(F, G, H, A, B, C, D, E, k[3], EXPAND(data, 3));
+ ROUND(E, F, G, H, A, B, C, D, k[4], EXPAND(data, 4));
+ ROUND(D, E, F, G, H, A, B, C, k[5], EXPAND(data, 5));
+ ROUND(C, D, E, F, G, H, A, B, k[6], EXPAND(data, 6));
+ ROUND(B, C, D, E, F, G, H, A, k[7], EXPAND(data, 7));
+ ROUND(A, B, C, D, E, F, G, H, k[8], EXPAND(data, 8));
+ ROUND(H, A, B, C, D, E, F, G, k[9], EXPAND(data, 9));
+ ROUND(G, H, A, B, C, D, E, F, k[10], EXPAND(data, 10));
+ ROUND(F, G, H, A, B, C, D, E, k[11], EXPAND(data, 11));
+ ROUND(E, F, G, H, A, B, C, D, k[12], EXPAND(data, 12));
+ ROUND(D, E, F, G, H, A, B, C, k[13], EXPAND(data, 13));
+ ROUND(C, D, E, F, G, H, A, B, k[14], EXPAND(data, 14));
+ ROUND(B, C, D, E, F, G, H, A, k[15], EXPAND(data, 15));
+ }
+
+ /* Update state */
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+ state[4] += E;
+ state[5] += F;
+ state[6] += G;
+ state[7] += H;
+}
+
+static void sha256_block(struct sha256_ctx *ctx, const unsigned char *block)
+{
+ uint32_t data[SHA256_DATA_LENGTH];
+ uint16_t i;
+
+ /* Update block count */
+ if (!++ctx->count_low)
+ ++ctx->count_high;
+
+ /* Endian independent conversion */
+ for (i = 0; i < SHA256_DATA_LENGTH; i++, block += 4)
+ data[i] = STRING2INT(block);
+
+ sha256_transform(ctx->state, data);
+}
+
+void
+sha256_update(struct sha256_ctx *ctx, const unsigned char *buffer, uint32_t length)
+{
+ uint32_t left;
+
+ if (ctx->index) { /* Try to fill partial block */
+ left = SHA256_DATA_SIZE - ctx->index;
+ if (length < left) {
+ memcpy(ctx->block + ctx->index, buffer, length);
+ ctx->index += length;
+ return; /* Finished */
+ } else {
+ memcpy(ctx->block + ctx->index, buffer, left);
+ sha256_block(ctx, ctx->block);
+ buffer += left;
+ length -= left;
+ }
+ }
+ while (length >= SHA256_DATA_SIZE) {
+ sha256_block(ctx, buffer);
+ buffer += SHA256_DATA_SIZE;
+ length -= SHA256_DATA_SIZE;
+ }
+ /* Buffer leftovers */
+ /* NOTE: The corresponding sha1 code checks for the special case length == 0.
+ * That seems supoptimal, as I suspect it increases the number of branches. */
+
+ memcpy(ctx->block, buffer, length);
+ ctx->index = length;
+}
+
+/* Final wrapup - pad to SHA1_DATA_SIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+
+void sha256_final(struct sha256_ctx *ctx)
+{
+ uint32_t data[SHA256_DATA_LENGTH];
+ uint32_t i;
+ uint32_t words;
+
+ i = ctx->index;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+
+/* assert(i < SHA256_DATA_SIZE);
+ */
+ ctx->block[i++] = 0x80;
+
+ /* Fill rest of word */
+ for (; i & 3; i++)
+ ctx->block[i] = 0;
+
+ /* i is now a multiple of the word size 4 */
+ words = i >> 2;
+ for (i = 0; i < words; i++)
+ data[i] = STRING2INT(ctx->block + 4 * i);
+
+ if (words > (SHA256_DATA_LENGTH - 2)) { /* No room for length in this block. Process it and
+ * pad with another one */
+ for (i = words; i < SHA256_DATA_LENGTH; i++)
+ data[i] = 0;
+ sha256_transform(ctx->state, data);
+ for (i = 0; i < (SHA256_DATA_LENGTH - 2); i++)
+ data[i] = 0;
+ } else
+ for (i = words; i < SHA256_DATA_LENGTH - 2; i++)
+ data[i] = 0;
+
+ /* There are 512 = 2^9 bits in one block */
+ data[SHA256_DATA_LENGTH - 2] =
+ (ctx->count_high << 9) | (ctx->count_low >> 23);
+ data[SHA256_DATA_LENGTH - 1] =
+ (ctx->count_low << 9) | (ctx->index << 3);
+ sha256_transform(ctx->state, data);
+}
+
+void sha256_digest(const struct sha256_ctx *ctx, unsigned char *s)
+{
+ uint32_t i;
+
+ if (s!=NULL)
+ for (i = 0; i < _SHA256_DIGEST_LENGTH; i++) {
+ *s++ = ctx->state[i] >> 24;
+ *s++ = 0xff & (ctx->state[i] >> 16);
+ *s++ = 0xff & (ctx->state[i] >> 8);
+ *s++ = 0xff & ctx->state[i];
+ }
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/sis.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/sis.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/sis.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/sis.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by Tomasz Kojm
+ *
+ * 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.
+ */
+
+#ifndef __SIS_H
+#define __SIS_H
+
+#include "clamav.h"
+#include "others.h"
+
+struct sis_file_hdr {
+ uint32_t uid1;
+ uint32_t uid2;
+ uint32_t uid3;
+ uint32_t uid4;
+ uint16_t checksum;
+ uint16_t nlangs;
+ uint16_t nfiles;
+ uint16_t nreqs;
+ uint16_t ilang;
+ uint16_t ifiles;
+ uint16_t idrive;
+ uint16_t ncaps;
+ uint32_t iver;
+ uint16_t options;
+ uint16_t type;
+ uint16_t majorver;
+ uint16_t minorver;
+ uint16_t variant;
+ uint32_t plangs;
+ uint32_t pfiles;
+ uint32_t preqs;
+ uint32_t pcerts;
+ uint32_t pname;
+};
+
+struct sis_file_hdr6 {
+ uint32_t psig;
+ uint32_t pcaps;
+ uint32_t ispace;
+ uint32_t maxispace;
+ uint32_t reserved[4];
+};
+
+int cli_scansis(int desc, cli_ctx *ctx);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/snprintf.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,16 @@
+#ifndef _SNPRINTF_H
+#define _SNPRINTF_H
+
+#include "clamav-config.h"
+
+#include <sys/types.h> /* For size_t */
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *str, size_t count, const char *fmt, ...);
+#endif /* !HAVE_SNPRINTF */
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+#endif /* !HAVE_SNPRINTF */
+
+#endif /* _SNPRINTF_H */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/special.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/special.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/special.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/special.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004 trog at uncon.org
+ *
+ * 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.
+ */
+
+#ifndef __SPECIAL_H
+#define __SPECIAL_H
+
+int cli_check_mydoom_log(int desc, const char **virname);
+int cli_check_jpeg_exploit(int fd);
+int cli_check_riff_exploit(int fd);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/spin.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/spin.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/spin.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/spin.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __SPIN_H
+#define __SPIN_H
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int unspin(char *, int, struct cli_exe_section *, int, uint32_t, int, cli_ctx *);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/str.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/str.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/str.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/str.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2002 - 2005 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __STR_H
+#define __STR_H
+
+#include <sys/types.h>
+
+#include "cltypes.h"
+
+int cli_strbcasestr(const char *haystack, const char *needle);
+int cli_chomp(char *string);
+char *cli_strtok(const char *line, int field, const char *delim);
+uint16_t *cli_hex2ui(const char *hex);
+char *cli_hex2str(const char *hex);
+int cli_hex2num(const char *hex);
+char *cli_str2hex(const char *string, unsigned int len);
+char *cli_utf16toascii(const char *str, unsigned int length);
+char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output);
+const char *cli_memstr(const char *haystack, int hs, const char *needle, int ns);
+char *cli_strrcpy(char *dest, const char *source);
+void cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens);
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/suecrypt.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by aCaB <acab at clamav.net>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __UNSUE_H
+#define __UNSUE_H
+
+#include "cltypes.h"
+#include "execs.h"
+
+char *sudecrypt(int, size_t, struct cli_exe_section *, uint16_t, char *, uint32_t, uint32_t, uint32_t);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/table.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/table.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/table.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/table.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * Hashtable mapping strings to numbers
+ */
+typedef struct tableEntry {
+ char *key;
+ int value;
+ struct tableEntry *next;
+} tableEntry;
+
+typedef struct table {
+ tableEntry *tableHead;
+ tableEntry *tableLast;
+ unsigned int flags;
+} table_t;
+
+#define TABLE_HAS_DELETED_ENTRIES 0x1
+
+struct table *tableCreate(void);
+void tableDestroy(table_t *table);
+int tableInsert(table_t *table, const char *key, int value);
+int tableUpdate(table_t *table, const char *key, int new_value);
+int tableFind(const table_t *table, const char *key);
+void tableRemove(table_t *table, const char *key);
+void tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg);
Added: test-suite/trunk/MultiSource/Applications/ClamAV/target.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/target.h?rev=46573&view=auto
==============================================================================
(empty)
Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_farm_farm.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2007 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * Compare the results of scanning files on a set of machines
+ * This is useful for regression testing versions, and for testing
+ * across different operating systems and architectures
+ * The file is always copied which is slow, and could be removed for regression
+ * testing, if we have some mechanism to sync the data
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <memory.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+
+#define PORT 3310
+#define LEN 128
+
+/*
+ * Ensure you don't have StreamMaxLength on any of the servers, or that it's
+ * big enough for all your samples
+ * Uses SESSIONS, which isn't good
+ * If localhost is one of them, it's probably best to put it last so that it
+ * can be scanning while waiting for the remote machines to respond
+ */
+static struct machine {
+ const char *name;
+ in_addr_t ip;
+ int sock;
+} machines[] = {
+ { "eric", 0, -1 },
+ /*{ "motorola", 0, -1 },*/
+ /*{ "ultra60", 0, -1 },*/
+ { "mac", 0, -1 },
+ { "localhost", 0, -1 },
+ { NULL, 0, -1 }
+};
+
+struct args {
+ const char *filename;
+ const struct machine *m;
+ char *ret;
+};
+
+static void dir(const char *dirname);
+static in_addr_t resolve(const char *machine);
+static int start(in_addr_t ip);
+static void *scan(void *v);
+
+int
+main(int argc, char **argv)
+{
+ struct machine *m;
+
+ if(argc <= 1) {
+ fputs("Arg count\n", stderr);
+ return 1;
+ }
+
+ for(m = machines; m->name; m++) {
+ m->ip = resolve(m->name);
+
+ if(m->ip == INADDR_NONE) {
+ fprintf(stderr, "Can't resolve %s\n", m->name);
+ return 1;
+ }
+ m->sock = start(m->ip);
+ if(m->sock < 0)
+ fprintf(stderr, "%s is down\n", m->name);
+ }
+
+ signal(SIGPIPE, SIG_IGN);
+
+ while(*++argv)
+ dir(*argv);
+
+ return 0;
+}
+
+static void
+dir(const char *dirname)
+{
+ int i, nmachines;
+ const struct dirent *dirent;
+ struct machine *m;
+ DIR *d = opendir(dirname);
+ char **results;
+
+ if(d == NULL) {
+ perror(dirname);
+ return;
+ }
+ for(nmachines = 0, m = machines; m->name; m++)
+ if(m->sock >= 0)
+ nmachines++;
+
+ if(nmachines < 2) {
+ fputs("Needs at least 2 machines up to run\n", stderr);
+ closedir(d);
+ return;
+ }
+
+ results = (char **)malloc(nmachines * sizeof(char *));
+ if(results == NULL)
+ return;
+ for(i = 0, m = machines; m->name; m++)
+ if(m->sock >= 0) {
+ results[i] = malloc(LEN);
+ if(results[i++] == NULL) {
+ free(results);
+ closedir(d);
+ return;
+ }
+ }
+
+ if(i != nmachines) {
+ fputs("Failed sanity check\n", stderr);
+ closedir(d);
+ return;
+ }
+
+ while((dirent = readdir(d)) != NULL) {
+ int nthreads, founddiffs;
+ pthread_t *tids;
+ struct args *args;
+ char name[PATH_MAX];
+
+ if(dirent->d_ino == (ino_t)0)
+ continue;
+ if(dirent->d_name[0] == '.')
+ continue;
+
+ tids = malloc(nmachines * sizeof(pthread_t));
+ if(tids == NULL) {
+ free(results);
+ closedir(d);
+ return;
+ }
+ args = malloc(nmachines * sizeof(struct args));
+ if(args == NULL) {
+ free(tids);
+ free(results);
+ closedir(d);
+ return;
+ }
+
+ snprintf(name, sizeof(name) -1, "%s/%s", dirname, dirent->d_name);
+ for(nthreads = 0, m = machines; m->name; m++) {
+ if(m->sock < 0)
+ continue;
+
+ args[nthreads].filename = name;
+ args[nthreads].m = m;
+ args[nthreads].ret = results[nthreads];
+ pthread_create(&tids[nthreads], NULL, scan, &args[nthreads]);
+ nthreads++;
+ }
+ /*printf("Scanning %s\n", name);*/
+ founddiffs = 0;
+ while(--nthreads >= 0)
+ /* TODO: timeout */
+ pthread_join(tids[nthreads], NULL);
+
+ free(args);
+ free(tids);
+ for(i = 0; i <= nmachines - 2; i++) {
+ int j;
+
+ for(j = i + 1; j <= nmachines - 1; j++) {
+ const char *s, *t;
+
+ s = strchr(results[i], ' ');
+ t = strchr(results[j], ' ');
+ if((s == NULL) || (t == NULL) || (strcmp(s, t) != 0)) {
+ printf("%s:\n", name);
+ printf("\t%s: %s\n", machines[i].name, s ? s : "null");
+ printf("\t%s: %s\n", machines[j].name, t ? t : "null");
+ founddiffs = 1;
+ }
+ }
+ }
+
+ /*if(!founddiffs)
+ printf("%s passed\n", name);*/
+ }
+ closedir(d);
+}
+
+static in_addr_t
+resolve(const char *machine)
+{
+ in_addr_t ret = inet_addr(machine);
+
+ if(ret == INADDR_NONE) {
+ const struct hostent *h = gethostbyname(machine);
+
+ if(h == NULL) {
+ fprintf(stderr, "Unknown host %s\n", machine);
+ return INADDR_NONE;
+ }
+
+ memcpy((char *)&ret, h->h_addr, sizeof(in_addr_t));
+ }
+ return ret;
+}
+
+static int
+start(in_addr_t ip)
+{
+ int sock;
+ const struct protoent *proto;
+ struct sockaddr_in server;
+
+ memset((char *)&server, 0, sizeof(struct sockaddr_in));
+ server.sin_family = AF_INET;
+ server.sin_port = (in_port_t)htons(PORT);
+ server.sin_addr.s_addr = ip;
+
+ proto = getprotobyname("tcp");
+ if(proto == NULL) {
+ fputs("Unknown prototol tcp, check /etc/protocols\n", stderr);
+ return -1;
+ } else if((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
+ perror("socket");
+ return -1;
+ } else if(connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
+ perror("connect");
+ close(sock);
+ return -1;
+ } else if(send(sock, "SESSION\n", 8, 0) < 8) {
+ perror("send");
+ close(sock);
+ return -1;
+ }
+ return sock;
+}
+
+static void *
+scan(void *v)
+{
+ struct args *args;
+ FILE *fin;
+ int sock;
+ ssize_t nbytes;
+ size_t buflen;
+ in_port_t port;
+ struct sockaddr_in data;
+ const struct machine *m;
+ char buf[1024]; /* must be less than MTU */
+
+ args = (struct args *)v;
+ m = args->m;
+ if(m->sock < 0)
+ return NULL;
+ if(m->ip == htonl(INADDR_LOOPBACK)) {
+ char cmd[NAME_MAX + 7];
+
+ snprintf(cmd, sizeof(cmd) - 1, "SCAN %s\n", args->filename);
+ buflen = strlen(cmd);
+
+ if(send(m->sock, cmd, buflen, 0) != (ssize_t)buflen) {
+ perror(m->name);
+ return NULL;
+ }
+ nbytes = recv(m->sock, args->ret, LEN, 0);
+ if(nbytes < 0) {
+ perror(m->name);
+ return NULL;
+ }
+ args->ret[nbytes - 1] = '\0'; /* remove the trailing \n */
+
+ return NULL;
+ }
+ fin = fopen(args->filename, "r");
+ if(fin == NULL) {
+ perror(args->filename);
+ return NULL;
+ }
+ if(send(m->sock, "STREAM\n", 7, 0) != 7) {
+ perror(m->name);
+ fclose(fin);
+ return NULL;
+ }
+
+ if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("socket");
+ fputs("Failed to create TCPSocket to talk to clamd\n", stderr);
+ fclose(fin);
+ return NULL;
+ }
+
+ nbytes = recv(m->sock, buf, sizeof(buf), 0);
+ if(nbytes <= 0) {
+ perror(m->name);
+ close(sock);
+ fclose(fin);
+ return NULL;
+ }
+ buf[nbytes] = '\0';
+
+ if(sscanf(buf, "PORT %hu\n", &port) != 1) {
+ fprintf(stderr, "Expected port information from clamd, got '%s'",
+ buf);
+ close(sock);
+ fclose(fin);
+ return NULL;
+ }
+
+ memset((char *)&data, 0, sizeof(struct sockaddr_in));
+ data.sin_family = AF_INET;
+ data.sin_port = (in_port_t)htons(port);
+ data.sin_addr.s_addr = m->ip;
+
+ if(connect(sock, (struct sockaddr *)&data, sizeof(struct sockaddr_in)) < 0) {
+ perror(m->name);
+ fprintf(stderr, "Couldn't connect to port %d\n", port);
+ close(sock);
+ fclose(fin);
+ return NULL;
+ }
+
+ shutdown(sock, SHUT_RD);
+
+ while((buflen = fread(buf, 1, sizeof(buf), fin)) > 0) {
+ ssize_t sent = send(sock, buf, buflen, 0);
+
+ if(sent != (ssize_t)buflen) {
+ /* Probably hit scanstream len */
+ if(sent < 0)
+ perror(m->name);
+ else
+ fprintf(stderr, "%s: only sent %d bytes of %d to %s\n",
+ args->filename, sent, buflen, m->name);
+ break;
+ }
+ }
+
+ close(sock);
+ fclose(fin);
+
+ /* TODO: timeout */
+ nbytes = recv(m->sock, args->ret, LEN, 0);
+ if(nbytes < 0) {
+ perror(m->name);
+ return NULL;
+ }
+ args->ret[(nbytes) ? (nbytes - 1) : 0] = '\0'; /* remove the trailing \n */
+
+ return NULL;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_libclamav_libclamav.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * $CC $CFLAGS -I../.. -I../../libclamav debugm.c -lclamav
+ * Now try a.out /sbin/* or a.out /usr/bin/*
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <features.h>
+#include <unistd.h>
+#include <memory.h>
+#include <pthread.h>
+#include "clamav-config.h"
+#include "others.h"
+#include "mbox.h"
+#include "pdf.h"
+#include "binhex.h"
+#include "untar.h"
+#include "special.h"
+#include "tnef.h"
+#include "pst.h"
+#include "pe.h"
+
+struct args {
+ cli_ctx ctx;
+ const char *filename;
+};
+
+static void *
+mbox(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cl_mbox(%s) returns %d\n",
+ args->filename, cli_mbox("/tmp/libclamav", fd, &args->ctx));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+pdf(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cl_pdf(%s) returns %d\n",
+ args->filename, cli_pdf("/tmp/libclamav", fd, &args->ctx));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+scandir(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cl_scandir(%s) returns %d\n",
+ args->filename, cli_scandir("/tmp/libclamav", &args->ctx));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+untar(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cl_untar(%s) returns %d\n",
+ args->filename, cli_untar("/tmp/libclamav", fd, 1));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+binhex(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cl_binhex(%s) returns %d\n",
+ args->filename, cli_binhex("/tmp/libclamav", fd));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+jpeg(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cli_check_jpeg_exploit(%s) returns %d\n",
+ args->filename, cli_check_jpeg_exploit(fd));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+tnef(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cli_tnef(%s) returns %d\n",
+ args->filename, cli_tnef("/tmp/libclamav", fd));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+uuencode(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cli_uuencode(%s) returns %d\n",
+ args->filename, cli_uuencode("/tmp/libclamav", fd));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+pst(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cli_pst(%s) returns %d\n",
+ args->filename, cli_pst("/tmp/libclamav", fd));
+ close(fd);
+
+ return NULL;
+}
+
+static void *
+pe(void *v)
+{
+ struct args *args = (struct args *)v;
+ int fd = open(args->filename, O_RDONLY);
+
+ if(fd < 0) {
+ perror(args->filename);
+ return NULL;
+ }
+ printf("cli_scanpe(%s) returns %d\n",
+ args->filename, cli_scanpe(fd, &args->ctx));
+ close(fd);
+
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct rlimit rlim;
+ const char *virname;
+ struct cl_engine engine;
+ struct cl_limits limits;
+ unsigned long scanned;
+ struct args args;
+
+ if(argc == 1) {
+ fprintf(stderr, "Usage: %s files...\n", argv[0]);
+ return 1;
+ }
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+ perror("setrlimit");
+
+ if((mkdir("/tmp/libclamav", 0750) < 0) && (errno != EEXIST)) {
+ perror("/tmp/libclamav");
+ return errno;
+ }
+
+ memset(&args.ctx, '\0', sizeof(cli_ctx));
+ args.ctx.engine = &engine;
+ args.ctx.virname = &virname;
+ args.ctx.limits = &limits;
+ args.ctx.scanned = &scanned;
+ args.ctx.options = 0;
+
+ while(*++argv) {
+ pthread_t t;
+
+ args.filename = *argv;
+
+ if(pthread_create(&t, NULL, mbox, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, pdf, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, untar, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, binhex, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, jpeg, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, tnef, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, uuencode, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, pst, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ if(pthread_create(&t, NULL, pe, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+
+ /* TODO: pass through all in cli_magic_scandesc */
+ if(pthread_create(&t, NULL, scandir, &args) != 0)
+ perror("pthread_create");
+ if(pthread_detach(t) != 0)
+ perror("pthread_detach");
+ }
+ puts("Hit SIGINT when all is finished");
+ pause();
+ puts("Finished - don't forget to rm -rf /tmp/libclamav");
+
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_mbox_debugm.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,91 @@
+/*
+ * $CC $CFLAGS -I../.. debugm.c -lclamav -lefence (or what ever memory debugger)
+ * If you're going to use HAVE_BACKTRACE, ensure CFLAGS includes -g and doesn't
+ * include -fomit-frame-pointer
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <features.h>
+#include "clamav-config.h"
+
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
+/*#define HAVE_BACKTRACE /* Only tested on Linux... */
+#endif
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+static void print_trace(void);
+static void sigsegv(int sig);
+
+static void
+sigsegv(int sig)
+{
+ signal(SIGSEGV, SIG_DFL);
+ print_trace();
+ _exit(SIGSEGV);
+}
+
+static void
+print_trace(void)
+{
+#ifdef HAVE_BACKTRACE
+ void *array[10];
+ size_t size, i;
+ char **strings;
+
+ puts("Segfault caught, backtrace:");
+
+ size = backtrace(array, 10);
+ strings = backtrace_symbols(array, size);
+
+ for(i = 0; i < size; i++)
+ printf("\t%s\n", strings[i]);
+
+ free(strings);
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+ struct rlimit rlim;
+
+ if(argc == 1) {
+ fprintf(stderr, "Usage: %s files...\n", argv[0]);
+ return 1;
+ }
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+ perror("setrlimit");
+
+ if(mkdir("/tmp/mboxtest", 0750) < 0) {
+ perror("/tmp/mboxtest");
+ return errno;
+ }
+ signal(SIGSEGV, sigsegv);
+ while(*++argv) {
+ int fd = open(*argv, 0);
+
+ if(fd < 0) {
+ perror(*argv);
+ return errno;
+ }
+ printf("cl_mbox(%s) returns %d\n",
+ *argv, cl_mbox("/tmp/mboxtest", fd));
+ close(fd);
+ }
+ puts("Finished - don't forget to rm -rf /tmp/mboxtest");
+
+ return 0;
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/test_pe_debugpe.c Wed Jan 30 15:17:10 2008
@@ -0,0 +1,177 @@
+/*
+ * $CC -DHAVE_CONFIG_H $CFLAGS -I../.. debugpe.c -lclamav -lefence (or what
+ * ever memory debugger)
+ * If you're going to use HAVE_BACKTRACE, ensure CFLAGS includes -g and doesn't
+ * include -fomit-frame-pointer
+ *
+ * njh at bandsman.co.uk
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <clamav.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <features.h>
+#include <memory.h>
+#include <unistd.h>
+
+#include "clamav-config.h"
+#include "others.h"
+#include "pe.h"
+
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
+/*#define HAVE_BACKTRACE /* Only tested on Linux... */
+#endif
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+static const uint16_t test1[] = {
+ 0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+ 0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+ 0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+ 0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+ 0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+ 0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+ 0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+ 0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test2[] = {
+ 0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+ 0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+ 0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+ 0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+ 0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+ 0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+ 0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+ 0x6a82, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test3[] = {
+ 0x5a4d, 0x0091, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+ 0x00b8, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+ 0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+ 0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+ 0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+ 0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+ 0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+ 0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+static const uint16_t test4[] = {
+ 0x5a4d, 0x0090, 0x0003, 0x0000, 0x0004, 0x0000, 0xffff, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000,
+ 0x1f0e, 0x0eba, 0xb400, 0xcd09, 0xb821, 0x4c01, 0x21cd, 0x6854,
+ 0x7369, 0x7020, 0x6f72, 0x7267, 0x6d61, 0x6320, 0x6e61, 0x6f6e,
+ 0x2074, 0x6562, 0x7220, 0x6e75, 0x6920, 0x206e, 0x4f44, 0x2053,
+ 0x6f6d, 0x6564, 0x0d2e, 0x0a0d, 0x0024, 0x0000, 0x0000, 0x0000,
+ 0x07c2, 0x23b9, 0x6686, 0x70d7, 0x6686, 0x70d7, 0x6686, 0x70d7,
+ 0x6a83, 0x7088, 0x668f, 0x70d7, 0x6e05, 0x7088, 0x6687, 0x70d7
+};
+
+static struct tests {
+ const uint16_t *test;
+ unsigned int size;
+} tests[] = {
+ { test1, sizeof(test1) },
+ { test2, sizeof(test2) },
+ { test3, sizeof(test3) },
+ { test4, sizeof(test4) },
+ { NULL, 0 },
+};
+
+static const char *tmp_file = "/tmp/petest";
+
+static void print_trace(void);
+static void sigsegv(int sig);
+
+static void
+sigsegv(int sig)
+{
+ signal(SIGSEGV, SIG_DFL);
+ print_trace();
+ _exit(SIGSEGV);
+}
+
+static void
+print_trace(void)
+{
+#ifdef HAVE_BACKTRACE
+ void *array[10];
+ size_t size, i;
+ char **strings;
+
+ puts("Segfault caught, backtrace:");
+
+ size = backtrace(array, 10);
+ strings = backtrace_symbols(array, size);
+
+ for(i = 0; i < size; i++)
+ printf("\t%s\n", strings[i]);
+
+ free(strings);
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+ const struct tests *t;
+ int fd;
+ struct rlimit rlim;
+ cli_ctx ctx;
+
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ if(setrlimit(RLIMIT_CORE, &rlim) < 0)
+ perror("setrlimit");
+
+ memset(&ctx, '\0', sizeof(cli_ctx));
+ /*printf("cl_scanpe(-1) returns %d\n", cli_scanpe(-1, &ctx));
+ printf("cl_scanpe(10) returns %d\n", cli_scanpe(10, &ctx));
+ printf("cl_scanpe(10000) returns %d\n", cli_scanpe(10000, &ctx));*/
+ cli_scanpe(-1, &ctx);
+ cli_scanpe(-1, NULL);
+ cli_scanpe(10, &ctx);
+ cli_scanpe(10, NULL);
+ cli_scanpe(10000, &ctx);
+ cli_scanpe(10000, NULL);
+
+ for(t = tests; t->test; t++) {
+ int n;
+
+ for(n = t->size; n >= 1; --n) {
+ int m;
+
+ for(m = 0; m < n; m++) {
+ fd = open(tmp_file, O_CREAT|O_RDWR, 0600);
+
+ if(fd < 0) {
+ perror(tmp_file);
+ return errno;
+ }
+
+ write(fd, &t->test[m], n - m);
+
+ signal(SIGSEGV, sigsegv);
+
+ memset(&ctx, '\0', sizeof(cli_ctx));
+ cli_scanpe(fd, &ctx);
+ cli_scanpe(fd, NULL);
+ /*printf("cl_scanpe() returns %d\n", cli_scanpe(fd, &ctx));*/
+ close(fd);
+ }
+ }
+ }
+
+ return unlink(tmp_file);
+}
Added: test-suite/trunk/MultiSource/Applications/ClamAV/text.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/text.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/text.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/text.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2002 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * $Log: text.h,v $
+ * Revision 1.9 2006/07/01 16:17:35 njh
+ * Added destroy flag
+ *
+ * Revision 1.8 2006/04/09 19:59:28 kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.7 2004/12/04 16:03:55 nigelhorne
+ * Text/plain now handled as no encoding
+ *
+ * Revision 1.6 2004/08/22 10:34:24 nigelhorne
+ * Use fileblob
+ *
+ * Revision 1.5 2004/08/21 11:57:57 nigelhorne
+ * Use line.[ch]
+ *
+ * Revision 1.4 2004/07/20 14:35:29 nigelhorne
+ * Some MYDOOM.I were getting through
+ *
+ * Revision 1.3 2004/06/22 04:08:02 nigelhorne
+ * Optimise empty lines
+ *
+ */
+
+/* The contents could change, ONLY access in text.c */
+typedef struct text {
+ line_t *t_line; /* NULL if the line is empty */
+ struct text *t_next;
+} text;
+
+#include "message.h"
+
+void textDestroy(text *t_head);
+text *textAddMessage(text *aText, message *aMessage);
+text *textMove(text *t_head, text *t);
+blob *textToBlob(text *t, blob *b, int destroy);
+fileblob *textToFileblob(text *t, fileblob *fb, int destroy);
Added: test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/tnef.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2005 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+int cli_tnef(const char *dir, int desc);
Added: test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/treewalk.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2002, 2003 Tomasz Kojm <tkojm at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __TREEWALK_H
+#define __TREEWALK_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "clamav.h"
+#include "options.h"
+
+struct s_du {
+ unsigned int files;
+ unsigned long int space; /* in kilobytes */
+};
+
+int treewalk(const char *dirname, struct cl_engine *engine, const struct passwd *user, const struct optstruct *opt, const struct cl_limits *limits, unsigned int options, unsigned int depth);
+
+int clamav_rmdirs(const char *dir);
+int fixperms(const char *dirname);
+int du(const char *dirname, struct s_du *n);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unarj.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ * Extract component parts of ARJ archives
+ *
+ * Copyright (C) 2007 trog at uncon.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __UNARJ_H
+#define __UNARJ_H
+
+typedef struct arj_metadata_tag {
+ uint32_t comp_size;
+ uint32_t orig_size;
+ uint8_t method;
+ char *filename;
+ int encrypted;
+ int ofd;
+} arj_metadata_t;
+
+int cli_unarj_open(int fd, const char *dirname);
+int cli_unarj_prepare_file(int fd, const char *dirname, arj_metadata_t *metadata);
+int cli_unarj_extract_file(int fd, const char *dirname, arj_metadata_t *metadata);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unsp.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __UNSP_H
+#define __UNSP_H
+
+#include "cltypes.h"
+#include "others.h"
+
+struct UNSP {
+ char *src_curr;
+ char *src_end;
+ uint32_t bitmap;
+ uint32_t oldval;
+ int error;
+ /* the following are not in the original structure */
+ char *table;
+ uint32_t tablesz;
+};
+
+uint32_t unspack(char *, char *, cli_ctx *, uint32_t, uint32_t, uint32_t, int);
+uint32_t very_real_unpack(uint16_t *, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, char *, uint32_t);
+uint32_t get_byte(struct UNSP *);
+int getbit_from_table(uint16_t *, struct UNSP *);
+uint32_t get_100_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
+uint32_t get_100_bits_from_table(uint16_t *, struct UNSP *);
+uint32_t get_n_bits_from_table(uint16_t *, uint32_t, struct UNSP *);
+uint32_t get_n_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
+uint32_t get_bb(uint16_t *, uint32_t, struct UNSP *);
+uint32_t get_bitmap(struct UNSP *, uint32_t);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/untar.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/untar.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/untar.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/untar.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2004 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ *
+ * Change History:
+ * $Log: untar.h,v $
+ * Revision 1.5 2006/12/22 18:29:13 njh
+ * Recommit fix for bug 153
+ *
+ * Revision 1.4 2006/04/09 19:59:28 kojm
+ * update GPL headers with new address for FSF
+ *
+ * Revision 1.3 2005/03/22 21:26:27 kojm
+ * add support for old fashioned tar archives
+ *
+ * Revision 1.2 2004/09/05 18:58:22 nigelhorne
+ * Extract files completed
+ *
+ * Revision 1.1 2004/09/05 15:28:10 nigelhorne
+ * First draft
+ *
+ */
+int cli_untar(const char *dir, int desc, unsigned int posix, const struct cl_limits *limits);
Added: test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/unzip.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2003 - 2006 Tomasz Kojm <tkojm at clamav.net>
+ * (C) 2006 Sensory Networks, Inc.
+ *
+ * The code of this module was based on zziplib 0.12.83:
+ * (c) 1999 - 2002 Guido Draheim <guidod at gmx.de>, published under
+ * the Lesser GNU General Public License
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __UNZIP_H
+#define __UNZIP_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "cltypes.h"
+
+#ifndef HAVE_ATTRIB_PACKED
+#define __attribute__(x)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack(1)
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack 1
+#endif
+
+/******** Zip format structures *********/
+
+/* Local file header */
+struct zip_file_header
+{
+# define ZIP_FILE_HEADER_MAGIC 0x04034b50
+ uint32_t z_magic; /* local file header signature */
+ uint16_t z_version; /* version needed to extract */
+ uint16_t z_flags; /* general purpose bit flag */
+ uint16_t z_compr; /* compression method */
+ uint16_t z_modtime; /* last mod file time */
+ uint16_t z_moddate; /* last mod file date */
+ uint32_t z_crc32; /* crc-32 */
+ uint32_t z_csize; /* compressed size */
+ uint32_t z_usize; /* uncompressed size */
+ uint16_t z_namlen; /* file name length */
+ uint16_t z_extras; /* extra field length */
+
+ /* followed by filename (of variable size) */
+ /* followed by extra field (of variable size) */
+} __attribute__((packed));
+
+/* Data descriptor (only if bit 3 of z_flags is set) */
+struct zip_file_trailer
+{
+# define ZIP_FILE_TRAILER_MAGIC 0x08074B50
+ uint32_t z_magic; /* data descriptor signature (0x08074b50) */
+ uint32_t z_crc32; /* crc-32 */
+ uint32_t z_csize; /* compressed size */
+ uint32_t z_usize; /* uncompressed size */
+} __attribute__((packed));
+
+/* Central file header */
+struct zip_root_dirent
+{
+# define ZIP_ROOT_DIRENT_MAGIC 0x02014b50
+ uint32_t z_magic; /* central file header signature */
+ uint16_t z_version1; /* version made by */
+ uint16_t z_version2; /* version needed to extract */
+ uint16_t z_flags; /* general purpose bit flag */
+ uint16_t z_compr; /* compression method */
+ uint16_t z_modtime; /* last mod file time */
+ uint16_t z_moddate; /* last mod file date */
+ uint32_t z_crc32; /* crc-32 */
+ uint32_t z_csize; /* compressed size */
+ uint32_t z_usize; /* uncompressed size */
+ uint16_t z_namlen; /* file name length */
+ uint16_t z_extras; /* extra field length */
+ uint16_t z_comment; /* file comment length */
+ uint16_t z_diskstart; /* disk number start */
+ uint16_t z_filetype; /* internal file attributes */
+ uint32_t z_filemode; /* extrnal file attributes */
+ uint32_t z_off; /* relative offset of local header */
+
+ /* followed by filename (of variable size) */
+ /* followed by extra field (of variable size) */
+ /* followed by file comment (of variable size) */
+} __attribute__((packed));
+
+/* End of central directory record */
+struct zip_disk_trailer
+{
+# define ZIP_DISK_TRAILER_MAGIC 0x06054b50
+ uint32_t z_magic; /* end of central dir signature */
+ uint16_t z_disk; /* number of this disk */
+ uint16_t z_finaldisk; /* number of the disk with the start
+ * of the central dir
+ */
+ uint16_t z_entries; /* total number of entries in the
+ * central dir on this disk
+ */
+ uint16_t z_finalentries; /* total number of entries in the
+ * central dir
+ */
+ uint32_t z_rootsize; /* size of the central directory */
+ uint32_t z_rootseek; /* offset of start of central directory
+ * with respect to the starting disk
+ * number
+ */
+ uint16_t z_comment; /* zipfile comment length */
+
+ /* followed by zipfile comment (of variable size) */
+} __attribute__((packed));
+
+#define ZIP_METHOD_STORED 0
+#define ZIP_METHOD_SHRUNK 1
+#define ZIP_METHOD_REDUCEDx1 2
+#define ZIP_METHOD_REDUCEDx2 3
+#define ZIP_METHOD_REDUCEDx3 4
+#define ZIP_METHOD_REDUCEDx4 5
+#define ZIP_METHOD_IMPLODED 6
+#define ZIP_METHOD_TOKENIZED 7
+#define ZIP_METHOD_DEFLATED 8
+#define ZIP_METHOD_DEFLATED64 9
+#define ZIP_METHOD_IMPLODED_DCL 10
+#define ZIP_METHOD_BZIP2 12
+#define ZIP_METHOD_AES 99
+
+
+/******** Internal structures *********/
+
+struct __zip_file
+{
+ struct __zip_dir *dir;
+ uint16_t method;
+ int16_t *bf;
+ size_t restlen;
+ size_t crestlen;
+ size_t usize;
+ size_t csize;
+ char *buf32k;
+ z_stream d_stream;
+};
+
+struct __zip_dir_hdr
+{
+ uint32_t d_usize; /* uncompressed size */
+ uint32_t d_csize; /* compressed size */
+ uint32_t d_crc32; /* crc-32 */
+ uint32_t d_off; /* offset of file in zipfile */
+ uint16_t d_reclen; /* next dir_hdr structure offset */
+ uint16_t d_namlen; /* explicit namelen of d_name */
+ uint16_t d_compr; /* compression type */
+ int16_t d_bf[2]; /* compression type/brute force */
+ uint16_t d_flags; /* general purpose flags */
+ char d_name[1]; /* actual name of the entry */
+};
+
+struct __zip_dirent
+{
+ uint16_t d_compr; /* compression method */
+ uint32_t d_csize; /* compressed size */
+ uint32_t st_size; /* file size / decompressed size */
+ uint16_t d_flags; /* general purpose flags */
+ char *d_name; /* file name / strdupped name */
+ uint32_t d_crc32; /* crc-32 */
+ uint32_t d_off; /* the offset in the file */
+};
+
+struct __zip_dir
+{
+ int fd;
+ int errcode;
+ struct {
+ struct __zip_file *fp;
+ char *buf32k;
+ } cache;
+ struct __zip_dir_hdr *hdr0;
+ struct __zip_dir_hdr *hdr;
+ struct __zip_dirent dirent;
+};
+
+/* typedefs */
+typedef struct __zip_dir zip_dir;
+typedef struct __zip_dir_hdr zip_dir_hdr;
+typedef struct __zip_file zip_file;
+typedef struct __zip_dirent zip_dirent;
+
+zip_dir *zip_dir_open(int fd, off_t start, int *errcode_p);
+int zip_dir_read(zip_dir *dir, zip_dirent *d);
+zip_file *zip_file_open(zip_dir *dir, const char *name, int d_off);
+ssize_t zip_file_read(zip_file *fp, char *buf, size_t len);
+int zip_file_close(zip_file *fp);
+int zip_dir_close(zip_dir *dir);
+
+#ifdef HAVE_PRAGMA_PACK
+#pragma pack()
+#endif
+
+#ifdef HAVE_PRAGMA_PACK_HPPA
+#pragma pack
+#endif
+
+#endif /* __UNZIP_H */
Added: test-suite/trunk/MultiSource/Applications/ClamAV/upack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/upack.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/upack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/upack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 Michal 'GiM' Spadlinski http://gim.org.pl/
+ *
+ * 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.
+ */
+
+#ifndef __UPACK_H
+#define __UPACK_H
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include "cltypes.h"
+
+int unupack(int, char *, uint32_t, char *, uint32_t, uint32_t, uint32_t, uint32_t, int);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/upx.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/upx.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/upx.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/upx.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __UPX_H
+#define __UPX_H
+
+#include "cltypes.h"
+
+int upx_inflate2b(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+int upx_inflate2d(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+int upx_inflate2e(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/utils.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/utils.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/utils.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/utils.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,59 @@
+/*-
+ * This code is derived from OpenBSD's libc/regex, original license follows:
+ *
+ * Copyright (c) 1992, 1993, 1994 Henry Spencer.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Henry Spencer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)utils.h 8.3 (Berkeley) 3/20/94
+ */
+
+/* utility definitions */
+#define DUPMAX _POSIX2_RE_DUP_MAX /* xxx is this right? */
+#define INFINITY (DUPMAX + 1)
+#define NC (CHAR_MAX - CHAR_MIN + 1)
+typedef unsigned char uch;
+
+/* switch off assertions (if not already off) if no REDEBUG */
+#ifdef CL_DEBUG
+#define REDEBUG
+#endif
+
+#ifndef REDEBUG
+#ifndef NDEBUG
+#define NDEBUG /* no assertions please */
+#endif
+#endif
+#include <assert.h>
+
+/* for old systems with bcopy() but no memmove() */
+#ifdef USEBCOPY
+#define memmove(d, s, c) bcopy(s, d, c)
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/uuencode.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 Nigel Horne <njh at bandsman.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef __UUENCODE_H
+#define __UUENCODE_H
+
+int cli_uuencode(const char *dir, int desc);
+int uudecodeFile(message *m, const char *firstline, const char *dir, FILE *fin);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/vba_extract.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,48 @@
+/*
+ * Extract VBA source code for component MS Office Documents
+ *
+ * Copyright (C) 2004 trog at uncon.org
+ *
+ * This code is based on the OpenOffice and libgsf sources.
+ *
+ * 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.
+ */
+
+#ifndef __VBA_EXTRACT_H
+#define __VBA_EXTRACT_H
+
+#include "cltypes.h"
+
+typedef struct vba_project_tag {
+ int count;
+ char **name;
+ uint32_t *offset;
+ uint32_t *length; /* for Word 6 macros */
+ unsigned char *key; /* for Word 6 macros */
+ char *dir;
+} vba_project_t;
+
+vba_project_t *vba56_dir_read(const char *dir);
+unsigned char *vba_decompress(int fd, uint32_t offset, int *size);
+int cli_decode_ole_object(int fd, const char *dir);
+
+char *ppt_vba_read(const char *dir);
+
+vba_project_t *wm_dir_read(const char *dir);
+unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
+ unsigned char key);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/wwunpack.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2006 Sensory Networks, Inc.
+ * Written by aCaB <acab at clamav.net>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __WWP32_H
+#define __WWP32_H
+
+#include "cltypes.h"
+#include "rebuildpe.h"
+
+int wwunpack(char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, uint16_t);
+
+#endif
Added: test-suite/trunk/MultiSource/Applications/ClamAV/yc.h
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/ClamAV/yc.h?rev=46573&view=auto
==============================================================================
--- test-suite/trunk/MultiSource/Applications/ClamAV/yc.h (added)
+++ test-suite/trunk/MultiSource/Applications/ClamAV/yc.h Wed Jan 30 15:17:10 2008
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2005 aCaB <acab at clamav.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __YC_H
+#define __YC_H
+
+#include "pe.h"
+#include "execs.h"
+#include "cltypes.h"
+
+int yc_decrypt(char *, unsigned int, struct cli_exe_section *, unsigned int, uint32_t, int);
+
+#endif
Modified: test-suite/trunk/MultiSource/Applications/Makefile
URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/MultiSource/Applications/Makefile?rev=46573&r1=46572&r2=46573&view=diff
==============================================================================
--- test-suite/trunk/MultiSource/Applications/Makefile (original)
+++ test-suite/trunk/MultiSource/Applications/Makefile Wed Jan 30 15:17:10 2008
@@ -5,7 +5,7 @@
include $(LEVEL)/Makefile.config
PARALLEL_DIRS = Burg aha sgefa siod lambda-0.1.3 d spiff hbd treecc SPASS \
- hexxagon oggenc JM viterbi minisat SIBsim4
+ hexxagon oggenc JM viterbi minisat SIBsim4 ClamAV
# Obsequi uses Linux-only features; need to fix that
ifeq ($(OS),Linux)
More information about the llvm-commits
mailing list