179343712SPeter Avalos /*-
2c30bd091SSascha Wildner * Copyright (c) 2008, 2016 Christos Zoulas
379343712SPeter Avalos * All rights reserved.
479343712SPeter Avalos *
579343712SPeter Avalos * Redistribution and use in source and binary forms, with or without
679343712SPeter Avalos * modification, are permitted provided that the following conditions
779343712SPeter Avalos * are met:
879343712SPeter Avalos * 1. Redistributions of source code must retain the above copyright
979343712SPeter Avalos * notice, this list of conditions and the following disclaimer.
1079343712SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
1179343712SPeter Avalos * notice, this list of conditions and the following disclaimer in the
1279343712SPeter Avalos * documentation and/or other materials provided with the distribution.
1379343712SPeter Avalos *
1479343712SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1579343712SPeter Avalos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1679343712SPeter Avalos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1779343712SPeter Avalos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1879343712SPeter Avalos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1979343712SPeter Avalos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2079343712SPeter Avalos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2179343712SPeter Avalos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2279343712SPeter Avalos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2379343712SPeter Avalos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2479343712SPeter Avalos * POSSIBILITY OF SUCH DAMAGE.
2579343712SPeter Avalos */
2679343712SPeter Avalos #include "file.h"
2779343712SPeter Avalos
2879343712SPeter Avalos #ifndef lint
29*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: readcdf.c,v 1.76 2022/01/17 16:59:01 christos Exp $")
3079343712SPeter Avalos #endif
3179343712SPeter Avalos
32e8af9738SPeter Avalos #include <assert.h>
3379343712SPeter Avalos #include <stdlib.h>
3479343712SPeter Avalos #include <unistd.h>
3579343712SPeter Avalos #include <string.h>
3679343712SPeter Avalos #include <time.h>
3779343712SPeter Avalos #include <ctype.h>
3879343712SPeter Avalos
3979343712SPeter Avalos #include "cdf.h"
4079343712SPeter Avalos #include "magic.h"
4179343712SPeter Avalos
4279343712SPeter Avalos #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
4379343712SPeter Avalos
44e8af9738SPeter Avalos static const struct nv {
45e8af9738SPeter Avalos const char *pattern;
46e8af9738SPeter Avalos const char *mime;
47e8af9738SPeter Avalos } app2mime[] = {
48e8af9738SPeter Avalos { "Word", "msword", },
49e8af9738SPeter Avalos { "Excel", "vnd.ms-excel", },
50e8af9738SPeter Avalos { "Powerpoint", "vnd.ms-powerpoint", },
51e8af9738SPeter Avalos { "Crystal Reports", "x-rpt", },
52e8af9738SPeter Avalos { "Advanced Installer", "vnd.ms-msi", },
53e8af9738SPeter Avalos { "InstallShield", "vnd.ms-msi", },
54e8af9738SPeter Avalos { "Microsoft Patch Compiler", "vnd.ms-msi", },
55e8af9738SPeter Avalos { "NAnt", "vnd.ms-msi", },
56e8af9738SPeter Avalos { "Windows Installer", "vnd.ms-msi", },
57e8af9738SPeter Avalos { NULL, NULL, },
58e8af9738SPeter Avalos }, name2mime[] = {
59c30bd091SSascha Wildner { "Book", "vnd.ms-excel", },
60c30bd091SSascha Wildner { "Workbook", "vnd.ms-excel", },
61e8af9738SPeter Avalos { "WordDocument", "msword", },
62e8af9738SPeter Avalos { "PowerPoint", "vnd.ms-powerpoint", },
63e8af9738SPeter Avalos { "DigitalSignature", "vnd.ms-msi", },
64e8af9738SPeter Avalos { NULL, NULL, },
65e8af9738SPeter Avalos }, name2desc[] = {
66c30bd091SSascha Wildner { "Book", "Microsoft Excel", },
67c30bd091SSascha Wildner { "Workbook", "Microsoft Excel", },
68c30bd091SSascha Wildner { "WordDocument", "Microsoft Word", },
69e8af9738SPeter Avalos { "PowerPoint", "Microsoft PowerPoint", },
70e8af9738SPeter Avalos { "DigitalSignature", "Microsoft Installer", },
71e8af9738SPeter Avalos { NULL, NULL, },
72e8af9738SPeter Avalos };
73e8af9738SPeter Avalos
74e8af9738SPeter Avalos static const struct cv {
75e8af9738SPeter Avalos uint64_t clsid[2];
76e8af9738SPeter Avalos const char *mime;
77e8af9738SPeter Avalos } clsid2mime[] = {
78e8af9738SPeter Avalos {
7982c5fa3eSPeter Avalos { 0x00000000000c1084ULL, 0x46000000000000c0ULL },
80e8af9738SPeter Avalos "x-msi",
8182c5fa3eSPeter Avalos },
8282c5fa3eSPeter Avalos { { 0, 0 },
8382c5fa3eSPeter Avalos NULL,
8482c5fa3eSPeter Avalos },
85e8af9738SPeter Avalos }, clsid2desc[] = {
86e8af9738SPeter Avalos {
8782c5fa3eSPeter Avalos { 0x00000000000c1084ULL, 0x46000000000000c0ULL },
88e8af9738SPeter Avalos "MSI Installer",
89e8af9738SPeter Avalos },
9082c5fa3eSPeter Avalos { { 0, 0 },
9182c5fa3eSPeter Avalos NULL,
9282c5fa3eSPeter Avalos },
93e8af9738SPeter Avalos };
94e8af9738SPeter Avalos
95e8af9738SPeter Avalos private const char *
cdf_clsid_to_mime(const uint64_t clsid[2],const struct cv * cv)96e8af9738SPeter Avalos cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
97e8af9738SPeter Avalos {
98e8af9738SPeter Avalos size_t i;
99e8af9738SPeter Avalos for (i = 0; cv[i].mime != NULL; i++) {
100e8af9738SPeter Avalos if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
101e8af9738SPeter Avalos return cv[i].mime;
102e8af9738SPeter Avalos }
103c30bd091SSascha Wildner #ifdef CDF_DEBUG
104c30bd091SSascha Wildner fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
105c30bd091SSascha Wildner clsid[1]);
106c30bd091SSascha Wildner #endif
107e8af9738SPeter Avalos return NULL;
108e8af9738SPeter Avalos }
109e8af9738SPeter Avalos
110e8af9738SPeter Avalos private const char *
cdf_app_to_mime(const char * vbuf,const struct nv * nv)111e8af9738SPeter Avalos cdf_app_to_mime(const char *vbuf, const struct nv *nv)
112e8af9738SPeter Avalos {
113e8af9738SPeter Avalos size_t i;
114e8af9738SPeter Avalos const char *rv = NULL;
11582c5fa3eSPeter Avalos #ifdef USE_C_LOCALE
11682c5fa3eSPeter Avalos locale_t old_lc_ctype, c_lc_ctype;
117e8af9738SPeter Avalos
11882c5fa3eSPeter Avalos c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
11982c5fa3eSPeter Avalos assert(c_lc_ctype != NULL);
12082c5fa3eSPeter Avalos old_lc_ctype = uselocale(c_lc_ctype);
121e8af9738SPeter Avalos assert(old_lc_ctype != NULL);
122c30bd091SSascha Wildner #else
1236fca56fbSSascha Wildner char *old_lc_ctype = setlocale(LC_CTYPE, NULL);
1246fca56fbSSascha Wildner assert(old_lc_ctype != NULL);
1256fca56fbSSascha Wildner old_lc_ctype = strdup(old_lc_ctype);
1266fca56fbSSascha Wildner assert(old_lc_ctype != NULL);
1276fca56fbSSascha Wildner (void)setlocale(LC_CTYPE, "C");
12882c5fa3eSPeter Avalos #endif
129e8af9738SPeter Avalos for (i = 0; nv[i].pattern != NULL; i++)
130e8af9738SPeter Avalos if (strcasestr(vbuf, nv[i].pattern) != NULL) {
131e8af9738SPeter Avalos rv = nv[i].mime;
132e8af9738SPeter Avalos break;
133e8af9738SPeter Avalos }
134c30bd091SSascha Wildner #ifdef CDF_DEBUG
135c30bd091SSascha Wildner fprintf(stderr, "unknown app %s\n", vbuf);
136c30bd091SSascha Wildner #endif
13782c5fa3eSPeter Avalos #ifdef USE_C_LOCALE
13882c5fa3eSPeter Avalos (void)uselocale(old_lc_ctype);
13982c5fa3eSPeter Avalos freelocale(c_lc_ctype);
140c30bd091SSascha Wildner #else
1416fca56fbSSascha Wildner (void)setlocale(LC_CTYPE, old_lc_ctype);
1426fca56fbSSascha Wildner free(old_lc_ctype);
14382c5fa3eSPeter Avalos #endif
144e8af9738SPeter Avalos return rv;
145e8af9738SPeter Avalos }
146e8af9738SPeter Avalos
14779343712SPeter Avalos private int
cdf_file_property_info(struct magic_set * ms,const cdf_property_info_t * info,size_t count,const cdf_directory_t * root_storage)14879343712SPeter Avalos cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
14982c5fa3eSPeter Avalos size_t count, const cdf_directory_t *root_storage)
15079343712SPeter Avalos {
15179343712SPeter Avalos size_t i;
15279343712SPeter Avalos cdf_timestamp_t tp;
15379343712SPeter Avalos struct timespec ts;
15479343712SPeter Avalos char buf[64];
155a96e001bSPeter Avalos const char *str = NULL;
156c30bd091SSascha Wildner const char *s, *e;
15779343712SPeter Avalos int len;
15879343712SPeter Avalos
15982c5fa3eSPeter Avalos if (!NOTMIME(ms) && root_storage)
16082c5fa3eSPeter Avalos str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
16182c5fa3eSPeter Avalos clsid2mime);
162e8af9738SPeter Avalos
16379343712SPeter Avalos for (i = 0; i < count; i++) {
16479343712SPeter Avalos cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
16579343712SPeter Avalos switch (info[i].pi_type) {
166f72f8299SJan Lentfer case CDF_NULL:
167f72f8299SJan Lentfer break;
16879343712SPeter Avalos case CDF_SIGNED16:
16979343712SPeter Avalos if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
17079343712SPeter Avalos info[i].pi_s16) == -1)
17179343712SPeter Avalos return -1;
17279343712SPeter Avalos break;
17379343712SPeter Avalos case CDF_SIGNED32:
17479343712SPeter Avalos if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
17579343712SPeter Avalos info[i].pi_s32) == -1)
17679343712SPeter Avalos return -1;
17779343712SPeter Avalos break;
17879343712SPeter Avalos case CDF_UNSIGNED32:
17979343712SPeter Avalos if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
18079343712SPeter Avalos info[i].pi_u32) == -1)
18179343712SPeter Avalos return -1;
18279343712SPeter Avalos break;
18317b11469SPeter Avalos case CDF_FLOAT:
18417b11469SPeter Avalos if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
18517b11469SPeter Avalos info[i].pi_f) == -1)
18617b11469SPeter Avalos return -1;
18717b11469SPeter Avalos break;
18817b11469SPeter Avalos case CDF_DOUBLE:
18917b11469SPeter Avalos if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
19017b11469SPeter Avalos info[i].pi_d) == -1)
19117b11469SPeter Avalos return -1;
19217b11469SPeter Avalos break;
19379343712SPeter Avalos case CDF_LENGTH32_STRING:
194f72f8299SJan Lentfer case CDF_LENGTH32_WSTRING:
19579343712SPeter Avalos len = info[i].pi_str.s_len;
19679343712SPeter Avalos if (len > 1) {
19779343712SPeter Avalos char vbuf[1024];
198f72f8299SJan Lentfer size_t j, k = 1;
199f72f8299SJan Lentfer
200f72f8299SJan Lentfer if (info[i].pi_type == CDF_LENGTH32_WSTRING)
201f72f8299SJan Lentfer k++;
202f72f8299SJan Lentfer s = info[i].pi_str.s_buf;
203c30bd091SSascha Wildner e = info[i].pi_str.s_buf + len;
204c30bd091SSascha Wildner for (j = 0; s < e && j < sizeof(vbuf)
205c30bd091SSascha Wildner && len--; s += k) {
20679343712SPeter Avalos if (*s == '\0')
20779343712SPeter Avalos break;
2086fca56fbSSascha Wildner if (isprint(CAST(unsigned char, *s)))
20982c5fa3eSPeter Avalos vbuf[j++] = *s;
21079343712SPeter Avalos }
21179343712SPeter Avalos if (j == sizeof(vbuf))
21279343712SPeter Avalos --j;
21379343712SPeter Avalos vbuf[j] = '\0';
214f72f8299SJan Lentfer if (NOTMIME(ms)) {
21579343712SPeter Avalos if (vbuf[0]) {
21679343712SPeter Avalos if (file_printf(ms, ", %s: %s",
21779343712SPeter Avalos buf, vbuf) == -1)
21879343712SPeter Avalos return -1;
21979343712SPeter Avalos }
220e8af9738SPeter Avalos } else if (str == NULL && info[i].pi_id ==
22179343712SPeter Avalos CDF_PROPERTY_NAME_OF_APPLICATION) {
222e8af9738SPeter Avalos str = cdf_app_to_mime(vbuf, app2mime);
22379343712SPeter Avalos }
22479343712SPeter Avalos }
22579343712SPeter Avalos break;
22679343712SPeter Avalos case CDF_FILETIME:
22779343712SPeter Avalos tp = info[i].pi_tp;
22879343712SPeter Avalos if (tp != 0) {
22979343712SPeter Avalos char tbuf[64];
230e8af9738SPeter Avalos if (tp < 1000000000000000LL) {
23179343712SPeter Avalos cdf_print_elapsed_time(tbuf,
23279343712SPeter Avalos sizeof(tbuf), tp);
23379343712SPeter Avalos if (NOTMIME(ms) && file_printf(ms,
23479343712SPeter Avalos ", %s: %s", buf, tbuf) == -1)
23579343712SPeter Avalos return -1;
23679343712SPeter Avalos } else {
23779343712SPeter Avalos char *c, *ec;
23879343712SPeter Avalos cdf_timestamp_to_timespec(&ts, tp);
239e8af9738SPeter Avalos c = cdf_ctime(&ts.tv_sec, tbuf);
240e8af9738SPeter Avalos if (c != NULL &&
241e8af9738SPeter Avalos (ec = strchr(c, '\n')) != NULL)
24279343712SPeter Avalos *ec = '\0';
24379343712SPeter Avalos
24479343712SPeter Avalos if (NOTMIME(ms) && file_printf(ms,
24579343712SPeter Avalos ", %s: %s", buf, c) == -1)
24679343712SPeter Avalos return -1;
24779343712SPeter Avalos }
24879343712SPeter Avalos }
24979343712SPeter Avalos break;
25079343712SPeter Avalos case CDF_CLIPBOARD:
25179343712SPeter Avalos break;
25279343712SPeter Avalos default:
25379343712SPeter Avalos return -1;
25479343712SPeter Avalos }
25579343712SPeter Avalos }
2566fca56fbSSascha Wildner if (ms->flags & MAGIC_MIME_TYPE) {
257a96e001bSPeter Avalos if (str == NULL)
258a96e001bSPeter Avalos return 0;
2599f86ab30SPeter Avalos if (file_printf(ms, "application/%s", str) == -1)
2609f86ab30SPeter Avalos return -1;
26179343712SPeter Avalos }
26279343712SPeter Avalos return 1;
26379343712SPeter Avalos }
26479343712SPeter Avalos
26579343712SPeter Avalos private int
cdf_file_catalog(struct magic_set * ms,const cdf_header_t * h,const cdf_stream_t * sst)26682c5fa3eSPeter Avalos cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
26782c5fa3eSPeter Avalos const cdf_stream_t *sst)
26882c5fa3eSPeter Avalos {
26982c5fa3eSPeter Avalos cdf_catalog_t *cat;
27082c5fa3eSPeter Avalos size_t i;
27182c5fa3eSPeter Avalos char buf[256];
27282c5fa3eSPeter Avalos cdf_catalog_entry_t *ce;
27382c5fa3eSPeter Avalos
27482c5fa3eSPeter Avalos if (NOTMIME(ms)) {
27582c5fa3eSPeter Avalos if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
27682c5fa3eSPeter Avalos return -1;
27782c5fa3eSPeter Avalos if (cdf_unpack_catalog(h, sst, &cat) == -1)
27882c5fa3eSPeter Avalos return -1;
27982c5fa3eSPeter Avalos ce = cat->cat_e;
28082c5fa3eSPeter Avalos /* skip first entry since it has a , or paren */
28182c5fa3eSPeter Avalos for (i = 1; i < cat->cat_num; i++)
28282c5fa3eSPeter Avalos if (file_printf(ms, "%s%s",
28382c5fa3eSPeter Avalos cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
28482c5fa3eSPeter Avalos i == cat->cat_num - 1 ? "]" : ", ") == -1) {
28582c5fa3eSPeter Avalos free(cat);
28682c5fa3eSPeter Avalos return -1;
28782c5fa3eSPeter Avalos }
28882c5fa3eSPeter Avalos free(cat);
2896fca56fbSSascha Wildner } else if (ms->flags & MAGIC_MIME_TYPE) {
29082c5fa3eSPeter Avalos if (file_printf(ms, "application/CDFV2") == -1)
29182c5fa3eSPeter Avalos return -1;
29282c5fa3eSPeter Avalos }
29382c5fa3eSPeter Avalos return 1;
29482c5fa3eSPeter Avalos }
29582c5fa3eSPeter Avalos
29682c5fa3eSPeter Avalos private int
cdf_file_summary_info(struct magic_set * ms,const cdf_header_t * h,const cdf_stream_t * sst,const cdf_directory_t * root_storage)297ff91a668SPeter Avalos cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
29882c5fa3eSPeter Avalos const cdf_stream_t *sst, const cdf_directory_t *root_storage)
29979343712SPeter Avalos {
30079343712SPeter Avalos cdf_summary_info_header_t si;
30179343712SPeter Avalos cdf_property_info_t *info;
30279343712SPeter Avalos size_t count;
30379343712SPeter Avalos int m;
30479343712SPeter Avalos
305ff91a668SPeter Avalos if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
30679343712SPeter Avalos return -1;
30779343712SPeter Avalos
30879343712SPeter Avalos if (NOTMIME(ms)) {
309e8af9738SPeter Avalos const char *str;
310e8af9738SPeter Avalos
31117b11469SPeter Avalos if (file_printf(ms, "Composite Document File V2 Document")
31217b11469SPeter Avalos == -1)
31379343712SPeter Avalos return -1;
31479343712SPeter Avalos
31579343712SPeter Avalos if (file_printf(ms, ", %s Endian",
31679343712SPeter Avalos si.si_byte_order == 0xfffe ? "Little" : "Big") == -1)
31717b11469SPeter Avalos return -2;
31879343712SPeter Avalos switch (si.si_os) {
31979343712SPeter Avalos case 2:
32079343712SPeter Avalos if (file_printf(ms, ", Os: Windows, Version %d.%d",
321f72f8299SJan Lentfer si.si_os_version & 0xff,
3226fca56fbSSascha Wildner CAST(uint32_t, si.si_os_version) >> 8) == -1)
32317b11469SPeter Avalos return -2;
32479343712SPeter Avalos break;
32579343712SPeter Avalos case 1:
32679343712SPeter Avalos if (file_printf(ms, ", Os: MacOS, Version %d.%d",
3276fca56fbSSascha Wildner CAST(uint32_t, si.si_os_version) >> 8,
328f72f8299SJan Lentfer si.si_os_version & 0xff) == -1)
32917b11469SPeter Avalos return -2;
33079343712SPeter Avalos break;
33179343712SPeter Avalos default:
33279343712SPeter Avalos if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
333f72f8299SJan Lentfer si.si_os_version & 0xff,
3346fca56fbSSascha Wildner CAST(uint32_t, si.si_os_version) >> 8) == -1)
33517b11469SPeter Avalos return -2;
33679343712SPeter Avalos break;
33779343712SPeter Avalos }
33882c5fa3eSPeter Avalos if (root_storage) {
33982c5fa3eSPeter Avalos str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
34082c5fa3eSPeter Avalos clsid2desc);
34182c5fa3eSPeter Avalos if (str) {
342e8af9738SPeter Avalos if (file_printf(ms, ", %s", str) == -1)
343e8af9738SPeter Avalos return -2;
34479343712SPeter Avalos }
34582c5fa3eSPeter Avalos }
34682c5fa3eSPeter Avalos }
34779343712SPeter Avalos
34882c5fa3eSPeter Avalos m = cdf_file_property_info(ms, info, count, root_storage);
34979343712SPeter Avalos free(info);
35079343712SPeter Avalos
35117b11469SPeter Avalos return m == -1 ? -2 : m;
35279343712SPeter Avalos }
35379343712SPeter Avalos
354e8af9738SPeter Avalos #ifdef notdef
355e8af9738SPeter Avalos private char *
format_clsid(char * buf,size_t len,const uint64_t uuid[2])356e8af9738SPeter Avalos format_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
357e8af9738SPeter Avalos snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
358e8af9738SPeter Avalos PRIx64 "-%.12" PRIx64,
35982c5fa3eSPeter Avalos (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
36082c5fa3eSPeter Avalos (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
36182c5fa3eSPeter Avalos (uuid[0] >> 0) & (uint64_t)0x0000000000000ffffULL,
36282c5fa3eSPeter Avalos (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
36382c5fa3eSPeter Avalos (uuid[1] >> 0) & (uint64_t)0x0000fffffffffffffULL);
364e8af9738SPeter Avalos return buf;
365e8af9738SPeter Avalos }
366e8af9738SPeter Avalos #endif
367e8af9738SPeter Avalos
368c30bd091SSascha Wildner private int
cdf_file_catalog_info(struct magic_set * ms,const cdf_info_t * info,const cdf_header_t * h,const cdf_sat_t * sat,const cdf_sat_t * ssat,const cdf_stream_t * sst,const cdf_dir_t * dir,cdf_stream_t * scn)369c30bd091SSascha Wildner cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
370c30bd091SSascha Wildner const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
371c30bd091SSascha Wildner const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
372c30bd091SSascha Wildner {
373c30bd091SSascha Wildner int i;
374c30bd091SSascha Wildner
375c30bd091SSascha Wildner if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
376c30bd091SSascha Wildner dir, "Catalog", scn)) == -1)
377c30bd091SSascha Wildner return i;
378c30bd091SSascha Wildner #ifdef CDF_DEBUG
379c30bd091SSascha Wildner cdf_dump_catalog(h, scn);
380c30bd091SSascha Wildner #endif
381c30bd091SSascha Wildner if ((i = cdf_file_catalog(ms, h, scn)) == -1)
382c30bd091SSascha Wildner return -1;
383c30bd091SSascha Wildner return i;
384c30bd091SSascha Wildner }
385c30bd091SSascha Wildner
386c30bd091SSascha Wildner private int
cdf_check_summary_info(struct magic_set * ms,const cdf_info_t * info,const cdf_header_t * h,const cdf_sat_t * sat,const cdf_sat_t * ssat,const cdf_stream_t * sst,const cdf_dir_t * dir,cdf_stream_t * scn,const cdf_directory_t * root_storage,const char ** expn)387c30bd091SSascha Wildner cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info,
388c30bd091SSascha Wildner const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
389c30bd091SSascha Wildner const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn,
390c30bd091SSascha Wildner const cdf_directory_t *root_storage, const char **expn)
391c30bd091SSascha Wildner {
392c30bd091SSascha Wildner int i;
393c30bd091SSascha Wildner const char *str = NULL;
394c30bd091SSascha Wildner cdf_directory_t *d;
395c30bd091SSascha Wildner char name[__arraycount(d->d_name)];
396c30bd091SSascha Wildner size_t j, k;
397c30bd091SSascha Wildner
398c30bd091SSascha Wildner #ifdef CDF_DEBUG
399c30bd091SSascha Wildner cdf_dump_summary_info(h, scn);
400c30bd091SSascha Wildner #endif
401c30bd091SSascha Wildner if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) {
402c30bd091SSascha Wildner *expn = "Can't expand summary_info";
403c30bd091SSascha Wildner return i;
404c30bd091SSascha Wildner }
405c30bd091SSascha Wildner if (i == 1)
406c30bd091SSascha Wildner return i;
407c30bd091SSascha Wildner for (j = 0; str == NULL && j < dir->dir_len; j++) {
408c30bd091SSascha Wildner d = &dir->dir_tab[j];
409c30bd091SSascha Wildner for (k = 0; k < sizeof(name); k++)
4106fca56fbSSascha Wildner name[k] = CAST(char, cdf_tole2(d->d_name[k]));
411c30bd091SSascha Wildner str = cdf_app_to_mime(name,
412c30bd091SSascha Wildner NOTMIME(ms) ? name2desc : name2mime);
413c30bd091SSascha Wildner }
414c30bd091SSascha Wildner if (NOTMIME(ms)) {
415c30bd091SSascha Wildner if (str != NULL) {
416c30bd091SSascha Wildner if (file_printf(ms, "%s", str) == -1)
417c30bd091SSascha Wildner return -1;
418c30bd091SSascha Wildner i = 1;
419c30bd091SSascha Wildner }
4206fca56fbSSascha Wildner } else if (ms->flags & MAGIC_MIME_TYPE) {
421c30bd091SSascha Wildner if (str == NULL)
422c30bd091SSascha Wildner str = "vnd.ms-office";
423c30bd091SSascha Wildner if (file_printf(ms, "application/%s", str) == -1)
424c30bd091SSascha Wildner return -1;
425c30bd091SSascha Wildner i = 1;
426c30bd091SSascha Wildner }
427c30bd091SSascha Wildner if (i <= 0) {
428c30bd091SSascha Wildner i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst,
429c30bd091SSascha Wildner dir, scn);
430c30bd091SSascha Wildner }
431c30bd091SSascha Wildner return i;
432c30bd091SSascha Wildner }
433c30bd091SSascha Wildner
434c30bd091SSascha Wildner private struct sinfo {
435c30bd091SSascha Wildner const char *name;
436c30bd091SSascha Wildner const char *mime;
437c30bd091SSascha Wildner const char *sections[5];
438c30bd091SSascha Wildner const int types[5];
439c30bd091SSascha Wildner } sectioninfo[] = {
440c30bd091SSascha Wildner { "Encrypted", "encrypted",
441c30bd091SSascha Wildner {
442c30bd091SSascha Wildner "EncryptedPackage", "EncryptedSummary",
443c30bd091SSascha Wildner NULL, NULL, NULL,
444c30bd091SSascha Wildner },
445c30bd091SSascha Wildner {
446c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
447c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
448c30bd091SSascha Wildner 0, 0, 0,
449c30bd091SSascha Wildner
450c30bd091SSascha Wildner },
451c30bd091SSascha Wildner },
452c30bd091SSascha Wildner { "QuickBooks", "quickbooks",
453c30bd091SSascha Wildner {
454c30bd091SSascha Wildner #if 0
455c30bd091SSascha Wildner "TaxForms", "PDFTaxForms", "modulesInBackup",
456c30bd091SSascha Wildner #endif
457c30bd091SSascha Wildner "mfbu_header", NULL, NULL, NULL, NULL,
458c30bd091SSascha Wildner },
459c30bd091SSascha Wildner {
460c30bd091SSascha Wildner #if 0
461c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STORAGE,
462c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STORAGE,
463c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
464c30bd091SSascha Wildner #endif
465c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
466c30bd091SSascha Wildner 0, 0, 0, 0
467c30bd091SSascha Wildner },
468c30bd091SSascha Wildner },
469c30bd091SSascha Wildner { "Microsoft Excel", "vnd.ms-excel",
470c30bd091SSascha Wildner {
471c30bd091SSascha Wildner "Book", "Workbook", NULL, NULL, NULL,
472c30bd091SSascha Wildner },
473c30bd091SSascha Wildner {
474c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
475c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
476c30bd091SSascha Wildner 0, 0, 0,
477c30bd091SSascha Wildner },
478c30bd091SSascha Wildner },
479c30bd091SSascha Wildner { "Microsoft Word", "msword",
480c30bd091SSascha Wildner {
481c30bd091SSascha Wildner "WordDocument", NULL, NULL, NULL, NULL,
482c30bd091SSascha Wildner },
483c30bd091SSascha Wildner {
484c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
485c30bd091SSascha Wildner 0, 0, 0, 0,
486c30bd091SSascha Wildner },
487c30bd091SSascha Wildner },
488c30bd091SSascha Wildner { "Microsoft PowerPoint", "vnd.ms-powerpoint",
489c30bd091SSascha Wildner {
490c30bd091SSascha Wildner "PowerPoint", NULL, NULL, NULL, NULL,
491c30bd091SSascha Wildner },
492c30bd091SSascha Wildner {
493c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
494c30bd091SSascha Wildner 0, 0, 0, 0,
495c30bd091SSascha Wildner },
496c30bd091SSascha Wildner },
497c30bd091SSascha Wildner { "Microsoft Outlook Message", "vnd.ms-outlook",
498c30bd091SSascha Wildner {
499c30bd091SSascha Wildner "__properties_version1.0",
500c30bd091SSascha Wildner "__recip_version1.0_#00000000",
501c30bd091SSascha Wildner NULL, NULL, NULL,
502c30bd091SSascha Wildner },
503c30bd091SSascha Wildner {
504c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STREAM,
505c30bd091SSascha Wildner CDF_DIR_TYPE_USER_STORAGE,
506c30bd091SSascha Wildner 0, 0, 0,
507c30bd091SSascha Wildner },
508c30bd091SSascha Wildner },
509c30bd091SSascha Wildner };
510c30bd091SSascha Wildner
511c30bd091SSascha Wildner private int
cdf_file_dir_info(struct magic_set * ms,const cdf_dir_t * dir)512c30bd091SSascha Wildner cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
513c30bd091SSascha Wildner {
514c30bd091SSascha Wildner size_t sd, j;
515c30bd091SSascha Wildner
516c30bd091SSascha Wildner for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
517c30bd091SSascha Wildner const struct sinfo *si = §ioninfo[sd];
518c30bd091SSascha Wildner for (j = 0; si->sections[j]; j++) {
519c30bd091SSascha Wildner if (cdf_find_stream(dir, si->sections[j], si->types[j])
520c30bd091SSascha Wildner > 0)
521c30bd091SSascha Wildner break;
522c30bd091SSascha Wildner #ifdef CDF_DEBUG
523c30bd091SSascha Wildner fprintf(stderr, "Can't read %s\n", si->sections[j]);
524c30bd091SSascha Wildner #endif
525c30bd091SSascha Wildner }
526c30bd091SSascha Wildner if (si->sections[j] == NULL)
527c30bd091SSascha Wildner continue;
528c30bd091SSascha Wildner if (NOTMIME(ms)) {
529c30bd091SSascha Wildner if (file_printf(ms, "CDFV2 %s", si->name) == -1)
530c30bd091SSascha Wildner return -1;
5316fca56fbSSascha Wildner } else if (ms->flags & MAGIC_MIME_TYPE) {
532c30bd091SSascha Wildner if (file_printf(ms, "application/%s", si->mime) == -1)
533c30bd091SSascha Wildner return -1;
534c30bd091SSascha Wildner }
535c30bd091SSascha Wildner return 1;
536c30bd091SSascha Wildner }
537c30bd091SSascha Wildner return -1;
538c30bd091SSascha Wildner }
539c30bd091SSascha Wildner
54079343712SPeter Avalos protected int
file_trycdf(struct magic_set * ms,const struct buffer * b)5416fca56fbSSascha Wildner file_trycdf(struct magic_set *ms, const struct buffer *b)
54279343712SPeter Avalos {
5436fca56fbSSascha Wildner int fd = b->fd;
5446fca56fbSSascha Wildner const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
5456fca56fbSSascha Wildner size_t nbytes = b->flen;
54679343712SPeter Avalos cdf_info_t info;
54779343712SPeter Avalos cdf_header_t h;
54879343712SPeter Avalos cdf_sat_t sat, ssat;
54979343712SPeter Avalos cdf_stream_t sst, scn;
55079343712SPeter Avalos cdf_dir_t dir;
55179343712SPeter Avalos int i;
55279343712SPeter Avalos const char *expn = "";
55382c5fa3eSPeter Avalos const cdf_directory_t *root_storage;
55479343712SPeter Avalos
555c30bd091SSascha Wildner scn.sst_tab = NULL;
55679343712SPeter Avalos info.i_fd = fd;
55779343712SPeter Avalos info.i_buf = buf;
55879343712SPeter Avalos info.i_len = nbytes;
559c30bd091SSascha Wildner if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
56079343712SPeter Avalos return 0;
56179343712SPeter Avalos if (cdf_read_header(&info, &h) == -1)
56279343712SPeter Avalos return 0;
56379343712SPeter Avalos #ifdef CDF_DEBUG
56479343712SPeter Avalos cdf_dump_header(&h);
56579343712SPeter Avalos #endif
56679343712SPeter Avalos
56779343712SPeter Avalos if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
56879343712SPeter Avalos expn = "Can't read SAT";
56979343712SPeter Avalos goto out0;
57079343712SPeter Avalos }
57179343712SPeter Avalos #ifdef CDF_DEBUG
57279343712SPeter Avalos cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
57379343712SPeter Avalos #endif
57479343712SPeter Avalos
57579343712SPeter Avalos if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
57679343712SPeter Avalos expn = "Can't read SSAT";
57779343712SPeter Avalos goto out1;
57879343712SPeter Avalos }
57979343712SPeter Avalos #ifdef CDF_DEBUG
58079343712SPeter Avalos cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
58179343712SPeter Avalos #endif
58279343712SPeter Avalos
58379343712SPeter Avalos if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
58479343712SPeter Avalos expn = "Can't read directory";
58579343712SPeter Avalos goto out2;
58679343712SPeter Avalos }
58779343712SPeter Avalos
588e8af9738SPeter Avalos if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
589e8af9738SPeter Avalos &root_storage)) == -1) {
59079343712SPeter Avalos expn = "Cannot read short stream";
59179343712SPeter Avalos goto out3;
59279343712SPeter Avalos }
59379343712SPeter Avalos #ifdef CDF_DEBUG
59479343712SPeter Avalos cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
59579343712SPeter Avalos #endif
596e8af9738SPeter Avalos #ifdef notdef
597e8af9738SPeter Avalos if (root_storage) {
598e8af9738SPeter Avalos if (NOTMIME(ms)) {
599e8af9738SPeter Avalos char clsbuf[128];
600e8af9738SPeter Avalos if (file_printf(ms, "CLSID %s, ",
601e8af9738SPeter Avalos format_clsid(clsbuf, sizeof(clsbuf),
602e8af9738SPeter Avalos root_storage->d_storage_uuid)) == -1)
603e8af9738SPeter Avalos return -1;
604e8af9738SPeter Avalos }
605e8af9738SPeter Avalos }
606e8af9738SPeter Avalos #endif
60779343712SPeter Avalos
608*3b9cdfa3SAntonio Huete Jimenez if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
609*3b9cdfa3SAntonio Huete Jimenez "FileHeader", &scn) != -1) {
61082c5fa3eSPeter Avalos #define HWP5_SIGNATURE "HWP Document File"
611c30bd091SSascha Wildner if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1
61282c5fa3eSPeter Avalos && memcmp(scn.sst_tab, HWP5_SIGNATURE,
61382c5fa3eSPeter Avalos sizeof(HWP5_SIGNATURE) - 1) == 0) {
61482c5fa3eSPeter Avalos if (NOTMIME(ms)) {
61582c5fa3eSPeter Avalos if (file_printf(ms,
61682c5fa3eSPeter Avalos "Hangul (Korean) Word Processor File 5.x") == -1)
61782c5fa3eSPeter Avalos return -1;
6186fca56fbSSascha Wildner } else if (ms->flags & MAGIC_MIME_TYPE) {
61982c5fa3eSPeter Avalos if (file_printf(ms, "application/x-hwp") == -1)
62082c5fa3eSPeter Avalos return -1;
62182c5fa3eSPeter Avalos }
62282c5fa3eSPeter Avalos i = 1;
62382c5fa3eSPeter Avalos goto out5;
62482c5fa3eSPeter Avalos } else {
625c30bd091SSascha Wildner cdf_zero_stream(&scn);
62682c5fa3eSPeter Avalos }
62782c5fa3eSPeter Avalos }
62882c5fa3eSPeter Avalos
62979343712SPeter Avalos if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
63079343712SPeter Avalos &scn)) == -1) {
631c30bd091SSascha Wildner if (errno != ESRCH) {
63279343712SPeter Avalos expn = "Cannot read summary info";
633f72f8299SJan Lentfer }
634c30bd091SSascha Wildner } else {
635c30bd091SSascha Wildner i = cdf_check_summary_info(ms, &info, &h,
636c30bd091SSascha Wildner &sat, &ssat, &sst, &dir, &scn, root_storage, &expn);
637c30bd091SSascha Wildner cdf_zero_stream(&scn);
63879343712SPeter Avalos }
639c30bd091SSascha Wildner if (i <= 0) {
640c30bd091SSascha Wildner if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat,
641c30bd091SSascha Wildner &sst, &dir, &scn)) == -1) {
642c30bd091SSascha Wildner if (errno != ESRCH) {
643c30bd091SSascha Wildner expn = "Cannot read summary info";
644a96e001bSPeter Avalos }
645e8af9738SPeter Avalos } else {
646c30bd091SSascha Wildner i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat,
647c30bd091SSascha Wildner &sst, &dir, &scn, root_storage, &expn);
648a96e001bSPeter Avalos }
649e8af9738SPeter Avalos }
650c30bd091SSascha Wildner if (i <= 0) {
651c30bd091SSascha Wildner i = cdf_file_dir_info(ms, &dir);
652c30bd091SSascha Wildner if (i < 0)
653c30bd091SSascha Wildner expn = "Cannot read section info";
654c30bd091SSascha Wildner }
65582c5fa3eSPeter Avalos out5:
656c30bd091SSascha Wildner cdf_zero_stream(&scn);
657c30bd091SSascha Wildner cdf_zero_stream(&sst);
65879343712SPeter Avalos out3:
65979343712SPeter Avalos free(dir.dir_tab);
66079343712SPeter Avalos out2:
66179343712SPeter Avalos free(ssat.sat_tab);
66279343712SPeter Avalos out1:
66379343712SPeter Avalos free(sat.sat_tab);
66479343712SPeter Avalos out0:
6656fca56fbSSascha Wildner /* If we handled it already, return */
6666fca56fbSSascha Wildner if (i != -1)
6676fca56fbSSascha Wildner return i;
6686fca56fbSSascha Wildner /* Provide a default handler */
669e8af9738SPeter Avalos if (NOTMIME(ms)) {
670e8af9738SPeter Avalos if (file_printf(ms,
671e8af9738SPeter Avalos "Composite Document File V2 Document") == -1)
67279343712SPeter Avalos return -1;
67379343712SPeter Avalos if (*expn)
674c30bd091SSascha Wildner if (file_printf(ms, ", %s", expn) == -1)
67579343712SPeter Avalos return -1;
6766fca56fbSSascha Wildner } else if (ms->flags & MAGIC_MIME_TYPE) {
677*3b9cdfa3SAntonio Huete Jimenez /* https://reposcope.com/mimetype/application/x-ole-storage */
678*3b9cdfa3SAntonio Huete Jimenez if (file_printf(ms, "application/x-ole-storage") == -1)
679e8af9738SPeter Avalos return -1;
680e8af9738SPeter Avalos }
6816fca56fbSSascha Wildner return 1;
68279343712SPeter Avalos }
683