1 /*
2 *    Yerase's TNEF Stream Reader Library
3 *    Copyright (C) 2003  Randall E. Hand
4 *
5 *    This program is free software; you can redistribute it and/or modify
6 *    it under the terms of the GNU General Public License as published by
7 *    the Free Software Foundation; either version 2 of the License, or
8 *    (at your option) any later version.
9 *
10 *    This program is distributed in the hope that it will be useful,
11 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *    GNU General Public License for more details.
14 *
15 *    You should have received a copy of the GNU General Public License
16 *    along with this program; if not, write to the Free Software
17 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 *
19 *    You can contact me at randall.hand@gmail.com for questions or assistance
20 */
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <limits.h>
26 #include "ytnef.h"
27 #include "tnef-errors.h"
28 #include "mapi.h"
29 #include "mapidefs.h"
30 #include "mapitags.h"
31 #include "config.h"
32 
33 #define RTF_PREBUF "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscript \\fdecor MS Sans SerifSymbolArialTimes New RomanCourier{\\colortbl\\red0\\green0\\blue0\n\r\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab\\tx"
34 #define DEBUG(lvl, curlvl, msg) \
35         if ((lvl) >= (curlvl)) \
36             printf("DEBUG(%i/%i): %s\n", curlvl, lvl,  msg);
37 #define DEBUG1(lvl, curlvl, msg, var1) \
38         if ((lvl) >= (curlvl)) { \
39             printf("DEBUG(%i/%i):", curlvl, lvl); \
40             printf(msg, var1); \
41             printf("\n"); \
42         }
43 #define DEBUG2(lvl, curlvl, msg, var1, var2) \
44         if ((lvl) >= (curlvl)) { \
45             printf("DEBUG(%i/%i):", curlvl, lvl); \
46             printf(msg, var1, var2); \
47             printf("\n"); \
48         }
49 #define DEBUG3(lvl, curlvl, msg, var1, var2, var3) \
50         if ((lvl) >= (curlvl)) { \
51             printf("DEBUG(%i/%i):", curlvl, lvl); \
52             printf(msg, var1, var2,var3); \
53             printf("\n"); \
54         }
55 
56 #define MIN(x,y) (((x)<(y))?(x):(y))
57 
58 #define PREALLOCCHECK(sz,max) { if(sz==0||(unsigned)sz>max) { printf("ERROR: invalid alloc size %u at %s : %i, suspected corruption\n", (unsigned)sz, __FILE__, __LINE__); return(-1); } }
59 #define ALLOCCHECK(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(-1); } }
60 #define ALLOCCHECK_CHAR(x) { if(!x) { printf("Out of Memory at %s : %i\n", __FILE__, __LINE__); return(NULL); } }
61 #define SIZECHECK(x) { if ((((char *)d - (char *)data) + x) > size) {  printf("Corrupted file detected at %s : %i\n", __FILE__, __LINE__); return(-1); } }
62 
63 int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p);
64 void SetFlip(void);
65 
66 int TNEFDefaultHandler STD_ARGLIST;
67 int TNEFAttachmentFilename STD_ARGLIST;
68 int TNEFAttachmentSave STD_ARGLIST;
69 int TNEFDetailedPrint STD_ARGLIST;
70 int TNEFHexBreakdown STD_ARGLIST;
71 int TNEFBody STD_ARGLIST;
72 int TNEFRendData STD_ARGLIST;
73 int TNEFDateHandler STD_ARGLIST;
74 int TNEFPriority  STD_ARGLIST;
75 int TNEFVersion  STD_ARGLIST;
76 int TNEFMapiProperties STD_ARGLIST;
77 int TNEFIcon STD_ARGLIST;
78 int TNEFSubjectHandler STD_ARGLIST;
79 int TNEFFromHandler STD_ARGLIST;
80 int TNEFRecipTable STD_ARGLIST;
81 int TNEFAttachmentMAPI STD_ARGLIST;
82 int TNEFSentFor STD_ARGLIST;
83 int TNEFMessageClass STD_ARGLIST;
84 int TNEFMessageID STD_ARGLIST;
85 int TNEFParentID STD_ARGLIST;
86 int TNEFOriginalMsgClass STD_ARGLIST;
87 int TNEFCodePage STD_ARGLIST;
88 
89 
90 BYTE *TNEFFileContents = NULL;
91 DWORD TNEFFileContentsSize;
92 BYTE *TNEFFileIcon = NULL;
93 DWORD TNEFFileIconSize;
94 
95 int IsCompressedRTF(variableLength *p);
96 
97 TNEFHandler TNEFList[] = {
98   {attNull,                    "Null",                        TNEFDefaultHandler},
99   {attFrom,                    "From",                        TNEFFromHandler},
100   {attSubject,                 "Subject",                     TNEFSubjectHandler},
101   {attDateSent,                "Date Sent",                   TNEFDateHandler},
102   {attDateRecd,                "Date Received",               TNEFDateHandler},
103   {attMessageStatus,           "Message Status",              TNEFDefaultHandler},
104   {attMessageClass,            "Message Class",               TNEFMessageClass},
105   {attMessageID,               "Message ID",                  TNEFMessageID},
106   {attParentID,                "Parent ID",                   TNEFParentID},
107   {attConversationID,          "Conversation ID",             TNEFDefaultHandler},
108   {attBody,                    "Body",                        TNEFBody},
109   {attPriority,                "Priority",                    TNEFPriority},
110   {attAttachData,              "Attach Data",                 TNEFAttachmentSave},
111   {attAttachTitle,             "Attach Title",                TNEFAttachmentFilename},
112   {attAttachMetaFile,          "Attach Meta-File",            TNEFIcon},
113   {attAttachCreateDate,        "Attachment Create Date",      TNEFDateHandler},
114   {attAttachModifyDate,        "Attachment Modify Date",      TNEFDateHandler},
115   {attDateModified,            "Date Modified",               TNEFDateHandler},
116   {attAttachTransportFilename, "Attachment Transport name",   TNEFDefaultHandler},
117   {attAttachRenddata,          "Attachment Display info",     TNEFRendData},
118   {attMAPIProps,               "MAPI Properties",             TNEFMapiProperties},
119   {attRecipTable,              "Recip Table",                 TNEFRecipTable},
120   {attAttachment,              "Attachment",                  TNEFAttachmentMAPI},
121   {attTnefVersion,             "TNEF Version",                TNEFVersion},
122   {attOemCodepage,             "OEM CodePage",                TNEFCodePage},
123   {attOriginalMessageClass,    "Original Message Class",      TNEFOriginalMsgClass},
124   {attOwner,                   "Owner",                       TNEFDefaultHandler},
125   {attSentFor,                 "Sent For",                    TNEFSentFor},
126   {attDelegate,                "Delegate",                    TNEFDefaultHandler},
127   {attDateStart,               "Date Start",                  TNEFDateHandler},
128   {attDateEnd,                 "Date End",                    TNEFDateHandler},
129   {attAidOwner,                "Aid Owner",                   TNEFDefaultHandler},
130   {attRequestRes,              "Request Response",            TNEFDefaultHandler}
131 };
132 
133 
SwapWord(BYTE * p,int size)134 WORD SwapWord(BYTE *p, int size) {
135   union BYTES2WORD
136   {
137       WORD word;
138       BYTE bytes[sizeof(WORD)];
139   };
140 
141   union BYTES2WORD converter;
142   converter.word = 0;
143   int i = 0;
144   int correct = size > sizeof(WORD) ? sizeof(WORD) : size;
145 
146 #ifdef WORDS_BIGENDIAN
147   for (i = 0; i < correct; ++i)
148   {
149       converter.bytes[i] = p[correct - i];
150   }
151 #else
152   for (i = 0; i < correct; ++i)
153   {
154       converter.bytes[i] = p[i];
155   }
156 #endif
157 
158   return converter.word;
159 }
160 
SwapDWord(BYTE * p,int size)161 DWORD SwapDWord(BYTE *p, int size) {
162   union BYTES2DWORD
163   {
164       DWORD dword;
165       BYTE  bytes[sizeof(DWORD)];
166   };
167 
168   union BYTES2DWORD converter;
169   converter.dword = 0;
170   int i = 0;
171   int correct = size > sizeof(DWORD) ? sizeof(DWORD) : size;
172 
173 #ifdef WORDS_BIGENDIAN
174   for (i = 0; i < correct; ++i)
175   {
176       converter.bytes[i] = p[correct - i];
177   }
178 #else
179   for (i = 0; i < correct; ++i)
180   {
181       converter.bytes[i] = p[i];
182   }
183 #endif
184 
185   return converter.dword;
186 }
187 
188 
189 
SwapDDWord(BYTE * p,int size)190 DDWORD SwapDDWord(BYTE *p, int size) {
191   union BYTES2DDWORD
192   {
193       DDWORD ddword;
194       BYTE   bytes[sizeof(DDWORD)];
195   };
196 
197   union BYTES2DDWORD converter;
198   converter.ddword = 0;
199   int i = 0;
200   int correct = size > sizeof(DDWORD) ? sizeof(DDWORD) : size;
201 
202 #ifdef WORDS_BIGENDIAN
203   for (i = 0; i < correct; ++i)
204   {
205       converter.bytes[i] = p[correct - i];
206   }
207 #else
208   for (i = 0; i < correct; ++i)
209   {
210       converter.bytes[i] = p[i];
211   }
212 #endif
213 
214   return converter.ddword;
215 }
216 
217 /* convert 16-bit unicode to UTF8 unicode */
to_utf8(size_t len,char * buf)218 char *to_utf8(size_t len, char *buf) {
219   int i, j = 0;
220   // an arbitrary length limit should be imposed by the caller of this function
221   char *utf8 = malloc(3 * len / 2 + 1);
222 
223   for (i = 0; i < len - 1; i += 2) {
224     unsigned int c = SwapWord((BYTE *)buf + i, 2);
225     if (c <= 0x007f) {
226       utf8[j++] = 0x00 | ((c & 0x007f) >> 0);
227     } else if (c < 0x07ff) {
228       utf8[j++] = 0xc0 | ((c & 0x07c0) >> 6);
229       utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
230     } else {
231       utf8[j++] = 0xe0 | ((c & 0xf000) >> 12);
232       utf8[j++] = 0x80 | ((c & 0x0fc0) >> 6);
233       utf8[j++] = 0x80 | ((c & 0x003f) >> 0);
234     }
235   }
236 
237   /* just in case the original was not null terminated */
238   utf8[j++] = '\0';
239 
240   return utf8;
241 }
242 
243 
244 // -----------------------------------------------------------------------------
245 int TNEFDefaultHandler STD_ARGLIST {
246   if (TNEF->Debug >= 1)
247     printf("%s: [%i] %.*s\n", TNEFList[id].name, size, size, data);
248   return 0;
249 }
250 
251 // -----------------------------------------------------------------------------
252 int TNEFCodePage STD_ARGLIST {
253   TNEF->CodePage.size = size;
254   TNEF->CodePage.data = calloc(size, sizeof(BYTE));
255   ALLOCCHECK(TNEF->CodePage.data);
256   memcpy(TNEF->CodePage.data, data, size);
257   return 0;
258 }
259 
260 // -----------------------------------------------------------------------------
261 int TNEFParentID STD_ARGLIST {
262   memcpy(TNEF->parentID, data, MIN(size, sizeof(TNEF->parentID)));
263   return 0;
264 }
265 // -----------------------------------------------------------------------------
266 int TNEFMessageID STD_ARGLIST {
267   memcpy(TNEF->messageID, data, MIN(size, sizeof(TNEF->messageID)));
268   return 0;
269 }
270 // -----------------------------------------------------------------------------
271 int TNEFBody STD_ARGLIST {
272   TNEF->body.size = size;
273   PREALLOCCHECK(size, 100000);
274   TNEF->body.data = calloc(size+1, sizeof(BYTE));
275   ALLOCCHECK(TNEF->body.data);
276   memcpy(TNEF->body.data, data, size);
277   return 0;
278 }
279 // -----------------------------------------------------------------------------
280 int TNEFOriginalMsgClass STD_ARGLIST {
281   TNEF->OriginalMessageClass.size = size;
282   PREALLOCCHECK(size, 100);
283   TNEF->OriginalMessageClass.data = calloc(size+1, sizeof(BYTE));
284   ALLOCCHECK(TNEF->OriginalMessageClass.data);
285   memcpy(TNEF->OriginalMessageClass.data, data, size);
286   return 0;
287 }
288 // -----------------------------------------------------------------------------
289 int TNEFMessageClass STD_ARGLIST {
290   memcpy(TNEF->messageClass, data, MIN(size, sizeof(TNEF->messageClass)-1));
291   return 0;
292 }
293 // -----------------------------------------------------------------------------
294 int TNEFFromHandler STD_ARGLIST {
295   PREALLOCCHECK(size, 100);
296   TNEF->from.data = calloc(size+1, sizeof(BYTE));
297   ALLOCCHECK(TNEF->from.data);
298   TNEF->from.size = size;
299   memcpy(TNEF->from.data, data, size);
300   return 0;
301 }
302 // -----------------------------------------------------------------------------
303 int TNEFSubjectHandler STD_ARGLIST {
304   if (TNEF->subject.data)
305     free(TNEF->subject.data);
306 
307   PREALLOCCHECK(size, 100);
308   TNEF->subject.data = calloc(size+1, sizeof(BYTE));
309   ALLOCCHECK(TNEF->subject.data);
310   TNEF->subject.size = size;
311   memcpy(TNEF->subject.data, data, size);
312   return 0;
313 }
314 
315 // -----------------------------------------------------------------------------
316 int TNEFRendData STD_ARGLIST {
317   Attachment *p;
318   // Find the last attachment.
319   p = &(TNEF->starting_attach);
320   while (p->next != NULL) p = p->next;
321 
322   // Add a new one
323   p->next = calloc(1, sizeof(Attachment));
324   ALLOCCHECK(p->next);
325   p = p->next;
326 
327   TNEFInitAttachment(p);
328 
329  int correct = (size >= sizeof(renddata)) ? sizeof(renddata) : size;
330   memcpy(&(p->RenderData), data, correct);
331   return 0;
332 }
333 
334 // -----------------------------------------------------------------------------
335 int TNEFVersion STD_ARGLIST {
336   WORD major;
337   WORD minor;
338   minor = SwapWord((BYTE*)data, size);
339   major = SwapWord((BYTE*)data + 2, size - 2);
340 
341   snprintf(TNEF->version, sizeof(TNEF->version), "TNEF%i.%i", major, minor);
342   return 0;
343 }
344 
345 // -----------------------------------------------------------------------------
346 int TNEFIcon STD_ARGLIST {
347   Attachment *p;
348   // Find the last attachment.
349   p = &(TNEF->starting_attach);
350   while (p->next != NULL) p = p->next;
351 
352   p->IconData.size = size;
353   PREALLOCCHECK(size, 10000);
354   p->IconData.data = calloc(size, sizeof(BYTE));
355   ALLOCCHECK(p->IconData.data);
356   memcpy(p->IconData.data, data, size);
357   return 0;
358 }
359 
360 // -----------------------------------------------------------------------------
361 int TNEFRecipTable STD_ARGLIST {
362   DWORD count;
363   BYTE *d;
364   int current_row;
365   int propcount;
366   int current_prop;
367 
368   d = (BYTE*)data;
369   SIZECHECK(sizeof(DWORD));
370   count = SwapDWord((BYTE*)d, sizeof(DWORD));
371   d += sizeof(DWORD);
372 //    printf("Recipient Table containing %u rows\n", count);
373 
374   return 0;
375 
376   for (current_row = 0; current_row < count; current_row++) {
377     propcount = SwapDWord((BYTE*)d, sizeof(DWORD));
378     if (TNEF->Debug >= 1)
379       printf("> Row %i contains %i properties\n", current_row, propcount);
380     d += sizeof(DWORD);
381     for (current_prop = 0; current_prop < propcount; current_prop++) {
382 
383 
384     }
385   }
386   return 0;
387 }
388 // -----------------------------------------------------------------------------
389 int TNEFAttachmentMAPI STD_ARGLIST {
390   Attachment *p;
391   // Find the last attachment.
392   //
393   p = &(TNEF->starting_attach);
394   while (p->next != NULL) p = p->next;
395   return TNEFFillMapi(TNEF, (BYTE*)data, size, &(p->MAPI));
396 }
397 // -----------------------------------------------------------------------------
398 int TNEFMapiProperties STD_ARGLIST {
399   if (TNEFFillMapi(TNEF, (BYTE*)data, size, &(TNEF->MapiProperties)) < 0) {
400     printf("ERROR Parsing MAPI block\n");
401     return -1;
402   };
403   if (TNEF->Debug >= 3) {
404     MAPIPrint(&(TNEF->MapiProperties));
405   }
406   return 0;
407 }
408 
TNEFFillMapi(TNEFStruct * TNEF,BYTE * data,DWORD size,MAPIProps * p)409 int TNEFFillMapi(TNEFStruct *TNEF, BYTE *data, DWORD size, MAPIProps *p) {
410   int i, j;
411   DWORD num;
412   BYTE *d;
413   MAPIProperty *mp;
414   DWORD type;
415   DWORD length;
416   variableLength *vl;
417 
418   WORD temp_word;
419   DWORD temp_dword;
420   DDWORD temp_ddword;
421   int mp_count = 0, p_count = 0;
422   int count = -1;
423   int offset;
424 
425   d = data;
426   SIZECHECK(sizeof(DWORD));
427   p_count = SwapDWord((BYTE*)data, sizeof(DWORD));
428   d += sizeof(DWORD);
429   // Arbitrary limit on the amount of properties
430   PREALLOCCHECK(p_count, 1000);
431   p->properties = calloc(p_count, sizeof(MAPIProperty));
432   ALLOCCHECK(p->properties);
433   p->count = p_count;
434   mp = p->properties;
435 
436   for (i = 0; i < p->count; i++) {
437     if (count == -1) {
438       SIZECHECK(sizeof(DWORD));
439       mp->id = SwapDWord((BYTE*)d, sizeof(DWORD));
440       d += sizeof(DWORD);
441       mp->custom = 0;
442       mp_count = 1;
443       mp->namedproperty = 0;
444       length = -1;
445       if (PROP_ID(mp->id) >= 0x8000) {
446         // Read the GUID
447         SIZECHECK(16);
448         memcpy(&(mp->guid[0]), d, 16);
449         d += 16;
450 
451         SIZECHECK(sizeof(DWORD));
452         length = SwapDWord((BYTE*)d, sizeof(DWORD));
453         d += sizeof(DWORD);
454         if (length > 0) {
455           PREALLOCCHECK(length, 1000);
456           mp->propnames = calloc(length, sizeof(variableLength));
457           ALLOCCHECK(mp->propnames);
458           mp->namedproperty = length;
459           while (length > 0) {
460             SIZECHECK(sizeof(DWORD));
461             type = SwapDWord((BYTE*)d, sizeof(DWORD));
462             d += sizeof(DWORD);
463             PREALLOCCHECK(type, 100);
464             mp->propnames[length - 1].data = calloc(type+1, sizeof(BYTE));
465             ALLOCCHECK(mp->propnames[length - 1].data);
466             mp->propnames[length - 1].size = type;
467             SIZECHECK(type);
468             for (j = 0; j < (type >> 1); j++) {
469               mp->propnames[length - 1].data[j] = d[j * 2];
470             }
471             d += type + ((type % 4) ? (4 - type % 4) : 0);
472             length--;
473           }
474         } else {
475           // READ the type
476           SIZECHECK(sizeof(DWORD));
477           type = SwapDWord((BYTE*)d, sizeof(DWORD));
478           d += sizeof(DWORD);
479           mp->id = PROP_TAG(PROP_TYPE(mp->id), type);
480         }
481         mp->custom = 1;
482       }
483 
484       DEBUG2(TNEF->Debug, 3, "Type id = %04x, Prop id = %04x", PROP_TYPE(mp->id),
485              PROP_ID(mp->id));
486       if (PROP_TYPE(mp->id) & MV_FLAG) {
487         mp->id = PROP_TAG(PROP_TYPE(mp->id) - MV_FLAG, PROP_ID(mp->id));
488         SIZECHECK(sizeof(DWORD));
489         mp_count = SwapDWord((BYTE*)d, sizeof(DWORD));
490         d += sizeof(DWORD);
491         count = 0;
492       }
493       PREALLOCCHECK(mp_count, 1000);
494       mp->data = calloc(mp_count, sizeof(variableLength));
495       ALLOCCHECK(mp->data);
496       mp->count = mp_count;
497       vl = mp->data;
498     } else {
499       i--;
500       count++;
501       vl = &(mp->data[count]);
502     }
503 
504     switch (PROP_TYPE(mp->id)) {
505       case PT_BINARY:
506       case PT_OBJECT:
507       case PT_STRING8:
508       case PT_UNICODE:
509         // First number of objects (assume 1 for now)
510         if (count == -1) {
511           SIZECHECK(sizeof(DWORD));
512           vl->size = SwapDWord((BYTE*)d, sizeof(DWORD));
513           d += sizeof(DWORD);
514         }
515         // now size of object
516         SIZECHECK(sizeof(DWORD));
517         vl->size = SwapDWord((BYTE*)d, sizeof(DWORD));
518         d += sizeof(DWORD);
519 
520         // now actual object
521         if (vl->size != 0) {
522           SIZECHECK(vl->size);
523           PREALLOCCHECK(vl->size, 100000);
524           if (PROP_TYPE(mp->id) == PT_UNICODE) {
525             vl->data =(BYTE*) to_utf8(vl->size, (char*)d);
526             if(vl->data == NULL)
527               return -1;
528           } else {
529             vl->data = calloc(vl->size, sizeof(BYTE));
530             ALLOCCHECK(vl->data);
531             memcpy(vl->data, d, vl->size);
532           }
533         } else {
534           vl->data = NULL;
535         }
536 
537         // Make sure to read in a multiple of 4
538         num = vl->size;
539         offset = ((num % 4) ? (4 - num % 4) : 0);
540         d += num + ((num % 4) ? (4 - num % 4) : 0);
541         break;
542 
543       case PT_I2:
544         // Read in 2 bytes, but proceed by 4 bytes
545         vl->size = 2;
546         PREALLOCCHECK(vl->size, 10000);
547         vl->data = calloc(vl->size, sizeof(WORD));
548         ALLOCCHECK(vl->data);
549         SIZECHECK(sizeof(WORD))
550         temp_word = SwapWord((BYTE*)d, sizeof(WORD));
551         memcpy(vl->data, &temp_word, vl->size);
552         d += 4;
553         break;
554       case PT_BOOLEAN:
555       case PT_LONG:
556       case PT_R4:
557       case PT_CURRENCY:
558       case PT_APPTIME:
559       case PT_ERROR:
560         vl->size = 4;
561         PREALLOCCHECK(vl->size, 10000);
562         vl->data = calloc(vl->size, sizeof(BYTE));
563         ALLOCCHECK(vl->data);
564         SIZECHECK(4);
565         temp_dword = SwapDWord((BYTE*)d, 4);
566         memcpy(vl->data, &temp_dword, vl->size);
567         d += 4;
568         break;
569       case PT_DOUBLE:
570       case PT_I8:
571       case PT_SYSTIME:
572         vl->size = 8;
573         PREALLOCCHECK(vl->size, 10000);
574         vl->data = calloc(vl->size, sizeof(BYTE));
575         ALLOCCHECK(vl->data);
576         SIZECHECK(8);
577         temp_ddword = SwapDDWord(d, 8);
578         memcpy(vl->data, &temp_ddword, vl->size);
579         d += 8;
580         break;
581       case PT_CLSID:
582         vl->size = 16;
583         PREALLOCCHECK(vl->size, 10000);
584         vl->data = calloc(vl->size, sizeof(BYTE));
585         ALLOCCHECK(vl->data);
586         SIZECHECK(vl->size);
587         memcpy(vl->data, d, vl->size);
588         d+=16;
589         break;
590       default:
591         printf("Bad file\n");
592         return -1;
593     }
594 
595     switch (PROP_ID(mp->id)) {
596       case PR_SUBJECT:
597       case PR_SUBJECT_IPM:
598       case PR_ORIGINAL_SUBJECT:
599       case PR_NORMALIZED_SUBJECT:
600       case PR_CONVERSATION_TOPIC:
601         DEBUG(TNEF->Debug, 3, "Got a Subject");
602         if (TNEF->subject.size == 0) {
603           int i;
604           DEBUG(TNEF->Debug, 3, "Assigning a Subject");
605           PREALLOCCHECK(vl->size, 100);
606           TNEF->subject.data = calloc(vl->size+1, sizeof(BYTE));
607           ALLOCCHECK(TNEF->subject.data);
608           TNEF->subject.size = vl->size;
609           memcpy(TNEF->subject.data, vl->data, vl->size);
610           //  Unfortunately, we have to normalize out some invalid
611           //  characters, or else the file won't write
612           for (i = 0; i != TNEF->subject.size; i++) {
613             switch (TNEF->subject.data[i]) {
614               case '\\':
615               case '/':
616               case '\0':
617                 TNEF->subject.data[i] = '_';
618                 break;
619             }
620           }
621         }
622         break;
623     }
624 
625     if (count == (mp->count - 1)) {
626       count = -1;
627     }
628     if (count == -1) {
629       mp++;
630     }
631 
632   }
633   if ((d - data) < size) {
634     if (TNEF->Debug >= 1)  {
635       printf("ERROR DURING MAPI READ\n");
636       printf("Read %td bytes, Expected %u bytes\n", (d - data), size);
637       printf("%td bytes missing\n", size - (d - data));
638     }
639     return -1;
640   } else if ((d - data) > size) {
641     if (TNEF->Debug >= 1)  {
642       printf("ERROR DURING MAPI READ\n");
643       printf("Read %td bytes, Expected %u bytes\n", (d - data), size);
644       printf("%li bytes extra\n", (d - data) - size);
645     }
646     return -1;
647   }
648   return 0;
649 }
650 // -----------------------------------------------------------------------------
651 int TNEFSentFor STD_ARGLIST {
652   WORD name_length, addr_length;
653   BYTE *d;
654 
655   d = (BYTE*)data;
656 
657   while ((d - (BYTE*)data) < size) {
658     SIZECHECK(sizeof(WORD));
659     name_length = SwapWord((BYTE*)d, sizeof(WORD));
660     d += sizeof(WORD);
661     SIZECHECK(name_length);
662     if (TNEF->Debug >= 1)
663       printf("Sent For : %.*s", name_length, d);
664     d += name_length;
665 
666     SIZECHECK(sizeof(WORD));
667     addr_length = SwapWord((BYTE*)d, sizeof(WORD));
668     d += sizeof(WORD);
669     SIZECHECK(addr_length);
670     if (TNEF->Debug >= 1)
671       printf("<%.*s>\n", addr_length, d);
672     d += addr_length;
673   }
674   return 0;
675 }
676 // -----------------------------------------------------------------------------
677 int TNEFDateHandler STD_ARGLIST {
678   dtr *Date;
679   Attachment *p;
680   WORD * tmp_src, *tmp_dst;
681   int i;
682 
683   if (size < sizeof(dtr))
684     return -1;
685 
686   p = &(TNEF->starting_attach);
687   switch (TNEFList[id].id) {
688     case attDateSent: Date = &(TNEF->dateSent); break;
689     case attDateRecd: Date = &(TNEF->dateReceived); break;
690     case attDateModified: Date = &(TNEF->dateModified); break;
691     case attDateStart: Date = &(TNEF->DateStart); break;
692     case attDateEnd:  Date = &(TNEF->DateEnd); break;
693     case attAttachCreateDate:
694       while (p->next != NULL) p = p->next;
695       Date = &(p->CreateDate);
696       break;
697     case attAttachModifyDate:
698       while (p->next != NULL) p = p->next;
699       Date = &(p->ModifyDate);
700       break;
701     default:
702       if (TNEF->Debug >= 1)
703         printf("MISSING CASE\n");
704       return YTNEF_UNKNOWN_PROPERTY;
705   }
706 
707   tmp_src = (WORD *)data;
708   tmp_dst = (WORD *)Date;
709   for (i = 0; i < sizeof(dtr) / sizeof(WORD); i++) {
710     *tmp_dst++ = SwapWord((BYTE *)tmp_src++, sizeof(WORD));
711   }
712   return 0;
713 }
714 
TNEFPrintDate(dtr Date)715 void TNEFPrintDate(dtr Date) {
716   char days[7][15] = {"Sunday", "Monday", "Tuesday",
717                       "Wednesday", "Thursday", "Friday", "Saturday"
718                      };
719   char months[12][15] = {"January", "February", "March", "April", "May",
720                          "June", "July", "August", "September", "October", "November",
721                          "December"
722                         };
723 
724   if (Date.wDayOfWeek < 7)
725     printf("%s ", days[Date.wDayOfWeek]);
726 
727   if ((Date.wMonth < 13) && (Date.wMonth > 0))
728     printf("%s ", months[Date.wMonth - 1]);
729 
730   printf("%hu, %hu ", Date.wDay, Date.wYear);
731 
732   if (Date.wHour > 12)
733     printf("%i:%02hu:%02hu pm", (Date.wHour - 12),
734            Date.wMinute, Date.wSecond);
735   else if (Date.wHour == 12)
736     printf("%hu:%02hu:%02hu pm", (Date.wHour),
737            Date.wMinute, Date.wSecond);
738   else
739     printf("%hu:%02hu:%02hu am", Date.wHour,
740            Date.wMinute, Date.wSecond);
741 }
742 // -----------------------------------------------------------------------------
743 int TNEFHexBreakdown STD_ARGLIST {
744   int i;
745   if (TNEF->Debug == 0)
746     return 0;
747 
748   printf("%s: [%i bytes] \n", TNEFList[id].name, size);
749 
750   for (i = 0; i < size; i++) {
751     printf("%02x ", data[i]);
752     if ((i + 1) % 16 == 0) printf("\n");
753   }
754   printf("\n");
755   return 0;
756 }
757 
758 // -----------------------------------------------------------------------------
759 int TNEFDetailedPrint STD_ARGLIST {
760   int i;
761   if (TNEF->Debug == 0)
762     return 0;
763 
764   printf("%s: [%i bytes] \n", TNEFList[id].name, size);
765 
766   for (i = 0; i < size; i++) {
767     printf("%c", data[i]);
768   }
769   printf("\n");
770   return 0;
771 }
772 
773 // -----------------------------------------------------------------------------
774 int TNEFAttachmentFilename STD_ARGLIST {
775   Attachment *p;
776   p = &(TNEF->starting_attach);
777   while (p->next != NULL) p = p->next;
778 
779   p->Title.size = size;
780   PREALLOCCHECK(size, 100);
781   p->Title.data = calloc(size+1, sizeof(BYTE));
782   ALLOCCHECK(p->Title.data);
783   memcpy(p->Title.data, data, size);
784 
785   return 0;
786 }
787 
788 // -----------------------------------------------------------------------------
789 int TNEFAttachmentSave STD_ARGLIST {
790   Attachment *p;
791   p = &(TNEF->starting_attach);
792   while (p->next != NULL) p = p->next;
793 
794   p->FileData.data = calloc(sizeof(char), size);
795   ALLOCCHECK(p->FileData.data);
796   p->FileData.size = size;
797 
798   memcpy(p->FileData.data, data, size);
799 
800   return 0;
801 }
802 
803 // -----------------------------------------------------------------------------
804 int TNEFPriority STD_ARGLIST {
805   DWORD value;
806 
807   value = SwapDWord((BYTE*)data, size);
808   switch (value) {
809     case 3:
810       sprintf((TNEF->priority), "high");
811       break;
812     case 2:
813       sprintf((TNEF->priority), "normal");
814       break;
815     case 1:
816       sprintf((TNEF->priority), "low");
817       break;
818     default:
819       sprintf((TNEF->priority), "N/A");
820       break;
821   }
822   return 0;
823 }
824 
825 // -----------------------------------------------------------------------------
TNEFCheckForSignature(DWORD sig)826 int TNEFCheckForSignature(DWORD sig) {
827   DWORD signature = 0x223E9F78;
828 
829   sig = SwapDWord((BYTE *)&sig, sizeof(DWORD));
830 
831   if (signature == sig) {
832     return 0;
833   } else {
834     return YTNEF_NOT_TNEF_STREAM;
835   }
836 }
837 
838 // -----------------------------------------------------------------------------
TNEFGetKey(TNEFStruct * TNEF,WORD * key)839 int TNEFGetKey(TNEFStruct *TNEF, WORD *key) {
840   if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(WORD), 1, key) < 1) {
841     if (TNEF->Debug >= 1)
842       printf("Error reading Key\n");
843     return YTNEF_ERROR_READING_DATA;
844   }
845   *key = SwapWord((BYTE *)key, sizeof(WORD));
846 
847   DEBUG1(TNEF->Debug, 2, "Key = 0x%X", *key);
848   DEBUG1(TNEF->Debug, 2, "Key = %i", *key);
849   return 0;
850 }
851 
852 // -----------------------------------------------------------------------------
TNEFGetHeader(TNEFStruct * TNEF,DWORD * type,DWORD * size)853 int TNEFGetHeader(TNEFStruct *TNEF, DWORD *type, DWORD *size) {
854   BYTE component;
855 
856   DEBUG(TNEF->Debug, 2, "About to read Component");
857   if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(BYTE), 1, &component) < 1) {
858     return YTNEF_ERROR_READING_DATA;
859   }
860 
861 
862   DEBUG(TNEF->Debug, 2, "About to read type");
863   if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, type)  < 1) {
864     if (TNEF->Debug >= 1)
865       printf("ERROR: Error reading type\n");
866     return YTNEF_ERROR_READING_DATA;
867   }
868   DEBUG1(TNEF->Debug, 2, "Type = 0x%X", *type);
869   DEBUG1(TNEF->Debug, 2, "Type = %u", *type);
870 
871 
872   DEBUG(TNEF->Debug, 2, "About to read size");
873   if (TNEF->IO.ReadProc(&(TNEF->IO), sizeof(DWORD), 1, size) < 1) {
874     if (TNEF->Debug >= 1)
875       printf("ERROR: Error reading size\n");
876     return YTNEF_ERROR_READING_DATA;
877   }
878 
879 
880   DEBUG1(TNEF->Debug, 2, "Size = %u", *size);
881 
882   *type = SwapDWord((BYTE *)type, sizeof(DWORD));
883   *size = SwapDWord((BYTE *)size, sizeof(DWORD));
884 
885   return 0;
886 }
887 
888 // -----------------------------------------------------------------------------
TNEFRawRead(TNEFStruct * TNEF,BYTE * data,DWORD size,WORD * checksum)889 int TNEFRawRead(TNEFStruct *TNEF, BYTE *data, DWORD size, WORD *checksum) {
890   WORD temp;
891   int i;
892 
893   if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(BYTE), size, data) < size) {
894     if (TNEF->Debug >= 1)
895       printf("ERROR: Error reading data\n");
896     return YTNEF_ERROR_READING_DATA;
897   }
898 
899 
900   if (checksum != NULL) {
901     *checksum = 0;
902     for (i = 0; i < size; i++) {
903       temp = data[i];
904       *checksum = (*checksum + temp);
905     }
906   }
907   return 0;
908 }
909 
910 #define INITVARLENGTH(x) (x).data = NULL; (x).size = 0;
911 #define INITDTR(x) (x).wYear=0; (x).wMonth=0; (x).wDay=0; \
912                    (x).wHour=0; (x).wMinute=0; (x).wSecond=0; \
913                    (x).wDayOfWeek=0;
914 #define INITSTR(x) memset((x), 0, sizeof(x));
TNEFInitMapi(MAPIProps * p)915 void TNEFInitMapi(MAPIProps *p) {
916   p->count = 0;
917   p->properties = NULL;
918 }
919 
TNEFInitAttachment(Attachment * p)920 void TNEFInitAttachment(Attachment *p) {
921   INITDTR(p->Date);
922   INITVARLENGTH(p->Title);
923   INITVARLENGTH(p->MetaFile);
924   INITDTR(p->CreateDate);
925   INITDTR(p->ModifyDate);
926   INITVARLENGTH(p->TransportFilename);
927   INITVARLENGTH(p->FileData);
928   INITVARLENGTH(p->IconData);
929   memset(&(p->RenderData), 0, sizeof(renddata));
930   TNEFInitMapi(&(p->MAPI));
931   p->next = NULL;
932 }
933 
TNEFInitialize(TNEFStruct * TNEF)934 void TNEFInitialize(TNEFStruct *TNEF) {
935   INITSTR(TNEF->version);
936   INITVARLENGTH(TNEF->from);
937   INITVARLENGTH(TNEF->subject);
938   INITDTR(TNEF->dateSent);
939   INITDTR(TNEF->dateReceived);
940 
941   INITSTR(TNEF->messageStatus);
942   INITSTR(TNEF->messageClass);
943   INITSTR(TNEF->messageID);
944   INITSTR(TNEF->parentID);
945   INITSTR(TNEF->conversationID);
946   INITVARLENGTH(TNEF->body);
947   INITSTR(TNEF->priority);
948   TNEFInitAttachment(&(TNEF->starting_attach));
949   INITDTR(TNEF->dateModified);
950   TNEFInitMapi(&(TNEF->MapiProperties));
951   INITVARLENGTH(TNEF->CodePage);
952   INITVARLENGTH(TNEF->OriginalMessageClass);
953   INITVARLENGTH(TNEF->Owner);
954   INITVARLENGTH(TNEF->SentFor);
955   INITVARLENGTH(TNEF->Delegate);
956   INITDTR(TNEF->DateStart);
957   INITDTR(TNEF->DateEnd);
958   INITVARLENGTH(TNEF->AidOwner);
959   TNEF->RequestRes = 0;
960   TNEF->IO.data = NULL;
961   TNEF->IO.InitProc = NULL;
962   TNEF->IO.ReadProc = NULL;
963   TNEF->IO.CloseProc = NULL;
964 }
965 #undef INITVARLENGTH
966 #undef INITDTR
967 #undef INITSTR
968 
969 #define FREEVARLENGTH(x) if ((x).size > 0) { \
970                             free((x).data); (x).size =0; }
TNEFFree(TNEFStruct * TNEF)971 void TNEFFree(TNEFStruct *TNEF) {
972   Attachment *p, *store;
973 
974   FREEVARLENGTH(TNEF->from);
975   FREEVARLENGTH(TNEF->subject);
976   FREEVARLENGTH(TNEF->body);
977   FREEVARLENGTH(TNEF->CodePage);
978   FREEVARLENGTH(TNEF->OriginalMessageClass);
979   FREEVARLENGTH(TNEF->Owner);
980   FREEVARLENGTH(TNEF->SentFor);
981   FREEVARLENGTH(TNEF->Delegate);
982   FREEVARLENGTH(TNEF->AidOwner);
983   TNEFFreeMapiProps(&(TNEF->MapiProperties));
984 
985   p = TNEF->starting_attach.next;
986   while (p != NULL) {
987     TNEFFreeAttachment(p);
988     store = p->next;
989     free(p);
990     p = store;
991   }
992 }
993 
TNEFFreeAttachment(Attachment * p)994 void TNEFFreeAttachment(Attachment *p) {
995   FREEVARLENGTH(p->Title);
996   FREEVARLENGTH(p->MetaFile);
997   FREEVARLENGTH(p->TransportFilename);
998   FREEVARLENGTH(p->FileData);
999   FREEVARLENGTH(p->IconData);
1000   TNEFFreeMapiProps(&(p->MAPI));
1001 }
1002 
TNEFFreeMapiProps(MAPIProps * p)1003 void TNEFFreeMapiProps(MAPIProps *p) {
1004   int i, j;
1005   for (i = 0; i < p->count; i++) {
1006     for (j = 0; j < p->properties[i].count; j++) {
1007       FREEVARLENGTH(p->properties[i].data[j]);
1008     }
1009     free(p->properties[i].data);
1010     for (j = 0; j < p->properties[i].namedproperty; j++) {
1011       FREEVARLENGTH(p->properties[i].propnames[j]);
1012     }
1013     free(p->properties[i].propnames);
1014   }
1015   free(p->properties);
1016   p->count = 0;
1017 }
1018 #undef FREEVARLENGTH
1019 
1020 // Procedures to handle File IO
TNEFFile_Open(TNEFIOStruct * IO)1021 int TNEFFile_Open(TNEFIOStruct *IO) {
1022   TNEFFileInfo *finfo;
1023   finfo = (TNEFFileInfo *)IO->data;
1024 
1025   DEBUG1(finfo->Debug, 3, "Opening %s", finfo->filename);
1026   if ((finfo->fptr = fopen(finfo->filename, "rb")) == NULL) {
1027     return -1;
1028   } else {
1029     return 0;
1030   }
1031 }
1032 
TNEFFile_Read(TNEFIOStruct * IO,int size,int count,void * dest)1033 int TNEFFile_Read(TNEFIOStruct *IO, int size, int count, void *dest) {
1034   TNEFFileInfo *finfo;
1035   finfo = (TNEFFileInfo *)IO->data;
1036 
1037   DEBUG2(finfo->Debug, 3, "Reading %i blocks of %i size", count, size);
1038   if (finfo->fptr != NULL) {
1039     return fread((BYTE *)dest, size, count, finfo->fptr);
1040   } else {
1041     return -1;
1042   }
1043 }
1044 
TNEFFile_Close(TNEFIOStruct * IO)1045 int TNEFFile_Close(TNEFIOStruct *IO) {
1046   TNEFFileInfo *finfo;
1047   finfo = (TNEFFileInfo *)IO->data;
1048 
1049   DEBUG1(finfo->Debug, 3, "Closing file %s", finfo->filename);
1050   if (finfo->fptr != NULL) {
1051     fclose(finfo->fptr);
1052     finfo->fptr = NULL;
1053   }
1054   return 0;
1055 }
1056 
TNEFParseFile(char * filename,TNEFStruct * TNEF)1057 int TNEFParseFile(char *filename, TNEFStruct *TNEF) {
1058   TNEFFileInfo finfo;
1059 
1060   if (TNEF->Debug >= 1)
1061     printf("Attempting to parse %s...\n", filename);
1062 
1063 
1064   finfo.filename = filename;
1065   finfo.fptr = NULL;
1066   finfo.Debug = TNEF->Debug;
1067   TNEF->IO.data = (void *)&finfo;
1068   TNEF->IO.InitProc = TNEFFile_Open;
1069   TNEF->IO.ReadProc = TNEFFile_Read;
1070   TNEF->IO.CloseProc = TNEFFile_Close;
1071   return TNEFParse(TNEF);
1072 }
1073 //-------------------------------------------------------------
1074 // Procedures to handle Memory IO
TNEFMemory_Open(TNEFIOStruct * IO)1075 int TNEFMemory_Open(TNEFIOStruct *IO) {
1076   TNEFMemInfo *minfo;
1077   minfo = (TNEFMemInfo *)IO->data;
1078 
1079   minfo->ptr = minfo->dataStart;
1080   return 0;
1081 }
1082 
TNEFMemory_Read(TNEFIOStruct * IO,int size,int count,void * dest)1083 int TNEFMemory_Read(TNEFIOStruct *IO, int size, int count, void *dest) {
1084   TNEFMemInfo *minfo;
1085   int length;
1086   long max;
1087   minfo = (TNEFMemInfo *)IO->data;
1088 
1089   length = count * size;
1090   max = (minfo->dataStart + minfo->size) - (minfo->ptr);
1091   if (length > max) {
1092     return -1;
1093   }
1094 
1095   DEBUG1(minfo->Debug, 3, "Copying %i bytes", length);
1096 
1097   memcpy(dest, minfo->ptr, length);
1098   minfo->ptr += length;
1099   return count;
1100 }
1101 
TNEFMemory_Close(TNEFIOStruct * IO)1102 int TNEFMemory_Close(TNEFIOStruct *IO) {
1103   // Do nothing, really...
1104   return 0;
1105 }
1106 
TNEFParseMemory(BYTE * memory,long size,TNEFStruct * TNEF)1107 int TNEFParseMemory(BYTE *memory, long size, TNEFStruct *TNEF) {
1108   TNEFMemInfo minfo;
1109 
1110   DEBUG(TNEF->Debug, 1, "Attempting to parse memory block...\n");
1111 
1112   minfo.dataStart = memory;
1113   minfo.ptr = memory;
1114   minfo.size = size;
1115   minfo.Debug = TNEF->Debug;
1116   TNEF->IO.data = (void *)&minfo;
1117   TNEF->IO.InitProc = TNEFMemory_Open;
1118   TNEF->IO.ReadProc = TNEFMemory_Read;
1119   TNEF->IO.CloseProc = TNEFMemory_Close;
1120   return TNEFParse(TNEF);
1121 }
1122 
1123 
TNEFParse(TNEFStruct * TNEF)1124 int TNEFParse(TNEFStruct *TNEF) {
1125   WORD key;
1126   DWORD type;
1127   DWORD size;
1128   DWORD signature;
1129   BYTE *data;
1130   WORD checksum, header_checksum;
1131   int i;
1132 
1133   if (TNEF->IO.ReadProc == NULL) {
1134     printf("ERROR: Setup incorrectly: No ReadProc\n");
1135     return YTNEF_INCORRECT_SETUP;
1136   }
1137 
1138   if (TNEF->IO.InitProc != NULL) {
1139     DEBUG(TNEF->Debug, 2, "About to initialize");
1140     if (TNEF->IO.InitProc(&TNEF->IO) != 0) {
1141       return YTNEF_CANNOT_INIT_DATA;
1142     }
1143     DEBUG(TNEF->Debug, 2, "Initialization finished");
1144   }
1145 
1146   DEBUG(TNEF->Debug, 2, "Reading Signature");
1147   if (TNEF->IO.ReadProc(&TNEF->IO, sizeof(DWORD), 1, &signature) < 1) {
1148     printf("ERROR: Error reading signature\n");
1149     if (TNEF->IO.CloseProc != NULL) {
1150       TNEF->IO.CloseProc(&TNEF->IO);
1151     }
1152     return YTNEF_ERROR_READING_DATA;
1153   }
1154 
1155   DEBUG(TNEF->Debug, 2, "Checking Signature");
1156   if (TNEFCheckForSignature(signature) < 0) {
1157     printf("ERROR: Signature does not match. Not TNEF.\n");
1158     if (TNEF->IO.CloseProc != NULL) {
1159       TNEF->IO.CloseProc(&TNEF->IO);
1160     }
1161     return YTNEF_NOT_TNEF_STREAM;
1162   }
1163 
1164   DEBUG(TNEF->Debug, 2, "Reading Key.");
1165 
1166   if (TNEFGetKey(TNEF, &key) < 0) {
1167     printf("ERROR: Unable to retrieve key.\n");
1168     if (TNEF->IO.CloseProc != NULL) {
1169       TNEF->IO.CloseProc(&TNEF->IO);
1170     }
1171     return YTNEF_NO_KEY;
1172   }
1173 
1174   DEBUG(TNEF->Debug, 2, "Starting Full Processing.");
1175 
1176   while (TNEFGetHeader(TNEF, &type, &size) == 0) {
1177     DEBUG2(TNEF->Debug, 2, "Header says type=0x%X, size=%u", type, size);
1178     DEBUG2(TNEF->Debug, 2, "Header says type=%u, size=%u", type, size);
1179     if(size == 0) {
1180       printf("ERROR: Field with size of 0\n");
1181       return YTNEF_ERROR_READING_DATA;
1182     }
1183     PREALLOCCHECK(size, 100000);
1184     data = calloc(size, sizeof(BYTE));
1185     ALLOCCHECK(data);
1186     if (TNEFRawRead(TNEF, data, size, &header_checksum) < 0) {
1187       printf("ERROR: Unable to read data.\n");
1188       if (TNEF->IO.CloseProc != NULL) {
1189         TNEF->IO.CloseProc(&TNEF->IO);
1190       }
1191       free(data);
1192       return YTNEF_ERROR_READING_DATA;
1193     }
1194     if (TNEFRawRead(TNEF, (BYTE *)&checksum, 2, NULL) < 0) {
1195       printf("ERROR: Unable to read checksum.\n");
1196       if (TNEF->IO.CloseProc != NULL) {
1197         TNEF->IO.CloseProc(&TNEF->IO);
1198       }
1199       free(data);
1200       return YTNEF_ERROR_READING_DATA;
1201     }
1202     checksum = SwapWord((BYTE *)&checksum, sizeof(WORD));
1203     if (checksum != header_checksum) {
1204       printf("ERROR: Checksum mismatch. Data corruption?:\n");
1205       if (TNEF->IO.CloseProc != NULL) {
1206         TNEF->IO.CloseProc(&TNEF->IO);
1207       }
1208       free(data);
1209       return YTNEF_BAD_CHECKSUM;
1210     }
1211     for (i = 0; i < (sizeof(TNEFList) / sizeof(TNEFHandler)); i++) {
1212       if (TNEFList[i].id == type) {
1213         if (TNEFList[i].handler != NULL) {
1214           if (TNEFList[i].handler(TNEF, i, (char*)data, size) < 0) {
1215             free(data);
1216             if (TNEF->IO.CloseProc != NULL) {
1217               TNEF->IO.CloseProc(&TNEF->IO);
1218             }
1219             return YTNEF_ERROR_IN_HANDLER;
1220           } else {
1221             //  Found our handler and processed it.  now time to get out
1222             break;
1223           }
1224         } else {
1225           DEBUG2(TNEF->Debug, 1, "No handler for %s: %u bytes",
1226                  TNEFList[i].name, size);
1227         }
1228       }
1229     }
1230 
1231     free(data);
1232   }
1233 
1234   if (TNEF->IO.CloseProc != NULL) {
1235     TNEF->IO.CloseProc(&TNEF->IO);
1236   }
1237   return 0;
1238 
1239 }
1240 
1241 // ----------------------------------------------------------------------------
1242 
MAPIFindUserProp(MAPIProps * p,unsigned int ID)1243 variableLength *MAPIFindUserProp(MAPIProps *p, unsigned int ID) {
1244   int i;
1245   if (p != NULL) {
1246     for (i = 0; i < p->count; i++) {
1247       if ((p->properties[i].id == ID) && (p->properties[i].custom == 1)) {
1248         return (p->properties[i].data);
1249       }
1250     }
1251   }
1252   return MAPI_UNDEFINED;
1253 }
1254 
MAPIFindProperty(MAPIProps * p,unsigned int ID)1255 variableLength *MAPIFindProperty(MAPIProps *p, unsigned int ID) {
1256   int i;
1257   if (p != NULL) {
1258     for (i = 0; i < p->count; i++) {
1259       if ((p->properties[i].id == ID) && (p->properties[i].custom == 0)) {
1260         return (p->properties[i].data);
1261       }
1262     }
1263   }
1264   return MAPI_UNDEFINED;
1265 }
1266 
MAPISysTimetoDTR(BYTE * data,dtr * thedate)1267 int MAPISysTimetoDTR(BYTE *data, dtr *thedate) {
1268   DDWORD ddword_tmp;
1269   int startingdate = 0;
1270   int tmp_date;
1271   int days_in_year = 365;
1272   unsigned int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1273 
1274   ddword_tmp = *((DDWORD *)data);
1275   ddword_tmp = ddword_tmp / 10; // micro-s
1276   ddword_tmp /= 1000; // ms
1277   ddword_tmp /= 1000; // s
1278 
1279   thedate->wSecond = (ddword_tmp % 60);
1280 
1281   ddword_tmp /= 60; // seconds to minutes
1282   thedate->wMinute = (ddword_tmp % 60);
1283 
1284   ddword_tmp /= 60; //minutes to hours
1285   thedate->wHour = (ddword_tmp % 24);
1286 
1287   ddword_tmp /= 24; // Hours to days
1288 
1289   // Now calculate the year based on # of days
1290   thedate->wYear = 1601;
1291   startingdate = 1;
1292   while (ddword_tmp >= days_in_year) {
1293     ddword_tmp -= days_in_year;
1294     thedate->wYear++;
1295     days_in_year = 365;
1296     startingdate++;
1297     if ((thedate->wYear % 4) == 0) {
1298       if ((thedate->wYear % 100) == 0) {
1299         // if the year is 1700,1800,1900, etc, then it is only
1300         // a leap year if exactly divisible by 400, not 4.
1301         if ((thedate->wYear % 400) == 0) {
1302           startingdate++;
1303           days_in_year = 366;
1304         }
1305       }  else {
1306         startingdate++;
1307         days_in_year = 366;
1308       }
1309     }
1310     startingdate %= 7;
1311   }
1312 
1313   // the remaining number is the day # in this year
1314   // So now calculate the Month, & Day of month
1315   if ((thedate->wYear % 4) == 0) {
1316     // 29 days in february in a leap year
1317     months[1] = 29;
1318   }
1319 
1320   tmp_date = (int)ddword_tmp;
1321   thedate->wDayOfWeek = (tmp_date + startingdate) % 7;
1322   thedate->wMonth = 0;
1323 
1324   while (tmp_date > months[thedate->wMonth]) {
1325     tmp_date -= months[thedate->wMonth];
1326     thedate->wMonth++;
1327   }
1328   thedate->wMonth++;
1329   thedate->wDay = tmp_date + 1;
1330   return 0;
1331 }
1332 
MAPIPrint(MAPIProps * p)1333 void MAPIPrint(MAPIProps *p) {
1334   int j, i, index, h, x;
1335   DDWORD *ddword_ptr;
1336   DDWORD ddword_tmp;
1337   dtr thedate;
1338   MAPIProperty *mapi;
1339   variableLength *mapidata;
1340   variableLength vlTemp;
1341   int found;
1342 
1343   for (j = 0; j < p->count; j++) {
1344     mapi = &(p->properties[j]);
1345     printf("   #%i: Type: [", j);
1346     switch (PROP_TYPE(mapi->id)) {
1347       case PT_UNSPECIFIED:
1348         printf("  NONE   "); break;
1349       case PT_NULL:
1350         printf("  NULL   "); break;
1351       case PT_I2:
1352         printf("   I2    "); break;
1353       case PT_LONG:
1354         printf("  LONG   "); break;
1355       case PT_R4:
1356         printf("   R4    "); break;
1357       case PT_DOUBLE:
1358         printf(" DOUBLE  "); break;
1359       case PT_CURRENCY:
1360         printf("CURRENCY "); break;
1361       case PT_APPTIME:
1362         printf("APP TIME "); break;
1363       case PT_ERROR:
1364         printf("  ERROR  "); break;
1365       case PT_BOOLEAN:
1366         printf(" BOOLEAN "); break;
1367       case PT_OBJECT:
1368         printf(" OBJECT  "); break;
1369       case PT_I8:
1370         printf("   I8    "); break;
1371       case PT_STRING8:
1372         printf(" STRING8 "); break;
1373       case PT_UNICODE:
1374         printf(" UNICODE "); break;
1375       case PT_SYSTIME:
1376         printf("SYS TIME "); break;
1377       case PT_CLSID:
1378         printf("OLE GUID "); break;
1379       case PT_BINARY:
1380         printf(" BINARY  "); break;
1381       default:
1382         printf("<%x>", PROP_TYPE(mapi->id)); break;
1383     }
1384 
1385     printf("]  Code: [");
1386     if (mapi->custom == 1) {
1387       printf("UD:x%04x", PROP_ID(mapi->id));
1388     } else {
1389       found = 0;
1390       for (index = 0; index < sizeof(MPList) / sizeof(MAPIPropertyTagList); index++) {
1391         if ((MPList[index].id == PROP_ID(mapi->id)) && (found == 0)) {
1392           printf("%s", MPList[index].name);
1393           found = 1;
1394         }
1395       }
1396       if (found == 0) {
1397         printf("0x%04x", PROP_ID(mapi->id));
1398       }
1399     }
1400     printf("]\n");
1401     if (mapi->namedproperty > 0) {
1402       for (i = 0; i < mapi->namedproperty; i++) {
1403         printf("    Name: %s\n", mapi->propnames[i].data);
1404       }
1405     }
1406     for (i = 0; i < mapi->count; i++) {
1407       mapidata = &(mapi->data[i]);
1408       if (mapi->count > 1) {
1409         printf("    [%i/%u] ", i, mapi->count);
1410       } else {
1411         printf("    ");
1412       }
1413       printf("Size: %i", mapidata->size);
1414       switch (PROP_TYPE(mapi->id)) {
1415         case PT_SYSTIME:
1416           MAPISysTimetoDTR(mapidata->data, &thedate);
1417           printf("    Value: ");
1418           ddword_tmp = *((DDWORD *)mapidata->data);
1419           TNEFPrintDate(thedate);
1420           printf(" [HEX: ");
1421           for (x = 0; x < sizeof(ddword_tmp); x++) {
1422             printf(" %02x", (BYTE)mapidata->data[x]);
1423           }
1424           printf("] (%llu)\n", ddword_tmp);
1425           break;
1426         case PT_LONG:
1427           printf("    Value: %i\n", *((int*)mapidata->data));
1428           break;
1429         case PT_I2:
1430           printf("    Value: %hi\n", *((short int*)mapidata->data));
1431           break;
1432         case PT_BOOLEAN:
1433           if (mapi->data->data[0] != 0) {
1434             printf("    Value: True\n");
1435           } else {
1436             printf("    Value: False\n");
1437           }
1438           break;
1439         case PT_OBJECT:
1440           printf("\n");
1441           break;
1442         case PT_BINARY:
1443           if (IsCompressedRTF(mapidata) == 1) {
1444             printf("    Detected Compressed RTF. ");
1445             printf("Decompressed text follows\n");
1446             printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1447             if ((vlTemp.data = (BYTE*)DecompressRTF(mapidata, &(vlTemp.size))) != NULL) {
1448               printf("%s\n", vlTemp.data);
1449               free(vlTemp.data);
1450             }
1451             printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
1452           } else {
1453             printf("    Value: [");
1454             for (h = 0; h < mapidata->size; h++) {
1455               if (isprint(mapidata->data[h])) {
1456                 printf("%c", mapidata->data[h]);
1457               } else {
1458                 printf(".");
1459               }
1460 
1461             }
1462             printf("]\n");
1463           }
1464           break;
1465         case PT_STRING8:
1466           printf("    Value: [%.*s]\n", mapidata->size, mapidata->data);
1467           if (strlen((char*)mapidata->data) != mapidata->size - 1) {
1468             printf("Detected Hidden data: [");
1469             for (h = 0; h < mapidata->size; h++) {
1470               if (isprint(mapidata->data[h])) {
1471                 printf("%c", mapidata->data[h]);
1472               } else {
1473                 printf(".");
1474               }
1475 
1476             }
1477             printf("]\n");
1478           }
1479           break;
1480         case PT_CLSID:
1481           printf("    Value: ");
1482           printf("[HEX: ");
1483           for(x=0; x< 16; x++) {
1484             printf(" %02x", (BYTE)mapidata->data[x]);
1485           }
1486           printf("]\n");
1487           break;
1488         default:
1489           printf("    Value: [%.*s]\n", mapidata->size, mapidata->data);
1490       }
1491     }
1492   }
1493 }
1494 
1495 
IsCompressedRTF(variableLength * p)1496 int IsCompressedRTF(variableLength *p) {
1497   BYTE *src;
1498   ULONG magic;
1499 
1500   if (p->size < 3*sizeof(DWORD))
1501     return 0;
1502 
1503   src = p->data;
1504   magic = SwapDWord((BYTE*)src + 2*sizeof(DWORD), sizeof(DWORD));
1505 
1506   if (magic == 0x414c454d || magic == 0x75465a4c) {
1507     return 1;
1508   } else {
1509     return 0;
1510   }
1511 }
1512 
DecompressRTF(variableLength * p,int * size)1513 BYTE *DecompressRTF(variableLength *p, int *size) {
1514   BYTE *dst; // destination for uncompressed bytes
1515   BYTE *src;
1516   unsigned int in;
1517   unsigned int out;
1518   variableLength comp_Prebuf;
1519   ULONG compressedSize, uncompressedSize, magic;
1520 
1521   comp_Prebuf.size = strlen(RTF_PREBUF);
1522   comp_Prebuf.data = calloc(comp_Prebuf.size+1, 1);
1523   ALLOCCHECK_CHAR(comp_Prebuf.data);
1524   memcpy(comp_Prebuf.data, RTF_PREBUF, comp_Prebuf.size);
1525 
1526   src = p->data;
1527   in = 0;
1528 
1529   if (p->size < 20) {
1530     printf("File too small\n");
1531     return(NULL);
1532   }
1533   compressedSize = (ULONG)SwapDWord((BYTE*)src + in, sizeof(DWORD));
1534   in += sizeof(DWORD);
1535   uncompressedSize = (ULONG)SwapDWord((BYTE*)src + in, sizeof(DWORD));
1536   in += sizeof(DWORD);
1537   magic = SwapDWord((BYTE*)src + in, sizeof(DWORD));
1538   in += 2*sizeof(DWORD);
1539 
1540   // check size excluding the size field itself
1541   if (compressedSize != p->size - 4) {
1542     printf(" Size Mismatch: %u != %i\n", compressedSize, p->size - 4);
1543     free(comp_Prebuf.data);
1544     return NULL;
1545   }
1546 
1547   // process the data
1548   if (magic == 0x414c454d) {
1549     // magic number that identifies the stream as a uncompressed stream
1550     dst = calloc(uncompressedSize, 1);
1551     ALLOCCHECK_CHAR(dst);
1552     memcpy(dst, src + 4, uncompressedSize);
1553   } else if (magic == 0x75465a4c) {
1554     // magic number that identifies the stream as a compressed stream
1555     int flagCount = 0;
1556     int flags = 0;
1557     // Prevent overflow on 32 Bit Systems
1558     if (comp_Prebuf.size >= INT_MAX - uncompressedSize) {
1559        printf("Corrupted file\n");
1560        return NULL;
1561     }
1562     dst = calloc(comp_Prebuf.size + uncompressedSize, 1);
1563     ALLOCCHECK_CHAR(dst);
1564     memcpy(dst, comp_Prebuf.data, comp_Prebuf.size);
1565     out = comp_Prebuf.size;
1566     while ((out < (comp_Prebuf.size + uncompressedSize)) && (in < p->size)) {
1567       // each flag byte flags 8 literals/references, 1 per bit
1568       flags = (flagCount++ % 8 == 0) ? src[in++] : flags >> 1;
1569       if ((flags & 1) == 1) { // each flag bit is 1 for reference, 0 for literal
1570         unsigned int offset = src[in++];
1571         unsigned int length = src[in++];
1572         unsigned int end;
1573         offset = (offset << 4) | (length >> 4); // the offset relative to block start
1574         length = (length & 0xF) + 2; // the number of bytes to copy
1575         // the decompression buffer is supposed to wrap around back
1576         // to the beginning when the end is reached. we save the
1577         // need for such a buffer by pointing straight into the data
1578         // buffer, and simulating this behaviour by modifying the
1579         // pointers appropriately.
1580         offset = (out / 4096) * 4096 + offset;
1581         if (offset >= out) // take from previous block
1582           offset -= 4096;
1583         // note: can't use System.arraycopy, because the referenced
1584         // bytes can cross through the current out position.
1585         end = offset + length;
1586         while ((offset < end) && (out < (comp_Prebuf.size + uncompressedSize))
1587              && (offset < (comp_Prebuf.size + uncompressedSize)))
1588           dst[out++] = dst[offset++];
1589       } else { // literal
1590         if ((out >= (comp_Prebuf.size + uncompressedSize)) ||
1591             (in >= p->size)) {
1592           printf("Corrupted stream\n");
1593           return NULL;
1594         }
1595         dst[out++] = src[in++];
1596       }
1597     }
1598     // copy it back without the prebuffered data
1599     src = dst;
1600     dst = calloc(uncompressedSize, 1);
1601     ALLOCCHECK_CHAR(dst);
1602     memcpy(dst, src + comp_Prebuf.size, uncompressedSize);
1603     free(src);
1604     *size = uncompressedSize;
1605     free(comp_Prebuf.data);
1606     return dst;
1607   } else { // unknown magic number
1608     printf("Unknown compression type (magic number %x)\n", magic);
1609   }
1610   free(comp_Prebuf.data);
1611   return NULL;
1612 }
1613