2abe7362 |
/* |
e1cbc270 |
* 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 |
b0e47a6d |
|
2abe7362 |
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
|
b0e47a6d |
#include "mpool.h"
#include "readdb.h" |
60d8d2c3 |
#include "clamav.h" |
53506979 |
#include "others.h"
#include "openioc.h"
#ifdef HAVE_LIBXML2 |
2abe7362 |
#include <libxml/xmlreader.h>
struct openioc_hash { |
288057e9 |
unsigned char *hash;
void *next; |
2abe7362 |
};
|
288057e9 |
static const xmlChar *openioc_read(xmlTextReaderPtr reader) |
2abe7362 |
{ |
288057e9 |
const xmlChar *name; |
2abe7362 |
if (xmlTextReaderRead(reader) != 1)
return NULL;
name = xmlTextReaderConstLocalName(reader);
if (name != NULL) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s%s\n", name, |
288057e9 |
xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT ? " end tag" : ""); |
2abe7362 |
} |
288057e9 |
return name; |
2abe7362 |
}
|
7e302913 |
static int openioc_is_context_hash(xmlTextReaderPtr reader)
{ |
288057e9 |
xmlChar *document = xmlTextReaderGetAttribute(reader, (const xmlChar *)"document");
xmlChar *search = xmlTextReaderGetAttribute(reader, (const xmlChar *)"search");
int rc = 0; |
7e302913 |
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;
}
|
288057e9 |
static int openioc_parse_content(xmlTextReaderPtr reader, struct openioc_hash **elems, int context_hash) |
2abe7362 |
{ |
288057e9 |
const xmlChar *xmlval;
struct openioc_hash *elem; |
2abe7362 |
int rc = CL_SUCCESS;
|
7e302913 |
if (context_hash == 0) { |
288057e9 |
xmlChar *type = xmlTextReaderGetAttribute(reader, (const xmlChar *)"type"); |
7e302913 |
if (type == NULL) { |
3cd30f98 |
cli_dbgmsg("openioc_parse: xmlTextReaderGetAttribute no type attribute " |
7e302913 |
"for <Content> element\n"); |
2abe7362 |
return rc; |
288057e9 |
} else { |
7e302913 |
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 |
} |
288057e9 |
|
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; |
288057e9 |
*elems = elem; |
2abe7362 |
} else { |
288057e9 |
cli_dbgmsg("openioc_parse: xmlTextReaderConstValue() returns NULL for Content md5 value.\n"); |
2abe7362 |
} |
288057e9 |
} else { |
3cd30f98 |
cli_dbgmsg("openioc_parse: No text for XML Content element.\n"); |
2abe7362 |
}
return rc;
}
|
288057e9 |
static int openioc_parse_indicatoritem(xmlTextReaderPtr reader, struct openioc_hash **elems) |
2abe7362 |
{ |
288057e9 |
const xmlChar *name;
int rc = CL_SUCCESS; |
7e302913 |
int context_hash = 0; |
2abe7362 |
while (1) {
name = openioc_read(reader);
if (name == NULL)
break; |
288057e9 |
if (xmlStrEqual(name, (const xmlChar *)"Context") && |
7e302913 |
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
context_hash = openioc_is_context_hash(reader); |
288057e9 |
} else if (xmlStrEqual(name, (const xmlChar *)"Content") &&
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;
}
|
288057e9 |
static int openioc_parse_indicator(xmlTextReaderPtr reader, struct openioc_hash **elems) |
2abe7362 |
{ |
288057e9 |
const xmlChar *name; |
2abe7362 |
int rc = CL_SUCCESS;
while (1) {
name = openioc_read(reader);
if (name == NULL)
return rc; |
288057e9 |
if (xmlStrEqual(name, (const xmlChar *)"Indicator") && |
2abe7362 |
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;
} |
288057e9 |
} else if (xmlStrEqual(name, (const xmlChar *)"IndicatorItem") &&
xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) { |
2abe7362 |
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;
}
|
288057e9 |
int openioc_parse(const char *fname, int fd, struct cl_engine *engine, unsigned int options) |
2abe7362 |
{
int rc;
xmlTextReaderPtr reader = NULL; |
288057e9 |
const xmlChar *name;
struct openioc_hash *elems = NULL, *elem = NULL;
const char *iocp = NULL; |
2abe7362 |
uint16_t ioclen; |
288057e9 |
char *virusname; |
3cd30f98 |
int hash_count = 0; |
288057e9 |
|
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); |
288057e9 |
if (xmlStrEqual(name, (const xmlChar *)"Indicator") && |
2abe7362 |
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) { |
544fa973 |
engine->hm_hdb = MPOOL_CALLOC(engine->mempool, 1, sizeof(struct cli_matcher)); |
288057e9 |
if (NULL == engine->hm_hdb) { |
691e9545 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader); |
2abe7362 |
return CL_EMEM; |
691e9545 |
} |
2abe7362 |
#ifdef USE_MPOOL
engine->hm_hdb->mempool = engine->mempool;
#endif
}
}
while (elems != NULL) { |
288057e9 |
const char *sp;
char *hash, *vp; |
2abe7362 |
int i, hashlen;
|
288057e9 |
elem = elems; |
2abe7362 |
elems = elems->next; |
288057e9 |
hash = (char *)(elem->hash); |
2abe7362 |
while (isspace(*hash))
hash++;
hashlen = strlen(hash);
if (hashlen == 0) {
xmlFree(elem->hash);
free(elem);
continue;
} |
288057e9 |
vp = hash + hashlen - 1; |
53506979 |
while (isspace(*vp) && vp > hash) {
*vp-- = '\0'; |
2abe7362 |
hashlen--;
} |
288057e9 |
virusname = calloc(1, ioclen + hashlen + 2); |
762c9ae3 |
if (NULL == virusname) { |
544fa973 |
cli_dbgmsg("openioc_parse: calloc for virname memory failed.\n"); |
691e9545 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader); |
2abe7362 |
return CL_EMEM;
} |
53506979 |
sp = fname; |
ad8ddf98 |
vp = virusname; |
288057e9 |
for (i = 0; i < ioclen; i++, sp++, vp++) { |
2abe7362 |
switch (*sp) { |
288057e9 |
case '\\':
case '/':
case '?':
case '%':
case '*':
case ':':
case '|':
case '"':
case '<':
case '>': |
2abe7362 |
*vp = '_'; |
288057e9 |
break;
default:
if (isspace(*sp))
*vp = '_';
else
*vp = *sp; |
2abe7362 |
}
}
*vp++ = '.'; |
288057e9 |
sp = hash;
for (i = 0; i < hashlen; i++, sp++) { |
2abe7362 |
if (isxdigit(*sp)) {
*vp++ = *sp;
}
} |
ad8ddf98 |
|
288057e9 |
vp = virusname; |
544fa973 |
virusname = CLI_MPOOL_VIRNAME(engine->mempool, virusname, options & CL_DB_OFFICIAL); |
ad8ddf98 |
if (!(virusname)) { |
544fa973 |
cli_dbgmsg("openioc_parse: MPOOL_MALLOC for virname memory failed.\n"); |
ad8ddf98 |
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", |
288057e9 |
hash_count, hash_count == 1 ? "" : "s", fname); |
3cd30f98 |
|
7f92f975 |
xmlTextReaderClose(reader);
xmlFreeTextReader(reader);
|
53506979 |
return CL_SUCCESS; |
2abe7362 |
} |
53506979 |
#else |
288057e9 |
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 |