2abe7362 |
/* |
c442ca9c |
* Copyright (C) 2014-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
2abe7362 |
*
* Authors: Steven Morgan <smorgan@sourcefire.com>
*
* 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 <dirent.h>
#include <errno.h>
#include <string.h>
|
60d8d2c3 |
#include "clamav.h" |
53506979 |
#include "others.h"
#include "openioc.h"
#ifdef HAVE_LIBXML2 |
2abe7362 |
#include <libxml/xmlreader.h>
struct openioc_hash {
unsigned char * hash;
void * next;
};
static const xmlChar * openioc_read(xmlTextReaderPtr reader)
{
const xmlChar * name;
if (xmlTextReaderRead(reader) != 1)
return NULL;
name = xmlTextReaderConstLocalName(reader);
if (name != NULL) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s%s\n", name, |
2abe7362 |
xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT?" end tag":"");
}
return name;
}
|
7e302913 |
static int openioc_is_context_hash(xmlTextReaderPtr reader)
{
xmlChar * document = xmlTextReaderGetAttribute(reader, (const xmlChar *)"document");
xmlChar * search = xmlTextReaderGetAttribute(reader, (const xmlChar *)"search");
int rc = 0;
if ((document != NULL && search != NULL) &&
!xmlStrcmp(document, (const xmlChar *)"FileItem") &&
(!xmlStrcmp(search, (const xmlChar *)"FileItem/Md5sum") ||
!xmlStrcmp(search, (const xmlChar *)"FileItem/Sha1sum") ||
!xmlStrcmp(search, (const xmlChar *)"FileItem/Sha256sum")))
rc = 1;
if (document != NULL)
xmlFree(document);
if (search != NULL)
xmlFree(search);
return rc;
}
static int openioc_parse_content(xmlTextReaderPtr reader, struct openioc_hash ** elems, int context_hash) |
2abe7362 |
{
const xmlChar * xmlval;
struct openioc_hash * elem;
int rc = CL_SUCCESS;
|
7e302913 |
if (context_hash == 0) {
xmlChar * type = xmlTextReaderGetAttribute(reader, (const xmlChar *)"type");
if (type == NULL) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderGetAttribute no type attribute " |
7e302913 |
"for <Content> element\n"); |
2abe7362 |
return rc; |
7e302913 |
} else {
if (xmlStrcasecmp(type, (const xmlChar *)"sha1") &&
xmlStrcasecmp(type, (const xmlChar *)"sha256") &&
xmlStrcasecmp(type, (const xmlChar *)"md5")) {
xmlFree(type);
return rc;
} |
2abe7362 |
} |
7e302913 |
xmlFree(type); |
2abe7362 |
}
if (xmlTextReaderRead(reader) == 1 && xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) {
xmlval = xmlTextReaderConstValue(reader);
if (xmlval) {
elem = cli_calloc(1, sizeof(struct openioc_hash));
if (NULL == elem) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: calloc fails for openioc_hash.\n"); |
2abe7362 |
return CL_EMEM;
}
elem->hash = xmlStrdup(xmlval);
elem->next = *elems;
*elems = elem;
} else { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderConstValue() returns NULL for Content md5 value.\n"); |
2abe7362 |
}
}
else { |
3cd30f98 |
cli_dbgmsg("openioc_parse: No text for XML Content element.\n"); |
2abe7362 |
}
return rc;
}
static int openioc_parse_indicatoritem(xmlTextReaderPtr reader, struct openioc_hash ** elems)
{
const xmlChar * name;
int rc = CL_SUCCESS; |
7e302913 |
int context_hash = 0; |
2abe7362 |
while (1) {
name = openioc_read(reader);
if (name == NULL)
break; |
7e302913 |
if (xmlStrEqual(name, (const xmlChar *)"Context") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
context_hash = openioc_is_context_hash(reader);
} else if (xmlStrEqual(name, (const xmlChar *)"Content") && |
2abe7362 |
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) { |
7e302913 |
rc = openioc_parse_content(reader, elems, context_hash); |
2abe7362 |
if (rc != CL_SUCCESS) {
break;
}
} else if (xmlStrEqual(name, (const xmlChar *)"IndicatorItem") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
break;
}
}
return rc;
}
static int openioc_parse_indicator(xmlTextReaderPtr reader, struct openioc_hash ** elems)
{
const xmlChar * name;
int rc = CL_SUCCESS;
while (1) {
name = openioc_read(reader);
if (name == NULL)
return rc;
if (xmlStrEqual(name, (const xmlChar *)"Indicator") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
rc = openioc_parse_indicator(reader, elems);
if (rc != CL_SUCCESS) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: openioc_parse_indicator recursion error.\n"); |
2abe7362 |
break;
}
} else if (xmlStrEqual(name, (const xmlChar *)"IndicatorItem") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
rc = openioc_parse_indicatoritem(reader, elems);
if (rc != CL_SUCCESS) {
break;
}
} else if (xmlStrEqual(name, (const xmlChar *)"Indicator") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
break;
}
}
return rc;
}
|
ad8ddf98 |
int openioc_parse(const char * fname, int fd, struct cl_engine *engine, unsigned int options) |
2abe7362 |
{
int rc;
xmlTextReaderPtr reader = NULL;
const xmlChar * name;
struct openioc_hash * elems = NULL, * elem = NULL;
const char * iocp = NULL;
uint16_t ioclen;
char * virusname; |
3cd30f98 |
int hash_count = 0; |
2abe7362 |
if (fname == NULL)
return CL_ENULLARG;
if (fd < 0)
return CL_EARG;
|
3cd30f98 |
cli_dbgmsg("openioc_parse: XML parsing file %s\n", fname); |
2abe7362 |
|
d3e752ad |
reader = xmlReaderForFd(fd, NULL, NULL, CLAMAV_MIN_XMLREADER_FLAGS); |
2abe7362 |
if (reader == NULL) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlReaderForFd error\n"); |
2abe7362 |
return CL_EOPEN;
}
rc = xmlTextReaderRead(reader);
while (rc == 1) {
name = xmlTextReaderConstLocalName(reader); |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s\n", name); |
2abe7362 |
if (xmlStrEqual(name, (const xmlChar *)"Indicator") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
rc = openioc_parse_indicator(reader, &elems);
if (rc != CL_SUCCESS) { |
691e9545 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader); |
2abe7362 |
return rc;
}
}
if (xmlStrEqual(name, (const xmlChar *)"ioc") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
break;
}
rc = xmlTextReaderRead(reader);
}
iocp = strrchr(fname, *PATHSEP);
if (NULL == iocp)
iocp = fname;
else
iocp++;
|
8efbf4a0 |
ioclen = (uint16_t)strlen(fname); |
2abe7362 |
if (elems != NULL) {
if (NULL == engine->hm_hdb) {
engine->hm_hdb = mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher)); |
691e9545 |
if (NULL == engine->hm_hdb) {
xmlTextReaderClose(reader);
xmlFreeTextReader(reader); |
2abe7362 |
return CL_EMEM; |
691e9545 |
} |
2abe7362 |
#ifdef USE_MPOOL
engine->hm_hdb->mempool = engine->mempool;
#endif
}
}
while (elems != NULL) { |
53506979 |
const char * sp;
char * hash, * vp; |
2abe7362 |
int i, hashlen;
elem = elems;
elems = elems->next; |
cd94be7a |
hash = (char *)(elem->hash); |
2abe7362 |
while (isspace(*hash))
hash++;
hashlen = strlen(hash);
if (hashlen == 0) {
xmlFree(elem->hash);
free(elem);
continue;
} |
53506979 |
vp = hash+hashlen-1;
while (isspace(*vp) && vp > hash) {
*vp-- = '\0'; |
2abe7362 |
hashlen--;
} |
906cbb7d |
virusname = calloc(1, ioclen+hashlen+2); |
762c9ae3 |
if (NULL == virusname) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n"); |
691e9545 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader); |
2abe7362 |
return CL_EMEM;
} |
53506979 |
sp = fname; |
ad8ddf98 |
vp = virusname; |
2abe7362 |
for (i=0; i<ioclen; i++, sp++, vp++) {
switch (*sp) {
case '\\':
case '/':
case '?':
case '%':
case '*':
case ':':
case '|':
case '"':
case '<':
case '>':
*vp = '_'; |
3e14b32b |
break; |
2abe7362 |
default:
if (isspace(*sp))
*vp = '_';
else
*vp = *sp;
}
}
*vp++ = '.';
sp = hash;
for (i=0; i<hashlen; i++, sp++) {
if (isxdigit(*sp)) {
*vp++ = *sp;
}
} |
ad8ddf98 |
vp = virusname;
virusname = cli_mpool_virname(engine->mempool, virusname, options & CL_DB_OFFICIAL);
if (!(virusname)) {
cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n");
xmlTextReaderClose(reader);
xmlFreeTextReader(reader);
free(vp);
return CL_EMEM;
}
free(vp);
|
2abe7362 |
rc = hm_addhash_str(engine->hm_hdb, hash, 0, virusname); |
7e302913 |
if (rc != CL_SUCCESS) |
3cd30f98 |
cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n", |
2abe7362 |
rc, hashlen, virusname); |
3cd30f98 |
else
hash_count++;
|
2abe7362 |
xmlFree(elem->hash);
free(elem);
} |
7e302913 |
|
3cd30f98 |
if (hash_count == 0)
cli_warnmsg("openioc_parse: No hash signatures extracted from %s.\n", fname);
else
cli_dbgmsg("openioc_parse: %i hash signature%s extracted from %s.\n",
hash_count, hash_count==1?"":"s", fname);
|
7f92f975 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader);
|
53506979 |
return CL_SUCCESS; |
2abe7362 |
} |
53506979 |
#else |
77a04a7f |
int openioc_parse(const char * fname, int fd, struct cl_engine *engine, unsigned int options) |
53506979 |
{ |
3cd30f98 |
cli_dbgmsg("openioc_parse: libxml2 support is compiled out and is needed for OpenIOC support.\n"); |
53506979 |
return CL_SUCCESS;
}
#endif |