1 package siTriggered;
2 use Exporter;
3 @ISA = qw(Exporter);
4 my @events = (
5 "got_ping",
6 "detected_hardware",
7 "trigger_wake",
8 "reload_ldap_config",
9 );
10 @EXPORT = @events;
12 use strict;
13 use warnings;
14 use GOSA::GosaSupportDaemon;
15 use Socket;
18 BEGIN {}
20 END {}
22 ### Start ######################################################################
24 my $ldap_uri;
25 my $ldap_base;
26 my $ldap_admin_dn;
27 my $ldap_admin_password;
28 my $mesg;
30 my %cfg_defaults = (
31 "server" => {
32 "ldap-uri" => [\$ldap_uri, ""],
33 "ldap-base" => [\$ldap_base, ""],
34 "ldap-admin-dn" => [\$ldap_admin_dn, ""],
35 "ldap-admin-password" => [\$ldap_admin_password, ""],
36 },
37 );
38 &read_configfile($main::cfg_file, %cfg_defaults);
41 sub get_events {
42 return \@events;
43 }
46 sub read_configfile {
47 my ($cfg_file, %cfg_defaults) = @_;
48 my $cfg;
50 if( defined( $cfg_file) && ( (-s $cfg_file) > 0 )) {
51 if( -r $cfg_file ) {
52 $cfg = Config::IniFiles->new( -file => $cfg_file );
53 } else {
54 &main::daemon_log("ERROR: siTriggered.pm couldn't read config file!", 1);
55 }
56 } else {
57 $cfg = Config::IniFiles->new() ;
58 }
59 foreach my $section (keys %cfg_defaults) {
60 foreach my $param (keys %{$cfg_defaults{ $section }}) {
61 my $pinfo = $cfg_defaults{ $section }{ $param };
62 ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
63 }
64 }
65 }
68 sub reload_ldap_config {
69 my ($msg, $msg_hash, $session_id) = @_;
70 my $header = @{$msg_hash->{header}}[0];
71 my $target = @{$msg_hash->{$header}}[0];
73 my $out_msg = &ClientPackages::new_ldap_config($target, $session_id);
74 my @out_msg_l = ( $out_msg );
75 return @out_msg_l;
76 }
79 sub got_ping {
80 my ($msg, $msg_hash, $session_id) = @_;
82 my $source = @{$msg_hash->{source}}[0];
83 my $target = @{$msg_hash->{target}}[0];
84 my $header = @{$msg_hash->{header}}[0];
85 my $act_time = &get_time;
86 my @out_msg_l;
87 my $out_msg;
89 $session_id = @{$msg_hash->{'session_id'}}[0];
91 # check known_clients_db
92 my $sql_statement = "SELECT * FROM known_clients WHERE hostname='$source'";
93 my $query_res = $main::known_clients_db->select_dbentry( $sql_statement );
94 if( 1 == keys %{$query_res} ) {
95 my $sql_statement= "UPDATE known_clients ".
96 "SET status='$header', timestamp='$act_time' ".
97 "WHERE hostname='$source'";
98 my $res = $main::known_clients_db->update_dbentry( $sql_statement );
99 }
101 # check known_server_db
102 $sql_statement = "SELECT * FROM known_server WHERE hostname='$source'";
103 $query_res = $main::known_server_db->select_dbentry( $sql_statement );
104 if( 1 == keys %{$query_res} ) {
105 my $sql_statement= "UPDATE known_server ".
106 "SET status='$header', timestamp='$act_time' ".
107 "WHERE hostname='$source'";
108 my $res = $main::known_server_db->update_dbentry( $sql_statement );
109 }
111 # create out_msg
112 my $out_hash = &create_xml_hash($header, $source, "GOSA");
113 &add_content2xml_hash($out_hash, "session_id", $session_id);
114 $out_msg = &create_xml_string($out_hash);
115 my $forward_to_gosa = @{$msg_hash->{'forward_to_gosa'}}[0];
116 if (defined $forward_to_gosa) {
117 $out_msg =~s/<\/xml>/<forward_to_gosa>$forward_to_gosa<\/forward_to_gosa><\/xml>/;
118 }
119 push(@out_msg_l, $out_msg);
121 return @out_msg_l;
122 }
125 sub detected_hardware {
126 my ($msg, $msg_hash, $session_id) = @_ ;
127 my $address = $msg_hash->{source}[0];
128 my $gotoHardwareChecksum= $msg_hash->{detected_hardware}[0]->{gotoHardwareChecksum};
130 my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
131 my $res = $main::known_clients_db->select_dbentry( $sql_statement );
133 # check hit
134 my $hit_counter = keys %{$res};
135 if( not $hit_counter == 1 ) {
136 &main::daemon_log("$session_id ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
137 return;
138 }
140 my $macaddress = $res->{1}->{macaddress};
141 my $hostkey = $res->{1}->{hostkey};
143 if (not defined $macaddress) {
144 &main::daemon_log("$session_id ERROR: no mac address found for client $address", 1);
145 return;
146 }
147 # Build LDAP connection
148 my $ldap_handle = &main::get_ldap_handle($session_id);
149 if( not defined $ldap_handle ) {
150 &main::daemon_log("$session_id ERROR: cannot connect to ldap: $ldap_uri", 1);
151 return;
152 }
154 # Perform search
155 $mesg = $ldap_handle->search(
156 base => $ldap_base,
157 scope => 'sub',
158 filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
159 );
161 # We need to create a base entry first (if not done from ArpHandler)
162 if($mesg->count == 0) {
163 &main::daemon_log("INFO: Need to create a new LDAP Entry for client $address", 4);
164 my $ipaddress= $1 if $address =~ /^([0-9\.]*?):.*$/;
165 my $dnsname;
166 if (defined($msg_hash->{'force-hostname'}) &&
167 defined($msg_hash->{'force-hostname'}[0]) &&
168 length($msg_hash->{'force-hostname'}[0]) > 0){
169 $dnsname= $msg_hash->{'force-hostname'}[0];
170 &main::daemon_log("INFO: Using forced hostname $dnsname for client $address", 4);
171 } else {
172 $dnsname= gethostbyaddr(inet_aton($ipaddress), AF_INET) || $ipaddress;
173 }
175 my $cn = (($dnsname =~ /^(\d){1,3}\.(\d){1,3}\.(\d){1,3}\.(\d){1,3}/) ? $dnsname : sprintf "%s", $dnsname =~ /([^\.]+)\.?/);
176 my $dn = "cn=$cn,ou=incoming,$ldap_base";
177 &main::daemon_log("INFO: Creating entry for $dn",5);
178 my $entry= Net::LDAP::Entry->new( $dn );
179 $entry->dn($dn);
180 $entry->add("objectClass" => "goHard");
181 $entry->add("cn" => $cn);
182 $entry->add("macAddress" => $macaddress);
183 $entry->add("gotomode" => "locked");
184 $entry->add("gotoSysStatus" => "new-system");
185 $entry->add("ipHostNumber" => $ipaddress);
186 if(defined($main::gosa_unit_tag) && length($main::gosa_unit_tag) > 0) {
187 $entry->add("objectClass" => "gosaAdministrativeUnitTag");
188 $entry->add("gosaUnitTag" => $main::gosa_unit_tag);
189 }
190 my $res=$entry->update($ldap_handle);
191 if(defined($res->{'errorMessage'}) &&
192 length($res->{'errorMessage'}) >0) {
193 &main::daemon_log("ERROR: can not add entries to LDAP: ".$res->{'errorMessage'}, 1);
194 return;
195 } else {
196 # Fill $mesg again
197 $mesg = $ldap_handle->search(
198 base => $ldap_base,
199 scope => 'sub',
200 filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
201 );
202 }
203 }
205 if($mesg->count == 1) {
206 my $entry= $mesg->entry(0);
207 $entry->changetype("modify");
208 foreach my $attribute (
209 "gotoSndModule", "ghNetNic", "gotoXResolution", "ghSoundAdapter", "ghCpuType", "gotoXkbModel",
210 "ghGfxAdapter", "gotoXMousePort", "ghMemSize", "gotoXMouseType", "ghUsbSupport", "gotoXHsync",
211 "gotoXDriver", "gotoXVsync", "gotoXMonitor", "gotoHardwareChecksum") {
212 if(defined($msg_hash->{detected_hardware}[0]->{$attribute}) &&
213 length($msg_hash->{detected_hardware}[0]->{$attribute}) >0 ) {
214 if(defined($entry->get_value($attribute))) {
215 $entry->delete($attribute => []);
216 }
217 &main::daemon_log("INFO: Adding attribute $attribute with value ".$msg_hash->{detected_hardware}[0]->{$attribute},5);
218 $entry->add($attribute => $msg_hash->{detected_hardware}[0]->{$attribute});
219 }
220 }
221 foreach my $attribute (
222 "gotoModules", "ghScsiDev", "ghIdeDev") {
223 if(defined($msg_hash->{detected_hardware}[0]->{$attribute}) &&
224 length($msg_hash->{detected_hardware}[0]->{$attribute}) >0 ) {
225 if(defined($entry->get_value($attribute))) {
226 $entry->delete($attribute => []);
227 }
228 foreach my $array_entry (keys %{{map { $_ => 1 } sort(@{$msg_hash->{detected_hardware}[0]->{$attribute}}) }}) {
229 $entry->add($attribute => $array_entry);
230 }
231 }
232 }
234 my $res=$entry->update($ldap_handle);
235 if(defined($res->{'errorMessage'}) &&
236 length($res->{'errorMessage'}) >0) {
237 &main::daemon_log("ERROR: can not add entries to LDAP: ".$res->{'errorMessage'}, 1);
238 } else {
239 &main::daemon_log("INFO: Added Hardware configuration to LDAP", 5);
240 }
242 }
243 return ;
244 }
247 sub trigger_wake {
248 my ($msg, $msg_hash, $session_id) = @_ ;
250 foreach (@{$msg_hash->{macAddress}}){
251 &main::daemon_log("$session_id INFO: trigger wake for $_", 5);
252 my $host = $_;
253 my $ipaddr = '255.255.255.255';
254 my $port = getservbyname('discard', 'udp');
256 my ($raddr, $them, $proto);
257 my ($hwaddr, $hwaddr_re, $pkt);
259 # get the hardware address (ethernet address)
260 $hwaddr_re = join(':', ('[0-9A-Fa-f]{1,2}') x 6);
261 if ($host =~ m/^$hwaddr_re$/) {
262 $hwaddr = $host;
263 } else {
264 &main::daemon_log("$session_id ERROR: trigger_wake called with non mac address", 1);
265 }
267 # Generate magic sequence
268 foreach (split /:/, $hwaddr) {
269 $pkt .= chr(hex($_));
270 }
271 $pkt = chr(0xFF) x 6 . $pkt x 16;
273 # Allocate socket and send packet
275 $raddr = gethostbyname($ipaddr);
276 $them = pack_sockaddr_in($port, $raddr);
277 $proto = getprotobyname('udp');
279 socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
280 setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt : $!";
282 send(S, $pkt, 0, $them) or die "send : $!";
283 close S;
284 }
286 return;
287 }
289 1;