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