libclamav/matcher-md5.c
44712fcb
 /*
  *  Copyright (C) 2007-2010 Sourcefire, Inc.
  *
  *  Authors: 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 "clamav.h"
 #include "memory.h"
 #include "mpool.h"
 #include "others.h"
 #include "cltypes.h"
 #include "matcher.h"
 #include "matcher-md5.h"
 
 #define HASH(a,b,c) (211 * a + 37 * b + c)
 
 int cli_md5m_addpatt(struct cli_matcher *root, struct cli_md5m_patt *patt)
 {
 	unsigned int idx;
 	struct cli_md5m_patt *prev, *next = NULL;
 
     idx = HASH(patt->md5[0], patt->md5[1], patt->md5[2]);
     prev = next = root->md5tab[idx];
     while(next) {
 	if(patt->md5[0] >= next->md5[0])
 	    break;
 	prev = next;
 	next = next->next;
     }
 
     if(next == root->md5tab[idx]) {
 	patt->next = root->md5tab[idx];
 	root->md5tab[idx] = patt;
     } else {
 	patt->next = prev->next;
 	prev->next = patt;
     }
 
     root->md5_patterns++;
     return CL_SUCCESS;
 }
 
 int cli_md5m_init(struct cli_matcher *root)
 {
8e7139b4
 #ifdef USE_MPOOL
44712fcb
     if(!root->mempool) {
 	cli_errmsg("cli_md5m_init: mempool must be initialized\n");
 	return CL_EMEM;
     }
8e7139b4
 #endif
44712fcb
 
     if(!(root->md5tab = (struct cli_md5m_patt **) mpool_calloc(root->mempool, HASH(255, 255, 255) + 1, sizeof(struct cli_md5m_patt *)))) {
 	mpool_free(root->mempool, root->bm_shift);
 	return CL_EMEM;
     }
 
     return CL_SUCCESS;
 }
 
 void cli_md5m_free(struct cli_matcher *root)
 {
 	struct cli_md5m_patt *patt, *prev;
 	unsigned int i, size = HASH(255, 255, 255) + 1;
 
     if(root->md5tab) {
 	for(i = 0; i < size; i++) {
 	    patt = root->md5tab[i];
 	    while(patt) {
 		prev = patt;
 		patt = patt->next;
 		if(prev->virname)
 		    mpool_free(root->mempool, prev->virname);
 		mpool_free(root->mempool, prev);
 	    }
 	}
 	mpool_free(root->mempool, root->md5tab);
     }
 }
 
 int cli_md5m_scan(const unsigned char *md5, uint32_t filesize, const char **virname, const struct cli_matcher *root)
 {
 	unsigned int pchain = 0, idx;
 	struct cli_md5m_patt *p;
 
     if(!root)
 	return CL_CLEAN;
 
     idx = HASH(md5[0], md5[1], md5[2]);
     p = root->md5tab[idx];
     if(!p || (!p->next && p->filesize != filesize))
 	return CL_CLEAN;
 
     while(p) {
 	if(p->md5[0] != md5[0]) {
 	    if(pchain)
 		break;
 	    p = p->next;
 	    continue;
 	} else pchain = 1;
 
 	if(p->filesize != filesize) {
 	    p = p->next;
 	    continue;
 	}
 
 	if(!memcmp(p->md5, md5, 16)) {
 	    if(virname)
 		*virname = p->virname;
 	    return CL_VIRUS;
 	}
 	p = p->next;
     }
 
     return CL_CLEAN;
 }