1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6 
7 #include "logger.h"
8 #include "pldstr.h"
9 #include "bytedecoders.h"
10 #include "olestream-unwrap.h"
11 #include "localization.h"
12 #include "sci_malloc.h"
13 #include "charEncoding.h"
14 #include "os_string.h"
15 
16 
17 #define DUW if (oleuw->debug)
18 
19 struct OLE10_header
20 {
21     unsigned char data[6];
22     char *attach_name;
23     unsigned char data2[8];
24     char *fname_1;
25     char *fname_2;
26     size_t attach_size;
27     size_t attach_size_1;
28     size_t attach_start_offset;
29 };
30 
31 
32 /*-----------------------------------------------------------------\
33  Function Name	: OLEUNWRAP_init
34  Returns Type	: int
35  	----Parameter List
36 	1. struct OLEUNWRAP_object *oleuw ,
37  	------------------
38  Exit Codes	:
39  Side Effects	:
40 --------------------------------------------------------------------
41  Comments:
42 
43 --------------------------------------------------------------------
44  Changes:
45 
46 \------------------------------------------------------------------*/
OLEUNWRAP_init(struct OLEUNWRAP_object * oleuw)47 int OLEUNWRAP_init( struct OLEUNWRAP_object *oleuw )
48 {
49     oleuw->debug = 0;
50     oleuw->verbose = 0;
51     oleuw->filename_report_fn = NULL;
52 
53     return OLEUW_OK;
54 }
55 
56 /*-----------------------------------------------------------------\
57  Function Name	: OLEUNWRAP_set_debug
58  Returns Type	: int
59  	----Parameter List
60 	1. struct OLEUNWRAP_object *oleuw,
61 	2.  int level ,
62  	------------------
63  Exit Codes	:
64  Side Effects	:
65 --------------------------------------------------------------------
66  Comments:
67 
68 --------------------------------------------------------------------
69  Changes:
70 
71 \------------------------------------------------------------------*/
OLEUNWRAP_set_debug(struct OLEUNWRAP_object * oleuw,int level)72 int OLEUNWRAP_set_debug( struct OLEUNWRAP_object *oleuw, int level )
73 {
74     oleuw->debug = level;
75     return OLEUW_OK;
76 }
77 
78 /*-----------------------------------------------------------------\
79  Function Name	: OLEUNWRAP_set_verbose
80  Returns Type	: int
81  	----Parameter List
82 	1. struct OLEUNWRAP_object *oleuw,
83 	2.  int level ,
84  	------------------
85  Exit Codes	:
86  Side Effects	:
87 --------------------------------------------------------------------
88  Comments:
89 
90 --------------------------------------------------------------------
91  Changes:
92 
93 \------------------------------------------------------------------*/
OLEUNWRAP_set_verbose(struct OLEUNWRAP_object * oleuw,int level)94 int OLEUNWRAP_set_verbose( struct OLEUNWRAP_object *oleuw, int level )
95 {
96     oleuw->verbose = level;
97     return OLEUW_OK;
98 }
99 
100 /*-----------------------------------------------------------------\
101  Function Name	: OLEUNWRAP_set_save_unknown_streams
102  Returns Type	: int
103  	----Parameter List
104 	1. struct OLEUNWRAP_object *oleuw,
105 	2.  int level ,
106  	------------------
107  Exit Codes	:
108  Side Effects	:
109 --------------------------------------------------------------------
110  Comments:
111 
112 --------------------------------------------------------------------
113  Changes:
114 
115 \------------------------------------------------------------------*/
OLEUNWRAP_set_save_unknown_streams(struct OLEUNWRAP_object * oleuw,int level)116 int OLEUNWRAP_set_save_unknown_streams( struct OLEUNWRAP_object *oleuw, int level )
117 {
118     oleuw->save_unknown_streams = level;
119     return OLEUW_OK;
120 }
121 
122 
123 /*-----------------------------------------------------------------\
124  Function Name	: OLEUNWRAP_save_stream
125  Returns Type	: int
126  	----Parameter List
127 	1. char *fname,
128 	2.  char *stream,
129 	3.  size_t bytes ,
130  	------------------
131  Exit Codes	:
132  Side Effects	:
133 --------------------------------------------------------------------
134  Comments:
135 
136 --------------------------------------------------------------------
137  Changes:
138 
139 \------------------------------------------------------------------*/
OLEUNWRAP_save_stream(struct OLEUNWRAP_object * oleuw,char * fname,char * decode_path,char * stream,size_t bytes)140 int OLEUNWRAP_save_stream( struct OLEUNWRAP_object *oleuw, char *fname, char *decode_path, char *stream, size_t bytes )
141 {
142     char *full_name;
143     FILE *f;
144     int result = 0;
145 
146     DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: fname=%s, decodepath=%s, size=%ld"
147                    , FL
148                    , fname
149                    , decode_path
150                    , bytes
151                   );
152 
153     full_name = PLD_dprintf("%s/%s", decode_path, fname );
154     if (full_name == NULL)
155     {
156         LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to create filename string from '%s' and '%s'"), FL, fname, decode_path);
157         return -1;
158     }
159 
160     wcfopen(f, full_name, "wb");
161     if (f != NULL)
162     {
163         size_t write_count;
164 
165         write_count = fwrite( stream, 1, bytes, f );
166         if (write_count != bytes)
167         {
168             LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:WARNING: Only wrote %d of %d bytes to file %s\n"), FL, write_count, bytes, full_name );
169         }
170 
171         fclose(f);
172 
173 
174     }
175     else
176     {
177         LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to open %s for writing (%s)\n"), FL, full_name, strerror(errno));
178         result = -1;
179     }
180 
181     if (full_name)
182     {
183         FREE(full_name);
184     }
185 
186     DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: Done saving '%s'", FL, fname);
187 
188     return result;
189 }
190 
191 /*-----------------------------------------------------------------\
192  Function Name	: OLEUNWRAP_sanitize_filename
193  Returns Type	: int
194  	----Parameter List
195 	1. char *fname ,
196  	------------------
197  Exit Codes	:
198  Side Effects	:
199 --------------------------------------------------------------------
200  Comments:
201 
202 --------------------------------------------------------------------
203  Changes:
204 
205 \------------------------------------------------------------------*/
OLEUNWRAP_sanitize_filename(char * fname)206 int OLEUNWRAP_sanitize_filename( char *fname )
207 {
208     while (*fname)
209     {
210         if ( !isalnum((int)*fname) && (*fname != '.') )
211         {
212             *fname = '_';
213         }
214         if ( (*fname < ' ') || (*fname > '~') )
215         {
216             *fname = '_';
217         }
218         fname++;
219     }
220     return 0;
221 }
222 
223 /*-----------------------------------------------------------------\
224  Function Name	: OLEUNWRAP_decode_attachment
225  Returns Type	: int
226  	----Parameter List
227 	1. char *stream ,
228  	------------------
229  Exit Codes	:
230  Side Effects	:
231 --------------------------------------------------------------------
232  Comments:
233 
234 --------------------------------------------------------------------
235  Changes:
236 
237 \------------------------------------------------------------------*/
OLEUNWRAP_decode_attachment(struct OLEUNWRAP_object * oleuw,char * stream,size_t stream_size,char * decode_path)238 int OLEUNWRAP_decode_attachment( struct OLEUNWRAP_object *oleuw, char *stream, size_t stream_size, char *decode_path )
239 {
240     struct OLE10_header oh;
241     char *sp = stream;
242     char *data_start_point = stream;
243     int result = OLEUW_OK;
244 
245     /* Get the data size*/
246     oh.attach_size_1 = (size_t)get_4byte_value( (unsigned char *) sp );
247     sp += 4;
248 
249     DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: attachsize = %d, stream length = %d\n", FL, oh.attach_size_1, stream_size );
250 
251     oh.attach_start_offset = (stream_size - oh.attach_size_1);
252     data_start_point = stream + oh.attach_start_offset;
253 
254     /*if (oh.attach_start_offset == 4)*/
255     if (oh.attach_start_offset < 4)
256     {
257         /* If we only had the stream byte-length in our header*/
258         /*		then we know we don't have a complex header.*/
259         oh.attach_name = PLD_dprintf("unknown-%ld", oh.attach_size_1);
260         oh.attach_size = oh.attach_size_1;
261     }
262     else
263     {
264 
265         DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Decoding file information header", FL);
266         /* Unknown memory segment*/
267         memcpy( oh.data, sp, 2 );
268         sp += 2;
269 
270         /* Full attachment string*/
271         oh.attach_name = os_strdup( sp );
272         sp = sp + strlen(oh.attach_name) + 1;
273 
274         /* Attachment full path*/
275         oh.fname_1 = os_strdup( sp );
276         sp += strlen(oh.fname_1) + 1;
277 
278         /* Unknown memory segment*/
279         memcpy( oh.data2, sp, 8 );
280         sp = sp + 8;
281 
282         /* Attachment full path*/
283         oh.fname_2 = os_strdup( sp );
284         sp += strlen(oh.fname_2) + 1;
285 
286         oh.attach_size = (size_t)get_4byte_value( (unsigned char*) sp );
287         sp += 4;
288 
289         if (oh.attach_size > stream_size)
290         {
291             oh.attach_size = stream_size;
292         }
293 
294         data_start_point = sp;
295     }
296 
297     DUW LOGGER_log(_("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Attachment %s:%s:%s size = %d\n"), FL, oh.attach_name, oh.fname_1, oh.fname_2, oh.attach_size );
298 
299 
300     /** 20050119:2053:PLD - Added to sanitize 8-bit filenames **/
301     /** Sanitize the output filename **/
302     OLEUNWRAP_sanitize_filename(oh.attach_name);
303     OLEUNWRAP_sanitize_filename(oh.fname_1);
304     OLEUNWRAP_sanitize_filename(oh.fname_2);
305 
306     result = OLEUNWRAP_save_stream( oleuw, oh.attach_name, decode_path, data_start_point, oh.attach_size );
307     if (result == OLEUW_OK)
308     {
309         if (oleuw->debug > 0)
310         {
311             LOGGER_log(_("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Calling reporter for the filename"), FL);
312         }
313         if ((oleuw->verbose > 0) && (oleuw->filename_report_fn != NULL))
314         {
315             oleuw->filename_report_fn(oh.attach_name);
316         }
317         /* Do call back to reporting function*/
318     }
319 
320     /* Clean up our previously allocated data*/
321     if (oh.fname_1 != NULL)
322     {
323         FREE(oh.fname_1);
324     }
325     if (oh.attach_name != NULL)
326     {
327         FREE(oh.attach_name);
328     }
329     if (oh.fname_2 != NULL)
330     {
331         FREE(oh.fname_2);
332     }
333 
334     return OLEUW_OK;
335 }
336 
337 /*-----------------------------------------------------------------\
338  Function Name	: OLEUNWRAP_decodestream
339  Returns Type	: int
340  	----Parameter List
341 	1. char *element_string,
342 	2.  char *stream ,
343  	------------------
344  Exit Codes	:
345  Side Effects	:
346 --------------------------------------------------------------------
347  Comments:
348 
349 --------------------------------------------------------------------
350  Changes:
351 
352 \------------------------------------------------------------------*/
OLEUNWRAP_decodestream(struct OLEUNWRAP_object * oleuw,char * element_string,char * stream,size_t stream_size,char * decode_path)353 int OLEUNWRAP_decodestream( struct OLEUNWRAP_object *oleuw, char *element_string, char *stream, size_t stream_size, char *decode_path )
354 {
355     int result = OLEUW_OK;
356 
357     if (strstr(element_string, OLEUW_ELEMENT_10NATIVE_STRING) != NULL)
358     {
359         OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path );
360 
361     }
362     else
363     {
364         if (oleuw->debug)
365         {
366             LOGGER_log(_("Unable to decode stream with element string '%s'\n"), element_string);
367         }
368         result = OLEUW_STREAM_NOT_DECODED;
369     }
370 
371     return result;
372 }
373 
374 
375 /*-----------------------------------------------------------------\
376  Function Name	: OLEUNWRAP_set_filename_report_fn
377  Returns Type	: int
378  	----Parameter List
379 	1. struct OLEUNWRAP_object *oleuw,
380 	2.  int (*ptr_to_fn)(char *) ,
381  	------------------
382  Exit Codes	:
383  Side Effects	:
384 --------------------------------------------------------------------
385  Comments:
386 
387 --------------------------------------------------------------------
388  Changes:
389 
390 \------------------------------------------------------------------*/
OLEUNWRAP_set_filename_report_fn(struct OLEUNWRAP_object * oleuw,int (* ptr_to_fn)(char *))391 int OLEUNWRAP_set_filename_report_fn( struct OLEUNWRAP_object *oleuw, int (*ptr_to_fn)(char *) )
392 {
393 
394     oleuw->filename_report_fn = ptr_to_fn;
395 
396     return 0;
397 }
398 
399