Changeset 163
- Timestamp:
- 01/19/07 14:01:41 (2 years ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
honeyclient/branches/exp/mbriggs-db/lib/HoneyClient/Manager/DB.pm
r162 r163 9 9 ############################################################################## 10 10 # Package: HoneyClient::Manager::DB 11 # $LastChangedRevision: 183 5$11 # $LastChangedRevision: 1836 $ 12 12 # File: DB.pm 13 13 # Description: A module server that provides an interface to the Honeyclient DB 14 14 # Author: mbriggs 15 15 # 16 # CVS: $Id: DB.pm 183 5 2007-01-16 13:06:53Z mbriggs $16 # CVS: $Id: DB.pm 1836 2007-01-19 18:45:32Z mbriggs $ 17 17 # 18 18 # Copyright (C) 2006 The MITRE Corporation. All rights reserved. … … 73 73 use Relations::Query; 74 74 use Relations::Abstract; 75 use Data::Dumper; 75 76 76 77 # Traps signals, allowing END: blocks to perform cleanup. … … 129 130 name => 1, 130 131 new_val => 1, 131 old_val => 1,132 old_val => 0, 132 133 }, 133 134 datecreated => 0, 134 135 notes => 0, 135 136 }, 136 selectFunc => undef,137 selectFunc => \&_SelectRegKeys, 137 138 insertFunc => \&_InsertRegKey, 138 139 }, … … 160 161 # Returns ID of Inserted File 161 162 163 sub _quote { 164 my ($self,$ref) = @_; 165 if (!ref $ref) { 166 return $self->{dbh}->quote($ref); 167 } 168 elsif (ref $ref eq 'HASH') { 169 my %hash = %$ref; 170 foreach (keys %hash) { 171 $hash{$_} = $self->_quote($hash{$_}); 172 } 173 return \%hash; 174 } 175 elsif (ref $ref eq 'ARRAY') { 176 my @arr = @$ref; 177 foreach (@arr) { 178 $_ = $self->_quote($_); 179 } 180 } 181 elsif (ref $ref eq 'SCALAR') { $ref = $self->_quote($$ref);} 182 else {Carp::croak(__PACKAGE__."->_quote was passed an illegal reference type: ".ref $ref);} 183 } 184 162 185 sub _InsertFile { 163 186 my ($self,$h_file,$serial) = @_; 164 my ($contentid,$rc );187 my ($contentid,$rc,%file); 165 188 eval { 166 189 167 190 if (!$self->_VerifyHash($h_file,$tables{Files}{fields},1)) {return;} 168 my %fileContent = map { $_ => $self->{dbh}->quote($h_file->{content}->{$_}) } ('md5','sha1','type','size'); 191 %file = %{$self->_quote($h_file)}; 192 %fileContent = %{ delete $file{content} }; 169 193 170 194 my $abstract = new Relations::Abstract($self->{dbh}); … … 178 202 # If content found, record instance only and link to file content 179 203 if (defined($row) && $row > 0) { 180 $contentid= $row->{id};204 $file{contentid} = $row->{id}; 181 205 } 182 206 else { 183 $ contentid= $abstract->insert_id(207 $file{contentid} = $abstract->insert_id( 184 208 -id => 'id', 185 209 -table => 'FileContent', 186 210 -set => \%fileContent); 187 211 } 188 my %file = map { $_ => $self->{dbh}->quote($h_file->{$_}) } ('path','name','datecreated');#,'subsecs'); 189 $file{contentid} = $self->{dbh}->quote($contentid); $file{serial} = $self->{dbh}->quote($serial); 190 212 $file{serial} = $self->_quote($serial); 191 213 $rc = $abstract->insert_id( 192 214 -id => 'id', … … 211 233 my $abstract = new Relations::Abstract($self->{dbh}); 212 234 213 my %proc = map { $_ => $self->{dbh}->quote($h_proc->{$_}) } (keys %$h_proc);214 $proc{serial} = $se rial;235 my %proc = %{$self->_quote($h_proc)}; 236 $proc{serial} = $self->_quote($serial); 215 237 216 238 $rc = $abstract->insert_id( … … 236 258 my $abstract = new Relations::Abstract($self->{dbh}); 237 259 238 my %regkey = map { $_ => $self->{dbh}->quote($h_regkey->{$_}) } ('key_name','status','datecreated','notes');239 $regkey{serial} = $se rial;240 260 my %regkey = %{$self->_quote($h_regkey)}; 261 $regkey{serial} = $self->_quote($serial); 262 my @entries = @{delete $regkey{entries}} if (exists $h_regkey->{entries}); 241 263 $id = $abstract->insert_id( 242 264 -id => 'id', … … 244 266 -set => \%regkey 245 267 ); 246 foreach my $entry (@ {$h_regkey->{entries}}) {247 my %entry = map { $_ => $self->{dbh}->quote($entry->{$_}) } (keys %$entry);268 foreach my $entry (@entries) { 269 $entry{rkid} = $id; 248 270 $abstract->insert_id( 249 271 -id => 'id', 250 -table => 'R egKeyEntries',272 -table => 'RKEntries', 251 273 -set => \%entry 252 274 ) or Carp::croak __PACKAGE__."->_InsertRegKey Failed: Insert returned a NULL ID"; … … 293 315 my %fields = %$h_fields; 294 316 my $key; 295 296 foreach $key (keys %$hash) { 297 if (ref $key && ref $fields{$key}) { 298 $self->_VerifyHash($hash{$key},$h_fields{$key},$required); 299 } 317 318 foreach $key (keys %{$hash}) { 319 if (ref $fields{$key}) { 320 my $rc = 0; 321 if (ref $hash->{$key} eq 'HASH') { 322 eval {$self->_VerifyHash($hash->{$key},$h_fields->{$key},$required)}; 323 if ($@) { 324 Carp::croak($@); 325 } 326 } 327 if (ref $hash->{$key} eq 'ARRAY') { 328 foreach (@{$hash->{$key}}) { 329 eval {$self->_VerifyHash($_,$h_fields->{$key},$required)}; 330 if ($@) { 331 Carp::croak($@); 332 } 333 } 334 } 335 } 300 336 elsif (exists $fields{$key}) { 301 337 delete $fields{$key}; 302 338 } 303 339 else { 304 Carp::croak("Invalid Record. $key is not a member of the Table ");340 Carp::croak("Invalid Record. $key is not a member of the Table\n"); 305 341 } 306 342 } … … 376 412 while ($dbname = $sth->fetchrow_array()) { 377 413 if ($dbname eq 'HoneyClient') { 378 print "It thinks DB exists!\n";#TODO: Delete Debug statement379 414 return 1; 380 415 } … … 435 470 "); # or die "Failed Creating RegKeys Table"; not necessary because of RaiseError?? 436 471 $abstract->run_query(" 437 CREATE TABLE R egKeyEntries472 CREATE TABLE RKEntries 438 473 ( 439 474 id INT UNSIGNED AUTO_INCREMENT, 440 r egkeyid INT UNSIGNED NOT NULL,475 rkid INT UNSIGNED NOT NULL, 441 476 name VARCHAR(255) NOT NULL, 442 477 new_val VARCHAR(255) NOT NULL, 443 old_val VARCHAR(255) NOT NULL,478 old_val VARCHAR(255), 444 479 PRIMARY KEY (id) 445 480 ) ENGINE=InnoDB … … 680 715 681 716 eval { 682 my $fingerprint = {vmid => $self-> {dbh}->quote($fpData->{vmid})};717 my $fingerprint = {vmid => $self->_quote($fpData->{vmid})}; 683 718 $fingerprint->{numfiles} = ref $fpData->{Files} eq 'ARRAY' ? scalar(@{$fpData->{Files}}) : 0; 684 719 $fingerprint->{numregkeys} = ref $fpData->{RegKeys} eq 'ARRAY' ? scalar(@{$fpData->{RegKeys}}) : 0; … … 812 847 my ($i,$rows,$r,$serial); 813 848 for ($i = 0; $i < $numfiles; $i++) { 814 815 }816 849 $rows = $self->Select({ 817 850 table => 'Files', 818 where => {'md5'=>$h_sigData->{Files}->[$i]->{md5},'sha1'=>$h_sigData->{Files}->[$i]->{sha1}} 851 where => { 852 'content' => { 853 'md5' => $h_sigData->{Files}->[$i]->{content}->{md5}, 854 'sha1' => $h_sigData->{Files}->[$i]->{content}->{sha1}, 855 } 856 } 819 857 }); 820 while ($r = shift(@$rows)) { 821 $serial = delete $r->{serial}; 822 $fileMatches{$serial}{$i} = $r; 823 } 858 foreach (@$rows) { 859 $serial = $_->{serial}; 860 $serial = delete $_->{serial}; 861 $fileMatches->{$serial}->{$i} = $_; 862 } 863 } 824 864 for ($i = 0; $i < $numregkeys; $i++) { 825 865 $rows = $self->Select({ 826 866 table => 'RegKeys', 827 where => {'`key`' => $h_sigData->{RegKeys}->[$i]->{key}, 828 'name' => $h_sigData->{RegKeys}->[$i]->{name}, 829 'value' => $h_sigData->{RegKeys}->[$i]->{value}, 867 where => {'key_name' => $h_sigData->{RegKeys}->[$i]->{key}, 868 'entries' => $h_sigData->{RegKeys}->[$i]->{entries}, 830 869 } 831 870 }); … … 901 940 902 941 sub Select { 903 my ($self,$h_query) = @_; 942 my ($self,$h_query) = @_; 904 943 if (!exists $tables{$h_query->{table}}){ 905 944 Carp::carp("Attempted query on non-existent table: $h_query->{table}"); 906 945 return; 907 946 } 908 if ( !$self->_VerifyHash($h_query->{where}, $tables{$h_query->{table}}{fields},0) ){ 909 my @f = keys %{$h_query->{where}}; 910 Carp::carp("Query contains invalid fields: @f"); 911 return; 912 } 913 map {$h_query->{where}->{$_} = $self->{dbh}->quote($h_query->{where}->{$_})} (keys %{$h_query->{where}}); 914 if ($tables{$h_query->{table}}{selectFunc}) { 915 return &{$tables{$h_query->{table}}{selectFunc}}($self,$h_query); 947 if (!$self->_VerifyHash($h_query->{where}, $tables{$h_query->{table}}{fields},0) ) { 948 my $f = join ',',(keys %{$h_query->{where}});#TODO: Error Handling 949 Carp::carp("Query contains invalid fields $f"); 950 return; 951 } 952 if ($tables{ $h_query->{table} }{selectFunc}) { 953 return &{ $tables{$h_query->{table}}{selectFunc} }($self,$h_query); 916 954 } 917 955 else { 918 956 my $query = new Relations::Query( 919 -select => '*', 920 -from => $h_query->{table}, 921 -where => $h_query->{where}, 922 -order_by => $h_query->{order_by}, 923 -limit => $h_query->{limit} 957 -select => '*', 958 -from => $h_query->{table} 924 959 ); 960 foreach ('order_by','limit') { 961 $query->set("-$_" => $h_query->{$_}) if (defined $h_query->{$_}); 962 } 963 if ( defined $h_query->{where} ) { 964 my %where = %{$self->_quote($h_query->{where})}; 965 $query->set(-where => \%where); 966 } 925 967 return $self->{dbh}->selectall_arrayref($query->get(),{ Slice => {} }); 926 968 } … … 933 975 sub _SelectFiles { 934 976 my ($self,$q) = @_; 935 $q->{'select'} = [ 'Files.id','Files.contentid','Files.serial','Files.name', 936 'Files.path','Files.datecreated','Files.notes','FileContent.md5','FileContent.sha1', 937 'FileContent.size','FileContent.type' 977 my (%where,%content); 978 my $select = [ 'Files.id','Files.contentid','Files.serial','Files.name', 979 'Files.path','Files.datecreated','FileContent.md5','FileContent.sha1', 980 'FileContent.size','FileContent.type','FileContent.notes' 938 981 ]; 939 #map {$q->{where}->{$_} = $self->{dbh}->quote($q->{where}->{$_})} (keys %{$q->{where}});940 982 my $query = new Relations::Query( 941 -select => $ q->{'select'},983 -select => $select, 942 984 -from => 'Files JOIN FileContent on Files.contentid=FileContent.id', 943 985 ); 944 foreach my $property ('where','order_by','limit') { 945 $query->add("-$property" => $q->{$property}) if( $q->{$property} ); 986 if (exists $q->{where}) { 987 %where = %{$self->_quote($q->{where})}; 988 %content = %{delete $where{content}} if (exists $where{content}); 989 $query->set(-where => \%where) if (keys %where); 990 $query->add(-where => \%content) if (keys %content); 991 } 992 foreach ('order_by','limit') { 993 $query->set("-$_" => $q->{$_}) if( $q->{$_} ); 946 994 } 947 995 my $sth = $self->{dbh}->prepare($query->get()); 948 996 $sth->execute(); 949 997 950 my $file = {}; my @files; 951 map {$file->{$_}=undef} ('id','contentid','serial','name','path','datecreated','notes'); 952 map {$file->{content}->{$_}=undef} ('md5','sha1','size','type'); 953 $sth->bind_columns(\$file->{id},\$file->{contentid},\$file->{serial},\$file->{name}, 954 \$file->{path},\$file->{datecreated},\$file->{notes},\$file->{content}->{md5},\$file->{content}->{sha1}, 955 \$file->{content}->{size},\$file->{content}->{type} 956 ); 998 my %file; my @files; 999 map {$file{$_}=''} ('id','contentid','serial','name','path','datecreated'); 1000 map {$file{content}{$_}=undef} ('md5','sha1','size','type','notes'); 1001 eval { 1002 $sth->bind_columns( 1003 \($file{id},$file{contentid},$file{serial},$file{name},$file{path},$file{datecreated},$file{content}{md5}, 1004 $file{content}{sha1},$file{content}{size},$file{content}{type},$file{content}{notes}) 1005 ); 1006 }; 1007 if ($@) { 1008 Carp::croak($@); 1009 } 1010 957 1011 while ($sth->fetch) { 958 push @files, $file; 959 } 1012 my %tempf = %file; 1013 my %tempc = %{$file{content}}; 1014 $tempf{content} = \%tempc; 1015 push @files, \%tempf; 1016 } 960 1017 return \@files; 961 1018 } … … 968 1025 #TODO: _SelectRegKeys function 969 1026 my ($self,$q) = @_; 970 971 my ($rowR,$rowE,@regkeys,%ids); 972 %$rowR = map {$_,undef}, ('id','serial','key_name','status','datecreated','notes'); 973 %$rowE = map {$_,undef}, ('name','new_val','old_val','rkid'); 974 975 my $query = new Relations::Query(); my $entries; 976 if ($entries = delete exists $q->{where}->{entries}) { 977 $query->set( 978 -select => "RegKeys.*,RKEntries.name,RKEntries.new_val,RKEntries.old_val,RKEntries.rkid", 979 -from => "RegKeys JOIN RKEntries ON RegKeys.id=RKEntries.rkid" 980 ); 981 foreach my $entry (@{$entries}) { 982 $query->set(-where => $q->{where}); 983 $query->add(-where => $entry); 984 my $sth = $self->{dbh}->prepare($query->get()); 985 $sth->execute(); 986 $sth->bind_columns(\$rowR->{id},\$rowR->{serial},\$rowR->{key_name},\$rowR->{status}, 987 \$rowR->{datecreated},\$rowR->{notes},\$rowE->{name},\$rowE->{new_val}, 988 \$rowE->{old_val},\$rowE->{rkid}); 989 $sth->fetch(); 990 if(exists $ids{$rowR->{id}) { 991 push @($regkeys[$rowR->{id}]->{entries}),$rowE; 1027 my (@regkeys,%ids,%entries); 1028 my %rowR = map {$_,undef} ('id','serial','key_name','status','datecreated','notes'); 1029 my %rowE = map {$_,undef} ('name','new_val','old_val','rkid'); 1030 my $query = new Relations::Query(); 1031 if ($q->{where}) { 1032 my %where = %{$self->_quote(delete $q->{where})}; 1033 if (%entries = %{delete $where{entries}}) { 1034 $query->set( 1035 -select => "RegKeys.*,RKEntries.name,RKEntries.new_val,RKEntries.old_val,RKEntries.rkid", 1036 -from => "RegKeys JOIN RKEntries ON RegKeys.id=RKEntries.rkid" 1037 ); 1038 foreach my $entry (@{$entries}) { 1039 $query->set(-where => \%where) if (keys %where); 1040 $query->add(-where => \%$entry); 1041 my $sth = $self->{dbh}->prepare($query->get()); 1042 $sth->execute(); 1043 $sth->bind_columns(\$rowR{id},\$rowR{serial},\$rowR{key_name},\$rowR{status}, 1044 \$rowR{datecreated},\$rowR{notes},\$rowE{name},\$rowE{new_val}, 1045 \$rowE{old_val},\$rowE{rkid}); 1046 while($sth->fetch()) { 1047 if(exists $ids{$rowR{id}}) { 1048 push @{$regkeys[$rowR{id}]->{entries}},\%rowE; 1049 } 1050 else { 1051 push @regkeys, \%rowR; 1052 $ids{$rowR{id}} = $#regkeys; 1053 push @{$regkeys[$rowR{id}]->{entries}},\%rowE; 1054 } 1055 } 992 1056 } 993 else { 994 push $regkeys, $rowR; 995 $ids{$rowR->{id}} = $#regkeys; 996 push @{$regkeys[$#regkeys]->{entries}},$rowE; 1057 } 1058 else { 1059 $query->set( 1060 -select => "*", 1061 -from => "RegKeys", 1062 -where => $q->{where} 1063 ); 1064 @regkeys = @{$self->{dbh}->selectall_arrayref($query->get(),{ Slice => {} })}; 1065 foreach my $row (@regkeys) { 1066 my $subquery = new Relations::Query( 1067 -select => ['name','new_val','old_val'], 1068 -from => 'RKEntries', 1069 -where => {rkid => $row->{id}} 1070 ); 1071 $rowE = $self->{dbh}->selectall_arrayref($query->get(),{ Slice => {} }); 1072 if(scalar @{$rowE}) { $row->{entries} = $rowE; } 997 1073 } 998 }999 }1000 else {1001 $query->set(1002 -select => "*",1003 -from => "RegKeys",1004 -where => $q->{where}1005 );1006 @regkeys = @{$self->{dbh}->selectall_arrayref($query->get(),{ Slice => {} })};1007 foreach my $row (@regkeys) {1008 my $subquery = new Relations::Query(1009 -select => ['name','new_val','old_val'],1010 -from => 'RKEntries',1011 -where => {rkid => $row->{id}}1012 );1013 $rowE = $self->{dbh}->selectall_arrayref($query->get(),{ Slice => {} });1014 if(scalar @{$rowE}) { $row->{entries} = $rowE; }1015 1074 } 1016 1075 } … … 1023 1082 sub _SelectFingerprint { 1024 1083 my ($self,$q) = @_; 1025 map {$q->{where}->{$_} = $self->{dbh}->quote($q->{where}->{$_})} (keys %{$q->{where}});1026 1084 my $query = new Relations::Query( 1027 1085 -select => '*', 1028 1086 -from => 'Fingerprints', 1029 -where => $q->where,1030 1087 -limit => 1 1031 1088 ); 1089 if (exists $q->{where} ) { 1090 my %where = %{$self->_quote($q->{where})}; 1091 $query->set(-where => \%where); 1092 } 1032 1093 my $fingerprint = $self->{dbh}->selectrow_hashref($query->get()) or return undef; 1033 1094 # Get Files
