From 0411150583dd14d5bdcc8856400cd8e6a1586d0e Mon Sep 17 00:00:00 2001 From: Brian Carrier <carrier@sleuthkit.org> Date: Sat, 14 Feb 2009 03:26:59 +0000 Subject: [PATCH] Fix bug 2596397 that caused incorrect timeline sorting --- CHANGES.txt | 3 + tools/timeline/mactime.base | 134 ++++++++++++++++++++---------------- 2 files changed, 76 insertions(+), 61 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index a7cec7319..894289fed 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -40,6 +40,9 @@ instead of fs_dir_add(). 2/6/09: Bug Fix: Fixed bug 2568528, which was caused by incorrect adjustment of attribute FILLER offset. Reported by Andy Bontoft. +2/13/09: Bug Fix: Fixed bug 2596397, which was caused by mactime +doing text-based sorting on dates of different lengths (fix was to +pad with 0s). Fix by Bruce Nikkel. ---------------- VERSION 3.0.0 -------------- diff --git a/tools/timeline/mactime.base b/tools/timeline/mactime.base index 7f272b009..0a7d03462 100644 --- a/tools/timeline/mactime.base +++ b/tools/timeline/mactime.base @@ -9,13 +9,13 @@ # # The Sleuth Kit # Brian Carrier [carrier <at> sleuthkit [dot] org] -# Copyright (c) 2003-2008 Brian Carrier. All rights reserved +# Copyright (c) 2003-2009 Brian Carrier. All rights reserved # # TASK # Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved # # -# The modifications to the original mactime are distributed under +# The modifications to the original mactime are distributed under # the Common Public License 1.0 # # @@ -93,13 +93,13 @@ sub version { my $month_num = 0; my $header = 0; -my $in_seconds = 0; +my $in_seconds = 0; my $out_seconds = 0; -my %time2macstr; +my %timestr2macstr; my %file2other; -my %gid2names = (); -my %uid2names = (); +my %gid2names = (); +my %uid2names = (); usage() if (scalar(@ARGV) == 0); @@ -226,7 +226,7 @@ sub version { } } else { - $in_seconds = 0; + $in_seconds = 0; $out_seconds = 0; } @@ -260,14 +260,15 @@ sub version { sub parse_isodate { my $iso_date = shift; - my $sec = 0; - my $min = 0; - my $hour = 0; + my $sec = 0; + my $min = 0; + my $hour = 0; my $wday = 0; my $yday = 0; if ($iso_date =~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/) { - return mktime ($sec, $min, $hour, $3, $2 - 1, $1 - 1900, $wday, $yday); - } else { + return mktime($sec, $min, $hour, $3, $2 - 1, $1 - 1900, $wday, $yday); + } + else { return -1; } } @@ -287,20 +288,20 @@ sub read_body { chomp; my ( - $tmp1, $file, $st_ino, $st_ls, - $st_uid, $st_gid, $st_size, $st_atime, + $tmp1, $file, $st_ino, $st_ls, + $st_uid, $st_gid, $st_size, $st_atime, $st_mtime, $st_ctime, $st_crtime, $tmp2 ) = &tm_split($_); # Sanity check so that we ignore the header entries - next unless ((defined $st_ino) && ($st_ino =~ /[\d-]+/)); - next unless ((defined $st_uid) && ($st_uid =~ /\d+/)); - next unless ((defined $st_gid) && ($st_gid =~ /\d+/)); - next unless ((defined $st_size) && ($st_gid =~ /\d+/)); - next unless ((defined $st_mtime) && ($st_mtime =~ /\d+/)); - next unless ((defined $st_atime) && ($st_atime =~ /\d+/)); - next unless ((defined $st_ctime) && ($st_ctime =~ /\d+/)); + next unless ((defined $st_ino) && ($st_ino =~ /[\d-]+/)); + next unless ((defined $st_uid) && ($st_uid =~ /\d+/)); + next unless ((defined $st_gid) && ($st_gid =~ /\d+/)); + next unless ((defined $st_size) && ($st_gid =~ /\d+/)); + next unless ((defined $st_mtime) && ($st_mtime =~ /\d+/)); + next unless ((defined $st_atime) && ($st_atime =~ /\d+/)); + next unless ((defined $st_ctime) && ($st_ctime =~ /\d+/)); next unless ((defined $st_crtime) && ($st_crtime =~ /\d+/)); # we need *some* value in mactimes! @@ -313,71 +314,79 @@ sub read_body { && ($st_ctime < $in_seconds) && ($st_crtime < $in_seconds)); - # First, put all the times in one big array... + # add leading zeros to timestamps because we will later sort + # these using a string-based comparison + $st_mtime = sprintf("%.10d", $st_mtime); + $st_atime = sprintf("%.10d", $st_atime); + $st_ctime = sprintf("%.10d", $st_ctime); + $st_crtime = sprintf("%.10d", $st_crtime); + + # Put all the times in one big array along with the inode and + # name (they are used in the final sorting) # If the date on the file is too old, don't put it in the array my $post = ",$st_ino,$file"; if ($out_seconds) { - $time2macstr{"$st_mtime$post"} .= "m" + $timestr2macstr{"$st_mtime$post"} .= "m" if ( ($st_mtime >= $in_seconds) && ($st_mtime < $out_seconds) - && ( (!(exists $time2macstr{"$st_mtime$post"})) - || ($time2macstr{"$st_mtime$post"} !~ /m/)) + && ( (!(exists $timestr2macstr{"$st_mtime$post"})) + || ($timestr2macstr{"$st_mtime$post"} !~ /m/)) ); - $time2macstr{"$st_atime$post"} .= "a" + $timestr2macstr{"$st_atime$post"} .= "a" if ( ($st_atime >= $in_seconds) && ($st_atime < $out_seconds) - && ( (!(exists $time2macstr{"$st_atime$post"})) - || ($time2macstr{"$st_atime$post"} !~ /a/)) + && ( (!(exists $timestr2macstr{"$st_atime$post"})) + || ($timestr2macstr{"$st_atime$post"} !~ /a/)) ); - $time2macstr{"$st_ctime$post"} .= "c" + $timestr2macstr{"$st_ctime$post"} .= "c" if ( ($st_ctime >= $in_seconds) && ($st_ctime < $out_seconds) - && ( (!(exists $time2macstr{"$st_ctime$post"})) - || ($time2macstr{"$st_ctime$post"} !~ /c/)) + && ( (!(exists $timestr2macstr{"$st_ctime$post"})) + || ($timestr2macstr{"$st_ctime$post"} !~ /c/)) ); - $time2macstr{"$st_crtime$post"} .= "b" + $timestr2macstr{"$st_crtime$post"} .= "b" if ( ($st_crtime >= $in_seconds) && ($st_crtime < $out_seconds) - && ( (!(exists $time2macstr{"$st_crtime$post"})) - || ($time2macstr{"$st_crtime$post"} !~ /b/)) + && ( (!(exists $timestr2macstr{"$st_crtime$post"})) + || ($timestr2macstr{"$st_crtime$post"} !~ /b/)) ); } else { - $time2macstr{"$st_mtime$post"} .= "m" + $timestr2macstr{"$st_mtime$post"} .= "m" if ( ($st_mtime >= $in_seconds) - && ( (!(exists $time2macstr{"$st_mtime$post"})) - || ($time2macstr{"$st_mtime$post"} !~ /m/)) + && ( (!(exists $timestr2macstr{"$st_mtime$post"})) + || ($timestr2macstr{"$st_mtime$post"} !~ /m/)) ); - $time2macstr{"$st_atime$post"} .= "a" + $timestr2macstr{"$st_atime$post"} .= "a" if ( ($st_atime >= $in_seconds) - && ( (!(exists $time2macstr{"$st_atime$post"})) - || ($time2macstr{"$st_atime$post"} !~ /a/)) + && ( (!(exists $timestr2macstr{"$st_atime$post"})) + || ($timestr2macstr{"$st_atime$post"} !~ /a/)) ); - $time2macstr{"$st_ctime$post"} .= "c" + $timestr2macstr{"$st_ctime$post"} .= "c" if ( ($st_ctime >= $in_seconds) - && ( (!(exists $time2macstr{"$st_ctime$post"})) - || ($time2macstr{"$st_ctime$post"} !~ /c/)) + && ( (!(exists $timestr2macstr{"$st_ctime$post"})) + || ($timestr2macstr{"$st_ctime$post"} !~ /c/)) ); - $time2macstr{"$st_crtime$post"} .= "b" + $timestr2macstr{"$st_crtime$post"} .= "b" if ( ($st_crtime >= $in_seconds) - && ( (!(exists $time2macstr{"$st_crtime$post"})) - || ($time2macstr{"$st_crtime$post"} !~ /b/)) + && ( (!(exists $timestr2macstr{"$st_crtime$post"})) + || ($timestr2macstr{"$st_crtime$post"} !~ /b/)) ); } @@ -438,9 +447,9 @@ sub print_header { # sub print_tl { - my $prev_day = ""; # has the format of 'day day_week mon year' - my $prev_hour = ""; # has just the hour and is used for hourly index - my $prev_cnt = 0; + my $prev_day = ""; # has the format of 'day day_week mon year' + my $prev_hour = ""; # has just the hour and is used for hourly index + my $prev_cnt = 0; my $old_date_string = ""; my $delim = ":"; @@ -449,7 +458,10 @@ sub print_tl { $delim = ","; } - for my $key (sort { $a cmp $b } keys %time2macstr) { + # Cycle through the files and print them in sorted order. + # Note that we sort using a string comparison because the keys + # also contain the inode and file name + for my $key (sort { $a cmp $b } keys %timestr2macstr) { my $time; my $inode; my $file; @@ -588,32 +600,36 @@ sub print_tl { # # Muck around with the [mac]times string to make it pretty. # - my $mactime_tmp = $time2macstr{$key}; - my $mactime = ""; + my $mactime_tmp = $timestr2macstr{$key}; + my $mactime = ""; if ($mactime_tmp =~ /m/) { $mactime = "m"; - } else { + } + else { $mactime = "."; } if ($mactime_tmp =~ /a/) { $mactime .= "a"; - } else { + } + else { $mactime .= "."; } if ($mactime_tmp =~ /c/) { $mactime .= "c"; - } else { + } + else { $mactime .= "."; } if ($mactime_tmp =~ /b/) { $mactime .= "b"; - } else { + } + else { $mactime .= "."; } - + my ($ls, $uids, $groups, $size) = split(/:/, $file2other{$file}); print "FILE: $file MODES: $ls U: $uids G: $groups S: $size\n" @@ -735,7 +751,6 @@ package main; my $passwd_loaded = 0; # flags to use to avoid reloading everything my $group_loaded = 0; # unnecessarily... - # # Update user information for the user named $name. We cache the password, # uid, login group, home directory and shell. @@ -778,7 +793,6 @@ sub add_gr_info { } } - sub load_passwd_info { my ($file_name) = @_; my (@pw_info); @@ -802,7 +816,6 @@ sub load_passwd_info { close(FILE); } - sub load_group_info { my ($file_name) = @_; my (@gr_info); @@ -825,7 +838,6 @@ sub load_group_info { close(FILE); } - # # Split a time machine record. # -- GitLab