1 /*
2 
3     File: xml.c
4 
5     Copyright (C) 2011 Simson Garfinkel
6     Copyright (C) 2011 Christophe Grenier
7 
8     This software is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License along
19     with this program; if not, write the Free Software Foundation, Inc., 51
20     Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 
22  */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #ifdef ENABLE_DFXML
28 #include <stdio.h>
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <stdarg.h>
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>	/* unlink, ftruncate */
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #include <errno.h>
40 #ifdef HAVE_SYS_UTSNAME_H
41 #include <sys/utsname.h>
42 #endif
43 #ifdef HAVE_PWD_H
44 #include <pwd.h>
45 #endif
46 #ifdef HAVE_TIME_H
47 #include <time.h>
48 #endif
49 #ifdef HAVE_SYS_TIME_H
50 #include <sys/time.h>
51 #endif
52 #include "types.h"
53 #include "common.h"
54 #include "dir.h"
55 #include "filegen.h"
56 #include "photorec.h"
57 #include "ext2_dir.h"
58 #include "ewf.h"
59 #include "file_jpg.h"
60 #include "file_gz.h"
61 #include "ntfs_dir.h"
62 #include "misc.h"
63 #include "dfxml.h"
64 
65 static FILE *xml_handle = NULL;
66 static int xml_stack_depth = 0;
67 static char *command_line = NULL;
68 
69 static const char *xml_header = "<?xml version='1.0' encoding='UTF-8'?>\n";
70 static char xml_dir[2048];
71 static char xml_fname[2048];			/* what photorec uses elsewhere */
72 
73 
xml_open(const char * recup_dir,const unsigned int dir_num)74 FILE *xml_open(const char *recup_dir, const unsigned int dir_num)
75 {
76   snprintf(xml_dir, sizeof(xml_dir), "%s.%u/", recup_dir,dir_num);
77   snprintf(xml_fname, sizeof(xml_fname), "%s.%u/report.xml", recup_dir, dir_num);
78   xml_handle = fopen(xml_fname,"w");
79   return xml_handle;
80 }
81 
xml_set_command_line(const int argc,char ** argv)82 void xml_set_command_line(const int argc, char **argv)
83 {
84   int i;
85   int len=argc;
86   if(command_line!=NULL)
87     return ;
88   /* Capture the command line */
89   for(i=0; i<argc; i++)
90   {
91     len+=strlen(argv[i]);
92   }
93   command_line = (char *)MALLOC(len);
94   command_line[0]='\0';
95   for(i=0; i<argc; i++)
96   {
97     if(i>0)
98       strcat(command_line," ");
99     strcat(command_line, argv[i]);
100   }
101 }
102 
xml_clear_command_line(void)103 void xml_clear_command_line(void)
104 {
105   free(command_line);
106   command_line=NULL;
107 }
108 
xml_close()109 void xml_close()
110 {
111   if(xml_handle==NULL)
112     return;
113   fclose(xml_handle);
114   xml_handle = NULL;
115 }
116 
xml_spaces(void)117 static void xml_spaces(void)
118 {
119   int i;
120   if(xml_handle==NULL)
121     return;
122   for(i = 0; i < xml_stack_depth * 2; i++)
123   {
124     fputc(' ', xml_handle);
125   }
126 }
127 
xml_tagout(const char * tag,const char * attribute)128 static void xml_tagout(const char *tag,const char *attribute)
129 {
130   if(attribute[0]=='\0')
131     xml_printf("<%s>", tag);
132   else
133     xml_printf("<%s %s>", tag, attribute);
134 }
135 
136 /**
137  * output the closing tag */
xml_ctagout(const char * tag)138 static void xml_ctagout(const char *tag)
139 {
140   xml_printf("</%s>", tag);
141 }
142 
xml_push(const char * tag,const char * attribute)143 void xml_push(const char *tag,const char *attribute)
144 {
145   if(xml_handle==NULL)
146     return;
147   xml_tagout(tag, attribute);
148   fputc('\n', xml_handle);
149   xml_stack_depth++;
150 }
151 
xml_pop(const char * tag)152 void xml_pop(const char *tag)
153 {
154   if(xml_handle==NULL)
155     return;
156   xml_stack_depth--;
157   xml_ctagout(tag);
158   fputc('\n', xml_handle);
159 }
160 
xml_printf(const char * fmt,...)161 void xml_printf(const char *fmt,...)
162 {
163   va_list ap;
164   if(xml_handle==NULL)
165     return;
166   va_start(ap, fmt);
167   xml_spaces();
168   vfprintf(xml_handle, fmt, ap);
169   va_end(ap);
170 }
171 
xml_out2s(const char * tag,const char * value)172 void xml_out2s(const char *tag, const char *value)
173 {
174   if(xml_handle==NULL)
175     return;
176   xml_spaces();
177   fprintf(xml_handle, "<%s>", tag);
178   for(;*value!='\0'; value++)
179   {
180     if(*value=='&')
181       fputs("&amp;", xml_handle);
182     else
183       putc(*value, xml_handle);
184   }
185   fprintf(xml_handle, "</%s>\n", tag);
186 }
187 
xml_out2i(const char * tag,const uint64_t value)188 void xml_out2i(const char *tag, const uint64_t value)
189 {
190   xml_printf("<%s>%llu</%s>\n", tag, (long long unsigned)value, tag);
191 }
192 
xml_add_DFXML_creator(const char * package,const char * version)193 void xml_add_DFXML_creator(const char *package, const char *version)
194 {
195   xml_push("creator","");
196   xml_out2s("package", package);
197   xml_out2s("version", version);
198   xml_push("build_environment","");
199   xml_printf("<compiler>%s</compiler>\n", get_compiler());
200 #ifdef RECORD_COMPILATION_DATE
201   xml_out2s("compilation_date", get_compilation_date());
202 #endif
203   xml_printf("<library name='libext2fs' version='%s'/>\n", td_ext2fs_version());
204   xml_printf("<library name='libewf' version='%s'/>\n", td_ewf_version());
205   xml_printf("<library name='libjpeg' version='%s'/>\n", td_jpeg_version());
206   xml_printf("<library name='libntfs' version='%s'/>\n", td_ntfs_version());
207   xml_printf("<library name='zlib' version='%s'/>\n", td_zlib_version());
208   xml_pop("build_environment");
209   xml_push("execution_environment","");
210 #if defined(__CYGWIN__) || defined(__MINGW32__)
211   xml_out2s("os_sysname", "Windows");
212   xml_out2s("os_release", get_os());
213   xml_out2s("os_version", get_os());
214 #ifdef HAVE_SYS_UTSNAME_H
215   {
216     struct utsname name;
217     if(uname(&name)==0)
218     {
219       xml_out2s("host", name.nodename);
220       xml_out2s("arch", name.machine);
221     }
222   }
223 #endif
224 #elif defined(HAVE_SYS_UTSNAME_H)
225   {
226     struct utsname name;
227     if(uname(&name)==0)
228     {
229       xml_out2s("os_sysname", name.sysname);
230       xml_out2s("os_release", name.release);
231       xml_out2s("os_version", name.version);
232       xml_out2s("host", name.nodename);
233       xml_out2s("arch", name.machine);
234     }
235   }
236 #elif defined(UNAMES)
237   xml_out2s("os_sysname", UNAMES);
238 #endif
239 #ifdef HAVE_GETEUID
240   xml_out2i("uid", geteuid());
241 #if 0
242 #ifdef HAVE_GETPWUID
243   {
244     struct passwd *tmp=getpwuid(getuid());
245     if(tmp != NULL)
246     {
247       xml_out2s("username", tmp->pw_name);
248     }
249   }
250 #endif
251 #endif
252 #endif
253   {
254     char outstr[200];
255     const time_t t = time(NULL);
256     struct tm tm_tmp;
257     const struct tm *tmp = localtime_r(&t,&tm_tmp);
258     if (tmp != NULL &&
259 	strftime(outstr, sizeof(outstr), "%Y-%m-%dT%H:%M:%S%z", tmp) != 0)
260     {
261       xml_out2s("start_time", outstr);
262     }
263   }
264   xml_pop("execution_environment");
265   xml_pop("creator");
266 }
267 
xml_setup(disk_t * disk,const partition_t * partition)268 void xml_setup(disk_t *disk, const partition_t *partition)
269 {
270   if(xml_handle==NULL)
271     return;
272   fputs(xml_header, xml_handle);
273   xml_push("dfxml", "xmloutputversion='1.0'");
274   xml_push("metadata",
275       "\n  xmlns='http://www.forensicswiki.org/wiki/Category:Digital_Forensics_XML' "
276       "\n  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "
277       "\n  xmlns:dc='http://purl.org/dc/elements/1.1/'" );
278   xml_out2s("dc:type","Carve Report");
279   xml_pop("metadata");
280   xml_add_DFXML_creator("PhotoRec", VERSION);
281   xml_push("source", "");
282   xml_out2s("image_filename", disk->device);
283   xml_out2i("sectorsize", disk->sector_size);
284   if(disk->model != NULL)
285     xml_out2s("device_model", disk->model);
286   xml_out2i("image_size", disk->disk_real_size);
287   xml_push("volume", "");
288   xml_push("byte_runs", "");
289   xml_printf( "<byte_run offset='0' img_offset='%llu' len='%llu'/>\n",
290       (long long unsigned)partition->part_offset,
291       (long long unsigned)partition->part_size);
292   xml_pop("byte_runs");
293   if(partition->blocksize > 0)
294     xml_out2i("block_size", partition->blocksize);
295   xml_pop("volume");
296   xml_pop("source");
297   xml_push("configuration", "");
298   xml_pop("configuration");			// configuration
299 }
300 
xml_shutdown(void)301 void xml_shutdown(void)
302 {
303   if(xml_handle==NULL)
304     return;
305   xml_pop("dfxml");
306   xml_close();
307 }
308 
309 /* If fname begins with xml_dir then just return the relative part */
relative_name(const char * fname)310 static const char *relative_name(const char *fname)
311 {
312   if(fname==NULL)
313     return "";
314   if(strncmp(fname, xml_dir, strlen(xml_dir))==0)
315     return fname+strlen(xml_dir);
316   return fname;
317 }
318 
319 /* See filegen.h for the definition of file_recovery_struct */
xml_log_file_recovered(const file_recovery_t * file_recovery)320 void xml_log_file_recovered(const file_recovery_t *file_recovery)
321 {
322   struct td_list_head *tmp;
323   uint64_t file_size=0;
324   if(xml_handle==NULL)
325     return;
326   if(file_recovery==NULL || file_recovery->filename[0]=='\0')
327     return;
328   xml_push("fileobject", "");
329   xml_out2s("filename", relative_name(file_recovery->filename));
330   xml_out2i("filesize", file_recovery->file_size);
331   xml_push("byte_runs", "");
332   td_list_for_each(tmp, &file_recovery->location.list)
333   {
334     const alloc_list_t *element=td_list_entry_const(tmp, const alloc_list_t, list);
335     if(element->data>0)
336     {
337       const uint64_t len=element->end - element->start + 1;
338       xml_printf( "<byte_run offset='%llu' img_offset='%llu' len='%llu'/>\n",
339 	  (long long unsigned)file_size,
340 	  (long long unsigned)element->start,
341 	  (long long unsigned)len);
342       file_size+=len;
343     }
344   }
345   xml_pop("byte_runs");
346   xml_pop("fileobject");
347   fflush(xml_handle);
348 }
349 #endif
350