Ejemplo n.º 1
0
/**
 * Open a directory and cycle through its contents.  Read each file and recurse
 * into each directory.
 *
 * @param fs_info File system to process
 * @param stack Stack to prevent infinite recursion loops
 * @param dir_inum Metadata address of directory to open
 * @param path Path of directory being opened
 * @returns 1 on error
 */
static uint8_t
proc_dir(TSK_FS_INFO * fs_info, TSK_STACK * stack,
    TSK_INUM_T dir_inum, const char *path)
{
    TSK_FS_DIR *fs_dir;
    size_t i;
    char *path2 = NULL;
    char *buf = NULL;

    // open the directory
    if ((fs_dir = tsk_fs_dir_open_meta(fs_info, dir_inum)) == NULL) {
        fprintf(stderr, "Error opening directory: %" PRIuINUM "\n",
            dir_inum);
        tsk_error_print(stderr);
        return 1;
    }

    /* These should be dynamic lengths, but this is just a sample program.
     * Allocate heap space instead of stack to prevent overflow for deep
     * directories. */
    if ((path2 = (char *) malloc(4096)) == NULL) {
        return 1;
    }

    if ((buf = (char *) malloc(2048)) == NULL) {
        free(path2);
        return 1;
    }

    // cycle through each entry
    for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {
        TSK_FS_FILE *fs_file;
        TSK_OFF_T off = 0;
        size_t len = 0;

        // get the entry
        if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
            fprintf(stderr,
                "Error getting directory entry %" PRIuSIZE
                " in directory %" PRIuINUM "\n", i, dir_inum);
            tsk_error_print(stderr);

            free(path2);
            free(buf);
            return 1;
        }

        /* Ignore NTFS System files */
        if ((TSK_FS_TYPE_ISNTFS(fs_file->fs_info->ftype)) &&
            (fs_file->name->name[0] == '$')) {
            tsk_fs_file_close(fs_file);
            continue;
        }

        //printf("Processing %s/%s\n", path, fs_file->name->name);

        // make sure it's got metadata and not only a name
        if (fs_file->meta) {
            ssize_t cnt;

            /* Note that we could also cycle through all of the attributes in the
             * file by using one of the tsk_fs_attr_get() functions and reading it
             * with tsk_fs_attr_read().  See the File Systems section of the Library
             * User's Guide for more details: 
             * http://www.sleuthkit.org/sleuthkit/docs/api-docs/ */
            
            // read file contents
            if (fs_file->meta->type == TSK_FS_META_TYPE_REG) {
                int myflags = 0;

                for (off = 0; off < fs_file->meta->size; off += len) {
                    if (fs_file->meta->size - off < 2048)
                        len = (size_t) (fs_file->meta->size - off);
                    else
                        len = 2048;

                    cnt = tsk_fs_file_read(fs_file, off, buf, len,
                        (TSK_FS_FILE_READ_FLAG_ENUM) myflags);
                    if (cnt == -1) {
                        // could check tsk_errno here for a recovery error (TSK_ERR_FS_RECOVER)
                        fprintf(stderr, "Error reading %s file: %s\n",
                            ((fs_file->name->
                                    flags & TSK_FS_NAME_FLAG_UNALLOC)
                                || (fs_file->meta->
                                    flags & TSK_FS_META_FLAG_UNALLOC)) ?
                            "unallocated" : "allocated",
                            fs_file->name->name);
                        tsk_error_print(stderr);
                        break;
                    }
                    else if (cnt != (ssize_t) len) {
                        fprintf(stderr,
                            "Warning: %" PRIuSIZE " of %" PRIuSIZE
                            " bytes read from %s file %s\n", cnt, len,
                            ((fs_file->name->
                                    flags & TSK_FS_NAME_FLAG_UNALLOC)
                                || (fs_file->meta->
                                    flags & TSK_FS_META_FLAG_UNALLOC)) ?
                            "unallocated" : "allocated",
                            fs_file->name->name);
                    }

                    // do something with the data...
                }
            }

            // recurse into another directory (unless it is a '.' or '..')
            else if (fs_file->meta->type == TSK_FS_META_TYPE_DIR) {
                if (TSK_FS_ISDOT(fs_file->name->name) == 0) {

                    // only go in if it is not on our stack
                    if (tsk_stack_find(stack, fs_file->meta->addr) == 0) {
                        // add the address to the top of the stack
                        tsk_stack_push(stack, fs_file->meta->addr);

                        snprintf(path2, 4096, "%s/%s", path,
                            fs_file->name->name);
                        if (proc_dir(fs_info, stack, fs_file->meta->addr,
                                path2)) {
                            tsk_fs_file_close(fs_file);
                            tsk_fs_dir_close(fs_dir);
                            free(path2);
                            free(buf);
                            return 1;
                        }

                        // pop the address
                        tsk_stack_pop(stack);
                    }
                }
            }
        }
        tsk_fs_file_close(fs_file);
    }
    tsk_fs_dir_close(fs_dir);

    free(path2);
    free(buf);
    return 0;
}
Ejemplo n.º 2
0
/* Compare the differences between dir_open_meta and dir_open 
 * @param a_path Path of directory to open
 * @param a_addr The metadata address of the same directory as the path
 * @returns 1 if a test failed
 */
static int
test_dir_open_apis(TSK_FS_INFO * a_fs, const char *a_path,
    TSK_INUM_T a_addr)
{
    TSK_FS_DIR *fs_dir_m;
    TSK_FS_DIR *fs_dir_p;
    TSK_FS_DIR *fs_dir_tmp;
    TSK_FS_FILE *fs_file_m;
    TSK_FS_FILE *fs_file_p;
    int retval = 0;
    size_t entry = 0;

    // open via inode addr
    fs_dir_m = tsk_fs_dir_open_meta(a_fs, a_addr);
    if (!fs_dir_m) {
        fprintf(stderr, "Error opening dir %" PRIuINUM " via meta\n",
            a_addr);
        tsk_error_print(stderr);
        return 1;
    }

    /* open the root directory to throw some more state into the system
     * in case data is cached from first call */
    fs_dir_tmp = tsk_fs_dir_open_meta(a_fs, a_fs->root_inum);
    if (!fs_dir_tmp) {
        fprintf(stderr, "Error opening root directory via meta\n");
        tsk_error_print(stderr);
        return 1;
    }

    // open via path
    fs_dir_p = tsk_fs_dir_open(a_fs, a_path);
    if (!fs_dir_p) {
        fprintf(stderr, "Error opening directory %s\n", a_path);
        tsk_error_print(stderr);
        return 1;
    }

    // test that path has the name structure set (correctly)
    if ((fs_dir_p->fs_file == NULL) || (fs_dir_p->fs_file->name == NULL)) {
        fprintf(stderr, "dir opened via path has null name (%s)\n",
            a_path);
        retval = 1;
        goto open_cleanup;
    }

    if (fs_dir_p->fs_file->name->meta_addr !=
        fs_dir_p->fs_file->meta->addr) {
        fprintf(stderr,
            "dir opened via path has different meta addresses in name and meta (%s) (%"
            PRIuINUM " vs %" PRIuINUM "\n", a_path,
            fs_dir_p->fs_file->name->meta_addr,
            fs_dir_p->fs_file->meta->addr);
        retval = 1;
        goto open_cleanup;
    }

    // verify both methods have same dir addr
    if (fs_dir_p->fs_file->meta->addr != fs_dir_m->fs_file->meta->addr) {
        fprintf(stderr,
            "parent dir addrs from fs_dir_open_meta and via path are different: %"
            PRIuINUM " vs %" PRIuINUM " (%s - %" PRIuINUM "\n",
            fs_dir_p->fs_file->meta->addr, fs_dir_m->fs_file->meta->addr,
            a_path, a_addr);
        retval = 1;
        goto open_cleanup;
    }

    // verify path method has same dir addr as open via meta
    if (fs_dir_p->fs_file->meta->addr != a_addr) {
        fprintf(stderr,
            "parent dir addrs from fs_dir_open is diff from meta address %"
            PRIuINUM " (%s - %" PRIuINUM "\n",
            fs_dir_p->fs_file->meta->addr, a_path, a_addr);
        retval = 1;
        goto open_cleanup;
    }

    // verify both have same size
    if (tsk_fs_dir_getsize(fs_dir_p) != tsk_fs_dir_getsize(fs_dir_m)) {
        fprintf(stderr,
            "sizes from fs_dir_open_meta and via path are different: %"
            PRIuSIZE " vs %" PRIuSIZE " (%s - %" PRIuINUM "\n",
            tsk_fs_dir_getsize(fs_dir_p), tsk_fs_dir_getsize(fs_dir_m),
            a_path, a_addr);
        retval = 1;
        goto open_cleanup;
    }


    // compare the first entry in both. 
    if (tsk_fs_dir_getsize(fs_dir_p) == 0) {
        fprintf(stderr, "directory sizes are 0\n");
        retval = 1;
        goto open_cleanup;
    }

    fs_file_m = tsk_fs_dir_get(fs_dir_m, 0);
    if (fs_file_m == NULL) {
        fprintf(stderr,
            "Error opening entry 0 from meta open: %" PRIuINUM "\n",
            a_addr);
        tsk_error_print(stderr);
        retval = 1;
        goto open_cleanup;
    }

    fs_file_p = tsk_fs_dir_get(fs_dir_p, 0);
    if (fs_file_p == NULL) {
        fprintf(stderr,
            "Error opening entry 0 from path open: %" PRIuINUM "\n",
            a_addr);
        tsk_error_print(stderr);
        retval = 1;
        goto open_cleanup;
    }

    if (compare_names(fs_file_p->name, fs_file_m->name, 1)) {
        fprintf(stderr, "results from entry 0 are different\n");
        retval = 1;
        goto open_cleanup;
    }
    tsk_fs_file_close(fs_file_m);
    tsk_fs_file_close(fs_file_p);


    // compare the last entry in both
    entry = tsk_fs_dir_getsize(fs_dir_m) - 1;
    fs_file_m = tsk_fs_dir_get(fs_dir_m, entry);
    if (fs_file_m == NULL) {
        fprintf(stderr,
            "Error opening entry %" PRIuSIZE " from meta open: %" PRIuINUM
            "\n", entry, a_addr);
        tsk_error_print(stderr);
        retval = 1;
        goto open_cleanup;
    }

    fs_file_p = tsk_fs_dir_get(fs_dir_p, entry);
    if (fs_file_p == NULL) {
        fprintf(stderr,
            "Error opening entry %" PRIuSIZE " from path open: %" PRIuINUM
            "\n", entry, a_addr);
        tsk_error_print(stderr);
        retval = 1;
        goto open_cleanup;
    }

    if (compare_names(fs_file_p->name, fs_file_m->name, 1)) {
        fprintf(stderr, "results from entry %" PRIuSIZE " are different\n",
            entry);
        retval = 1;
        goto open_cleanup;
    }
    tsk_fs_file_close(fs_file_m);
    tsk_fs_file_close(fs_file_p);


  open_cleanup:
    tsk_fs_dir_close(fs_dir_p);
    tsk_fs_dir_close(fs_dir_tmp);
    tsk_fs_dir_close(fs_dir_m);

    return retval;
}
Ejemplo n.º 3
0
/**
 * \ingroup fslib
 *
 * Find the meta data address for a given file name (UTF-8).
 * The basic idea of the function is to break the given name into its
 * subdirectories and start looking for each (starting in the root
 * directory).
 *
 * @param a_fs FS to analyze
 * @param a_path UTF-8 path of file to search for
 * @param [out] a_result Meta data address of file
 * @param [out] a_fs_name Copy of name details (or NULL if details not wanted)
 * @returns -1 on (system) error, 0 if found, and 1 if not found
 */
int8_t
tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path,
    TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name)
{
    char *cpath;
    size_t clen;
    char *cur_dir;              // The "current" directory or file we are looking for
    char *cur_attr;             // The "current" attribute of the dir we are looking for
    TSK_INUM_T next_meta;
    uint8_t is_done;
    char *strtok_last;
    *a_result = 0;

    // copy path to a buffer that we can modify
    clen = strlen(a_path) + 1;
    if ((cpath = (char *) tsk_malloc(clen)) == NULL) {
        return -1;
    }
    strncpy(cpath, a_path, clen);

    // Get the first part of the directory path.
    cur_dir = (char *) strtok_r(cpath, "/", &strtok_last);
    cur_attr = NULL;

    /* If there is no token, then only a '/' was given */
    if (cur_dir == NULL) {
        free(cpath);
        *a_result = a_fs->root_inum;

        // create the dummy entry if needed
        if (a_fs_name) {
            a_fs_name->meta_addr = a_fs->root_inum;
            // Note that we are not filling in meta_seq -- we could, we just aren't

            a_fs_name->type = TSK_FS_NAME_TYPE_DIR;
            a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC;
            if (a_fs_name->name)
                a_fs_name->name[0] = '\0';
            if (a_fs_name->shrt_name)
                a_fs_name->shrt_name[0] = '\0';
        }
        return 0;
    }

    /* If this is NTFS, separate out the attribute of the current directory */
    if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
        && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
        *(cur_attr) = '\0';
        cur_attr++;
    }

    if (tsk_verbose)
        tsk_fprintf(stderr, "Looking for %s\n", cur_dir);

    // initialize the first place to look, the root dir
    next_meta = a_fs->root_inum;

    // we loop until we know the outcome and then exit.
    // everything should return from inside the loop.
    is_done = 0;
    while (is_done == 0) {
        size_t i;
        TSK_FS_FILE *fs_file_alloc = NULL;      // set to the allocated file that is our target
        TSK_FS_FILE *fs_file_del = NULL;        // set to an unallocated file that matches our criteria

        TSK_FS_DIR *fs_dir = NULL;

        // open the next directory in the recursion
        if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) {
            free(cpath);
            return -1;
        }

        /* Verify this is indeed a directory.  We had one reported
         * problem where a file was a disk image and opening it as
         * a directory found the directory entries inside of the file
         * and this caused problems... */
        if ( !TSK_FS_IS_DIR_META(fs_dir->fs_file->meta->type)) {
            tsk_error_reset();
            tsk_error_set_errno(TSK_ERR_FS_GENFS);
            tsk_error_set_errstr("Address %" PRIuINUM
                " is not for a directory\n", next_meta);
            free(cpath);
            return -1;
        }

        // cycle through each entry
        for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {

            TSK_FS_FILE *fs_file;
            uint8_t found_name = 0;

            if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) {
                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return -1;
            }

            /*
             * Check if this is the name that we are currently looking for,
             * as identified in 'cur_dir'
             */
            if ((fs_file->name->name)
                && (a_fs->name_cmp(a_fs, fs_file->name->name,
                        cur_dir) == 0)) {
                found_name = 1;
            }
            else if ((fs_file->name->shrt_name)
                && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name,
                        cur_dir) == 0)) {
                found_name = 1;
            }

            /* For NTFS, we have to check the attribute name. */
            if ((found_name == 1) && (TSK_FS_TYPE_ISNTFS(a_fs->ftype))) {
                /*  ensure we have the right attribute name */
                if (cur_attr != NULL) {
                    found_name = 0;
                    if (fs_file->meta) {
                        int cnt, i;

                        // cycle through the attributes
                        cnt = tsk_fs_file_attr_getsize(fs_file);
                        for (i = 0; i < cnt; i++) {
                            const TSK_FS_ATTR *fs_attr =
                                tsk_fs_file_attr_get_idx(fs_file, i);
                            if (!fs_attr)
                                continue;

                            if ((fs_attr->name)
                                && (a_fs->name_cmp(a_fs, fs_attr->name,
                                        cur_attr) == 0)) {
                                found_name = 1;
                                break;
                            }
                        }
                    }
                }
            }

            if (found_name) {
                /* If we found our file and it is allocated, then stop. If
                 * it is unallocated, keep on going to see if we can get
                 * an allocated hit */
                if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) {
                    fs_file_alloc = fs_file;
                    break;
                }
                else {
                    // if we already have an unalloc and its addr is 0, then use the new one
                    if ((fs_file_del)
                        && (fs_file_del->name->meta_addr == 0)) {
                        tsk_fs_file_close(fs_file_del);
                    }
                    fs_file_del = fs_file;
                }
            }
            // close the file if we did not save it for future analysis.
            else {
                tsk_fs_file_close(fs_file);
                fs_file = NULL;
            }
        }

        // we found a directory, go into it
        if ((fs_file_alloc) || (fs_file_del)) {

            const char *pname;
            TSK_FS_FILE *fs_file_tmp;

            // choose the alloc one first (if they both exist)
            if (fs_file_alloc)
                fs_file_tmp = fs_file_alloc;
            else
                fs_file_tmp = fs_file_del;

            pname = cur_dir;    // save a copy of the current name pointer

            // advance to the next name
            cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last));
            cur_attr = NULL;

            if (tsk_verbose)
                tsk_fprintf(stderr,
                    "Found it (%s), now looking for %s\n", pname, cur_dir);

            /* That was the last name in the path -- we found the file! */
            if (cur_dir == NULL) {
                *a_result = fs_file_tmp->name->meta_addr;

                // make a copy if one was requested
                if (a_fs_name) {
                    tsk_fs_name_copy(a_fs_name, fs_file_tmp->name);
                }

                if (fs_file_alloc)
                    tsk_fs_file_close(fs_file_alloc);
                if (fs_file_del)
                    tsk_fs_file_close(fs_file_del);

                tsk_fs_dir_close(fs_dir);
                free(cpath);
                return 0;
            }

            // update the attribute field, if needed
            if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)
                && ((cur_attr = strchr(cur_dir, ':')) != NULL)) {
                *(cur_attr) = '\0';
                cur_attr++;
            }

            // update the value for the next directory to open
            next_meta = fs_file_tmp->name->meta_addr;

            if (fs_file_alloc) {
                tsk_fs_file_close(fs_file_alloc);
                fs_file_alloc = NULL;
            }
            if (fs_file_del) {
                tsk_fs_file_close(fs_file_del);
                fs_file_del = NULL;
            }
        }

        // no hit in directory
        else {
            is_done = 1;
        }

        tsk_fs_dir_close(fs_dir);
        fs_dir = NULL;
    }

    free(cpath);
    return 1;
}
Ejemplo n.º 4
0
/* Test function that compares the dir_open/dir_get() APIs
 * with the dir_walk results
 * @param a_addr Address of directory to analyze
 * @returns 1 if a test failed.
 */
static int
test_walk_apis(TSK_FS_INFO * a_fs, TSK_INUM_T a_addr)
{
    TSK_FS_DIR *fs_dir;
    int retval = 0;

    fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr);
    if (!fs_dir) {
        fprintf(stderr, "Error opening dir %" PRIuINUM " via meta\n",
            a_addr);
        tsk_error_print(stderr);
        return 1;
    }

    // verify they have the same number of entries
    // walk the directory to get its count
    size_t walk_size = 0;
    if (tsk_fs_dir_walk(a_fs, a_addr, (TSK_FS_DIR_WALK_FLAG_ENUM) 0,
            dir_walk_count_cb, &walk_size)) {
        fprintf(stderr, "Error doing dent walk on dir %" PRIuINUM "\n",
            a_addr);
        retval = 1;
        goto walk_cleanup;
    }

    if (walk_size != tsk_fs_dir_getsize(fs_dir)) {
        fprintf(stderr,
            "Size returned by dir_walk different from dir_getsize: %"
            PRIuINUM ": %" PRIuSIZE " %" PRIuSIZE "\n", a_addr, walk_size,
            tsk_fs_dir_getsize(fs_dir));
        retval = 1;
        goto walk_cleanup;
    }

    // verify each entry is the same
    for (size_t i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) {
        TSK_FS_FILE *fs_file;

        fs_file = tsk_fs_dir_get(fs_dir, i);
        if (fs_file == NULL) {
            fprintf(stderr,
                "Error getting entry %" PRIuSIZE " from directory %"
                PRIuINUM "\n", i, a_addr);
            tsk_error_print(stderr);
            retval = 1;
            goto walk_cleanup;
        }
        if (fs_file->meta == NULL) {
            fprintf(stderr,
                "Error: %s (%" PRIuINUM
                ") does not have meta set in dir: \n", fs_file->name->name,
                fs_file->name->meta_addr);
            retval = 1;
            goto walk_cleanup;
        }

        s_found = 0;
        if (tsk_fs_dir_walk(a_fs, a_addr, (TSK_FS_DIR_WALK_FLAG_ENUM) 0,
                dir_walk_comp_cb, (void *) fs_file)) {
            fprintf(stderr, "Error doing dent walk on dir %" PRIuINUM "\n",
                a_addr);
            retval = 1;
            goto walk_cleanup;
        }
        if (s_found == 0) {
            fprintf(stderr,
                "entry %" PRIuSIZE " in dir not found via walk: %s\n", i,
                fs_file->name->name);
            retval = 1;
            goto walk_cleanup;
        }
        tsk_fs_file_close(fs_file);
    }

  walk_cleanup:
    tsk_fs_dir_close(fs_dir);
    return retval;
}