1#
2# Case Management methods, including the windows and functions to read the
3# config files
4#
5# Brian Carrier [carrier@sleuthkit.org]
6# Copyright (c) 2001-2005 by Brian Carrier.  All rights reserved
7#
8# This file is part of the Autopsy Forensic Browser (Autopsy)
9#
10# Autopsy is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# Autopsy is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with Autopsy; if not, write to the Free Software
22# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23#
24# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
25# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
26# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
27# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
30# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35package Caseman;
36
37# If the order of these views are changed, then the order of the main
38# function may have to be as well
39
40# Case Views
41$Caseman::CASE_NEW      = 1;
42$Caseman::CASE_NEW_DOIT = 2;
43$Caseman::CASE_OPEN     = 3;
44$Caseman::CASE_OPEN_LOG = 4;
45$Caseman::CASE_DETAILS  = 5;
46
47# $Caseman::CASE_DEL = 6;
48my $CASE_MAX = 5;
49
50# Host Views
51$Caseman::HOST_ADD      = 7;
52$Caseman::HOST_ADD_DOIT = 8;
53$Caseman::HOST_OPEN     = 9;
54$Caseman::HOST_OPEN_LOG = 10;
55$Caseman::HOST_DETAILS  = 11;
56
57# $Caseman::HOST_DEL = 12;
58my $HOST_MAX = 11;
59
60# Image Views
61$Caseman::IMG_ADD       = 13;
62$Caseman::IMG_ADD_PREP  = 14;
63$Caseman::IMG_ADD_DOIT  = 15;
64$Caseman::VOL_OPEN      = 16;
65$Caseman::VOL_OPEN_LOG  = 17;
66$Caseman::VOL_DETAILS   = 18;
67$Caseman::IMG_DEL       = 19;
68$Caseman::VOL_MAKESTR   = 20;
69$Caseman::VOL_MAKEBLKLS = 21;
70my $IMG_MAX = 21;
71
72# Module Variables
73# %vol2par - Volume to parent volume (vol to img, str to vol)
74# %vol2start - Starting sector of volume in image
75# %vol2end  - ending sector of volume in image
76# %vol2cat - The big picture type of volume (part, disk, strings, blkls)
77# %vol2ftype - The file system type (fat, dos, ntfs etc.)
78# %vol2itype - The image file type (could be for a parent image)
79# %vol2dtype- the disk type
80# %mod2vol;   # Mapping for image, given the strings or blkls
81# %vol2mnt;   # Mapping for mount point, given the vol name
82# %vol2str;   # Mapping for ASCII strings file, given  the vol name
83# %vol2uni;   # Mapping for Unicode strings file, given  the vol name
84# %vol2blkls;   # Mapping for blkls file, given  the vol name
85# %vol2path - full file path of volume
86# %vol2sname - short name of volume
87
88sub main {
89
90    # By default, show the case open window
91    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::CASE_OPEN
92      unless (exists $Args::args{'view'});
93
94    Args::check_view();
95    my $view = Args::get_view();
96
97    # The only live function is for the open img
98    if ($::LIVE == 1) {
99        Args::check_inv();
100        if ($view == $Caseman::VOL_OPEN) {
101            return vol_open();
102        }
103
104        Args::check_vol('vol');
105
106        # Args::check_ftype();
107        # Args::check_mnt();
108
109        if ($view == $Caseman::VOL_OPEN_LOG) {
110            return vol_open_log();
111        }
112        else {
113            Print::print_check_err(
114                "Invalid Live Analysis Case Management View");
115        }
116        return 0;
117    }
118
119    # Case functions
120    if ($view <= $CASE_MAX) {
121        if ($view == $Caseman::CASE_OPEN) {
122            return case_open();
123        }
124        elsif ($view == $Caseman::CASE_NEW) {
125            return case_new();
126        }
127
128        Args::check_case();
129        $::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
130        $::case_dir =~ s/\/\//\//g;
131
132        if ($view == $Caseman::CASE_OPEN_LOG) {
133            return case_open_log();
134        }
135        elsif ($view == $Caseman::CASE_NEW_DOIT) {
136            return case_new_doit();
137        }
138        elsif ($view == $Caseman::CASE_DETAILS) {
139            return case_details();
140        }
141    }
142
143    Args::check_case();
144    $::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
145    $::case_dir =~ s/\/\//\//g;
146
147    # Host functions
148    if ($view <= $HOST_MAX) {
149        if ($view == $Caseman::HOST_OPEN) {
150            return host_open();
151        }
152        elsif ($view == $Caseman::HOST_ADD) {
153            return host_add();
154        }
155
156        Args::check_host();
157        $::host_dir = "$::case_dir" . Args::get_host() . "/";
158        $::host_dir =~ s/\/\//\//g;
159        if ($view == $Caseman::HOST_ADD_DOIT) {
160            return host_add_doit();
161        }
162
163        Caseman::read_host_config();
164        if ($view == $Caseman::HOST_OPEN_LOG) {
165            return host_open_log();
166        }
167        elsif ($view == $Caseman::HOST_DETAILS) {
168            return host_details();
169        }
170    }
171
172    Args::check_host();
173    $::host_dir = "$::case_dir" . Args::get_host() . "/";
174    $::host_dir =~ s/\/\//\//g;
175    Caseman::read_host_config();
176    Args::check_inv();
177
178    if ($view <= $IMG_MAX) {
179        if ($view == $Caseman::VOL_OPEN) {
180            return vol_open();
181        }
182        elsif ($view == $Caseman::IMG_ADD) {
183            return img_add();
184        }
185        elsif ($view == $Caseman::IMG_ADD_PREP) {
186            return img_add_prep();
187        }
188        elsif ($view == $Caseman::IMG_ADD_DOIT) {
189            return img_add_doit();
190        }
191
192        Args::check_vol('vol');
193
194        if ($view == $Caseman::VOL_OPEN_LOG) {
195            return vol_open_log();
196        }
197        elsif ($view == $Caseman::VOL_DETAILS) {
198            return vol_details();
199        }
200
201        #       elsif ($view == $Caseman::IMG_DEL) {
202        # 		return img_del();
203        # 	}
204        elsif ($view == $Caseman::VOL_MAKESTR) {
205            return vol_makestr();
206        }
207        elsif ($view == $Caseman::VOL_MAKEBLKLS) {
208            return vol_makeblkls();
209        }
210    }
211
212    Print::print_check_err("Invalid Case Management View");
213}
214
215####################################################################
216# General menu Functions
217
218sub print_menu_tabs {
219
220    if ($::LIVE == 1) {
221        print "<h2>Live Analysis Mode</h2>\n";
222    }
223
224    print "<table width=\"600\" height=\"60\" background=\"$::YEL_PIX\" "
225      . "border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tr>\n"
226      . "<td align=\"center\" width=\"200\">";
227
228    my $view = Args::get_view();
229
230    # Case Gallery Tab
231    if ($view == $Caseman::CASE_OPEN) {
232        print "<img border=0 src=\"pict/menu_t_cg_cur.jpg\" "
233          . "width=200 height=65 alt=\"Case Gallery (Current Mode)\">\n";
234    }
235    elsif ($::LIVE == 1) {
236        print "<img border=0 src=\"pict/menu_t_cg_org.jpg\" "
237          . "width=200 height=65 alt=\"Case Gallery\">\n";
238    }
239    else {
240        print "<a href=\"$::PROGNAME?"
241          . "mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
242          . "<img border=0 src=\"pict/menu_t_cg_link.jpg\" "
243          . "width=200 height=65 alt=\"Case Gallery\"></a>\n";
244    }
245    print "</td>\n" . "<td align=\"center\" width=\"200\">";
246
247    # Host Gallery Tab
248    # Current
249    if ($view == $Caseman::HOST_OPEN) {
250        print "<img border=0 src=\"pict/menu_t_hg_cur.jpg\" "
251          . "width=200 height=65 alt=\"Host Gallery (Current Mode)\">\n";
252    }
253
254    # Link
255    elsif (($view == $Caseman::VOL_OPEN) && ($::LIVE == 0)) {
256        print "<a href=\"$::PROGNAME?"
257          . "mod=$::MOD_CASEMAN&view=$Caseman::HOST_OPEN"
258          . "&case=$Args::args{'case'}\">"
259          . "<img border=0 src=\"pict/menu_t_hg_link.jpg\" "
260          . "width=200 height=65 alt=\"Host Gallery\"></a>\n";
261    }
262
263    # Non-link
264    else {
265        print "<img border=0 src=\"pict/menu_t_hg_org.jpg\" "
266          . "width=200 height=65 alt=\"Host Gallery (Not Available)\">\n";
267    }
268
269    print "</td>\n" . "<td align=\"center\" width=\"200\">";
270
271    # Host Manager Tab
272    # Current
273    if ($view == $Caseman::VOL_OPEN) {
274        print "<img border=0 src=\"pict/menu_t_hm_cur.jpg\" "
275          . "width=200 height=65 alt=\"Host Manager (Current Mode)\">\n";
276    }
277
278    # non-link
279    else {
280        print "<img border=0 src=\"pict/menu_t_hm_org.jpg\" "
281          . "width=200 height=65 alt=\"Host Manager (Not Available)\">\n";
282    }
283
284    print "</td>\n</tr>\n" . "</table>\n";
285}
286
287####################################################################
288# Case Functions
289
290# if no args are passed, return case config using args{'case'},
291# else use the case value passed
292#
293# Case config:
294# In case directory with case_name.case
295sub case_config_fname {
296    if (scalar(@_) == 1) {
297        my $c = shift;
298        return "$::LOCKDIR/" . "$c/case.aut";
299    }
300    else {
301        return "$::LOCKDIR/" . "$Args::args{'case'}/case.aut";
302    }
303}
304
305# Read case config and save it to $Caseman::cvals
306sub read_case_config {
307    return if ($::LIVE == 1);
308
309    my $case;
310
311    if (scalar(@_) == 1) {
312        $case = shift;
313    }
314    else {
315        $case = Args::get_case();
316    }
317
318    my $fname = case_config_fname($case);
319
320    %Caseman::cvals = ();
321
322    open CONFIG, "<$fname"
323      or die "Can't open case config file ($fname)";
324
325    while (<CONFIG>) {
326        next if ((/^\#/) || (/^\s+$/));
327        s/^\s+//;
328        s/\s+$//;
329        $Caseman::cvals{$1} = Print::html_encode($2) if (/^(\S+)\s+(.*)$/);
330    }
331    close(CONFIG);
332
333    $Caseman::cvals{'desc'} = "None Provided"
334      unless (exists $Caseman::cvals{'desc'});
335
336    $Caseman::cvals{'created'} = "unknown"
337      unless (exists $Caseman::cvals{'created'});
338}
339
340sub case_new {
341    Print::print_html_header("Create A New Case");
342
343    print <<EOF;
344<br>
345<br>
346<center>
347<img src=\"pict/menu_h_cnew.jpg\" alt=\"New Case\">
348<br><br><br>
349
350<table width=\"600\" background=\"$::YEL_PIX\" cellspacing=\"0\"
351  cellpadding=\"2\" border=0>
352<form action=\"$::PROGNAME\" method=\"get\">
353<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
354<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW_DOIT\">
355<tr>
356  <td colspan=3 align=left>
357    1.  <b>Case Name:</b> The name of this investigation.  It can contain only letters, numbers, and symbols.
358  </td>
359</tr>
360<tr>
361  <td>&nbsp;&nbsp;</td>
362  <td align=left colspan=2><input type=\"text\" name=\"case\"></td>
363</tr>
364
365<tr><td colspan=3>&nbsp;</td></tr>
366
367<tr>
368  <td colspan=3 align=left>
369    2.  <b>Description:</b> An optional, one line description of this case.
370  </td>
371</tr>
372<tr>
373  <td>&nbsp;&nbsp;</td>
374  <td align=left colspan=2><input type=\"text\" name=\"desc\" size=32 maxlength=32></td>
375</tr>
376
377<tr><td colspan=3>&nbsp;</td></tr>
378
379<tr>
380  <td colspan=3 align=left>
381    3.  <b>Investigator Names:</b> The optional names (with no spaces) of the investigators for this case.
382  </td>
383</tr>
384<tr>
385  <td>&nbsp;</td>
386  <td align=left><tt>a.</tt> <input type=\"text\" name=\"inv1\"></td>
387  <td align=left><tt>b.</tt> <input type=\"text\" name=\"inv2\"></td>
388</tr>
389<tr>
390  <td>&nbsp;</td>
391  <td align=left><tt>c.</tt> <input type=\"text\" name=\"inv3\"></td>
392  <td align=left><tt>d.</tt> <input type=\"text\" name=\"inv4\"></td>
393</tr>
394<tr>
395  <td>&nbsp;</td>
396  <td align=left><tt>e.</tt> <input type=\"text\" name=\"inv5\"></td>
397  <td align=left><tt>f.</tt> <input type=\"text\" name=\"inv6\"></td>
398</tr>
399<tr>
400  <td>&nbsp;</td>
401  <td align=left><tt>g.</tt> <input type=\"text\" name=\"inv7\"></td>
402  <td align=left><tt>h.</tt> <input type=\"text\" name=\"inv8\"></td>
403</tr>
404<tr>
405  <td>&nbsp;</td>
406  <td align=left><tt>i.</tt> <input type=\"text\" name=\"inv9\"></td>
407  <td align=left><tt>j.</tt> <input type=\"text\" name=\"inv10\"></td>
408</tr>
409</table>
410
411<br><br>
412<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
413<tr>
414  <td align=center>
415    <input type=\"image\" src=\"pict/menu_b_cnew.jpg\"
416      alt=\"Create Case\" width=\"176\" height=20 border=0>
417  </td>
418</form>
419  <td align=center>
420    <form action=\"$::PROGNAME\" method=\"get\">
421    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
422    <input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">
423    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\"
424    alt=\"Cancel\" width=\"167\" height=20 border=0>
425    </form>
426  </td>
427  <td align=center><a href=\"$::HELP_URL\"
428    target=\"_blank\">
429    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\"
430    width=\"167\" height=20 border=0></a>
431  </td>
432</tr>
433</table>
434EOF
435
436    Print::print_html_footer();
437    return;
438}
439
440# Create the directory and case configuration file
441# Gets the input from CASE_NEW
442sub case_new_doit {
443    Print::print_html_header("Creating Case: $Args::args{'case'}");
444    my $case = $Args::args{'case'};
445
446    print "<h3>Creating Case: <tt>$case</tt></h3>\n";
447
448    # Make the directory
449    if (-d "$::case_dir") {
450
451        # we can't send all of this to print_err, bc it doesn't want HTML
452        print "Error: $::case_dir already exists<br>"
453          . "Please remove the directory and its contents and try again"
454          . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
455          . "view=$Caseman::CASE_OPEN\">"
456          . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
457          . "width=\"43\" height=20 border=\"0\"></a>\n";
458        Print::print_err("\n");
459    }
460
461    unless (mkdir "$::case_dir", $::MKDIR_MASK) {
462        Print::print_err("Error making directory $::case_dir: $!");
463    }
464
465    print "Case directory (<tt>$::case_dir</tt>) created<br>\n";
466    Print::log_case_info("Case $case created");
467
468    my $fname = Caseman::case_config_fname();
469
470    open CASE_CONFIG, ">$fname" or die "Can't open case config: $fname";
471
472    print CASE_CONFIG "# Autopsy case config file\n"
473      . "# Case: $case\n\n"
474      . "created "
475      . localtime() . "\n";
476
477    if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
478        Print::print_err(
479            "Invalid Description\n" . "Use the browser's back button to fix")
480          if ($Args::args{'desc'} =~ /\n/);
481
482        print CASE_CONFIG "desc $Args::args{'desc'}\n";
483    }
484    print CASE_CONFIG "images	$::IMGDIR\n";
485    print CASE_CONFIG "data		$::DATADIR\n";
486    print CASE_CONFIG "log		$::LOGDIR\n";
487    print CASE_CONFIG "reports	$::REPDIR\n";
488
489    close CASE_CONFIG;
490    print "Configuration file (<tt>$fname</tt>) created<br>\n";
491
492    my $iname = investig_fname();
493    open INVES, ">>$iname" or die "Can't open investigators file: $iname";
494
495    my @invs;
496    if (   (exists $Args::args{'inv1'})
497        && ($Args::args{'inv1'} ne "")
498        && ($Args::args{'inv1'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
499    {
500        print INVES "$1\n";
501        push @invs, $1;
502    }
503    if (   (exists $Args::args{'inv2'})
504        && ($Args::args{'inv2'} ne "")
505        && ($Args::args{'inv2'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
506    {
507        print INVES "$1\n";
508        push @invs, $1;
509    }
510    if (   (exists $Args::args{'inv3'})
511        && ($Args::args{'inv3'} ne "")
512        && ($Args::args{'inv3'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
513    {
514        print INVES "$1\n";
515        push @invs, $1;
516    }
517    if (   (exists $Args::args{'inv4'})
518        && ($Args::args{'inv4'} ne "")
519        && ($Args::args{'inv4'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
520    {
521        print INVES "$1\n";
522        push @invs, $1;
523    }
524    if (   (exists $Args::args{'inv5'})
525        && ($Args::args{'inv5'} ne "")
526        && ($Args::args{'inv5'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
527    {
528        print INVES "$1\n";
529        push @invs, $1;
530    }
531    if (   (exists $Args::args{'inv6'})
532        && ($Args::args{'inv6'} ne "")
533        && ($Args::args{'inv6'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
534    {
535        print INVES "$1\n";
536        push @invs, $1;
537    }
538    if (   (exists $Args::args{'inv7'})
539        && ($Args::args{'inv7'} ne "")
540        && ($Args::args{'inv7'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
541    {
542        print INVES "$1\n";
543        push @invs, $1;
544    }
545    if (   (exists $Args::args{'inv8'})
546        && ($Args::args{'inv8'} ne "")
547        && ($Args::args{'inv8'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
548    {
549        print INVES "$1\n";
550        push @invs, $1;
551    }
552    if (   (exists $Args::args{'inv9'})
553        && ($Args::args{'inv9'} ne "")
554        && ($Args::args{'inv9'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
555    {
556        print INVES "$1\n";
557        push @invs, $1;
558    }
559    if (   (exists $Args::args{'inv10'})
560        && ($Args::args{'inv10'} ne "")
561        && ($Args::args{'inv10'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
562    {
563        print INVES "$1\n";
564        push @invs, $1;
565    }
566
567    close(INVES);
568
569    Print::log_session_info("Case $case created");
570
571    print "<br><br>We must now create a host for this case.\n";
572
573    print "<form action=\"$::PROGNAME\" method=\"get\">\n"
574      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
575      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
576      . "<input type=\"hidden\" name=\"case\" value=\"$case\">\n";
577
578    if (scalar @invs == 0) {
579        print "<option hiddden name=\"inv\" value=\"unknown\">\n";
580    }
581    else {
582        print "<br><br>Please select your name from the list: "
583          . "<select name=\"inv\" size=\"1\">\n";
584
585        foreach $i (@invs) {
586            print "<option value=\"$i\">$i</option>\n";
587        }
588        print "</select>\n";
589    }
590
591    print "<br><br>"
592      . "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" alt=\"Add New Host\" "
593      . "height=20 border=\"0\"></form>\n";
594
595    Print::print_html_footer();
596    return;
597}
598
599# Open a Case
600# This provides a form with a list of options
601sub case_open {
602    Print::print_html_header("Open A Case");
603
604    # Read the directories of the Evidence Locker into an array
605    # Verify that there is a config file in the directory
606    my @cases;
607    opendir CASES, $::LOCKDIR or die "Can't open $::LOCKDIR directory: $!";
608    foreach my $c (readdir CASES) {
609        next if (($c eq '.') || ($c eq '..'));
610        my $cfile = Caseman::case_config_fname($c);
611
612        push @cases, $c
613          if ((-d "$::LOCKDIR/$c") && (-e "$cfile"));
614    }
615    closedir CASES;
616
617    print "<br><br><center>";
618
619    # Were there any cases?
620    if (scalar @cases == 0) {
621        print "No cases exist in <tt>$::LOCKDIR</tt><br><br>\n"
622          . "Select the New Case button below to make one<br>\n";
623    }
624    else {
625
626        print "Select the case to open or create a new one<br>\n";
627
628        print_menu_tabs();
629
630        print "<table width=\"600\" background=\"$::YEL_PIX\" "
631          . " cellspacing=\"0\" cellpadding=\"2\" border=0>\n";
632
633        print "<form action=\"$::PROGNAME\" method=\"get\">\n"
634          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
635          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN_LOG\">\n"
636          . Args::make_hidden()
637          . "<tr><th>Name</th>"
638          . "<th>Description</th>"
639          . "<td>&nbsp;</td></tr>\n";
640
641        my $first = 0;
642        foreach my $c (@cases) {
643
644            print "<tr><td align=\"left\">"
645              . "<input type=\"radio\" name=\"case\" value=$c";
646            if ($first == 0) {
647                print " CHECKED";
648                $first = 1;
649            }
650            print ">" . Print::html_encode($c) . "</td>";
651
652            Caseman::read_case_config($c);
653
654            print "<td>$Caseman::cvals{'desc'}</td>"
655              . "<td align=center>"
656              . "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
657              . "view=$Caseman::CASE_DETAILS&case=$c\">"
658              . "details</a></td>"
659              . "</tr>\n";
660        }
661        print "</table>\n";
662    }
663
664    print "<br><br>"
665      . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
666      . "<tr>\n";
667
668    # Print the OK button if there were cases
669    if (scalar @cases != 0) {
670        print "<td align=center>"
671          . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
672          . "width=167 height=20 alt=\"Ok\" border=0>"
673          . "</form></td>\n\n";
674    }
675
676    # Print a 'New Case' Button
677    print "<td align=center>"
678      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
679      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
680      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW\">\n"
681      . "<input type=\"image\" src=\"pict/menu_b_cnew.jpg\" "
682      . "width=167 height=20 alt=\"New Case\" border=0>\n"
683      . "</form></td>"
684      .
685
686      # Print a Menu Button
687      "<td align=center>"
688      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
689      . "<input type=\"image\" src=\"pict/menu_b_menu.jpg\" "
690      . "width=167 height=20 alt=\"Main Menu\" border=0>\n"
691      . "</form></td></tr></table>\n";
692
693    print "<table width=600 cellspacing=\"0\" cellpadding=\"2\">\n<tr>"
694      . "<td>&nbsp;</td>\n"
695      . "<td align=center width=200><a href=\"$::HELP_URL\" "
696      . " target=\"_blank\">"
697      . "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
698      . "width=\"167\" height=20 border=0>"
699      . "</a></td>"
700      . "<td>&nbsp;</td>\n"
701      . "</tr>\n"
702      . "</table>";
703
704    Print::print_html_footer();
705    return;
706}
707
708# Log that a given case was opened and then proceed to open a host
709sub case_open_log {
710    Print::log_session_info("Case $Args::args{'case'} opened");
711    Print::log_case_info("Case $Args::args{'case'} opened");
712    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::HOST_OPEN;
713    host_open();
714}
715
716# Display Case Details
717sub case_details {
718
719    Print::print_html_header("Details of $Args::args{'case'}");
720
721    read_case_config();
722
723    print "<br><br>"
724      . "<center>"
725      . "<img src=\"pict/menu_h_cdet.jpg\" alt=\"Case Details\">"
726      . "<br><br><br>\n"
727      . "<table width=\"600\" cellspacing=\"0\" background=\"$::YEL_PIX\" "
728      . "cellpadding=\"2\" border=0>\n"
729      . "  <tr><td align=\"right\" width=300><b>Name:</b></td>"
730      . "<td align=\"left\" width=300><tt>$Args::args{'case'}</tt></td></tr>\n"
731      .
732
733      # Description
734      "  <tr><td align=\"right\"><b>Description:</b></td>"
735      . "<td align=\"left\"><tt>$Caseman::cvals{'desc'}</tt></td></tr>\n"
736      . "  <tr><td align=\"right\"><b>Created:</b></td>"
737      . "<td align=\"left\"><tt>$Caseman::cvals{'created'}</tt></td></tr>\n";
738
739    # Display the valid investigators
740    my @invs = read_invest();
741    my $cnt  = 0;
742    print "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
743      if (scalar @invs > 0);
744
745    foreach my $i (@invs) {
746        if ($cnt == 0) {
747            print "  <tr><td align=\"right\"><b>Investigators:</b></td>";
748            $cnt++;
749        }
750        else {
751            print "  <tr><td>&nbsp;</td>";
752        }
753        print "<td align=\"left\"><tt>"
754          . Print::html_encode($i)
755          . "</tt></td></tr>\n";
756    }
757
758    print "</table>\n"
759      . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
760      . "<img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" "
761      . "width=\"167\" height=20 border=\"0\"></a>";
762
763    Print::print_html_footer();
764    return 0;
765}
766
767####################################################################
768# Host Functions
769
770# if no args are passed, return host config using args{'host'},
771# else use the host value passed
772sub host_config_fname {
773    if (scalar(@_) == 1) {
774        my $h = shift;
775        return "$::case_dir" . "$h/host.aut";
776    }
777    else {
778        return "$::host_dir" . "host.aut";
779    }
780}
781
782# Converts the original single image host config to the volume-based config
783sub convert_host_config {
784
785    return if ($::LIVE == 1);
786
787    my $host = Args::get_host();
788
789    Print::log_host_info("Converting host config files");
790    print STDERR "Converting host config file to new format\n";
791
792    # The file to convert
793    my $cfile = host_config_fname();
794    unless (open(FILE, $cfile)) {
795        Print::print_check_err("Error opening $cfile");
796    }
797
798    my $tmpcfile = "$::host_dir" . "host-convert.aut";
799    unless (open(FILE_TMP, ">>$tmpcfile")) {
800        Print::print_check_err("Error opening $tmpcfile");
801    }
802
803    my $img_cnt = 0;
804    my $vol_cnt = 0;
805    $img2vol{'qazwsxedc'} = ""; # stores the image path to partition / file name
806    $img2vol2{'qazwsxedc'} =
807      "";    # stores the image path to file name (no partitions)
808
809    while (<FILE>) {
810        if ((/^\#/) || (/^\s+$/)) {
811            print FILE_TMP $_;
812            next;
813        }
814
815        # remove whitespace
816        s/^\s+//;
817        s/\s+$//;
818
819        # normal file system image entry
820        #
821        # 'image	images/hda1.dd		openbsd		/usr
822        if (/^image\s+($::REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
823
824            my $i = $1;
825            my $t = $2;
826            my $r = $3;
827
828            # Add trailing / to original mount point if needed
829            if (($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
830                $r .= '/';
831            }
832            my $vnum = "vol" . $vol_cnt;
833            my $inum = "img" . $img_cnt;
834            $img2vol{$i}  = $vnum;
835            $img2vol2{$i} = $inum;
836
837            print FILE_TMP "image   $inum     raw     $i\n";
838            print FILE_TMP "part    $vnum     $inum   0   0   $t  $r\n";
839
840            $img_cnt++;
841            $vol_cnt++;
842        }
843
844        # swap
845        # swap		images/hda3.dd
846        elsif (/^swap\s+($::REG_IMG)\s*$/o) {
847            my $i = $1;
848
849            my $vnum = "vol" . $vol_cnt;
850            my $inum = "img" . $img_cnt;
851            $img2vol{$i}  = $vnum;
852            $img2vol2{$i} = $inum;
853
854            print FILE_TMP "image   $inum     raw     $i\n";
855            print FILE_TMP "part	$vnum   $inum 0   0   swap\n";
856            $img_cnt++;
857            $vol_cnt++;
858
859        }
860
861        # raw
862        # raw	images/hda3.dd
863        elsif (/^raw\s+($::REG_IMG)\s*$/o) {
864            my $i = $1;
865            $img2vol{$i}  = "vol" . $vol_cnt;
866            $img2vol2{$i} = "img" . $img_cnt;
867
868            print FILE_TMP "image   img" . $img_cnt . "     raw     $i\n";
869            print FILE_TMP "part    vol" . $vol_cnt . "   img" . $img_cnt
870              . " 0   0   raw\n";
871            $img_cnt++;
872            $vol_cnt++;
873        }
874
875        # entry for a strings or blkls file
876        #
877        # strings 	data/hda1.str		images/hda1.dd
878        elsif (/^strings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
879            my $i = $1;
880            my $o = $2;
881
882            if (exists $img2vol{$o}) {
883                my $vname = $img2vol{$o};
884                print FILE_TMP "strings vol" . $vol_cnt . "     $vname  $i\n";
885                $img2vol{$i}  = "vol" . $vol_cnt;
886                $img2vol2{$i} = "vol" . $vol_cnt;
887            }
888            else {
889                print STDERR "Error: Volume for strings $o not found<br>\n";
890            }
891            $vol_cnt++;
892        }
893
894        # entry for a strings or blkls file
895        #
896        # unistrings 	data/hda1.str		images/hda1.dd
897        elsif (/^unistrings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
898            my $i = $1;
899            my $o = $2;
900
901            if (exists $img2vol{$o}) {
902                my $vname = $img2vol{$o};
903                print FILE_TMP "unistrings    vol" . $vol_cnt
904                  . "   $vname     $i\n";
905                $img2vol{$i}  = "vol" . $vol_cnt;
906                $img2vol2{$i} = "vol" . $vol_cnt;
907            }
908            else {
909                print STDERR
910                  "Error: Volume for unicode strings $o not found<br>\n";
911            }
912            $vol_cnt++;
913        }
914
915        # blkls entry
916        # blkls data/image.blkls	[images/image.dd]
917        elsif (/^blkls\s+($::REG_IMG)\s*($::REG_IMG)$/o) {
918            my $i = $1;
919            my $o = $2;
920
921            $img2vol{$i} = "vol" . $vol_cnt;
922
923            if (exists $img2vol{$o}) {
924                my $vname = $img2vol{$o};
925                print FILE_TMP "blkls     vol" . $vol_cnt . "  $vname     $i\n";
926                $img2vol{$i}  = "vol" . $vol_cnt;
927                $img2vol2{$i} = "vol" . $vol_cnt;
928            }
929            else {
930                print STDERR "Error: Volume for blkls $o not found<br>\n";
931            }
932            $vol_cnt++;
933        }
934
935        # body data/body.txt
936        elsif (/^body\s+($::REG_IMG)$/o) {
937            my $i = $1;
938            print FILE_TMP "body    vol" . $vol_cnt . " $i\n";
939            $img2vol{$i}  = "vol" . $vol_cnt;
940            $img2vol2{$i} = "vol" . $vol_cnt;
941
942            $vol_cnt++;
943        }
944
945        # timeline data/timeline.txt
946        elsif (/^timeline\s+($::REG_IMG)$/o) {
947            my $i = $1;
948            print FILE_TMP "timeline    vol" . $vol_cnt . " $i\n";
949            $img2vol{$i}  = "vol" . $vol_cnt;
950            $img2vol2{$i} = "vol" . $vol_cnt;
951            $vol_cnt++;
952        }
953
954        # timezone XYZ
955        elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
956            print FILE_TMP "$_\n";
957        }
958
959        # timeskew XYZ
960        elsif (/^timeskew\s+($::REG_SKEW)$/o) {
961            print FILE_TMP "$_\n";
962        }
963
964        # desc XYZ
965        elsif (/^desc\s+(.*)$/) {
966            print FILE_TMP "$_\n";
967        }
968
969        # hash databases
970        elsif (/^alert_db\s+'(.*)'$/) {
971            print FILE_TMP "$_\n";
972        }
973        elsif (/^exclude_db\s+'(.*)'$/) {
974            print FILE_TMP "$_\n";
975        }
976        else {
977            my $msg =
978                "Error: invalid entry in $cfile:$." . "\n"
979              . "image	path	fs_type		mnt_point\n"
980              . "strings	path	orig_img\n"
981              . "blkls		path	[orig_img]\n"
982              . "body		path\n"
983              . "timeline	path\n"
984              . "timezone	TZ\n"
985              . "desc		DESCRIPTION\n";
986            Print::print_check_err($msg);
987        }
988    }
989
990    close(FILE);
991    close(FILE_TMP);
992    unless (rename $cfile, $cfile . ".bak") {
993        print STDERR "Error backing up original host config file\n";
994    }
995    unless (rename $tmpcfile, $cfile) {
996        print STDERR "Error renaming new host config file\n";
997    }
998
999    Notes::convert(\%img2vol);
1000    Hash::convert(\%img2vol2);
1001}
1002
1003# reads host config file and sets global hash values for images and other
1004sub read_host_config {
1005
1006    if ($::LIVE == 1) {
1007        %Caseman::mod2vol    = ();
1008        %Caseman::vol2str    = ();
1009        %Caseman::vol2uni    = ();
1010        %Caseman::vol2blkls  = ();
1011        $Caseman::tz         = "";
1012        $Caseman::ts         = 0;
1013        $Caseman::host_desc  = "";
1014        $Caseman::exclude_db = "";
1015        $Caseman::alert_db   = "";
1016        return;
1017    }
1018
1019    my $host = Args::get_host();
1020
1021    my $cfile = host_config_fname();
1022  restart:
1023    unless (open(FILE, $cfile)) {
1024        Print::print_check_err("Error opening $cfile");
1025    }
1026
1027    %Caseman::vol2mnt   = ();
1028    %Caseman::vol2ftype = ();
1029    %Caseman::vol2dtype = ();
1030    %Caseman::vol2cat   = ();
1031    %Caseman::mod2vol   = ();
1032    %Caseman::vol2str   = ();
1033    %Caseman::vol2uni   = ();
1034    %Caseman::vol2blkls = ();
1035    %Caseman::vol2par   = ();
1036    %Caseman::vol2start = ();
1037    %Caseman::vol2end   = ();
1038    $Caseman::vol2path  = ();
1039    $Caseman::vol2sname = ();
1040
1041    $Caseman::tz         = "";
1042    $Caseman::ts         = 0;
1043    $Caseman::host_desc  = "";
1044    $Caseman::exclude_db = "";
1045    $Caseman::alert_db   = "";
1046
1047    while (<FILE>) {
1048        next if ((/^\#/) || (/^\s+$/));
1049
1050        # remove whitespace
1051        s/^\s+//;
1052        s/\s+$//;
1053
1054        # old file system image entry
1055        #
1056        # 'image	images/hda1.dd		openbsd		/usr
1057        if (/^image\s+($::REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
1058
1059            close(FILE);
1060            convert_host_config();
1061            goto restart;
1062        }
1063        elsif (
1064            /^image\s+($::REG_INAME)\s+($::REG_IMGTYPE)\s+($::REG_IMG_CONFIG)$/o
1065          )
1066        {
1067            my $me = $1;
1068            my $t  = $2;
1069            my $i  = $3;
1070
1071            unless ((-e "$::host_dir$i")
1072                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
1073            {
1074                Print::print_check_err(
1075                        "Error: image $i in ${host}.host:$. not found: "
1076                      . "$::host_dir"
1077                      . "$i \nEdit the config file and refresh your browser\n"
1078                      . "(Or your version of Perl does not support large files)"
1079                );
1080            }
1081
1082            if (exists $Caseman::vol2path{$me}) {
1083                $Caseman::vol2path{$me} .= " \'$::host_dir" . "$i\'";
1084            }
1085            else {
1086                $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
1087                $Caseman::vol2sname{$me} = $i;
1088                $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
1089
1090                $Caseman::vol2par{$me}   = "";
1091                $Caseman::vol2cat{$me}   = "image";
1092                $Caseman::vol2itype{$me} = $t;
1093                $Caseman::vol2ftype{$me} = "";
1094
1095                $Caseman::vol2start{$me} = 0;
1096                $Caseman::vol2end{$me}   = 0;
1097            }
1098        }
1099        elsif (
1100/^part\s+($::REG_VNAME)\s+($::REG_INAME)\s+(\d+)\s+(\d+)\s+($::REG_FTYPE)\s*([\w\-\_\.\/:\\]+)?$/o
1101          )
1102        {
1103            my $par = $2;
1104            my $me  = $1;
1105            my $s   = $3;
1106            my $e   = $4;
1107            my $t   = $5;
1108            my $r   = $6;    # Not defined for swap and raw
1109
1110            unless (exists $Fs::addr_unit{$t}) {
1111                Print::print_check_err(
1112                        "Error: unknown type: $t in host config: $."
1113                      . "\nEdit the file and refresh your browser");
1114            }
1115
1116            if (exists $Caseman::vol2itype{$par}) {
1117                $Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
1118            }
1119            else {
1120                Print::print_check_err(
1121"Error: Image $par for partition $me was not found in config: $."
1122                      . "\nEdit the file and refresh your browser");
1123            }
1124
1125            $Caseman::vol2ftype{$me} = $t;
1126            $Caseman::vol2cat{$me}   = "part";
1127            $Caseman::vol2start{$me} = $s;
1128            $Caseman::vol2end{$me}   = $e;
1129
1130            # Add trailing / to original mount point if needed
1131            if ((defined $r) && ($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
1132                $r .= '/';
1133            }
1134            $Caseman::vol2mnt{$me}   = $r;
1135            $Caseman::vol2par{$me}   = $par;
1136            $Caseman::vol2path{$me}  = $Caseman::vol2path{$par};
1137            $Caseman::vol2sname{$me} =
1138              $Caseman::vol2sname{$par} . "-" . $s . "-" . $e;
1139        }
1140        elsif (/^disk\s+($::REG_VNAME)\s+($::REG_INAME)\s+($::REG_FTYPE)?$/o) {
1141            my $par = $2;
1142            my $me  = $1;
1143            my $t   = $3;
1144
1145            unless (exists $Vs::type{$t}) {
1146                Print::print_check_err(
1147                    "Error: unknown volume system type: $t in host config: $."
1148                      . "\nEdit the file and refresh your browser");
1149            }
1150
1151            if (exists $Caseman::vol2itype{$par}) {
1152                $Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
1153            }
1154            else {
1155                Print::print_check_err(
1156"Error: Image $par for disk $me was not found in config: $.\n"
1157                      . "Edit the file and refresh your browser");
1158            }
1159
1160            $Caseman::vol2ftype{$me} = "raw";
1161            $Caseman::vol2dtype{$me} = $t;
1162            $Caseman::vol2cat{$me}   = "disk";
1163            $Caseman::vol2start{$me} = 0;
1164            $Caseman::vol2end{$me}   = 0;
1165            $Caseman::vol2mnt{$me}   = "";
1166            $Caseman::vol2par{$me}   = $par;
1167            $Caseman::vol2path{$me}  = $Caseman::vol2path{$par};
1168            $Caseman::vol2sname{$me} = $Caseman::vol2sname{$par} . "-disk";
1169        }
1170
1171        # entry for a strings or blkls file
1172        #
1173        # strings 	data/hda1.str		volX
1174        elsif (/^strings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
1175            my $i   = $3;
1176            my $par = $2;
1177            my $me  = $1;
1178
1179            unless ((-e "$::host_dir$i")
1180                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
1181            {
1182                Print::print_check_err("Error: strings file not found: "
1183                      . "$::host_dir$i\nEdit host config in $::host_dir and refresh your browser"
1184                );
1185            }
1186
1187            unless (exists $Caseman::vol2cat{$par}) {
1188                Print::print_check_err(
1189"Error: Volume $par for strings $me was not found in config: $."
1190                      . "\nEdit the file and refresh your browser");
1191            }
1192
1193            $Caseman::vol2ftype{$me} = "strings";
1194            $Caseman::vol2cat{$me}   = "mod";
1195            $Caseman::vol2itype{$me} = "raw";
1196            $Caseman::mod2vol{$me}   = $par;
1197            $Caseman::vol2str{$par}  = $me;
1198            $Caseman::vol2par{$me}   = $par;
1199            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
1200            $Caseman::vol2start{$me} = 0;
1201            $Caseman::vol2end{$me}   = 0;
1202            $Caseman::vol2sname{$me} = $i;
1203            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
1204
1205        }
1206
1207        # entry for a strings or blkls file
1208        #
1209        # unistrings 	data/hda1.str		volX
1210        elsif (/^unistrings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o)
1211        {
1212            my $i   = $3;
1213            my $par = $2;
1214            my $me  = $1;
1215
1216            unless ((-e "$::host_dir$i")
1217                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
1218            {
1219                Print::print_check_err("Error: Unicode strings file not found: "
1220                      . "$::host_dir$i\nEdit host config in $::host_dir and refresh your browser"
1221                );
1222            }
1223
1224            unless (exists $Caseman::vol2cat{$par}) {
1225                Print::print_check_err(
1226"Error: Volume $par for unistrings $me was not found in config: $."
1227                      . "\nEdit the file and refresh your browser");
1228            }
1229
1230            $Caseman::vol2ftype{$me} = "strings";
1231            $Caseman::vol2cat{$me}   = "mod";
1232            $Caseman::vol2itype{$me} = "raw";
1233            $Caseman::mod2vol{$me}   = $par;
1234            $Caseman::vol2uni{$par}  = $me;
1235            $Caseman::vol2par{$me}   = $par;
1236            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
1237            $Caseman::vol2start{$me} = 0;
1238            $Caseman::vol2end{$me}   = 0;
1239            $Caseman::vol2sname{$me} = $i;
1240            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
1241        }
1242
1243        # blkls entry
1244        # blkls themname	myname
1245        elsif ((/^blkls\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) ||
1246          (/^dls\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o)) {
1247            my $i   = $3;
1248            my $par = $2;
1249            my $me  = $1;
1250
1251            unless (
1252                (-e "$::host_dir$i")
1253                || (   (-l "$::host_dir$i")
1254                    && (-e readlink "$::host_dir$i"))
1255              )
1256            {
1257                Print::print_check_err("Error: blkls file not found: "
1258                      . "$::host_dir$i \nEdit host config in $::host_dir and refresh your browser"
1259                );
1260            }
1261
1262            unless (exists $Caseman::vol2cat{$par}) {
1263                Print::print_check_err(
1264"Error: Volume $par for blkls $me was not found in config: $."
1265                      . "\nEdit the file and refresh your browser");
1266            }
1267
1268            $Caseman::vol2ftype{$me}  = "blkls";
1269            $Caseman::vol2cat{$me}    = "mod";
1270            $Caseman::vol2itype{$me}  = "raw";
1271            $Caseman::vol2mnt{$me}    = "";
1272            $Caseman::vol2par{$me}    = $par;
1273            $Caseman::mod2vol{$me}    = $par;
1274            $Caseman::vol2blkls{$par} = $me;
1275            $Caseman::vol2path{$me}   = "\'$::host_dir" . "$i\'";
1276            $Caseman::vol2start{$me}  = 0;
1277            $Caseman::vol2end{$me}    = 0;
1278            $Caseman::vol2sname{$me}  = $i;
1279            $Caseman::vol2sname{$me}  = $1 if ($i =~ /\/($::REG_FILE)$/);
1280
1281        }
1282
1283        # body data/body.txt
1284        elsif (/^body\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
1285            my $me = $1;
1286            my $i  = $2;
1287
1288            unless ((-e "$::host_dir$i")
1289                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
1290            {
1291                Print::print_check_err("Error: body file not found: "
1292                      . "$::host_dir$i <br>Edit host config in $::host_dir and refresh your browser"
1293                );
1294            }
1295
1296            $Caseman::vol2cat{$me}   = "timeline";
1297            $Caseman::vol2ftype{$me} = "body";
1298            $Caseman::vol2itype{$me} = "raw";
1299            $Caseman::vol2path{$me}  = "\'$::host_dir" . "$i\'";
1300            $Caseman::vol2start{$me} = 0;
1301            $Caseman::vol2end{$me}   = 0;
1302            $Caseman::vol2sname{$me} = $i;
1303            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
1304        }
1305
1306        # timeline data/timeline.txt
1307        elsif (/^timeline\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
1308            my $me = $1;
1309            my $i  = $2;
1310
1311            unless ((-e "$::host_dir$i")
1312                || ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
1313            {
1314                Print::print_check_err("Error: timeline file not found: "
1315                      . "$::host_dir$i \nEdit host config in $::host_dir and refresh your browser"
1316                );
1317            }
1318
1319            $Caseman::vol2cat{$me}   = "timeline";
1320            $Caseman::vol2ftype{$me} = "timeline";
1321            $Caseman::vol2itype{$me} = "raw";
1322
1323# We do not add the quotes to the path for timeline because it is opened only by the Perl code and it doesn't like the quotes
1324            $Caseman::vol2path{$me}  = "$::host_dir" . "$i";
1325            $Caseman::vol2start{$me} = 0;
1326            $Caseman::vol2end{$me}   = 0;
1327            $Caseman::vol2sname{$me} = $i;
1328            $Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
1329
1330        }
1331
1332        # timezone XYZ
1333        elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
1334            $Caseman::tz = "\'$1\'";
1335        }
1336
1337        # timeskew XYZ
1338        elsif (/^timeskew\s+($::REG_SKEW)$/o) {
1339            $Caseman::ts = "\'$1\'";
1340        }
1341
1342        # desc XYZ
1343        elsif (/^desc\s+(.*)$/) {
1344            $Caseman::host_desc = Print::html_encode($1);
1345        }
1346
1347        # hash databases
1348        elsif (/^alert_db\s+'($::REG_HASHDB)'$/) {
1349            $Caseman::alert_db = "$1";
1350        }
1351        elsif (/^exclude_db\s+'($::REG_HASHDB)'$/) {
1352            $Caseman::exclude_db = "$1";
1353        }
1354        else {
1355            my $msg = "Error: invalid entry in $cfile:$." . "\n" . "$_\n";
1356            Print::print_check_err($msg);
1357        }
1358    }
1359    close(FILE);
1360}
1361
1362# Add a new image entry to the host config and return its id
1363sub add_img_host_config {
1364    my $type  = shift;
1365    my $other = shift;
1366    my $id    = shift;
1367
1368    my $read  = host_config_fname();
1369    my $write = $read . "-" . rand();
1370
1371    unless (open(READ, "<$read")) {
1372        Print::print_check_err("Error opening $read");
1373    }
1374
1375    unless (open(WRITE, ">$write")) {
1376        Print::print_check_err("Error opening $write");
1377    }
1378
1379    my $maxcnt = 0;
1380
1381    while (<READ>) {
1382        s/^\s+//;
1383        s/\s+$//;
1384        if (/^\w+\s+img(\d+)\s+.*$/) {
1385            $maxcnt = $1 if ($1 > $maxcnt);
1386        }
1387        print WRITE "$_\n";
1388    }
1389    $maxcnt++;
1390    if ($id eq "") {
1391        $id = "img" . $maxcnt;
1392    }
1393    print WRITE "$type  $id  $other\n";
1394
1395    Print::log_host_info("Image added: $type $id $other");
1396
1397    close(READ);
1398    close(WRITE);
1399    unless (rename $write, $read) {
1400        print STDERR "Error renaming temp host config file\n";
1401    }
1402
1403    return $id;
1404}
1405
1406# Add a new volume entry to the host config and return its id
1407sub add_vol_host_config {
1408    my $type  = shift;
1409    my $other = shift;
1410
1411    my $read  = host_config_fname();
1412    my $write = $read . "-" . rand();
1413
1414    unless (open(READ, "<$read")) {
1415        Print::print_check_err("Error opening $read");
1416    }
1417
1418    unless (open(WRITE, ">$write")) {
1419        Print::print_check_err("Error opening $write");
1420    }
1421
1422    # We want to find the max count ... not just the unused
1423    # ones because we could end up reusing one and that could
1424    # mess up the notes
1425    my $maxcnt = 0;
1426
1427    while (<READ>) {
1428        s/^\s+//;
1429        s/\s+$//;
1430        if (/^\w+\s+vol(\d+)\s+.*$/) {
1431            $maxcnt = $1 if ($1 > $maxcnt);
1432        }
1433        print WRITE "$_\n";
1434    }
1435    $maxcnt++;
1436    print WRITE "$type  vol" . $maxcnt . "  $other\n";
1437    Print::log_host_info("Volume added: $type  vol" . $maxcnt . " $other");
1438
1439    close(READ);
1440    close(WRITE);
1441    unless (rename $write, $read) {
1442        print STDERR "Error renaming temp host config file\n";
1443    }
1444
1445    return "vol" . $maxcnt;
1446}
1447
1448# Delete anentry from the host config
1449# DOES NOT WORK RIGHT NOW
1450sub del_host_config_BLAH {
1451    return;
1452    my $type  = shift;
1453    my $other = shift;
1454
1455    my $read  = host_config_fname();
1456    my $write = $read . "-" . rand();
1457
1458    unless (open(READ, "<$read")) {
1459        Print::print_check_err("Error opening $read");
1460    }
1461
1462    unless (open(WRITE, ">$write")) {
1463        Print::print_check_err("Error opening $write");
1464    }
1465
1466    while (<READ>) {
1467        s/^\s+//;
1468        s/\s+$//;
1469        print WRITE "$_\n"
1470          unless ((/^(\w+)\s+($::REG_IMG)/o)
1471            && ($2 eq $img)
1472            && ($1 ne 'desc')
1473            && ($1 ne 'timezone'));
1474    }
1475
1476    if ($type ne "") {
1477        if (defined $ref) {
1478            print WRITE "$type  $img    $ref\n";
1479        }
1480        else {
1481            print WRITE "$type  $img\n";
1482        }
1483    }
1484
1485    close(READ);
1486    close(WRITE);
1487    unless (rename $write, $read) {
1488        print STDERR "Error renaming temp host config file\n";
1489    }
1490
1491    return;
1492}
1493
1494# Given the image and md5, it is saved to the MD5.txt file and any other
1495# references to the image are removed
1496#
1497# if $md5 is "", then nothing is written
1498sub update_md5 {
1499    my $vol = shift;
1500    my $md5 = shift;
1501    $md5 =~ tr/[a-f]/[A-F]/;
1502
1503    my $read  = "$::host_dir/md5.txt";
1504    my $write = $read . "-" . rand();
1505
1506    unless (open(WRITE, ">$write")) {
1507        Print::print_check_err("Error opening $write");
1508    }
1509
1510    if (-e "$read") {
1511        unless (open(READ, "<$read")) {
1512            Print::print_check_err("Error opening $read");
1513        }
1514
1515        while (<READ>) {
1516            s/^\s+//;
1517            s/\s+$//;
1518            print WRITE "$_\n"
1519              unless ((/^$::REG_MD5\s+($::REG_VNAME)/o) && ($1 eq $vol));
1520        }
1521        close(READ);
1522    }
1523
1524    print WRITE "$md5   $vol\n" if ($md5 ne "");
1525
1526    close(WRITE);
1527
1528    unless (rename $write, $read) {
1529        print STDERR "Error renaming temp MD5 hash file\n";
1530    }
1531    return;
1532}
1533
1534sub host_add {
1535    Print::print_html_header("Add A New Host To $Args::args{'case'}");
1536
1537    print "<b>Case: </b> $Args::args{'case'}<br><br>\n";
1538
1539    print "<center>"
1540      . "<img src=\"pict/menu_h_hnew.jpg\" alt=\"Add Host\">"
1541      . "<br><br><br>\n";
1542
1543    print "<table width=\"600\" cellspacing=\"0\" background=\"$::YEL_PIX\" "
1544      . "cellpadding=\"2\" border=0>\n"
1545      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
1546      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1547      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD_DOIT\">\n"
1548      . Args::make_hidden()
1549      . "<tr><td colspan=\"2\">&nbsp;</td></tr>"
1550      .
1551
1552      # Host name
1553"<tr><td align=\"left\" colspan=2>1.  <b>Host Name:</b>  The name of the computer being investigated.  It can contain only letters, numbers, and symbols.</td></tr>"
1554      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1555      . "<td align=\"left\"><input type=\"text\" name=\"host\" size=32 maxlength=32 value=\"host1\"></td></tr>\n"
1556      .
1557
1558      # Description
1559"<tr><td align=\"left\" colspan=2>2.  <b>Description:</b>  An optional one-line description or note about this computer.</td></tr>"
1560      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1561      . "<td align=\"left\">"
1562      . "<input type=\"text\" name=\"desc\" size=32 maxlength=32></td></tr>\n"
1563      .
1564
1565      # Empty line
1566      "<tr><td colspan=\"2\">&nbsp;</td></tr>" .
1567
1568      # Timezone
1569"<tr><td align=\"left\" colspan=2>3.  <b>Time zone:</b> An optional timezone value (i.e. EST5EDT).  If not given, it defaults to the local setting.  A list of time zones can be found in the help files.</td></tr>"
1570      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1571      . "<td align=\"left\">"
1572      . "<input type=\"text\" name=\"tz\" size=16 maxlength=64></td></tr>\n"
1573      .
1574
1575      # Timeskew
1576"<tr><td align=\"left\" colspan=2>4.  <b>Timeskew Adjustment:</b> An optional value to describe how many seconds this computer's clock was out of sync.  For example, if the computer was 10 seconds fast, then enter -10 to compensate.</td></tr>"
1577      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1578      . "<td align=\"left\">"
1579      . "<input type=\"text\" name=\"ts\" size=8 maxlength=16 value=\"0\">"
1580      . "</td></tr>\n"
1581      .
1582
1583      # Spacer
1584      "<tr><td colspan=\"2\">&nbsp;</td></tr>" .
1585
1586      # Alert
1587"<tr><td align=\"left\" colspan=2>5.  <b>Path of Alert Hash Database:</b> An optional hash database of known bad files.</td></tr>"
1588      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1589      . "<td align=\"left\">"
1590      . "<input type=\"text\" name=\"alert_db\" size=32 maxlength=512>"
1591      . "</td></tr>\n"
1592      .
1593
1594      # Ignore
1595"<tr><td align=\"left\" colspan=2>6.  <b>Path of Ignore Hash Database:</b> An optional hash database of known good files.</td></tr>"
1596      . "<tr><td align=\"left\">&nbsp;&nbsp;&nbsp;</td>"
1597      . "<td align=\"left\">"
1598      . "<input type=\"text\" name=\"exclude_db\" size=32 maxlength=512>"
1599      . "</td></tr>\n"
1600      .
1601
1602      # Spacer
1603      "<tr><td colspan=\"2\">&nbsp;</td></tr>" . "</table>\n";
1604
1605    if (exists $Args::args{'inv'}) {
1606        print
1607          "<input type=\"hidden\" name=\"inv\" value=\"$Args::args{'inv'}\">\n";
1608    }
1609
1610    # Ok Button
1611    print "<br><br><table width=\"600\" cellspacing=\"8\" cellpadding=\"2\">\n"
1612      . "<tr><td align=center>"
1613      . "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" "
1614      . "width=167 height=20 alt=\"Add Host\" border=0>\n"
1615      . "</form></td>\n"
1616      .
1617
1618      # Cancel Button
1619      "<td align=center>"
1620      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
1621      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1622      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
1623      . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
1624      . "<input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
1625      . "alt=\"Cancel\" width=\"167\" height=20 border=0>\n"
1626      . "</form></td>\n"
1627      .
1628
1629      # Help Button
1630      "<td align=center><a href=\"$::HELP_URL\" "
1631      . "target=\"_blank\">"
1632      . "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
1633      . "width=\"167\" height=20 border=0></a>"
1634      . "</td></tr>\n"
1635      . "</table>";
1636
1637    Print::print_html_footer();
1638
1639    return 0;
1640}
1641
1642# Make the directories and config files for a host
1643sub host_add_doit {
1644    Args::check_tz()
1645      if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
1646    Args::check_ts();
1647    Print::print_html_header(
1648        "Adding Host $Args::args{'host'} to $Args::args{'case'}");
1649
1650    print "<h3>Adding host: <tt>$Args::args{'host'}</tt> to "
1651      . "case <tt>$Args::args{'case'}</tt></h3>\n";
1652
1653    # Do some sanity checks before we start making the directories and such
1654    if (   (exists $Args::args{'alert_db'})
1655        && ($Args::args{'alert_db'} ne ""))
1656    {
1657
1658        unless ($Args::args{'alert_db'} =~ /^$::REG_HASHDB$/o) {
1659            print "Invalid Alert Database path\n"
1660              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1661              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
1662              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
1663              . "width=\"43\" height=20 border=\"0\"></a>\n";
1664            return 1;
1665        }
1666
1667        unless (-e "$Args::args{'alert_db'}") {
1668            print "Alert Database Not Found: $Args::args{'alert_db'}"
1669              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1670              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
1671              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
1672              . "width=\"43\" height=20 border=\"0\"></a>\n";
1673            return 1;
1674        }
1675    }
1676
1677    if (   (exists $Args::args{'exclude_db'})
1678        && ($Args::args{'exclude_db'} ne ""))
1679    {
1680        unless ($Args::args{'exclude_db'} =~ /^$::REG_HASHDB$/o) {
1681            print "Invalid Exclude Database path\n"
1682              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1683              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
1684              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
1685              . "width=\"43\" height=20 border=\"0\"></a>\n";
1686            return 1;
1687        }
1688
1689        unless (-e "$Args::args{'exclude_db'}") {
1690            print "Exclude Database Not Found: $Args::args{'exclude_db'}"
1691              . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1692              . "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
1693              . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
1694              . "width=\"43\" height=20 border=\"0\"></a>\n";
1695            return 1;
1696        }
1697    }
1698
1699    # Make the directory
1700    if (-d "$::host_dir") {
1701
1702        print "Error: $::host_dir already exists<br>"
1703          . "Please remove the directory and its contents and try again"
1704          . "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1705          . "view=$Caseman::HOST_OPEN&case=$Args::enc_args{'case'}\">"
1706          . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
1707          . "width=\"43\" height=20 border=\"0\"></a>\n";
1708        Print::print_err("\n");
1709    }
1710    unless (mkdir "$::host_dir", $::MKDIR_MASK) {
1711        Print::print_err("Error making directory $::host_dir: $!");
1712    }
1713
1714    print "Host Directory (<tt>$::host_dir</tt>) created<p>\n";
1715    Print::log_case_info("Host $Args::args{'host'} added to case");
1716
1717    # Images directory
1718    unless (mkdir "$::host_dir" . "$::IMGDIR", $::MKDIR_MASK) {
1719        rmdir "$::host_dir";
1720        Print::print_err("Error making $::host_dir" . "$::IMGDIR");
1721    }
1722
1723    # Output Directory
1724    unless (mkdir "$::host_dir" . "$::DATADIR", $::MKDIR_MASK) {
1725        rmdir "$::host_dir" . "$::IMGDIR";
1726        rmdir "$::host_dir";
1727        Print::print_err("Error making $::host_dir" . "$::DATADIR");
1728    }
1729
1730    # Log Directory
1731    unless (mkdir "$::host_dir" . "$::LOGDIR", $::MKDIR_MASK) {
1732        rmdir "$::host_dir" . "$::DATADIR";
1733        rmdir "$::host_dir" . "$::IMGDIR";
1734        rmdir "$::host_dir";
1735        Print::print_err("Error making $::host_dir" . "$::LOGDIR");
1736    }
1737
1738    # Reports directory
1739    unless (mkdir "$::host_dir" . "$::REPDIR", $::MKDIR_MASK) {
1740        rmdir "$::host_dir" . "$::LOGDIR";
1741        rmdir "$::host_dir" . "$::DATADIR";
1742        rmdir "$::host_dir" . "$::IMGDIR";
1743        rmdir "$::host_dir";
1744        Print::print_err("Error making $::host_dir" . "$::REPDIR");
1745    }
1746
1747    # Make a directory for mounting the image in loopback
1748    unless (mkdir "$::host_dir" . "mnt", $::MKDIR_MASK) {
1749        rmdir "$::host_dir" . "$::REPDIR";
1750        rmdir "$::host_dir" . "$::LOGDIR";
1751        rmdir "$::host_dir" . "$::DATADIR";
1752        rmdir "$::host_dir" . "$::IMGDIR";
1753        rmdir "$::host_dir";
1754        Print::print_err("Error making $::host_dir" . "mnt");
1755    }
1756
1757    Print::log_host_info(
1758        "Host $Args::args{'host'} added to case $Args::args{'case'}");
1759
1760    # Create config file
1761    my $fname = Caseman::host_config_fname();
1762    open HOST_CONFIG, ">$fname" or die "Can't open host config: $fname";
1763
1764    print HOST_CONFIG "# Autopsy host config file\n"
1765      . "# Case: $Args::args{'case'}		Host: $Args::args{'host'}\n"
1766      . "# Created: "
1767      . localtime() . "\n\n";
1768
1769    if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
1770        Print::print_err(
1771            "Invalid Description\n" . "Use the browser's back button to fix")
1772          if ($Args::args{'desc'} =~ /\n/);
1773
1774        print HOST_CONFIG "desc $Args::args{'desc'}\n";
1775    }
1776
1777    print HOST_CONFIG "timezone  " . Args::get_tz() . "\n"
1778      if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
1779    print HOST_CONFIG "timeskew  " . Args::get_ts() . "\n";
1780
1781    if (   (exists $Args::args{'alert_db'})
1782        && ($Args::args{'alert_db'} ne ""))
1783    {
1784
1785        # Index it if it is not
1786        unless (-e "$Args::args{'alert_db'}-md5.idx") {
1787            print
1788"Alert Database has not been indexed - it will be as an md5sum file<br>\n";
1789
1790            print "<hr>\n";
1791            Hash::index_md5sum($Args::args{'alert_db'});
1792            print "<hr>\n";
1793        }
1794
1795        # only print it if it was successful
1796        print HOST_CONFIG "alert_db \'$Args::args{'alert_db'}\'\n"
1797          if (-e "$Args::args{'alert_db'}-md5.idx");
1798    }
1799
1800    if (   (exists $Args::args{'exclude_db'})
1801        && ($Args::args{'exclude_db'} ne ""))
1802    {
1803
1804        # Index it if it is not
1805        unless (-e "$Args::args{'exclude_db'}-md5.idx") {
1806            print
1807"Exclude Database has not been indexed - it will be as an md5sum file<br>\n";
1808
1809            print "<hr>\n";
1810            Hash::index_md5sum($Args::args{'exclude_db'});
1811            print "<hr>\n";
1812        }
1813
1814        # only print it if it was successful
1815        print HOST_CONFIG "exclude_db \'$Args::args{'exclude_db'}\'\n"
1816          if (-e "$Args::args{'exclude_db'}-md5.idx");
1817    }
1818
1819    close HOST_CONFIG;
1820
1821    print "Configuration file (<tt>$fname</tt>) created<br><br>\n";
1822
1823    print "We must now import an image file for this host\n";
1824
1825    print "<br><br><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1826      . "view=$Caseman::HOST_OPEN_LOG&$Args::baseargs\">"
1827      . "<img src=\"pict/menu_b_inew.jpg\" alt=\"Add Image\" "
1828      . " height=20 border=\"0\"></a>\n";
1829
1830    Print::print_html_footer();
1831    return 0;
1832}
1833
1834# Open a host in the given case
1835sub host_open {
1836    Print::print_html_header("Open Host In $Args::args{'case'}");
1837
1838    # Create an array of directories in the case, verifying that there is
1839    # a config file
1840    my @hosts;
1841    opendir HOSTS, $::case_dir or die "Can't open $::case_dir directory: $!";
1842    foreach my $h (readdir HOSTS) {
1843        next if (($h eq '.') || ($h eq '..'));
1844
1845        my $hfile = Caseman::host_config_fname($h);
1846        push @hosts, $h
1847          if ((-d "$::case_dir" . "$h") && (-e "$hfile"));
1848    }
1849    closedir HOSTS;
1850
1851    print "<b>Case:</b> $Args::args{'case'}<br><br>\n";
1852
1853    print "<center>";
1854
1855    if (scalar @hosts == 0) {
1856        print "No hosts have been added to the case yet"
1857          . "<br><br>Select the Add Host button below to create one.<br>\n";
1858    }
1859    else {
1860
1861        print "Select the host to open or create a new one<br>\n";
1862
1863        print_menu_tabs();
1864
1865        print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
1866          . "background=\"$::YEL_PIX\" border=0>\n";
1867
1868        print "<form action=\"$::PROGNAME\" method=\"get\">\n"
1869          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1870          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
1871          . Args::make_hidden()
1872          . "<tr><th>Name</th>"
1873          . "<th>Description</th><th>&nbsp;</th></tr>\n";
1874
1875        my $first = 0;
1876        foreach my $h (@hosts) {
1877
1878            print "<tr><td align=\"left\">"
1879              . "<input type=\"radio\" name=\"host\" value=$h";
1880            if ($first == 0) {
1881                print " CHECKED";
1882                $first = 1;
1883            }
1884            print "> " . Print::html_encode($h) . " </td>";
1885
1886            my $fname = Caseman::host_config_fname($h);
1887            open CONFIG, "<$fname"
1888              or die "Can't open host config file ($fname)";
1889
1890            my $desc = "None Provided";
1891            while (<CONFIG>) {
1892                s/^\s+//;
1893                s/\s+$//;
1894
1895                if (/^desc\s+(.*)$/) {
1896                    $desc = Print::html_encode($1);
1897                    last;
1898                }
1899            }
1900            close CONFIG;
1901
1902            print "<td align=left>$desc</td>"
1903              . "<td align=center>"
1904              . "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
1905              . "view=$Caseman::HOST_DETAILS&$Args::baseargs&"
1906              . "host=$h\">details</a></td></tr>\n";
1907        }
1908        print "</table>\n";
1909
1910        # Display pulldown of investigators
1911        my @invs = read_invest();
1912        if (scalar @invs == 0) {
1913            print "<input type=\"hidden\" name=\"inv\" value=\"unknown\">\n";
1914        }
1915        else {
1916            print "<br>Investigator (for reports only): ";
1917            my $cur_inv = "";
1918            $cur_inv = $Args::args{'inv'} if (exists $Args::args{'inv'});
1919
1920            print "<select name=\"inv\" size=\"1\">\n";
1921
1922            if (($cur_inv eq "") && (scalar @invs != 1)) {
1923                print "<option value=\"\" selected>Select One" . "</option>\n";
1924            }
1925            foreach my $i (@invs) {
1926                print "<option value=\"$i\"";
1927                print " selected" if ($cur_inv eq $i);
1928                print ">" . Print::html_encode($i) . "</option>\n";
1929            }
1930            print "</select>\n";
1931        }
1932    }
1933    print "<br><br><table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
1934      . "<tr>\n";
1935
1936    # Make a table for the buttons.  The table will either be 3 or 2
1937    # entries wide, depending on if there is an 'Ok' button or not
1938
1939    unless (scalar @hosts == 0) {
1940        print "<td align=center>"
1941          . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
1942          . "alt=\"Ok\" width=\"167\" height=20 border=0>\n"
1943          . "</form>\n</td>\n";
1944    }
1945
1946    # Add Host
1947    print "<td align=center>"
1948      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
1949      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1950      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
1951      . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
1952      . "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" "
1953      . "alt=\"Add Host\" width=\"176\" height=20 border=0>\n"
1954      . "</form></td>"
1955      .
1956
1957      # Close Button
1958      "<td align=center>"
1959      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
1960      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1961      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">\n"
1962      . "<input type=\"image\" src=\"pict/menu_b_ccls.jpg\" "
1963      . "alt=\"Close Case\" width=\"176\" height=20 border=0>\n"
1964      . "</form></td></tr></table>\n";
1965
1966    print "<table width=\"600\"  cellspacing=\"0\" cellpadding=\"2\">\n"
1967      . "<tr><td>&nbsp;</td>"
1968      . "<td align=center><a href=\"$::HELP_URL\" "
1969      . " target=\"_blank\">"
1970      . "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
1971      . "width=\"167\" height=20 border=0>"
1972      . "</a></td><td>&nbsp;</td></tr>\n"
1973      . "</table>\n";
1974
1975    Print::print_html_footer();
1976    return 0;
1977}
1978
1979# Log that a given host was opened and then proceed to open an image
1980sub host_open_log {
1981    unless ((exists $Args::args{'inv'}) && ($Args::args{'inv'} ne "")) {
1982        my @invs = read_invest();
1983        if (scalar @invs == 0) {
1984            $Args::args{'inv'} = $Args::enc_args{'inv'} = 'unknown';
1985        }
1986        else {
1987            Print::print_html_header("Missing Investigator");
1988            print "<br>An investigator must be selected<p>\n"
1989              . "<form action=\"$::PROGNAME\" method=\"get\">\n"
1990              . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
1991              . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
1992              . Args::make_hidden();
1993
1994            print "Select one of the following:";
1995            print "<select name=\"inv\" size=\"1\">\n";
1996
1997            print "<option value=\"\" selected>Select One" . "</option>\n";
1998
1999            foreach my $i (@invs) {
2000                print "<option value=\"$i\">$i</option>\n";
2001            }
2002            print "</select><p>\n"
2003              . "<input type=\"image\" src=\"pict/but_ok.jpg\" alt=\"Ok\" "
2004              . "width=43 height=20 border=\"0\">\n"
2005              . "</form>\n";
2006
2007            Print::print_html_footer();
2008            return 0;
2009        }
2010    }
2011
2012    Args::check_inv();
2013    Print::log_case_info(
2014        "Host $Args::args{'host'} opened by $Args::args{'inv'}");
2015    Print::log_host_info(
2016        "Host $Args::args{'host'} opened by $Args::args{'inv'}");
2017    Print::log_host_inv("Host $Args::args{'host'} opened");
2018
2019    $Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::VOL_OPEN;
2020    vol_open();
2021}
2022
2023# Provide details about the configuration of a host.  This window is
2024# a link from the HOST_OPEN window
2025sub host_details {
2026    Print::print_html_header(
2027        "Details of $Args::args{'case'}:$Args::args{'host'}");
2028
2029    print "<b>Case: </b>$Args::args{'case'}<br><br>"
2030      . "<center>"
2031      . "<img src=\"pict/menu_h_hdet.jpg\" alt=\"Host Details\">"
2032      . "<br><br><br>\n"
2033      . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
2034      . "background=\"$::YEL_PIX\" border=0>\n"
2035      .
2036
2037      # Name
2038      "<tr><td align=\"right\" width=300><b>Name:</b></td>"
2039      . "<td align=\"left\" width=300><tt>$Args::args{'host'}</tt></td></tr>\n"
2040      .
2041
2042      # Description
2043      "<tr><td align=\"right\"><b>Description:</b></td>"
2044      . "<td align=\"left\"><tt>"
2045      . (($Caseman::host_desc ne "") ? $Caseman::host_desc : "&nbsp;")
2046      . "</tt></td></tr>\n"
2047      .
2048
2049      # Timezone
2050      "<tr><td align=\"right\"><b>Time zone: </b></td>"
2051      . "<td align=\"left\"><tt>$Caseman::tz</tt></td></tr>\n"
2052      .
2053
2054      # Timeskew
2055      "<tr><td align=\"right\"><b>Timeskew:</b></td>"
2056      . "<td align=\"left\"><tt>$Caseman::ts</tt></td></tr>\n"
2057      . "<tr><td colspan=2>&nbsp;</td></tr>\n"
2058      .
2059
2060      # Actual Directory
2061      "<tr><td align=\"right\"><b>Directory:</b></td>"
2062      . "<td align=\"left\"><tt>"
2063      . Print::html_encode($::host_dir)
2064      . "</tt></td></tr>\n"
2065      . "<tr><td colspan=2>&nbsp;</td></tr>\n"
2066      .
2067
2068      # Alert Database
2069      "<tr><td align=\"right\"><b>Alert Hash Database:</b></td>"
2070      . "<td align=\"left\"><tt>"
2071      . (($Caseman::alert_db ne "")
2072        ? Print::html_encode($Caseman::alert_db)
2073        : "&nbsp;")
2074      . "</tt></td></tr>\n"
2075      .
2076
2077      # Exclude Database
2078      "<tr><td align=\"right\"><b>Exclude Hash Database:</b></td>"
2079      . "<td align=\"left\"><tt>"
2080      . (($Caseman::exclude_db ne "")
2081        ? Print::html_encode($Caseman::exclude_db)
2082        : "&nbsp;")
2083      . "</tt></td></tr>\n"
2084      . "</table>\n";
2085
2086    # Final Button
2087    print "<br><br><form action=\"$::PROGNAME\" method=\"get\">\n"
2088      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2089      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
2090      . Args::make_hidden()
2091      . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
2092      . "alt=\"Ok\" width=\"167\" height=20 border=\"0\">\n</form>";
2093
2094    Print::print_html_footer();
2095
2096    return;
2097}
2098
2099# Read the investigators file and return a sorted list
2100sub read_invest {
2101    my $fname = investig_fname();
2102    open INVES, "<$fname" or return;
2103
2104    my @investigs;
2105    while (<INVES>) {
2106        chomp;
2107        s/^\s+//;
2108        s/\s+$//;
2109        push @investigs, $1
2110          if (/^($::REG_INVESTIG)$/o);
2111    }
2112    close(INVES);
2113    sort { lc($a) cmp lc($b) } @investigs;
2114}
2115
2116# File of investigators name in list
2117sub investig_fname {
2118    return "$::case_dir" . "investigators.txt";
2119}
2120
2121####################################################################
2122# Image Functions
2123
2124# Types of modes for fname (i.e. can we overwrite it if it exists)
2125my $FNAME_MODE_INIT = 0;
2126my $FNAME_MODE_OVER = 1;
2127
2128my $MD5_NOTHING = 1;
2129my $MD5_CALC    = 2;
2130my $MD5_ADD     = 3;
2131
2132my $IMG_ADD_SYM  = 1;
2133my $IMG_ADD_COPY = 2;
2134my $IMG_ADD_MOVE = 3;
2135
2136# Open an image that has been configured
2137sub vol_open {
2138    Print::print_html_header(
2139        "Open Image In $Args::args{'case'}:$Args::args{'host'}");
2140
2141    print "<b>Case:</b> $Args::args{'case'}<br>\n";
2142    print "<b>Host:</b> $Args::args{'host'}<br>\n";
2143    print "<center>\n";
2144
2145    # the images have been loaded from reading the host config file in
2146    # autopsy_main
2147    if (scalar(keys %Caseman::vol2ftype) == 0) {
2148        print "No images have been added to this host yet<br><br>\n"
2149          . "Select the Add Image File button below to add one\n";
2150        goto EGRESS;
2151    }
2152
2153    if ($::LIVE == 1) {
2154        print "Select a volume to analyze.<br>\n";
2155    }
2156    else {
2157        print "Select a volume to analyze or add a new image file.<br>\n";
2158    }
2159
2160    print_menu_tabs();
2161
2162    print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
2163      . "background=\"$::YEL_PIX\" border=0>\n";
2164
2165    # We want to sort, so rearrange the hash
2166    my %mnt2vol;
2167    my %par2disk;
2168
2169    # Cycle through each image we read from the host config
2170    foreach my $i (keys %Caseman::vol2cat) {
2171        if ($Caseman::vol2cat{$i} eq "disk") {
2172            $mnt2vol{"1disk--AUTOPSY--$i"} = $i;
2173        }
2174        elsif ($Caseman::vol2cat{$i} eq "part") {
2175            if (   ($Caseman::vol2ftype{$i} eq "raw")
2176                || ($Caseman::vol2ftype{$i} eq "swap"))
2177            {
2178                $mnt2vol{"2$Caseman::vol2ftype{$i}--AUTOPSY--$i"} = $i;
2179            }
2180            else {
2181                $mnt2vol{"2$Caseman::vol2mnt{$i}--AUTOPSY--$i"} = $i;
2182            }
2183        }
2184    }
2185
2186    # sort via parent volume, then starting location,
2187    # and then mount point (which includes the name)
2188    my @mnt = sort {
2189        ($Caseman::vol2par{$mnt2vol{$a}} cmp $Caseman::vol2par{$mnt2vol{$b}})
2190          or ($Caseman::vol2start{$mnt2vol{$a}} <=>
2191            $Caseman::vol2start{$mnt2vol{$b}})
2192          or (lc($a) cmp lc($b))
2193    } keys %mnt2vol;
2194
2195    # It is possible to have only the blkls image and not the original
2196    # We need to search for those now because they will not be in the
2197    # list that we just made (which are arranged via mount point)
2198    my @orphan_blkls;
2199
2200    # cycle through each image and check its type and original
2201    foreach my $k (keys %Caseman::vol2ftype) {
2202        if (   ($Caseman::vol2ftype{$k} eq "blkls")
2203            && (!exists $Caseman::mod2vol{$k}))
2204        {
2205            push @orphan_blkls, $k;
2206        }
2207    }
2208
2209    print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
2210      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2211      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN_LOG\">\n"
2212      . Args::make_hidden()
2213
2214      . "<tr><th>&nbsp;</th>"
2215      . "<th align=left>mount</th>"
2216      . "<th align=left>name</th>"
2217      .    # vol name
2218      "<th align=left>fs type</th></tr>\n";
2219
2220    my $prev_par = "";
2221
2222    for (my $i = 0; $i <= $#mnt; $i++) {
2223        my $vol = $mnt2vol{$mnt[$i]};
2224
2225        if ($Caseman::vol2par{$vol} ne $prev_par) {
2226            print "<tr><td colspan=5><hr></td></tr>\n" if ($i != 0);
2227            $prev_par = $Caseman::vol2par{$vol};
2228        }
2229
2230        # Mount Point
2231        # If we have the dummy string at the end of the duplicate
2232        # entry, then take it off and print the original
2233        $mnt[$i] = $1 if ($mnt[$i] =~ /^\d(.*?)--AUTOPSY--$::REG_VNAME$/o);
2234        print "<tr>" . "<td><input type=\"radio\" name=\"vol\" value=$vol";
2235        print " CHECKED" if ($i == 0);
2236        print "></td>"
2237          . "<td><tt>"
2238          . Print::html_encode($mnt[$i])
2239          . "</tt></td>";
2240
2241        # image name and ftype
2242        print
2243"<td><tt>$Caseman::vol2sname{$vol}</tt></td><td>$Caseman::vol2ftype{$vol}</td>";
2244        if ($::LIVE == 0) {
2245            print "<td align=center><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
2246              . "view=$Caseman::VOL_DETAILS&$Args::baseargs&"
2247              . "vol=$vol\">details</a></td>"
2248              . "</tr>\n";
2249        }
2250        else {
2251            print "<td>&nbsp;</td></tr>\n";
2252        }
2253    }
2254
2255    # If we are done with the regular images and have some orphan
2256    # blkls images, print them
2257    my @sort = sort @orphan_blkls;
2258    for (my $i = 0; $i <= $#sort; $i++) {
2259        print
2260"<tr><td>&nbsp;</td><td>&nbsp;</td><td>(<input type=\"radio\" name=\"vol\" "
2261          . "value=$sort[$i]";
2262        print " CHECKED" if ($#mnt == 0);
2263        print "> unalloc)</td><td><tt>"
2264          . Print::html_encode($Caseman::vol2sname{$sort[$i]})
2265          . "</tt></td><td>"
2266          . Print::html_encode($Caseman::vol2ftype{$sort[$i]})
2267          . "</td></tr>\n";
2268    }
2269
2270    # Begin Button
2271    print "</table>\n";
2272
2273  EGRESS:
2274
2275    print "<br><br>"
2276      . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n";
2277
2278    # Ok Button
2279    if (scalar(keys %Caseman::vol2ftype) == 0) {
2280        print "<tr><td width=200>&nbsp;</td>\n";
2281    }
2282    else {
2283        print "<tr><td align=center width=200>"
2284          . "<input type=\"image\" src=\"pict/menu_b_analyze.jpg\" "
2285          . "alt=\"Analyze\" width=\"167\" height=20 border=0>\n"
2286          . "</form></td>\n";
2287    }
2288
2289    # Image Add Button
2290    if ($::LIVE == 0) {
2291        print "<td align=center width=200>"
2292          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
2293          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2294          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD\">\n"
2295          . Args::make_hidden()
2296          . "<input type=\"image\" src=\"pict/menu_b_ifnew.jpg\" "
2297          . "alt=\"Add Image\" width=167 height=20 border=0></form></td>\n"
2298          .
2299
2300          # Cancel Button
2301          "<td align=center width=200>"
2302          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
2303          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2304          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
2305          . "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
2306          . "<input type=\"image\" src=\"pict/menu_b_hcls.jpg\" "
2307          . "width=167 height=20 alt=\"Close Host\" border=0>\n"
2308          . "</form></td></tr>";
2309    }
2310    else {
2311        print "<td width=200>&nbsp;</td><td width=200>&nbsp;</td></tr>\n";
2312    }
2313
2314    # Help Button
2315    print
2316"<td width=200>&nbsp;</td><td align=center width=200><a href=\"$::HELP_URL\" "
2317      . " target=\"_blank\">"
2318      . "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
2319      . "width=\"167\" height=20 border=0>"
2320      . "</a></td><td width=200>&nbsp;</td></tr>\n"
2321      . "</table>\n";
2322
2323    # Other features that can be done on a host
2324
2325    if ($::LIVE == 0) {
2326        print "<hr><p>"
2327          . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
2328          . "<tr>\n";
2329
2330        # Timeline of file activity
2331        print "<td align=\"center\" width=200>"
2332          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
2333          . "mod=$::MOD_TL&view=$Timeline::FRAME\">"
2334          . "<img border=0 "
2335          . "src=\"pict/menu_b_tl.jpg\" "
2336          . "width=\"167\" height=20 "
2337          . "alt=\"File Activity Timelines\"></a></td>\n";
2338
2339        # verify the integrity of the images
2340        print "<td align=\"center\" width=200>"
2341          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
2342          . "mod=$::MOD_HASH&view=$Hash::IMG_LIST_FR\">"
2343          . "<img border=0 "
2344          . "src=\"pict/menu_b_int.jpg\" "
2345          . "width=\"167\" height=20 "
2346          . "alt=\"Image Integrity\"></a></td>\n"
2347          .
2348
2349          # Hashdatabases
2350          "<td align=\"center\" width=200>"
2351          . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
2352          . "mod=$::MOD_HASH&view=$Hash::DB_MANAGER\">"
2353          . "<img border=0 "
2354          . "src=\"pict/menu_b_hashdb.jpg\" "
2355          . "width=\"167\" height=20 "
2356          . "alt=\"Hash Databases\"></a></td>\n"
2357          . "</tr></table>\n";
2358
2359        # Notes
2360        if ($::USE_NOTES == 1) {
2361            print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
2362              . "<tr>\n"
2363              . "<td align=\"center\" width=300>"
2364              . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
2365              . "<img border=0 "
2366              . "src=\"pict/menu_b_note.jpg\" "
2367              . "width=\"167\" height=20 "
2368              . "alt=\"View Notes\"></a></td>\n"
2369              .
2370
2371              "<td width=300 align=\"center\">"
2372              . "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_SEQ\">"
2373              . "<img border=0 "
2374              . "src=\"pict/menu_b_seq.jpg\" "
2375              . "width=\"167\" height=20 "
2376              . "alt=\"Event Sequencer\"></a></td>\n"
2377              .
2378
2379              "</tr>\n" . "</table>\n";
2380        }
2381
2382        # If LIVE
2383    }
2384    else {
2385        print "<a href=\"./about\"><br>\n"
2386          . "<img src=\"pict/logo.jpg\" border=0 alt=\"Logo\"></a><br>\n";
2387
2388    }
2389
2390    Print::print_html_footer();
2391
2392    return 0;
2393}
2394
2395# Log in the host log that a given image was opened by what user
2396# then open the main window
2397sub vol_open_log {
2398
2399    # These will be stopped in the func during  LIVE
2400    Print::log_host_info(
2401        "Image $Args::args{'vol'} opened by $Args::args{'inv'}");
2402    Print::log_host_inv("$Args::args{'vol'}: volume opened");
2403
2404    $Args::args{'mod'}  = $Args::enc_args{'mod'}  = $::MOD_FRAME;
2405    $Args::args{'view'} = $Args::enc_args{'view'} = $Frame::IMG_FRAME;
2406    Frame::main();
2407}
2408
2409# Menu to add a new image to the host
2410#
2411# The list of new images is determined by looking in the images directory
2412# and seeing which is not yet configured
2413#
2414sub img_add {
2415    Print::print_html_header(
2416        "Add Image To $Args::args{'case'}:$Args::args{'host'}");
2417
2418    print "<b>Case:</b> $Args::args{'case'}<br>\n"
2419      . "<b>Host:</b> $Args::args{'host'}<br>\n";
2420
2421    print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
2422      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2423      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
2424      . Args::make_hidden();
2425
2426    print <<EOF1;
2427<center>
2428<img src=\"pict/menu_h_inew.jpg\" alt=\"Add Image\">
2429<br><br><br>
2430
2431<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
2432<tr>
2433  <td colspan=4>&nbsp;</td>
2434</tr>
2435
2436<tr>
2437  <td align=left colspan=4>
2438    1. <b>Location</b><br>Enter the full path (starting with <tt>/</tt>) to the image file.<br>
2439    If the image is split (either raw or EnCase), then enter '*' for the extension.
2440  </td>
2441</tr>
2442<tr>
2443  <td>&nbsp;&nbsp;</td>
2444  <td align=left colspan=3>
2445    <input type=\"text\" name=\"img_path\" size=36 maxlength=256>
2446  </td>
2447</tr>
2448<tr><td colspan=4>&nbsp;</td><tr>
2449<tr>
2450  <td align=left colspan=4>2. <b>Type</b><br>Please select if this image file is for a disk or a single partition.</td>
2451</tr>
2452<tr>
2453  <td>&nbsp;&nbsp;</td>
2454  <td align=left>
2455    <input type=\"radio\" name=\"imgtype\" value="disk" CHECKED>
2456      Disk
2457  </td>
2458  <td align=left>
2459    <input type=\"radio\" name=\"imgtype\" value="volume">
2460      Partition
2461  </td>
2462  <td align=left>&nbsp;
2463  </td>
2464</tr>
2465
2466<tr><td colspan=4>&nbsp;</td><tr>
2467<tr>
2468  <td align=left colspan=4>3. <b>Import Method</b><br>To analyze the image file, it must be located in the evidence locker. It can be imported from its current location using a symbolic link, by copying it, or by moving it.  Note that if a system failure occurs during the move, then the image could become corrupt.</td>
2469</tr>
2470<tr>
2471  <td>&nbsp;&nbsp;</td>
2472  <td align=left>
2473    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_SYM CHECKED>
2474      Symlink
2475  </td>
2476  <td align=left>
2477    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_COPY>
2478      Copy
2479  </td>
2480  <td align=left>
2481    <input type=\"radio\" name=\"sort\" value=$IMG_ADD_MOVE>
2482	  Move
2483  </td>
2484</tr>
2485
2486
2487<tr>
2488  <td colspan=4>&nbsp;</td>
2489</tr>
2490
2491</table>
2492
2493<br>
2494<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
2495<tr>
2496  <td align=center colspan=2>
2497    <input type=\"image\" src=\"pict/menu_b_next.jpg\" alt=\"Next Step\" width=\"167\" height=20 border=0>
2498  </td>
2499</tr>
2500
2501</form>
2502
2503EOF1
2504
2505    print "<tr><td colspan=2>&nbsp;</td></tr>\n"
2506      . "<td align=center>\n"
2507      . "    <form action=\"$::PROGNAME\" method=\"get\">\n"
2508      . "    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2509      . "    <input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
2510      .
2511
2512      Args::make_hidden()
2513      . "    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
2514      . "alt=\"Cancel\" width=\"167\" height=20 border=0></form>\n"
2515      . "  </td>\n"
2516      .
2517
2518      # HELP
2519      "  <td align=center>\n"
2520      . "    <a href=\"$::HELP_URL\" target=\"_blank\">\n"
2521      . "    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
2522      . "width=\"167\" height=20 border=0></a>\n"
2523      . "  </td>\n"
2524      . "</tr>\n"
2525      . "</table>\n";
2526
2527    Print::print_html_footer();
2528
2529    return 0;
2530}
2531
2532# List the images from the glob - called from img_add_prep if spl_conf is not set
2533sub img_add_split_conf {
2534    my $img_path = Args::get_img_path_wild();
2535    my $img_type = $Args::args{'imgtype'};
2536
2537    print "<center><br><br><b>Split Image Confirmation</b><br><br>\n";
2538
2539    my @spl_img = glob($img_path);
2540    if (scalar(@spl_img) == 0) {
2541        print "No images were found at this location ($img_path)<br>\n"
2542          . "Use the back button and fix the path<br>\n";
2543        return;
2544    }
2545
2546    print <<EOF1;
2547The following images will be added to the case.<br>
2548If this is not the correct order, then you should change the naming convention.<br>
2549Press the Next button at the bottom of the page if this is correct.<br><br>
2550
2551<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
2552<tr>
2553  <td colspan=2>&nbsp;</td>
2554</tr>
2555EOF1
2556
2557    my $a = 0;
2558    foreach $i (@spl_img) {
2559
2560       # We need to do this when we analyze the image, so do it here too to show
2561       # what will be analyzed
2562        $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
2563        print
2564"<tr><td align=\"center\">$a</td><td align=\"left\"><tt>$i</tt></td></tr>\n";
2565        $a++;
2566    }
2567
2568    my $vs = "";
2569    $vs = "&vstype=$Args::args{'vstype'}"
2570      if (exists $Args::args{'vstype'});
2571
2572    # Print the Ok Button
2573    print "</table><br><br>\n"
2574      . "<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" border=0>"
2575      . "<tr><td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
2576      . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD_PREP&spl_conf=1&sort=$Args::args{'sort'}&"
2577      . "img_path=$img_path&imgtype=$Args::args{'imgtype'}$vs\">"
2578      . "<img src=\"pict/menu_b_next.jpg\" alt=\"Next\" "
2579      . "width=\"167\" height=20 border=0></a></td>\n"
2580      . "<td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
2581      . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD\">"
2582      . "<img src=\"pict/menu_b_cancel.jpg\" alt=\"cancel\" width=\"167\" height=\"20\" border=\"0\">"
2583      . "</a></td></tr></table>\n";
2584
2585    return 0;
2586}
2587
2588# Run the autodetect stuff and get confirmation from the user
2589sub img_add_prep {
2590    Args::check_img_path_wild();
2591    Args::check_sort();
2592    unless ((exists $Args::args{'imgtype'})
2593        && ($Args::args{'imgtype'} =~ /^\w+$/))
2594    {
2595        Print::print_check_err("Invalid image type");
2596    }
2597
2598    Print::print_html_header("Collecting details on new image file");
2599
2600    my $img_path = Args::get_img_path_wild();
2601
2602    my $img_type = $Args::args{'imgtype'};
2603    my $spl_conf = 0;
2604    $spl_conf = 1
2605      if ((exists $Args::args{'spl_conf'}) && ($Args::args{'spl_conf'} == 1));
2606
2607    # If we have a wildcard then it is a split image, so we verify it first and
2608    # then make a string of the images so we can test it.
2609    if ($img_path =~ /[\*\?]/) {
2610        if ($spl_conf == 0) {
2611            return img_add_split_conf();
2612        }
2613        else {
2614            $img_tmp = "";
2615            foreach my $i (glob($img_path)) {
2616                if ($i =~ /^($::REG_IMG_PATH)$/) {
2617                    $img_tmp .= "\"$1\" ";
2618                }
2619            }
2620            $img_path = $img_tmp;
2621        }
2622    }
2623    else {
2624        unless ((-f $img_path)
2625            || (-d $img_path)
2626            || (-l $img_path)
2627            || (-b $img_path)
2628            || (-c $img_path))
2629        {
2630            Print::print_err("Image file not found ($img_path)");
2631        }
2632        $img_path = "\"$img_path\"";
2633    }
2634
2635    # Get the image type
2636    local *OUT;
2637    Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path");
2638    my $itype = Exec::read_pipe_line(*OUT);
2639    if (defined $itype) {
2640        chomp $itype;
2641        $itype = $1 if ($itype =~ /^(\w+)$/);
2642    }
2643    else {
2644        print
2645"The image format type could not be determined for this image file<br>\n";
2646        return;
2647    }
2648    close(OUT);
2649
2650    # The plan here is to collect the needed info and then we print it
2651
2652    my $conflict = 0;
2653    my $cnt      = 0;
2654    $start[0]  = "";
2655    $end[0]    = "";
2656    $type[0]   = "";
2657    $desc[0]   = "";
2658    $active[0] = "";
2659
2660    my $vstype = "";
2661
2662    my $vstype_flag = "";
2663    my $mmls_out    = "";    # Will contain output of mmls (if disk image)
2664    if ($img_type eq "disk") {
2665        my $out;
2666
2667        if (   (exists $Args::args{'vstype'})
2668            && ($Args::args{'vstype'} =~ /^(\w+)$/))
2669        {
2670            $vstype      = $Args::args{'vstype'};
2671            $vstype_flag = "-t $vstype";
2672        }
2673
2674        # Get the type
2675        else {
2676
2677            Exec::exec_pipe(*OUT, "'$::TSKDIR/mmstat' -i $itype $img_path");
2678
2679            $vstype = Exec::read_pipe_line(*OUT);
2680            close(OUT);
2681
2682            chomp $vstype if (defined $vstype);
2683
2684            if (   (!defined $vstype)
2685                || ($vstype =~ /^Error determining/)
2686                || ($vstype eq "")
2687                || (!exists $Vs::type{$vstype})
2688                || ($vstype !~ /^\w+$/))
2689            {
2690                print
2691"<table><tr><td colspan=2><font color=\"$::DEL_COLOR[0]\">Warning:</font> Autopsy could not determine the volume system type for the disk image (i.e. the type of partition table).<br>\n"
2692                  . "Please select the type from the list below or reclassify the image as a volume image instead of as a disk image.</td></tr>\n"
2693                  . "<tr><td colspan=2>&nbsp;</td></tr>\n"
2694                  . "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
2695                  . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
2696                  . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
2697                  . "<input type=\"hidden\" name=\"spl_conf\" value=\"1\">\n"
2698                  . "<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">\n"
2699                  . "<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">\n"
2700                  . Args::make_hidden()
2701                  . "<tr><td>Disk Image <input type=\"radio\" name=\"imgtype\" value=\"disk\" CHECKED></td>\n"
2702                  . "<td>Volume Image<input type=\"radio\" name=\"imgtype\" value=\"volume\"></td></tr>\n"
2703                  . "<tr><td>Volume System Type (disk image only): <select name=\"vstype\">\n";
2704
2705                foreach my $vs (sort keys %Vs::type) {
2706                    print "<option value=\"$vs\"";
2707                    print " selected" if ($vs eq 'dos');
2708                    print ">${vs}</option>\n";
2709                }
2710
2711                print "</select></td>"
2712                  . "<td>&nbsp;</td></tr>"
2713                  . "<tr><td colspan=2>&nbsp;</td></tr>"
2714                  . "</table><br><br>\n"
2715                  . "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"176\" height=20 border=0>"
2716                  . "</form>\n";
2717                return;
2718            }
2719            $vstype = $1 if ($vstype =~ /^(\w+)$/);
2720            $vstype_flag = "-t $vstype";
2721        }
2722
2723        # Run 'mmls' on the image
2724        Exec::exec_pipe(*OUT,
2725            "'$::TSKDIR/mmls' -a -i $itype -aM $vstype_flag -r $img_path");
2726
2727        # cycle through results and add each to table with file system type
2728        my $part_type = "";
2729
2730        while ($_ = Exec::read_pipe_line(*OUT)) {
2731            $mmls_out .= "$_";    # Save the line
2732            last if (/^Error determining partition/);
2733
2734            if (/^\d+:\s+[\d:]+\s+(\d+)\s+(\d+)\s+\d+\s+(\S.*)$/) {
2735                $start[$cnt]  = $1;
2736                $end[$cnt]    = $2;
2737                $desc[$cnt]   = $3;
2738                $active[$cnt] = 1;
2739            }
2740            elsif ((/^DOS Partition/)
2741                || (/^BSD Disk/)
2742                || (/^Sun VTOC/)
2743                || (/^MAC Partition/)
2744                || (/^GUID Partition/))
2745            {
2746                $part_type = $_;
2747
2748                #print "<tr><td colspan=7>&nbsp;</td></tr>\n";
2749                #print "<tr><td colspan=7>$_</td></tr>\n";
2750                next;
2751            }
2752            elsif (/^Sector:/) {
2753
2754                #print "<tr><td colspan=7>$_</td></tr>\n";
2755                next;
2756            }
2757            else {
2758                next;
2759            }
2760
2761            # Skip the BSD partition for the full disk
2762            next
2763              if ( ($part_type =~ /^BSD Disk/)
2764                && ($start[$cnt] == 0)
2765                && ($desc[$cnt] =~ /^Unused/));
2766
2767            # Skip if this is an extended DOS partition
2768            next
2769              if ( ($part_type =~ /^DOS Partition/)
2770                && ($desc[$cnt] =~ /Extended \(/));
2771
2772            # Get rid of the leading 0s
2773            $start[$cnt] = $1
2774              if ($start[$cnt] =~ /^0+([1-9]\d*)$/);
2775            $end[$cnt] = $1
2776              if ($end[$cnt] =~ /^0+([1-9]\d*)$/);
2777
2778            # Do we already have this partition?
2779            my $i;
2780            for ($i = 0; $i < $cnt; $i++) {
2781                next if ($active[$i] == 0);
2782
2783                if ($start[$i] == $start[$cnt]) {
2784                    $conflict = 1;
2785
2786                    if ($end[$i] == $end[$cnt]) {
2787                        last;
2788                    }
2789
2790                    #The previous was the BSD partition - skip it */
2791                    if (   ($desc[$i] =~ /^FreeBSD \(0xA5\)/)
2792                        || ($desc[$i] =~ /^OpenBSD \(0xA6\)/)
2793                        || ($desc[$i] =~ /^NetBSD \(0xA9\)/))
2794                    {
2795                        $active[$i] = 0;
2796
2797                        # if the current one is the BSD partition for
2798                        # the full partition/disk then skip it
2799                        if ($desc[$cnt] =~ /^Unused /) {
2800                            $active[$cnt] = 0;
2801                        }
2802                    }
2803                }
2804
2805                # Do we start inside of another?
2806                if (($start[$i] > $start[$cnt]) && ($end[$i] < $start[$cnt])) {
2807                    $conflict = 1;
2808                }
2809
2810                # Do we end inside of another?
2811                elsif (($start[$i] < $end[$cnt]) && ($end[$i] > $end[$cnt])) {
2812                    $conflict = 1;
2813                }
2814            }
2815            if (($end[$i] == $end[$cnt]) && ($i != $cnt)) {
2816                next;
2817            }
2818
2819            local *OUT2;
2820            my $out2;
2821
2822            # Run 'fstat -t' on the image
2823            Exec::exec_pipe(*OUT2,
2824                "'$::TSKDIR/fsstat' -o $start[$cnt] -i $itype -t $img_path");
2825
2826            $type[$cnt] = Exec::read_pipe_line(*OUT2);
2827            close(OUT2);
2828
2829            if (   (!exists $type[$cnt])
2830                || (!defined $type[$cnt])
2831                || ($type[$cnt] =~ /^Cannot determine/)
2832                || ($type[$cnt] eq ""))
2833            {
2834                $type[$cnt] = "Unknown";
2835            }
2836            chomp $type[$cnt];
2837
2838            $cnt++;
2839        }
2840        close(OUT);
2841
2842        if ($conflict == 1) {
2843            print
2844"<tr><td colspan=2><font color=\"$::DEL_COLOR[0]\">Warning:</font> Conflicts in the partitions were detected.<br>The full <tt>mmls</tt> output is given at the bottom of the page</td></tr>\n"
2845              . "<tr><td colspan=2>&nbsp;</td></tr>\n";
2846        }
2847    }
2848
2849    # If a volume, then run fsstat on it
2850    elsif ($img_type eq "volume") {
2851
2852        # Run 'fstat -t' on the image
2853        Exec::exec_pipe(*OUT, "'$::TSKDIR/fsstat' -t -i $itype $img_path");
2854
2855        $type[0] = Exec::read_pipe_line(*OUT);
2856        close(OUT);
2857
2858        if (   (!defined $type[0])
2859            || ($type[0] =~ /^Cannot determine/)
2860            || ($type[0] eq ""))
2861        {
2862            $type[0] = "Unknown";
2863            print
2864"<font color=\"$::DEL_COLOR[0]\">Warning:</font> The file system type of the volume image file could not be determined.<br>\n"
2865              . "If this is a disk image file, return to the previous page and change the type.<br><br>\n";
2866        }
2867        chomp $type[0];
2868        $start[0]  = 0;
2869        $end[0]    = 0;
2870        $active[0] = 1;
2871        $desc[0]   = $type[0];
2872        $cnt++;
2873        close(OUT);
2874    }
2875    else {
2876        Print::print_err("Unknown image type: $img_type");
2877    }
2878
2879    my $sname = $img_path;
2880    $sname = "$::IMGDIR/" . "$1" if ($sname =~ /\/($::REG_FILE)\"$/);
2881
2882# Now that we have the information about the partitions and disks, print the fields
2883    print <<EOF1;
2884
2885<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">
2886<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
2887<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_DOIT\">
2888<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">
2889<input type=\"hidden\" name=\"num_img\" value=\"$cnt\">
2890<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">
2891
2892
2893<center>
2894<h3>Image File Details</h3>
2895<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
2896<tr>
2897  <td align=left colspan=4>
2898	<b>Local Name: </b> $sname
2899  </td>
2900</tr>
2901
2902EOF1
2903
2904    # We do not currently offer integrity options for non-raw files
2905    if (($itype eq "raw") || ($itype eq "split")) {
2906
2907        print <<EOF1b;
2908<tr>
2909  <td align=left colspan=4>
2910	<b>Data Integrity: </b> An MD5 hash can be used to verify the
2911	integrity of the image.  (With split images, this hash is for the full image file)
2912  </td>
2913</tr>
2914
2915<tr>
2916  <td>&nbsp;&nbsp;</td>
2917  <td align=left colspan=3>
2918    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_NOTHING\" CHECKED>
2919	<u>Ignore</u> the hash value for this image.
2920  </td>
2921</tr>
2922
2923<tr>
2924  <td>&nbsp;&nbsp;</td>
2925  <td align=left colspan=3>
2926    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_CALC\">
2927	<u>Calculate</u> the hash value for this image.
2928  </td>
2929</tr>
2930
2931<tr>
2932  <td>&nbsp;&nbsp;</td>
2933  <td align=left colspan=3>
2934    <input type=\"radio\" name=\"do_md5\" value=\"$MD5_ADD\">
2935	<u>Add</u> the following MD5 hash value for this image:
2936  </td>
2937</tr>
2938
2939<tr>
2940  <td>&nbsp;&nbsp;</td>
2941  <td align=left colspan=3>&nbsp;&nbsp;&nbsp;&nbsp;
2942	<input type=\"text\" name=\"md5\" size=36 maxlength=32>
2943  </td>
2944</tr>
2945
2946<tr>
2947  <td>&nbsp;&nbsp;</td>
2948  <td align=left colspan=3>&nbsp;&nbsp;&nbsp;&nbsp;
2949	<input type=\"checkbox\" name=\"ver_md5\" value=\"1\">
2950	&nbsp;Verify hash after importing?
2951  </td>
2952</tr>
2953EOF1b
2954    }
2955    else {
2956        print
2957          "<input type=\"hidden\" name=\"do_md5\" value=\"$MD5_NOTHING\">\n";
2958    }
2959
2960    print <<EOF1c;
2961</table>
2962
2963<h3>File System Details</h3>
2964<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
2965
2966<tr>
2967  <td colspan=2 align=left>Analysis of the image file shows the following partitions:</td>
2968</tr>
2969<tr>
2970  <td colspan=2>&nbsp;</td>
2971</tr>
2972
2973EOF1c
2974
2975    print Args::make_hidden();
2976
2977    print "<input type=\"hidden\" name=\"vstype\" value=\"$vstype\">\n"
2978      if ($vstype ne "");
2979
2980    my $idx     = 1;
2981    my $ms_cnt  = 0;
2982    my @ms_name = ("C:", "D:", "E:", "F:", "G:", "H:", "I:", "J:");
2983    for (my $i = 0; $i < $cnt; $i++) {
2984        next if ($active[$i] == 0);
2985        print
2986"<tr><td colspan=2><u>Partition $idx</u> (Type: $desc[$i])</td><tr>\n";
2987
2988        if ($cnt > 1) {
2989            print "<tr><td colspan=2>&nbsp;&nbsp;Add to case? "
2990              . "<input type=\"checkbox\" name=\"yes-${idx}\" value=1 CHECKED></td></tr>\n";
2991        }
2992        else {
2993            print "<input type=\"hidden\" name=\"yes-${idx}\" value=1>\n";
2994        }
2995
2996        unless (($start[$i] == 0) && ($end[$i] == 0)) {
2997            print "<tr><td colspan=2>&nbsp;&nbsp;Sector Range: "
2998              . "$start[$i] to $end[$i]"
2999              . "</td></tr>\n";
3000        }
3001
3002        print
3003          "<input type=\"hidden\" name=\"start-${idx}\" value=\"$start[$i]\">"
3004          . "<input type=\"hidden\" name=\"end-${idx}\" value=\"$end[$i]\">\n"
3005          . "<tr><td>&nbsp;&nbsp;Mount Point: <input type=\"text\" name=\"mnt-${idx}\" size=\"6\"";
3006        if (($type[$i] =~ /^ntfs/) || ($type[$i] =~ /^fat/)) {
3007            print " value=\"$ms_name[$ms_cnt]\""
3008              if ($ms_cnt < 8);
3009            $ms_cnt++;
3010        }
3011        elsif (($type[$i] =~ /^raw/)
3012            || ($type[$i] =~ /^swap/))
3013        {
3014            print " value=\"N/A\"";
3015        }
3016        else {
3017            print " value=\"/$idx/\"";
3018        }
3019        print "></td>\n"
3020          . "<td>File System Type: <select name=\"ftype-${idx}\">\n";
3021
3022        foreach my $fs (@Fs::types) {
3023            print "<option value=\"$fs\"";
3024            print " selected" if ($fs eq $type[$i]);
3025            print ">${fs}</option>\n";
3026        }
3027
3028        # The following do not have 'metas' but should be in the list
3029        print "<option value=\"\">======</option>\n";
3030        if ($type[$i] eq "Unknown") {
3031            print "<option value=\"raw\" selected>raw</option>\n";
3032        }
3033        else {
3034            print "<option value=\"raw\">raw</option>\n";
3035        }
3036
3037        print "<option value=\"swap\">swap</option>\n"
3038          . "</select></td></tr>\n"
3039          . "<tr><td colspan=2>&nbsp;</td></tr>\n";
3040
3041        $idx++;
3042    }
3043
3044    print "</table>\n";
3045
3046    print <<EOF2;
3047<br><br>
3048<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
3049<tr>
3050  <td align=center>
3051    <input type=\"image\" src=\"pict/menu_b_add.jpg\"
3052      alt=\"Add\" width=\"176\" height=20 border=0>
3053  </td>
3054</form>
3055  <td align=center>
3056    <form action=\"$::PROGNAME\" method=\"get\">
3057EOF2
3058    print Args::make_hidden();
3059    print <<EOF3;
3060    <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
3061    <input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">
3062    <input type=\"image\" src=\"pict/menu_b_cancel.jpg\"
3063    alt=\"Cancel\" width=\"167\" height=20 border=0>
3064    </form>
3065  </td>
3066  <td align=center><a href=\"$::HELP_URL\"
3067    target=\"_blank\">
3068    <img src=\"pict/menu_b_help.jpg\" alt=\"Help\"
3069    width=\"167\" height=20 border=0></a>
3070  </td>
3071</tr>
3072</table>
3073EOF3
3074
3075    if ($img_type eq "disk") {
3076        print
3077"</center><p>For your reference, the <tt>mmls</tt> output was the following:<br><pre>$mmls_out</pre>\n";
3078    }
3079
3080    Print::print_html_footer();
3081
3082    return 0;
3083}
3084
3085# Add the image to the configuration by adding it to the host config file
3086# and the md5.txt file if that data was provided
3087sub img_add_doit {
3088
3089    Args::check_num_img();
3090    Args::check_img_path_wild();
3091    Args::check_sort();
3092    Args::check_do_md5();
3093
3094    my $num_img     = Args::get_num_img();
3095    my $img_path    = Args::get_img_path_wild();
3096    my $import_type = Args::get_sort();
3097
3098    Print::print_html_header("Add a new image to an Autopsy Case");
3099
3100    my $err     = 0;
3101    my $add_num = 0;
3102    $start[0] = 0;
3103    $end[0]   = 0;
3104    $ftype[0] = "";
3105    $mnt[0]   = "";
3106
3107 # We need a string with all images in it for the hashes and file system testing
3108    my $img_path_full;
3109    if ($img_path =~ /[\*\?]/) {
3110        $img_path_full = "";
3111        foreach my $i (glob($img_path)) {
3112            if ($i =~ /^($::REG_IMG_PATH)$/) {
3113                $img_path_full .= "\"$1\" ";
3114            }
3115        }
3116    }
3117    else {
3118        $img_path_full = "\"$img_path\"";
3119    }
3120
3121    # Get the image type
3122    local *OUT;
3123    Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path_full");
3124    my $itype = Exec::read_pipe_line(*OUT);
3125    if (defined $itype) {
3126        chomp $itype;
3127        $itype = $1 if ($itype =~ /^(\w+)$/);
3128    }
3129    else {
3130        print
3131"The image format type could not be determined for this image file<br>\n";
3132        return;
3133    }
3134    close(OUT);
3135
3136    # Check the hash of the image if that is the plan
3137    my $do_md5  = Args::get_do_md5();
3138    my $act_md5 = "";
3139    unless ($do_md5 == $MD5_NOTHING) {
3140
3141        # Do we need to calculate an MD5?
3142        if (
3143            ($do_md5 == $MD5_CALC)
3144            || (   ($do_md5 == $MD5_ADD)
3145                && (exists $Args::args{'ver_md5'})
3146                && ($Args::args{'ver_md5'} == 1))
3147          )
3148        {
3149
3150            print "<p>Calculating MD5 (this could take a while)<br>\n";
3151            $act_md5 = Hash::calc_md5_split($img_path_full);
3152            unless ($act_md5 =~ /^$::REG_MD5$/o) {
3153                print "Error calculating MD5: $act_md5<br>\n";
3154                return 1;
3155            }
3156            print "Current MD5: <tt>$act_md5</tt><br>\n";
3157        }
3158
3159        # And md5 value was given so we can add it to the md5.txt file
3160        if (($do_md5 == $MD5_ADD) && (exists $Args::args{'md5'})) {
3161
3162            my $md5 = $Args::args{'md5'};
3163            unless ($md5 =~ /^$::REG_MD5$/o) {
3164                if ($md5 eq "") {
3165                    print "MD5 value missing<br>\n";
3166                }
3167                else {
3168                    print "Invalid MD5 value (32 numbers or letters a-f)<br>\n";
3169                }
3170                print "<p><a href=\"$::PROGNAME?"
3171                  . "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&"
3172                  . "$Args::baseargs\">"
3173                  . "<img src=\"pict/menu_b_back.jpg\" border=\"0\" "
3174                  . "width=\"167\" height=20 alt=\"Back\"></a>\n";
3175                return 1;
3176            }
3177            $md5 =~ tr/[a-f]/[A-F]/;
3178
3179            # They also want us to validate the MD5
3180            if (   (exists $Args::args{'ver_md5'})
3181                && ($Args::args{'ver_md5'} == 1))
3182            {
3183
3184                if ($act_md5 eq $md5) {
3185                    print "Integrity Check Passed<br>\n";
3186                    Print::log_host_info("Integrity check passed on new image");
3187                }
3188                else {
3189                    print "<font color=\"$::DEL_COLOR[0]\">"
3190                      . "Integrity Check Failed<br></font><br>\n"
3191                      . "Provided: <tt>$md5</tt><br>\n"
3192                      . "Image not added to case<br>\n";
3193
3194                    Print::log_host_info("Integrity check failed on new image");
3195                    return 1;
3196                }
3197            }
3198
3199            # set the act_md5 value to what was given and verified
3200            $act_md5 = $md5;
3201        }
3202
3203        # We will add the MD5 to the config file after we get its ID
3204    }
3205
3206    # Proces the image arguments to make sure they are all there and test the
3207    # file system type
3208    print "Testing partitions<br>\n";
3209    for (my $i = 0; $i <= $num_img; $i++) {
3210
3211        next
3212          unless ((exists $Args::args{"yes-" . $i})
3213            && ($Args::args{"yes-" . $i} == 1));
3214
3215        if (   (exists $Args::args{"start-" . $i})
3216            && ($Args::args{"start-" . $i} =~ /^(\d+)$/))
3217        {
3218            $start[$add_num] = $1;
3219        }
3220        else {
3221            print "Missing starting address for partition $i<br>\n";
3222            $err = 1;
3223            last;
3224        }
3225
3226        if (   (exists $Args::args{"end-" . $i})
3227            && ($Args::args{"end-" . $i} =~ /^(\d+)$/))
3228        {
3229            $end[$add_num] = $1;
3230        }
3231        else {
3232            print "Missing ending address for partition $i<br>\n";
3233            $err = 1;
3234            last;
3235        }
3236
3237        if (   (exists $Args::args{"mnt-" . $i})
3238            && ($Args::args{"mnt-" . $i} =~ /^($::REG_MNT)$/))
3239        {
3240            $mnt[$add_num] = $1;
3241        }
3242        else {
3243            print "Missing mount point for partition $i<br>\n";
3244            $err = 1;
3245            last;
3246        }
3247
3248        if (   (exists $Args::args{"ftype-" . $i})
3249            && ($Args::args{"ftype-" . $i} =~ /^($::REG_FTYPE)$/))
3250        {
3251            $ftype[$add_num] = $1;
3252        }
3253        else {
3254            print "Missing file system type for partition $i<br>\n";
3255            $err = 1;
3256            last;
3257        }
3258
3259        # Test the File System
3260        if (($ftype[$add_num] ne 'swap') && ($ftype[$add_num] ne 'raw')) {
3261
3262            local *OUT;
3263            my $out;
3264
3265            # Run 'fsstat' and see if there is any output - else there was
3266            # an error and the data went to STDERR
3267            Exec::exec_pipe(*OUT,
3268"'$::TSKDIR/fsstat' -o $start[$add_num] -i $itype -f $ftype[$add_num] $img_path_full"
3269            );
3270            unless (read(OUT, $out, 1)) {
3271                print
3272"<p>Partition $i is not a <tt>$ftype[$add_num]</tt> file system<br>\n";
3273                $err = 1;
3274                last;
3275            }
3276            close(OUT);
3277        }
3278        $add_num++;
3279    }
3280
3281    # Go back if we got an error
3282    if ($err == 1) {
3283        print "Use the browser's back button to fix the data<br>\n";
3284        return 1;
3285    }
3286
3287    ##################################################
3288    # Copy the images and add them to the config file
3289
3290    if ($import_type == $IMG_ADD_SYM) {
3291        Print::print_err("ERROR: /bin/ln missing")
3292          unless (-x '/bin/ln');
3293
3294        print "Linking image(s) into evidence locker<br>\n";
3295    }
3296    elsif ($import_type == $IMG_ADD_COPY) {
3297        Print::print_err("ERROR: /bin/cp missing")
3298          unless (-x '/bin/cp');
3299
3300        print
3301"Copying image(s) into evidence locker (this could take a little while)<br>\n";
3302    }
3303    elsif ($import_type == $IMG_ADD_MOVE) {
3304        Print::print_err("ERROR: /bin/mv missing")
3305          unless (-x '/bin/mv');
3306
3307        print "Moving image(s) into evidence locker<br>\n";
3308    }
3309    else {
3310        Print::print_err("Invalid Import Type: $import_type\n");
3311    }
3312
3313    my $imgid = "";
3314    foreach my $i (glob($img_path)) {
3315
3316        # remove the tainting
3317        $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
3318
3319        # Deterine the local (target) name
3320        my $img = "";
3321        if ($i =~ /\/($::REG_FILE)$/) {
3322            $img = "$::IMGDIR/$1";
3323        }
3324        else {
3325            Print::print_err("Error Parsing Image Path ($i)\n");
3326        }
3327
3328        # Get the full path of the destination
3329        my $img_dst = "$::host_dir" . "$img";
3330        if ((-e "$img_dst") || (-l "$img_dst")) {
3331            Print::print_err(
3332"An image by the same name already exists in the Host directory ($img)\n"
3333                  . "Use the browser's back button to fix the name or delete the existing file."
3334            );
3335        }
3336
3337        my $orig_size = (stat("$i"))[7];
3338
3339        # Copy, Move, or link it
3340        if ($import_type == $IMG_ADD_SYM) {
3341
3342            Print::log_host_info(
3343"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3344            );
3345
3346            Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
3347        }
3348        elsif ($import_type == $IMG_ADD_COPY) {
3349            Print::log_host_info(
3350"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3351            );
3352
3353            Exec::exec_sys("/bin/cp '$i' '$img_dst'");
3354        }
3355        elsif ($import_type == $IMG_ADD_MOVE) {
3356            Print::log_host_info(
3357"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3358            );
3359
3360            Exec::exec_sys("/bin/mv '$i' '$img_dst'");
3361        }
3362
3363        my $new_size = (stat("$img_dst"))[7];
3364
3365        if ($new_size != $orig_size) {
3366            Print::print_err(
3367"Original image size ($orig_size) is not the same as the destination size ($new_size)"
3368            );
3369        }
3370
3371        # Add the disk and partition images to the config file
3372        $imgid = Caseman::add_img_host_config("image", "$itype  $img", $imgid);
3373    }
3374    print "Image file added with ID <tt>$imgid</tt><br>\n";
3375
3376    # AFM files have raw files that we also need to copy
3377    # This approach is not the best, since it may copy more than
3378    # is needed
3379    if ($itype eq "afm") {
3380        my $afm_base_path = "";
3381
3382        if ($img_path =~ /^(.*?)\.afm/i) {
3383            $afm_base_path = $1;
3384            $afm_base_path .= ".[0-9][0-9][0-9]";
3385        }
3386        else {
3387            Print::print_err(
3388                "Error parsing out base name of AFM file $img_path");
3389        }
3390
3391        print "BASE: $afm_base_path<br>\n";
3392
3393        my $copied = 0;
3394
3395        foreach my $i (glob($afm_base_path)) {
3396            $copied++;
3397
3398            # remove the tainting
3399            $i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
3400
3401            # Deterine the local (target) name
3402            my $img = "";
3403            if ($i =~ /\/($::REG_FILE)$/) {
3404                $img = "$::IMGDIR/$1";
3405            }
3406            else {
3407                Print::print_err("Error Parsing Image Path ($i)\n");
3408            }
3409
3410            # Get the full path of the destination
3411            my $img_dst = "$::host_dir" . "$img";
3412            if ((-e "$img_dst") || (-l "$img_dst")) {
3413                Print::print_err(
3414"An image by the same name already exists in the Host directory ($img) (AFM import)\n"
3415                      . "Use the browser's back button to fix the name or delete the existing file."
3416                );
3417            }
3418
3419            my $orig_size = (stat("$i"))[7];
3420
3421            # Copy, Move, or link it
3422            if ($import_type == $IMG_ADD_SYM) {
3423
3424                Print::log_host_info(
3425"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3426                );
3427
3428                Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
3429            }
3430            elsif ($import_type == $IMG_ADD_COPY) {
3431                Print::log_host_info(
3432"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3433                );
3434
3435                Exec::exec_sys("/bin/cp '$i' '$img_dst'");
3436            }
3437            elsif ($import_type == $IMG_ADD_MOVE) {
3438                Print::log_host_info(
3439"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
3440                );
3441
3442                Exec::exec_sys("/bin/mv '$i' '$img_dst'");
3443            }
3444
3445            my $new_size = (stat("$img_dst"))[7];
3446
3447            if ($new_size != $orig_size) {
3448                Print::print_err(
3449"Original image size ($orig_size) is not the same as the destination size ($new_size) after AFM import"
3450                );
3451            }
3452        }
3453        if ($copied == 0) {
3454            Print::print_err(
3455"No AFM raw files were found with the same base name and a numeric extension"
3456            );
3457        }
3458        else {
3459            print "$copied AFM raw files imported<br>\n";
3460        }
3461    }
3462
3463    Caseman::update_md5("$imgid", "$act_md5")
3464      unless (($do_md5 == $MD5_NOTHING) || ($imgid eq ""));
3465
3466    # Add a disk entry if the image is of a disk
3467    unless (($add_num == 1) && ($end[0] == 0) && ($start[0] == 0)) {
3468        unless ((exists $Args::args{'vstype'})
3469            && ($Args::args{'vstype'} =~ /^(\w+)$/))
3470        {
3471            Print::print_err("Missing Volume System Type");
3472        }
3473        my $vstype = $Args::args{'vstype'};
3474
3475        my $diskid = Caseman::add_vol_host_config("disk", "$imgid    $vstype");
3476        print "<p>Disk image (type $vstype) added with ID <tt>$diskid</tt>\n";
3477    }
3478
3479    # Add the file system / partition entries
3480    for (my $i = 0; $i < $add_num; $i++) {
3481        my $volid =
3482          Caseman::add_vol_host_config("part",
3483            "$imgid	$start[$i]  $end[$i]    $ftype[$i]  $mnt[$i]");
3484        print
3485"<p>Volume image ($start[$i] to $end[$i] - $ftype[$i] - $mnt[$i]) added with ID <tt>$volid</tt>\n";
3486    }
3487
3488    print <<EOF;
3489<p>
3490<center>
3491<table width=600>
3492<tr>
3493  <td width=300 align=center>
3494    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">
3495    <img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
3496    </a>
3497  </td>
3498  <td width=300 align=center>
3499    <a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&${Args::baseargs_novol}\">
3500    <img src=\"pict/menu_b_inew.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
3501    </a>
3502  </td>
3503</tr>
3504</table>
3505</center>
3506
3507EOF
3508    Print::print_html_footer();
3509
3510    return 0;
3511}
3512
3513# Display details of image based on config values
3514# provides links to remove the config of the image and to get the file
3515# system details
3516
3517sub vol_details {
3518    Print::print_html_header("Details of $Args::args{'vol'}");
3519
3520    Args::get_unitsize();
3521
3522    my $vol = Args::get_vol('vol');
3523
3524    my $mnt   = $Caseman::vol2mnt{$vol};
3525    my $ftype = $Caseman::vol2ftype{$vol};
3526
3527    print "<center>"
3528      . "<img src=\"pict/menu_h_idet.jpg\" alt=\"Image Details\">"
3529      . "<br><br><br>\n"
3530      . "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
3531      . "background=\"$::YEL_PIX\" border=0>\n"
3532      . "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
3533      .
3534
3535      # Name
3536      "  <tr><td align=\"right\" width=\"300\"><b>Name:</b></td>"
3537      . "<td align=\"left\"><tt>$Caseman::vol2sname{$vol}</tt></td></tr>\n"
3538      . "<tr><td align=\"right\" width=\"300\"><b>Volume Id:</b></td>"
3539      . "<td align=\"left\"><tt>$vol</tt></td></tr>\n"
3540      . "<tr><td align=\"right\" width=\"300\"><b>Parent Volume Id:</b></td>"
3541      . "<td align=\"left\"><tt>$Caseman::vol2par{$vol}</tt></td></tr>\n"
3542      . "<tr><td align=\"right\" width=\"300\"><b>Image File Format:</b></td>"
3543      . "<td align=\"left\"><tt>$Caseman::vol2itype{$vol}</tt></td></tr>\n"
3544
3545      # Mount
3546      . "  <tr><td align=\"right\"><b>Mounting Point:</b></td>"
3547      . "<td align=\"left\"><tt>$mnt</tt></td></tr>\n"
3548      .
3549
3550      # Type
3551      "  <tr><td align=\"right\"><b>File System Type:</b></td>"
3552      . "<td align=\"left\"><tt>$ftype</tt></td></tr>\n";
3553
3554    # Host Directory
3555    print "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
3556
3557      # Strings File
3558      . "  <tr><td colspan=2 align=\"center\"><b>External Files</b></td></tr>\n"
3559      . "  <tr><td align=\"right\"><b>ASCII Strings:</b></td>"
3560      . "<td align=\"left\"><tt>"
3561      . (
3562        (exists $Caseman::vol2str{$vol})
3563        ? $Caseman::vol2sname{$Caseman::vol2str{$vol}}
3564        : "&nbsp;"
3565      )
3566      . "</tt></td></tr>\n"
3567      .
3568
3569      # Unicode Strings File
3570      "  <tr><td align=\"right\"><b>Unicode Strings:</b></td>"
3571      . "<td align=\"left\"><tt>"
3572      . (
3573        (exists $Caseman::vol2uni{$vol})
3574        ? $Caseman::vol2sname{$Caseman::vol2uni{$vol}}
3575        : "&nbsp;"
3576      )
3577      . "</tt></td></tr>\n";
3578
3579    if (($ftype ne "raw") && ($ftype ne "swap")) {
3580
3581        # blkls file
3582        print
3583"  <tr><td align=\"right\"><b>Unallocated $Fs::addr_unit{$ftype}s:</b></td>"
3584          . "<td align=\"left\"><tt>"
3585          . (
3586            (exists $Caseman::vol2blkls{$vol})
3587            ? $Caseman::vol2sname{$Caseman::vol2blkls{$vol}}
3588            : "&nbsp;"
3589          )
3590          . "</tt></td></tr>\n";
3591
3592        # Strings of blkls
3593        print
3594          "  <tr><td align=\"right\"><b>ASCII Strings of Unallocated:</b></td>"
3595          . "<td align=\"left\"><tt>"
3596          . (
3597            (
3598                     (exists $Caseman::vol2blkls{$vol})
3599                  && (exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}})
3600            )
3601            ? $Caseman::vol2sname{$Caseman::vol2str{$Caseman::vol2blkls{$vol}}}
3602            : "&nbsp;"
3603          )
3604          . "</tt></td></tr>\n";
3605
3606        # Unicodde Strings of blkls
3607        print
3608"  <tr><td align=\"right\"><b>Unicode Strings of Unallocated:</b></td>"
3609          . "<td align=\"left\"><tt>"
3610          . (
3611            (
3612                     (exists $Caseman::vol2blkls{$vol})
3613                  && (exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})
3614            )
3615            ? $Caseman::vol2sname{$Caseman::vol2uni{$Caseman::vol2blkls{$vol}}}
3616            : "&nbsp;"
3617          )
3618          . "</tt></td></tr>\n";
3619    }
3620
3621    print "  <tr><td colspan=\"2\">&nbsp;</td></tr>\n"
3622      . "</table>\n<a name=\"extract\"\n";
3623
3624    # Section for Strings file and 'blkls' file
3625
3626    if (
3627           (!(exists $Caseman::vol2str{$vol}))
3628        || (!(exists $Caseman::vol2uni{$vol}))
3629        || (!(exists $Caseman::vol2blkls{$vol}))
3630        || (
3631            (exists $Caseman::vol2blkls{$vol})
3632            && (   (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
3633                || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
3634        )
3635      )
3636    {
3637        print "<hr><table width=600>\n<tr>";
3638    }
3639
3640    # Strings File
3641    if (   (!(exists $Caseman::vol2str{$vol}))
3642        || (!(exists $Caseman::vol2uni{$vol})))
3643    {
3644
3645        print
3646"<td align=\"center\" width=280><h3>Extract Strings of<br>Entire Volume</h3>"
3647          . "Extracting the ASCII and Unicode strings from a file system will "
3648          . "make keyword searching faster.<br><br>\n"
3649          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
3650          . "Generate MD5? "
3651          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
3652          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
3653          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
3654          . "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
3655          . Args::make_hidden();
3656
3657        if (!(exists $Caseman::vol2str{$vol})) {
3658            print
3659"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED>  \n";
3660        }
3661        if (!(exists $Caseman::vol2uni{$vol})) {
3662            print
3663"  Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
3664        }
3665
3666        print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
3667          . "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n"
3668          . "<td width=40>&nbsp;</td>\n";
3669    }
3670
3671    if (($ftype eq 'blkls') || ($ftype eq 'swap') || ($ftype eq 'raw')) {
3672
3673        # Place holder for types that have no notion of unallocated
3674    }
3675
3676    # Unallocated Space File
3677    elsif (!(exists $Caseman::vol2blkls{$vol})) {
3678
3679        print
3680"<td align=\"center\" width=280><h3>Extract Unallocated $Fs::addr_unit{$ftype}s</h3>"
3681          . "Extracting the unallocated data in a file system allows "
3682          . "more focused keyword searches and data recovery.<br><br>\n"
3683          . "(Note: This Does Not Include Slack Space)<br>\n"
3684          . "<form action=\"$::PROGNAME\" method=\"get\">\n";
3685
3686        print "Generate MD5? "
3687          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
3688          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
3689          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKEBLKLS\">\n"
3690          .
3691
3692          "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
3693          . Args::make_hidden()
3694          . "<input type=\"image\" src=\"pict/srch_b_un.jpg\" "
3695          . "alt=\"Extract Unallocated Data\" border=\"0\">\n<br></form>\n";
3696    }
3697
3698    # strings of 'blkls'
3699    elsif ((!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
3700        || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
3701    {
3702
3703        print
3704"<td align=\"center\" width=280><h3>Extract Strings of<br>Unallocated $Fs::addr_unit{$ftype}s</h3>"
3705          . "Extracting the ASCII strings from the unallocated data will make "
3706          . "keyword searching faster.<br><br>\n"
3707          . "<form action=\"$::PROGNAME\" method=\"get\">\n"
3708          . "Generate MD5? "
3709          . "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
3710          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
3711          . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
3712          .
3713
3714"<input type=\"hidden\" name=\"vol\" value=\"$Caseman::vol2blkls{$vol}\">\n"
3715          . "<input type=\"hidden\" name=\"fname_mode\" value=\"$FNAME_MODE_INIT\">\n"
3716          . Args::make_hidden();
3717
3718        if (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}})) {
3719            print
3720"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED>  \n";
3721        }
3722        if (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})) {
3723            print
3724"  Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
3725        }
3726        print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
3727          . "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n";
3728    }
3729    if (
3730           (!(exists $Caseman::vol2str{$vol}))
3731        || (!(exists $Caseman::vol2uni{$vol}))
3732        || (!(exists $Caseman::vol2blkls{$vol}))
3733        || (
3734            (exists $Caseman::vol2blkls{$vol})
3735            && (   (!(exists $Caseman::vol2str{$Caseman::vol2blkls{$vol}}))
3736                || (!(exists $Caseman::vol2uni{$Caseman::vol2blkls{$vol}})))
3737        )
3738      )
3739    {
3740        print "</tr></table><hr>\n";
3741    }
3742
3743    print "<p>"
3744      . "<table width=\"400\" cellspacing=\"0\" cellpadding=\"2\">\n"
3745      .
3746
3747      # Ok
3748      "<tr><td align=center width=200>"
3749      . "<form action=\"$::PROGNAME\" method=\"get\">\n"
3750      . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
3751      . "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
3752      . Args::make_hidden()
3753      . "<input type=\"image\" src=\"pict/menu_b_close.jpg\" "
3754      . "alt=\"Close\" width=\"167\" height=20 border=0></form></td>\n";
3755
3756    print "<td align=center width=200>";
3757    if (($ftype ne "raw") && ($ftype ne "swap")) {
3758
3759        # File System Details
3760        print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_blank\">\n"
3761          . Args::make_hidden()
3762          . "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
3763          . "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_FS\">\n"
3764          . "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
3765          . "<input type=\"image\" src=\"pict/menu_b_fs.jpg\" "
3766          . "width=167 height=20 "
3767          . "alt=\"File System\" border=0></form></td>\n";
3768    }
3769    else {
3770        print "&nbsp;</td>\n";
3771    }
3772
3773# Remove Image
3774# THis was removed 12/03 because it causes problems because the image still
3775# exists and config entries and ... it becomes a mess
3776#	print
3777#	  "<td align=center width=200>".
3778#	  "<form action=\"$::PROGNAME\" method=\"get\">\n".
3779#          "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n".
3780#          "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_DEL\">\n".
3781#	  Args::make_hidden().
3782#          "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n".
3783#          "<input type=\"hidden\" name=\"mnt\" value=\"$Args::args{'mnt'}\">\n".
3784#	  "<input type=\"image\" src=\"pict/menu_b_rem.jpg\" ".
3785#	  "width=167 height=20 alt=\"Remove\" border=0></form>".
3786#          "</td>\n".
3787#	  "</tr></table>\n";
3788
3789    Print::print_html_footer();
3790    return 0;
3791}
3792
3793# remove the config files
3794sub img_del {
3795    Args::check_vol('vol');
3796
3797    # Args::check_ftype();
3798    Print::print_html_header(
3799        "Removing Configuration Settings for $Args::args{'vol'}");
3800
3801    Caseman::del_host_config("", $Args::args{'vol'}, "");
3802    Caseman::update_md5($Args::args{'vol'}, "");
3803
3804    print "Settings for <tt>$Args::args{'vol'}</tt> removed from "
3805      . "<tt>$Args::args{'case'}:$Args::args{'host'}</tt>.\n"
3806      . "<p>NOTE: The actual file still exists in the host directory.\n";
3807
3808    print "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
3809      . "view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">"
3810      . "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
3811      . "width=\"43\" height=20 border=\"0\"></a>\n";
3812
3813    Print::print_html_footer();
3814
3815    return 0;
3816}
3817
3818# Make a strings -t d file for the image to decrease the search time
3819# Can make both ASCII and Unicode strings files
3820sub vol_makestr {
3821    Print::print_html_header("Extracting Strings");
3822
3823    my $ascii = 0;
3824    my $uni   = 0;
3825
3826    my $vol     = Args::get_vol('vol');
3827    my $ftype   = $Caseman::vol2ftype{$vol};
3828    my $img     = $Caseman::vol2path{$vol};
3829    my $offset  = $Caseman::vol2start{$vol};
3830    my $imgtype = $Caseman::vol2itype{$vol};
3831
3832    if ((exists $Args::args{'str'}) && ($Args::args{'str'} == 1)) {
3833        if (exists $Caseman::vol2str{$vol}) {
3834            Print::print_err(
3835"Image already has an ASCII strings file: $Caseman::vol2sname{$vol}"
3836            );
3837        }
3838        $ascii = 1;
3839    }
3840
3841    if ((exists $Args::args{'uni'}) && ($Args::args{'uni'} == 1)) {
3842        if (exists $Caseman::vol2uni{$vol}) {
3843            Print::print_err(
3844"Image already has a Unicode strings file: $Caseman::vol2sname{$vol}"
3845            );
3846        }
3847
3848        $uni = 1;
3849    }
3850    if (($uni == 0) && ($ascii == 0)) {
3851        goto str_egress;
3852    }
3853
3854    my $base_name = $Caseman::vol2sname{$vol};
3855
3856    if ($ascii == 1) {
3857        my $fname_rel = "$::DATADIR/${base_name}-$ftype.asc";
3858        my $fname     = "$::host_dir" . "$fname_rel";
3859
3860        if (-e "$fname") {
3861            my $i = 1;
3862            $i++ while (-e "$::host_dir"
3863                . "$::DATADIR/"
3864                . "${base_name}-$ftype-$i.asc");
3865
3866            $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.asc";
3867            $fname     = "$::host_dir" . "$fname_rel";
3868        }
3869
3870        print
3871"Extracting ASCII strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
3872
3873        Print::log_host_inv(
3874            "$Caseman::vol2sname{$vol}: Saving ASCII strings to $fname_rel");
3875
3876        local *OUT;
3877
3878        my $hit_cnt = 0;
3879        $SIG{ALRM} = sub {
3880            if (($hit_cnt++ % 5) == 0) {
3881                print "+";
3882            }
3883            else {
3884                print "-";
3885            }
3886            alarm(5);
3887        };
3888
3889        alarm(5);
3890
3891        if ($ftype eq "blkls") {
3892            Exec::exec_pipe(*OUT,
3893                "'$::TSKDIR/srch_strings' -a -t d $img > '$fname'");
3894        }
3895        elsif ((($ftype eq "raw") || ($ftype eq "swap"))
3896            && ($Caseman::vol2end{$vol} != 0))
3897        {
3898            Exec::exec_pipe(*OUT,
3899                    "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
3900                  . $Caseman::vol2start{$vol} . "-"
3901                  . $Caseman::vol2end{$vol}
3902                  . " | '$::TSKDIR/srch_strings' -a -t d > '$fname'");
3903        }
3904        else {
3905            Exec::exec_pipe(*OUT,
3906"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d > '$fname'"
3907            );
3908        }
3909        alarm(0);
3910        $SIG{ALRM} = 'DEFAULT';
3911
3912        print $_ while ($_ = Exec::read_pipe_line(*OUT));
3913        close(OUT);
3914
3915        print "<br>\n" if ($hit_cnt != 0);
3916
3917        # Verify that it worked
3918        unless (open(STR, "$fname")) {
3919            print(  "Error opening $fname<br>\n"
3920                  . "Either an error occurred while generating the file or "
3921                  . "no ASCII strings exist<br>");
3922            goto str_uni;
3923        }
3924
3925        # append to config
3926        my $strvol =
3927          Caseman::add_vol_host_config("strings", "$vol   $fname_rel");
3928        print "Host configuration file updated<br>";
3929
3930        $Caseman::vol2ftype{$strvol} = "strings";
3931        $Caseman::mod2vol{$strvol}   = $vol;
3932        $Caseman::vol2str{$vol}      = $strvol;
3933        $Caseman::vol2cat{$strvol}   = "mod";
3934        $Caseman::vol2itype{$strvol} = "raw";
3935
3936        $Caseman::vol2par{$strvol}   = $vol;
3937        $Caseman::vol2path{$strvol}  = "$::host_dir" . "$fname_rel";
3938        $Caseman::vol2start{$strvol} = 0;
3939        $Caseman::vol2end{$strvol}   = 0;
3940        $Caseman::vol2sname{$strvol} = $fname_rel;
3941
3942        # Calculate MD5
3943        if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
3944            print "Calculating MD5 Value<br><br>\n";
3945            my $m = Hash::int_create_wrap($strvol);
3946            print "MD5 Value: <tt>$m</tt><br><br>\n";
3947        }
3948    }
3949
3950  str_uni:
3951
3952    if ($uni == 1) {
3953
3954        my $fname_rel = "$::DATADIR/${base_name}-$ftype.uni";
3955        my $fname     = "$::host_dir" . "$fname_rel";
3956
3957        if (-e "$fname") {
3958            my $i = 1;
3959            $i++ while (-e "$::host_dir"
3960                . "$::DATADIR/"
3961                . "${base_name}-$ftype-$i.uni");
3962
3963            $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.uni";
3964            $fname     = "$::host_dir" . "$fname_rel";
3965        }
3966
3967        print "<hr>\n" if ($ascii == 1);
3968
3969        print
3970"Extracting Unicode strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
3971
3972        Print::log_host_inv(
3973            "$Caseman::vol2sname{$vol}: Saving Unicode strings to $fname_rel");
3974
3975        local *OUT;
3976
3977        my $hit_cnt = 0;
3978        $SIG{ALRM} = sub {
3979            if (($hit_cnt++ % 5) == 0) {
3980                print "+";
3981            }
3982            else {
3983                print "-";
3984            }
3985            alarm(5);
3986        };
3987
3988        alarm(5);
3989        if ($ftype eq "blkls") {
3990            Exec::exec_pipe(*OUT,
3991                "'$::TSKDIR/srch_strings' -a -t d -e l $img > '$fname'");
3992        }
3993        elsif ((($ftype eq "raw") || ($ftype eq "swap"))
3994            && ($Caseman::vol2end{$vol} != 0))
3995        {
3996            Exec::exec_pipe(*OUT,
3997                    "'$::TSKDIR/blkls' -e -f $ftype -i $imgtype $img "
3998                  . $Caseman::vol2start{$vol} . "-"
3999                  . $Caseman::vol2end{$vol}
4000                  . " | '$::TSKDIR/srch_strings' -a -t d -e l > '$fname'");
4001        }
4002
4003        else {
4004            Exec::exec_pipe(*OUT,
4005"'$::TSKDIR/blkls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -e l  > '$fname'"
4006            );
4007        }
4008
4009        alarm(0);
4010        $SIG{ALRM} = 'DEFAULT';
4011
4012        print $_ while ($_ = Exec::read_pipe_line(*OUT));
4013        close(OUT);
4014
4015        print "<br>\n" if ($hit_cnt != 0);
4016
4017        # Verify that it worked
4018        unless (open(STR, "$fname")) {
4019            print "Error opening $fname<br>\n"
4020              . "Either an error occurred while generating the file or "
4021              . "no Unicode strings exist";
4022            goto str_egress;
4023        }
4024
4025        # append to config
4026        my $strvol =
4027          Caseman::add_vol_host_config("unistrings", "$vol    $fname_rel");
4028        print "Host configuration file updated<br>";
4029
4030        $Caseman::vol2ftype{$strvol} = "strings";
4031        $Caseman::mod2vol{$strvol}   = $vol;
4032        $Caseman::vol2uni{$vol}      = $strvol;
4033        $Caseman::vol2cat{$strvol}   = "mod";
4034        $Caseman::vol2itype{$strvol} = "raw";
4035
4036        $Caseman::vol2par{$strvol}   = $vol;
4037        $Caseman::vol2path{$strvol}  = "$::host_dir" . "$fname_rel";
4038        $Caseman::vol2start{$strvol} = 0;
4039        $Caseman::vol2end{$strvol}   = 0;
4040        $Caseman::vol2sname{$strvol} = $fname_rel;
4041
4042        # Calculate MD5
4043        if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
4044            print "Calculating MD5 Value<br><br>\n";
4045            $m = Hash::int_create_wrap($strvol);
4046            print "MD5 Value: <tt>$m</tt><br><br>\n";
4047        }
4048    }
4049
4050  str_egress:
4051
4052    my $dest_vol = $vol;
4053
4054    # We need to return with a real image to VOL_DETAILS so check the mod
4055    $dest_vol = $Caseman::mod2vol{$vol}
4056      if (exists $Caseman::mod2vol{$vol});
4057
4058    print "<hr><a href=\"$::PROGNAME?$Args::baseargs_novol&mod=$::MOD_CASEMAN&"
4059      . "view=$Caseman::VOL_DETAILS&vol=$dest_vol\" target=_top>Image Details</a><p>\n";
4060
4061    print
4062"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs\""
4063      . " target=\"_top\">Keyword Search</a>\n";
4064
4065    Print::print_html_footer();
4066
4067    return 0;
4068}
4069
4070sub vol_makeblkls {
4071    Print::print_html_header("Extracting Unallocated Space");
4072
4073    my $vol     = Args::get_vol('vol');
4074    my $ftype   = $Caseman::vol2ftype{$vol};
4075    my $img     = $Caseman::vol2path{$vol};
4076    my $offset  = $Caseman::vol2start{$vol};
4077    my $imgtype = $Caseman::vol2itype{$vol};
4078
4079    my $base_name = $Caseman::vol2sname{$vol};
4080    $base_name = $1 if ($base_name =~ /^(.*?)\.dd$/);
4081    my $fname_rel = "$::DATADIR/${base_name}-$ftype.unalloc";
4082    my $fname     = "$::host_dir" . "$fname_rel";
4083
4084    if (-e "$::host_dir" . "$fname_rel") {
4085        my $i = 1;
4086        $i++ while (-e "$::host_dir"
4087            . "$::DATADIR/"
4088            . "${base_name}-$ftype-$i.unalloc");
4089
4090        $fname_rel = "$::DATADIR/${base_name}-$ftype-$i.unalloc";
4091        $fname     = "$::host_dir" . "$fname_rel";
4092    }
4093
4094    Print::log_host_inv(
4095        "$Args::args{'vol'}: Saving unallocated data to $fname_rel");
4096
4097    print
4098"Extracting unallocated data from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
4099
4100    local *OUT;
4101
4102    my $hit_cnt = 0;
4103    $SIG{ALRM} = sub {
4104        if (($hit_cnt++ % 5) == 0) {
4105            print "+";
4106        }
4107        else {
4108            print "-";
4109        }
4110        alarm(5);
4111    };
4112
4113    alarm(5);
4114
4115    Exec::exec_pipe(*OUT,
4116        "'$::TSKDIR/blkls' -f $ftype  -o $offset -i $imgtype $img > '$fname'");
4117
4118    alarm(0);
4119    $SIG{ALRM} = 'DEFAULT';
4120
4121    print "$_" while ($_ = Exec::read_pipe_line(*OUT));
4122    close(OUT);
4123
4124    print "<br>\n"
4125      if ($hit_cnt != 0);
4126
4127    # append to config
4128    my $blklsvol = Caseman::add_vol_host_config("blkls", "$vol    $fname_rel");
4129    print "Host configuration file updated<br>";
4130
4131    $Caseman::vol2ftype{$blklsvol} = "blkls";
4132    $Caseman::mod2vol{$blklsvol}   = $vol;
4133    $Caseman::vol2blkls{$vol}      = $blklsrvol;
4134    $Caseman::vol2cat{$blklsvol}   = "mod";
4135    $Caseman::vol2itype{$blklsvol} = "raw";
4136
4137    $Caseman::vol2par{$blklsvol}   = $vol;
4138    $Caseman::vol2path{$blklsvol}  = "$::host_dir" . "$fname_rel";
4139    $Caseman::vol2start{$blklsvol} = 0;
4140    $Caseman::vol2end{$blklsvol}   = 0;
4141    $Caseman::vol2sname{$blklsvol} = $fname_rel;
4142
4143    # Calculate MD5
4144    if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
4145        print "Calculating MD5 Value<br>\n";
4146        my $m = Hash::int_create_wrap($blklsvol);
4147        print "MD5 Value: <tt>$m</tt><br><br>\n";
4148    }
4149
4150    print "<a href=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_CASEMAN&"
4151      . "view=$Caseman::VOL_DETAILS\" target=_top>Image Details</a><p>\n";
4152
4153    print
4154"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs_novol&"
4155      . "vol=$fname_rel\" target=\"_top\">Keyword Search</a>\n";
4156
4157    Print::print_html_footer();
4158    return 0;
4159}
4160
41611;
4162