libclamav/filetypes.c
888f5794
 /*
e1cbc270
  *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
70ef8414
  *  Copyright (C) 2007-2013 Sourcefire, Inc.
7021b545
  *
2023340a
  *  Authors: Tomasz Kojm
888f5794
  *
  *  This program is free software; you can redistribute it and/or modify
bb34cb31
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
888f5794
  *
  *  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
48b7b4a7
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
888f5794
  */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
ad3c01bf
 #include <sys/types.h>
288057e9
 #ifdef HAVE_UNISTD_H
4e9ab8ed
 #include <unistd.h>
 #endif
888f5794
 
 #include "clamav.h"
 #include "filetypes.h"
8000d078
 #include "others.h"
 #include "readdb.h"
c6fb0b98
 #include "matcher-ac.h"
bd988961
 #include "str.h"
c8f2d060
 #include "textdet.h"
589d8d8e
 #include "default.h"
6b7c7dc6
 #include "iowrap.h"
6c2feae2
 #include "mbr.h"
00acb79c
 #include "gpt.h"
b5641e9c
 #include "ooxml.h"
888f5794
 
3506ac49
 #include "htmlnorm.h"
 #include "entconv.h"
e21657df
 #include "mpool.h"
70ef8414
 #define UNZIP_PRIVATE
 #include "unzip.h"
3506ac49
 
27948a03
 // clang-format off
7021b545
 static const struct ftmap_s {
     const char *name;
     cli_file_t code;
 } ftmap[] = {
27948a03
     { "CL_TYPE_TEXT_ASCII",   CL_TYPE_TEXT_ASCII   },
     { "CL_TYPE_TEXT_UTF8",    CL_TYPE_TEXT_UTF8    },
     { "CL_TYPE_TEXT_UTF16LE", CL_TYPE_TEXT_UTF16LE },
     { "CL_TYPE_TEXT_UTF16BE", CL_TYPE_TEXT_UTF16BE },
     { "CL_TYPE_BINARY_DATA",  CL_TYPE_BINARY_DATA  },
     { "CL_TYPE_IGNORED",      CL_TYPE_IGNORED      },
     { "CL_TYPE_ANY",          CL_TYPE_ANY          },
     { "CL_TYPE_MSEXE",        CL_TYPE_MSEXE        },
     { "CL_TYPE_ELF",          CL_TYPE_ELF          },
     { "CL_TYPE_MACHO",        CL_TYPE_MACHO        },
     { "CL_TYPE_MACHO_UNIBIN", CL_TYPE_MACHO_UNIBIN },
     { "CL_TYPE_POSIX_TAR",    CL_TYPE_POSIX_TAR    },
     { "CL_TYPE_OLD_TAR",      CL_TYPE_OLD_TAR      },
     { "CL_TYPE_CPIO_OLD",     CL_TYPE_CPIO_OLD     },
     { "CL_TYPE_CPIO_ODC",     CL_TYPE_CPIO_ODC     },
     { "CL_TYPE_CPIO_NEWC",    CL_TYPE_CPIO_NEWC    },
     { "CL_TYPE_CPIO_CRC",     CL_TYPE_CPIO_CRC     },
     { "CL_TYPE_GZ",           CL_TYPE_GZ           },
     { "CL_TYPE_ZIP",          CL_TYPE_ZIP          },
     { "CL_TYPE_BZ",           CL_TYPE_BZ           },
     { "CL_TYPE_RAR",          CL_TYPE_RAR          },
     { "CL_TYPE_ARJ",          CL_TYPE_ARJ          },
     { "CL_TYPE_MSSZDD",       CL_TYPE_MSSZDD       },
     { "CL_TYPE_MSOLE2",       CL_TYPE_MSOLE2       },
     { "CL_TYPE_MSCAB",        CL_TYPE_MSCAB        },
     { "CL_TYPE_MSCHM",        CL_TYPE_MSCHM        },
     { "CL_TYPE_SIS",          CL_TYPE_SIS          },
     { "CL_TYPE_SCRENC",       CL_TYPE_SCRENC       },
     { "CL_TYPE_GRAPHICS",     CL_TYPE_GRAPHICS     },
     { "CL_TYPE_RIFF",         CL_TYPE_RIFF         },
     { "CL_TYPE_BINHEX",       CL_TYPE_BINHEX       },
     { "CL_TYPE_TNEF",         CL_TYPE_TNEF         },
     { "CL_TYPE_CRYPTFF",      CL_TYPE_CRYPTFF      },
     { "CL_TYPE_PDF",          CL_TYPE_PDF          },
     { "CL_TYPE_UUENCODED",    CL_TYPE_UUENCODED    },
     { "CL_TYPE_HTML_UTF16",   CL_TYPE_HTML_UTF16   },
     { "CL_TYPE_SCRIPT",       CL_TYPE_SCRIPT       },
     { "CL_TYPE_RTF",          CL_TYPE_RTF          },
     { "CL_TYPE_HTML",         CL_TYPE_HTML         },
     { "CL_TYPE_MAIL",         CL_TYPE_MAIL         },
     { "CL_TYPE_SFX",          CL_TYPE_SFX          },
     { "CL_TYPE_ZIPSFX",       CL_TYPE_ZIPSFX       },
     { "CL_TYPE_RARSFX",       CL_TYPE_RARSFX       },
     { "CL_TYPE_CABSFX",       CL_TYPE_CABSFX       },
     { "CL_TYPE_ARJSFX",       CL_TYPE_ARJSFX       },
     { "CL_TYPE_NULSFT",       CL_TYPE_NULSFT       },
     { "CL_TYPE_AUTOIT",       CL_TYPE_AUTOIT       },
     { "CL_TYPE_ISHIELD_MSI",  CL_TYPE_ISHIELD_MSI  },
     { "CL_TYPE_7Z",           CL_TYPE_7Z           },
     { "CL_TYPE_7ZSFX",        CL_TYPE_7ZSFX        },
     { "CL_TYPE_SWF",          CL_TYPE_SWF          },
     { "CL_TYPE_ISO9660",      CL_TYPE_ISO9660      },
     { "CL_TYPE_JAVA",         CL_TYPE_JAVA         },
     { "CL_TYPE_DMG",          CL_TYPE_DMG          },
     { "CL_TYPE_MBR",          CL_TYPE_MBR          },
     { "CL_TYPE_GPT",          CL_TYPE_GPT          },
     { "CL_TYPE_APM",          CL_TYPE_APM          },
     { "CL_TYPE_XAR",          CL_TYPE_XAR          },
     { "CL_TYPE_PART_ANY",     CL_TYPE_PART_ANY     },
     { "CL_TYPE_PART_HFSPLUS", CL_TYPE_PART_HFSPLUS },
     { "CL_TYPE_XZ",           CL_TYPE_XZ           },
     { "CL_TYPE_OOXML_WORD",   CL_TYPE_OOXML_WORD   },
     { "CL_TYPE_OOXML_PPT",    CL_TYPE_OOXML_PPT    },
     { "CL_TYPE_OOXML_XL",     CL_TYPE_OOXML_XL     },
     { "CL_TYPE_INTERNAL",     CL_TYPE_INTERNAL     },
     { "CL_TYPE_XDP",          CL_TYPE_XDP          },
     { "CL_TYPE_XML_WORD",     CL_TYPE_XML_WORD     },
     { "CL_TYPE_XML_XL",       CL_TYPE_XML_XL       },
     { "CL_TYPE_HWP3",         CL_TYPE_HWP3         },
     { "CL_TYPE_XML_HWP",      CL_TYPE_XML_HWP      },
     { "CL_TYPE_HWPOLE2",      CL_TYPE_HWPOLE2      },
     { "CL_TYPE_OOXML_HWP",    CL_TYPE_OOXML_HWP    },
     { "CL_TYPE_PS",           CL_TYPE_PS           },
     { "CL_TYPE_MHTML",        CL_TYPE_MHTML        },
     { "CL_TYPE_LNK",          CL_TYPE_LNK          },
b03b2712
     { "CL_TYPE_EGG",          CL_TYPE_EGG          },
     { "CL_TYPE_EGGSFX",       CL_TYPE_EGGSFX       },
27948a03
     { NULL,                   CL_TYPE_IGNORED      }
888f5794
 };
27948a03
 // clang-format on
888f5794
 
cd94be7a
 cli_file_t cli_partitiontype(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
 
7021b545
 cli_file_t cli_ftcode(const char *name)
 {
288057e9
     unsigned int i;
888f5794
 
288057e9
     for (i = 0; ftmap[i].name; i++)
         if (!strcmp(ftmap[i].name, name))
             return ftmap[i].code;
888f5794
 
7021b545
     return CL_TYPE_ERROR;
 }
888f5794
 
c27d4056
 const char *cli_ftname(cli_file_t code)
 {
288057e9
     unsigned int i;
c27d4056
 
288057e9
     for (i = 0; ftmap[i].name; i++)
         if (ftmap[i].code == code)
             return ftmap[i].name;
c27d4056
 
     return NULL;
 }
 
0d9dbdef
 void cli_ftfree(const struct cl_engine *engine)
7021b545
 {
288057e9
     struct cli_ftype *ftypes = engine->ftypes, *pt;
 
     while (ftypes) {
         pt     = ftypes;
         ftypes = ftypes->next;
544fa973
         MPOOL_FREE(engine->mempool, pt->magic);
         MPOOL_FREE(engine->mempool, pt->tname);
         MPOOL_FREE(engine->mempool, pt);
7021b545
     }
1d1c4b15
 
     ftypes = engine->ptypes;
288057e9
     while (ftypes) {
         pt     = ftypes;
         ftypes = ftypes->next;
544fa973
         MPOOL_FREE(engine->mempool, pt->magic);
         MPOOL_FREE(engine->mempool, pt->tname);
         MPOOL_FREE(engine->mempool, pt);
1d1c4b15
     }
 }
 
 cli_file_t cli_partitiontype(const unsigned char *buf, size_t buflen, const struct cl_engine *engine)
 {
     struct cli_ftype *ptype = engine->ptypes;
 
288057e9
     while (ptype) {
         if (ptype->offset + ptype->length <= buflen) {
             if (!memcmp(buf + ptype->offset, ptype->magic, ptype->length)) {
                 cli_dbgmsg("Recognized %s partition\n", ptype->tname);
                 return ptype->type;
             }
         }
         ptype = ptype->next;
1d1c4b15
     }
 
f290ffd3
     cli_dbgmsg("Partition type is potentially unsupported\n");
1d1c4b15
     return CL_TYPE_PART_ANY;
7021b545
 }
e88f97f3
 
7021b545
 cli_file_t cli_filetype(const unsigned char *buf, size_t buflen, const struct cl_engine *engine)
888f5794
 {
288057e9
     struct cli_ftype *ftype = engine->ftypes;
216a697f
 
288057e9
     while (ftype) {
         if (ftype->offset + ftype->length <= buflen) {
             if (!memcmp(buf + ftype->offset, ftype->magic, ftype->length)) {
                 cli_dbgmsg("Recognized %s file\n", ftype->tname);
                 return ftype->type;
             }
         }
         ftype = ftype->next;
888f5794
     }
 
c8f2d060
     return cli_texttype(buf, buflen);
888f5794
 }
 
f304dc68
 int is_tar(const unsigned char *buf, unsigned int nbytes);
a7f5fd00
 
1d3cb0a3
 /* organize by length, cannot exceed SIZEOF_LOCAL_HEADER */
27948a03
 // clang-format off
8059ffb7
 const struct ooxml_ftcodes {
     const char *entry;
     size_t len;
     cli_file_t type;
 } ooxml_detect[] = {
     { "xl/",                     3, CL_TYPE_OOXML_XL    },
     { "ppt/",                    4, CL_TYPE_OOXML_PPT   },
     { "word/",                   5, CL_TYPE_OOXML_WORD  },
     { "BinData",                 7, CL_TYPE_ZIP         }, /* HWP */
     { "mimetype",                8, CL_TYPE_ZIP         }, /* HWP */
     { "Contents",                8, CL_TYPE_ZIP         }, /* HWP */
     { "docProps/",               9, CL_TYPE_ZIP         }, /* MS */
ce174c71
     { "customXml/",             10, CL_TYPE_ZIP         }, /* MS */
8059ffb7
     { "version.xml",            11, CL_TYPE_ZIP         }, /* HWP */
     { "settings.xml",           12, CL_TYPE_ZIP         }, /* HWP */
     { "_.rels/.rels",           12, CL_TYPE_ZIP         }, /* MS */
     { "[ContentTypes].xml",     18, CL_TYPE_ZIP         }, /* MS */
     { "[Content_Types].xml",    19, CL_TYPE_ZIP         }, /* MS */
     { "Preview/PrvText.txt",    19, CL_TYPE_ZIP         }, /* HWP */
     { "Contents/content.hpf",   20, CL_TYPE_OOXML_HWP   },
     { "META-INF/container.xml", 22, CL_TYPE_ZIP         }, /* HWP */
     { NULL,                      0, CL_TYPE_ANY         }
 };
27948a03
 // clang-format on
 
8250b1a7
 /* set to biggest ooxml_detect len */
 #define OOXML_DETECT_MAXLEN 22
8059ffb7
 
288057e9
 #define OOXML_FTIDENTIFIED(type)                                                \
     do {                                                                        \
         if (type != CL_TYPE_ZIP) {                                              \
             switch (type) {                                                     \
                 case CL_TYPE_OOXML_XL:                                          \
                     cli_dbgmsg("Recognized OOXML XL file\n");                   \
                     return CL_TYPE_OOXML_XL;                                    \
                 case CL_TYPE_OOXML_PPT:                                         \
                     cli_dbgmsg("Recognized OOXML PPT file\n");                  \
                     return CL_TYPE_OOXML_PPT;                                   \
                 case CL_TYPE_OOXML_WORD:                                        \
                     cli_dbgmsg("Recognized OOXML WORD file\n");                 \
                     return CL_TYPE_OOXML_WORD;                                  \
                 case CL_TYPE_OOXML_HWP:                                         \
                     cli_dbgmsg("Recognized OOXML HWP file\n");                  \
                     return CL_TYPE_OOXML_HWP;                                   \
                 default:                                                        \
                     cli_dbgmsg("unexpected ooxml_filetype return: %i\n", type); \
             }                                                                   \
         }                                                                       \
     } while (0)
c6f7be55
 
1d1c4b15
 cli_file_t cli_filetype2(fmap_t *map, const struct cl_engine *engine, cli_file_t basetype)
a7f5fd00
 {
288057e9
     unsigned char buffer[MAGIC_BUFFER_SIZE];
     const unsigned char *buff;
     unsigned char *decoded;
     int bread, sret;
     cli_file_t ret = CL_TYPE_BINARY_DATA;
     struct cli_matcher *root;
     struct cli_ac_data mdata;
 
     if (!engine) {
         cli_errmsg("cli_filetype2: engine == NULL\n");
         return CL_TYPE_ERROR;
c8f2d060
     }
 
288057e9
     if (basetype == CL_TYPE_PART_ANY) {
1d1c4b15
         bread = MIN(map->len, CL_PART_MBUFF_SIZE);
288057e9
     } else {
1d1c4b15
         bread = MIN(map->len, CL_FILE_MBUFF_SIZE);
     }
288057e9
     if (bread > MAGIC_BUFFER_SIZE) {
1d1c4b15
         /* Save anyone who tampered with the header */
         bread = MAGIC_BUFFER_SIZE;
     }
 
048d7677
     buff = fmap_need_off_once(map, 0, bread);
288057e9
     if (buff) {
6b7c7dc6
         sret = cli_memcpy(buffer, buff, bread);
288057e9
         if (sret) {
6b7c7dc6
             cli_errmsg("cli_filetype2: fileread error!\n");
             return CL_TYPE_ERROR;
         }
         sret = 0;
     } else {
         return CL_TYPE_ERROR;
     }
1d1c4b15
 
288057e9
     if (basetype == CL_TYPE_PART_ANY) { /* typing a partition */
1d1c4b15
         ret = cli_partitiontype(buff, bread, engine);
288057e9
     } else { /* typing a file */
1d1c4b15
         ret = cli_filetype(buff, bread, engine);
 
288057e9
         if (ret == CL_TYPE_BINARY_DATA) {
             switch (is_tar(buff, bread)) {
                 case 1:
                     cli_dbgmsg("Recognized old fashioned tar file\n");
                     return CL_TYPE_OLD_TAR;
                 case 2:
                     cli_dbgmsg("Recognized POSIX tar file\n");
                     return CL_TYPE_POSIX_TAR;
             }
1d3cb0a3
         } else if (ret == CL_TYPE_ZIP && bread > 2 * (SIZEOF_LOCAL_HEADER + 5)) {
288057e9
             const char lhdr_magic[4]    = {0x50, 0x4b, 0x03, 0x04};
             const unsigned char *zbuff  = buff;
             uint32_t zread              = bread;
             uint64_t zoff               = bread;
             const unsigned char *znamep = buff;
             int32_t zlen                = bread;
             int lhc                     = 0;
8059ffb7
             int zi, i, likely_ooxml = 0;
c8c80ddf
             cli_file_t ret2;
288057e9
 
             for (zi = 0; zi < 32; zi++) {
cd94be7a
                 znamep = (const unsigned char *)cli_memstr((const char *)znamep, zlen, lhdr_magic, 4);
44006f3e
                 if (NULL != znamep) {
1d3cb0a3
                     znamep += SIZEOF_LOCAL_HEADER;
44006f3e
                     zlen = zread - (znamep - zbuff);
8250b1a7
                     if (zlen > OOXML_DETECT_MAXLEN) {
8059ffb7
                         for (i = 0; ooxml_detect[i].entry; i++) {
8250b1a7
                             if (0 == memcmp(znamep, ooxml_detect[i].entry, ooxml_detect[i].len)) {
                                 if (ooxml_detect[i].type != CL_TYPE_ZIP) {
                                     OOXML_FTIDENTIFIED(ooxml_detect[i].type);
                                     /* returns any unexpected type detection */
                                     return ooxml_detect[i].type;
8059ffb7
                                 }
8250b1a7
 
                                 likely_ooxml = 1;
c6f7be55
                             }
                         }
8250b1a7
                         /* only check first three readable zip headers */
c8c80ddf
                         if (++lhc > 2) {
8250b1a7
                             /* if likely, check full archive */
c8c80ddf
                             if (likely_ooxml) {
                                 cli_dbgmsg("Likely OOXML, checking additional zip headers\n");
                                 if ((ret2 = cli_ooxml_filetype(NULL, map)) != CL_SUCCESS) {
                                     /* either an error or retyping has occurred, return error or just CL_TYPE_ZIP? */
8059ffb7
                                     OOXML_FTIDENTIFIED(ret2);
8250b1a7
                                     /* falls-through to additional filetyping */
c8c80ddf
                                 }
                             }
                             break;
44006f3e
                         }
288057e9
                     } else {
8250b1a7
                         znamep = NULL; /* force to map more */
                     }
44006f3e
                 }
 
                 if (znamep == NULL) {
1d3cb0a3
                     if (map->len - zoff > SIZEOF_LOCAL_HEADER) {
                         zoff -= SIZEOF_LOCAL_HEADER + OOXML_DETECT_MAXLEN + 1; /* remap for SIZEOF_LOCAL_HEADER+filelen for header overlap map boundary */
288057e9
                         zread = MIN(MAGIC_BUFFER_SIZE, map->len - zoff);
44006f3e
                         zbuff = fmap_need_off_once(map, zoff, zread);
                         if (zbuff == NULL) {
                             cli_dbgmsg("cli_filetype2: error mapping data for OOXML check\n");
                             return CL_TYPE_ERROR;
                         }
                         zoff += zread;
                         znamep = zbuff;
288057e9
                         zlen   = zread;
                     } else {
44006f3e
                         break; /* end of data */
70ef8414
                     }
                 }
44006f3e
             }
6c2feae2
         } else if (ret == CL_TYPE_MBR) {
e5d13808
             /* given filetype sig type 0 */
             int iret = cli_mbr_check(buff, bread, map->len);
             if (iret == CL_TYPE_GPT) {
                 cli_dbgmsg("Recognized GUID Partition Table file\n");
                 return CL_TYPE_GPT;
288057e9
             } else if (iret == CL_CLEAN) {
e5d13808
                 return CL_TYPE_MBR;
6c2feae2
             }
 
             /* re-detect type */
             cli_dbgmsg("Recognized binary data\n");
             ret = CL_TYPE_BINARY_DATA;
70ef8414
         }
11dbe195
     }
 
288057e9
     if (ret >= CL_TYPE_TEXT_ASCII && ret <= CL_TYPE_BINARY_DATA) {
         /* HTML files may contain special characters and could be
c8f2d060
 	 * misidentified as BINARY_DATA by cli_filetype()
 	 */
288057e9
         root = engine->root[0];
         if (!root)
             return ret;
bd988961
 
288057e9
         if (cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))
             return ret;
bd988961
 
288057e9
         sret = cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, NULL, AC_SCAN_FT, NULL);
4e9ab8ed
 
288057e9
         cli_ac_freedata(&mdata);
bd988961
 
288057e9
         if (sret >= CL_TYPENO) {
             ret = sret;
         } else {
             if (cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))
                 return ret;
4e9ab8ed
 
288057e9
             decoded = (unsigned char *)cli_utf16toascii((char *)buff, bread);
             if (decoded) {
                 sret = cli_ac_scanbuff(decoded, bread / 2, NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, NULL, AC_SCAN_FT, NULL);
                 free(decoded);
                 if (sret == CL_TYPE_HTML)
                     ret = CL_TYPE_HTML_UTF16;
             }
             cli_ac_freedata(&mdata);
3506ac49
 
288057e9
             if ((((struct cli_dconf *)engine->dconf)->phishing & PHISHING_CONF_ENTCONV) && ret != CL_TYPE_HTML_UTF16) {
                 const char *encoding;
b3fc7f97
 
288057e9
                 /* check if we can autodetect this encoding.
b3fc7f97
 		     * If we can't don't try to detect HTML sig, since
 		     * we just tried that above, and failed */
288057e9
                 if ((encoding = encoding_detect_bom(buff, bread))) {
                     unsigned char decodedbuff[(MAGIC_BUFFER_SIZE + 1) * 2];
                     m_area_t in_area, out_area;
 
                     memset(decodedbuff, 0, sizeof(decodedbuff));
 
                     in_area.buffer  = (unsigned char *)buff;
                     in_area.length  = bread;
                     in_area.offset  = 0;
                     out_area.buffer = decodedbuff;
                     out_area.length = sizeof(decodedbuff);
                     out_area.offset = 0;
 
544fa973
                     /* in htmlnorm we simply skip over \0 chars, allowing HTML parsing in any unicode
b3fc7f97
 			     * (multibyte characters will not be exactly handled, but that is not a problem).
 			     * However when detecting whether a file is HTML or not, we need exact conversion.
 			     * (just eliminating zeros and matching would introduce false positives */
288057e9
                     if (encoding_normalize_toascii(&in_area, encoding, &out_area) >= 0 && out_area.length > 0) {
                         if (cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))
                             return ret;
 
                         if (out_area.length > 0) {
                             sret = cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */
                             if (sret == CL_TYPE_HTML) {
                                 cli_dbgmsg("cli_filetype2: detected HTML signature in Unicode file\n");
                                 /* htmlnorm is able to handle any unicode now, since it skips null chars */
                                 ret = CL_TYPE_HTML;
                             }
                         }
 
                         cli_ac_freedata(&mdata);
                     }
                 }
             }
         }
bd988961
     }
 
a7f5fd00
     return ret;
 }