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 29 FILE_RCSID("@(#)$File: readcdf.c,v 1.27 2011/09/28 13:30:10 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 43 private int 44 cdf_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 if (file_printf(ms, "application/%s", str) == -1) 148 return -1; 149 } 150 return 1; 151 } 152 153 private int 154 cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, 155 const cdf_stream_t *sst) 156 { 157 cdf_summary_info_header_t si; 158 cdf_property_info_t *info; 159 size_t count; 160 int m; 161 162 if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) 163 return -1; 164 165 if (NOTMIME(ms)) { 166 if (file_printf(ms, "Composite Document File V2 Document") == -1) 167 return -1; 168 169 if (file_printf(ms, ", %s Endian", 170 si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 171 return -1; 172 switch (si.si_os) { 173 case 2: 174 if (file_printf(ms, ", Os: Windows, Version %d.%d", 175 si.si_os_version & 0xff, 176 (uint32_t)si.si_os_version >> 8) == -1) 177 return -1; 178 break; 179 case 1: 180 if (file_printf(ms, ", Os: MacOS, Version %d.%d", 181 (uint32_t)si.si_os_version >> 8, 182 si.si_os_version & 0xff) == -1) 183 return -1; 184 break; 185 default: 186 if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 187 si.si_os_version & 0xff, 188 (uint32_t)si.si_os_version >> 8) == -1) 189 return -1; 190 break; 191 } 192 } 193 194 m = cdf_file_property_info(ms, info, count); 195 free(info); 196 197 return m; 198 } 199 200 protected int 201 file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, 202 size_t nbytes) 203 { 204 cdf_info_t info; 205 cdf_header_t h; 206 cdf_sat_t sat, ssat; 207 cdf_stream_t sst, scn; 208 cdf_dir_t dir; 209 int i; 210 const char *expn = ""; 211 const char *corrupt = "corrupt: "; 212 213 info.i_fd = fd; 214 info.i_buf = buf; 215 info.i_len = nbytes; 216 if (ms->flags & MAGIC_APPLE) 217 return 0; 218 if (cdf_read_header(&info, &h) == -1) 219 return 0; 220 #ifdef CDF_DEBUG 221 cdf_dump_header(&h); 222 #endif 223 224 if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 225 expn = "Can't read SAT"; 226 goto out0; 227 } 228 #ifdef CDF_DEBUG 229 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 230 #endif 231 232 if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 233 expn = "Can't read SSAT"; 234 goto out1; 235 } 236 #ifdef CDF_DEBUG 237 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 238 #endif 239 240 if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 241 expn = "Can't read directory"; 242 goto out2; 243 } 244 245 if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) { 246 expn = "Cannot read short stream"; 247 goto out3; 248 } 249 #ifdef CDF_DEBUG 250 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 251 #endif 252 253 if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 254 &scn)) == -1) { 255 if (errno == ESRCH) { 256 corrupt = expn; 257 expn = "No summary info"; 258 } else { 259 expn = "Cannot read summary info"; 260 } 261 goto out4; 262 } 263 #ifdef CDF_DEBUG 264 cdf_dump_summary_info(&h, &scn); 265 #endif 266 if ((i = cdf_file_summary_info(ms, &h, &scn)) == -1) 267 expn = "Can't expand summary_info"; 268 if (i == 0) { 269 const char *str = "vnd.ms-office"; 270 cdf_directory_t *d; 271 char name[__arraycount(d->d_name)]; 272 size_t j, k; 273 for (j = 0; j < dir.dir_len; j++) { 274 d = &dir.dir_tab[j]; 275 for (k = 0; k < sizeof(name); k++) 276 name[k] = (char)cdf_tole2(d->d_name[k]); 277 if (strstr(name, "WordDocument") == 0) { 278 str = "msword"; 279 break; 280 } 281 } 282 if (file_printf(ms, "application/%s", str) == -1) 283 return -1; 284 i = 1; 285 } 286 free(scn.sst_tab); 287 out4: 288 free(sst.sst_tab); 289 out3: 290 free(dir.dir_tab); 291 out2: 292 free(ssat.sat_tab); 293 out1: 294 free(sat.sat_tab); 295 out0: 296 if (i != 1) { 297 if (file_printf(ms, "Composite Document File V2 Document") 298 == -1) 299 return -1; 300 if (*expn) 301 if (file_printf(ms, ", %s%s", corrupt, expn) == -1) 302 return -1; 303 i = 1; 304 } 305 return i; 306 } 307