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