1 package siTriggered;
2 use Exporter;
3 @ISA = qw(Exporter);
4 my @events = (
5 "got_ping",
6 "detected_hardware",
7 "trigger_wake",
8 );
9 @EXPORT = @events;
11 use strict;
12 use warnings;
13 use GOSA::GosaSupportDaemon;
14 use Socket;
17 BEGIN {}
19 END {}
21 ### Start ######################################################################
23 my $ldap_uri;
24 my $ldap_base;
25 my $ldap_admin_dn;
26 my $ldap_admin_password;
28 my %cfg_defaults = (
29 "server" => {
30 "ldap-uri" => [\$ldap_uri, ""],
31 "ldap-base" => [\$ldap_base, ""],
32 "ldap-admin-dn" => [\$ldap_admin_dn, ""],
33 "ldap-admin-password" => [\$ldap_admin_password, ""],
34 },
35 );
36 &read_configfile($main::cfg_file, %cfg_defaults);
39 sub get_events {
40 return \@events;
41 }
44 sub read_configfile {
45 my ($cfg_file, %cfg_defaults) = @_;
46 my $cfg;
48 if( defined( $cfg_file) && ( length($cfg_file) > 0 )) {
49 if( -r $cfg_file ) {
50 $cfg = Config::IniFiles->new( -file => $cfg_file );
51 } else {
52 &main::daemon_log("ERROR: siTriggered.pm couldn't read config file!", 1);
53 }
54 } else {
55 $cfg = Config::IniFiles->new() ;
56 }
57 foreach my $section (keys %cfg_defaults) {
58 foreach my $param (keys %{$cfg_defaults{ $section }}) {
59 my $pinfo = $cfg_defaults{ $section }{ $param };
60 ${@$pinfo[0]} = $cfg->val( $section, $param, @$pinfo[1] );
61 }
62 }
63 }
65 sub got_ping {
66 my ($msg, $msg_hash, $session_id) = @_;
68 my $source = @{$msg_hash->{source}}[0];
69 my $target = @{$msg_hash->{target}}[0];
70 my $header = @{$msg_hash->{header}}[0];
71 my $act_time = &get_time;
72 my @out_msg_l;
73 my $out_msg;
75 $session_id = @{$msg_hash->{'session_id'}}[0];
77 # check known_clients_db
78 my $sql_statement = "SELECT * FROM known_clients WHERE hostname='$source'";
79 my $query_res = $main::known_clients_db->select_dbentry( $sql_statement );
80 if( 1 == keys %{$query_res} ) {
81 my $sql_statement= "UPDATE known_clients ".
82 "SET status='$header', timestamp='$act_time' ".
83 "WHERE hostname='$source'";
84 my $res = $main::known_clients_db->update_dbentry( $sql_statement );
85 }
87 # check known_server_db
88 $sql_statement = "SELECT * FROM known_server WHERE hostname='$source'";
89 $query_res = $main::known_server_db->select_dbentry( $sql_statement );
90 if( 1 == keys %{$query_res} ) {
91 my $sql_statement= "UPDATE known_server ".
92 "SET status='$header', timestamp='$act_time' ".
93 "WHERE hostname='$source'";
94 my $res = $main::known_server_db->update_dbentry( $sql_statement );
95 }
97 # create out_msg
98 my $out_hash = &create_xml_hash($header, $source, "GOSA");
99 &add_content2xml_hash($out_hash, "session_id", $session_id);
100 $out_msg = &create_xml_string($out_hash);
101 push(@out_msg_l, $out_msg);
103 return @out_msg_l;
104 }
107 sub detected_hardware {
108 my ($msg, $msg_hash, $session_id) = @_ ;
109 my $address = $msg_hash->{source}[0];
110 my $gotoHardwareChecksum= $msg_hash->{detected_hardware}[0]->{gotoHardwareChecksum};
112 my $sql_statement= "SELECT * FROM known_clients WHERE hostname='$address'";
113 my $res = $main::known_clients_db->select_dbentry( $sql_statement );
115 # check hit
116 my $hit_counter = keys %{$res};
117 if( not $hit_counter == 1 ) {
118 &main::daemon_log("ERROR: more or no hit found in known_clients_db by query by '$address'", 1);
119 return;
120 }
122 my $macaddress = $res->{1}->{macaddress};
123 my $hostkey = $res->{1}->{hostkey};
125 if (not defined $macaddress) {
126 &main::daemon_log("ERROR: no mac address found for client $address", 1);
127 return;
128 }
129 # Build LDAP connection
130 my $ldap = Net::LDAP->new($ldap_uri);
131 if( not defined $ldap ) {
132 &main::daemon_log("ERROR: cannot connect to ldap: $ldap_uri", 1);
133 return;
134 }
136 # Bind to a directory with dn and password
137 my $mesg= $ldap->bind($ldap_admin_dn, password => $ldap_admin_password);
139 # Perform search
140 $mesg = $ldap->search(
141 base => $ldap_base,
142 scope => 'sub',
143 filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
144 );
146 # We need to create a base entry first (if not done from ArpHandler)
147 if($mesg->count == 0) {
148 &main::daemon_log("INFO: Need to create a new LDAP Entry for client $address", 6);
149 my $resolver=Net::DNS::Resolver->new;
150 my $ipaddress= $1 if $address =~ /^([0-9\.]*?):.*$/;
151 my $dnsresult= $resolver->search($ipaddress);
152 my $dnsname= (defined($dnsresult))?$dnsresult->{answer}[0]->{ptrdname}:$ipaddress;
153 my $cn = (($dnsname =~ /^(\d){1,3}\.(\d){1,3}\.(\d){1,3}\.(\d){1,3}/) ? $dnsname : sprintf "%s", $dnsname =~ /([^\.]+)\.?/);
154 my $dn = "cn=$cn,ou=incoming,$ldap_base";
155 &main::daemon_log("INFO: Creating entry for $dn",5);
156 my $entry= Net::LDAP::Entry->new( $dn );
157 $entry->dn($dn);
158 $entry->add("objectClass" => "goHard");
159 $entry->add("cn" => $cn);
160 $entry->add("macAddress" => $macaddress);
161 $entry->add("gotomode" => "locked");
162 $entry->add("gotoSysStatus" => "new-system");
163 $entry->add("ipHostNumber" => $ipaddress);
164 if(defined($main::gosa_unit_tag) && length($main::gosa_unit_tag) > 0) {
165 $entry->add("objectClass" => "gosaAdministrativeUnit");
166 $entry->add("gosaUnitTag" => $main::gosa_unit_tag);
167 }
168 my $res=$entry->update($ldap);
169 if(defined($res->{'errorMessage'}) &&
170 length($res->{'errorMessage'}) >0) {
171 &main::daemon_log("ERROR: can not add entries to LDAP: ".$res->{'errorMessage'}, 1);
172 return;
173 } else {
174 # Fill $mesg again
175 $mesg = $ldap->search(
176 base => $ldap_base,
177 scope => 'sub',
178 filter => "(&(objectClass=GOhard)(|(macAddress=$macaddress)(dhcpHWaddress=ethernet $macaddress)))"
179 );
180 }
181 }
183 if($mesg->count == 1) {
184 my $entry= $mesg->entry(0);
185 $entry->changetype("modify");
186 foreach my $attribute (
187 "gotoSndModule", "ghNetNic", "gotoXResolution", "ghSoundAdapter", "ghCpuType", "gotoXkbModel",
188 "ghGfxAdapter", "gotoXMousePort", "ghMemSize", "gotoXMouseType", "ghUsbSupport", "gotoXHsync",
189 "gotoXDriver", "gotoXVsync", "gotoXMonitor", "gotoHardwareChecksum") {
190 if(defined($msg_hash->{detected_hardware}[0]->{$attribute}) &&
191 length($msg_hash->{detected_hardware}[0]->{$attribute}) >0 ) {
192 if(defined($entry->get_value($attribute))) {
193 $entry->delete($attribute);
194 }
195 &main::daemon_log("INFO: Adding attribute $attribute with value ".$msg_hash->{detected_hardware}[0]->{$attribute},5);
196 $entry->add($attribute => $msg_hash->{detected_hardware}[0]->{$attribute});
197 }
198 }
199 foreach my $attribute (
200 "gotoModules", "ghScsiDev", "ghIdeDev") {
201 if(defined($msg_hash->{detected_hardware}[0]->{$attribute}) &&
202 length($msg_hash->{detected_hardware}[0]->{$attribute}) >0 ) {
203 if(defined($entry->get_value($attribute))) {
204 $entry->delete($attribute);
205 }
206 foreach my $array_entry (@{$msg_hash->{detected_hardware}[0]->{$attribute}}) {
207 $entry->add($attribute => $array_entry);
208 }
209 }
210 }
212 my $res=$entry->update($ldap);
213 if(defined($res->{'errorMessage'}) &&
214 length($res->{'errorMessage'}) >0) {
215 &main::daemon_log("ERROR: can not add entries to LDAP: ".$res->{'errorMessage'}, 1);
216 } else {
217 &main::daemon_log("INFO: Added Hardware configuration to LDAP", 5);
218 }
220 }
221 return ;
222 }
225 sub trigger_wake {
226 my ($msg, $msg_hash, $session_id) = @_ ;
228 foreach (@{$msg_hash->{macAddress}}){
229 &main::daemon_log("INFO: trigger wake for $_", 5);
230 my $host = shift;
231 my $ipaddr = shift || '255.255.255.255';
232 my $port = getservbyname('discard', 'udp');
234 my ($raddr, $them, $proto);
235 my ($hwaddr, $hwaddr_re, $pkt);
237 # get the hardware address (ethernet address)
238 $hwaddr_re = join(':', ('[0-9A-Fa-f]{1,2}') x 6);
239 if ($host =~ m/^$hwaddr_re$/) {
240 $hwaddr = $host;
241 } else {
242 # $host is not a hardware address, try to resolve it
243 my $ip_re = join('\.', ('([0-9]|[1-9][0-9]|1[0-9]{2}|2([0-4][0-9]|5[0-5]))') x 4);
244 my $ip_addr;
245 if ($host =~ m/^$ip_re$/) {
246 $ip_addr = $host;
247 } else {
248 my $h;
249 unless ($h = gethost($host)) {
250 return undef;
251 }
252 $ip_addr = inet_ntoa($h->addr);
253 }
254 }
256 # Generate magic sequence
257 foreach (split /:/, $hwaddr) {
258 $pkt .= chr(hex($_));
259 }
260 $pkt = chr(0xFF) x 6 . $pkt x 16;
262 # Allocate socket and send packet
264 $raddr = gethostbyname($ipaddr)->addr;
265 $them = pack_sockaddr_in($port, $raddr);
266 $proto = getprotobyname('udp');
268 socket(S, AF_INET, SOCK_DGRAM, $proto) or die "socket : $!";
269 setsockopt(S, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt : $!";
271 send(S, $pkt, 0, $them) or die "send : $!";
272 close S;
273 }
275 return;
276 }
278 1;