1#
2# Sort files based on their application type (content)
3#
4# Brian Carrier [carrier@sleuthkit.org]
5# Copyright (c) 2001-2008 by Brian Carrier.  All rights reserved
6#
7# This file is part of the Autopsy Forensic Browser (Autopsy)
8#
9# Autopsy is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# Autopsy is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with Autopsy; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22#
23# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
24# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
25# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
26# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
29# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34package Appsort;
35
36$Appsort::FRAME = 1;
37$Appsort::MENU  = 2;
38$Appsort::ENTER = 3;
39$Appsort::RUN   = 4;
40$Appsort::VIEW  = 5;
41$Appsort::BLANK = 6;
42
43sub main {
44
45    if ($::LIVE == 1) {
46        Print::print_html_header("Unsupported for Live Analysis");
47        print
48"<center><h2>This feature is not available during a live analysis</h2></center>";
49        Print::print_html_footer();
50        return 0;
51    }
52
53    # By default, show the main frame
54    $Args::args{'view'} = $Args::enc_args{'view'} = $Appsort::FRAME
55      unless (exists $Args::args{'view'});
56
57    Args::check_view();
58    my $view = Args::get_view();
59
60    if ($view == $Appsort::BLANK) {
61        return blank();
62    }
63
64    # Check Basic Args
65    Args::check_vol('vol');
66
67    # These windows don't need the meta data address
68    if ($view == $Appsort::FRAME) {
69        return frame();
70    }
71    elsif ($view == $Appsort::ENTER) {
72        return enter();
73    }
74    elsif ($view == $Appsort::MENU) {
75        return menu();
76    }
77    elsif ($view == $Appsort::RUN) {
78        return run();
79    }
80    elsif ($view == $Appsort::VIEW) {
81        return view();
82    }
83    else {
84        Print::print_check_err("Invalid Application Sorting View");
85    }
86}
87
88sub get_sorter_dir {
89    if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) {
90        return "$::host_dir" . "$::DATADIR/sorter-$1/";
91    }
92    Print::print_err("Invalid Sorter Directory");
93}
94
95sub get_sorter_graphics_dir {
96    if ($Args::args{'vol'} =~ /^($::REG_VNAME)$/) {
97        return "$::host_dir" . "$::DATADIR/sorter-graphics-$1/";
98    }
99    Print::print_err("Invalid Sorter Graphics Directory");
100}
101
102# sorter frameset
103sub frame {
104    Print::print_html_header_frameset("Sorter on $Args::args{'vol'}");
105
106    print "<frameset cols=\"20%,80%\">\n";
107
108    # Block List
109    print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::MENU&"
110      . "$Args::baseargs\">\n";
111
112    # Blank
113    print "<frame src=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::BLANK&"
114      . "$Args::baseargs\" name=\"content\">\n"
115      . "</frameset>\n";
116
117    Print::print_html_footer_frameset();
118    return 0;
119}
120
121# The left-hand frame for running sorter
122sub menu {
123    Print::print_html_header("sorter menu");
124
125    print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::ENTER&"
126      . "$Args::baseargs\" "
127      . "target=\"content\">Sort Files by Type</a>";
128
129    print "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&view=$Appsort::VIEW&"
130      . "$Args::baseargs\" "
131      . "target=\"content\">View Sorted Files</a>";
132
133    Print::print_html_footer();
134    return 0;
135}
136
137# Get the data and print the form so that sorter can be run
138sub enter {
139    Print::print_html_header("sorter - enter data to create");
140
141    print "<center>"
142      . "<h3>File Type Sortings</h3></center><br>"
143      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
144      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_APPSORT\">\n"
145      . "<input type=\"hidden\" name=\"view\" value=\"$Appsort::RUN\">\n"
146      . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
147      . Args::make_hidden();
148
149    print <<EOF1;
150<p>The <b>sorter</b> tool will process an image and organize the
151files based on their file type.  The files are organized into categories
152that are defined in configuration files.  The categories will be saved
153in the <tt>$::DATADIR</tt> directory.
154<hr>
155EOF1
156
157    my $sort_dir = get_sorter_dir();
158    if (-d "$sort_dir") {
159        print "WARNING: This will overwrite any existing data in:<br>"
160          . "&nbsp;&nbsp;&nbsp;&nbsp;<tt>$sort_dir</tt><br>\n";
161    }
162
163    my $tab = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
164
165    print <<EOF2;
166
167<p>
168<input type=\"checkbox\" name=\"sorter_cat\" value=\"1\" CHECKED>
169Sort files into categories by type
170
171  <p>$tab
172  <input type=\"checkbox\" name=\"sorter_unk\" value=\"1\">
173  Do not save data about <tt>unknown</tt> file types
174
175  <p>$tab
176  <input type=\"checkbox\" name=\"sorter_save\" value=\"1\">
177  Save a copy of files in category directory (may require lots of disk space)
178
179  <p>$tab
180  <input type=\"checkbox\" name=\"sorter_img\" value=\"1\">
181  Save ONLY graphic images and make thumbnails <br>
182  $tab (may require lots of disk space and will save to a different directory than sorting all file types)
183
184<p>
185<input type=\"checkbox\" name=\"sorter_ext\" value=\"1\" CHECKED>
186Extension and File Type Validation
187
188EOF2
189
190    if (($::NSRLDB ne "") && (-e "$::NSRLDB")) {
191
192        # NSRL
193        print
194"<p><input type=\"checkbox\" name=\"sorter_nsrl\" value=\"1\" CHECKED>"
195          . "Exclude files in the <b>NIST NSRL</b>\n";
196    }
197
198    if (($Caseman::alert_db ne "") && (-e "$Caseman::alert_db")) {
199        print
200"<p><input type=\"checkbox\" name=\"sorter_alert\" value=\"1\" CHECKED>"
201          . "Alert files that are found in the <b>Alert Hash Database</b>\n";
202    }
203
204    if (($Caseman::exclude_db ne "") && (-e "$Caseman::exclude_db")) {
205        print
206"<p><input type=\"checkbox\" name=\"sorter_exclude\" value=\"1\" CHECKED>"
207          . "Ignore files that are found in the <b>Exclude Hash Database</b>\n";
208    }
209
210    print "<p><input type=\"image\" src=\"pict/but_ok.jpg\" "
211      . "width=43 height=20 alt=\"Ok\" border=\"0\">\n</form>\n";
212
213    Print::print_html_footer();
214    return;
215}
216
217# Run sorter on the image
218sub run {
219    Print::print_html_header("sorter - create");
220
221    my $sort_args = "";
222    my $ext       = 0;
223    my $cat       = 0;
224
225    my $vol = Args::get_vol('vol');
226    my $mnt = $Caseman::vol2mnt{$vol};
227
228    my $ftype   = $Caseman::vol2ftype{$vol};
229    my $img     = $Caseman::vol2path{$vol};
230    my $offset  = $Caseman::vol2start{$vol};
231    my $imgtype = $Caseman::vol2itype{$vol};
232
233    Print::log_host_inv("Running 'sorter' on ($Caseman::vol2sname{$vol}");
234
235    $ext = 1
236      if ( (exists $Args::args{'sorter_ext'})
237        && ($Args::args{'sorter_ext'} == 1));
238    $cat = 1
239      if ( (exists $Args::args{'sorter_cat'})
240        && ($Args::args{'sorter_cat'} == 1));
241
242    if (($cat == 0) && ($ext == 0)) {
243        print "At least one action must be selected\n"
244          . "<p><a href=\"$::PROGNAME?mod=$::MOD_APPSORT&"
245          . "view=$Appsort::ENTER&$Args::baseargs\">"
246          . "<img border=0 src=\"pict/but_ok.jpg\" alt=\"Ok\" "
247          . "width=43 height=20></a>\n";
248
249        return;
250    }
251
252    # If both actions are wanted then no flags are needed
253    $sort_args .= "-e " if (($ext == 1) && ($cat == 0));
254    $sort_args .= "-E " if (($ext == 0) && ($cat == 1));
255
256    my $sort_dir = get_sorter_dir();
257
258    if ($cat == 1) {
259        if (   (exists $Args::args{'sorter_img'})
260            && ($Args::args{'sorter_img'} == 1))
261        {
262            my $config = "$::TSKDIR/../share/tsk3/sorter/images.sort";
263
264            Print::print_err("images configuration file not found ($config)")
265              unless (-e "$config");
266
267            $sort_args .= "-C \'$config\' -s -U ";
268
269            $sort_dir = get_sorter_graphics_dir();
270
271        }
272        else {
273            $sort_args .= "-s "
274              if ( (exists $Args::args{'sorter_save'})
275                && ($Args::args{'sorter_save'} == 1));
276
277            $sort_args .= "-U "
278              if ( (exists $Args::args{'sorter_unk'})
279                && ($Args::args{'sorter_unk'} == 1));
280        }
281    }
282
283    if ($::NSRLDB ne "") {
284        $sort_args .= "-n \'$::NSRLDB\' "
285          if ( (exists $Args::args{'sorter_nsrl'})
286            && ($Args::args{'sorter_nsrl'} == 1));
287    }
288
289    if ($Caseman::alert_db ne "") {
290        $sort_args .= "-a \'$Caseman::alert_db\' "
291          if ( (exists $Args::args{'sorter_alert'})
292            && ($Args::args{'sorter_alert'} == 1));
293    }
294
295    if ($Caseman::exclude_db ne "") {
296        $sort_args .= "-x \'$Caseman::exclude_db\' "
297          if ( (exists $Args::args{'sorter_exclude'})
298            && ($Args::args{'sorter_exclude'} == 1));
299    }
300
301    unless (-d "$sort_dir") {
302        unless (mkdir "$sort_dir", $::MKDIR_MASK) {
303            Print::print_err("Error making $sort_dir");
304        }
305    }
306    if (-e "$sort_dir/index.html") {
307        unlink("$sort_dir/index.html");
308    }
309
310    my $exec =
311"-h -m '$mnt' -d '$sort_dir' -o $offset -i $imgtype -f $ftype $sort_args $img";
312
313    # print "Executing: <tt>sorter $exec</tt><p>\n";
314
315    # Execute Sorter
316    my $hit_cnt = 0;
317    $SIG{ALRM} = sub {
318        if (($hit_cnt++ % 5) == 0) {
319            print "+";
320        }
321        else {
322            print "-";
323        }
324        alarm(5);
325    };
326    alarm(5);
327
328    local *OUT;
329    Exec::exec_pipe(*OUT, "LANG=C LC_ALL=C '$::TSKDIR/sorter' $exec");
330    alarm(0);
331    $SIG{ALRM} = 'DEFAULT';
332
333    while ($_ = Exec::read_pipe_line(*OUT)) {
334        print "$_<br>\n";
335        $hit_cnt = 0;
336    }
337
338    close(OUT);
339
340    if (-e "$sort_dir/index.html") {
341        print "<p>Output can be found by viewing:<br>"
342          . "&nbsp;&nbsp;<tt>$sort_dir/index.html</tt><p>\n";
343
344        # Print the index.html file from the output
345        print "<hr><center><h3>Results Summary</h3></center>\n";
346        open INDEX, "<$sort_dir/index.html"
347          or die "Can't open sorter index file ($sort_dir/index.html)";
348
349        while (<INDEX>) {
350            next if ((/^<HTML><HEAD><TITLE>/i)
351                || (/^<BODY><center><H2>/i));
352
353            # Extract out the symlinks to the categories
354            if (/^\s*<li><a href="\.\/[\w\.]+">([\w\s]+)<\/a> \((\d+)\)\s*$/i) {
355                print "<LI>$1 ($2)\n";
356            }
357
358            # Skip the link on the thumbnails link
359            elsif (/^\s*\(<a href=[\"\.\/\w]+>thumbnails<\/A>\)\s*$/) {
360                print "(thumbnails)\n";
361            }
362            else {
363                print "$_";
364            }
365        }
366        close(INDEX);
367    }
368
369    Print::print_html_footer();
370    return;
371}
372
373# View Page
374sub view {
375    Print::print_html_header("");
376    print "<center><h3>File Type Sorting</h3>\n"
377      . "Autopsy does not currently support viewing the sorted files.<br>\n"
378      . "After sorting, you can view the results by opening the following file:<p>\n";
379    print "<tt>" . get_sorter_dir() . "index.html</tt>";
380
381    Print::print_html_footer();
382    return 0;
383}
384
385# Blank Page
386sub blank {
387    Print::print_html_header("");
388    print "<center><h3>File Type Sorting</h3>\n"
389      . "In this mode, Autopsy will examine allocated and unallocated files<br> and "
390      . "sort them into categories and verify the extension.<p>This allows you to find a file based on"
391      . "its type and find \"hidden\" files.<p>\n"
392      .
393
394      "WARNING: This can be a time intensive process.<br>\n";
395
396    Print::print_html_footer();
397    return 0;
398}
399
400