libclamav/xdp.c
30a75097
 /*
  *  Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
  *
  *  Author: Shawn Webb
  *
  *  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.
  *
  *  In addition, as a special exception, the copyright holders give
  *  permission to link the code of portions of this program with the
  *  OpenSSL library under certain conditions as described in each
  *  individual source file, and distribute linked combinations
  *  including the two.
  *  
  *  You must obey the GNU General Public License in all respects
  *  for all of the code used other than OpenSSL.  If you modify
  *  file(s) with this exception, you may extend this exception to your
  *  version of the file(s), but you are not obligated to do so.  If you
  *  do not wish to do so, delete this exception statement from your
  *  version.  If you delete this exception statement from all source
  *  files in the program, then also delete it here.
  */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
c7f5e09e
 #include <stdio.h>
 #include <stdlib.h>
15ef4b1c
 #if !defined(_WIN32)
c7f5e09e
 #include <unistd.h>
15ef4b1c
 #endif
30a75097
 #include <errno.h>
 #include "xar.h"
 #include "fmap.h"
 #ifdef _WIN32
 #ifndef LIBXML_WRITER_ENABLED
 #define LIBXML_WRITER_ENABLED 1
 #endif
 #endif
57fba2d5
 #if HAVE_LIBXML2
30a75097
 #include <libxml/xmlreader.h>
57fba2d5
 #endif
30a75097
 #include "clamav.h"
 #include "fmap.h"
 #include "str.h"
 #include "scanners.h"
 #include "conv.h"
 #include "xdp.h"
12766605
 #include "bignum_fast.h"
 #include "filetypes.h"
30a75097
 
d77d1aa6
 static char *dump_xdp(cli_ctx *ctx, const char *start, size_t sz);
 
 static char *dump_xdp(cli_ctx *ctx, const char *start, size_t sz)
c7f5e09e
 {
     int fd;
     char *filename;
     size_t nwritten=0;
     ssize_t writeret;
 
     if (cli_gentempfd(ctx->engine->tmpdir, &filename, &fd) != CL_SUCCESS)
         return NULL;
 
     while (nwritten < sz) {
         writeret = write(fd, start+nwritten, sz-nwritten);
         if (writeret < 0) {
             if (errno == EAGAIN)
                 continue;
 
             close(fd);
             cli_unlink(filename);
             free(filename);
 
             return NULL;
         }
 
         nwritten += writeret;
     }
 
15ef4b1c
     cli_dbgmsg("dump_xdp: Dumped payload to %s\n", filename);
c7f5e09e
 
50dc7e62
     close(fd);
 
c7f5e09e
     return filename;
 }
 
30a75097
 int cli_scanxdp(cli_ctx *ctx)
 {
 #if HAVE_LIBXML2
     xmlTextReaderPtr reader = NULL;
     fmap_t *map = *(ctx->fmap);
     const char *buf;
     const xmlChar *name, *value;
     char *decoded;
     size_t decodedlen;
     int rc = CL_SUCCESS;
c7f5e09e
     char *dumpname;
12766605
     size_t i;
30a75097
     
     buf = (const char *)fmap_need_off_once(map, map->offset, map->len);
c7f5e09e
     if (!(buf))
         return CL_EREAD;
 
50dc7e62
     if (ctx->engine->keeptmp) {
         dumpname = dump_xdp(ctx, buf, map->len);
         if (dumpname)
             free(dumpname);
     }
c7f5e09e
 
     /*
      * Since a PDF file can contain embedded XDP documents,
      * it's possible that the filetyping code matched an embedded XDP document.
      * If that's the case, then xmlReaderForMemory will throw an error. For now,
      * silently ignore the error and return CL_SUCCESS so the filetyping code can
      * continue on.
      */
fb05a793
     reader = xmlReaderForMemory(buf, (int)(map->len), "noname.xml", NULL, CLAMAV_MIN_XMLREADER_FLAGS);
30a75097
     if (!(reader))
c7f5e09e
         return CL_SUCCESS;
30a75097
 
     while (xmlTextReaderRead(reader) == 1) {
         name = xmlTextReaderConstLocalName(reader);
         if (!(name))
             continue;
 
         if (!strcmp((const char *)name, "chunk") && xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
             value = xmlTextReaderReadInnerXml(reader);
             if (value) {
                 decoded = cl_base64_decode((char *)value, strlen((const char *)value), NULL, &decodedlen, 0);
                 if (decoded) {
ad91f419
                     unsigned int shouldscan=0;
 
                     if (decodedlen > 5) {
                         for (i=0; i < MIN(MAGIC_BUFFER_SIZE, decodedlen-5); i++) {
                             if (decoded[i] != '%')
                                 continue;
 
                             if (decoded[i+1] == 'P' || decoded[i+1] == 'p') {
                                 if (decoded[i+2] == 'D' || decoded[i+2] == 'd') {
                                     if (decoded[i+3] == 'F' || decoded[i+3] == 'f') {
                                         if (decoded[i+4] == '-') {
                                             shouldscan=1;
                                             break;
                                         }
                                     }
                                 }
                             }
                         }
                     }
 
                     if (!shouldscan) {
d77d1aa6
                         free(decoded);
                         xmlFree((void *)value);
                         break;
                     }
 
30a75097
                     rc = cli_mem_scandesc(decoded, decodedlen, ctx);
                     free(decoded);
ddadcdd1
                     if (rc != CL_SUCCESS || rc == CL_BREAK) {
d77d1aa6
                         xmlFree((void *)value);
30a75097
                         break;
ddadcdd1
                     }
30a75097
                 }
d77d1aa6
 
                 xmlFree((void *)value);
30a75097
             }
         }
     }
 
     xmlFreeTextReader(reader);
 
     return rc;
 #else
     return CL_SUCCESS;
 #endif
 }