Exemple #1
0
/** \internal
 * Internal method that the other findFilesInFs can call after they
 * have opened FS_INFO.
 * @returns OK, STOP, or ERR (error message will already have been registered)
 */
TSK_RETVAL_ENUM
    TskAuto::findFilesInFsInt(TSK_FS_INFO * a_fs_info, TSK_INUM_T a_inum)
{
    // see if the super class wants us to proceed
    TSK_FILTER_ENUM retval = filterFs(a_fs_info);
    if ((retval == TSK_FILTER_STOP) || (m_stopAllProcessing))
        return TSK_STOP;
    else if (retval == TSK_FILTER_SKIP)
        return TSK_OK;

    /* Walk the files, starting at the given inum */
    if (tsk_fs_dir_walk(a_fs_info, a_inum,
            (TSK_FS_DIR_WALK_FLAG_ENUM) (TSK_FS_DIR_WALK_FLAG_RECURSE |
                m_fileFilterFlags), dirWalkCb, this)) {

        tsk_error_set_errstr2(
            "Error walking directory in file system at offset %" PRIuOFF, a_fs_info->offset);
        registerError();
        return TSK_ERR;
    }
    
    if (m_stopAllProcessing)
        return TSK_STOP;

    /* We could do some analysis of unallocated blocks at this point...  */

    return TSK_OK;
}
Exemple #2
0
/**
 * Starts in a specified byte offset of the opened disk images and looks for a
 * file system. Will start processing the file system at a specified
 * file system. Will call processFile() on each file
 * that is found in that directory.
 *
 * @param a_start Byte offset of file system starting location.
 * @param a_ftype Type of file system that will be analyzed.
 * @param a_inum inum to start walking files system at.
 *
 * @returns 1 if an error occured (messages will have been registered) and 0 on success
 */
uint8_t
    TskAuto::findFilesInFs(TSK_OFF_T a_start, TSK_FS_TYPE_ENUM a_ftype,
    TSK_INUM_T a_inum)
{
    if (!m_img_info) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_AUTO_NOTOPEN);
        tsk_error_set_errstr("findFilesInFs -- img_info ");
        registerError();
        return 1;
    }

    TSK_FS_INFO *fs_info;
    if ((fs_info = tsk_fs_open_img(m_img_info, a_start, a_ftype)) == NULL) {
        if (getCurVsPartFlag() & TSK_VS_PART_FLAG_ALLOC) {
            tsk_error_set_errstr2(
                "Sector offset: %" PRIuOFF ", Partition Type: %s",
                a_start / 512, getCurVsPartDescr().c_str());
            registerError();
            return 1;
        }
        else {
            tsk_error_reset();
            return 0;
        }
    }

    findFilesInFsInt(fs_info, a_inum);
    tsk_fs_close(fs_info);
    return m_errors.empty() ? 0 : 1;
}
Exemple #3
0
/**
 * Starts in a specified byte offset of the opened disk images and looks for a
 * file system. Will call processFile() on each file
 * that is found.  Same as findFilesInFs, but gives more detailed return values.
 * @param a_start Byte offset to start analyzing from. 
 * @param a_ftype File system type.
 * @returns Error (messages will have been registered), OK, or STOP.
 */
TSK_RETVAL_ENUM
    TskAuto::findFilesInFsRet(TSK_OFF_T a_start, TSK_FS_TYPE_ENUM a_ftype)
{
    if (!m_img_info) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_AUTO_NOTOPEN);
        tsk_error_set_errstr("findFilesInFsRet -- img_info");
        registerError();
        return TSK_ERR;
    }

    TSK_FS_INFO *fs_info;
    if ((fs_info = tsk_fs_open_img(m_img_info, a_start, a_ftype)) == NULL) {
        if (getCurVsPartFlag() & TSK_VS_PART_FLAG_ALLOC) {
            tsk_error_set_errstr2 ("Sector offset: %" PRIuOFF ", Partition Type: %s",
                a_start/512, getCurVsPartDescr().c_str() );
            registerError();
            return TSK_ERR;
        }
        else {
            tsk_error_reset();
            return TSK_OK;
        }
    }

    TSK_RETVAL_ENUM retval = findFilesInFsInt(fs_info, fs_info->root_inum);
    tsk_fs_close(fs_info);
    if (m_errors.empty() == false)
        return TSK_ERR;
    else 
        return retval;
}
Exemple #4
0
std::string TskAuto::errorRecordToString(error_record &rec) {
    tsk_error_reset();
    tsk_error_set_errno(rec.code);
    tsk_error_set_errstr("%s", rec.msg1.c_str());
    tsk_error_set_errstr2("%s", rec.msg2.c_str());
    const char *msg = tsk_error_get();
    std::string ret;
    if  (msg != NULL)
        ret = msg;
    tsk_error_reset();
    return ret;
}
Exemple #5
0
/*
 * This thread sets error variables, updates the semaphore,
 * waits on the semaphore, and reads them back.
 */
void * thread_1(void *arg) {
	xErrorsTestShared * shared = (xErrorsTestShared*) arg;
	// wait to be told to start.
#ifdef __APPLE__
	kern_return_t se = semaphore_wait(shared->sync_barrier);
	if (se != 0) {
		fprintf(stderr, "sem_wait failed: %d\n", se);
		shared->failure = true;
	}
#else
	if (sem_wait(&shared->sync_barrier) != 0) {
		fprintf(stderr, "sem_wait failed: %s\n", strerror(errno));
		shared->failure = true;
	}
#endif
	tsk_error_set_errno(42);
	tsk_error_set_errstr("I just set errno to %d.", 42);
	tsk_error_set_errstr2("Indeed, I just set errno to %d.", 42);
#ifdef __APPLE__
	se = semaphore_signal(shared->sync_barrier);
	if (se != 0) {
		fprintf(stderr, "sem_signal failed: %d\n", se);
		shared->failure = true;
	}
	se = semaphore_wait(shared->sync_barrier);
	if (se != 0) {
		fprintf(stderr, "sem_wait failed: %d\n", se);
		shared->failure = true;
	}
#else
	sem_post(&shared->sync_barrier);
	sem_wait(&shared->sync_barrier);
#endif
	shared->errno_check_failed = 42 != tsk_error_get_errno();
	char const * s = tsk_error_get_errstr();
	shared->errstr_check_failed = 0 != strcmp("I just set errno to 42.", s);
	s = tsk_error_get_errstr2();
	shared->errstr2_check_failed = 0 != strcmp("Indeed, I just set errno to 42.", s);
	return 0;
}
Exemple #6
0
/**
 * \internal
 * Searches an exFAT file system for its volume label directory entry, which 
 * should be in the root directory of the file system. If the entry is found, 
 * its metadata is copied into the TSK_FS_META object of a TSK_FS_FILE object.
 *
 * @param [in] a_fatfs Generic FAT file system info structure.
 * @param [out] a_fatfs Generic file system file structure.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t
exfatfs_find_volume_label_dentry(FATFS_INFO *a_fatfs, TSK_FS_FILE *a_fs_file)
{
    const char *func_name = "exfatfs_find_volume_label_dentry";
    TSK_FS_INFO *fs = (TSK_FS_INFO *)a_fatfs;
    TSK_DADDR_T current_sector = 0;
    TSK_DADDR_T last_sector_of_data_area = 0;
    char *sector_buf = NULL;
    ssize_t bytes_read = 0;
    TSK_INUM_T current_inum = 0;
    FATFS_DENTRY *dentry = NULL;
    uint64_t i = 0;

    assert(a_fatfs != NULL);
    assert(a_fs_file != NULL);

    tsk_error_reset();
    if (fatfs_ptr_arg_is_null(a_fatfs, "a_fatfs", func_name) ||
        fatfs_ptr_arg_is_null(a_fs_file, "a_fs_file", func_name)) {
        return FATFS_FAIL; 
    }

    /* Allocate or reset the TSK_FS_META object. */
    if (a_fs_file->meta == NULL) {
        if ((a_fs_file->meta =
                tsk_fs_meta_alloc(FATFS_FILE_CONTENT_LEN)) == NULL) {
            return FATFS_FAIL;
        }
    }
    else {
        tsk_fs_meta_reset(a_fs_file->meta);
    }

    /* Allocate a buffer for reading in sector-size chunks of the image. */
    if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) {
        return FATFS_FAIL;
    }

    current_sector = a_fatfs->rootsect;
    last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1;
    while (current_sector < last_sector_of_data_area) {
        int8_t sector_is_alloc = 0;

        /* Read in a sector from the root directory. The volume label
         * directory entry will probably be near the beginning of the 
         * directory, probably in the first sector. */
        bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize);
        if (bytes_read != a_fatfs->ssize) {
            if (bytes_read >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("%s: error reading sector: %" PRIuDADDR, func_name, current_sector);
            free(sector_buf);
            return FATFS_FAIL;
        }

        /* Get the allocation status of the sector (yes, it should be allocated). */
        sector_is_alloc = fatfs_is_sectalloc(a_fatfs, current_sector);
        if (sector_is_alloc == -1) {
            return FATFS_FAIL;
        }

        /* Get the inode address of the first directory entry of the sector. */
        current_inum = FATFS_SECT_2_INODE(a_fatfs, current_sector);

        /* Loop through the putative directory entries in the sector, 
         * until the volume label entry is found.  */
        for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) {
            dentry = (FATFS_DENTRY*)&(sector_buf[i]); 

            /* The type of the directory entry is encoded in the first byte 
             * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ 
            if (exfatfs_get_enum_from_type(dentry->data[0]) == EXFATFS_DIR_ENTRY_TYPE_VOLUME_LABEL) {
                if (!exfatfs_is_vol_label_dentry(dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN)) {
                    continue;
                }

                /* Found it, save it to the TSK_FS_META object of the 
                 * TSK_FS_FILE object and exit. */ 
                if (exfatfs_dinode_copy(a_fatfs, current_inum, dentry, 
                    sector_is_alloc, a_fs_file) == TSK_OK) {
                        return FATFS_OK;
                }
                else {
                    return FATFS_FAIL;
                }
            }
        }
    }

    free(sector_buf);
    return FATFS_OK;
}
Exemple #7
0
/**
 * \internal
 * Searches the root directory of an exFAT file system for an allocation bitmap
 * directory entry. If the entry is found, data from the entry is saved to a
 * FATFS_INFO object.
 *
 * @param [in, out] a_fatfs Generic FAT file system info structure.
 * @return 0 on success, 1 otherwise, per TSK convention.
 */
static uint8_t
exfatfs_get_alloc_bitmap(FATFS_INFO *a_fatfs)
{
    const char *func_name = "exfatfs_get_alloc_bitmap";
    TSK_FS_INFO *fs = &(a_fatfs->fs_info);
    TSK_DADDR_T current_sector = 0;
    TSK_DADDR_T last_sector_of_data_area = 0;
    char *sector_buf = NULL;
    EXFATFS_ALLOC_BITMAP_DIR_ENTRY *dentry = NULL;
    uint64_t i = 0;
    uint64_t first_sector_of_alloc_bitmap = 0;
    uint64_t alloc_bitmap_length_in_bytes = 0;
    uint64_t last_sector_of_alloc_bitmap = 0;

    assert(a_fatfs != NULL);
    
    if ((sector_buf = (char*)tsk_malloc(a_fatfs->ssize)) == NULL) {
        return FATFS_FAIL;
    }

    last_sector_of_data_area = a_fatfs->firstdatasect + (a_fatfs->clustcnt * a_fatfs->csize) - 1;
    for (current_sector = a_fatfs->rootsect; current_sector < last_sector_of_data_area; current_sector++) {
        ssize_t bytes_read = 0;

        /* Read in a sector from the root directory. The allocation bitmap
         * directory entries will probably be near the beginning of the 
         * directory, probably in the first sector. */
        bytes_read = tsk_fs_read_block(fs, current_sector, sector_buf, a_fatfs->ssize);
        if (bytes_read != a_fatfs->ssize) {
            if (bytes_read >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("%s: sector: %" PRIuDADDR, func_name, current_sector);
            free(sector_buf);
            return FATFS_FAIL;
        }

        /* Read the directory entries in the sector, looking for allocation
         * bitmap entries. There will be one entry unless the file system is 
         * TexFAT (transactional exFAT), in which case there will be two. */
        for (i = 0; i < a_fatfs->ssize; i += sizeof(FATFS_DENTRY)) {
            dentry = (EXFATFS_ALLOC_BITMAP_DIR_ENTRY*)&(sector_buf[i]); 

            /* The type of the directory entry is encoded in the first byte 
             * of the entry. See EXFATFS_DIR_ENTRY_TYPE_ENUM. */ 
            if (exfatfs_get_enum_from_type(dentry->entry_type) == EXFATFS_DIR_ENTRY_TYPE_ALLOC_BITMAP) {
                /* Do an in-depth test. */
                if (!exfatfs_is_alloc_bitmap_dentry((FATFS_DENTRY*)dentry, FATFS_DATA_UNIT_ALLOC_STATUS_UNKNOWN, a_fatfs)) {
                    continue;
                }

                /* The first bit of the flags byte is 0 for the first 
                 * allocation bitmap directory entry and 1 for the second 
                 * bitmap directory entry. If TexFAT is in use and there are
                 * two allocation bitmaps, the first bitmap should be the
                 * stable copy of the last known good allocation bitmap. 
                 * Therefore, the SleuthKit will use the first bitmap to 
                 * determine which clusters are allocated. */
                if (~(dentry->flags & 0x01)) {
                    first_sector_of_alloc_bitmap = FATFS_CLUST_2_SECT(a_fatfs, tsk_getu32(fs->endian, dentry->first_cluster_of_bitmap));
                    alloc_bitmap_length_in_bytes = tsk_getu64(fs->endian, dentry->length_of_alloc_bitmap_in_bytes);
                    last_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap + (roundup(alloc_bitmap_length_in_bytes, a_fatfs->ssize) / a_fatfs->ssize) - 1;

                    /* The allocation bitmap must lie within the boundaries of the data area. 
                     * It also must be big enough for the number of clusters reported in the VBR. */
                    if ((first_sector_of_alloc_bitmap >= a_fatfs->firstdatasect) &&
                        (last_sector_of_alloc_bitmap <= last_sector_of_data_area) &&
                        (alloc_bitmap_length_in_bytes >= (a_fatfs->clustcnt + 7) / 8))
                    {
                        a_fatfs->EXFATFS_INFO.first_sector_of_alloc_bitmap = first_sector_of_alloc_bitmap; 
                        a_fatfs->EXFATFS_INFO.length_of_alloc_bitmap_in_bytes = alloc_bitmap_length_in_bytes;
                        free(sector_buf);
                        return FATFS_OK;
                    }
                }
            }
        }
    }
    free(sector_buf);

    return FATFS_FAIL;
}
/**
 * Find the corresponding name at a
 * given offset.  The offset was likely determined from the index.
 * The entries in the DB following the one specified are also processed
 * if they have the same hash value and their name is different. 
 * The callback is called for each entry. 
 *
 * @param hdb_info Database to get data from.
 * @param hash MD5/SHA-1 hash value that was searched for
 * @param offset Byte offset where hash value should be located in db_file
 * @param flags (not used)
 * @param action Callback used for each entry found in lookup
 * @param cb_ptr Pointer to data passed to callback
 *
 * @return 1 on error and 0 on success
 */
uint8_t
nsrl_getentry(TSK_HDB_INFO * hdb_info, const char *hash, TSK_OFF_T offset,
              TSK_HDB_FLAG_ENUM flags,
              TSK_HDB_LOOKUP_FN action, void *cb_ptr)
{
    char buf[TSK_HDB_MAXLEN], *name, *cur_hash, pname[TSK_HDB_MAXLEN];
    int found = 0;
    int ver;

    if (tsk_verbose)
        fprintf(stderr,
                "nsrl_getentry: Lookup up hash %s at offset %" PRIuOFF
                "\n", hash, offset);

    if ((hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID)
        && (strlen(hash) != TSK_HDB_HTYPE_MD5_LEN)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Invalid hash value (expected to be MD5): %s\n",
                 hash);
        return 1;
    }
    else if ((hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID)
             && (strlen(hash) != TSK_HDB_HTYPE_SHA1_LEN)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Invalid hash value (expected to be SHA1): %s\n",
                 hash);
        return 1;
    }

    /* read the header line ... -- this should be done only once... */
    fseeko(hdb_info->hDb, 0, SEEK_SET);
    if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_READDB);
        tsk_error_set_errstr(
                 "nsrl_getentry: Error reading NSRLFile.txt header\n");
        return 1;
    }

    if ((ver = get_format_ver(buf)) == -1) {
        tsk_error_set_errstr2( "nsrl_getentry");
        return 1;
    }

    memset(pname, '0', TSK_HDB_MAXLEN);

    /* Loop so that we can find consecutive occurances of the same hash */
    while (1) {
        size_t len;

        if (0 != fseeko(hdb_info->hDb, offset, SEEK_SET)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "nsrl_getentry: Error seeking to get file name: %lu",
                     (unsigned long) offset);
            return 1;
        }

        if (NULL == fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb)) {
            if (feof(hdb_info->hDb))
                break;

            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_READDB);
            tsk_error_set_errstr(
                     "nsrl_getentry: Error reading database");
            return 1;
        }

        len = strlen(buf);
        if (len < TSK_HDB_HTYPE_SHA1_LEN + 5) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
            tsk_error_set_errstr(
                     "nsrl_getentry: Invalid entry in database (too short): %s",
                     buf);
            return 1;
        }

        /* Which field are we looking for */
        if (hdb_info->hash_type == TSK_HDB_HTYPE_SHA1_ID) {
            if (nsrl_parse_sha1(buf, &cur_hash, &name, ver)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
                tsk_error_set_errstr(
                         "nsrl_getentry: Invalid entry in database: %s",
                         buf);
                return 1;
            }
        }
        else if (hdb_info->hash_type == TSK_HDB_HTYPE_MD5_ID) {
            if (nsrl_parse_md5(buf, &cur_hash, &name, ver)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
                tsk_error_set_errstr(
                         "nsrl_getentry: Invalid entry in database: %s",
                         buf);
                return 1;
            }
        }

        /* Verify that this is the hash we are looking for */
        if (0 != strcasecmp(cur_hash, hash)) {
            break;
        }

        /* Check if this is the same name as the previous entry */
        if (strcmp(name, pname) != 0) {
            int retval;
            retval = action(hdb_info, hash, name, cb_ptr);
            if (retval == TSK_WALK_STOP)
                return 0;
            else if (retval == TSK_WALK_ERROR)
                return 1;

            found = 1;
            strncpy(pname, name, TSK_HDB_MAXLEN);
        }

        /* Advance to the next row */
        offset += len;
    }

    if (found == 0) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_ARG);
        tsk_error_set_errstr(
                 "nsrl_getentry: Hash not found in file at offset: %lu",
                 (unsigned long) offset);
        return 1;
    }

    return 0;
}
/**
 * Process the database to create a sorted index of it. Consecutive
 * entries with the same hash value are not added to the index, but
 * will be found during lookup.
 *
 * @param hdb_info Hash database to make index of.
 * @param dbtype Type of database 
 *
 * @return 1 on error and 0 on success.
 */
uint8_t
nsrl_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype)
{
    size_t i, len;
    char buf[TSK_HDB_MAXLEN];
    char *hash = NULL, phash[TSK_HDB_HTYPE_SHA1_LEN + 1];
    TSK_OFF_T offset = 0;
    int ver = 0;
    int db_cnt = 0, idx_cnt = 0, ig_cnt = 0;

    if (tsk_hdb_idxinitialize(hdb_info, dbtype)) {
        tsk_error_set_errstr2( "nsrl_makeindex");
        return 1;
    }

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
                 hdb_info->db_fname);

    /* Allocate a buffer for the previous hash value */
    memset(phash, '0', TSK_HDB_HTYPE_SHA1_LEN + 1);

    /* read the file */
    fseek(hdb_info->hDb, 0, SEEK_SET);
    for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb);
         offset += len, i++) {

        len = strlen(buf);

        /* Get the version of the database on the first time around */
        if (i == 0) {
            if ((ver = get_format_ver(buf)) == -1) {
                return 1;
            }
            ig_cnt++;
            continue;
        }

        /* Parse the line */
        if (hdb_info->hash_type & TSK_HDB_HTYPE_SHA1_ID) {
            if (nsrl_parse_sha1(buf, &hash, NULL, ver)) {
                ig_cnt++;
                continue;
            }
        }
        else if (hdb_info->hash_type & TSK_HDB_HTYPE_MD5_ID) {
            if (nsrl_parse_md5(buf, &hash, NULL, ver)) {
                ig_cnt++;
                continue;
            }
        }

        db_cnt++;

        /* We only want to add one of each hash to the index */
        if (memcmp(hash, phash, hdb_info->hash_len) == 0) {
            continue;
        }

        /* Add the entry to the index */
        if (tsk_hdb_idxaddentry(hdb_info, hash, offset)) {
            tsk_error_set_errstr2( "nsrl_makeindex");
            return 1;
        }

        idx_cnt++;

        /* Set the previous has value */
        strncpy(phash, hash, hdb_info->hash_len + 1);
    }

    if (idx_cnt > 0) {
        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr,
                    "  Invalid Database Entries (headers or errors): %d\n",
                    ig_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                    (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Close and sort the index */
        if (tsk_hdb_idxfinalize(hdb_info)) {
            tsk_error_set_errstr2( "nsrl_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
                 "nsrl_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}
Exemple #10
0
/*
 * Load the primary partition table (MBR) into the internal
 * data structures in TSK_VS_INFO
 *
 * This will automatically call load_ext_table for extended
 * partitions
 *
 * sect_cur is the address of the table to load
 *
 * 0 is returned if the load is successful and 1 if error
 */
static uint8_t
dos_load_prim_table(TSK_VS_INFO * vs, uint8_t test)
{
    dos_sect *sect;
    char *sect_buf;
    int i, added = 0;
    char *table_str;
    ssize_t cnt;
    TSK_DADDR_T taddr = vs->offset / vs->block_size + DOS_PART_SOFFSET;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "dos_load_prim: Table Sector: %" PRIuDADDR "\n", taddr);

    if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
        return 1;
    sect = (dos_sect *) sect_buf;

    /* Read the table */
    cnt = tsk_vs_read_block
        (vs, DOS_PART_SOFFSET, sect_buf, vs->block_size);

    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("Primary DOS table sector %" PRIuDADDR,
            taddr);
        free(sect_buf);
        return 1;
    }


    /* Sanity Check */
    if (tsk_vs_guessu16(vs, sect->magic, DOS_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("File is not a DOS partition (invalid primary magic) (Sector: %"
            PRIuDADDR ")", taddr);
        if (tsk_verbose)
            fprintf(stderr,
                "File is not a DOS partition (invalid primary magic) (Sector: %"
                PRIuDADDR ")", taddr);
        free(sect_buf);
        return 1;
    }

    /* Because FAT and NTFS use the same magic - check for a
     * standard MS OEM name and sizes.  Not a great check, but we can't
     * really test the table entries.
     */
    if (test) {
        if (tsk_verbose)
            tsk_fprintf(stderr,
                "dos_load_prim_table: Testing FAT/NTFS conditions\n");

        if (strncmp("MSDOS", sect->oemname, 5) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: MSDOS OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: MSDOS OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("MSWIN", sect->oemname, 5) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: MSWIN OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: MSWIN OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("NTFS", sect->oemname, 4) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: NTFS OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: NTFS OEM name exists\n");
            free(sect_buf);
            return 1;
        }
        else if (strncmp("FAT", sect->oemname, 4) == 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_MAGIC);
            tsk_error_set_errstr
                ("dos_load_prim_table: FAT OEM name exists");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "dos_load_prim_table: FAT OEM name exists\n");
            free(sect_buf);
            return 1;
        }
    }

    /* Add an entry of 1 sector for the table  to the internal structure */
    if ((table_str = tsk_malloc(32)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(table_str, 32, "Primary Table (#0)");
    if (NULL == tsk_vs_part_add(vs, DOS_PART_SOFFSET, (TSK_DADDR_T) 1,
            TSK_VS_PART_FLAG_META, table_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }

    /* Cycle through the partition table */
    for (i = 0; i < 4; i++) {
        dos_part *part = &sect->ptable[i];

        /* We currently ignore CHS */
        uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
        uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_pri:0:%d    Start: %" PRIu32 "   Size: %" PRIu32
                "  Type: %d\n", i, part_start, part_size, part->ptype);

        if (part_size == 0)
            continue;

        // make sure the first couple are in the image bounds
        if ((i < 2) && (part_start > max_addr)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("dos_load_prim_table: Starting sector too large for image");
            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "Starting sector %" PRIu32 " too large for image\n",
                    part_start);
            free(sect_buf);
            return 1;
        }
#if 0
// I'm not sure if this is too strict ...
        else if ((part_start + part_size) > max_addr) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
            tsk_error_set_errstr
                ("dos_load_prim_table: Partition ends after image");
            return 1;
        }
#endif

        added = 1;

        /* Add the partition to the internal structure
         * If it is an extended partition, process it now */
        if (dos_is_ext(part->ptype)) {
            if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
                    dos_get_desc(part->ptype), 0, i)) {
                free(sect_buf);
                return 1;
            }

            if (dos_load_ext_table(vs, part_start, part_start, 1)) {
                if (tsk_verbose) {
                    fprintf(stderr,
                        "Error loading extended table, moving on");
                    tsk_error_print(stderr);
                }
                tsk_error_reset();
            }
        }
        else {
            if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) part_start,
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
                    dos_get_desc(part->ptype), 0, i)) {
                free(sect_buf);
                return 1;
            }
        }
    }
    free(sect_buf);

    if (added == 0) {
        if (tsk_verbose)
            tsk_fprintf(stderr, "dos_load_prim: No valid entries\n");

        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("dos_load_prim_table: No valid entries in primary table");
        return 1;
    }
    return 0;
}
Exemple #11
0
/**
 * Process the database to create a sorted index of it. Consecutive
 * entries with the same hash value are not added to the index, but
 * will be found during lookup.
 *
 * @param hdb_info Hash database to make index of
 * @param dbtype Text of database type (should always be TSK_HDB_DBTYPE_HK_STR)
 *
 * @return 1 on error and 0 on success.
 */
uint8_t
hk_makeindex(TSK_HDB_INFO * hdb_info, TSK_TCHAR * dbtype)
{
    int i;
    size_t len = 0;
    char buf[TSK_HDB_MAXLEN];
    char *hash = NULL, phash[TSK_HDB_HTYPE_MD5_LEN + 1];
    TSK_OFF_T offset = 0;
    int db_cnt = 0, idx_cnt = 0, ig_cnt = 0;

    if (tsk_hdb_idxinitialize(hdb_info, dbtype)) {
        tsk_error_set_errstr2( "hk_makeindex");
        return 1;
    }
    fseek(hdb_info->hDb, 0, SEEK_SET);

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
                 hdb_info->db_fname);

    /* Allocate a buffer to hold the previous hash values */
    memset(phash, '0', TSK_HDB_HTYPE_MD5_LEN + 1);

    /* read each line of the file */
    fseek(hdb_info->hDb, 0, SEEK_SET);
    for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb);
         offset += (TSK_OFF_T) len, i++) {

        len = strlen(buf);

        /* Parse each line to get the MD5 value */
        if (hk_parse_md5(buf, &hash, NULL, 0, NULL, 0)) {
            ig_cnt++;
            continue;
        }
        db_cnt++;

        /* If this entry is for the same hash value as the last entry,
         * the skip it -- we'll look for it during lookup */
        if (memcmp(hash, phash, TSK_HDB_HTYPE_MD5_LEN) == 0) {
            continue;
        }

        /* Add the entry to the index */
        if (tsk_hdb_idxaddentry(hdb_info, hash, offset)) {
            tsk_error_set_errstr2( "hk_makeindex");
            return 1;
        }

        idx_cnt++;

        /* Set the previous hash value */
        strncpy(phash, hash, TSK_HDB_HTYPE_MD5_LEN + 1);
    }

    if (idx_cnt > 0) {
        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr,
                    "  Invalid Database Entries (headers or errors): %d\n",
                    ig_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                    (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Finish the index making process */
        if (tsk_hdb_idxfinalize(hdb_info)) {
            tsk_error_set_errstr2( "hk_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
                 "hk_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}
Exemple #12
0
/**
 * \ingroup fslib
 * Read the contents of a given attribute using a typical read() type interface.
 * 0s are returned for missing runs. 
 * 
 * @param a_fs_attr The attribute to read.
 * @param a_offset The byte offset to start reading from.
 * @param a_buf The buffer to read the data into.
 * @param a_len The number of bytes to read from the file.
 * @param a_flags Flags to use while reading
 * @returns The number of bytes read or -1 on error (incl if offset is past end of file).
 */
ssize_t
tsk_fs_attr_read(const TSK_FS_ATTR * a_fs_attr, TSK_OFF_T a_offset,
    char *a_buf, size_t a_len, TSK_FS_FILE_READ_FLAG_ENUM a_flags)
{
    TSK_FS_INFO *fs;

    if ((a_fs_attr == NULL) || (a_fs_attr->fs_file == NULL)
        || (a_fs_attr->fs_file->fs_info == NULL)) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_attr_read: Attribute has null pointers.");
        return -1;
    }
    fs = a_fs_attr->fs_file->fs_info;

    /* for compressed data, call the specialized function */
    if (a_fs_attr->flags & TSK_FS_ATTR_COMP) {
        if (a_fs_attr->r == NULL) {
            tsk_error_set_errno(TSK_ERR_FS_ARG);
            tsk_error_set_errstr
                ("tsk_fs_attr_read: Attribute has compressed type set, but no compressed read function defined");
            return -1;
        }
        return a_fs_attr->r(a_fs_attr, a_offset, a_buf, a_len);
    }

    /* For resident data, copy data from the local buffer */
    else if (a_fs_attr->flags & TSK_FS_ATTR_RES) {
        size_t len_toread;

        if (a_offset >= a_fs_attr->size) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ_OFF);
            tsk_error_set_errstr("tsk_fs_attr_read - %" PRIuOFF, a_offset);
            return -1;
        }

        len_toread = a_len;
        if (a_offset + a_len > a_fs_attr->size) {
            len_toread = (size_t) (a_fs_attr->size - a_offset);
            memset(&a_buf[len_toread], 0, a_len - len_toread);
        }

        memcpy(a_buf, &a_fs_attr->rd.buf[a_offset], len_toread);

        return (ssize_t) len_toread;
    }

    /* For non-resident data, load the needed block and copy the data */
    else if (a_fs_attr->flags & TSK_FS_ATTR_NONRES) {
        TSK_FS_ATTR_RUN *data_run_cur;
        TSK_DADDR_T blkoffset_toread;   // block offset of where we want to start reading from
        size_t byteoffset_toread;       // byte offset in blkoffset_toread of where we want to start reading from
        size_t len_remain;      // length remaining to copy
        size_t len_toread;      // length total to copy

        if (((a_flags & TSK_FS_FILE_READ_FLAG_SLACK)
                && (a_offset >= a_fs_attr->nrd.allocsize))
            || (!(a_flags & TSK_FS_FILE_READ_FLAG_SLACK)
                && (a_offset >= a_fs_attr->size))) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ_OFF);
            tsk_error_set_errstr("tsk_fs_attr_read - %" PRIuOFF, a_offset);
            return -1;
        }

        blkoffset_toread = a_offset / fs->block_size;
        byteoffset_toread = (size_t) (a_offset % fs->block_size);

        // determine how many bytes we can copy
        len_toread = a_len;
        if (a_flags & TSK_FS_FILE_READ_FLAG_SLACK) {
            if (a_offset + a_len > a_fs_attr->nrd.allocsize)
                len_toread =
                    (size_t) (a_fs_attr->nrd.allocsize - a_offset);
        }
        else {
            if (a_offset + a_len > a_fs_attr->size)
                len_toread = (size_t) (a_fs_attr->size - a_offset);
        }
        // wipe the buffer we won't read into
        if (len_toread < a_len)
            memset(&a_buf[len_toread], 0, a_len - len_toread);

        len_remain = len_toread;

        // cycle through the run until we find where we can start to process the clusters
        for (data_run_cur = a_fs_attr->nrd.run; data_run_cur;
            data_run_cur = data_run_cur->next) {
            TSK_DADDR_T blkoffset_inrun;
            size_t len_inrun;

            // we are done
            if (len_remain <= 0)
                break;

            // See if this run contains the starting offset they requested
            if (data_run_cur->offset + data_run_cur->len <=
                blkoffset_toread)
                continue;

            // block offset into this run
            if (data_run_cur->offset < blkoffset_toread)
                blkoffset_inrun = blkoffset_toread - data_run_cur->offset;
            else
                blkoffset_inrun = 0;

            // see if we need to read the rest of this run and into the next or if it is all here
            len_inrun = len_remain;
            if ((data_run_cur->len - blkoffset_inrun) * fs->block_size -
                byteoffset_toread < len_remain)
                len_inrun =
                    (size_t) ((data_run_cur->len -
                        blkoffset_inrun) * fs->block_size -
                    byteoffset_toread);

            /* sparse files/runs just get 0s */
            if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
            }
            /* FILLER entries exist when the source file system can store run
             * info out of order and we did not get all of the run info.  We
             * return 0s if data is read from this type of run. */
            else if (data_run_cur->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
                if (tsk_verbose)
                    fprintf(stderr,
                        "tsk_fs_attr_read_type: File %" PRIuINUM
                        " has FILLER entry, using 0s\n",
                        (a_fs_attr->fs_file->meta) ? a_fs_attr->fs_file->
                        meta->addr : 0);
            }
            // we return 0s for reads past the initsize (unless they want slack space)
            else if (((TSK_OFF_T) ((data_run_cur->offset +
                            blkoffset_inrun) * fs->block_size +
                        byteoffset_toread) >= a_fs_attr->nrd.initsize)
                && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                memset(&a_buf[len_toread - len_remain], 0, len_inrun);
                if (tsk_verbose)
                    fprintf(stderr,
                        "tsk_fs_attr_read: Returning 0s for read past end of initsize (%"
                        PRIuINUM ")\n", ((a_fs_attr->fs_file)
                            && (a_fs_attr->fs_file->meta)) ? a_fs_attr->
                        fs_file->meta->addr : 0);
            }
            else {
                TSK_OFF_T fs_offset_b;
                ssize_t cnt;

                // calcuate the byte offset in the file system
                fs_offset_b =
                    (data_run_cur->addr +
                    blkoffset_inrun) * fs->block_size;

                // add the byte offset in the block
                fs_offset_b += byteoffset_toread;

                // reset this in case we need to also read from the next run 
                byteoffset_toread = 0;

                cnt =
                    tsk_fs_read(fs, fs_offset_b,
                    &a_buf[len_toread - len_remain], len_inrun);
                if (cnt != len_inrun) {
                    if (cnt >= 0) {
                        tsk_error_reset();
                        tsk_error_set_errno(TSK_ERR_FS_READ);
                    }
                    tsk_error_set_errstr2
                        ("tsk_fs_attr_read_type: offset: %" PRIuOFF
                        "  Len: %" PRIuSIZE "", fs_offset_b, len_inrun);
                    return cnt;
                }

                // see if part of the data is in the non-initialized space
                if (((TSK_OFF_T) ((data_run_cur->offset +
                                blkoffset_inrun) * fs->block_size +
                            byteoffset_toread + len_inrun) >
                        a_fs_attr->nrd.initsize)
                    && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {

                    size_t uninit_off = a_fs_attr->nrd.initsize -
                        ((data_run_cur->offset +
                            blkoffset_inrun) * fs->block_size +
                        byteoffset_toread);

                    memset(&a_buf[len_toread - len_remain + uninit_off], 0,
                        len_inrun - uninit_off);
                }

            }
            len_remain -= len_inrun;
        }
        return (ssize_t) (len_toread - len_remain);
    }

    tsk_error_set_errno(TSK_ERR_FS_ARG);
    tsk_error_set_errstr("tsk_fs_attr_read: Unknown attribute type: %x",
        a_fs_attr->flags);
    return -1;
}
Exemple #13
0
/** \internal
 * Process a directory and load up FS_DIR with the entries. If a pointer to
 * an already allocated FS_DIR struture is given, it will be cleared.  If no existing
 * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return
 * value is error or corruption, then the FS_DIR structure could
 * have entries (depending on when the error occured).
 *
 * @param a_fs File system to analyze
 * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated
 * structure or a new structure.
 * @param a_addr Address of directory to process.
 * @returns error, corruption, ok etc.
 */
TSK_RETVAL_ENUM
iso9660_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir,
    TSK_INUM_T a_addr)
{
    TSK_RETVAL_ENUM retval;
    TSK_FS_DIR *fs_dir;
    ssize_t cnt;
    char *buf;
    size_t length;

    if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr
            ("iso9660_dir_open_meta: Invalid inode value: %" PRIuINUM,
            a_addr);
        return TSK_ERR;
    }
    else if (a_fs_dir == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("iso9660_dir_open_meta: NULL fs_attr argument given");
        return TSK_ERR;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "iso9660_dir_open_meta: Processing directory %" PRIuINUM "\n",
            a_addr);

    fs_dir = *a_fs_dir;
    if (fs_dir) {
        tsk_fs_dir_reset(fs_dir);
    }
    else {
        if ((*a_fs_dir = fs_dir =
                tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) {
            return TSK_ERR;
        }
    }

    //  handle the orphan directory if its contents were requested
    if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) {
        return tsk_fs_dir_find_orphans(a_fs, fs_dir);
    }

    fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr);
    if (fs_dir->fs_file == NULL) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_INODE_NUM);
        tsk_error_set_errstr("iso9660_dir_open_meta: %" PRIuINUM
            " is not a valid inode", a_addr);
        return TSK_COR;
    }

    /* read directory extent into memory */
    length = (size_t) fs_dir->fs_file->meta->size;
    if ((buf = tsk_malloc(length)) == NULL)
        return TSK_ERR;

    cnt = tsk_fs_file_read(fs_dir->fs_file, 0, buf, length, 0);
    if (cnt != length) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ);
        }
        tsk_error_set_errstr2("iso9660_dir_open_meta");
        return TSK_ERR;
    }

    // process the contents
    retval = iso9660_proc_dir(a_fs, fs_dir, buf, length, a_addr,
        fs_dir->fs_file->meta->attr->head->nrd.run->addr);

    // if we are listing the root directory, add the Orphan directory entry
    if (a_addr == a_fs->root_inum) {
        TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0);
        if (fs_name == NULL)
            return TSK_ERR;

        if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }

        if (tsk_fs_dir_add(fs_dir, fs_name)) {
            tsk_fs_name_free(fs_name);
            return TSK_ERR;
        }
        tsk_fs_name_free(fs_name);
    }

    return retval;
}
/* 
 * Process the partition table at the sector address 
 *
 * This method just finds out if it is sparc or Intel and then
 * calls the appropriate method
 *
 * Return 0 on success and 1 on error
 */
static uint8_t
sun_load_table(TSK_VS_INFO * vs)
{
    sun_dlabel_sparc *dlabel_sp;
    sun_dlabel_i386 *dlabel_x86;
    char *buf;
    ssize_t cnt;
    TSK_DADDR_T taddr =
        vs->offset / vs->block_size + SUN_SPARC_PART_SOFFSET;
    int result = 0;


    /* Sanity check in case label sizes change */
    if ((sizeof(*dlabel_sp) > vs->block_size) ||
        (sizeof(*dlabel_x86) > vs->block_size)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_BUF);
        tsk_error_set_errstr
            ("sun_load_table: disk labels bigger than block size");
        return 1;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr);

    if ((buf = tsk_malloc(vs->block_size)) == NULL) {
        goto on_error;
    }

    /* Try the given offset */
    cnt = tsk_vs_read_block
        (vs, SUN_SPARC_PART_SOFFSET, buf, vs->block_size);

    /* If -1 is returned, tsk_errno is already set */
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("SUN Disk Label in Sector: %" PRIuDADDR,
            taddr);
        goto on_error;
    }


    /* Check the magic value 
     * Both intel and sparc have the magic value in the same location
     *
     * We try both in case someone specifies the exact location of the
     * intel disk label.
     * */
    dlabel_sp = (sun_dlabel_sparc *) buf;
    dlabel_x86 = (sun_dlabel_i386 *) buf;
    if (tsk_vs_guessu16(vs, dlabel_sp->magic, SUN_MAGIC) == 0) {
        if (tsk_getu32(vs->endian, dlabel_sp->sanity) == SUN_SANITY) {
            result = sun_load_table_sparc(vs, dlabel_sp);
            // TODO: I assume based on the existing free that the previous function
            // does not take ownership of buf.
            free(buf);
            return result;
        }
        else if (tsk_getu32(vs->endian, dlabel_x86->sanity) == SUN_SANITY) {
            result = sun_load_table_i386(vs, dlabel_x86);
            // TODO: I assume based on the existing free that the previous function
            // does not take ownership of buf.
            free(buf);
            return result;
        }
    }


    /* Now try the next sector, which is where the intel 
     * could be stored */

    taddr = vs->offset / vs->block_size / SUN_I386_PART_SOFFSET;
    if (tsk_verbose)
        tsk_fprintf(stderr,
            "sun_load_table: Trying sector: %" PRIuDADDR "\n", taddr + 1);

    cnt = tsk_vs_read_block
        (vs, SUN_I386_PART_SOFFSET, buf, vs->block_size);

    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("SUN (Intel) Disk Label in Sector: %"
            PRIuDADDR, taddr);
        goto on_error;
    }

    dlabel_x86 = (sun_dlabel_i386 *) buf;
    if (tsk_vs_guessu16(vs, dlabel_x86->magic, SUN_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("SUN (intel) partition table (Sector: %"
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
                dlabel_sp->magic));
        goto on_error;
    }

    if (tsk_getu32(vs->endian, dlabel_x86->sanity) != SUN_SANITY) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("SUN (intel) sanity value (Sector: %"
            PRIuDADDR ") %x", taddr, tsk_getu16(vs->endian,
                dlabel_sp->magic));
        goto on_error;
    }

    result = sun_load_table_i386(vs, dlabel_x86);
    // TODO: I assume based on the existing free that the previous function
    // does not take ownership of buf.
    free(buf);
    return result;

on_error:
    if( buf != NULL ) {
        free( buf );
    }
    return 1;
}
Exemple #15
0
/**
* Process the database to create a sorted index of it. Consecutive
* entries with the same hash value are not added to the index, but
* will be found during lookup.
*
* @param hdb_info_base Hash database to make index of.
* @param dbtype Type of hash database (should always be TSK_HDB_DBTYPE_MD5SUM_STR)
*
* @return 1 on error and 0 on success.
*/
uint8_t
    md5sum_makeindex(TSK_HDB_INFO *hdb_info_base, TSK_TCHAR * dbtype)
{
    TSK_HDB_BINSRCH_INFO *hdb_info = (TSK_HDB_BINSRCH_INFO*)hdb_info_base;
    int i;
    char buf[TSK_HDB_MAXLEN];
    char *hash = NULL, phash[TSK_HDB_HTYPE_MD5_LEN + 1];
    TSK_OFF_T offset = 0;
    int db_cnt = 0, idx_cnt = 0, ig_cnt = 0;
    size_t len;

    /* Initialize the TSK index file */
    if (hdb_binsrch_idx_initialize(hdb_info, dbtype)) {
        tsk_error_set_errstr2( "md5sum_makeindex");
        return 1;
    }

    /* Status */
    if (tsk_verbose)
        TFPRINTF(stderr, _TSK_T("Extracting Data from Database (%s)\n"),
        hdb_info->base.db_fname);

    /* Allocate a buffer for the previous hash value */
    memset(phash, '0', TSK_HDB_HTYPE_MD5_LEN + 1);

    /* read the file and add to the index */
    fseek(hdb_info->hDb, 0, SEEK_SET);
    for (i = 0; NULL != fgets(buf, TSK_HDB_MAXLEN, hdb_info->hDb);
        offset += (TSK_OFF_T) len, i++) {

            len = strlen(buf);

            /* Parse each line */
            if (md5sum_parse_md5(buf, &hash, NULL)) {
                ig_cnt++;
                continue;
            }
            db_cnt++;

            /* We only want to add one of each hash to the index */
            if (memcmp(hash, phash, TSK_HDB_HTYPE_MD5_LEN) == 0) {
                continue;
            }

            /* Add the entry to the index */
            if (hdb_binsrch_idx_add_entry_str(hdb_info, hash, offset)) {
                tsk_error_set_errstr2( "md5sum_makeindex");
                return 1;
            }

            idx_cnt++;

            /* Set the previous has value */
            strncpy(phash, hash, TSK_HDB_HTYPE_MD5_LEN + 1);
    }

    if (idx_cnt > 0) {

        if (tsk_verbose) {
            fprintf(stderr, "  Valid Database Entries: %d\n", db_cnt);
            fprintf(stderr,
                "  Invalid Database Entries (headers or errors): %d\n",
                ig_cnt);
            fprintf(stderr, "  Index File Entries %s: %d\n",
                (idx_cnt == db_cnt) ? "" : "(optimized)", idx_cnt);
        }

        /* Close and sort the index */
        if (hdb_binsrch_idx_finalize(hdb_info)) {
            tsk_error_set_errstr2( "md5sum_makeindex");
            return 1;
        }
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_HDB_CORRUPT);
        tsk_error_set_errstr(
            "md5sum_makeindex: No valid entries found in database");
        return 1;
    }

    return 0;
}
Exemple #16
0
uint8_t
fatxxfs_open(FATFS_INFO *fatfs)
{
    const char *func_name = "fatxxfs_open";
	TSK_FS_INFO *fs = &(fatfs->fs_info);
	FATXXFS_SB *fatsb = (FATXXFS_SB*)(&fatfs->boot_sector_buffer);
	int i = 0;
    TSK_DADDR_T sectors = 0;
	TSK_FS_DIR * test_dir1; // Directories used to try opening the root directory

    // clean up any error messages that are lying around
    tsk_error_reset();

    /* Calculate block sizes and layout info */
    // sector size
    fatfs->ssize = tsk_getu16(fs->endian, fatsb->ssize);
    if (fatfs->ssize == 512) {
        fatfs->ssize_sh = 9;
    }
    else if (fatfs->ssize == 1024) {
        fatfs->ssize_sh = 10;
    }
    else if (fatfs->ssize == 2048) {
        fatfs->ssize_sh = 11;
    }
    else if (fatfs->ssize == 4096) {
        fatfs->ssize_sh = 12;
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Error: sector size (%d) is not a multiple of device size (%d)\nDo you have a disk image instead of a partition image?",
            fatfs->ssize, fs->dev_bsize);
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid sector size (%d)\n",
                func_name, fatfs->ssize);
        return 1;
    }

    // cluster size 
    fatfs->csize = fatsb->csize;
    if ((fatfs->csize != 0x01) &&
        (fatfs->csize != 0x02) &&
        (fatfs->csize != 0x04) &&
        (fatfs->csize != 0x08) &&
        (fatfs->csize != 0x10) &&
        (fatfs->csize != 0x20) &&
        (fatfs->csize != 0x40) && (fatfs->csize != 0x80)) {
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid cluster size (%d)\n",
                func_name, fatfs->csize);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not a FATXX file system (cluster size)");
        return 1;
    }

    // number of FAT tables
    fatfs->numfat = fatsb->numfat;
    if ((fatfs->numfat == 0) || (fatfs->numfat > 8)) {
        if (tsk_verbose)
            fprintf(stderr, "%s: Invalid number of FATS (%d)\n",
                func_name, fatfs->numfat);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr("Not a FATXX file system (number of FATs)");
        return 1;
    }

    /* We can't do a sanity check on this b.c. TSK_FS_TYPE_FAT32 has a value of 0 */
    /* num of root entries */
    fatfs->numroot = tsk_getu16(fs->endian, fatsb->numroot);

    /* if sectors16 is 0, then the number of sectors is stored in sectors32 */
    if (0 == (sectors = tsk_getu16(fs->endian, fatsb->sectors16)))
        sectors = tsk_getu32(fs->endian, fatsb->sectors32);

    /* if secperfat16 is 0, then read sectperfat32 */
    if (0 == (fatfs->sectperfat =
            tsk_getu16(fs->endian, fatsb->sectperfat16)))
        fatfs->sectperfat =
            tsk_getu32(fs->endian, fatsb->a.f32.sectperfat32);

    if (fatfs->sectperfat == 0) {
        if (tsk_verbose)
            fprintf(stderr,
                "%s: Invalid number of sectors per FAT (%d)\n",
                func_name, fatfs->sectperfat);
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Not a FATXX file system (invalid sectors per FAT)");
        return 1;
    }

    fatfs->firstfatsect = tsk_getu16(fs->endian, fatsb->reserved);
    if ((fatfs->firstfatsect == 0) || (fatfs->firstfatsect > sectors)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr
            ("Not a FATXX file system (invalid first FAT sector %"
            PRIuDADDR ")", fatfs->firstfatsect);
        if (tsk_verbose)
            fprintf(stderr,
                "%s: Invalid first FAT (%" PRIuDADDR ")\n",
                func_name, fatfs->firstfatsect);
        return 1;
    }

    /* Calculate the block info
     * 
     * The sector of the beginning of the data area  - which is 
     * after all of the FATs
     *
     * For TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16, the data area starts with the root
     * directory entries and then the first cluster.  For TSK_FS_TYPE_FAT32,
     * the data area starts with clusters and the root directory
     * is somewhere in the data area
     */
    fatfs->firstdatasect = fatfs->firstfatsect +
        fatfs->sectperfat * fatfs->numfat;

    /* The sector where the first cluster is located.  It will be used
     * to translate cluster addresses to sector addresses 
     *
     * For TSK_FS_TYPE_FAT32, the first cluster is the start of the data area and
     * it is after the root directory for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16.  At this
     * point in the program, numroot is set to 0 for TSK_FS_TYPE_FAT32
     */
    fatfs->firstclustsect = fatfs->firstdatasect +
        ((fatfs->numroot * 32 + fatfs->ssize - 1) / fatfs->ssize);

    /* total number of clusters */
    fatfs->clustcnt = (sectors - fatfs->firstclustsect) / fatfs->csize;

    /* the first cluster is #2, so the final cluster is: */
    fatfs->lastclust = 1 + fatfs->clustcnt;


    /* identify the FAT type by the total number of data clusters
     * this calculation is from the MS FAT Overview Doc
     *
     * A FAT file system made by another OS could use different values
     */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT_DETECT) {

        if (fatfs->clustcnt < 4085) {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT12;
        }
        else if (fatfs->clustcnt < 65525) {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT16;
        }
        else {
            fatfs->fs_info.ftype = TSK_FS_TYPE_FAT32;
        }

        fatfs->fs_info.ftype = fatfs->fs_info.ftype;
    }

    /* Some sanity checks */
    else {
        if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12)
            && (fatfs->clustcnt >= 4085)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_MAGIC);
            tsk_error_set_errstr
                ("Too many sectors for TSK_FS_TYPE_FAT12: try auto-detect mode");
            if (tsk_verbose)
                fprintf(stderr,
                    "%s: Too many sectors for FAT12\n", func_name);
            return 1;
        }
    }

    if ((fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) && (fatfs->numroot != 0)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Invalid TSK_FS_TYPE_FAT32 image (numroot != 0)");
        if (tsk_verbose)
            fprintf(stderr, "%s: numroom != 0 for FAT32\n", func_name);
        return 1;
    }

    if ((fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) && (fatfs->numroot == 0)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_MAGIC);
        tsk_error_set_errstr
            ("Invalid FAT image (numroot == 0, and not TSK_FS_TYPE_FAT32)");
        if (tsk_verbose)
            fprintf(stderr, "%s: numroom == 0 and not FAT32\n", func_name);
        return 1;
    }

    /* additional sanity checks if we think we are using the backup boot sector.
     * The scenario to prevent here is if fat_open is called 6 sectors before the real start
     * of the file system, then we want to detect that it was not a backup that we saw.  
     */
    if (fatfs->using_backup_boot_sector) {
        // only FAT32 has backup boot sectors..
        if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_MAGIC);
            tsk_error_set_errstr
                ("Invalid FAT image (Used what we thought was a backup boot sector, but it is not TSK_FS_TYPE_FAT32)");
            if (tsk_verbose)
                fprintf(stderr,
                    "%s: Had to use backup boot sector, but this isn't FAT32\n", func_name);
            return 1;
        }
        if (fatfs->numroot > 1) {
            uint8_t buf1[512];
            uint8_t buf2[512];
            int i2;
            int numDiffs;
	        ssize_t cnt = 0;

            cnt =
                tsk_fs_read(fs, fatfs->firstfatsect * fatfs->ssize,
                (char *) buf1, 512);
            if (cnt != 512) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2("%s: FAT1", func_name);
                fs->tag = 0;
                return 1;
            }

            cnt =
                tsk_fs_read(fs,
                (fatfs->firstfatsect + fatfs->sectperfat) * fatfs->ssize,
                (char *) buf2, 512);
            if (cnt != 512) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2("%s: FAT2", func_name);
                fs->tag = 0;
                return 1;
            }

            numDiffs = 0;
            for (i2 = 0; i2 < 512; i2++) {
                if (buf1[i2] != buf2[i2]) {
                    numDiffs++;
                }
            }
            if (numDiffs > 25) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_MAGIC);
                tsk_error_set_errstr
                    ("Invalid FAT image (Too many differences between FATS from guessing (%d diffs))",
                    numDiffs);
                if (tsk_verbose)
                    fprintf(stderr,
                        "%s: Too many differences in FAT from guessing (%d diffs)\n",
                        func_name, numDiffs);
                return 1;
            }
        }
    }

    /* Set the mask to use on the cluster values */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT12) {
        fatfs->mask = FATFS_12_MASK;
    }
    else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT16) {
        fatfs->mask = FATFS_16_MASK;
    }
    else if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) {
        fatfs->mask = FATFS_32_MASK;
    }
    else {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr("Unknown FAT type in %s: %d\n",
            func_name, fatfs->fs_info.ftype);
        return 1;
    }
    fs->duname = "Sector";

    /* the root directories are always after the FAT for TSK_FS_TYPE_FAT12 and TSK_FS_TYPE_FAT16,
     * but are dynamically located for TSK_FS_TYPE_FAT32
     */
    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32)
        fatfs->rootsect = FATFS_CLUST_2_SECT(fatfs,
            tsk_getu32(fs->endian, fatsb->a.f32.rootclust));
    else
        fatfs->rootsect = fatfs->firstdatasect;

    for (i = 0; i < FATFS_FAT_CACHE_N; i++) {
        fatfs->fatc_addr[i] = 0;
        fatfs->fatc_ttl[i] = 0;
    }

    /*
     * block calculations : although there are no blocks in fat, we will
     * use these fields for sector calculations
     */
    fs->first_block = 0;
    fs->block_count = sectors;
    fs->last_block = fs->last_block_act = fs->block_count - 1;
    fs->block_size = fatfs->ssize;

    // determine the last block we have in this image
    if ((TSK_DADDR_T) ((fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size) <
        fs->block_count)
        fs->last_block_act =
            (fatfs->fs_info.img_info->size - fatfs->fs_info.offset) / fs->block_size - 1;

    /*
     * inode calculations
     */

    /* maximum number of dentries in a sector & cluster */
    fatfs->dentry_cnt_se = fatfs->ssize / sizeof(FATXXFS_DENTRY);
    fatfs->dentry_cnt_cl = fatfs->dentry_cnt_se * fatfs->csize;

    fs->root_inum = FATFS_ROOTINO;
    fs->first_inum = FATFS_FIRSTINO;

    /* Calculate inode addresses for the virtual files (MBR, one or two FATS) 
     * and the virtual orphan files directory. */
    fs->last_inum = (FATFS_SECT_2_INODE(fatfs, fs->last_block_act + 1) - 1) + FATFS_NUM_VIRT_FILES(fatfs);
    fatfs->mbr_virt_inum = fs->last_inum - FATFS_NUM_VIRT_FILES(fatfs) + 1;
    fatfs->fat1_virt_inum = fatfs->mbr_virt_inum + 1;
    if (fatfs->numfat == 2) {
        fatfs->fat2_virt_inum = fatfs->fat1_virt_inum + 1;
    }
    else {
        fatfs->fat2_virt_inum = fatfs->fat1_virt_inum;
    }

    /* Calculate the total number of inodes. */
    fs->inum_count = fs->last_inum - fs->first_inum + 1;

    /* Volume ID */
    for (fs->fs_id_used = 0; fs->fs_id_used < 4; fs->fs_id_used++) {
        if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32)
            fs->fs_id[fs->fs_id_used] =
                fatsb->a.f32.vol_id[fs->fs_id_used];
        else
            fs->fs_id[fs->fs_id_used] =
                fatsb->a.f16.vol_id[fs->fs_id_used];
    }

    /*
     * Set the function pointers  
     */

    fs->block_walk = fatfs_block_walk;
    fs->block_getflags = fatfs_block_getflags;

    fs->inode_walk = fatfs_inode_walk;
    fs->istat = fatfs_istat;
    fs->file_add_meta = fatfs_inode_lookup;

    fs->get_default_attr_type = fatfs_get_default_attr_type;
    fs->load_attrs = fatfs_make_data_runs;

    fs->dir_open_meta = fatfs_dir_open_meta;
    fs->name_cmp = fatfs_name_cmp;

    fs->fsstat = fatxxfs_fsstat;
    fs->fscheck = fatfs_fscheck;

    fs->close = fatfs_close;

    fs->jblk_walk = fatfs_jblk_walk;
    fs->jentry_walk = fatfs_jentry_walk;
    fs->jopen = fatfs_jopen;

    fatfs->is_cluster_alloc = fatxxfs_is_cluster_alloc;
    fatfs->is_dentry = fatxxfs_is_dentry;
    fatfs->dinode_copy =  fatxxfs_dinode_copy;
    fatfs->inode_lookup = fatxxfs_inode_lookup;
    fatfs->inode_walk_should_skip_dentry = fatxxfs_inode_walk_should_skip_dentry;
    fatfs->istat_attr_flags = fatxxfs_istat_attr_flags;
    fatfs->dent_parse_buf = fatxxfs_dent_parse_buf;

    // initialize the caches
    tsk_init_lock(&fatfs->cache_lock);
    tsk_init_lock(&fatfs->dir_lock);
    fatfs->inum2par = NULL;

	// Test to see if this is the odd Android case where the FAT entries have no short name
	//
	// If there are no entries found with the normal short name
	// and we find more entries by removing the short name test for allocated directories, then assume
	// this is the case where we have no short names
	fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC;
	test_dir1 = tsk_fs_dir_open_meta(fs, fs->root_inum);

	if (test_dir1 != NULL && test_dir1->names_used <= 4){ // At most four automatic directories ($MBR, $FAT1, $FAT1, $OrphanFiles)
	    TSK_FS_DIR * test_dir2; //  to see if it's the Android FAT version

		fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1;
		test_dir2 = tsk_fs_dir_open_meta(fs, fs->root_inum);

		if (test_dir2 != NULL && test_dir2->names_used > test_dir1->names_used){
			fatfs->subtype = TSK_FATFS_SUBTYPE_ANDROID_1;
		}
		else{
			fatfs->subtype = TSK_FATFS_SUBTYPE_SPEC;
		}
		tsk_fs_dir_close(test_dir2);
	}
	tsk_fs_dir_close(test_dir1);

    return 0;
}
Exemple #17
0
/** \internal
 *
 * return 1 on error and 0 on success
 */
uint8_t
tsk_fs_nofs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk,
    TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags,
    TSK_FS_BLOCK_WALK_CB a_action, void *a_ptr)
{
    TSK_FS_BLOCK *fs_block;
    TSK_DADDR_T addr;

    // clean up any error messages that are lying around
    tsk_error_reset();

    /*
     * Sanity checks.
     */
    if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("nofs_block_walk: Start block number: %"
            PRIuDADDR, a_start_blk);
        return 1;
    }

    if (a_end_blk < fs->first_block || a_end_blk > fs->last_block
        || a_end_blk < a_start_blk) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_WALK_RNG);
        tsk_error_set_errstr("nofs_block_walk: Last block number: %"
            PRIuDADDR, a_end_blk);
        return 1;
    }

    /* Sanity check on a_flags -- make sure at least one ALLOC is set */
    if (((a_flags & TSK_FS_BLOCK_WALK_FLAG_ALLOC) == 0) &&
        ((a_flags & TSK_FS_BLOCK_WALK_FLAG_UNALLOC) == 0)) {
        a_flags |=
            (TSK_FS_BLOCK_WALK_FLAG_ALLOC |
            TSK_FS_BLOCK_WALK_FLAG_UNALLOC);
    }

    /* All swap has is allocated blocks... exit if not wanted */
    if (!(a_flags & TSK_FS_BLOCK_FLAG_ALLOC)) {
        return 0;
    }

    if ((fs_block = tsk_fs_block_alloc(fs)) == NULL) {
        return 1;
    }

    for (addr = a_start_blk; addr <= a_end_blk; addr++) {
        int retval;

        if (tsk_fs_block_get(fs, fs_block, addr) == NULL) {
            tsk_error_set_errstr2("nofs_block_walk: Block %" PRIuDADDR,
                addr);
            tsk_fs_block_free(fs_block);
            return 1;
        }

        retval = a_action(fs_block, a_ptr);
        if (retval == TSK_WALK_STOP) {
            break;
        }
        else if (retval == TSK_WALK_ERROR) {
            tsk_fs_block_free(fs_block);
            return 1;
        }
    }

    /*
     * Cleanup.
     */
    tsk_fs_block_free(fs_block);
    return 0;
}
Exemple #18
0
/**
 * Print details about the file system to a file handle. 
 *
 * @param fs File system to print details on
 * @param hFile File handle to print text to
 * 
 * @returns 1 on error and 0 on success
 */
static uint8_t
fatxxfs_fsstat(TSK_FS_INFO * fs, FILE * hFile)
{
    unsigned int i;
    TSK_DADDR_T next, snext, sstart, send;
    FATFS_INFO *fatfs = (FATFS_INFO *) fs;
    FATXXFS_SB *sb = (FATXXFS_SB*)fatfs->boot_sector_buffer;
    char *data_buf;
    FATXXFS_DENTRY *vol_label_dentry = NULL;
    ssize_t cnt;

    // clean up any error messages that are lying around
    tsk_error_reset();

    if ((data_buf = (char *) tsk_malloc(fs->block_size)) == NULL) {
        return 1;
    }


    /* Read the root directory sector so that we can get the volume
     * label from it */
    cnt = tsk_fs_read_block(fs, fatfs->rootsect, data_buf, fs->block_size);
    if (cnt != fs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_READ);
        }
        tsk_error_set_errstr2("fatxxfs_fsstat: root directory: %" PRIuDADDR,
            fatfs->rootsect);
        free(data_buf);
        return 1;
    }


    /* Find the dentry that is set as the volume label */
    vol_label_dentry = NULL;
    if (fatfs->ssize <= fs->block_size) {
        FATXXFS_DENTRY *current_entry = (FATXXFS_DENTRY *) data_buf;
        for (i = 0; i < fatfs->ssize; i += sizeof(*current_entry)) {
            if (current_entry->attrib == FATFS_ATTR_VOLUME) {
                vol_label_dentry = current_entry;
                break;
            }
            current_entry++;
        }
    }


    /* Print the general file system information */

    tsk_fprintf(hFile, "FILE SYSTEM INFORMATION\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");

    tsk_fprintf(hFile, "File System Type: FAT");
    if (fs->ftype == TSK_FS_TYPE_FAT12)
        tsk_fprintf(hFile, "12\n");
    else if (fs->ftype == TSK_FS_TYPE_FAT16)
        tsk_fprintf(hFile, "16\n");
    else if (fs->ftype == TSK_FS_TYPE_FAT32)
        tsk_fprintf(hFile, "32\n");
    else
        tsk_fprintf(hFile, "\n");

    tsk_fprintf(hFile, "\nOEM Name: %c%c%c%c%c%c%c%c\n", sb->oemname[0],
        sb->oemname[1], sb->oemname[2], sb->oemname[3], sb->oemname[4],
        sb->oemname[5], sb->oemname[6], sb->oemname[7]);


    if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
        tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n",
            tsk_getu32(fs->endian, sb->a.f16.vol_id));

        tsk_fprintf(hFile,
            "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n",
            sb->a.f16.vol_lab[0], sb->a.f16.vol_lab[1],
            sb->a.f16.vol_lab[2], sb->a.f16.vol_lab[3],
            sb->a.f16.vol_lab[4], sb->a.f16.vol_lab[5],
            sb->a.f16.vol_lab[6], sb->a.f16.vol_lab[7],
            sb->a.f16.vol_lab[8], sb->a.f16.vol_lab[9],
            sb->a.f16.vol_lab[10]);

        if ((vol_label_dentry) && (vol_label_dentry->name[0])) {
            tsk_fprintf(hFile,
                "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n",
                vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3],
                vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7],
                vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]);
        }
        else {
            tsk_fprintf(hFile, "Volume Label (Root Directory):\n");
        }

        tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n",
            sb->a.f16.fs_type[0], sb->a.f16.fs_type[1],
            sb->a.f16.fs_type[2], sb->a.f16.fs_type[3],
            sb->a.f16.fs_type[4], sb->a.f16.fs_type[5],
            sb->a.f16.fs_type[6], sb->a.f16.fs_type[7]);
    }
    else {

        char *fat_fsinfo_buf;

        if ((fat_fsinfo_buf = (char *)
                tsk_malloc(sizeof(FATXXFS_FSINFO))) == NULL) {
            free(data_buf);
            return 1;
        }

        tsk_fprintf(hFile, "Volume ID: 0x%" PRIx32 "\n",
            tsk_getu32(fs->endian, sb->a.f32.vol_id));

        tsk_fprintf(hFile,
            "Volume Label (Boot Sector): %c%c%c%c%c%c%c%c%c%c%c\n",
            sb->a.f32.vol_lab[0], sb->a.f32.vol_lab[1],
            sb->a.f32.vol_lab[2], sb->a.f32.vol_lab[3],
            sb->a.f32.vol_lab[4], sb->a.f32.vol_lab[5],
            sb->a.f32.vol_lab[6], sb->a.f32.vol_lab[7],
            sb->a.f32.vol_lab[8], sb->a.f32.vol_lab[9],
            sb->a.f32.vol_lab[10]);

        if ((vol_label_dentry) && (vol_label_dentry->name[0])) {
            tsk_fprintf(hFile,
                "Volume Label (Root Directory): %c%c%c%c%c%c%c%c%c%c%c\n",
                vol_label_dentry->name[0], vol_label_dentry->name[1], vol_label_dentry->name[2], vol_label_dentry->name[3],
                vol_label_dentry->name[4], vol_label_dentry->name[5], vol_label_dentry->name[6], vol_label_dentry->name[7],
                vol_label_dentry->ext[0], vol_label_dentry->ext[1], vol_label_dentry->ext[2]);
        }
        else {
            tsk_fprintf(hFile, "Volume Label (Root Directory):\n");
        }

        tsk_fprintf(hFile, "File System Type Label: %c%c%c%c%c%c%c%c\n",
            sb->a.f32.fs_type[0], sb->a.f32.fs_type[1],
            sb->a.f32.fs_type[2], sb->a.f32.fs_type[3],
            sb->a.f32.fs_type[4], sb->a.f32.fs_type[5],
            sb->a.f32.fs_type[6], sb->a.f32.fs_type[7]);


        /* Process the FS info */
        if (tsk_getu16(fs->endian, sb->a.f32.fsinfo)) {
            FATXXFS_FSINFO *fat_info;
            cnt =
                tsk_fs_read(fs, 
                    (TSK_DADDR_T) tsk_getu16(fs->endian, sb->a.f32.fsinfo) * fs->block_size, 
                    fat_fsinfo_buf, sizeof(FATXXFS_FSINFO));

            if (cnt != sizeof(FATXXFS_FSINFO)) {
                if (cnt >= 0) {
                    tsk_error_reset();
                    tsk_error_set_errno(TSK_ERR_FS_READ);
                }
                tsk_error_set_errstr2
                    ("fatxxfs_fsstat: TSK_FS_TYPE_FAT32 FSINFO block: %"
                    PRIuDADDR, (TSK_DADDR_T) tsk_getu16(fs->endian,
                        sb->a.f32.fsinfo));
                free(data_buf);
                free(fat_fsinfo_buf);
                return 1;
            }


            fat_info = (FATXXFS_FSINFO *) fat_fsinfo_buf;
            tsk_fprintf(hFile,
                "Next Free Sector (FS Info): %" PRIuDADDR "\n",
                FATFS_CLUST_2_SECT(fatfs, tsk_getu32(fs->endian,
                        fat_info->nextfree)));

            tsk_fprintf(hFile,
                "Free Sector Count (FS Info): %" PRIu32 "\n",
                (tsk_getu32(fs->endian,
                        fat_info->freecnt) * fatfs->csize));

            free(fat_fsinfo_buf);
        }
    }

    free(data_buf);

    tsk_fprintf(hFile, "\nSectors before file system: %" PRIu32 "\n",
        tsk_getu32(fs->endian, sb->prevsect));

    tsk_fprintf(hFile, "\nFile System Layout (in sectors)\n");

    tsk_fprintf(hFile, "Total Range: %" PRIuDADDR " - %" PRIuDADDR "\n",
        fs->first_block, fs->last_block);

    if (fs->last_block != fs->last_block_act)
        tsk_fprintf(hFile,
            "Total Range in Image: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fs->first_block, fs->last_block_act);

    tsk_fprintf(hFile, "* Reserved: 0 - %" PRIuDADDR "\n",
        fatfs->firstfatsect - 1);

    tsk_fprintf(hFile, "** Boot Sector: 0\n");

    if (fatfs->fs_info.ftype == TSK_FS_TYPE_FAT32) {
        tsk_fprintf(hFile, "** FS Info Sector: %" PRIu16 "\n",
            tsk_getu16(fs->endian, sb->a.f32.fsinfo));

        tsk_fprintf(hFile, "** Backup Boot Sector: %" PRIu16 "\n",
            tsk_getu16(fs->endian, sb->a.f32.bs_backup));
    }

    for (i = 0; i < fatfs->numfat; i++) {
        TSK_DADDR_T base = fatfs->firstfatsect + i * (fatfs->sectperfat);

        tsk_fprintf(hFile, "* FAT %d: %" PRIuDADDR " - %" PRIuDADDR "\n",
            i, base, (base + fatfs->sectperfat - 1));
    }

    tsk_fprintf(hFile, "* Data Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
        fatfs->firstdatasect, fs->last_block);

    if (fatfs->fs_info.ftype != TSK_FS_TYPE_FAT32) {
        TSK_DADDR_T x = fatfs->csize * fatfs->clustcnt;

        tsk_fprintf(hFile,
            "** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstdatasect, fatfs->firstclustsect - 1);

        tsk_fprintf(hFile,
            "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstclustsect, (fatfs->firstclustsect + x - 1));

        if ((fatfs->firstclustsect + x - 1) != fs->last_block) {
            tsk_fprintf(hFile,
                "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n",
                (fatfs->firstclustsect + x), fs->last_block);
        }
    }
    else {
        TSK_LIST *list_seen = NULL;
        TSK_DADDR_T x = fatfs->csize * (fatfs->lastclust - 1);
        TSK_DADDR_T clust, clust_p;

        tsk_fprintf(hFile,
            "** Cluster Area: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->firstclustsect, (fatfs->firstclustsect + x - 1));


        clust_p = fatfs->rootsect;
        clust = FATFS_SECT_2_CLUST(fatfs, fatfs->rootsect);
        while ((clust) && (0 == FATFS_ISEOF(clust, FATFS_32_MASK))) {
            TSK_DADDR_T nxt;
            clust_p = clust;

            /* Make sure we do not get into an infinite loop */
            if (tsk_list_find(list_seen, clust)) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "Loop found while determining root directory size\n");
                break;
            }
            if (tsk_list_add(&list_seen, clust)) {
                tsk_list_free(list_seen);
                list_seen = NULL;
                return 1;
            }

            if (fatfs_getFAT(fatfs, clust, &nxt))
                break;
            clust = nxt;
        }
        tsk_list_free(list_seen);
        list_seen = NULL;

        tsk_fprintf(hFile,
            "*** Root Directory: %" PRIuDADDR " - %" PRIuDADDR "\n",
            fatfs->rootsect, (FATFS_CLUST_2_SECT(fatfs, clust_p + 1) - 1));

        if ((fatfs->firstclustsect + x - 1) != fs->last_block) {
            tsk_fprintf(hFile,
                "** Non-clustered: %" PRIuDADDR " - %" PRIuDADDR "\n",
                (fatfs->firstclustsect + x), fs->last_block);
        }
    }


    tsk_fprintf(hFile, "\nMETADATA INFORMATION\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");

    tsk_fprintf(hFile, "Range: %" PRIuINUM " - %" PRIuINUM "\n",
        fs->first_inum, fs->last_inum);
    tsk_fprintf(hFile, "Root Directory: %" PRIuINUM "\n", fs->root_inum);


    tsk_fprintf(hFile, "\nCONTENT INFORMATION\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");
    tsk_fprintf(hFile, "Sector Size: %" PRIu16 "\n", fatfs->ssize);
    tsk_fprintf(hFile, "Cluster Size: %" PRIu32 "\n",
        (uint32_t) fatfs->csize << fatfs->ssize_sh);

    tsk_fprintf(hFile, "Total Cluster Range: 2 - %" PRIuDADDR "\n",
        fatfs->lastclust);


    /* cycle via cluster and look at each cluster in the FAT 
     * for clusters marked as bad */
    cnt = 0;
    for (i = 2; i <= fatfs->lastclust; i++) {
        TSK_DADDR_T entry;
        TSK_DADDR_T sect;
        unsigned int a;

        /* Get the FAT table entry */
        if (fatfs_getFAT(fatfs, i, &entry))
            break;

        if (FATFS_ISBAD(entry, fatfs->mask) == 0) {
            continue;
        }

        if (cnt == 0)
            tsk_fprintf(hFile, "Bad Sectors: ");

        sect = FATFS_CLUST_2_SECT(fatfs, i);
        for (a = 0; a < fatfs->csize; a++) {
            tsk_fprintf(hFile, "%" PRIuDADDR " ", sect + a);
            if ((++cnt % 8) == 0)
                tsk_fprintf(hFile, "\n");
        }
    }
    if ((cnt > 0) && ((cnt % 8) != 0))
        tsk_fprintf(hFile, "\n");

    /* Display the FAT Table */
    tsk_fprintf(hFile, "\nFAT CONTENTS (in sectors)\n");
    tsk_fprintf(hFile, "--------------------------------------------\n");

    /* 'sstart' marks the first sector of the current run to print */
    sstart = fatfs->firstclustsect;

    /* cycle via cluster and look at each cluster in the FAT  to make runs */
    for (i = 2; i <= fatfs->lastclust; i++) {

        /* 'send' marks the end sector of the current run, which will extend
         * when the current cluster continues to the next 
         */
        send = FATFS_CLUST_2_SECT(fatfs, i + 1) - 1;

        /* get the next cluster */
        if (fatfs_getFAT(fatfs, i, &next))
            break;

        snext = FATFS_CLUST_2_SECT(fatfs, next);

        /* we are also using the next sector (clust) */
        if ((next & fatfs->mask) == (i + 1)) {
            continue;
        }

        /* The next clust is either further away or the clust is available,
         * print it if is further away 
         */
        else if ((next & fatfs->mask)) {
            if (FATFS_ISEOF(next, fatfs->mask))
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> EOF\n", sstart, send, send - sstart + 1);
            else if (FATFS_ISBAD(next, fatfs->mask))
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> BAD\n", sstart, send, send - sstart + 1);
            else
                tsk_fprintf(hFile,
                    "%" PRIuDADDR "-%" PRIuDADDR " (%" PRIuDADDR
                    ") -> %" PRIuDADDR "\n", sstart, send,
                    send - sstart + 1, snext);
        }

        /* reset the starting counter */
        sstart = send + 1;
    }

    return 0;
}
Exemple #19
0
/** \internal
 * Processes a non-resident TSK_FS_ATTR structure and calls the callback with the associated
 * data. 
 *
 * @param fs_attr Resident data structure to be walked
 * @param a_flags Flags for walking
 * @param a_action Callback action
 * @param a_ptr Pointer to data that is passed to callback
 * @returns 1 on error or 0 on success
 */
static uint8_t
tsk_fs_attr_walk_nonres(const TSK_FS_ATTR * fs_attr,
    TSK_FS_FILE_WALK_FLAG_ENUM a_flags, TSK_FS_FILE_WALK_CB a_action,
    void *a_ptr)
{
    char *buf = NULL;
    TSK_OFF_T tot_size;
    TSK_OFF_T off = 0;
    TSK_FS_ATTR_RUN *fs_attr_run;
    int retval;
    uint32_t skip_remain;
    TSK_FS_INFO *fs = fs_attr->fs_file->fs_info;
    uint8_t stop_loop = 0;

    if ((fs_attr->flags & TSK_FS_ATTR_NONRES) == 0) {
        tsk_error_set_errno(TSK_ERR_FS_ARG);
        tsk_error_set_errstr
            ("tsk_fs_file_walk_nonres: called with non-non-resident data");
        return 1;
    }

    /* if we want the slack space too, then use the allocsize  */
    if (a_flags & TSK_FS_FILE_WALK_FLAG_SLACK)
        tot_size = fs_attr->nrd.allocsize;
    else
        tot_size = fs_attr->size;

    skip_remain = fs_attr->nrd.skiplen;

    if ((a_flags & TSK_FS_FILE_WALK_FLAG_AONLY) == 0) {
        if ((buf = (char *) tsk_malloc(fs->block_size)) == NULL) {
            return 1;
        }
    }


    /* cycle through the number of runs we have */
    retval = TSK_WALK_CONT;
    for (fs_attr_run = fs_attr->nrd.run; fs_attr_run;
        fs_attr_run = fs_attr_run->next) {
        TSK_DADDR_T addr, len_idx;

        addr = fs_attr_run->addr;

        /* cycle through each block in the run */
        for (len_idx = 0; len_idx < fs_attr_run->len; len_idx++) {

            TSK_FS_BLOCK_FLAG_ENUM myflags;

            /* If the address is too large then give an error */
            if (addr + len_idx > fs->last_block) {
                if (fs_attr->fs_file->meta->
                    flags & TSK_FS_META_FLAG_UNALLOC)
                    tsk_error_set_errno(TSK_ERR_FS_RECOVER);
                else
                    tsk_error_set_errno(TSK_ERR_FS_BLK_NUM);
                tsk_error_set_errstr
                    ("Invalid address in run (too large): %" PRIuDADDR "",
                    addr + len_idx);
                return 1;
            }

            // load the buffer if they want more than just the address
            if ((a_flags & TSK_FS_FILE_WALK_FLAG_AONLY) == 0) {

                /* sparse files just get 0s */
                if (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) {
                    memset(buf, 0, fs->block_size);
                }
                /* FILLER entries exist when the source file system can store run
                 * info out of order and we did not get all of the run info.  We
                 * return 0s if data is read from this type of run. */
                else if (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) {
                    memset(buf, 0, fs->block_size);
                    if (tsk_verbose)
                        fprintf(stderr,
                            "tsk_fs_attr_walk_nonres: File %" PRIuINUM
                            " has FILLER entry, using 0s\n",
                            fs_attr->fs_file->meta->addr);
                }

                // we return 0s for reads past the initsize
                else if ((off >= fs_attr->nrd.initsize)
                    && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                    memset(buf, 0, fs->block_size);
                }
                else {
                    ssize_t cnt;

                    cnt = tsk_fs_read_block
                        (fs, addr + len_idx, buf, fs->block_size);
                    if (cnt != fs->block_size) {
                        if (cnt >= 0) {
                            tsk_error_reset();
                            tsk_error_set_errno(TSK_ERR_FS_READ);
                        }
                        tsk_error_set_errstr2
                            ("tsk_fs_file_walk: Error reading block at %"
                            PRIuDADDR, addr + len_idx);
                        return 1;
                    }
                    if ((off + fs->block_size > fs_attr->nrd.initsize)
                        && ((a_flags & TSK_FS_FILE_READ_FLAG_SLACK) == 0)) {
                        memset(&buf[fs_attr->nrd.initsize - off], 0,
                            fs->block_size -
                            (size_t) (fs_attr->nrd.initsize - off));
                    }
                }
            }

            /* Need to account for the skip length, which is the number of bytes
             * in the start of the attribute that are skipped and that are not
             * included in the overall length.  We will seek past those and not
             * return those in the action.  We just read a block size so check
             * if there is data to be returned in this buffer. */
            if (skip_remain >= fs->block_size) {
                skip_remain -= fs->block_size;
            }
            else {
                size_t ret_len;

                /* Do we want to return a full block, or just the end? */
                if ((TSK_OFF_T) fs->block_size - skip_remain <
                    tot_size - off)
                    ret_len = fs->block_size - skip_remain;
                else
                    ret_len = (size_t) (tot_size - off);

                /* Only do sparse or FILLER clusters if NOSPARSE is not set */
                if ((fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_SPARSE) ||
                    (fs_attr_run->flags & TSK_FS_ATTR_RUN_FLAG_FILLER) ||
                    (off > fs_attr->nrd.initsize)) {
                    myflags = fs->block_getflags(fs, 0);
                    myflags |= TSK_FS_BLOCK_FLAG_SPARSE;

                    if ((a_flags & TSK_FS_FILE_WALK_FLAG_NOSPARSE) == 0) {
                        retval =
                            a_action(fs_attr->fs_file, off, 0,
                            &buf[skip_remain], ret_len, myflags, a_ptr);
                    }
                }
                else {
                    myflags = fs->block_getflags(fs, addr + len_idx);
                    myflags |= TSK_FS_BLOCK_FLAG_RAW;

                    retval =
                        a_action(fs_attr->fs_file, off, addr + len_idx,
                        &buf[skip_remain], ret_len, myflags, a_ptr);
                }
                off += ret_len;
                skip_remain = 0;

                if (retval != TSK_WALK_CONT) {
                    stop_loop = 1;
                    break;
                }

                if (off >= tot_size) {
                    stop_loop = 1;
                    break;
                }
            }
        }
        if (stop_loop)
            break;
    }

    if (buf)
        free(buf);

    if (retval == TSK_WALK_ERROR)
        return 1;
    else
        return 0;
}
Exemple #20
0
/** \internal
 * Read an indirect block and process the contents to make a runlist from the pointers. 
 *
 * @param fs File system to analyze
 * @param fs_attr Structure to save run data into
 * @param fs_attr_indir Structure to save addresses of indirect block pointers in
 * @param buf Buffers to read block data into (0 is block sized, 1+ are DADDR_T arrays based on FS type)
 * @param level Indirection level that this will process at (1+)
 * @param addr Address of block to read
 * @param length Length of file remaining
 *
 * @returns the number of bytes processed during call and -1 if an error occurred
 */
static TSK_OFF_T
unix_make_data_run_indirect(TSK_FS_INFO * fs, TSK_FS_ATTR * fs_attr,
    TSK_FS_ATTR * fs_attr_indir, char *buf[], int level, TSK_DADDR_T addr,
    TSK_OFF_T length)
{
    char *myname = "unix_make_data_run_indirect";
    size_t addr_cnt = 0;
    TSK_DADDR_T *myaddrs = (TSK_DADDR_T *) buf[level];
    TSK_OFF_T length_remain = length;
    TSK_OFF_T retval;
    size_t fs_bufsize;
    size_t fs_blen;
    TSK_FS_ATTR_RUN *data_run;

    if (tsk_verbose)
        tsk_fprintf(stderr, "%s: level %d block %" PRIuDADDR "\n", myname,
            level, addr);

    // block_size is a fragment size in UFS, so we need to maintain length in fragments
    if (TSK_FS_TYPE_ISFFS(fs->ftype)) {
        FFS_INFO *ffs = (FFS_INFO *) fs;
        fs_blen = ffs->ffsbsize_f;
        fs_bufsize = ffs->ffsbsize_b;
    }
    else {
        fs_blen = 1;
        fs_bufsize = fs->block_size;
    }

    if (addr > fs->last_block) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_FS_INODE_COR);
        tsk_error_set_errstr("unix: Indirect block address too large: %"
            PRIuDADDR "", addr);
        return -1;
    }

    // make a non-resident run
    data_run = tsk_fs_attr_run_alloc();
    if (data_run == NULL)
        return -1;

    data_run->addr = addr;
    data_run->len = fs_blen;

    /*
     * Read a block of disk addresses.
     */
    // sparse
    if (addr == 0) {
        memset(buf[0], 0, fs_bufsize);
        data_run->flags = TSK_FS_ATTR_RUN_FLAG_SPARSE;
    }
    else {
        ssize_t cnt;
        // read the data into the scratch buffer
        cnt = tsk_fs_read_block(fs, addr, buf[0], fs_bufsize);
        if (cnt != fs_bufsize) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_FS_READ);
            }
            tsk_error_set_errstr2("unix_make_data_run_indir: Block %"
                PRIuDADDR, addr);
            return -1;
        }
    }

    // save the run
    tsk_fs_attr_append_run(fs, fs_attr_indir, data_run);

    // convert the raw addresses to the correct endian ordering
    if ((fs->ftype == TSK_FS_TYPE_FFS1)
        || (fs->ftype == TSK_FS_TYPE_FFS1B)
        || (TSK_FS_TYPE_ISEXT(fs->ftype))) {
        size_t n;
        uint32_t *iaddr = (uint32_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu32(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }
    else if (fs->ftype == TSK_FS_TYPE_FFS2) {
        size_t n;
        uint64_t *iaddr = (uint64_t *) buf[0];
        addr_cnt = fs_bufsize / sizeof(*iaddr);
        for (n = 0; n < addr_cnt; n++) {
            myaddrs[n] = tsk_getu64(fs->endian, (uint8_t *) & iaddr[n]);
        }
    }

    // pass the addresses to the next level
    if (level == 1) {
        retval =
            unix_make_data_run_direct(fs, fs_attr, myaddrs, addr_cnt,
            length_remain);
        if (retval != -1) {
            length_remain -= retval;
        }
    }
    else {
        size_t i;
        retval = 0;
        for (i = 0; i < addr_cnt && retval != -1; i++) {
            retval =
                unix_make_data_run_indirect(fs, fs_attr, fs_attr_indir,
                buf, level - 1, myaddrs[i], length_remain);
            if (retval == -1) {
                break;
            }
            else {
                length_remain -= retval;
            }
        }
    }

    if (retval == -1)
        return -1;
    else
        return length - length_remain;
}
/* 
 * Process the partition table at the sector address 
 * 
 * It is loaded into the internal sorted list 
 */
static uint8_t
gpt_load_table(TSK_VS_INFO * vs)
{
    gpt_head *head;
    gpt_entry *ent;
    dos_sect *dos_part;
    unsigned int i, a;
    uint32_t ent_size;
    char *safe_str, *head_str, *tab_str, *ent_buf;
    ssize_t cnt;
    char *sect_buf;
    TSK_DADDR_T taddr = vs->offset / vs->block_size + GPT_PART_SOFFSET;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr, "gpt_load_table: Sector: %" PRIuDADDR "\n",
            taddr);

    if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
        return 1;
    dos_part = (dos_sect *) sect_buf;

    cnt = tsk_vs_read_block
        (vs, GPT_PART_SOFFSET, sect_buf, vs->block_size);
    /* if -1, then tsk_errno is already set */
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2
            ("Error reading DOS safety partition table in Sector: %"
            PRIuDADDR, taddr);
        free(sect_buf);
        return 1;
    }

    /* Sanity Check */
    if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("Missing DOS safety partition (invalid magic) (Sector: %"
            PRIuDADDR ")", taddr);
        free(sect_buf);
        return 1;
    }

    if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr
            ("Missing DOS safety partition (invalid type in table: %d)",
            dos_part->ptable[0].ptype);
        free(sect_buf);
        return 1;
    }

    /* Read the GPT header */
    head = (gpt_head *) sect_buf;
    cnt = tsk_vs_read_block
        (vs, GPT_PART_SOFFSET + 1, sect_buf, vs->block_size);
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("GPT Header structure in Sector: %"
            PRIuDADDR, taddr + 1);
        free(sect_buf);
        return 1;
    }

    if (tsk_getu64(vs->endian, &head->signature) != GPT_HEAD_SIG) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("GPT Header: %" PRIx64, tsk_getu64(vs->endian,
                &head->signature));
        free(sect_buf);
        return 1;
    }

    // now that we checked the sig, lets make the meta  entries
    if ((safe_str = tsk_malloc(16)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(safe_str, 16, "Safety Table");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1,
            TSK_VS_PART_FLAG_META, safe_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }


    if ((head_str = tsk_malloc(16)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(head_str, 16, "GPT Header");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 1,
            (TSK_DADDR_T) ((tsk_getu32(vs->endian,
                        &head->head_size_b) + (vs->block_size-1)) / vs->block_size),
            TSK_VS_PART_FLAG_META, head_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }

    /* Allocate a buffer for each table entry */
    ent_size = tsk_getu32(vs->endian, &head->tab_size_b);
    if (ent_size < sizeof(gpt_entry)) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("Header reports partition entry size of %"
            PRIu32 " and not %" PRIuSIZE "", ent_size, sizeof(gpt_entry));
        free(sect_buf);
        return 1;
    }

    if ((tab_str = tsk_malloc(20)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(tab_str, 20, "Partition Table");
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) tsk_getu64(vs->endian,
                &head->tab_start_lba),
            (TSK_DADDR_T) ((ent_size * tsk_getu32(vs->endian,
                        &head->tab_num_ent) + (vs->block_size-1)) / vs->block_size),
            TSK_VS_PART_FLAG_META, tab_str, -1, -1)) {
        free(sect_buf);
        return 1;
    }


    /* Process the partition table */
    if ((ent_buf = tsk_malloc(vs->block_size)) == NULL) {
        free(sect_buf);
        return 1;
    }

    i = 0;
    for (a = 0; i < tsk_getu32(vs->endian, &head->tab_num_ent); a++) {
        char *name;

        /* Read a sector */
        cnt = tsk_vs_read_block(vs,
            tsk_getu64(vs->endian, &head->tab_start_lba) + a,
            ent_buf, vs->block_size);
        if (cnt != vs->block_size) {
            if (cnt >= 0) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_VS_READ);
            }
            tsk_error_set_errstr2
                ("Error reading GPT partition table sector : %" PRIuDADDR,
                tsk_getu64(vs->endian, &head->tab_start_lba) + a);
            free(ent_buf);
            free(sect_buf);
            return 1;
        }

        /* Process the sector */
        ent = (gpt_entry *) ent_buf;
        for (; (uintptr_t) ent < (uintptr_t) ent_buf + vs->block_size &&
            i < tsk_getu32(vs->endian, &head->tab_num_ent); i++) {

            UTF16 *name16;
            UTF8 *name8;
            int retVal;

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "gpt_load: %d  Starting Sector: %" PRIu64
                    "  End: %" PRIu64 " Flag: %" PRIx64 "\n", i,
                    tsk_getu64(vs->endian, ent->start_lba),
                    tsk_getu64(vs->endian, ent->end_lba),
                    tsk_getu64(vs->endian, ent->flags));


            if (tsk_getu64(vs->endian, ent->start_lba) == 0) {
                ent++;
                continue;
            }

            // make sure the first couple are in the image bounds
            if ((i < 2)
                && (tsk_getu64(vs->endian, ent->start_lba) > max_addr)) {
                tsk_error_reset();
                tsk_error_set_errno(TSK_ERR_VS_BLK_NUM);
                tsk_error_set_errstr
                    ("gpt_load_table: Starting sector too large for image");
                free(sect_buf);
                free(ent_buf);
                return 1;
            }


            if ((name = tsk_malloc(256)) == NULL) {
                free(sect_buf);
                free(ent_buf);
                return 1;
            }

            name16 = (UTF16 *) ((uintptr_t) ent->name);
            name8 = (UTF8 *) name;

            retVal =
                tsk_UTF16toUTF8(vs->endian, (const UTF16 **) &name16,
                (UTF16 *) ((uintptr_t) name16 + sizeof(ent->name)),
                &name8,
                (UTF8 *) ((uintptr_t) name8 + 256), TSKlenientConversion);

            if (retVal != TSKconversionOK) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "gpt_load_table: Error converting name to UTF8: %d\n",
                        retVal);
                *name = '\0';
            }

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) tsk_getu64(vs->endian, ent->start_lba),
                    (TSK_DADDR_T) (tsk_getu64(vs->endian,
                            ent->end_lba) - tsk_getu64(vs->endian,
                            ent->start_lba) + 1), TSK_VS_PART_FLAG_ALLOC,
                    name, -1, i)) {
                free(sect_buf);
                free(ent_buf);
                return 1;
            }

            ent++;
        }
    }

    free(sect_buf);
    free(ent_buf);
    return 0;
}
Exemple #22
0
/*
 * Load an extended partition table into the structure in TSK_VS_INFO.
 *
 * sect_cur: The sector where the extended table is located
 * sect_ext_base: The sector of the primary extended table (this does
 *   not change for recursive calls)
 * table: a counter that identifies the table depth
 *   (increases by 1 for each recursive call)
 *
 * For the primary extended table, sect_cur == sect_ext_base
 *
 * Return 1 on error and 0 on success
 *
 */
static uint8_t
dos_load_ext_table(TSK_VS_INFO * vs, TSK_DADDR_T sect_cur,
    TSK_DADDR_T sect_ext_base, int table)
{
    dos_sect *sect;
    char *sect_buf;
    int i;
    char *table_str;
    ssize_t cnt;
    TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size;  // max sector

    if (tsk_verbose)
        tsk_fprintf(stderr,
            "dos_load_ext: Table Sector: %" PRIuDADDR
            ", Primary Base Sector: %" PRIuDADDR "\n", sect_cur,
            sect_ext_base);

    if ((sect_buf = tsk_malloc(vs->block_size)) == NULL)
        return 1;
    sect = (dos_sect *) sect_buf;

    /* Read the partition table sector */
    cnt = tsk_vs_read_block(vs, sect_cur, sect_buf, vs->block_size);
    if (cnt != vs->block_size) {
        if (cnt >= 0) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_VS_READ);
        }
        tsk_error_set_errstr2("Extended DOS table sector %" PRIuDADDR,
            sect_cur);
        free(sect_buf);
        return 1;
    }

    /* Sanity Check */
    if (tsk_getu16(vs->endian, sect->magic) != DOS_MAGIC) {
        tsk_error_reset();
        tsk_error_set_errno(TSK_ERR_VS_MAGIC);
        tsk_error_set_errstr("Extended DOS partition table in sector %"
            PRIuDADDR, sect_cur);
        free(sect_buf);
        return 1;
    }

    /* Add an entry of 1 length for the table  to the internal structure */
    if ((table_str = tsk_malloc(32)) == NULL) {
        free(sect_buf);
        return 1;
    }

    snprintf(table_str, 32, "Extended Table (#%d)", table);
    if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) sect_cur,
            (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, table_str, table,
            -1)) {
        free(sect_buf);
        return 1;
    }

    /* Cycle through the four partitions in the table
     *
     * When another extended partition is found, it is processed
     * inside of the loop
     */
    for (i = 0; i < 4; i++) {
        dos_part *part = &sect->ptable[i];

        /* Get the starting sector and size, we currently
         * ignore CHS */
        uint32_t part_start = tsk_getu32(vs->endian, part->start_sec);
        uint32_t part_size = tsk_getu32(vs->endian, part->size_sec);

        if (tsk_verbose)
            tsk_fprintf(stderr,
                "load_ext: %d:%d    Start: %" PRIu32 "   Size: %"
                PRIu32 "  Type: %d\n", table, i, part_start, part_size,
                part->ptype);

        if (part_size == 0)
            continue;

        /* partitions are addressed differently
         * in extended partitions */
        if (dos_is_ext(part->ptype)) {

            /* part start is added to the start of the
             * first extended partition (the primary
             * extended partition) */

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) (sect_ext_base + part_start),
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_META,
                    dos_get_desc(part->ptype), table, i)) {
                free(sect_buf);
                return 1;
            }

            if (sect_ext_base + part_start > max_addr) {
                if (tsk_verbose)
                    tsk_fprintf(stderr,
                        "Starting sector %" PRIuDADDR
                        " of extended partition too large for image\n",
                        sect_ext_base + part_start);
            }
            /* Process the extended partition */
            else if (dos_load_ext_table(vs, sect_ext_base + part_start,
                    sect_ext_base, table + 1)) {
                free(sect_buf);
                return 1;
            }
        }

        else {
            /* part_start is added to the start of the
             * current partition for the actual
             * starting location */

            // we ignore the max_addr checks on extended partitions...

            if (NULL == tsk_vs_part_add(vs,
                    (TSK_DADDR_T) (sect_cur + part_start),
                    (TSK_DADDR_T) part_size, TSK_VS_PART_FLAG_ALLOC,
                    dos_get_desc(part->ptype), table, i)) {
                free(sect_buf);
                return 1;
            }
        }
    }

    free(sect_buf);
    return 0;
}