diff --git a/README b/README index 2c18ad3a..9c0932e0 100644 --- a/README +++ b/README @@ -66,3 +66,69 @@ Both are under GNU General Public License. Christophe GRENIER grenier@cgsecurity.org http://www.cgsecurity.org/ + +================================================================ +PhotoRec - Theory of operation: + +Carvers are plugable. Each carver consists of: + +struct file_hint_t - describes extension, name, max size, enable by default, etc. +file_enable_t list_file_enable[] - array with all file hints and whether enabled or not. + + +phmain.c - Contains the main() and driver logic for photorec. + +main(): + - reads parameters + - scans for available devices + - parses the HD (or image) + - resets the list of which file carvers are enabled + - Initializes ncurses + - Calls do_curses_photorec() (in pdisksel.c) + - shuts down ncurses + + +pdisksel.c - + int do_curses_photorec(int verbose, const char *recup_dir, const list_disk_t *list_disk, + file_enable_t *file_enable, char *cmd_device, char **current_cmd) + + - runs either photorec_disk_selection_cli() or photorec_disk_selection_ncurses() + - Both of these eventually call menu_photorec() in ppartsel.c + +ppartsel.c - menu_photorec(): + - Implements Search/Options/File Opt/Geometry/Quit menu + - Search Option: + - Creates new recup_dir + - Runs ext2_fix_group and ext2_fix_inode if necessary + - runs photorec() + +phrecn.c - photorec() + - runs multiple passes until status==STATUS_QUIT + - calls photorec_mkdir() to actually make the output directory + +photorec.c: - file_finish() + - called when file is done. + + called by: + - photorec_bf() + - photorec_bf_pad() + - photorec_bf_frag() + - photorec_bf_aux() + + file_recovery_t *file_recovery - + +photorec.c - file_finish2() + - called when a file is done. + + called by: + - photorec_aux() (in three places) + - photorec() + +Some utility functions: +phbf.c - set_filename(file_recovery,recup_dir,dir_num,disk_car,partition,nn) + - Figures out a file name + +================================================================ +XML Report Integration + +xml output file is always made and always placed in recup_dir diff --git a/src/Makefile.am b/src/Makefile.am index a092dd0d..2a78ca7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -251,9 +251,9 @@ file_C = filegen.c \ file_H = ext2.h filegen.h file_jpg.h file_sp3.h file_tar.h file_tiff.h file_txt.h list.h ole.h pe.h suspend.h -photorec_C = photorec.c phcfg.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c list.c ntfs_dir.c ntfsp.c sessionp.c setdate.c +photorec_C = photorec.c phcfg.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c list.c ntfs_dir.c ntfsp.c sessionp.c setdate.c dfxml.c -photorec_H = photorec.h phcfg.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h sessionp.h setdate.h +photorec_H = photorec.h phcfg.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h sessionp.h setdate.h dfxml.h photorec_ncurses_C = addpart.c askloc.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometry.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdisksel.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartsel.c photorec_ncurses_H = addpart.h askloc.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometry.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdisksel.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartsel.h diff --git a/src/dfxml.c b/src/dfxml.c new file mode 100644 index 00000000..b0821eab --- /dev/null +++ b/src/dfxml.c @@ -0,0 +1,364 @@ +/* + + File: xml.c + + Copyright (C) 2011 Simson Garfinkel + Copyright (C) 2011 Christophe Grenier + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#ifdef HAVE_UNISTD_H +#include /* unlink, ftruncate */ +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#include "types.h" +#include "common.h" +#include "dir.h" +#include "filegen.h" +#include "photorec.h" +#include "ext2_dir.h" +#include "ewf.h" +#include "file_jpg.h" +#include "ntfs_dir.h" +#include "misc.h" +#include "dfxml.h" + +static FILE *xml_handle = NULL; +static int xml_stack_depth = 0; +static char *command_line = NULL; + +static const char *xml_header = "\n"; +static char xml_dir[2048]; +static char xml_fname[2048]; /* what photorec uses elsewhere */ + + +FILE *xml_open(const char *recup_dir, const unsigned int dir_num) +{ + snprintf(xml_dir, sizeof(xml_dir), "%s.%u/", recup_dir,dir_num); + snprintf(xml_fname, sizeof(xml_fname), "%s.%u/report.xml", recup_dir, dir_num); + xml_handle = fopen(xml_fname,"w"); + return xml_handle; +} + +void xml_set_command_line(const int argc, char **argv) +{ + int i; + command_line = (char *)calloc(1, 1); + /* Capture the command line */ + for(i=0; i0) + strcat(command_line," "); + strcat(command_line, argv[i]); + } +} + +void xml_close() +{ + if(xml_handle==NULL) + return; + fclose(xml_handle); + xml_handle = NULL; +} + +static void xml_spaces(void) +{ + int i; + if(xml_handle==NULL) + return; + for(i = 0; i < xml_stack_depth * 2; i++) + { + fputc(' ', xml_handle); + } +} + +static void xml_tagout(const char *tag,const char *attribute) +{ + if(attribute[0]=='\0') + xml_printf("<%s>", tag); + else + xml_printf("<%s %s>", tag, attribute); +} + +/** + * output the closing tag */ +static void xml_ctagout(const char *tag) +{ + xml_printf("", tag); +} + +void xml_push(const char *tag,const char *attribute) +{ + if(xml_handle==NULL) + return; + xml_tagout(tag, attribute); + fputc('\n', xml_handle); + xml_stack_depth++; +} + +void xml_pop(const char *tag) +{ + if(xml_handle==NULL) + return; + xml_stack_depth--; + xml_ctagout(tag); + fputc('\n', xml_handle); +} + +void xml_printf(const char *fmt,...) +{ + va_list ap; + if(xml_handle==NULL) + return; + va_start(ap, fmt); + xml_spaces(); + vfprintf(xml_handle, fmt, ap); + va_end(ap); +} + +void xml_out2s(const char *tag, const char *value) +{ + xml_printf("<%s>%s\n", tag, value, tag); +} + +void xml_out2i(const char *tag, const uint64_t value) +{ + xml_printf("<%s>%llu\n", tag, (long long unsigned)value, tag); +} + +void xml_add_DFXML_creator(const char *package, const char *version) +{ + xml_push("creator",""); + xml_out2s("package", package); + xml_out2s("version", version); + xml_push("build_environment",""); + xml_printf("%s\n", get_compiler()); + xml_out2s("compilation_date", get_compilation_date()); + xml_printf("\n", td_ext2fs_version()); + xml_printf("\n", td_ewf_version()); + xml_printf("\n", td_jpeg_version()); + xml_printf("\n", td_ntfs_version()); + xml_pop("build_environment"); + xml_push("execution_environment",""); +#if defined(__CYGWIN__) || defined(__MINGW32__) + xml_out2s("os_sysname", "Windows"); + xml_out2s("os_release", get_os()); + xml_out2s("os_version", get_os()); +#ifdef HAVE_SYS_UTSNAME_H + { + struct utsname name; + if(uname(&name)==0) + { + xml_out2s("host", name.nodename); + xml_out2s("arch", name.machine); + } + } +#endif +#elif defined(HAVE_SYS_UTSNAME_H) + { + struct utsname name; + if(uname(&name)==0) + { + xml_out2s("os_sysname", name.sysname); + xml_out2s("os_release", name.release); + xml_out2s("os_version", name.version); + xml_out2s("host", name.nodename); + xml_out2s("arch", name.machine); + } + } +#elif defined(UNAMES) + xml_out2s("os_sysname", UNAMES); +#endif +#ifdef HAVE_GETEUID + xml_out2i("uid", geteuid()); +#ifdef HAVE_GETPWUID + { + struct passwd *tmp=getpwuid(getuid()); + if(tmp != NULL) + { + xml_out2s("username", tmp->pw_name); + } + } +#endif +#endif + { + char outstr[200]; + time_t t; + struct tm *tmp; + t = time(NULL); + tmp = localtime(&t); + if (tmp != NULL && + strftime(outstr, sizeof(outstr), "%Y-%m-%dT%H:%M:%S%z", tmp) != 0) + { + xml_out2s("start_time", outstr); + } + } + xml_pop("execution_environment"); + xml_pop("creator"); +} + +void xml_setup(disk_t *disk, const partition_t *partition) +{ + if(xml_handle==NULL) + return; + fputs(xml_header, xml_handle); + xml_push("dfxml", "xmloutputversion='1.0'"); + xml_push("metadata", + "\n xmlns='http://www.forensicswiki.org/wiki/Category:Digital_Forensics_XML' " + "\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " + "\n xmlns:dc='http://purl.org/dc/elements/1.1/'" ); + xml_out2s("dc:type","Carve Report"); + xml_pop("metadata"); + xml_add_DFXML_creator("PhotoRec", VERSION); + xml_push("source", ""); + xml_out2s("image_filename", disk->device); + xml_out2i("sectorsize", disk->sector_size); + if(disk->model != NULL) + xml_out2s("device_model", disk->model); + xml_out2i("image_size", disk->disk_real_size); + xml_push("volume", ""); + xml_push("byte_runs", ""); + xml_printf( "\n", + (long long unsigned)partition->part_offset, + (long long unsigned)partition->part_size); + xml_pop("byte_runs"); + if(partition->blocksize > 0) + xml_out2i("block_size", partition->blocksize); + xml_pop("volume"); + xml_pop("source"); + xml_push("configuration", ""); + xml_pop("configuration"); // configuration +} + +void xml_shutdown(void) +{ + if(xml_handle==NULL) + return; + xml_pop("dfxml"); + xml_close(); +} + +/* If fname begins with xml_dir then just return the relative part */ +static const char *relative_name(const char *fname) +{ + if(fname==NULL) + return ""; + if(strncmp(fname, xml_dir, strlen(xml_dir))==0) + return fname+strlen(xml_dir); + return fname; +} + +/* See filegen.h for the definition of file_recovery_struct */ +void xml_log_file_recovered(const file_recovery_t *file_recovery) +{ + struct td_list_head *tmp; + uint64_t file_size=0; + if(xml_handle==NULL) + return; + if(file_recovery->filename==NULL) + return; + xml_push("fileobject", ""); + xml_out2s("filename", relative_name(file_recovery->filename)); + xml_out2i("filesize", file_recovery->file_size); + xml_push("byte_runs", ""); + td_list_for_each(tmp, &file_recovery->location.list) + { + const alloc_list_t *element=td_list_entry(tmp, alloc_list_t, list); + if(element->data>0) + { + const uint64_t len=element->end - element->start + 1; + xml_printf( "\n", + (long long unsigned)file_size, + (long long unsigned)element->start, + (long long unsigned)len); + file_size+=len; + } + } + xml_pop("byte_runs"); + xml_pop("fileobject"); +} + +static void xml_log_file_recovered2_aux(const alloc_data_t *file, const uint64_t file_size) +{ + struct td_list_head *tmp; + uint64_t size=0; + td_list_for_each(tmp, &file->list) + { + const alloc_data_t *element=td_list_entry(tmp, alloc_data_t, list); + if(size >= file_size) + return ; + if(element->data>0) + { + const uint64_t len=element->end - element->start + 1; + if(size + len < file_size) + { + xml_printf("\n", + (long long unsigned)size, + (long long unsigned)element->start, + (long long unsigned)len); + size+=len; + } + else + { + xml_printf("\n", + (long long unsigned)size, + (long long unsigned)element->start, + (long long unsigned)(file_size - size)); + return ; + } + } + } +} + +void xml_log_file_recovered2(const file_recovery_t *file_recovery) +{ + if(xml_handle==NULL) + return; + if(file_recovery->filename==NULL) + return; + xml_push("fileobject", ""); + xml_out2s("filename", relative_name(file_recovery->filename)); + xml_out2i("filesize", file_recovery->file_size); + xml_push("byte_runs", ""); + xml_log_file_recovered2_aux(file_recovery->loc, file_recovery->file_size); + xml_pop("byte_runs"); + xml_pop("fileobject"); +} diff --git a/src/dfxml.h b/src/dfxml.h new file mode 100644 index 00000000..3ba9dd90 --- /dev/null +++ b/src/dfxml.h @@ -0,0 +1,48 @@ +/* + + File: dfxml.h + + Copyright (C) 2011 Simson Garfinkel + Copyright (C) 2011 Christophe Grenier + + This software is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + */ + +#ifndef _DFXML_H +#define _DFXML_H + +#include +#ifdef __cplusplus +extern "C" { +#endif + +FILE *xml_open(const char *default_filename, const unsigned int dir_num); +void xml_close(void); +void xml_push(const char *tag, const char *attribute); +void xml_pop(const char *tag); +void xml_out2s(const char *tag, const char *value); +void xml_out2i(const char *tag, const uint64_t value); +void xml_setup(disk_t *disk, const partition_t *partition); +void xml_set_command_line(const int argc, char **argv); +void xml_add_DFXML_creator(const char *package, const char *version); +void xml_shutdown(void); +void xml_log_file_recovered(const file_recovery_t *file_recovery); +void xml_log_file_recovered2(const file_recovery_t *file_recovery); +void xml_printf(const char *__restrict __format,...) __attribute__((format(printf,1,2))); +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif +#endif diff --git a/src/phmain.c b/src/phmain.c index fd3dbec7..61294abe 100644 --- a/src/phmain.c +++ b/src/phmain.c @@ -76,6 +76,8 @@ #include "file_jpg.h" #include "ntfs_dir.h" #include "pdisksel.h" +#include "dfxml.h" + extern const arch_fnct_t arch_none; extern file_enable_t list_file_enable[]; @@ -237,6 +239,7 @@ int main( int argc, char **argv ) "If you have problems with PhotoRec or bug reports, please contact me.\n"); return 0; } + xml_set_command_line(argc, argv); if(create_log!=TD_LOG_NONE) log_handle=log_open(logfile, create_log); #ifdef HAVE_SETLOCALE diff --git a/src/photorec.c b/src/photorec.c index 81bbd29c..b15c1656 100644 --- a/src/photorec.c +++ b/src/photorec.c @@ -47,6 +47,7 @@ #include "ntfsp.h" #include "log.h" #include "setdate.h" +#include "dfxml.h" /* #define DEBUG_FILE_FINISH */ /* #define DEBUG_UPDATE_SEARCH_SPACE */ @@ -669,6 +670,7 @@ int file_finish(file_recovery_t *file_recovery, const char *recup_dir, const int else { list_space_used(file_recovery, disk->sector_size); + xml_log_file_recovered(file_recovery); if(status!=STATUS_EXT2_ON_SAVE_EVERYTHING && status!=STATUS_EXT2_OFF_SAVE_EVERYTHING && status!=STATUS_FIND_OFFSET) { update_search_space(file_recovery,list_search_space,current_search_space,offset,blocksize); @@ -763,6 +765,7 @@ alloc_data_t *file_finish2(file_recovery_t *file_recovery, const char *recup_dir } else { + xml_log_file_recovered2(file_recovery); datanext=file_truncate(list_search_space, file_recovery, disk->sector_size, blocksize); } free_list_allocation(&file_recovery->location); diff --git a/src/phrecn.c b/src/phrecn.c index 6a725d5b..85c10b4a 100644 --- a/src/phrecn.c +++ b/src/phrecn.c @@ -76,6 +76,7 @@ #include "phnc.h" #include "phbs.h" #include "file_found.h" +#include "dfxml.h" /* #define DEBUG */ /* #define DEBUG_BF */ @@ -762,7 +763,13 @@ int photorec(disk_t *disk_car, partition_t *partition, const int verbose, const file_stats=init_file_stats(files_enable); real_start_time=time(NULL); - dir_num=photorec_mkdir(recup_dir,dir_num); + /* make the first recup_dir */ + dir_num=photorec_mkdir(recup_dir, dir_num); + + /* Open the XML output file */ + xml_open(recup_dir, dir_num); + xml_setup(disk_car, partition); + #if 0 test_files(disk_car, partition, list_search_space, recup_dir, &dir_num, &file_nbr); #endif @@ -1060,6 +1067,8 @@ int photorec(disk_t *disk_car, partition_t *partition, const int verbose, const free(file_stats); free_header_check(); free(new_recup_dir); + xml_shutdown(); + xml_close(); return 0; }