~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to libclamav/openioc.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2014 Cisco Systems, Inc.
 
3
 *
 
4
 *  Authors: Steven Morgan <smorgan@sourcefire.com>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License version 2 as
 
8
 *  published by the Free Software Foundation.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
18
 *  MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
#if HAVE_CONFIG_H
 
22
#include "clamav-config.h"
 
23
#endif
 
24
#include <stdio.h>
 
25
#include <stdlib.h>
 
26
#include <dirent.h>
 
27
#include <errno.h>
 
28
#include <string.h>
 
29
#include <openssl/ssl.h>
 
30
#include <openssl/err.h>
 
31
 
 
32
#include "libclamav/crypto.h"
 
33
#include "others.h"
 
34
#include "openioc.h"
 
35
 
 
36
#ifdef HAVE_LIBXML2
 
37
#ifdef _WIN32
 
38
#ifndef LIBXML_WRITER_ENABLED
 
39
#define LIBXML_WRITER_ENABLED 1
 
40
#endif
 
41
#endif
 
42
#include <libxml/xmlreader.h>
 
43
 
 
44
struct openioc_hash {
 
45
    unsigned char * hash;
 
46
    void * next;
 
47
};
 
48
 
 
49
static const xmlChar * openioc_read(xmlTextReaderPtr reader)
 
50
{
 
51
    const xmlChar * name;
 
52
    if (xmlTextReaderRead(reader) != 1)
 
53
        return NULL;
 
54
    name = xmlTextReaderConstLocalName(reader);
 
55
    if (name != NULL) {
 
56
        cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s%s\n", name,
 
57
                   xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT?" end tag":"");
 
58
    }
 
59
    return name;   
 
60
}
 
61
 
 
62
 
 
63
static int openioc_is_context_hash(xmlTextReaderPtr reader)
 
64
{
 
65
    xmlChar * document = xmlTextReaderGetAttribute(reader, (const xmlChar *)"document");
 
66
    xmlChar * search = xmlTextReaderGetAttribute(reader, (const xmlChar *)"search");
 
67
    int rc = 0;
 
68
 
 
69
    if ((document != NULL && search != NULL) &&
 
70
        !xmlStrcmp(document, (const xmlChar *)"FileItem") &&
 
71
        (!xmlStrcmp(search, (const xmlChar *)"FileItem/Md5sum") ||
 
72
         !xmlStrcmp(search, (const xmlChar *)"FileItem/Sha1sum") ||
 
73
         !xmlStrcmp(search, (const xmlChar *)"FileItem/Sha256sum")))
 
74
        rc = 1;
 
75
    if (document != NULL)
 
76
        xmlFree(document);
 
77
    if (search != NULL)
 
78
        xmlFree(search);
 
79
    return rc;
 
80
}
 
81
 
 
82
static int openioc_parse_content(xmlTextReaderPtr reader, struct openioc_hash ** elems, int context_hash)
 
83
{
 
84
    const xmlChar * xmlval;
 
85
    struct openioc_hash * elem;
 
86
    int rc = CL_SUCCESS;
 
87
 
 
88
    if (context_hash == 0) {
 
89
        xmlChar * type = xmlTextReaderGetAttribute(reader, (const xmlChar *)"type");
 
90
        if (type == NULL) {
 
91
            cli_dbgmsg("openioc_parse: xmlTextReaderGetAttribute no type attribute "
 
92
                       "for <Content> element\n");
 
93
            return rc;
 
94
        } else { 
 
95
            if (xmlStrcasecmp(type, (const xmlChar *)"sha1") &&
 
96
                xmlStrcasecmp(type, (const xmlChar *)"sha256") &&
 
97
                xmlStrcasecmp(type, (const xmlChar *)"md5")) {
 
98
                xmlFree(type);
 
99
                return rc;
 
100
            }
 
101
        }
 
102
        xmlFree(type);
 
103
    }
 
104
    
 
105
    if (xmlTextReaderRead(reader) == 1 && xmlTextReaderNodeType(reader) == XML_READER_TYPE_TEXT) {
 
106
        xmlval = xmlTextReaderConstValue(reader);
 
107
        if (xmlval) {
 
108
            elem = cli_calloc(1, sizeof(struct openioc_hash));
 
109
            if (NULL == elem) {
 
110
                cli_dbgmsg("openioc_parse: calloc fails for openioc_hash.\n");
 
111
                return CL_EMEM;
 
112
            }
 
113
            elem->hash = xmlStrdup(xmlval);
 
114
            elem->next = *elems;
 
115
            *elems = elem; 
 
116
        } else {
 
117
            cli_dbgmsg("openioc_parse: xmlTextReaderConstValue() returns NULL for Content md5 value.\n");           
 
118
        }
 
119
    }
 
120
    else {
 
121
        cli_dbgmsg("openioc_parse: No text for XML Content element.\n");
 
122
    }
 
123
    return rc;
 
124
}
 
125
 
 
126
static int openioc_parse_indicatoritem(xmlTextReaderPtr reader, struct openioc_hash ** elems)
 
127
{
 
128
    const xmlChar * name;
 
129
    int rc = CL_SUCCESS;
 
130
    int context_hash = 0;
 
131
 
 
132
    while (1) {
 
133
        name = openioc_read(reader);
 
134
        if (name == NULL)
 
135
            break;
 
136
        if (xmlStrEqual(name, (const xmlChar *)"Context") && 
 
137
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
 
138
            context_hash = openioc_is_context_hash(reader);
 
139
        } else if (xmlStrEqual(name, (const xmlChar *)"Content") && 
 
140
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
 
141
            rc = openioc_parse_content(reader, elems, context_hash);
 
142
            if (rc != CL_SUCCESS) {
 
143
                break;
 
144
            }
 
145
        } else if (xmlStrEqual(name, (const xmlChar *)"IndicatorItem") &&
 
146
                   xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
 
147
            break;
 
148
        }
 
149
    }
 
150
    return rc;
 
151
}
 
152
 
 
153
static int openioc_parse_indicator(xmlTextReaderPtr reader, struct openioc_hash ** elems)
 
154
{
 
155
    const xmlChar * name;
 
156
    int rc = CL_SUCCESS;
 
157
 
 
158
    while (1) {
 
159
        name = openioc_read(reader);
 
160
        if (name == NULL)
 
161
            return rc;
 
162
        if (xmlStrEqual(name, (const xmlChar *)"Indicator") && 
 
163
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
 
164
            rc = openioc_parse_indicator(reader, elems);
 
165
            if (rc != CL_SUCCESS) {
 
166
                cli_dbgmsg("openioc_parse: openioc_parse_indicator recursion error.\n");
 
167
                break;
 
168
            }
 
169
        } else if (xmlStrEqual(name, (const xmlChar *)"IndicatorItem") && 
 
170
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
 
171
            rc = openioc_parse_indicatoritem(reader, elems);
 
172
            if (rc != CL_SUCCESS) {
 
173
                break;
 
174
            }
 
175
        } else if (xmlStrEqual(name, (const xmlChar *)"Indicator") &&
 
176
                   xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
 
177
            break;
 
178
        }
 
179
    }
 
180
    return rc;
 
181
}
 
182
 
 
183
int openioc_parse(const char * fname, int fd, struct cl_engine *engine, unsigned int options)
 
184
{
 
185
    int rc;
 
186
    xmlTextReaderPtr reader = NULL;
 
187
    const xmlChar * name;
 
188
    struct openioc_hash * elems = NULL, * elem = NULL;
 
189
    const char * iocp = NULL;
 
190
    uint16_t ioclen;
 
191
    char * virusname;
 
192
    int hash_count = 0;
 
193
    
 
194
    if (fname == NULL)
 
195
        return CL_ENULLARG;
 
196
 
 
197
    if (fd < 0)
 
198
        return CL_EARG;
 
199
 
 
200
    cli_dbgmsg("openioc_parse: XML parsing file %s\n", fname);
 
201
 
 
202
    reader = xmlReaderForFd(fd, NULL, NULL, 0);
 
203
    if (reader == NULL) {
 
204
        cli_dbgmsg("openioc_parse: xmlReaderForFd error\n");
 
205
        return CL_EOPEN;
 
206
    }
 
207
    rc = xmlTextReaderRead(reader);
 
208
    while (rc == 1) {
 
209
        name = xmlTextReaderConstLocalName(reader);
 
210
        cli_dbgmsg("openioc_parse: xmlTextReaderRead read %s\n", name);
 
211
        if (xmlStrEqual(name, (const xmlChar *)"Indicator") && 
 
212
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
 
213
            rc = openioc_parse_indicator(reader, &elems);
 
214
            if (rc != CL_SUCCESS) {
 
215
                xmlTextReaderClose(reader);
 
216
                xmlFreeTextReader(reader);
 
217
                return rc;
 
218
            }
 
219
        }
 
220
        if (xmlStrEqual(name, (const xmlChar *)"ioc") &&
 
221
            xmlTextReaderNodeType(reader) == XML_READER_TYPE_END_ELEMENT) {
 
222
            break;
 
223
        }
 
224
        rc = xmlTextReaderRead(reader);
 
225
    }
 
226
 
 
227
    iocp = strrchr(fname, *PATHSEP);
 
228
 
 
229
    if (NULL == iocp)
 
230
        iocp = fname;
 
231
    else
 
232
        iocp++;
 
233
 
 
234
    ioclen = strlen(fname);
 
235
 
 
236
    if (elems != NULL) {
 
237
        if (NULL == engine->hm_hdb) {
 
238
            engine->hm_hdb = mpool_calloc(engine->mempool, 1, sizeof(struct cli_matcher));
 
239
            if (NULL == engine->hm_hdb) {            
 
240
                xmlTextReaderClose(reader);
 
241
                xmlFreeTextReader(reader);
 
242
                return CL_EMEM;
 
243
            }
 
244
#ifdef USE_MPOOL
 
245
            engine->hm_hdb->mempool = engine->mempool;
 
246
#endif
 
247
        }
 
248
    }
 
249
 
 
250
    while (elems != NULL) {
 
251
        const char * sp;
 
252
        char * hash, * vp;
 
253
        int i, hashlen;
 
254
 
 
255
        elem = elems;
 
256
        elems = elems->next;
 
257
        hash = elem->hash;
 
258
        while (isspace(*hash))
 
259
            hash++;
 
260
        hashlen = strlen(hash);
 
261
        if (hashlen == 0) {
 
262
            xmlFree(elem->hash);
 
263
            free(elem);
 
264
            continue;
 
265
        }
 
266
        vp = hash+hashlen-1;
 
267
        while (isspace(*vp) && vp > hash) {
 
268
            *vp-- = '\0';
 
269
            hashlen--;
 
270
        }
 
271
        virusname = calloc(1, ioclen+hashlen+2);
 
272
        if (NULL == virusname) {
 
273
            cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n");
 
274
            xmlTextReaderClose(reader);
 
275
            xmlFreeTextReader(reader);
 
276
            return CL_EMEM;
 
277
        }
 
278
        sp = fname;
 
279
        vp = virusname;
 
280
        for (i=0; i<ioclen; i++, sp++, vp++) {
 
281
            switch (*sp) {
 
282
            case '\\':
 
283
            case '/':
 
284
            case '?':
 
285
            case '%':
 
286
            case '*':
 
287
            case ':':
 
288
            case '|':
 
289
            case '"':
 
290
            case '<':
 
291
            case '>':
 
292
                *vp = '_';
 
293
                break;
 
294
            default:
 
295
                if (isspace(*sp))
 
296
                    *vp = '_';
 
297
                else
 
298
                    *vp = *sp;
 
299
            }
 
300
        }
 
301
        *vp++ = '.';
 
302
        sp = hash;
 
303
        for (i=0; i<hashlen; i++, sp++) {
 
304
            if (isxdigit(*sp)) {
 
305
                *vp++ = *sp;
 
306
            }
 
307
        }
 
308
 
 
309
        vp = virusname;
 
310
        virusname = cli_mpool_virname(engine->mempool, virusname, options & CL_DB_OFFICIAL);
 
311
        if (!(virusname)) {
 
312
            cli_dbgmsg("openioc_parse: mpool_malloc for virname memory failed.\n");
 
313
            xmlTextReaderClose(reader);
 
314
            xmlFreeTextReader(reader);
 
315
            free(vp);
 
316
            return CL_EMEM;
 
317
        }
 
318
 
 
319
        free(vp);
 
320
 
 
321
        rc = hm_addhash_str(engine->hm_hdb, hash, 0, virusname);
 
322
        if (rc != CL_SUCCESS)
 
323
            cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n",
 
324
                       rc, hashlen, virusname);
 
325
        else
 
326
            hash_count++;
 
327
 
 
328
        xmlFree(elem->hash);
 
329
        free(elem);
 
330
    }
 
331
 
 
332
    if (hash_count == 0)
 
333
        cli_warnmsg("openioc_parse: No hash signatures extracted from %s.\n", fname);
 
334
    else
 
335
        cli_dbgmsg("openioc_parse: %i hash signature%s extracted from %s.\n",
 
336
                   hash_count, hash_count==1?"":"s", fname);
 
337
 
 
338
    xmlTextReaderClose(reader);
 
339
    xmlFreeTextReader(reader);
 
340
 
 
341
    return CL_SUCCESS;
 
342
}
 
343
#else
 
344
int openioc_parse(const char * fname, int fd, struct cl_engine *engine, unsigned int options)
 
345
{
 
346
    cli_dbgmsg("openioc_parse: libxml2 support is compiled out and is needed for OpenIOC support.\n");
 
347
    return CL_SUCCESS;
 
348
}
 
349
#endif