readcdf.c revision 226048
1/*-
2 * Copyright (c) 2008 Christos Zoulas
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26#include "file.h"
27
28#ifndef lint
29FILE_RCSID("@(#)$File: readcdf.c,v 1.26 2011/08/26 13:38:28 christos Exp $")
30#endif
31
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35#include <time.h>
36#include <ctype.h>
37
38#include "cdf.h"
39#include "magic.h"
40
41#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
42
43private int
44cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
45    size_t count)
46{
47        size_t i;
48        cdf_timestamp_t tp;
49        struct timespec ts;
50        char buf[64];
51        const char *str = NULL;
52        const char *s;
53        int len;
54
55        for (i = 0; i < count; i++) {
56                cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
57                switch (info[i].pi_type) {
58                case CDF_NULL:
59                        break;
60                case CDF_SIGNED16:
61                        if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
62                            info[i].pi_s16) == -1)
63                                return -1;
64                        break;
65                case CDF_SIGNED32:
66                        if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
67                            info[i].pi_s32) == -1)
68                                return -1;
69                        break;
70                case CDF_UNSIGNED32:
71                        if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
72                            info[i].pi_u32) == -1)
73                                return -1;
74                        break;
75                case CDF_LENGTH32_STRING:
76                case CDF_LENGTH32_WSTRING:
77                        len = info[i].pi_str.s_len;
78                        if (len > 1) {
79                                char vbuf[1024];
80                                size_t j, k = 1;
81
82                                if (info[i].pi_type == CDF_LENGTH32_WSTRING)
83                                    k++;
84                                s = info[i].pi_str.s_buf;
85                                for (j = 0; j < sizeof(vbuf) && len--;
86                                    j++, s += k) {
87                                        if (*s == '\0')
88                                                break;
89                                        if (isprint((unsigned char)*s))
90                                                vbuf[j] = *s;
91                                }
92                                if (j == sizeof(vbuf))
93                                        --j;
94                                vbuf[j] = '\0';
95                                if (NOTMIME(ms)) {
96                                        if (vbuf[0]) {
97                                                if (file_printf(ms, ", %s: %s",
98                                                    buf, vbuf) == -1)
99                                                        return -1;
100                                        }
101                                } else if (info[i].pi_id ==
102                                        CDF_PROPERTY_NAME_OF_APPLICATION) {
103                                        if (strstr(vbuf, "Word"))
104                                                str = "msword";
105                                        else if (strstr(vbuf, "Excel"))
106                                                str = "vnd.ms-excel";
107                                        else if (strstr(vbuf, "Powerpoint"))
108                                                str = "vnd.ms-powerpoint";
109                                        else if (strstr(vbuf,
110                                            "Crystal Reports"))
111                                                str = "x-rpt";
112                                }
113                        }
114                        break;
115                case CDF_FILETIME:
116                        tp = info[i].pi_tp;
117                        if (tp != 0) {
118                                if (tp < 1000000000000000LL) {
119                                        char tbuf[64];
120                                        cdf_print_elapsed_time(tbuf,
121                                            sizeof(tbuf), tp);
122                                        if (NOTMIME(ms) && file_printf(ms,
123                                            ", %s: %s", buf, tbuf) == -1)
124                                                return -1;
125                                } else {
126                                        char *c, *ec;
127                                        cdf_timestamp_to_timespec(&ts, tp);
128                                        c = cdf_ctime(&ts.tv_sec);
129                                        if ((ec = strchr(c, '\n')) != NULL)
130                                                *ec = '\0';
131
132                                        if (NOTMIME(ms) && file_printf(ms,
133                                            ", %s: %s", buf, c) == -1)
134                                                return -1;
135                                }
136                        }
137                        break;
138                case CDF_CLIPBOARD:
139                        break;
140                default:
141                        return -1;
142                }
143        }
144        if (!NOTMIME(ms)) {
145		if (str == NULL)
146			return 0;
147        }
148        return 1;
149}
150
151private int
152cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
153    const cdf_stream_t *sst)
154{
155        cdf_summary_info_header_t si;
156        cdf_property_info_t *info;
157        size_t count;
158        int m;
159
160        if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
161                return -1;
162
163        if (NOTMIME(ms)) {
164                if (file_printf(ms, "Composite Document File V2 Document") == -1)
165                        return -1;
166
167                if (file_printf(ms, ", %s Endian",
168                    si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
169                        return -1;
170                switch (si.si_os) {
171                case 2:
172                        if (file_printf(ms, ", Os: Windows, Version %d.%d",
173                            si.si_os_version & 0xff,
174                            (uint32_t)si.si_os_version >> 8) == -1)
175                                return -1;
176                        break;
177                case 1:
178                        if (file_printf(ms, ", Os: MacOS, Version %d.%d",
179                            (uint32_t)si.si_os_version >> 8,
180                            si.si_os_version & 0xff) == -1)
181                                return -1;
182                        break;
183                default:
184                        if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
185                            si.si_os_version & 0xff,
186                            (uint32_t)si.si_os_version >> 8) == -1)
187                                return -1;
188                        break;
189                }
190        }
191
192        m = cdf_file_property_info(ms, info, count);
193        free(info);
194
195        return m;
196}
197
198protected int
199file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
200    size_t nbytes)
201{
202        cdf_info_t info;
203        cdf_header_t h;
204        cdf_sat_t sat, ssat;
205        cdf_stream_t sst, scn;
206        cdf_dir_t dir;
207        int i;
208        const char *expn = "";
209        const char *corrupt = "corrupt: ";
210
211        info.i_fd = fd;
212        info.i_buf = buf;
213        info.i_len = nbytes;
214        if (ms->flags & MAGIC_APPLE)
215                return 0;
216        if (cdf_read_header(&info, &h) == -1)
217                return 0;
218#ifdef CDF_DEBUG
219        cdf_dump_header(&h);
220#endif
221
222        if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
223                expn = "Can't read SAT";
224                goto out0;
225        }
226#ifdef CDF_DEBUG
227        cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
228#endif
229
230        if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
231                expn = "Can't read SSAT";
232                goto out1;
233        }
234#ifdef CDF_DEBUG
235        cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
236#endif
237
238        if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
239                expn = "Can't read directory";
240                goto out2;
241        }
242
243        if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) {
244                expn = "Cannot read short stream";
245                goto out3;
246        }
247#ifdef CDF_DEBUG
248        cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
249#endif
250
251        if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
252            &scn)) == -1) {
253                if (errno == ESRCH) {
254                        corrupt = expn;
255                        expn = "No summary info";
256                } else {
257                        expn = "Cannot read summary info";
258                }
259                goto out4;
260        }
261#ifdef CDF_DEBUG
262        cdf_dump_summary_info(&h, &scn);
263#endif
264        if ((i = cdf_file_summary_info(ms, &h, &scn)) == -1)
265                expn = "Can't expand summary_info";
266	if (i == 0) {
267		const char *str = "vnd.ms-office";
268		cdf_directory_t *d;
269		char name[__arraycount(d->d_name)];
270		size_t j, k;
271		for (j = 0; j < dir.dir_len; j++) {
272		    d = &dir.dir_tab[j];
273		    for (k = 0; k < sizeof(name); k++)
274			name[k] = (char)cdf_tole2(d->d_name[k]);
275		    if (strstr(name, "WordDocument") == 0) {
276			str = "msword";
277			break;
278		    }
279		}
280                if (file_printf(ms, "application/%s", str) == -1)
281                        return -1;
282		i = 1;
283	}
284        free(scn.sst_tab);
285out4:
286        free(sst.sst_tab);
287out3:
288        free(dir.dir_tab);
289out2:
290        free(ssat.sat_tab);
291out1:
292        free(sat.sat_tab);
293out0:
294        if (i != 1) {
295                if (file_printf(ms, "Composite Document File V2 Document") == -1)
296                        return -1;
297                if (*expn)
298                        if (file_printf(ms, ", %s%s", corrupt, expn) == -1)
299                                return -1;
300                i = 1;
301        }
302        return i;
303}
304