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.18 2009/05/06 20:48:22 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 = "vnd.ms-office"; 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_SIGNED16: 59 if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, 60 info[i].pi_s16) == -1) 61 return -1; 62 break; 63 case CDF_SIGNED32: 64 if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, 65 info[i].pi_s32) == -1) 66 return -1; 67 break; 68 case CDF_UNSIGNED32: 69 if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, 70 info[i].pi_u32) == -1) 71 return -1; 72 break; 73 case CDF_LENGTH32_STRING: 74 len = info[i].pi_str.s_len; 75 if (len > 1) { 76 s = info[i].pi_str.s_buf; 77 if (NOTMIME(ms)) { 78 char vbuf[1024]; 79 size_t j; 80 for (j = 0; j < sizeof(vbuf) && len--; 81 j++, s++) { 82 if (*s == '\0') 83 break; 84 if (isprint((unsigned char)*s)) 85 vbuf[j] = *s; 86 } 87 if (j == sizeof(vbuf)) 88 --j; 89 vbuf[j] = '\0'; 90 if (vbuf[0]) { 91 if (file_printf(ms, ", %s: %s", 92 buf, vbuf) == -1) 93 return -1; 94 } 95 } else if (info[i].pi_id == 96 CDF_PROPERTY_NAME_OF_APPLICATION) { 97 if (strstr(s, "Word")) 98 str = "msword"; 99 else if (strstr(s, "Excel")) 100 str = "vnd.ms-excel"; 101 else if (strstr(s, "Powerpoint")) 102 str = "vnd.ms-powerpoint"; 103 } 104 } 105 break; 106 case CDF_FILETIME: 107 tp = info[i].pi_tp; 108 if (tp != 0) { 109 if (tp < 1000000000000000LL) { 110 char tbuf[64]; 111 cdf_print_elapsed_time(tbuf, 112 sizeof(tbuf), tp); 113 if (NOTMIME(ms) && file_printf(ms, 114 ", %s: %s", buf, tbuf) == -1) 115 return -1; 116 } else { 117 char *c, *ec; 118 cdf_timestamp_to_timespec(&ts, tp); 119 c = ctime(&ts.tv_sec); 120 if ((ec = strchr(c, '\n')) != NULL) 121 *ec = '\0'; 122 123 if (NOTMIME(ms) && file_printf(ms, 124 ", %s: %s", buf, c) == -1) 125 return -1; 126 } 127 } 128 break; 129 case CDF_CLIPBOARD: 130 break; 131 default: 132 return -1; 133 } 134 } 135 if (!NOTMIME(ms)) { 136 if (file_printf(ms, "application/%s", str) == -1) 137 return -1; 138 } 139 return 1; 140 } 141 142 private int 143 cdf_file_summary_info(struct magic_set *ms, const cdf_stream_t *sst) 144 { 145 cdf_summary_info_header_t si; 146 cdf_property_info_t *info; 147 size_t count; 148 int m; 149 150 if (cdf_unpack_summary_info(sst, &si, &info, &count) == -1) 151 return -1; 152 153 if (NOTMIME(ms)) { 154 if (file_printf(ms, "CDF V2 Document") == -1) 155 return -1; 156 157 if (file_printf(ms, ", %s Endian", 158 si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 159 return -1; 160 switch (si.si_os) { 161 case 2: 162 if (file_printf(ms, ", Os: Windows, Version %d.%d", 163 si.si_os_version & 0xff, si.si_os_version >> 8) 164 == -1) 165 return -1; 166 break; 167 case 1: 168 if (file_printf(ms, ", Os: MacOS, Version %d.%d", 169 si.si_os_version >> 8, si.si_os_version & 0xff) 170 == -1) 171 return -1; 172 break; 173 default: 174 if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 175 si.si_os_version & 0xff, si.si_os_version >> 8) 176 == -1) 177 return -1; 178 break; 179 } 180 } 181 182 m = cdf_file_property_info(ms, info, count); 183 free(info); 184 185 return m; 186 } 187 188 protected int 189 file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, 190 size_t nbytes) 191 { 192 cdf_info_t info; 193 cdf_header_t h; 194 cdf_sat_t sat, ssat; 195 cdf_stream_t sst, scn; 196 cdf_dir_t dir; 197 int i; 198 const char *expn = ""; 199 200 info.i_fd = fd; 201 info.i_buf = buf; 202 info.i_len = nbytes; 203 if (ms->flags & MAGIC_APPLE) 204 return 0; 205 if (cdf_read_header(&info, &h) == -1) 206 return 0; 207 #ifdef CDF_DEBUG 208 cdf_dump_header(&h); 209 #endif 210 211 if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 212 expn = "Can't read SAT"; 213 goto out0; 214 } 215 #ifdef CDF_DEBUG 216 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 217 #endif 218 219 if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 220 expn = "Can't read SSAT"; 221 goto out1; 222 } 223 #ifdef CDF_DEBUG 224 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 225 #endif 226 227 if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 228 expn = "Can't read directory"; 229 goto out2; 230 } 231 232 if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) { 233 expn = "Cannot read short stream"; 234 goto out3; 235 } 236 #ifdef CDF_DEBUG 237 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 238 #endif 239 240 if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 241 &scn)) == -1) { 242 expn = "Cannot read summary info"; 243 goto out4; 244 } 245 #ifdef CDF_DEBUG 246 cdf_dump_summary_info(&h, &scn); 247 #endif 248 if ((i = cdf_file_summary_info(ms, &scn)) == -1) 249 expn = "Can't expand summary_info"; 250 free(scn.sst_tab); 251 out4: 252 free(sst.sst_tab); 253 out3: 254 free(dir.dir_tab); 255 out2: 256 free(ssat.sat_tab); 257 out1: 258 free(sat.sat_tab); 259 out0: 260 if (i != 1) { 261 if (file_printf(ms, "CDF V2 Document") == -1) 262 return -1; 263 if (*expn) 264 if (file_printf(ms, ", corrupt: %s", expn) == -1) 265 return -1; 266 i = 1; 267 } 268 return i; 269 } 270