/* Deterine if a symlink should be hashed or not. * Returns TRUE if a symlink should be hashed. */ bool state::should_hash_symlink(const tstring &fn, file_types *link_type) { /** * We must look at what this symlink points to before we process it. * The file_type() function uses lstat to examine the file. * Here we use the normal stat to examine what this symlink points to. */ struct __stat64 sb; if (TSTAT(fn.c_str(),&sb)) { ocb.error_filename(fn,"%s",strerror(errno)); return false; } file_types type = file_metadata_t::decode_file_type(sb); if (type == stat_directory) { if (mode_recursive){ process_dir(fn); } else { ocb.error_filename(fn,"Is a directory"); } return false; } if (link_type) *link_type = type; return true; }
/** * Opens a case from an existing database. * * @param path Full path to open database from. */ TskCaseDb * TskCaseDb::openDb(const TSK_TCHAR * path) { // Confirm that database already exsists struct STAT_STR stat_buf; if (TSTAT(path, &stat_buf) != 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); tsk_error_set_errstr("Database %" PRIttocTSK " does not exist. Must be created first.", path); return NULL; } TskDbSqlite *db = new TskDbSqlite(path, true); // Open the database. if (db->open(false)) return NULL; return new TskCaseDb(db); }
/** * Creates a new case with a new database and initializes its tables. * Fails if there's already a file at the given path. Returns a pointer * to a new TskCaseDb if successful, else NULL. * * @param path Full path to create new database at. */ TskCaseDb * TskCaseDb::newDb(const TSK_TCHAR * const path) { // Check if the database already exsists struct STAT_STR stat_buf; if (TSTAT(path, &stat_buf) == 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_AUTO_DB); tsk_error_set_errstr("Database %" PRIttocTSK " already exists. Must be deleted first.", path); return NULL; } TskDbSqlite *db = new TskDbSqlite(path, true); // Open the database. if (db->open(true)) return NULL; return new TskCaseDb(db); }
/** * \ingroup imglib * Opens one or more disk image files so that they can be read. If a file format * type is specified, this function will call the specific routine to open the file. * Otherwise, it will detect the type (it will default to raw if no specific type can * be detected). This function must be called before a disk image can be read from. * Note that the data type used to store the image paths is a TSK_TCHAR, which changes * depending on a Unix or Windows build. If you will always have UTF8, then consider * using tsk_img_open_utf8(). * * @param num_img The number of images to open (will be > 1 for split images). * @param images The path to the image files (the number of files must * be equal to num_img and they must be in a sorted order) * @param type The disk image type (can be autodetection) * @param a_ssize Size of device sector in bytes (or 0 for default) * * @return Pointer to TSK_IMG_INFO or NULL on error */ TSK_IMG_INFO * tsk_img_open(int num_img, const TSK_TCHAR * const images[], TSK_IMG_TYPE_ENUM type, unsigned int a_ssize) { TSK_IMG_INFO *img_info = NULL; // Get rid of any old error messages laying around tsk_error_reset(); if ((num_img == 0) || (images[0] == NULL)) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_NOFILE; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_img_open"); return NULL; } if ((a_ssize > 0) && (a_ssize < 512)) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "sector size is less than 512 bytes (%d)", a_ssize); return NULL; } if ((a_ssize % 512) != 0) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "sector size is not a multiple of 512 (%d)", a_ssize); return NULL; } if (tsk_verbose) TFPRINTF(stderr, _TSK_T("tsk_img_open: Type: %d NumImg: %d Img1: %s\n"), type, num_img, images[0]); /* If no type is given, then we use the autodetection methods * In case the image file matches the signatures of multiple formats, * we try all of the embedded formats */ if (type == TSK_IMG_TYPE_DETECT) { TSK_IMG_INFO *img_set = NULL; #if HAVE_LIBAFFLIB || HAVE_LIBEWF char *set = NULL; #endif struct STAT_STR stat_buf; // we rely on tsk_errno, so make sure it is 0 tsk_error_reset(); /* Try the non-raw formats first */ #if HAVE_LIBAFFLIB if ((img_info = aff_open(images, a_ssize)) != NULL) { /* we don't allow the "ANY" when autodetect is used because * we only want to detect the tested formats. */ if (img_info->itype == TSK_IMG_TYPE_AFF_ANY) { img_info->close(img_info); } else { set = "AFF"; img_set = img_info; } } else { // If AFF is otherwise happy except for a password, stop trying to guess if (tsk_errno == TSK_ERR_IMG_PASSWD) { return NULL; } tsk_error_reset(); } #endif #if HAVE_LIBEWF if ((img_info = ewf_open(num_img, images, a_ssize)) != NULL) { if (set == NULL) { set = "EWF"; img_set = img_info; } else { img_set->close(img_set); img_info->close(img_info); tsk_error_reset(); tsk_errno = TSK_ERR_IMG_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "EWF or %s", set); return NULL; } } else { tsk_error_reset(); } #endif // if any of the non-raw formats were detected, then use it. if (img_set != NULL) return img_set; /* We'll use the raw format */ if (num_img == 1) { if ((img_info = raw_open(images[0], a_ssize)) != NULL) { return img_info; } else if (tsk_errno) { return NULL; } } else { if ((img_info = split_open(num_img, images, a_ssize)) != NULL) { return img_info; } else if (tsk_errno) { return NULL; } } /* To improve the error message, verify the file can be read. */ if (TSTAT(images[0], &stat_buf) < 0) { // special case to handle windows objects #if defined(TSK_WIN32) || defined(__CYGWIN__) if (TSTRNCMP(_TSK_T("\\\\.\\"), images[0], 4) == 0) { if (tsk_verbose) TFPRINTF(stderr, _TSK_T ("tsk_img_open: Ignoring stat error because of windows object: %s\n"), images[0]); } else { #endif tsk_error_reset(); tsk_errno = TSK_ERR_IMG_STAT; snprintf(tsk_errstr, TSK_ERRSTR_L, "%" PRIttocTSK " : %s", images[0], strerror(errno)); return NULL; #if defined(TSK_WIN32) || defined(__CYGWIN__) } #endif } tsk_errno = TSK_ERR_IMG_UNKTYPE; tsk_errstr[0] = '\0'; tsk_errstr2[0] = '\0'; return NULL; } /* * Type values * Make a local copy that we can modify the string as we parse it */ switch (type) { case TSK_IMG_TYPE_RAW_SING: /* If we have more than one image name, and raw was the only * type given, then use split */ if (num_img > 1) img_info = split_open(num_img, images, a_ssize); else img_info = raw_open(images[0], a_ssize); break; case TSK_IMG_TYPE_RAW_SPLIT: /* If only one image file is given, and only one type was * given then use raw */ if (num_img == 1) img_info = raw_open(images[0], a_ssize); else img_info = split_open(num_img, images, a_ssize); break; #if HAVE_LIBAFFLIB case TSK_IMG_TYPE_AFF_AFF: case TSK_IMG_TYPE_AFF_AFD: case TSK_IMG_TYPE_AFF_AFM: case TSK_IMG_TYPE_AFF_ANY: img_info = aff_open(images, a_ssize); break; #endif #if HAVE_LIBEWF case TSK_IMG_TYPE_EWF_EWF: img_info = ewf_open(num_img, images, a_ssize); break; #endif case TSK_IMG_TYPE_QEMU: img_info = qemu_open(images[0], a_ssize); break; default: tsk_error_reset(); tsk_errno = TSK_ERR_IMG_UNSUPTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "%d", type); return NULL; } return img_info; }
/** * Open one or more files as a disk image. This serves as a * wrapper around the specific types of disk image formats. You * can specify the type or autodetection can be used. * * @param type The text a user supplied for the type of format. * Examples include "raw", "split", "aff", etc. * @param num_img The number of images that are being considered. * @param images The path to the files (the number of files must * be equal to num_img) * * @return Pointer to the Image state structure or NULL on error */ TSK_IMG_INFO * tsk_img_open(const TSK_TCHAR * type, const int num_img, const TSK_TCHAR ** images) { TSK_IMG_INFO *img_info = NULL; TSK_TCHAR *tp, *next; TSK_TCHAR type_lcl[128], *type_lcl_p; const TSK_TCHAR **img_tmp; int num_img_tmp = num_img; // Get rid of any old error messages laying around tsk_error_reset(); if ((num_img == 0) || (images[0] == NULL)) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_NOFILE; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_img_open"); tsk_errstr2[0] = '\0'; return NULL; } if (tsk_verbose) TFPRINTF(stderr, _TSK_T("tsk_img_open: Type: %s NumImg: %d Img1: %s\n"), (type ? type : _TSK_T("n/a")), num_img, images[0]); // only the first in list (lowest) layer gets the files img_tmp = images; /* If no type is given, then we use the autodetection methods * In case the image file matches the signatures of multiple formats, * we try all of the embedded formats */ if (type == NULL) { TSK_IMG_INFO *img_set = NULL; #if HAVE_LIBAFFLIB || HAVE_LIBEWF char *set = NULL; #endif struct STAT_STR stat_buf; /* First verify that the image file exists */ if (TSTAT(images[0], &stat_buf) < 0) { // special case to handle windows objects #if defined(TSK_WIN32) if ((images[0][0] == _TSK_T('\\')) && (images[0][1] == _TSK_T('\\')) && (images[0][2] == _TSK_T('.')) && (images[0][3] == _TSK_T('\\'))) { if (tsk_verbose) TFPRINTF(stderr, _TSK_T ("tsk_img_open: Ignoring stat error because of windows object: %s\n"), images[0]); } #endif /* AFFLIB supports s3 storage on Amazon, so skip those 'file' paths */ #if HAVE_LIBAFFLIB #if defined(TSK_WIN32) else #endif if (((images[0][0] == _TSK_T('s')) && (images[0][1] == _TSK_T('3')) && (images[0][2] == _TSK_T(':')) && (images[0][3] == _TSK_T('/')) && (images[0][4] == _TSK_T('/'))) || ((images[0][0] == _TSK_T('h')) && (images[0][1] == _TSK_T('t')) && (images[0][2] == _TSK_T('t')) && (images[0][3] == _TSK_T('p')) && (images[0][4] == _TSK_T(':')) && (images[0][5] == _TSK_T('/')) && (images[0][6] == _TSK_T('/')))) { if (tsk_verbose) TFPRINTF(stderr, _TSK_T ("tsk_img_open: Ignoring stat error because of s3/http object: %s\n"), images[0]); } #endif #if HAVE_LIBAFFLIB || defined(TSK_WIN32) else { #endif tsk_error_reset(); tsk_errno = TSK_ERR_IMG_STAT; snprintf(tsk_errstr, TSK_ERRSTR_L, "%" PRIttocTSK " : %s", images[0], strerror(errno)); return NULL; #if HAVE_LIBAFFLIB || defined(TSK_WIN32) } #endif } // we rely on tsk_errno, so make sure it is 0 tsk_error_reset(); /* Try the non-raw formats first */ #if HAVE_LIBAFFLIB if ((img_info = aff_open(images, NULL)) != NULL) { set = "AFF"; img_set = img_info; } else { tsk_error_reset(); } #endif #if HAVE_LIBEWF if ((img_info = ewf_open(num_img, images, NULL)) != NULL) { if (set == NULL) { set = "EWF"; img_set = img_info; } else { img_set->close(img_set); img_info->close(img_info); tsk_error_reset(); tsk_errno = TSK_ERR_IMG_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "EWF or %s", set); return NULL; } } else { tsk_error_reset(); } #endif if (img_set != NULL) return img_set; /* We'll use the raw format */ if (num_img == 1) { if ((img_info = raw_open(images, NULL)) != NULL) { return img_info; } else if (tsk_errno) { return NULL; } } else { if ((img_info = split_open(num_img, images, NULL)) != NULL) { return img_info; } else if (tsk_errno) { return NULL; } } tsk_errno = TSK_ERR_IMG_UNKTYPE; tsk_errstr[0] = '\0'; tsk_errstr2[0] = '\0'; return NULL; } /* * Type values * Make a local copy that we can modify the string as we parse it */ TSTRNCPY(type_lcl, type, 128); type_lcl_p = type_lcl; /* We parse this and go up in the layers */ tp = TSTRTOK(type_lcl, _TSK_T(",")); while (tp != NULL) { uint8_t imgtype; next = TSTRTOK(NULL, _TSK_T(",")); imgtype = tsk_img_parse_type(type); switch (imgtype) { case TSK_IMG_INFO_TYPE_RAW_SING: /* If we have more than one image name, and raw was the only * type given, then use split */ if ((num_img > 1) && (next == NULL) && (img_tmp != NULL)) { img_info = split_open(num_img_tmp, img_tmp, img_info); num_img_tmp = 0; } else { img_info = raw_open(img_tmp, img_info); } img_tmp = NULL; break; case TSK_IMG_INFO_TYPE_RAW_SPLIT: /* If only one image file is given, and only one type was * given then use raw */ if ((num_img == 1) && (next == NULL) && (img_tmp != NULL)) { img_info = raw_open(img_tmp, img_info); } else { img_info = split_open(num_img_tmp, img_tmp, img_info); num_img_tmp = 0; } img_tmp = NULL; break; #if HAVE_LIBAFFLIB case TSK_IMG_INFO_TYPE_AFF_AFF: case TSK_IMG_INFO_TYPE_AFF_AFD: case TSK_IMG_INFO_TYPE_AFF_AFM: img_info = aff_open(img_tmp, img_info); break; #endif #if HAVE_LIBEWF case TSK_IMG_INFO_TYPE_EWF_EWF: img_info = ewf_open(num_img_tmp, img_tmp, img_info); break; #endif default: tsk_error_reset(); tsk_errno = TSK_ERR_IMG_UNSUPTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "%" PRIttocTSK, tp); return NULL; } /* Advance the pointer */ tp = next; } /* Return the highest layer */ return img_info; }
/** * Get the size in bytes of the given file. * * @param a_file The file to test * @param is_winobj 1 if the file is a windows object and not a real file * * @return the size in bytes, or -1 on error/unknown, * -2 if unreadable, -3 if it's a directory. */ static TSK_OFF_T get_size(const TSK_TCHAR * a_file, uint8_t a_is_winobj) { TSK_OFF_T size = -1; struct STAT_STR sb; if (TSTAT(a_file, &sb) < 0) { if (a_is_winobj) { /* stat can fail for Windows objects; ignore that */ if (tsk_verbose) { tsk_fprintf(stderr, "raw_open: ignoring stat result on Windows device %" PRIttocTSK "\n", a_file); } } else { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_STAT); tsk_error_set_errstr("raw_open: image \"%" PRIttocTSK "\" - %s", a_file, strerror(errno)); return -2; } } else if ((sb.st_mode & S_IFMT) == S_IFDIR) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_MAGIC); tsk_error_set_errstr("raw_open: image \"%" PRIttocTSK "\" - is a directory", a_file); return -3; } #ifdef TSK_WIN32 { HANDLE fd; DWORD dwHi, dwLo; if ((fd = CreateFile(a_file, FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { int lastError = (int)GetLastError(); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); // print string of commonly found errors if (lastError == ERROR_ACCESS_DENIED) { tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - access denied", a_file); } else if (lastError == ERROR_SHARING_VIOLATION) { tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - sharing violation", a_file); } else if (lastError == ERROR_FILE_NOT_FOUND) { tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - file not found", a_file); } else { tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - (error %d)", a_file, lastError); } return -2; } /* We need different techniques to determine the size of Windows physical * devices versus normal files */ if (a_is_winobj == 0) { dwLo = GetFileSize(fd, &dwHi); if (dwLo == 0xffffffff) { int lastError = (int)GetLastError(); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - GetFileSize: %d", a_file, lastError); size = -1; } else { size = dwLo | ((TSK_OFF_T) dwHi << 32); } } else { //use GET_PARTITION_INFO_EX prior to IOCTL_DISK_GET_DRIVE_GEOMETRY // to determine the physical disk size because //calculating it with the help of GET_DRIVE_GEOMETRY gives only // approximate number DWORD junk; PARTITION_INFORMATION_EX partition; if (FALSE == DeviceIoControl(fd, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &partition, sizeof(partition), &junk, (LPOVERLAPPED)NULL) ) { DISK_GEOMETRY pdg; if (FALSE == DeviceIoControl(fd, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &pdg, sizeof(pdg), &junk, (LPOVERLAPPED) NULL)) { int lastError = (int)GetLastError(); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - DeviceIoControl: %d", a_file, lastError); size = -1; } else { size = pdg.Cylinders.QuadPart * (TSK_OFF_T) pdg.TracksPerCylinder * (TSK_OFF_T) pdg.SectorsPerTrack * (TSK_OFF_T) pdg.BytesPerSector; } } else { size = partition.PartitionLength.QuadPart; } } CloseHandle(fd); } #else int fd; if ((fd = open(a_file, O_RDONLY | O_BINARY)) < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open: file \"%" PRIttocTSK "\" - %s", a_file, strerror(errno)); return -2; } #ifdef __APPLE__ /* OS X doesn't support SEEK_END on char devices */ if ((sb.st_mode & S_IFMT) != S_IFCHR) { size = lseek(fd, 0, SEEK_END); } if (size <= 0) { int blkSize; long long blkCnt; if (ioctl(fd, DKIOCGETBLOCKSIZE, &blkSize) >= 0) { if (ioctl(fd, DKIOCGETBLOCKCOUNT, &blkCnt) >= 0) { size = blkCnt * (long long) blkSize; } } } #else /* We don't use the stat output because it doesn't work on raw * devices and such */ size = lseek(fd, 0, SEEK_END); #endif close(fd); #endif return size; }
/** * \internal * Open the file as a raw image. * @param image Path to disk image to open. * @param a_ssize Size of device sector in bytes (or 0 for default) * @returns NULL on error. */ TSK_IMG_INFO * raw_open(const TSK_TCHAR * image, unsigned int a_ssize) { IMG_RAW_INFO *raw_info; TSK_IMG_INFO *img_info; struct STAT_STR stat_buf; int is_winobj = 0; if ((raw_info = (IMG_RAW_INFO *) tsk_img_malloc(sizeof(IMG_RAW_INFO))) == NULL) return NULL; img_info = (TSK_IMG_INFO *) raw_info; img_info->itype = TSK_IMG_TYPE_RAW_SING; img_info->read = raw_read; img_info->close = raw_close; img_info->imgstat = raw_imgstat; img_info->sector_size = 512; if (a_ssize) img_info->sector_size = a_ssize; #if defined(TSK_WIN32) || defined(__CYGWIN__) if ((image[0] == _TSK_T('\\')) && (image[1] == _TSK_T('\\')) && (image[2] == _TSK_T('.')) && (image[3] == _TSK_T('\\'))) { is_winobj = 1; } #endif if (is_winobj == 0) { /* Exit if we are given a directory */ if (TSTAT(image, &stat_buf) < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_STAT); tsk_error_set_errstr("raw_open: %s", strerror(errno)); return NULL; } else if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) { if (tsk_verbose) TFPRINTF(stderr, _TSK_T("raw_open: image %s is a directory\n"), image); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_MAGIC); tsk_error_set_errstr("raw_open: path is for a directory"); return NULL; } } #ifdef TSK_WIN32 { DWORD dwHi, dwLo; if ((raw_info->fd = CreateFile(image, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { // if it is a device, try with SHARE_WRITE if ((image[0] == _TSK_T('\\')) && (image[1] == _TSK_T('\\')) && (image[2] == _TSK_T('.')) && (image[3] == _TSK_T('\\'))) { if (tsk_verbose) tsk_fprintf(stderr, "raw_open: Trying Windows device with share_write mode\n"); raw_info->fd = CreateFile(image, FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); } if (raw_info->fd == INVALID_HANDLE_VALUE) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); // print string of commonly found errors if (GetLastError() == ERROR_ACCESS_DENIED) { tsk_error_set_errstr("raw_open file: %" PRIttocTSK " (Access Denied)", image); } else if (GetLastError() == ERROR_SHARING_VIOLATION) { tsk_error_set_errstr("raw_open file: %" PRIttocTSK " (Sharing Violation)", image); } else if (GetLastError() == ERROR_FILE_NOT_FOUND) { tsk_error_set_errstr("raw_open file: %" PRIttocTSK " (File not found)", image); } else { tsk_error_set_errstr("raw_open file: %" PRIttocTSK " (%d)", image, (int) GetLastError()); } return NULL; } } /* We need different techniques to determine the size of physical * devices versus normal files */ if (is_winobj == 0) { dwLo = GetFileSize(raw_info->fd, &dwHi); if (dwLo == 0xffffffff) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open file: %" PRIttocTSK " GetFileSize: %d", image, (int) GetLastError()); return NULL; } img_info->size = dwLo | ((TSK_OFF_T) dwHi << 32); } else { DISK_GEOMETRY pdg; DWORD junk; if (FALSE == DeviceIoControl(raw_info->fd, // device to be queried IOCTL_DISK_GET_DRIVE_GEOMETRY, // operation to perform NULL, 0, &pdg, sizeof(pdg), &junk, (LPOVERLAPPED) NULL)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open file: %" PRIttocTSK " DeviceIoControl: %d", image, (int) GetLastError()); return NULL; } img_info->size = pdg.Cylinders.QuadPart * (TSK_OFF_T) pdg.TracksPerCylinder * (TSK_OFF_T) pdg.SectorsPerTrack * (TSK_OFF_T) pdg.BytesPerSector; } } #else if ((raw_info->fd = open(image, O_RDONLY | O_BINARY)) < 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_IMG_OPEN); tsk_error_set_errstr("raw_open file: %" PRIttocTSK " msg: %s", image, strerror(errno)); return NULL; } #if defined(__APPLE__) /* OS X doesn't support SEEK_END on char devices */ if ((stat_buf.st_mode & S_IFMT) != S_IFCHR) { img_info->size = lseek(raw_info->fd, 0, SEEK_END); lseek(raw_info->fd, 0, SEEK_SET); } if (img_info->size == 0) { int blkSize; long long blkCnt; if (ioctl(raw_info->fd, DKIOCGETBLOCKSIZE, &blkSize) >= 0) { if (ioctl(raw_info->fd, DKIOCGETBLOCKCOUNT, &blkCnt) >= 0) { img_info->size = blkCnt * (long long) blkSize; } } } #else /* We don't use the stat output because it doesn't work on raw * devices and such */ img_info->size = lseek(raw_info->fd, 0, SEEK_END); lseek(raw_info->fd, 0, SEEK_SET); #endif #endif raw_info->seek_pos = 0; return img_info; }
/** * Open the set of disk images as a set of split raw images * * @param num_img Number of images in set * @param images List of disk image paths (in sorted order) * @param next Pointer to next image type abstraction (can be NULL) * * @return NULL on error */ TSK_IMG_INFO * split_open(int num_img, const TSK_TCHAR ** images, TSK_IMG_INFO * next) { IMG_SPLIT_INFO *split_info; TSK_IMG_INFO *img_info; int i; if (next != NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_LAYERS; snprintf(tsk_errstr, TSK_ERRSTR_L, "split must be lowest layer"); return NULL; } if ((split_info = (IMG_SPLIT_INFO *) tsk_malloc(sizeof(IMG_SPLIT_INFO))) == NULL) return NULL; memset((void *) split_info, 0, sizeof(IMG_SPLIT_INFO)); img_info = (TSK_IMG_INFO *) split_info; img_info->itype = TSK_IMG_INFO_TYPE_RAW_SPLIT; img_info->read_random = split_read_random; img_info->get_size = split_get_size; img_info->close = split_close; img_info->imgstat = split_imgstat; img_info->next = NULL; /* Open the files */ split_info->cptr = (int *) tsk_malloc(num_img * sizeof(int)); if (split_info->cptr == NULL) { free(split_info); return NULL; } memset((void *) &split_info->cache, 0, SPLIT_CACHE * sizeof(IMG_SPLIT_CACHE)); split_info->next_slot = 0; split_info->max_off = (OFF_T *) tsk_malloc(num_img * sizeof(OFF_T)); if (split_info->max_off == NULL) { free(split_info->cptr); free(split_info); return NULL; } img_info->size = 0; split_info->num_img = num_img; split_info->images = images; /* Get size info for each file - we do not open each one because that * could cause us to run out of file decsriptors when we only need a few. * The descriptors are opened as needed */ for (i = 0; i < num_img; i++) { struct STAT_STR sb; split_info->cptr[i] = -1; if (TSTAT(images[i], &sb) < 0) { tsk_error_reset(); tsk_errno = TSK_ERR_IMG_STAT; snprintf(tsk_errstr, TSK_ERRSTR_L, "split_open - %" PRIttocTSK " - %s", images[i], strerror(errno)); free(split_info->max_off); free(split_info->cptr); free(split_info); return NULL; } else if ((sb.st_mode & S_IFMT) == S_IFDIR) { if (tsk_verbose) tsk_fprintf(stderr, "split_open: image %" PRIttocTSK " is a directory\n", images[i]); tsk_error_reset(); tsk_errno = TSK_ERR_IMG_MAGIC; snprintf(tsk_errstr, TSK_ERRSTR_L, "split_open: Image is a directory"); return NULL; } /* Add the size of this image to the total and save the current max */ img_info->size += sb.st_size; split_info->max_off[i] = img_info->size; if (tsk_verbose) tsk_fprintf(stderr, "split_open: %d size: %" PRIuOFF " max offset: %" PRIuOFF " Name: %" PRIttocTSK "\n", i, sb.st_size, split_info->max_off[i], images[i]); } return img_info; }
int main(int argc, char **argv1) { TSK_TCHAR **argv; extern int OPTIND; int ch; struct STAT_STR stat_buf; TSK_TCHAR *pipeline_config = NULL; TSK_TCHAR *framework_config = NULL; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif while ((ch = GETOPT(argc, argv, _TSK_T("c:p:vV"))) > 0) { switch (ch) { case _TSK_T('?'): default: TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"), argv[OPTIND]); usage(); case _TSK_T('c'): framework_config = OPTARG; break; case _TSK_T('p'): pipeline_config = OPTARG; break; case _TSK_T('v'): tsk_verbose++; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); } } /* We need at least one more argument */ if (OPTIND == argc) { tsk_fprintf(stderr, "Missing image name\n"); usage(); } TSK_TCHAR *imagePath = argv[OPTIND]; // Load the framework config if they specified it Poco::AutoPtr<Poco::Util::XMLConfiguration> pXMLConfig; if (framework_config) { // @@@ Not Unix-friendly try { pXMLConfig = new Poco::Util::XMLConfiguration(TskUtilities::toUTF8(framework_config)); } catch (std::exception& e) { fprintf(stderr, "Error opening framework config file (%s)\n", e.what()); return 1; } // Initialize properties based on the config file. TskSystemPropertiesImpl *systemProperties = new TskSystemPropertiesImpl(); systemProperties->initialize(*pXMLConfig); TskServices::Instance().setSystemProperties(*systemProperties); } // make up an output folder to store the database and such in TSK_TCHAR outDirPath[1024]; TSNPRINTF(outDirPath, 1024, _TSK_T("%s_tsk_out"), imagePath); if (TSTAT(outDirPath, &stat_buf) == 0) { fprintf(stderr, "Output directory already exists (%"PRIttocTSK")\n", outDirPath); return 1; } if (makeDir(outDirPath)) { return 1; } // @@@ Not UNIX-friendly TSK_SYS_PROP_SET(TskSystemPropertiesImpl::OUT_DIR, outDirPath); // Create and register our SQLite ImgDB class std::auto_ptr<TskImgDB> pImgDB(NULL); pImgDB = std::auto_ptr<TskImgDB>(new TskImgDBSqlite(outDirPath)); if (pImgDB->initialize() != 0) { fprintf(stderr, "Error initializing SQLite database\n"); tsk_error_print(stderr); return 1; } // @@@ Call pImgDB->addToolInfo() as needed to set version info... TskServices::Instance().setImgDB(*pImgDB); // Create a Blackboard and register it with the framework. TskServices::Instance().setBlackboard(TskDBBlackboard::instance()); // @@@ Not UNIX-friendly if (pipeline_config != NULL) TSK_SYS_PROP_SET(TskSystemPropertiesImpl::PIPELINE_CONFIG, pipeline_config); // Create an ImageFile and register it with the framework. TskImageFileTsk imageFileTsk; if (imageFileTsk.open(imagePath) != 0) { fprintf(stderr, "Error opening image: %"PRIttocTSK"\n", imagePath); tsk_error_print(stderr); return 1; } TskServices::Instance().setImageFile(imageFileTsk); // Let's get the pipelines setup to make sure there are no errors. TskPipelineManager pipelineMgr; TskPipeline *filePipeline; try { filePipeline = pipelineMgr.createPipeline(TskPipelineManager::FILE_ANALYSIS_PIPELINE); } catch (TskException &e ) { fprintf(stderr, "Error creating file analysis pipeline\n"); std::cerr << e.message() << endl; filePipeline = NULL; } TskPipeline *reportPipeline; try { reportPipeline = pipelineMgr.createPipeline(TskPipelineManager::REPORTING_PIPELINE); } catch (TskException &e ) { fprintf(stderr, "Error creating reporting pipeline\n"); std::cerr << e.message() << endl; reportPipeline = NULL; } // now we analyze the data. // Extract if (imageFileTsk.extractFiles() != 0) { fprintf(stderr, "Error adding file system info to database\n"); tsk_error_print(stderr); return 1; } //Run pipeline on all files // @@@ this needs to cycle over the files to analyze, 10 is just here for testing if (filePipeline) { for (int i = 0; i < 10; i++) { try { filePipeline->run(i); } catch (...) { // error message has been logged already. } } } if (reportPipeline) { try { reportPipeline->run(); } catch (...) { fprintf(stderr, "Error running reporting pipeline\n"); return 1; } } fprintf(stderr, "image analysis complete\n"); return 0; }