#
# $Date: 2006/05/11 18:09:24 $
#
# Case Management methods, including the windows and functions to read the
# config files
#
# Brian Carrier [carrier@sleuthkit.org]
# Copyright (c) 2001-2005 by Brian Carrier. All rights reserved
#
# This file is part of the Autopsy Forensic Browser (Autopsy)
#
# Autopsy is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Autopsy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Autopsy; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package Caseman;
# If the order of these views are changed, then the order of the main
# function may have to be as well
# Case Views
$Caseman::CASE_NEW = 1;
$Caseman::CASE_NEW_DOIT = 2;
$Caseman::CASE_OPEN = 3;
$Caseman::CASE_OPEN_LOG = 4;
$Caseman::CASE_DETAILS = 5;
# $Caseman::CASE_DEL = 6;
my $CASE_MAX = 5;
# Host Views
$Caseman::HOST_ADD = 7;
$Caseman::HOST_ADD_DOIT = 8;
$Caseman::HOST_OPEN = 9;
$Caseman::HOST_OPEN_LOG = 10;
$Caseman::HOST_DETAILS = 11;
# $Caseman::HOST_DEL = 12;
my $HOST_MAX = 11;
# Image Views
$Caseman::IMG_ADD = 13;
$Caseman::IMG_ADD_PREP = 14;
$Caseman::IMG_ADD_DOIT = 15;
$Caseman::VOL_OPEN = 16;
$Caseman::VOL_OPEN_LOG = 17;
$Caseman::VOL_DETAILS = 18;
$Caseman::IMG_DEL = 19;
$Caseman::VOL_MAKESTR = 20;
$Caseman::VOL_MAKEDLS = 21;
my $IMG_MAX = 21;
# Module Variables
# %vol2par - Volume to parent volume (vol to img, str to vol)
# %vol2start - Starting sector of volume in image
# %vol2end - ending sector of volume in image
# %vol2cat - The big picture type of volume (part, disk, strings, dls)
# %vol2ftype - The file system type (fat, dos, ntfs etc.)
# %vol2itype - The image file type (could be for a parent image)
# %vol2dtype- the disk type
# %mod2vol; # Mapping for image, given the strings or dls
# %vol2mnt; # Mapping for mount point, given the vol name
# %vol2str; # Mapping for ASCII strings file, given the vol name
# %vol2uni; # Mapping for Unicode strings file, given the vol name
# %vol2dls; # Mapping for dls file, given the vol name
# %vol2path - full file path of volume
# %vol2sname - short name of volume
sub main {
# By default, show the case open window
$Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::CASE_OPEN
unless (exists $Args::args{'view'});
Args::check_view();
my $view = Args::get_view();
# The only live function is for the open img
if ($::LIVE == 1) {
Args::check_inv();
if ($view == $Caseman::VOL_OPEN) {
return vol_open();
}
Args::check_vol('vol');
# Args::check_ftype();
# Args::check_mnt();
if ($view == $Caseman::VOL_OPEN_LOG) {
return vol_open_log();
}
else {
Print::print_check_err(
"Invalid Live Analysis Case Management View");
}
return 0;
}
# Case functions
if ($view <= $CASE_MAX) {
if ($view == $Caseman::CASE_OPEN) {
return case_open();
}
elsif ($view == $Caseman::CASE_NEW) {
return case_new();
}
Args::check_case();
$::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
$::case_dir =~ s/\/\//\//g;
if ($view == $Caseman::CASE_OPEN_LOG) {
return case_open_log();
}
elsif ($view == $Caseman::CASE_NEW_DOIT) {
return case_new_doit();
}
elsif ($view == $Caseman::CASE_DETAILS) {
return case_details();
}
}
Args::check_case();
$::case_dir = "$::LOCKDIR/" . Args::get_case() . "/";
$::case_dir =~ s/\/\//\//g;
# Host functions
if ($view <= $HOST_MAX) {
if ($view == $Caseman::HOST_OPEN) {
return host_open();
}
elsif ($view == $Caseman::HOST_ADD) {
return host_add();
}
Args::check_host();
$::host_dir = "$::case_dir" . Args::get_host() . "/";
$::host_dir =~ s/\/\//\//g;
if ($view == $Caseman::HOST_ADD_DOIT) {
return host_add_doit();
}
Caseman::read_host_config();
if ($view == $Caseman::HOST_OPEN_LOG) {
return host_open_log();
}
elsif ($view == $Caseman::HOST_DETAILS) {
return host_details();
}
}
Args::check_host();
$::host_dir = "$::case_dir" . Args::get_host() . "/";
$::host_dir =~ s/\/\//\//g;
Caseman::read_host_config();
Args::check_inv();
if ($view <= $IMG_MAX) {
if ($view == $Caseman::VOL_OPEN) {
return vol_open();
}
elsif ($view == $Caseman::IMG_ADD) {
return img_add();
}
elsif ($view == $Caseman::IMG_ADD_PREP) {
return img_add_prep();
}
elsif ($view == $Caseman::IMG_ADD_DOIT) {
return img_add_doit();
}
Args::check_vol('vol');
if ($view == $Caseman::VOL_OPEN_LOG) {
return vol_open_log();
}
elsif ($view == $Caseman::VOL_DETAILS) {
return vol_details();
}
# elsif ($view == $Caseman::IMG_DEL) {
# return img_del();
# }
elsif ($view == $Caseman::VOL_MAKESTR) {
return vol_makestr();
}
elsif ($view == $Caseman::VOL_MAKEDLS) {
return vol_makedls();
}
}
Print::print_check_err("Invalid Case Management View");
}
####################################################################
# General menu Functions
sub print_menu_tabs {
if ($::LIVE == 1) {
print "<h2>Live Analysis Mode</h2>\n";
}
print "<table width=\"600\" height=\"60\" background=\"$::YEL_PIX\" "
. "border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tr>\n"
. "<td align=\"center\" width=\"200\">";
my $view = Args::get_view();
# Case Gallery Tab
if ($view == $Caseman::CASE_OPEN) {
print "<img border=0 src=\"pict/menu_t_cg_cur.jpg\" "
. "width=200 height=65 alt=\"Case Gallery (Current Mode)\">\n";
}
elsif ($::LIVE == 1) {
print "<img border=0 src=\"pict/menu_t_cg_org.jpg\" "
. "width=200 height=65 alt=\"Case Gallery\">\n";
}
else {
print "<a href=\"$::PROGNAME?"
. "mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
. "<img border=0 src=\"pict/menu_t_cg_link.jpg\" "
. "width=200 height=65 alt=\"Case Gallery\"></a>\n";
}
print "</td>\n" . "<td align=\"center\" width=\"200\">";
# Host Gallery Tab
# Current
if ($view == $Caseman::HOST_OPEN) {
print "<img border=0 src=\"pict/menu_t_hg_cur.jpg\" "
. "width=200 height=65 alt=\"Host Gallery (Current Mode)\">\n";
}
# Link
elsif (($view == $Caseman::VOL_OPEN) && ($::LIVE == 0)) {
print "<a href=\"$::PROGNAME?"
. "mod=$::MOD_CASEMAN&view=$Caseman::HOST_OPEN"
. "&case=$Args::args{'case'}\">"
. "<img border=0 src=\"pict/menu_t_hg_link.jpg\" "
. "width=200 height=65 alt=\"Host Gallery\"></a>\n";
}
# Non-link
else {
print "<img border=0 src=\"pict/menu_t_hg_org.jpg\" "
. "width=200 height=65 alt=\"Host Gallery (Not Available)\">\n";
}
print "</td>\n" . "<td align=\"center\" width=\"200\">";
# Host Manager Tab
# Current
if ($view == $Caseman::VOL_OPEN) {
print "<img border=0 src=\"pict/menu_t_hm_cur.jpg\" "
. "width=200 height=65 alt=\"Host Manager (Current Mode)\">\n";
}
# non-link
else {
print "<img border=0 src=\"pict/menu_t_hm_org.jpg\" "
. "width=200 height=65 alt=\"Host Manager (Not Available)\">\n";
}
print "</td>\n</tr>\n" . "</table>\n";
}
####################################################################
# Case Functions
# if no args are passed, return case config using args{'case'},
# else use the case value passed
#
# Case config:
# In case directory with case_name.case
sub case_config_fname {
if (scalar(@_) == 1) {
my $c = shift;
return "$::LOCKDIR/" . "$c/case.aut";
}
else {
return "$::LOCKDIR/" . "$Args::args{'case'}/case.aut";
}
}
# Read case config and save it to $Caseman::cvals
sub read_case_config {
return if ($::LIVE == 1);
my $case;
if (scalar(@_) == 1) {
$case = shift;
}
else {
$case = Args::get_case();
}
my $fname = case_config_fname($case);
%Caseman::cvals = ();
open CONFIG, "<$fname"
or die "Can't open case config file ($fname)";
while (<CONFIG>) {
next if ((/^\#/) || (/^\s+$/));
s/^\s+//;
s/\s+$//;
$Caseman::cvals{$1} = $2 if (/^(\S+)\s+(.*)$/);
}
close(CONFIG);
$Caseman::cvals{'desc'} = "None Provided"
unless (exists $Caseman::cvals{'desc'});
$Caseman::cvals{'created'} = "unknown"
unless (exists $Caseman::cvals{'created'});
}
sub case_new {
Print::print_html_header("Create A New Case");
print <<EOF;
<br>
<br>
<center>
<img src=\"pict/menu_h_cnew.jpg\" alt=\"New Case\">
<br><br><br>
<table width=\"600\" background=\"$::YEL_PIX\" cellspacing=\"0\"
cellpadding=\"2\" border=0>
<form action=\"$::PROGNAME\" method=\"get\">
<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW_DOIT\">
<tr>
<td colspan=3 align=left>
1. <b>Case Name:</b> The name of this investigation. It can contain only letters, numbers, and symbols.
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=2><input type=\"text\" name=\"case\"></td>
</tr>
<tr><td colspan=3> </td></tr>
<tr>
<td colspan=3 align=left>
2. <b>Description:</b> An optional, one line description of this case.
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=2><input type=\"text\" name=\"desc\" size=32 maxlength=32></td>
</tr>
<tr><td colspan=3> </td></tr>
<tr>
<td colspan=3 align=left>
3. <b>Investigator Names:</b> The optional names (with no spaces) of the investigators for this case.
</td>
</tr>
<tr>
<td> </td>
<td align=left><tt>a.</tt> <input type=\"text\" name=\"inv1\"></td>
<td align=left><tt>b.</tt> <input type=\"text\" name=\"inv2\"></td>
</tr>
<tr>
<td> </td>
<td align=left><tt>c.</tt> <input type=\"text\" name=\"inv3\"></td>
<td align=left><tt>d.</tt> <input type=\"text\" name=\"inv4\"></td>
</tr>
<tr>
<td> </td>
<td align=left><tt>e.</tt> <input type=\"text\" name=\"inv5\"></td>
<td align=left><tt>f.</tt> <input type=\"text\" name=\"inv6\"></td>
</tr>
<tr>
<td> </td>
<td align=left><tt>g.</tt> <input type=\"text\" name=\"inv7\"></td>
<td align=left><tt>h.</tt> <input type=\"text\" name=\"inv8\"></td>
</tr>
<tr>
<td> </td>
<td align=left><tt>i.</tt> <input type=\"text\" name=\"inv9\"></td>
<td align=left><tt>j.</tt> <input type=\"text\" name=\"inv10\"></td>
</tr>
</table>
<br><br>
<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<td align=center>
<input type=\"image\" src=\"pict/menu_b_cnew.jpg\"
alt=\"Create Case\" width=\"176\" height=20 border=0>
</td>
</form>
<td align=center>
<form action=\"$::PROGNAME\" method=\"get\">
<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">
<input type=\"image\" src=\"pict/menu_b_cancel.jpg\"
alt=\"Cancel\" width=\"167\" height=20 border=0>
</form>
</td>
<td align=center><a href=\"$::HELP_URL\"
target=\"_blank\">
<img src=\"pict/menu_b_help.jpg\" alt=\"Help\"
width=\"167\" height=20 border=0></a>
</td>
</tr>
</table>
EOF
Print::print_html_footer();
return;
}
# Create the directory and case configuration file
# Gets the input from CASE_NEW
sub case_new_doit {
Print::print_html_header("Creating Case: $Args::args{'case'}");
my $case = $Args::args{'case'};
print "<h3>Creating Case: <tt>$case</tt></h3>\n";
# Make the directory
if (-d "$::case_dir") {
Print::print_err("Error: $::case_dir already exists<br>"
. "Please remove the directory and its contents and try again"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::CASE_OPEN\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n");
}
unless (mkdir "$::case_dir", $::MKDIR_MASK) {
Print::print_err("Error making directory $::case_dir: $!");
}
print "Case directory (<tt>$::case_dir</tt>) created<br>\n";
Print::log_case_info("Case $case created");
my $fname = Caseman::case_config_fname();
open CASE_CONFIG, ">$fname" or die "Can't open case config: $fname";
print CASE_CONFIG "# Autopsy case config file\n"
. "# Case: $case\n\n"
. "created "
. localtime() . "\n";
if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
Print::print_err("Invalid Description<br>\n"
. "Use the browser's back button to fix")
if ($Args::args{'desc'} =~ /\n/);
print CASE_CONFIG "desc $Args::args{'desc'}\n";
}
print CASE_CONFIG "images $::IMGDIR\n";
print CASE_CONFIG "data $::DATADIR\n";
print CASE_CONFIG "log $::LOGDIR\n";
print CASE_CONFIG "reports $::REPDIR\n";
close CASE_CONFIG;
print "Configuration file (<tt>$fname</tt>) created<br>\n";
my $iname = investig_fname();
open INVES, ">>$iname" or die "Can't open investigators file: $iname";
my @invs;
if ( (exists $Args::args{'inv1'})
&& ($Args::args{'inv1'} ne "")
&& ($Args::args{'inv1'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv2'})
&& ($Args::args{'inv2'} ne "")
&& ($Args::args{'inv2'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv3'})
&& ($Args::args{'inv3'} ne "")
&& ($Args::args{'inv3'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv4'})
&& ($Args::args{'inv4'} ne "")
&& ($Args::args{'inv4'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv5'})
&& ($Args::args{'inv5'} ne "")
&& ($Args::args{'inv5'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv6'})
&& ($Args::args{'inv6'} ne "")
&& ($Args::args{'inv6'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv7'})
&& ($Args::args{'inv7'} ne "")
&& ($Args::args{'inv7'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv8'})
&& ($Args::args{'inv8'} ne "")
&& ($Args::args{'inv8'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv9'})
&& ($Args::args{'inv9'} ne "")
&& ($Args::args{'inv9'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
if ( (exists $Args::args{'inv10'})
&& ($Args::args{'inv10'} ne "")
&& ($Args::args{'inv10'} =~ /^\s*($::REG_INVESTIG)\s*$/o))
{
print INVES "$1\n";
push @invs, $1;
}
close(INVES);
Print::log_session_info("Case $case created");
print "<br><br>We must now create a host for this case.\n";
print "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
. "<input type=\"hidden\" name=\"case\" value=\"$case\">\n";
if (scalar @invs == 0) {
print "<option hiddden name=\"inv\" value=\"unknown\">\n";
}
else {
print "<br><br>Please select your name from the list: "
. "<select name=\"inv\" size=\"1\">\n";
foreach $i (@invs) {
print "<option value=\"$i\">$i</option>\n";
}
print "</select>\n";
}
print "<br><br>"
. "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" alt=\"Add New Host\" "
. "height=20 border=\"0\"></form>\n";
Print::print_html_footer();
return;
}
# Open a Case
# This provides a form with a list of options
sub case_open {
Print::print_html_header("Open A Case");
# Read the directories of the Evidence Locker into an array
# Verify that there is a config file in the directory
my @cases;
opendir CASES, $::LOCKDIR or die "Can't open $::LOCKDIR directory: $!";
foreach my $c (readdir CASES) {
next if (($c eq '.') || ($c eq '..'));
my $cfile = Caseman::case_config_fname($c);
push @cases, $c
if ((-d "$::LOCKDIR/$c") && (-e "$cfile"));
}
closedir CASES;
print "<br><br><center>";
# Were there any cases?
if (scalar @cases == 0) {
print "No cases exist in <tt>$::LOCKDIR</tt><br><br>\n"
. "Select the New Case button below to make one<br>\n";
}
else {
print "Select the case to open or create a new one<br>\n";
print_menu_tabs();
print "<table width=\"600\" background=\"$::YEL_PIX\" "
. " cellspacing=\"0\" cellpadding=\"2\" border=0>\n";
print "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN_LOG\">\n"
. Args::make_hidden()
. "<tr><th>Name</th>"
. "<th>Description</th>"
. "<td> </td></tr>\n";
my $first = 0;
foreach my $c (@cases) {
print "<tr><td align=\"left\">"
. "<input type=\"radio\" name=\"case\" value=$c";
if ($first == 0) {
print " CHECKED";
$first = 1;
}
print ">$c</td>";
Caseman::read_case_config($c);
print "<td>$Caseman::cvals{'desc'}</td>"
. "<td align=center>"
. "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::CASE_DETAILS&case=$c\">"
. "details</a></td>"
. "</tr>\n";
}
print "</table>\n";
}
print "<br><br>"
. "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
. "<tr>\n";
# Print the OK button if there were cases
if (scalar @cases != 0) {
print "<td align=center>"
. "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
. "width=167 height=20 alt=\"Ok\" border=0>"
. "</form></td>\n\n";
}
# Print a 'New Case' Button
print "<td align=center>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_NEW\">\n"
. "<input type=\"image\" src=\"pict/menu_b_cnew.jpg\" "
. "width=167 height=20 alt=\"New Case\" border=0>\n"
. "</form></td>"
.
# Print a Menu Button
"<td align=center>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"image\" src=\"pict/menu_b_menu.jpg\" "
. "width=167 height=20 alt=\"Main Menu\" border=0>\n"
. "</form></td></tr></table>\n";
print "<table width=600 cellspacing=\"0\" cellpadding=\"2\">\n<tr>"
. "<td> </td>\n"
. "<td align=center width=200><a href=\"$::HELP_URL\" "
. " target=\"_blank\">"
. "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
. "width=\"167\" height=20 border=0>"
. "</a></td>"
. "<td> </td>\n"
. "</tr>\n"
. "</table>";
Print::print_html_footer();
return;
}
# Log that a given case was opened and then proceed to open a host
sub case_open_log {
Print::log_session_info("Case $Args::args{'case'} opened");
Print::log_case_info("Case $Args::args{'case'} opened");
$Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::HOST_OPEN;
host_open();
}
# Display Case Details
sub case_details {
Print::print_html_header("Details of $Args::args{'case'}");
read_case_config();
$Caseman::cvals{'desc'} = " "
unless (exists $Caseman::cvals{'desc'});
$Caseman::cvals{'created'} = " "
unless (exists $Caseman::cvals{'created'});
print "<br><br>"
. "<center>"
. "<img src=\"pict/menu_h_cdet.jpg\" alt=\"Case Details\">"
. "<br><br><br>\n"
. "<table width=\"600\" cellspacing=\"0\" background=\"$::YEL_PIX\" "
. "cellpadding=\"2\" border=0>\n"
. " <tr><td align=\"right\" width=300><b>Name:</b></td>"
. "<td align=\"left\" width=300><tt>$Args::args{'case'}</tt></td></tr>\n"
.
# Description
" <tr><td align=\"right\"><b>Description:</b></td>"
. "<td align=\"left\"><tt>$Caseman::cvals{'desc'}</tt></td></tr>\n"
. " <tr><td align=\"right\"><b>Created:</b></td>"
. "<td align=\"left\"><tt>$Caseman::cvals{'created'}</tt></td></tr>\n";
# Display the valid investigators
my @invs = read_invest();
my $cnt = 0;
print " <tr><td colspan=\"2\"> </td></tr>\n"
if (scalar @invs > 0);
foreach my $i (@invs) {
if ($cnt == 0) {
print " <tr><td align=\"right\"><b>Investigators:</b></td>";
$cnt++;
}
else {
print " <tr><td> </td>";
}
print "<td align=\"left\"><tt>$i</tt></td></tr>\n";
}
print "</table>\n"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::CASE_OPEN\">"
. "<img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" "
. "width=\"167\" height=20 border=\"0\"></a>";
Print::print_html_footer();
return 0;
}
####################################################################
# Host Functions
# if no args are passed, return host config using args{'host'},
# else use the host value passed
sub host_config_fname {
if (scalar(@_) == 1) {
my $h = shift;
return "$::case_dir" . "$h/host.aut";
}
else {
return "$::host_dir" . "host.aut";
}
}
# Converts the original single image host config to the volume-based config
sub convert_host_config {
return if ($::LIVE == 1);
my $host = Args::get_host();
Print::log_host_info("Converting host config files");
print STDERR "Converting host config file to new format\n";
# The file to convert
my $cfile = host_config_fname();
unless (open(FILE, $cfile)) {
Print::print_check_err("Error opening $cfile");
}
my $tmpcfile = "$::host_dir" . "host-convert.aut";
unless (open(FILE_TMP, ">>$tmpcfile")) {
Print::print_check_err("Error opening $tmpcfile");
}
my $img_cnt = 0;
my $vol_cnt = 0;
$img2vol{'qazwsxedc'} = ""; # stores the image path to partition / file name
$img2vol2{'qazwsxedc'} =
""; # stores the image path to file name (no partitions)
while (<FILE>) {
if ((/^\#/) || (/^\s+$/)) {
print FILE_TMP $_;
next;
}
# remove whitespace
s/^\s+//;
s/\s+$//;
# normal file system image entry
#
# 'image images/hda1.dd openbsd /usr
if (/^image\s+($::REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
my $i = $1;
my $t = $2;
my $r = $3;
# Add trailing / to original mount point if needed
if (($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
$r .= '/';
}
my $vnum = "vol" . $vol_cnt;
my $inum = "img" . $img_cnt;
$img2vol{$i} = $vnum;
$img2vol2{$i} = $inum;
print FILE_TMP "image $inum raw $i\n";
print FILE_TMP "part $vnum $inum 0 0 $t $r\n";
$img_cnt++;
$vol_cnt++;
}
# swap
# swap images/hda3.dd
elsif (/^swap\s+($::REG_IMG)\s*$/o) {
my $i = $1;
my $vnum = "vol" . $vol_cnt;
my $inum = "img" . $img_cnt;
$img2vol{$i} = $vnum;
$img2vol2{$i} = $inum;
print FILE_TMP "image $inum raw $i\n";
print FILE_TMP "part $vnum $inum 0 0 swap\n";
$img_cnt++;
$vol_cnt++;
}
# raw
# raw images/hda3.dd
elsif (/^raw\s+($::REG_IMG)\s*$/o) {
my $i = $1;
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "img" . $img_cnt;
print FILE_TMP "image img" . $img_cnt . " raw $i\n";
print FILE_TMP "part vol" . $vol_cnt . " img" . $img_cnt
. " 0 0 raw\n";
$img_cnt++;
$vol_cnt++;
}
# entry for a strings or dls file
#
# strings data/hda1.str images/hda1.dd
elsif (/^strings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
my $i = $1;
my $o = $2;
if (exists $img2vol{$o}) {
my $vname = $img2vol{$o};
print FILE_TMP "strings vol" . $vol_cnt . " $vname $i\n";
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "vol" . $vol_cnt;
}
else {
print STDERR "Error: Volume for strings $o not found<br>\n";
}
$vol_cnt++;
}
# entry for a strings or dls file
#
# unistrings data/hda1.str images/hda1.dd
elsif (/^unistrings\s+($::REG_IMG)\s+($::REG_IMG)$/o) {
my $i = $1;
my $o = $2;
if (exists $img2vol{$o}) {
my $vname = $img2vol{$o};
print FILE_TMP "unistrings vol" . $vol_cnt
. " $vname $i\n";
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "vol" . $vol_cnt;
}
else {
print STDERR
"Error: Volume for unicode strings $o not found<br>\n";
}
$vol_cnt++;
}
# dls entry
# dls data/image.dls [images/image.dd]
elsif (/^dls\s+($::REG_IMG)\s*($::REG_IMG)$/o) {
my $i = $1;
my $o = $2;
$img2vol{$i} = "vol" . $vol_cnt;
if (exists $img2vol{$o}) {
my $vname = $img2vol{$o};
print FILE_TMP "dls vol" . $vol_cnt . " $vname $i\n";
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "vol" . $vol_cnt;
}
else {
print STDERR "Error: Volume for dls $o not found<br>\n";
}
$vol_cnt++;
}
# body data/body.txt
elsif (/^body\s+($::REG_IMG)$/o) {
my $i = $1;
print FILE_TMP "body vol" . $vol_cnt . " $i\n";
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "vol" . $vol_cnt;
$vol_cnt++;
}
# timeline data/timeline.txt
elsif (/^timeline\s+($::REG_IMG)$/o) {
my $i = $1;
print FILE_TMP "timeline vol" . $vol_cnt . " $i\n";
$img2vol{$i} = "vol" . $vol_cnt;
$img2vol2{$i} = "vol" . $vol_cnt;
$vol_cnt++;
}
# timezone XYZ
elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
print FILE_TMP "$_\n";
}
# timeskew XYZ
elsif (/^timeskew\s+($::REG_SKEW)$/o) {
print FILE_TMP "$_\n";
}
# desc XYZ
elsif (/^desc\s+(.*)$/) {
print FILE_TMP "$_\n";
}
# hash databases
elsif (/^alert_db\s+'(.*)'$/) {
print FILE_TMP "$_\n";
}
elsif (/^exclude_db\s+'(.*)'$/) {
print FILE_TMP "$_\n";
}
else {
my $msg =
"Error: invalid entry in $cfile:$." . "<br>\n"
. "image path fs_type mnt_point<br>\n"
. "strings path orig_img<br>\n"
. "dls path [orig_img]<br>\n"
. "body path<br>\n"
. "timeline path<br>\n"
. "timezone TZ<br>\n"
. "desc DESCRIPTION<br>\n";
Print::print_check_err($msg);
}
}
close(FILE);
close(FILE_TMP);
unless (rename $cfile, $cfile . ".bak") {
print STDERR "Error backing up original host config file\n";
}
unless (rename $tmpcfile, $cfile) {
print STDERR "Error renaming new host config file\n";
}
Notes::convert(\%img2vol);
Hash::convert(\%img2vol2);
}
# reads host config file and sets global hash values for images and other
sub read_host_config {
if ($::LIVE == 1) {
%Caseman::mod2vol = ();
%Caseman::vol2str = ();
%Caseman::vol2uni = ();
%Caseman::vol2dls = ();
$Caseman::tz = "";
$Caseman::ts = 0;
$Caseman::host_desc = "";
$Caseman::exclude_db = "";
$Caseman::alert_db = "";
return;
}
my $host = Args::get_host();
my $cfile = host_config_fname();
restart:
unless (open(FILE, $cfile)) {
Print::print_check_err("Error opening $cfile");
}
%Caseman::vol2mnt = ();
%Caseman::vol2ftype = ();
%Caseman::vol2dtype = ();
%Caseman::vol2cat = ();
%Caseman::mod2vol = ();
%Caseman::vol2str = ();
%Caseman::vol2uni = ();
%Caseman::vol2dls = ();
%Caseman::vol2par = ();
%Caseman::vol2start = ();
%Caseman::vol2end = ();
$Caseman::vol2path = ();
$Caseman::vol2sname = ();
$Caseman::tz = "";
$Caseman::ts = 0;
$Caseman::host_desc = "";
$Caseman::exclude_db = "";
$Caseman::alert_db = "";
while (<FILE>) {
next if ((/^\#/) || (/^\s+$/));
# remove whitespace
s/^\s+//;
s/\s+$//;
# old file system image entry
#
# 'image images/hda1.dd openbsd /usr
if (/^image\s+($::REG_IMG)\s+([\w\-]+)\s+([\w\-\_\.\/:\\]+)$/o) {
close(FILE);
convert_host_config();
goto restart;
}
elsif (
/^image\s+($::REG_INAME)\s+($::REG_IMGTYPE)\s+($::REG_IMG_CONFIG)$/o
)
{
my $me = $1;
my $t = $2;
my $i = $3;
unless ((-e "$::host_dir$i")
|| ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
{
Print::print_check_err(
"Error: image $i in ${host}.host:$. not found: "
. "$::host_dir"
. "$i <br>Edit the config file and refresh your browser"
. "<br>(Or your version of Perl does not support large files)"
);
}
if (exists $Caseman::vol2path{$me}) {
$Caseman::vol2path{$me} .= " \'$::host_dir" . "$i\'";
}
else {
$Caseman::vol2path{$me} = "\'$::host_dir" . "$i\'";
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
$Caseman::vol2par{$me} = "";
$Caseman::vol2cat{$me} = "image";
$Caseman::vol2itype{$me} = $t;
$Caseman::vol2ftype{$me} = "";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
}
}
elsif (
/^part\s+($::REG_VNAME)\s+($::REG_INAME)\s+(\d+)\s+(\d+)\s+($::REG_FTYPE)\s*([\w\-\_\.\/:\\]+)?$/o
)
{
my $par = $2;
my $me = $1;
my $s = $3;
my $e = $4;
my $t = $5;
my $r = $6; # Not defined for swap and raw
unless (exists $Fs::addr_unit{$t}) {
Print::print_check_err(
"Error: unknown type: $t in host config: $."
. "<br>Edit the file and refresh your browser");
}
if (exists $Caseman::vol2itype{$par}) {
$Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
}
else {
Print::print_check_err(
"Error: Image $par for partition $me was not found in config: $."
. "<br>Edit the file and refresh your browser");
}
$Caseman::vol2ftype{$me} = $t;
$Caseman::vol2cat{$me} = "part";
$Caseman::vol2start{$me} = $s;
$Caseman::vol2end{$me} = $e;
# Add trailing / to original mount point if needed
if ((defined $r) && ($r !~ /.*?\/$/) && ($r !~ /.*?\\$/)) {
$r .= '/';
}
$Caseman::vol2mnt{$me} = $r;
$Caseman::vol2par{$me} = $par;
$Caseman::vol2path{$me} = $Caseman::vol2path{$par};
$Caseman::vol2sname{$me} =
$Caseman::vol2sname{$par} . "-" . $s . "-" . $e;
}
elsif (/^disk\s+($::REG_VNAME)\s+($::REG_INAME)\s+($::REG_FTYPE)?$/o) {
my $par = $2;
my $me = $1;
my $t = $3;
unless (exists $Vs::type{$t}) {
Print::print_check_err(
"Error: unknown volume system type: $t in host config: $."
. "<br>Edit the file and refresh your browser");
}
if (exists $Caseman::vol2itype{$par}) {
$Caseman::vol2itype{$me} = $Caseman::vol2itype{$par};
}
else {
Print::print_check_err(
"Error: Image $par for disk $me was not found in config: $."
. "<br>Edit the file and refresh your browser");
}
$Caseman::vol2ftype{$me} = "raw";
$Caseman::vol2dtype{$me} = $t;
$Caseman::vol2cat{$me} = "disk";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2mnt{$me} = "";
$Caseman::vol2par{$me} = $par;
$Caseman::vol2path{$me} = $Caseman::vol2path{$par};
$Caseman::vol2sname{$me} = $Caseman::vol2sname{$par} . "-disk";
}
# entry for a strings or dls file
#
# strings data/hda1.str volX
elsif (/^strings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
my $i = $3;
my $par = $2;
my $me = $1;
unless ((-e "$::host_dir$i")
|| ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
{
Print::print_check_err("Error: strings file not found: "
. "$::host_dir$i<br>Edit host config in $::host_dir and refresh your browser"
);
}
unless (exists $Caseman::vol2cat{$par}) {
Print::print_check_err(
"Error: Volume $par for strings $me was not found in config: $."
. "<br>Edit the file and refresh your browser");
}
$Caseman::vol2ftype{$me} = "strings";
$Caseman::vol2cat{$me} = "mod";
$Caseman::vol2itype{$me} = "raw";
$Caseman::mod2vol{$me} = $par;
$Caseman::vol2str{$par} = $me;
$Caseman::vol2par{$me} = $par;
$Caseman::vol2path{$me} = "\'$::host_dir" . "$i\'";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
}
# entry for a strings or dls file
#
# unistrings data/hda1.str volX
elsif (/^unistrings\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o)
{
my $i = $3;
my $par = $2;
my $me = $1;
unless ((-e "$::host_dir$i")
|| ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
{
Print::print_check_err("Error: Unicode strings file not found: "
. "$::host_dir$i<br>Edit host config in $::host_dir and refresh your browser"
);
}
unless (exists $Caseman::vol2cat{$par}) {
Print::print_check_err(
"Error: Volume $par for unistrings $me was not found in config: $."
. "<br>Edit the file and refresh your browser");
}
$Caseman::vol2ftype{$me} = "strings";
$Caseman::vol2cat{$me} = "mod";
$Caseman::vol2itype{$me} = "raw";
$Caseman::mod2vol{$me} = $par;
$Caseman::vol2uni{$par} = $me;
$Caseman::vol2par{$me} = $par;
$Caseman::vol2path{$me} = "\'$::host_dir" . "$i\'";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
}
# dls entry
# dls themname myname
elsif (/^dls\s+($::REG_VNAME)\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
my $i = $3;
my $par = $2;
my $me = $1;
unless (
(-e "$::host_dir$i")
|| ( (-l "$::host_dir$i")
&& (-e readlink "$::host_dir$i"))
)
{
Print::print_check_err("Error: dls file not found: "
. "$::host_dir$i <br>Edit host config in $::host_dir and refresh your browser"
);
}
unless (exists $Caseman::vol2cat{$par}) {
Print::print_check_err(
"Error: Volume $par for dls $me was not found in config: $."
. "<br>Edit the file and refresh your browser");
}
$Caseman::vol2ftype{$me} = "dls";
$Caseman::vol2cat{$me} = "mod";
$Caseman::vol2itype{$me} = "raw";
$Caseman::vol2mnt{$me} = "";
$Caseman::vol2par{$me} = $par;
$Caseman::mod2vol{$me} = $par;
$Caseman::vol2dls{$par} = $me;
$Caseman::vol2path{$me} = "\'$::host_dir" . "$i\'";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
}
# body data/body.txt
elsif (/^body\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
my $me = $1;
my $i = $2;
unless ((-e "$::host_dir$i")
|| ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
{
Print::print_check_err("Error: body file not found: "
. "$::host_dir$i <br>Edit host config in $::host_dir and refresh your browser"
);
}
$Caseman::vol2cat{$me} = "timeline";
$Caseman::vol2ftype{$me} = "body";
$Caseman::vol2itype{$me} = "raw";
$Caseman::vol2path{$me} = "\'$::host_dir" . "$i\'";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
}
# timeline data/timeline.txt
elsif (/^timeline\s+($::REG_VNAME)\s+($::REG_IMG)$/o) {
my $me = $1;
my $i = $2;
unless ((-e "$::host_dir$i")
|| ((-l "$::host_dir$i") && (-e readlink "$::host_dir$i")))
{
Print::print_check_err("Error: timeline file not found: "
. "$::host_dir$i <br>Edit host config in $::host_dir and refresh your browser"
);
}
$Caseman::vol2cat{$me} = "timeline";
$Caseman::vol2ftype{$me} = "timeline";
$Caseman::vol2itype{$me} = "raw";
# 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
$Caseman::vol2path{$me} = "$::host_dir" . "$i";
$Caseman::vol2start{$me} = 0;
$Caseman::vol2end{$me} = 0;
$Caseman::vol2sname{$me} = $i;
$Caseman::vol2sname{$me} = $1 if ($i =~ /\/($::REG_FILE)$/);
}
# timezone XYZ
elsif (/^timezone\s+($::REG_ZONE_ARGS)$/o) {
$Caseman::tz = "\'$1\'";
}
# timeskew XYZ
elsif (/^timeskew\s+($::REG_SKEW)$/o) {
$Caseman::ts = "\'$1\'";
}
# desc XYZ
elsif (/^desc\s+(.*)$/) {
$Caseman::host_desc = "$1";
}
# hash databases
elsif (/^alert_db\s+'(.*)'$/) {
$Caseman::alert_db = "$1";
}
elsif (/^exclude_db\s+'(.*)'$/) {
$Caseman::exclude_db = "$1";
}
else {
my $msg =
"Error: invalid entry in $cfile:$." . "<br>\n" . "$_<br>\n";
Print::print_check_err($msg);
}
}
close(FILE);
}
# Add a new image entry to the host config and return its id
sub add_img_host_config {
my $type = shift;
my $other = shift;
my $id = shift;
my $read = host_config_fname();
my $write = $read . "-" . rand();
unless (open(READ, "<$read")) {
Print::print_check_err("Error opening $read");
}
unless (open(WRITE, ">$write")) {
Print::print_check_err("Error opening $write");
}
my $maxcnt = 0;
while (<READ>) {
s/^\s+//;
s/\s+$//;
if (/^\w+\s+img(\d+)\s+.*$/) {
$maxcnt = $1 if ($1 > $maxcnt);
}
print WRITE "$_\n";
}
$maxcnt++;
if ($id eq "") {
$id = "img" . $maxcnt;
}
print WRITE "$type $id $other\n";
Print::log_host_info("Image added: $type $id $other");
close(READ);
close(WRITE);
unless (rename $write, $read) {
print STDERR "Error renaming temp host config file\n";
}
return $id;
}
# Add a new volume entry to the host config and return its id
sub add_vol_host_config {
my $type = shift;
my $other = shift;
my $read = host_config_fname();
my $write = $read . "-" . rand();
unless (open(READ, "<$read")) {
Print::print_check_err("Error opening $read");
}
unless (open(WRITE, ">$write")) {
Print::print_check_err("Error opening $write");
}
# We want to find the max count ... not just the unused
# ones because we could end up reusing one and that could
# mess up the notes
my $maxcnt = 0;
while (<READ>) {
s/^\s+//;
s/\s+$//;
if (/^\w+\s+vol(\d+)\s+.*$/) {
$maxcnt = $1 if ($1 > $maxcnt);
}
print WRITE "$_\n";
}
$maxcnt++;
print WRITE "$type vol" . $maxcnt . " $other\n";
Print::log_host_info("Volume added: $type vol" . $maxcnt . " $other");
close(READ);
close(WRITE);
unless (rename $write, $read) {
print STDERR "Error renaming temp host config file\n";
}
return "vol" . $maxcnt;
}
# Delete anentry from the host config
# DOES NOT WORK RIGHT NOW
sub del_host_config_BLAH {
return;
my $type = shift;
my $other = shift;
my $read = host_config_fname();
my $write = $read . "-" . rand();
unless (open(READ, "<$read")) {
Print::print_check_err("Error opening $read");
}
unless (open(WRITE, ">$write")) {
Print::print_check_err("Error opening $write");
}
while (<READ>) {
s/^\s+//;
s/\s+$//;
print WRITE "$_\n"
unless ((/^(\w+)\s+($::REG_IMG)/o)
&& ($2 eq $img)
&& ($1 ne 'desc')
&& ($1 ne 'timezone'));
}
if ($type ne "") {
if (defined $ref) {
print WRITE "$type $img $ref\n";
}
else {
print WRITE "$type $img\n";
}
}
close(READ);
close(WRITE);
unless (rename $write, $read) {
print STDERR "Error renaming temp host config file\n";
}
return;
}
# Given the image and md5, it is saved to the MD5.txt file and any other
# references to the image are removed
#
# if $md5 is "", then nothing is written
sub update_md5 {
my $vol = shift;
my $md5 = shift;
$md5 =~ tr/[a-f]/[A-F]/;
my $read = "$::host_dir/md5.txt";
my $write = $read . "-" . rand();
unless (open(WRITE, ">$write")) {
Print::print_check_err("Error opening $write");
}
if (-e "$read") {
unless (open(READ, "<$read")) {
Print::print_check_err("Error opening $read");
}
while (<READ>) {
s/^\s+//;
s/\s+$//;
print WRITE "$_\n"
unless ((/^$::REG_MD5\s+($::REG_VNAME)/o) && ($1 eq $vol));
}
close(READ);
}
print WRITE "$md5 $vol\n" if ($md5 ne "");
close(WRITE);
unless (rename $write, $read) {
print STDERR "Error renaming temp MD5 hash file\n";
}
return;
}
sub host_add {
Print::print_html_header("Add A New Host To $Args::args{'case'}");
print "<b>Case: </b> $Args::args{'case'}<br><br>\n";
print "<center>"
. "<img src=\"pict/menu_h_hnew.jpg\" alt=\"Add Host\">"
. "<br><br><br>\n";
print "<table width=\"600\" cellspacing=\"0\" background=\"$::YEL_PIX\" "
. "cellpadding=\"2\" border=0>\n"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD_DOIT\">\n"
. Args::make_hidden()
. "<tr><td colspan=\"2\"> </td></tr>"
.
# Host name
"<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>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\"><input type=\"text\" name=\"host\" size=32 maxlength=32 value=\"host1\"></td></tr>\n"
.
# Description
"<tr><td align=\"left\" colspan=2>2. <b>Description:</b> An optional one-line description or note about this computer.</td></tr>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\">"
. "<input type=\"text\" name=\"desc\" size=32 maxlength=32></td></tr>\n"
.
# Empty line
"<tr><td colspan=\"2\"> </td></tr>" .
# Timezone
"<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>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\">"
. "<input type=\"text\" name=\"tz\" size=16 maxlength=64></td></tr>\n"
.
# Timeskew
"<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>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\">"
. "<input type=\"text\" name=\"ts\" size=8 maxlength=16 value=\"0\">"
. "</td></tr>\n"
.
# Spacer
"<tr><td colspan=\"2\"> </td></tr>" .
# Alert
"<tr><td align=\"left\" colspan=2>5. <b>Path of Alert Hash Database:</b> An optional hash database of known bad files.</td></tr>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\">"
. "<input type=\"text\" name=\"alert_db\" size=32 maxlength=512>"
. "</td></tr>\n"
.
# Ignore
"<tr><td align=\"left\" colspan=2>6. <b>Path of Ignore Hash Database:</b> An optional hash database of known good files.</td></tr>"
. "<tr><td align=\"left\"> </td>"
. "<td align=\"left\">"
. "<input type=\"text\" name=\"exclude_db\" size=32 maxlength=512>"
. "</td></tr>\n"
.
# Spacer
"<tr><td colspan=\"2\"> </td></tr>" . "</table>\n";
if (exists $Args::args{'inv'}) {
print
"<input type=\"hidden\" name=\"inv\" value=\"$Args::args{'inv'}\">\n";
}
# Ok Button
print "<br><br><table width=\"600\" cellspacing=\"8\" cellpadding=\"2\">\n"
. "<tr><td align=center>"
. "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" "
. "width=167 height=20 alt=\"Add Host\" border=0>\n"
. "</form></td>\n"
.
# Cancel Button
"<td align=center>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
. "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
. "<input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
. "alt=\"Cancel\" width=\"167\" height=20 border=0>\n"
. "</form></td>\n"
.
# Help Button
"<td align=center><a href=\"$::HELP_URL\" "
. "target=\"_blank\">"
. "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
. "width=\"167\" height=20 border=0></a>"
. "</td></tr>\n"
. "</table>";
Print::print_html_footer();
return 0;
}
# Make the directories and config files for a host
sub host_add_doit {
Args::check_tz()
if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
Args::check_ts();
Print::print_html_header(
"Adding Host $Args::args{'host'} to $Args::args{'case'}");
print "<h3>Adding host: <tt>$Args::args{'host'}</tt> to "
. "case <tt>$Args::args{'case'}</tt></h3>\n";
# Do some sanity checks before we start making the directories and such
if ( (exists $Args::args{'alert_db'})
&& ($Args::args{'alert_db'} ne ""))
{
unless ($Args::args{'alert_db'} =~ /^$::REG_HASHDB$/o) {
print "Invalid Alert Database path\n"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n";
return 1;
}
unless (-e "$Args::args{'alert_db'}") {
print "Alert Database Not Found: $Args::args{'alert_db'}"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n";
return 1;
}
}
if ( (exists $Args::args{'exclude_db'})
&& ($Args::args{'exclude_db'} ne ""))
{
unless ($Args::args{'exclude_db'} =~ /^$::REG_HASHDB$/o) {
print "Invalid Exclude Database path\n"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n";
return 1;
}
unless (-e "$Args::args{'exclude_db'}") {
print "Exclude Database Not Found: $Args::args{'exclude_db'}"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_ADD&case=$Args::args{'case'}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n";
return 1;
}
}
# Make the directory
if (-d "$::host_dir") {
Print::print_err("Error: $::host_dir already exists<br>"
. "Please remove the directory and its contents and try again"
. "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_OPEN&case=$Args::enc_args{'case'}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n");
}
unless (mkdir "$::host_dir", $::MKDIR_MASK) {
Print::print_err("Error making directory $::host_dir: $!");
}
print "Host Directory (<tt>$::host_dir</tt>) created<p>\n";
Print::log_case_info("Host $Args::args{'host'} added to case");
# Images directory
unless (mkdir "$::host_dir" . "$::IMGDIR", $::MKDIR_MASK) {
rmdir "$::host_dir";
Print::print_err("Error making $::host_dir" . "$::IMGDIR");
}
# Output Directory
unless (mkdir "$::host_dir" . "$::DATADIR", $::MKDIR_MASK) {
rmdir "$::host_dir" . "$::IMGDIR";
rmdir "$::host_dir";
Print::print_err("Error making $::host_dir" . "$::DATADIR");
}
# Log Directory
unless (mkdir "$::host_dir" . "$::LOGDIR", $::MKDIR_MASK) {
rmdir "$::host_dir" . "$::DATADIR";
rmdir "$::host_dir" . "$::IMGDIR";
rmdir "$::host_dir";
Print::print_err("Error making $::host_dir" . "$::LOGDIR");
}
# Reports directory
unless (mkdir "$::host_dir" . "$::REPDIR", $::MKDIR_MASK) {
rmdir "$::host_dir" . "$::LOGDIR";
rmdir "$::host_dir" . "$::DATADIR";
rmdir "$::host_dir" . "$::IMGDIR";
rmdir "$::host_dir";
Print::print_err("Error making $::host_dir" . "$::REPDIR");
}
# Make a directory for mounting the image in loopback
unless (mkdir "$::host_dir" . "mnt", $::MKDIR_MASK) {
rmdir "$::host_dir" . "$::REPDIR";
rmdir "$::host_dir" . "$::LOGDIR";
rmdir "$::host_dir" . "$::DATADIR";
rmdir "$::host_dir" . "$::IMGDIR";
rmdir "$::host_dir";
Print::print_err("Error making $::host_dir" . "mnt");
}
Print::log_host_info(
"Host $Args::args{'host'} added to case $Args::args{'case'}");
# Create config file
my $fname = Caseman::host_config_fname();
open HOST_CONFIG, ">$fname" or die "Can't open host config: $fname";
print HOST_CONFIG "# Autopsy host config file\n"
. "# Case: $Args::args{'case'} Host: $Args::args{'host'}\n"
. "# Created: "
. localtime() . "\n\n";
if ((exists $Args::args{'desc'}) && ($Args::args{'desc'} ne "")) {
Print::print_err("Invalid Description<br>\n"
. "Use the browser's back button to fix")
if ($Args::args{'desc'} =~ /\n/);
print HOST_CONFIG "desc $Args::args{'desc'}\n";
}
print HOST_CONFIG "timezone " . Args::get_tz() . "\n"
if ((exists $Args::args{'tz'}) && ($Args::args{'tz'} ne ""));
print HOST_CONFIG "timeskew " . Args::get_ts() . "\n";
if ( (exists $Args::args{'alert_db'})
&& ($Args::args{'alert_db'} ne ""))
{
# Index it if it is not
unless (-e "$Args::args{'alert_db'}-md5.idx") {
print
"Alert Database has not been indexed - it will be as an md5sum file<br>\n";
print "<hr>\n";
Hash::index_md5sum($Args::args{'alert_db'});
print "<hr>\n";
}
# only print it if it was successful
print HOST_CONFIG "alert_db \'$Args::args{'alert_db'}\'\n"
if (-e "$Args::args{'alert_db'}-md5.idx");
}
if ( (exists $Args::args{'exclude_db'})
&& ($Args::args{'exclude_db'} ne ""))
{
# Index it if it is not
unless (-e "$Args::args{'exclude_db'}-md5.idx") {
print
"Exclude Database has not been indexed - it will be as an md5sum file<br>\n";
print "<hr>\n";
Hash::index_md5sum($Args::args{'exclude_db'});
print "<hr>\n";
}
# only print it if it was successful
print HOST_CONFIG "exclude_db \'$Args::args{'exclude_db'}\'\n"
if (-e "$Args::args{'exclude_db'}-md5.idx");
}
close HOST_CONFIG;
print "Configuration file (<tt>$fname</tt>) created<br><br>\n";
print "We must now import an image file for this host\n";
print "<br><br><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_OPEN_LOG&$Args::baseargs\">"
. "<img src=\"pict/menu_b_inew.jpg\" alt=\"Add Image\" "
. " height=20 border=\"0\"></a>\n";
Print::print_html_footer();
return 0;
}
# Open a host in the given case
sub host_open {
Print::print_html_header("Open Host In $Args::args{'case'}");
# Create an array of directories in the case, verifying that there is
# a config file
my @hosts;
opendir HOSTS, $::case_dir or die "Can't open $::case_dir directory: $!";
foreach my $h (readdir HOSTS) {
next if (($h eq '.') || ($h eq '..'));
my $hfile = Caseman::host_config_fname($h);
push @hosts, $h
if ((-d "$::case_dir" . "$h") && (-e "$hfile"));
}
closedir HOSTS;
print "<b>Case:</b> $Args::args{'case'}<br><br>\n";
print "<center>";
if (scalar @hosts == 0) {
print "No hosts have been added to the case yet"
. "<br><br>Select the Add Host button below to create one.<br>\n";
}
else {
print "Select the host to open or create a new one<br>\n";
print_menu_tabs();
print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
. "background=\"$::YEL_PIX\" border=0>\n";
print "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
. Args::make_hidden()
. "<tr><th>Name</th>"
. "<th>Description</th><th> </th></tr>\n";
my $first = 0;
foreach my $h (@hosts) {
print "<tr><td align=\"left\">"
. "<input type=\"radio\" name=\"host\" value=$h";
if ($first == 0) {
print " CHECKED";
$first = 1;
}
print "> $h </td>";
my $fname = Caseman::host_config_fname($h);
open CONFIG, "<$fname"
or die "Can't open host config file ($fname)";
my $desc = "None Provided";
while (<CONFIG>) {
s/^\s+//;
s/\s+$//;
if (/^desc\s+(.*)$/) {
$desc = $1;
last;
}
}
close CONFIG;
print "<td align=left>$desc</td>"
. "<td align=center>"
. "<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::HOST_DETAILS&$Args::baseargs&"
. "host=$h\">details</a></td></tr>\n";
}
print "</table>\n";
# Display pulldown of investigators
my @invs = read_invest();
if (scalar @invs == 0) {
print "<input type=\"hidden\" name=\"inv\" value=\"unknown\">\n";
}
else {
print "<br>Investigator (for reports only): ";
my $cur_inv = "";
$cur_inv = $Args::args{'inv'} if (exists $Args::args{'inv'});
print "<select name=\"inv\" size=\"1\">\n";
if (($cur_inv eq "") && (scalar @invs != 1)) {
print "<option value=\"\" selected>Select One" . "</option>\n";
}
foreach my $i (@invs) {
print "<option value=\"$i\"";
print " selected" if ($cur_inv eq $i);
print ">$i</option>\n";
}
print "</select>\n";
}
}
print "<br><br><table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
. "<tr>\n";
# Make a table for the buttons. The table will either be 3 or 2
# entries wide, depending on if there is an 'Ok' button or not
unless (scalar @hosts == 0) {
print "<td align=center>"
. "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
. "alt=\"Ok\" width=\"167\" height=20 border=0>\n"
. "</form>\n</td>\n";
}
# Add Host
print "<td align=center>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_ADD\">\n"
. "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
. "<input type=\"image\" src=\"pict/menu_b_hnew.jpg\" "
. "alt=\"Add Host\" width=\"176\" height=20 border=0>\n"
. "</form></td>"
.
# Close Button
"<td align=center>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::CASE_OPEN\">\n"
. "<input type=\"image\" src=\"pict/menu_b_ccls.jpg\" "
. "alt=\"Close Case\" width=\"176\" height=20 border=0>\n"
. "</form></td></tr></table>\n";
print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
. "<tr><td> </td>"
. "<td align=center><a href=\"$::HELP_URL\" "
. " target=\"_blank\">"
. "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
. "width=\"167\" height=20 border=0>"
. "</a></td><td> </td></tr>\n"
. "</table>\n";
Print::print_html_footer();
return 0;
}
# Log that a given host was opened and then proceed to open an image
sub host_open_log {
unless ((exists $Args::args{'inv'}) && ($Args::args{'inv'} ne "")) {
my @invs = read_invest();
if (scalar @invs == 0) {
$Args::args{'inv'} = $Args::enc_args{'inv'} = 'unknown';
}
else {
Print::print_html_header("Missing Investigator");
print "<br>An investigator must be selected<p>\n"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN_LOG\">\n"
. Args::make_hidden();
print "Select one of the following:";
print "<select name=\"inv\" size=\"1\">\n";
print "<option value=\"\" selected>Select One" . "</option>\n";
foreach my $i (@invs) {
print "<option value=\"$i\">$i</option>\n";
}
print "</select><p>\n"
. "<input type=\"image\" src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=43 height=20 border=\"0\">\n"
. "</form>\n";
Print::print_html_footer();
return 0;
}
}
Args::check_inv();
Print::log_case_info(
"Host $Args::args{'host'} opened by $Args::args{'inv'}");
Print::log_host_info(
"Host $Args::args{'host'} opened by $Args::args{'inv'}");
Print::log_host_inv("Host $Args::args{'host'} opened");
$Args::args{'view'} = $Args::enc_args{'view'} = $Caseman::VOL_OPEN;
vol_open();
}
# Provide details about the configuration of a host. This window is
# a link from the HOST_OPEN window
sub host_details {
Print::print_html_header(
"Details of $Args::args{'case'}:$Args::args{'host'}");
print "<b>Case: </b>$Args::args{'case'}<br><br>"
. "<center>"
. "<img src=\"pict/menu_h_hdet.jpg\" alt=\"Host Details\">"
. "<br><br><br>\n"
. "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
. "background=\"$::YEL_PIX\" border=0>\n"
.
# Name
"<tr><td align=\"right\" width=300><b>Name:</b></td>"
. "<td align=\"left\" width=300><tt>$Args::args{'host'}</tt></td></tr>\n"
.
# Description
"<tr><td align=\"right\"><b>Description:</b></td>"
. "<td align=\"left\"><tt>"
. (($Caseman::host_desc ne "") ? $Caseman::host_desc : " ")
. "</tt></td></tr>\n"
.
# Timezone
"<tr><td align=\"right\"><b>Time zone: </b></td>"
. "<td align=\"left\"><tt>$Caseman::tz</tt></td></tr>\n"
.
# Timeskew
"<tr><td align=\"right\"><b>Timeskew:</b></td>"
. "<td align=\"left\"><tt>$Caseman::ts</tt></td></tr>\n"
. "<tr><td colspan=2> </td></tr>\n"
.
# Actual Directory
"<tr><td align=\"right\"><b>Directory:</b></td>"
. "<td align=\"left\"><tt>$::host_dir</tt></td></tr>\n"
. "<tr><td colspan=2> </td></tr>\n"
.
# Alert Database
"<tr><td align=\"right\"><b>Alert Hash Database:</b></td>"
. "<td align=\"left\"><tt>"
. (($Caseman::alert_db ne "") ? $Caseman::alert_db : " ")
. "</tt></td></tr>\n"
.
# Exclude Database
"<tr><td align=\"right\"><b>Exclude Hash Database:</b></td>"
. "<td align=\"left\"><tt>"
. (($Caseman::exclude_db ne "") ? $Caseman::exclude_db : " ")
. "</tt></td></tr>\n"
. "</table>\n";
# Final Button
print "<br><br><form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
. Args::make_hidden()
. "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" "
. "alt=\"Ok\" width=\"167\" height=20 border=\"0\">\n</form>";
Print::print_html_footer();
return;
}
# Read the investigators file and return a sorted list
sub read_invest {
my $fname = investig_fname();
open INVES, "<$fname" or return;
my @investigs;
while (<INVES>) {
chomp;
s/^\s+//;
s/\s+$//;
push @investigs, $1
if (/^($::REG_INVESTIG)$/o);
}
close(INVES);
sort { lc($a) cmp lc($b) } @investigs;
}
# File of investigators name in list
sub investig_fname {
return "$::case_dir" . "investigators.txt";
}
####################################################################
# Image Functions
# Types of modes for fname (i.e. can we overwrite it if it exists)
my $FNAME_MODE_INIT = 0;
my $FNAME_MODE_OVER = 1;
my $MD5_NOTHING = 1;
my $MD5_CALC = 2;
my $MD5_ADD = 3;
my $IMG_ADD_SYM = 1;
my $IMG_ADD_COPY = 2;
my $IMG_ADD_MOVE = 3;
# Open an image that has been configured
sub vol_open {
Print::print_html_header(
"Open Image In $Args::args{'case'}:$Args::args{'host'}");
print "<b>Case:</b> $Args::args{'case'}<br>\n";
print "<b>Host:</b> $Args::args{'host'}<br>\n";
print "<center>\n";
# the images have been loaded from reading the host config file in
# autopsy_main
if (scalar(keys %Caseman::vol2ftype) == 0) {
print "No images have been added to this host yet<br><br>\n"
. "Select the Add Image File button below to add one\n";
goto EGRESS;
}
if ($::LIVE == 1) {
print "Select a volume to analyze.<br>\n";
}
else {
print "Select a volume to analyze or add a new image file.<br>\n";
}
print_menu_tabs();
print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
. "background=\"$::YEL_PIX\" border=0>\n";
# We want to sort, so rearrange the hash
my %mnt2vol;
my %par2disk;
# Cycle through each image we read from the host config
foreach my $i (keys %Caseman::vol2cat) {
if ($Caseman::vol2cat{$i} eq "disk") {
$mnt2vol{"1disk--AUTOPSY--$i"} = $i;
}
elsif ($Caseman::vol2cat{$i} eq "part") {
if ( ($Caseman::vol2ftype{$i} eq "raw")
|| ($Caseman::vol2ftype{$i} eq "swap"))
{
$mnt2vol{"2$Caseman::vol2ftype{$i}--AUTOPSY--$i"} = $i;
}
else {
$mnt2vol{"2$Caseman::vol2mnt{$i}--AUTOPSY--$i"} = $i;
}
}
}
# sort via parent volume, then starting location,
# and then mount point (which includes the name)
my @mnt = sort {
($Caseman::vol2par{$mnt2vol{$a}} cmp $Caseman::vol2par{$mnt2vol{$b}})
or ($Caseman::vol2start{$mnt2vol{$a}} <=>
$Caseman::vol2start{$mnt2vol{$b}})
or (lc($a) cmp lc($b))
} keys %mnt2vol;
# It is possible to have only the dls image and not the original
# We need to search for those now because they will not be in the
# list that we just made (which are arranged via mount point)
my @orphan_dls;
# cycle through each image and check its type and original
foreach my $k (keys %Caseman::vol2ftype) {
if ( ($Caseman::vol2ftype{$k} eq "dls")
&& (!exists $Caseman::mod2vol{$k}))
{
push @orphan_dls, $k;
}
}
print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN_LOG\">\n"
. Args::make_hidden()
. "<tr><th> </th>"
. "<th align=left>mount</th>"
. "<th align=left>name</th>"
. # vol name
"<th align=left>fs type</th></tr>\n";
my $prev_par = "";
for (my $i = 0; $i <= $#mnt; $i++) {
my $vol = $mnt2vol{$mnt[$i]};
if ($Caseman::vol2par{$vol} ne $prev_par) {
print "<tr><td colspan=5><hr></td></tr>\n" if ($i != 0);
$prev_par = $Caseman::vol2par{$vol};
}
# Mount Point
# If we have the dummy string at the end of the duplicate
# entry, then take it off and print the original
$mnt[$i] = $1 if ($mnt[$i] =~ /^\d(.*?)--AUTOPSY--$::REG_VNAME$/o);
print "<tr>" . "<td><input type=\"radio\" name=\"vol\" value=$vol";
print " CHECKED" if ($i == 0);
print "></td>" . "<td><tt>$mnt[$i]</tt></td>";
# image name and ftype
print
"<td><tt>$Caseman::vol2sname{$vol}</tt></td><td>$Caseman::vol2ftype{$vol}</td>";
if ($::LIVE == 0) {
print "<td align=center><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::VOL_DETAILS&$Args::baseargs&"
. "vol=$vol\">details</a></td>"
. "</tr>\n";
}
else {
print "<td> </td></tr>\n";
}
}
# If we are done with the regular images and have some orphan
# dls images, print them
my @sort = sort @orphan_dls;
for (my $i = 0; $i <= $#sort; $i++) {
print
"<tr><td> </td><td> </td><td>(<input type=\"radio\" name=\"vol\" "
. "value=$sort[$i]";
print " CHECKED" if ($#mnt == 0);
print
"> unalloc)</td><td><tt>$Caseman::vol2sname{$sort[$i]}</tt></td><td>$Caseman::vol2ftype{$sort[$i]}</td></tr>\n";
}
# Begin Button
print "</table>\n";
EGRESS:
print "<br><br>"
. "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n";
# Ok Button
if (scalar(keys %Caseman::vol2ftype) == 0) {
print "<tr><td width=200> </td>\n";
}
else {
print "<tr><td align=center width=200>"
. "<input type=\"image\" src=\"pict/menu_b_analyze.jpg\" "
. "alt=\"Analyze\" width=\"167\" height=20 border=0>\n"
. "</form></td>\n";
}
# Image Add Button
if ($::LIVE == 0) {
print "<td align=center width=200>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD\">\n"
. Args::make_hidden()
. "<input type=\"image\" src=\"pict/menu_b_ifnew.jpg\" "
. "alt=\"Add Image\" width=167 height=20 border=0></form></td>\n"
.
# Cancel Button
"<td align=center width=200>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::HOST_OPEN\">\n"
. "<input type=\"hidden\" name=\"case\" value=\"$Args::args{'case'}\">\n"
. "<input type=\"image\" src=\"pict/menu_b_hcls.jpg\" "
. "width=167 height=20 alt=\"Close Host\" border=0>\n"
. "</form></td></tr>";
}
else {
print "<td width=200> </td><td width=200> </td></tr>\n";
}
# Help Button
print
"<td width=200> </td><td align=center width=200><a href=\"$::HELP_URL\" "
. " target=\"_blank\">"
. "<img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
. "width=\"167\" height=20 border=0>"
. "</a></td><td width=200> </td></tr>\n"
. "</table>\n";
# Other features that can be done on a host
if ($::LIVE == 0) {
print "<hr><p>"
. "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
. "<tr>\n";
# Timeline of file activity
print "<td align=\"center\" width=200>"
. "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
. "mod=$::MOD_TL&view=$Timeline::FRAME\">"
. "<img border=0 "
. "src=\"pict/menu_b_tl.jpg\" "
. "width=\"167\" height=20 "
. "alt=\"File Activity Timelines\"></a></td>\n";
# verify the integrity of the images
print "<td align=\"center\" width=200>"
. "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
. "mod=$::MOD_HASH&view=$Hash::IMG_LIST_FR\">"
. "<img border=0 "
. "src=\"pict/menu_b_int.jpg\" "
. "width=\"167\" height=20 "
. "alt=\"Image Integrity\"></a></td>\n"
.
# Hashdatabases
"<td align=\"center\" width=200>"
. "<a href=\"$::PROGNAME?${Args::baseargs_novol}&"
. "mod=$::MOD_HASH&view=$Hash::DB_MANAGER\">"
. "<img border=0 "
. "src=\"pict/menu_b_hashdb.jpg\" "
. "width=\"167\" height=20 "
. "alt=\"Hash Databases\"></a></td>\n"
. "</tr></table>\n";
# Notes
if ($::USE_NOTES == 1) {
print "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">\n"
. "<tr>\n"
. "<td align=\"center\" width=300>"
. "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_NORM\">"
. "<img border=0 "
. "src=\"pict/menu_b_note.jpg\" "
. "width=\"167\" height=20 "
. "alt=\"View Notes\"></a></td>\n"
.
"<td width=300 align=\"center\">"
. "<a href=\"$::PROGNAME?${Args::baseargs_novol}&mod=$::MOD_NOTES&view=$Notes::READ_SEQ\">"
. "<img border=0 "
. "src=\"pict/menu_b_seq.jpg\" "
. "width=\"167\" height=20 "
. "alt=\"Event Sequencer\"></a></td>\n"
.
"</tr>\n" . "</table>\n";
}
# If LIVE
}
else {
print "<a href=\"./about\"><br>\n"
. "<img src=\"pict/logo.jpg\" border=0 alt=\"Logo\"></a><br>\n";
}
Print::print_html_footer();
return 0;
}
# Log in the host log that a given image was opened by what user
# then open the main window
sub vol_open_log {
# These will be stopped in the func during LIVE
Print::log_host_info(
"Image $Args::args{'vol'} opened by $Args::args{'inv'}");
Print::log_host_inv("$Args::args{'vol'}: volume opened");
$Args::args{'mod'} = $Args::enc_args{'mod'} = $::MOD_FRAME;
$Args::args{'view'} = $Args::enc_args{'view'} = $Frame::IMG_FRAME;
Frame::main();
}
# Menu to add a new image to the host
#
# The list of new images is determined by looking in the images directory
# and seeing which is not yet configured
#
sub img_add {
Print::print_html_header(
"Add Image To $Args::args{'case'}:$Args::args{'host'}");
print "<b>Case:</b> $Args::args{'case'}<br>\n"
. "<b>Host:</b> $Args::args{'host'}<br>\n";
print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
. Args::make_hidden();
print <<EOF1;
<center>
<img src=\"pict/menu_h_inew.jpg\" alt=\"Add Image\">
<br><br><br>
<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
<tr>
<td colspan=4> </td>
</tr>
<tr>
<td align=left colspan=4>
1. <b>Location</b><br>Enter the full path (starting with <tt>/</tt>) to the image file.<br>
If the image is split (either raw or EnCase), then enter '*' for the extension.
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"text\" name=\"img_path\" size=36 maxlength=256>
</td>
</tr>
<tr><td colspan=4> </td><tr>
<tr>
<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>
</tr>
<tr>
<td> </td>
<td align=left>
<input type=\"radio\" name=\"imgtype\" value="disk" CHECKED>
Disk
</td>
<td align=left>
<input type=\"radio\" name=\"imgtype\" value="volume">
Partition
</td>
<td align=left>
</td>
</tr>
<tr><td colspan=4> </td><tr>
<tr>
<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>
</tr>
<tr>
<td> </td>
<td align=left>
<input type=\"radio\" name=\"sort\" value=$IMG_ADD_SYM CHECKED>
Symlink
</td>
<td align=left>
<input type=\"radio\" name=\"sort\" value=$IMG_ADD_COPY>
Copy
</td>
<td align=left>
<input type=\"radio\" name=\"sort\" value=$IMG_ADD_MOVE>
Move
</td>
</tr>
<tr>
<td colspan=4> </td>
</tr>
</table>
<br>
<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<td align=center colspan=2>
<input type=\"image\" src=\"pict/menu_b_next.jpg\" alt=\"Next Step\" width=\"167\" height=20 border=0>
</td>
</tr>
</form>
EOF1
print "<tr><td colspan=2> </td></tr>\n"
. "<td align=center>\n"
. " <form action=\"$::PROGNAME\" method=\"get\">\n"
. " <input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. " <input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
.
Args::make_hidden()
. " <input type=\"image\" src=\"pict/menu_b_cancel.jpg\" "
. "alt=\"Cancel\" width=\"167\" height=20 border=0></form>\n"
. " </td>\n"
.
# HELP
" <td align=center>\n"
. " <a href=\"$::HELP_URL\" target=\"_blank\">\n"
. " <img src=\"pict/menu_b_help.jpg\" alt=\"Help\" "
. "width=\"167\" height=20 border=0></a>\n"
. " </td>\n"
. "</tr>\n"
. "</table>\n";
Print::print_html_footer();
return 0;
}
# List the images from the glob - called from img_add_prep if spl_conf is not set
sub img_add_split_conf {
my $img_path = Args::get_img_path_wild();
my $img_type = $Args::args{'imgtype'};
print "<center><br><br><b>Split Image Confirmation</b><br><br>\n";
my @spl_img = glob($img_path);
if (scalar(@spl_img) == 0) {
print "No images were found at this location ($img_path)<br>\n"
. "Use the back button and fix the path<br>\n";
return;
}
print <<EOF1;
The following images will be added to the case.<br>
If this is not the correct order, then you should change the naming convention.<br>
Press the Next button at the bottom of the page if this is correct.<br><br>
<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
<tr>
<td colspan=2> </td>
</tr>
EOF1
my $a = 0;
foreach $i (@spl_img) {
# We need to do this when we analyze the image, so do it here too to show
# what will be analyzed
$i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
print
"<tr><td align=\"center\">$a</td><td align=\"left\"><tt>$i</tt></td></tr>\n";
$a++;
}
my $vs = "";
$vs = "&vstype=$Args::args{'vstype'}"
if (exists $Args::args{'vstype'});
# Print the Ok Button
print "</table><br><br>\n"
. "<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" border=0>"
. "<tr><td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
. "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD_PREP&spl_conf=1&sort=$Args::args{'sort'}&"
. "img_path=$img_path&imgtype=$Args::args{'imgtype'}$vs\">"
. "<img src=\"pict/menu_b_next.jpg\" alt=\"Next\" "
. "width=\"167\" height=20 border=0></a></td>\n"
. "<td width=\"300\" align=\"center\"><a href=\"$::PROGNAME?${Args::baseargs_novol}&"
. "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD\">"
. "<img src=\"pict/menu_b_cancel.jpg\" alt=\"cancel\" width=\"167\" height=\"20\" border=\"0\">"
. "</a></td></tr></table>\n";
return 0;
}
# Run the autodetect stuff and get confirmation from the user
sub img_add_prep {
Args::check_img_path_wild();
Args::check_sort();
unless ((exists $Args::args{'imgtype'})
&& ($Args::args{'imgtype'} =~ /^\w+$/))
{
Print::print_check_err("Invalid image type");
}
Print::print_html_header("Collecting details on new image file");
my $img_path = Args::get_img_path_wild();
my $img_type = $Args::args{'imgtype'};
my $spl_conf = 0;
$spl_conf = 1
if ((exists $Args::args{'spl_conf'}) && ($Args::args{'spl_conf'} == 1));
# If we have a wildcard then it is a split image, so we verify it first and
# then make a string of the images so we can test it.
if ($img_path =~ /[\*\?]/) {
if ($spl_conf == 0) {
return img_add_split_conf();
}
else {
$img_tmp = "";
foreach my $i (glob($img_path)) {
if ($i =~ /^($::REG_IMG_PATH)$/) {
$img_tmp .= "\"$1\" ";
}
}
$img_path = $img_tmp;
}
}
else {
unless ((-f $img_path)
|| (-d $img_path)
|| (-l $img_path)
|| (-b $img_path)
|| (-c $img_path))
{
Print::print_err("Image file not found ($img_path)");
}
$img_path = "\"$img_path\"";
}
# Get the image type
local *OUT;
Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path");
my $itype = Exec::read_pipe_line(*OUT);
if (defined $itype) {
chomp $itype;
$itype = $1 if ($itype =~ /^(\w+)$/);
}
else {
print
"The image format type could not be determined for this image file<br>\n";
return;
}
close(OUT);
# The plan here is to collect the needed info and then we print it
my $conflict = 0;
my $cnt = 0;
$start[0] = "";
$end[0] = "";
$type[0] = "";
$desc[0] = "";
$active[0] = "";
my $vstype = "";
my $vstype_flag = "";
if ($img_type eq "disk") {
my $out;
if ( (exists $Args::args{'vstype'})
&& ($Args::args{'vstype'} =~ /^(\w+)$/))
{
$vstype = $Args::args{'vstype'};
$vstype_flag = "-t $vstype";
}
# Get the type
else {
Exec::exec_pipe(*OUT, "'$::TSKDIR/mmstat' -i $itype $img_path");
$vstype = Exec::read_pipe_line(*OUT);
close(OUT);
chomp $vstype if (defined $vstype);
if ( (!defined $vstype)
|| ($vstype =~ /^Error determining/)
|| ($vstype eq "")
|| (!exists $Vs::type{$vstype})
|| ($vstype !~ /^\w+$/))
{
print
"<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"
. "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"
. "<tr><td colspan=2> </td></tr>\n"
. "<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_PREP\">\n"
. "<input type=\"hidden\" name=\"spl_conf\" value=\"1\">\n"
. "<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">\n"
. "<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">\n"
. Args::make_hidden()
. "<tr><td>Disk Image <input type=\"radio\" name=\"imgtype\" value=\"disk\" CHECKED></td>\n"
. "<td>Volume Image<input type=\"radio\" name=\"imgtype\" value=\"volume\"></td></tr>\n"
. "<tr><td>Volume System Type (disk image only): <select name=\"vstype\">\n";
foreach my $vs (sort keys %Vs::type) {
print "<option value=\"$vs\"";
print " selected" if ($vs eq 'dos');
print ">${vs}</option>\n";
}
print "</select></td>"
. "<td> </td></tr>"
. "<tr><td colspan=2> </td></tr>"
. "</table><br><br>\n"
. "<input type=\"image\" src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"176\" height=20 border=0>"
. "</form>\n";
return;
}
$vstype = $1 if ($vstype =~ /^(\w+)$/);
$vstype_flag = "-t $vstype";
}
# Run 'mmls' on the image
Exec::exec_pipe(*OUT,
"'$::TSKDIR/mmls' -i $itype $vstype_flag -r $img_path");
# cycle through results and add each to table with file system type
my $part_type = "";
while ($_ = Exec::read_pipe_line(*OUT)) {
last if (/^Error determining partition/);
if (/^\d+:\s+[\d:]+\s+(\d+)\s+(\d+)\s+\d+\s+(\S.*)$/) {
$start[$cnt] = $1;
$end[$cnt] = $2;
$desc[$cnt] = $3;
$active[$cnt] = 1;
}
elsif ((/^DOS Partition/)
|| (/^BSD Disk/)
|| (/^Sun VTOC/)
|| (/^MAC Partition/)
|| (/^GUID Partition/))
{
$part_type = $_;
#print "<tr><td colspan=7> </td></tr>\n";
#print "<tr><td colspan=7>$_</td></tr>\n";
next;
}
elsif (/^Sector:/) {
#print "<tr><td colspan=7>$_</td></tr>\n";
next;
}
else {
next;
}
# Skip the BSD partition for the full disk
next
if ( ($part_type =~ /^BSD Disk/)
&& ($start[$cnt] == 0)
&& ($desc[$cnt] =~ /^Unused/));
# Skip if this is an extended DOS partition
next
if ( ($part_type =~ /^DOS Partition/)
&& ($desc[$cnt] =~ /Extended \(/));
# Get rid of the leading 0s
$start[$cnt] = $1
if ($start[$cnt] =~ /^0+([1-9]\d*)$/);
$end[$cnt] = $1
if ($end[$cnt] =~ /^0+([1-9]\d*)$/);
# Do we already have this partition?
my $i;
for ($i = 0; $i < $cnt; $i++) {
next if ($active[$i] == 0);
if ($start[$i] == $start[$cnt]) {
$conflict = 1;
if ($end[$i] == $end[$cnt]) {
last;
}
#The previous was the BSD partition - skip it */
if ( ($desc[$i] =~ /^FreeBSD \(0xA5\)/)
|| ($desc[$i] =~ /^OpenBSD \(0xA6\)/)
|| ($desc[$i] =~ /^NetBSD \(0xA9\)/))
{
$active[$i] = 0;
# if the current one is the BSD partition for
# the full partition/disk then skip it
if ($desc[$cnt] =~ /^Unused /) {
$active[$cnt] = 0;
}
}
}
# Do we start inside of another?
if (($start[$i] > $start[$cnt]) && ($end[$i] < $start[$cnt])) {
$conflict = 1;
}
# Do we end inside of another?
elsif (($start[$i] < $end[$cnt]) && ($end[$i] > $end[$cnt])) {
$conflict = 1;
}
}
if (($end[$i] == $end[$cnt]) && ($i != $cnt)) {
next;
}
local *OUT2;
my $out2;
# Run 'fstat -t' on the image
Exec::exec_pipe(*OUT2,
"'$::TSKDIR/fsstat' -o $start[$cnt] -i $itype -t $img_path");
$type[$cnt] = Exec::read_pipe_line(*OUT2);
close(OUT2);
if ( (!exists $type[$cnt])
|| (!defined $type[$cnt])
|| ($type[$cnt] =~ /^Cannot determine/)
|| ($type[$cnt] eq ""))
{
$type[$cnt] = "Unknown";
}
chomp $type[$cnt];
$cnt++;
}
close(OUT);
if ($conflict == 1) {
print
"<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"
. "<tr><td colspan=2> </td></tr>\n";
}
}
# If a volume, then run fsstat on it
elsif ($img_type eq "volume") {
# Run 'fstat -t' on the image
Exec::exec_pipe(*OUT, "'$::TSKDIR/fsstat' -t -i $itype $img_path");
$type[0] = Exec::read_pipe_line(*OUT);
close(OUT);
if ( (!defined $type[0])
|| ($type[0] =~ /^Cannot determine/)
|| ($type[0] eq ""))
{
$type[0] = "Unknown";
print
"<font color=\"$::DEL_COLOR[0]\">Warning:</font> The file system type of the volume image file could not be determined.<br>\n"
. "If this is a disk image file, return to the previous page and change the type.<br><br>\n";
}
chomp $type[0];
$start[0] = 0;
$end[0] = 0;
$active[0] = 1;
$desc[0] = $type[0];
$cnt++;
close(OUT);
}
else {
Print::print_err("Unknown image type: $img_type");
}
my $sname = $img_path;
$sname = "$::IMGDIR/" . "$1" if ($sname =~ /\/($::REG_FILE)\"$/);
# Now that we have the information about the partitions and disks, print the fields
print <<EOF1;
<form action=\"$::PROGNAME\" method=\"get\" target=\"_top\">
<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_ADD_DOIT\">
<input type=\"hidden\" name=\"img_path\" value=\"$Args::args{'img_path'}\">
<input type=\"hidden\" name=\"num_img\" value=\"$cnt\">
<input type=\"hidden\" name=\"sort\" value=\"$Args::enc_args{'sort'}\">
<center>
<h3>Image File Details</h3>
<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
<tr>
<td align=left colspan=4>
<b>Local Name: </b> $sname
</td>
</tr>
EOF1
# We do not currently offer integrity options for non-raw files
if (($itype eq "raw") || ($itype eq "split")) {
print <<EOF1b;
<tr>
<td align=left colspan=4>
<b>Data Integrity: </b> An MD5 hash can be used to verify the
integrity of the image. (With split images, this hash is for the full image file)
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"radio\" name=\"do_md5\" value=\"$MD5_NOTHING\" CHECKED>
<u>Ignore</u> the hash value for this image.
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"radio\" name=\"do_md5\" value=\"$MD5_CALC\">
<u>Calculate</u> the hash value for this image.
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"radio\" name=\"do_md5\" value=\"$MD5_ADD\">
<u>Add</u> the following MD5 hash value for this image:
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"text\" name=\"md5\" size=36 maxlength=32>
</td>
</tr>
<tr>
<td> </td>
<td align=left colspan=3>
<input type=\"checkbox\" name=\"ver_md5\" value=\"1\">
Verify hash after importing?
</td>
</tr>
EOF1b
}
else {
print
"<input type=\"hidden\" name=\"do_md5\" value=\"$MD5_NOTHING\">\n";
}
print <<EOF1c;
</table>
<h3>File System Details</h3>
<table width=\"600\" cellpadding=\"2\" cellspacing=\"0\" background=\"$::YEL_PIX\" border=0>
<tr>
<td colspan=2 align=left>Analysis of the image file shows the following partitions:</td>
</tr>
<tr>
<td colspan=2> </td>
</tr>
EOF1c
print Args::make_hidden();
print "<input type=\"hidden\" name=\"vstype\" value=\"$vstype\">\n"
if ($vstype ne "");
my $idx = 1;
my $ms_cnt = 0;
my @ms_name = ("C:", "D:", "E:", "F:", "G:", "H:", "I:", "J:");
for (my $i = 0; $i < $cnt; $i++) {
next if ($active[$i] == 0);
print
"<tr><td colspan=2><u>Partition $idx</u> (Type: $desc[$i])</td><tr>\n";
if ($cnt > 1) {
print "<tr><td colspan=2> Add to case? "
. "<input type=\"checkbox\" name=\"yes-${idx}\" value=1 CHECKED></td></tr>\n";
}
else {
print "<input type=\"hidden\" name=\"yes-${idx}\" value=1>\n";
}
unless (($start[$i] == 0) && ($end[$i] == 0)) {
print "<tr><td colspan=2> Sector Range: "
. "$start[$i] to $end[$i]"
. "</td></tr>\n";
}
print
"<input type=\"hidden\" name=\"start-${idx}\" value=\"$start[$i]\">"
. "<input type=\"hidden\" name=\"end-${idx}\" value=\"$end[$i]\">\n"
. "<tr><td> Mount Point: <input type=\"text\" name=\"mnt-${idx}\" size=\"6\"";
if (($type[$i] =~ /^ntfs/) || ($type[$i] =~ /^fat/)) {
print " value=\"$ms_name[$ms_cnt]\""
if ($ms_cnt < 8);
$ms_cnt++;
}
elsif (($type[$i] =~ /^raw/)
|| ($type[$i] =~ /^swap/))
{
print " value=\"N/A\"";
}
else {
print " value=\"/$idx/\"";
}
print "></td>\n"
. "<td>File System Type: <select name=\"ftype-${idx}\">\n";
foreach my $fs (@Fs::types) {
print "<option value=\"$fs\"";
print " selected" if ($fs eq $type[$i]);
print ">${fs}</option>\n";
}
# The following do not have 'metas' but should be in the list
print "<option value=\"\">======</option>\n";
if ($type[$i] eq "Unknown") {
print "<option value=\"raw\" selected>raw</option>\n";
}
else {
print "<option value=\"raw\">raw</option>\n";
}
print "<option value=\"swap\">swap</option>\n"
. "</select></td></tr>\n"
. "<tr><td colspan=2> </td></tr>\n";
$idx++;
}
print "</table>\n";
print <<EOF2;
<br><br>
<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\">
<tr>
<td align=center>
<input type=\"image\" src=\"pict/menu_b_add.jpg\"
alt=\"Add\" width=\"176\" height=20 border=0>
</td>
</form>
<td align=center>
<form action=\"$::PROGNAME\" method=\"get\">
EOF2
print Args::make_hidden();
print <<EOF3;
<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">
<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">
<input type=\"image\" src=\"pict/menu_b_cancel.jpg\"
alt=\"Cancel\" width=\"167\" height=20 border=0>
</form>
</td>
<td align=center><a href=\"$::HELP_URL\"
target=\"_blank\">
<img src=\"pict/menu_b_help.jpg\" alt=\"Help\"
width=\"167\" height=20 border=0></a>
</td>
</tr>
</table>
EOF3
if ($img_type eq "disk") {
print
"</center><p>For your reference, the <tt>mmls</tt> output was the following:<br>\n";
# Run 'mmls' on the image
Exec::exec_pipe(*OUT, "'$::TSKDIR/mmls' $vstype_flag -r $img_path");
# cycle through results and add each to table with file system type
while ($_ = Exec::read_pipe_line(*OUT)) {
print "<tt>$_</tt><br>\n";
}
}
Print::print_html_footer();
return 0;
}
# Add the image to the configuration by adding it to the host config file
# and the md5.txt file if that data was provided
sub img_add_doit {
Args::check_num_img();
Args::check_img_path_wild();
Args::check_sort();
Args::check_do_md5();
my $num_img = Args::get_num_img();
my $img_path = Args::get_img_path_wild();
my $import_type = Args::get_sort();
Print::print_html_header("Add a new image to an Autopsy Case");
my $err = 0;
my $add_num = 0;
$start[0] = 0;
$end[0] = 0;
$ftype[0] = "";
$mnt[0] = "";
# We need a string with all images in it for the hashes and file system testing
my $img_path_full;
if ($img_path =~ /[\*\?]/) {
$img_path_full = "";
foreach my $i (glob($img_path)) {
if ($i =~ /^($::REG_IMG_PATH)$/) {
$img_path_full .= "\"$1\" ";
}
}
}
else {
$img_path_full = "\"$img_path\"";
}
# Get the image type
local *OUT;
Exec::exec_pipe(*OUT, "'$::TSKDIR/img_stat' -t $img_path_full");
my $itype = Exec::read_pipe_line(*OUT);
if (defined $itype) {
chomp $itype;
$itype = $1 if ($itype =~ /^(\w+)$/);
}
else {
print
"The image format type could not be determined for this image file<br>\n";
return;
}
close(OUT);
# Check the hash of the image if that is the plan
my $do_md5 = Args::get_do_md5();
my $act_md5 = "";
unless ($do_md5 == $MD5_NOTHING) {
# Do we need to calculate an MD5?
if (
($do_md5 == $MD5_CALC)
|| ( ($do_md5 == $MD5_ADD)
&& (exists $Args::args{'ver_md5'})
&& ($Args::args{'ver_md5'} == 1))
)
{
print "<p>Calculating MD5 (this could take a while)<br>\n";
$act_md5 = Hash::calc_md5_split($img_path_full);
unless ($act_md5 =~ /^$::REG_MD5$/o) {
print "Error calculating MD5: $act_md5<br>\n";
return 1;
}
print "Current MD5: <tt>$act_md5</tt><br>\n";
}
# And md5 value was given so we can add it to the md5.txt file
if (($do_md5 == $MD5_ADD) && (exists $Args::args{'md5'})) {
my $md5 = $Args::args{'md5'};
unless ($md5 =~ /^$::REG_MD5$/o) {
if ($md5 eq "") {
print "MD5 value missing<br>\n";
}
else {
print "Invalid MD5 value (32 numbers or letters a-f)<br>\n";
}
print "<p><a href=\"$::PROGNAME?"
. "mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&"
. "$Args::baseargs\">"
. "<img src=\"pict/menu_b_back.jpg\" border=\"0\" "
. "width=\"167\" height=20 alt=\"Back\"></a>\n";
return 1;
}
$md5 =~ tr/[a-f]/[A-F]/;
# They also want us to validate the MD5
if ( (exists $Args::args{'ver_md5'})
&& ($Args::args{'ver_md5'} == 1))
{
if ($act_md5 eq $md5) {
print "Integrity Check Passed<br>\n";
Print::log_host_info("Integrity check passed on new image");
}
else {
print "<font color=\"$::DEL_COLOR[0]\">"
. "Integrity Check Failed<br></font><br>\n"
. "Provided: <tt>$md5</tt><br>\n"
. "Image not added to case<br>\n";
Print::log_host_info("Integrity check failed on new image");
return 1;
}
}
# set the act_md5 value to what was given and verified
$act_md5 = $md5;
}
# We will add the MD5 to the config file after we get its ID
}
# Proces the image arguments to make sure they are all there and test the
# file system type
print "Testing partitions<br>\n";
for (my $i = 0; $i <= $num_img; $i++) {
next
unless ((exists $Args::args{"yes-" . $i})
&& ($Args::args{"yes-" . $i} == 1));
if ( (exists $Args::args{"start-" . $i})
&& ($Args::args{"start-" . $i} =~ /^(\d+)$/))
{
$start[$add_num] = $1;
}
else {
print "Missing starting address for partition $i<br>\n";
$err = 1;
last;
}
if ( (exists $Args::args{"end-" . $i})
&& ($Args::args{"end-" . $i} =~ /^(\d+)$/))
{
$end[$add_num] = $1;
}
else {
print "Missing ending address for partition $i<br>\n";
$err = 1;
last;
}
if ( (exists $Args::args{"mnt-" . $i})
&& ($Args::args{"mnt-" . $i} =~ /^($::REG_MNT)$/))
{
$mnt[$add_num] = $1;
}
else {
print "Missing mount point for partition $i<br>\n";
$err = 1;
last;
}
if ( (exists $Args::args{"ftype-" . $i})
&& ($Args::args{"ftype-" . $i} =~ /^($::REG_FTYPE)$/))
{
$ftype[$add_num] = $1;
}
else {
print "Missing file system type for partition $i<br>\n";
$err = 1;
last;
}
# Test the File System
if (($ftype[$add_num] ne 'swap') && ($ftype[$add_num] ne 'raw')) {
local *OUT;
my $out;
# Run 'fsstat' and see if there is any output - else there was
# an error and the data went to STDERR
Exec::exec_pipe(*OUT,
"'$::TSKDIR/fsstat' -o $start[$add_num] -i $itype -f $ftype[$add_num] $img_path_full"
);
unless (read(OUT, $out, 1)) {
print
"<p>Partition $i is not a <tt>$ftype[$add_num]</tt> file system<br>\n";
$err = 1;
last;
}
close(OUT);
}
$add_num++;
}
# Go back if we got an error
if ($err == 1) {
print "Use the browser's back button to fix the data<br>\n";
return 1;
}
##################################################
# Copy the images and add them to the config file
if ($import_type == $IMG_ADD_SYM) {
Print::print_err("ERROR: /bin/ln missing")
unless (-x '/bin/ln');
print "Linking image(s) into evidence locker<br>\n";
}
elsif ($import_type == $IMG_ADD_COPY) {
Print::print_err("ERROR: /bin/cp missing")
unless (-x '/bin/cp');
print
"Copying image(s) into evidence locker (this could take a little while)<br>\n";
}
elsif ($import_type == $IMG_ADD_MOVE) {
Print::print_err("ERROR: /bin/mv missing")
unless (-x '/bin/mv');
print "Moving image(s) into evidence locker<br>\n";
}
else {
Print::print_err("Invalid Import Type: $import_type<br>\n");
}
my $imgid = "";
foreach my $i (glob($img_path)) {
# remove the tainting
$i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
# Deterine the local (target) name
my $img = "";
if ($i =~ /\/($::REG_FILE)$/) {
$img = "$::IMGDIR/$1";
}
else {
Print::print_err("Error Parsing Image Path ($i)<br>\n");
}
# Get the full path of the destination
my $img_dst = "$::host_dir" . "$img";
if ((-e "$img_dst") || (-l "$img_dst")) {
Print::print_err(
"An image by the same name already exists in the Host directory ($img)<br>\n"
. "Use the browser's back button to fix the name or delete the existing file."
);
}
my $orig_size = (stat("$i"))[7];
# Copy, Move, or link it
if ($import_type == $IMG_ADD_SYM) {
Print::log_host_info(
"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
}
elsif ($import_type == $IMG_ADD_COPY) {
Print::log_host_info(
"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/cp '$i' '$img_dst'");
}
elsif ($import_type == $IMG_ADD_MOVE) {
Print::log_host_info(
"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/mv '$i' '$img_dst'");
}
my $new_size = (stat("$img_dst"))[7];
if ($new_size != $orig_size) {
Print::print_err(
"Original image size ($orig_size) is not the same as the destination size ($new_size)"
);
}
# Add the disk and partition images to the config file
$imgid = Caseman::add_img_host_config("image", "$itype $img", $imgid);
}
print "Image file added with ID <tt>$imgid</tt><br>\n";
# AFM files have raw files that we also need to copy
# This approach is not the best, since it may copy more than
# is needed
if ($itype eq "afm") {
my $afm_base_path = "";
if ($img_path =~ /^(.*?)\.afm/i) {
$afm_base_path = $1;
$afm_base_path .= ".[0-9][0-9][0-9]";
}
else {
Print::print_err(
"Error parsing out base name of AFM file $img_path");
}
print "BASE: $afm_base_path<br>\n";
my $copied = 0;
foreach my $i (glob($afm_base_path)) {
$copied++;
# remove the tainting
$i = $1 if ($i =~ /^($::REG_IMG_PATH)$/);
# Deterine the local (target) name
my $img = "";
if ($i =~ /\/($::REG_FILE)$/) {
$img = "$::IMGDIR/$1";
}
else {
Print::print_err("Error Parsing Image Path ($i)<br>\n");
}
# Get the full path of the destination
my $img_dst = "$::host_dir" . "$img";
if ((-e "$img_dst") || (-l "$img_dst")) {
Print::print_err(
"An image by the same name already exists in the Host directory ($img) (AFM import)<br>\n"
. "Use the browser's back button to fix the name or delete the existing file."
);
}
my $orig_size = (stat("$i"))[7];
# Copy, Move, or link it
if ($import_type == $IMG_ADD_SYM) {
Print::log_host_info(
"Sym Linking image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/ln -s '$i' '$img_dst'");
}
elsif ($import_type == $IMG_ADD_COPY) {
Print::log_host_info(
"Copying image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/cp '$i' '$img_dst'");
}
elsif ($import_type == $IMG_ADD_MOVE) {
Print::log_host_info(
"Moving image $img_path into $Args::args{'case'}:$Args::args{'host'}"
);
Exec::exec_sys("/bin/mv '$i' '$img_dst'");
}
my $new_size = (stat("$img_dst"))[7];
if ($new_size != $orig_size) {
Print::print_err(
"Original image size ($orig_size) is not the same as the destination size ($new_size) after AFM import"
);
}
}
if ($copied == 0) {
Print::print_err(
"No AFM raw files were found with the same base name and a numeric extension"
);
}
else {
print "$copied AFM raw files imported<br>\n";
}
}
Caseman::update_md5("$imgid", "$act_md5")
unless (($do_md5 == $MD5_NOTHING) || ($imgid eq ""));
# Add a disk entry if the image is of a disk
unless (($add_num == 1) && ($end[0] == 0) && ($start[0] == 0)) {
unless ((exists $Args::args{'vstype'})
&& ($Args::args{'vstype'} =~ /^(\w+)$/))
{
Print::print_err("Missing Volume System Type");
}
my $vstype = $Args::args{'vstype'};
my $diskid = Caseman::add_vol_host_config("disk", "$imgid $vstype");
print "<p>Disk image (type $vstype) added with ID <tt>$diskid</tt>\n";
}
# Add the file system / partition entries
for (my $i = 0; $i < $add_num; $i++) {
my $volid =
Caseman::add_vol_host_config("part",
"$imgid $start[$i] $end[$i] $ftype[$i] $mnt[$i]");
print
"<p>Volume image ($start[$i] to $end[$i] - $ftype[$i] - $mnt[$i]) added with ID <tt>$volid</tt>\n";
}
print <<EOF;
<p>
<center>
<table width=600>
<tr>
<td width=300 align=center>
<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">
<img src=\"pict/menu_b_ok.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
</a>
</td>
<td width=300 align=center>
<a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&view=$Caseman::IMG_ADD&${Args::baseargs_novol}\">
<img src=\"pict/menu_b_inew.jpg\" alt=\"Ok\" width=\"167\" height=20 border=\"0\">
</a>
</td>
</tr>
</table>
</center>
EOF
Print::print_html_footer();
return 0;
}
# Display details of image based on config values
# provides links to remove the config of the image and to get the file
# system details
sub vol_details {
Print::print_html_header("Details of $Args::args{'vol'}");
Args::get_unitsize();
my $vol = Args::get_vol('vol');
my $mnt = $Caseman::vol2mnt{$vol};
my $ftype = $Caseman::vol2ftype{$vol};
print "<center>"
. "<img src=\"pict/menu_h_idet.jpg\" alt=\"Image Details\">"
. "<br><br><br>\n"
. "<table width=\"600\" cellspacing=\"0\" cellpadding=\"2\" "
. "background=\"$::YEL_PIX\" border=0>\n"
. " <tr><td colspan=\"2\"> </td></tr>\n"
.
# Name
" <tr><td align=\"right\" width=\"300\"><b>Name:</b></td>"
. "<td align=\"left\"><tt>$Caseman::vol2sname{$vol}</tt></td></tr>\n"
. "<tr><td align=\"right\" width=\"300\"><b>Volume Id:</b></td>"
. "<td align=\"left\"><tt>$vol</tt></td></tr>\n"
. "<tr><td align=\"right\" width=\"300\"><b>Parent Volume Id:</b></td>"
. "<td align=\"left\"><tt>$Caseman::vol2par{$vol}</tt></td></tr>\n"
. "<tr><td align=\"right\" width=\"300\"><b>Image File Format:</b></td>"
. "<td align=\"left\"><tt>$Caseman::vol2itype{$vol}</tt></td></tr>\n"
# Mount
. " <tr><td align=\"right\"><b>Mounting Point:</b></td>"
. "<td align=\"left\"><tt>$mnt</tt></td></tr>\n"
.
# Type
" <tr><td align=\"right\"><b>File System Type:</b></td>"
. "<td align=\"left\"><tt>$ftype</tt></td></tr>\n";
# Host Directory
print " <tr><td colspan=\"2\"> </td></tr>\n"
# Strings File
. " <tr><td colspan=2 align=\"center\"><b>External Files</b></td></tr>\n"
. " <tr><td align=\"right\"><b>ASCII Strings:</b></td>"
. "<td align=\"left\"><tt>"
. (
(exists $Caseman::vol2str{$vol})
? $Caseman::vol2sname{$Caseman::vol2str{$vol}}
: " "
)
. "</tt></td></tr>\n"
.
# Unicode Strings File
" <tr><td align=\"right\"><b>Unicode Strings:</b></td>"
. "<td align=\"left\"><tt>"
. (
(exists $Caseman::vol2uni{$vol})
? $Caseman::vol2sname{$Caseman::vol2uni{$vol}}
: " "
)
. "</tt></td></tr>\n";
if (($ftype ne "raw") && ($ftype ne "swap")) {
# dls file
print
" <tr><td align=\"right\"><b>Unallocated $Fs::addr_unit{$ftype}s:</b></td>"
. "<td align=\"left\"><tt>"
. (
(exists $Caseman::vol2dls{$vol})
? $Caseman::vol2sname{$Caseman::vol2dls{$vol}}
: " "
)
. "</tt></td></tr>\n";
# Strings of dls
print
" <tr><td align=\"right\"><b>ASCII Strings of Unallocated:</b></td>"
. "<td align=\"left\"><tt>"
. (
(
(exists $Caseman::vol2dls{$vol})
&& (exists $Caseman::vol2str{$Caseman::vol2dls{$vol}})
)
? $Caseman::vol2sname{$Caseman::vol2str{$Caseman::vol2dls{$vol}}}
: " "
)
. "</tt></td></tr>\n";
# Unicodde Strings of dls
print
" <tr><td align=\"right\"><b>Unicode Strings of Unallocated:</b></td>"
. "<td align=\"left\"><tt>"
. (
(
(exists $Caseman::vol2dls{$vol})
&& (exists $Caseman::vol2uni{$Caseman::vol2dls{$vol}})
)
? $Caseman::vol2sname{$Caseman::vol2uni{$Caseman::vol2dls{$vol}}}
: " "
)
. "</tt></td></tr>\n";
}
print " <tr><td colspan=\"2\"> </td></tr>\n"
. "</table>\n<a name=\"extract\"\n";
# Section for Strings file and 'dls' file
if (
(!(exists $Caseman::vol2str{$vol}))
|| (!(exists $Caseman::vol2uni{$vol}))
|| (!(exists $Caseman::vol2dls{$vol}))
|| (
(exists $Caseman::vol2dls{$vol})
&& ( (!(exists $Caseman::vol2str{$Caseman::vol2dls{$vol}}))
|| (!(exists $Caseman::vol2uni{$Caseman::vol2dls{$vol}})))
)
)
{
print "<hr><table width=600>\n<tr>";
}
# Strings File
if ( (!(exists $Caseman::vol2str{$vol}))
|| (!(exists $Caseman::vol2uni{$vol})))
{
print
"<td align=\"center\" width=280><h3>Extract Strings of<br>Entire Volume</h3>"
. "Extracting the ASCII and Unicode strings from a file system will "
. "make keyword searching faster.<br><br>\n"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "Generate MD5? "
. "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
. "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
. Args::make_hidden();
if (!(exists $Caseman::vol2str{$vol})) {
print
"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED> \n";
}
if (!(exists $Caseman::vol2uni{$vol})) {
print
" Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
}
print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
. "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n"
. "<td width=40> </td>\n";
}
if (($ftype eq 'dls') || ($ftype eq 'swap') || ($ftype eq 'raw')) {
# Place holder for types that have no notion of unallocated
}
# Unallocated Space File
elsif (!(exists $Caseman::vol2dls{$vol})) {
print
"<td align=\"center\" width=280><h3>Extract Unallocated $Fs::addr_unit{$ftype}s</h3>"
. "Extracting the unallocated data in a file system allows "
. "more focused keyword searches and data recovery.<br><br>\n"
. "(Note: This Does Not Include Slack Space)<br>\n"
. "<form action=\"$::PROGNAME\" method=\"get\">\n";
print "Generate MD5? "
. "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKEDLS\">\n"
.
"<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n"
. Args::make_hidden()
. "<input type=\"image\" src=\"pict/srch_b_un.jpg\" "
. "alt=\"Extract Unallocated Data\" border=\"0\">\n<br></form>\n";
}
# strings of 'dls'
elsif ((!(exists $Caseman::vol2str{$Caseman::vol2dls{$vol}}))
|| (!(exists $Caseman::vol2uni{$Caseman::vol2dls{$vol}})))
{
print
"<td align=\"center\" width=280><h3>Extract Strings of<br>Unallocated $Fs::addr_unit{$ftype}s</h3>"
. "Extracting the ASCII strings from the unallocated data will make "
. "keyword searching faster.<br><br>\n"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "Generate MD5? "
. "<input type=\"checkbox\" name=\"md5\" value=\"1\" CHECKED><br><br>"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_MAKESTR\">\n"
.
"<input type=\"hidden\" name=\"vol\" value=\"$Caseman::vol2dls{$vol}\">\n"
. "<input type=\"hidden\" name=\"fname_mode\" value=\"$FNAME_MODE_INIT\">\n"
. Args::make_hidden();
if (!(exists $Caseman::vol2str{$Caseman::vol2dls{$vol}})) {
print
"ASCII: <input type=\"checkbox\" name=\"str\" value=\"1\" CHECKED> \n";
}
if (!(exists $Caseman::vol2uni{$Caseman::vol2dls{$vol}})) {
print
" Unicode: <input type=\"checkbox\" name=\"uni\" value=\"1\" CHECKED>\n";
}
print "<br><br><input type=\"image\" src=\"pict/srch_b_str.jpg\" "
. "alt=\"Extract Strings\" border=\"0\">\n</form></td>\n";
}
if (
(!(exists $Caseman::vol2str{$vol}))
|| (!(exists $Caseman::vol2uni{$vol}))
|| (!(exists $Caseman::vol2dls{$vol}))
|| (
(exists $Caseman::vol2dls{$vol})
&& ( (!(exists $Caseman::vol2str{$Caseman::vol2dls{$vol}}))
|| (!(exists $Caseman::vol2uni{$Caseman::vol2dls{$vol}})))
)
)
{
print "</tr></table><hr>\n";
}
print "<p>"
. "<table width=\"400\" cellspacing=\"0\" cellpadding=\"2\">\n"
.
# Ok
"<tr><td align=center width=200>"
. "<form action=\"$::PROGNAME\" method=\"get\">\n"
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n"
. "<input type=\"hidden\" name=\"view\" value=\"$Caseman::VOL_OPEN\">\n"
. Args::make_hidden()
. "<input type=\"image\" src=\"pict/menu_b_close.jpg\" "
. "alt=\"Close\" width=\"167\" height=20 border=0></form></td>\n";
print "<td align=center width=200>";
if (($ftype ne "raw") && ($ftype ne "swap")) {
# File System Details
print "<form action=\"$::PROGNAME\" method=\"get\" target=\"_blank\">\n"
. Args::make_hidden()
. "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_FRAME\">\n"
. "<input type=\"hidden\" name=\"submod\" value=\"$::MOD_FS\">\n"
. "<input type=\"hidden\" name=\"vol\" value=\"$vol\">\n"
. "<input type=\"image\" src=\"pict/menu_b_fs.jpg\" "
. "width=167 height=20 "
. "alt=\"File System\" border=0></form></td>\n";
}
else {
print " </td>\n";
}
# Remove Image
# THis was removed 12/03 because it causes problems because the image still
# exists and config entries and ... it becomes a mess
# print
# "<td align=center width=200>".
# "<form action=\"$::PROGNAME\" method=\"get\">\n".
# "<input type=\"hidden\" name=\"mod\" value=\"$::MOD_CASEMAN\">\n".
# "<input type=\"hidden\" name=\"view\" value=\"$Caseman::IMG_DEL\">\n".
# Args::make_hidden().
# "<input type=\"hidden\" name=\"vol\" value=\"$Args::args{'vol'}\">\n".
# "<input type=\"hidden\" name=\"mnt\" value=\"$Args::args{'mnt'}\">\n".
# "<input type=\"image\" src=\"pict/menu_b_rem.jpg\" ".
# "width=167 height=20 alt=\"Remove\" border=0></form>".
# "</td>\n".
# "</tr></table>\n";
Print::print_html_footer();
return 0;
}
# remove the config files
sub img_del {
Args::check_vol('vol');
# Args::check_ftype();
Print::print_html_header(
"Removing Configuration Settings for $Args::args{'vol'}");
Caseman::del_host_config("", $Args::args{'vol'}, "");
Caseman::update_md5($Args::args{'vol'}, "");
print "Settings for <tt>$Args::args{'vol'}</tt> removed from "
. "<tt>$Args::args{'case'}:$Args::args{'host'}</tt>.\n"
. "<p>NOTE: The actual file still exists in the host directory.\n";
print "<p><a href=\"$::PROGNAME?mod=$::MOD_CASEMAN&"
. "view=$Caseman::VOL_OPEN&${Args::baseargs_novol}\">"
. "<img src=\"pict/but_ok.jpg\" alt=\"Ok\" "
. "width=\"43\" height=20 border=\"0\"></a>\n";
Print::print_html_footer();
return 0;
}
# Make a strings -t d file for the image to decrease the search time
# Can make both ASCII and Unicode strings files
sub vol_makestr {
Print::print_html_header("Extracting Strings");
my $ascii = 0;
my $uni = 0;
my $vol = Args::get_vol('vol');
my $ftype = $Caseman::vol2ftype{$vol};
my $img = $Caseman::vol2path{$vol};
my $offset = $Caseman::vol2start{$vol};
my $imgtype = $Caseman::vol2itype{$vol};
if ((exists $Args::args{'str'}) && ($Args::args{'str'} == 1)) {
if (exists $Caseman::vol2str{$vol}) {
Print::print_err(
"Image already has an ASCII strings file: $Caseman::vol2sname{$vol}"
);
}
$ascii = 1;
}
if ((exists $Args::args{'uni'}) && ($Args::args{'uni'} == 1)) {
if (exists $Caseman::vol2uni{$vol}) {
Print::print_err(
"Image already has a Unicode strings file: $Caseman::vol2sname{$vol}"
);
}
$uni = 1;
}
if (($uni == 0) && ($ascii == 0)) {
goto str_egress;
}
my $base_name = $Caseman::vol2sname{$vol};
if ($ascii == 1) {
my $fname_rel = "$::DATADIR/${base_name}-$ftype.asc";
my $fname = "$::host_dir" . "$fname_rel";
if (-e "$fname") {
my $i = 1;
$i++ while (-e "$::host_dir"
. "$::DATADIR/"
. "${base_name}-$ftype-$i.asc");
$fname_rel = "$::DATADIR/${base_name}-$ftype-$i.asc";
$fname = "$::host_dir" . "$fname_rel";
}
print
"Extracting ASCII strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
Print::log_host_inv(
"$Caseman::vol2sname{$vol}: Saving ASCII strings to $fname_rel");
local *OUT;
my $hit_cnt = 0;
$SIG{ALRM} = sub {
if (($hit_cnt++ % 5) == 0) {
print "+";
}
else {
print "-";
}
alarm(5);
};
alarm(5);
if ($ftype eq "dls") {
Exec::exec_pipe(*OUT,
"'$::TSKDIR/srch_strings' -a -t d $img > '$fname'");
}
elsif ((($ftype eq "raw") || ($ftype eq "swap"))
&& ($Caseman::vol2end{$vol} != 0))
{
Exec::exec_pipe(*OUT,
"'$::TSKDIR/dls' -e -f $ftype -i $imgtype $img "
. $Caseman::vol2start{$vol} . "-"
. $Caseman::vol2end{$vol}
. " | '$::TSKDIR/srch_strings' -a -t d > '$fname'");
}
else {
Exec::exec_pipe(*OUT,
"'$::TSKDIR/dls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d > '$fname'"
);
}
alarm(0);
$SIG{ALRM} = 'DEFAULT';
print $_ while ($_ = Exec::read_pipe_line(*OUT));
close(OUT);
print "<br>\n" if ($hit_cnt != 0);
# Verify that it worked
unless (open(STR, "$fname")) {
print( "Error opening $fname<br>\n"
. "Either an error occurred while generating the file or "
. "no ASCII strings exist<br>");
goto str_uni;
}
# append to config
my $strvol =
Caseman::add_vol_host_config("strings", "$vol $fname_rel");
print "Host configuration file updated<br>";
$Caseman::vol2ftype{$strvol} = "strings";
$Caseman::mod2vol{$strvol} = $vol;
$Caseman::vol2str{$vol} = $strvol;
$Caseman::vol2cat{$strvol} = "mod";
$Caseman::vol2itype{$strvol} = "raw";
$Caseman::vol2par{$strvol} = $vol;
$Caseman::vol2path{$strvol} = "$::host_dir" . "$fname_rel";
$Caseman::vol2start{$strvol} = 0;
$Caseman::vol2end{$strvol} = 0;
$Caseman::vol2sname{$strvol} = $fname_rel;
# Calculate MD5
if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
print "Calculating MD5 Value<br><br>\n";
my $m = Hash::int_create_wrap($strvol);
print "MD5 Value: <tt>$m</tt><br><br>\n";
}
}
str_uni:
if ($uni == 1) {
my $fname_rel = "$::DATADIR/${base_name}-$ftype.uni";
my $fname = "$::host_dir" . "$fname_rel";
if (-e "$fname") {
my $i = 1;
$i++ while (-e "$::host_dir"
. "$::DATADIR/"
. "${base_name}-$ftype-$i.uni");
$fname_rel = "$::DATADIR/${base_name}-$ftype-$i.uni";
$fname = "$::host_dir" . "$fname_rel";
}
print "<hr>\n" if ($ascii == 1);
print
"Extracting Unicode strings from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
Print::log_host_inv(
"$Caseman::vol2sname{$vol}: Saving Unicode strings to $fname_rel");
local *OUT;
my $hit_cnt = 0;
$SIG{ALRM} = sub {
if (($hit_cnt++ % 5) == 0) {
print "+";
}
else {
print "-";
}
alarm(5);
};
alarm(5);
if ($ftype eq "dls") {
Exec::exec_pipe(*OUT,
"'$::TSKDIR/srch_strings' -a -t d -e l $img > '$fname'");
}
elsif ((($ftype eq "raw") || ($ftype eq "swap"))
&& ($Caseman::vol2end{$vol} != 0))
{
Exec::exec_pipe(*OUT,
"'$::TSKDIR/dls' -e -f $ftype -i $imgtype $img "
. $Caseman::vol2start{$vol} . "-"
. $Caseman::vol2end{$vol}
. " | '$::TSKDIR/srch_strings' -a -t d -e l > '$fname'");
}
else {
Exec::exec_pipe(*OUT,
"'$::TSKDIR/dls' -e -f $ftype -o $offset -i $imgtype $img | '$::TSKDIR/srch_strings' -a -t d -e l > '$fname'"
);
}
alarm(0);
$SIG{ALRM} = 'DEFAULT';
print $_ while ($_ = Exec::read_pipe_line(*OUT));
close(OUT);
print "<br>\n" if ($hit_cnt != 0);
# Verify that it worked
unless (open(STR, "$fname")) {
print "Error opening $fname<br>\n"
. "Either an error occurred while generating the file or "
. "no Unicode strings exist";
goto str_egress;
}
# append to config
my $strvol =
Caseman::add_vol_host_config("unistrings", "$vol $fname_rel");
print "Host configuration file updated<br>";
$Caseman::vol2ftype{$strvol} = "strings";
$Caseman::mod2vol{$strvol} = $vol;
$Caseman::vol2uni{$vol} = $strvol;
$Caseman::vol2cat{$strvol} = "mod";
$Caseman::vol2itype{$strvol} = "raw";
$Caseman::vol2par{$strvol} = $vol;
$Caseman::vol2path{$strvol} = "$::host_dir" . "$fname_rel";
$Caseman::vol2start{$strvol} = 0;
$Caseman::vol2end{$strvol} = 0;
$Caseman::vol2sname{$strvol} = $fname_rel;
# Calculate MD5
if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
print "Calculating MD5 Value<br><br>\n";
$m = Hash::int_create_wrap($strvol);
print "MD5 Value: <tt>$m</tt><br><br>\n";
}
}
str_egress:
my $dest_vol = $vol;
# We need to return with a real image to VOL_DETAILS so check the mod
$dest_vol = $Caseman::mod2vol{$vol}
if (exists $Caseman::mod2vol{$vol});
print "<hr><a href=\"$::PROGNAME?$Args::baseargs_novol&mod=$::MOD_CASEMAN&"
. "view=$Caseman::VOL_DETAILS&vol=$dest_vol\" target=_top>Image Details</a><p>\n";
print
"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs\""
. " target=\"_top\">Keyword Search</a>\n";
Print::print_html_footer();
return 0;
}
sub vol_makedls {
Print::print_html_header("Extracting Unallocated Space");
my $vol = Args::get_vol('vol');
my $ftype = $Caseman::vol2ftype{$vol};
my $img = $Caseman::vol2path{$vol};
my $offset = $Caseman::vol2start{$vol};
my $imgtype = $Caseman::vol2itype{$vol};
my $base_name = $Caseman::vol2sname{$vol};
$base_name = $1 if ($base_name =~ /^(.*?)\.dd$/);
my $fname_rel = "$::DATADIR/${base_name}-$ftype.unalloc";
my $fname = "$::host_dir" . "$fname_rel";
if (-e "$::host_dir" . "$fname_rel") {
my $i = 1;
$i++ while (-e "$::host_dir"
. "$::DATADIR/"
. "${base_name}-$ftype-$i.unalloc");
$fname_rel = "$::DATADIR/${base_name}-$ftype-$i.unalloc";
$fname = "$::host_dir" . "$fname_rel";
}
Print::log_host_inv(
"$Args::args{'vol'}: Saving unallocated data to $fname_rel");
print
"Extracting unallocated data from <tt>$Caseman::vol2sname{$vol}</tt><br>\n";
local *OUT;
my $hit_cnt = 0;
$SIG{ALRM} = sub {
if (($hit_cnt++ % 5) == 0) {
print "+";
}
else {
print "-";
}
alarm(5);
};
alarm(5);
Exec::exec_pipe(*OUT,
"'$::TSKDIR/dls' -f $ftype -o $offset -i $imgtype $img > '$fname'");
alarm(0);
$SIG{ALRM} = 'DEFAULT';
print "$_" while ($_ = Exec::read_pipe_line(*OUT));
close(OUT);
print "<br>\n"
if ($hit_cnt != 0);
# append to config
my $dlsvol = Caseman::add_vol_host_config("dls", "$vol $fname_rel");
print "Host configuration file updated<br>";
$Caseman::vol2ftype{$dlsvol} = "dls";
$Caseman::mod2vol{$dlsvol} = $vol;
$Caseman::vol2dls{$vol} = $dlsrvol;
$Caseman::vol2cat{$dlsvol} = "mod";
$Caseman::vol2itype{$dlsvol} = "raw";
$Caseman::vol2par{$dlsvol} = $vol;
$Caseman::vol2path{$dlsvol} = "$::host_dir" . "$fname_rel";
$Caseman::vol2start{$dlsvol} = 0;
$Caseman::vol2end{$dlsvol} = 0;
$Caseman::vol2sname{$dlsvol} = $fname_rel;
# Calculate MD5
if ((exists $Args::args{'md5'}) && ($Args::args{'md5'} == 1)) {
print "Calculating MD5 Value<br>\n";
my $m = Hash::int_create_wrap($dlsvol);
print "MD5 Value: <tt>$m</tt><br><br>\n";
}
print "<a href=\"$::PROGNAME?$Args::baseargs&mod=$::MOD_CASEMAN&"
. "view=$Caseman::VOL_DETAILS\" target=_top>Image Details</a><p>\n";
print
"<a href=\"$::PROGNAME?mod=$::MOD_FRAME&submod=$::MOD_KWSRCH&$Args::baseargs_novol&"
. "vol=$fname_rel\" target=\"_top\">Keyword Search</a>\n";
Print::print_html_footer();
return 0;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1