1 package GOSA::GosaSupportDaemon;
3 use Exporter;
4 @ISA = qw(Exporter);
5 @EXPORT = qw(create_xml_hash send_msg_hash2address get_content_from_xml_hash add_content2xml_hash create_xml_string encrypt_msg decrypt_msg create_ciphering transform_msg2hash get_time send_msg);
7 use strict;
8 use warnings;
9 use IO::Socket::INET;
10 use Crypt::Rijndael;
11 use Digest::MD5 qw(md5 md5_hex md5_base64);
12 use MIME::Base64;
13 use XML::Simple;
17 BEGIN {}
19 END {}
21 ### Start ######################################################################
23 my $xml = new XML::Simple();
25 sub process_incoming_msg {
26 return;
27 }
29 sub daemon_log {
30 my ($msg, $level) = @_ ;
31 &main::daemon_log($msg, $level);
32 return;
33 }
36 ##=== FUNCTION ================================================================
37 ## NAME: logging
38 ## PARAMETERS: level - string - default 'info'
39 ## msg - string -
40 ## facility - string - default 'LOG_DAEMON'
41 ## RETURNS: nothing
42 ## DESCRIPTION: function for logging
43 ##===============================================================================
44 #my $log_file = $main::log_file;
45 #my $verbose = $main::verbose;
46 #my $foreground = $main::forground;
47 #sub daemon_log {
48 # # log into log_file
49 # my( $msg, $level ) = @_;
50 # if(not defined $msg) { return }
51 # if(not defined $level) { $level = 1 }
52 # if(defined $log_file){
53 # open(LOG_HANDLE, ">>$log_file");
54 # if(not defined open( LOG_HANDLE, ">>$log_file" )) {
55 # print STDERR "cannot open $log_file: $!";
56 # return }
57 # chomp($msg);
58 # if($level <= $verbose){
59 # print LOG_HANDLE "$level $msg\n";
60 # if(defined $foreground) { print $msg."\n" }
61 # }
62 # }
63 # close( LOG_HANDLE );
64 ##log into syslog
65 ## my ($msg, $level, $facility) = @_;
66 ## if(not defined $msg) {return}
67 ## if(not defined $level) {$level = "info"}
68 ## if(not defined $facility) {$facility = "LOG_DAEMON"}
69 ## openlog($0, "pid,cons,", $facility);
70 ## syslog($level, $msg);
71 ## closelog;
72 ## return;
73 #}
76 #=== FUNCTION ================================================================
77 # NAME: create_xml_hash
78 # PARAMETERS: header - string - message header (required)
79 # source - string - where the message come from (required)
80 # target - string - where the message should go to (required)
81 # [header_value] - string - something usefull (optional)
82 # RETURNS: hash - hash - nomen est omen
83 # DESCRIPTION: creates a key-value hash, all values are stored in a array
84 #===============================================================================
85 sub create_xml_hash {
86 my ($header, $source, $target, $header_value) = @_;
87 my $hash = {
88 header => [$header],
89 source => [$source],
90 target => [$target],
91 $header => [$header_value],
92 };
93 #daemon_log("create_xml_hash:", 7),
94 #chomp(my $tmp = Dumper $hash);
95 #daemon_log("\t$tmp", 7);
96 return $hash
97 }
100 sub transform_msg2hash {
101 my ($msg) = @_ ;
102 my $hash = $xml->XMLin($msg, ForceArray=>1);
103 return $hash;
104 }
107 #=== FUNCTION ================================================================
108 # NAME: send_msg_hash2address
109 # PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash
110 # PeerAddr string - socket address to send msg
111 # PeerPort string - socket port, if not included in socket address
112 # RETURNS: nothing
113 # DESCRIPTION: ????
114 #===============================================================================
115 sub send_msg_hash2address {
116 my ($msg_hash, $address, $passwd) = @_ ;
118 # fetch header for logging
119 my $header = @{$msg_hash->{header}}[0];
121 # generate xml string
122 my $msg_xml = &create_xml_string($msg_hash);
124 # fetch the appropriated passwd from hash
125 if(not defined $passwd) {
126 if(exists $main::known_daemons->{$address}) {
127 $passwd = $main::known_daemons->{$address}->{passwd};
128 } elsif(exists $main::known_clients->{$address}) {
129 $passwd = $main::known_clients->{$address}->{passwd};
131 } else {
132 daemon_log("$address not known, neither as server nor as client", 1);
133 return 1;
134 }
135 }
137 # create ciphering object
138 my $act_cipher = &create_ciphering($passwd);
140 # encrypt xml msg
141 my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
143 # opensocket
144 my $socket = &open_socket($address);
145 if(not defined $socket){
146 daemon_log("cannot send '$header'-msg to $address , server not reachable",
147 5);
149 # if (exists $main::known_clients->{$address}) {
150 # if ($main::known_clients->{$address}->{status} eq "down") {
151 # # if status of not reachable client is already 'down',
152 # # then delete client from known_clients
153 # &clean_up_known_clients($address);
154 #
155 # } else {
156 # # update status to 'down'
157 # &update_known_clients(hostname=>$address, status=>"down");
158 #
159 # }
160 # }
161 return 1;
162 }
164 # send xml msg
165 print $socket $crypted_msg."\n";
167 close $socket;
169 daemon_log("send '$header'-msg to $address", 1);
171 daemon_log("$msg_xml", 5);
173 #daemon_log("crypted message:",7);
174 #daemon_log("\t$crypted_msg", 7);
176 # update status of client in known_clients with last send msg
177 # if(exists $main::known_daemons->{$address}) {
178 # #&update_known_daemons();
179 # } elsif(exists $main::known_clients->{$address}) {
180 # &main::update_known_clients(hostname=>$address, status=>$header);
181 # }
183 return 0;
184 }
187 #=== FUNCTION ================================================================
188 # NAME: get_content_from_xml_hash
189 # PARAMETERS: xml_ref - ref - reference of the xml hash
190 # element - string - key of the value you want
191 # RETURNS: value - string - if key is either header, target or source
192 # value - list - for all other keys in xml hash
193 # DESCRIPTION:
194 #===============================================================================
195 sub get_content_from_xml_hash {
196 my ($xml_ref, $element) = @_ ;
197 #my $result = $main::xml_ref->{$element};
198 #if( $element eq "header" || $element eq "target" || $element eq "source") {
199 # return @$result[0];
200 #}
201 my @result = $xml_ref->{$element};
202 return \@result;
203 }
206 #=== FUNCTION ================================================================
207 # NAME: add_content2xml_hash
208 # PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash
209 # element - string - key for the hash
210 # content - string - value for the hash
211 # RETURNS: nothing
212 # DESCRIPTION: add key-value pair to xml_ref, if key alread exists,
213 # then append value to list
214 #===============================================================================
215 sub add_content2xml_hash {
216 my ($xml_ref, $element, $content) = @_;
217 if(not exists $$xml_ref{$element} ) {
218 $$xml_ref{$element} = [];
219 }
220 my $tmp = $$xml_ref{$element};
221 push(@$tmp, $content);
222 return;
223 }
226 #=== FUNCTION ================================================================
227 # NAME: create_xml_string
228 # PARAMETERS: xml_hash - hash - hash from function create_xml_hash
229 # RETURNS: xml_string - string - xml string representation of the hash
230 # DESCRIPTION: transform the hash to a string using XML::Simple module
231 #===============================================================================
232 sub create_xml_string {
233 my ($xml_hash) = @_ ;
234 my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
235 #$xml_string =~ s/[\n]+//g;
236 #daemon_log("create_xml_string:",7);
237 #daemon_log("$xml_string\n", 7);
238 return $xml_string;
239 }
242 #=== FUNCTION ================================================================
243 # NAME: encrypt_msg
244 # PARAMETERS: msg - string - message to encrypt
245 # my_cipher - ref - reference to a Crypt::Rijndael object
246 # RETURNS: crypted_msg - string - crypted message
247 # DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module
248 #===============================================================================
249 sub encrypt_msg {
250 my ($msg, $my_cipher) = @_;
251 if(not defined $my_cipher) { print "no cipher object\n"; }
252 $msg = "\0"x(16-length($msg)%16).$msg;
253 my $crypted_msg = $my_cipher->encrypt($msg);
254 chomp($crypted_msg = &encode_base64($crypted_msg));
255 return $crypted_msg;
256 }
259 #=== FUNCTION ================================================================
260 # NAME: decrypt_msg
261 # PARAMETERS: crypted_msg - string - message to decrypt
262 # my_cipher - ref - reference to a Crypt::Rijndael object
263 # RETURNS: msg - string - decrypted message
264 # DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module
265 #===============================================================================
266 sub decrypt_msg {
267 my ($crypted_msg, $my_cipher) = @_ ;
268 $crypted_msg = &decode_base64($crypted_msg);
269 my $msg = $my_cipher->decrypt($crypted_msg);
270 $msg =~ s/\0*//g;
271 return $msg;
272 }
275 #=== FUNCTION ================================================================
276 # NAME: create_ciphering
277 # PARAMETERS: passwd - string - used to create ciphering
278 # RETURNS: cipher - object
279 # DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key
280 #===============================================================================
281 sub create_ciphering {
282 my ($passwd) = @_;
283 $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
284 my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
286 #daemon_log("iv: $iv", 7);
287 #daemon_log("key: $passwd", 7);
288 my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
289 $my_cipher->set_iv($iv);
290 return $my_cipher;
291 }
294 #=== FUNCTION ================================================================
295 # NAME: open_socket
296 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
297 # [PeerPort] string necessary if port not appended by PeerAddr
298 # RETURNS: socket IO::Socket::INET
299 # DESCRIPTION: open a socket to PeerAddr
300 #===============================================================================
301 sub open_socket {
302 my ($PeerAddr, $PeerPort) = @_ ;
303 if(defined($PeerPort)){
304 $PeerAddr = $PeerAddr.":".$PeerPort;
305 }
306 my $socket;
307 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr,
308 Porto => "tcp",
309 Type => SOCK_STREAM,
310 Timeout => 5,
311 );
312 if(not defined $socket) {
313 return;
314 }
315 &daemon_log("open_socket:", 7);
316 &daemon_log("\t$PeerAddr", 7);
317 return $socket;
318 }
321 sub get_time {
322 my ($seconds, $minutes, $hours, $monthday, $month,
323 $year, $weekday, $yearday, $sommertime) = localtime(time);
324 $hours = $hours < 10 ? $hours = "0".$hours : $hours;
325 $minutes = $minutes < 10 ? $minutes = "0".$minutes : $minutes;
326 $seconds = $seconds < 10 ? $seconds = "0".$seconds : $seconds;
327 $month+=1;
328 $month = $month < 10 ? $month = "0".$month : $month;
329 $monthday = $monthday < 10 ? $monthday = "0".$monthday : $monthday;
330 $year+=1900;
331 return "$year$month$monthday$hours$minutes$seconds";
333 }
336 #=== FUNCTION ================================================================
337 # NAME: send_msg
338 # DESCRIPTION: Send a message to a destination
339 # PARAMETERS: [header] Name of the header
340 # [from] sender ip
341 # [to] recipient ip
342 # [data] Hash containing additional attributes for the xml
343 # package
344 # RETURNS: nothing
345 #===============================================================================
346 sub send_msg ($$$$$) {
347 my ($header, $from, $to, $data, $hostkey) = @_;
349 my $out_hash = &create_xml_hash($header, $from, $to);
351 while ( my ($key, $value) = each(%$data) ) {
352 if(ref($value) eq 'ARRAY'){
353 map(&add_content2xml_hash($out_hash, $key, $_), @$value);
354 } else {
355 &add_content2xml_hash($out_hash, $key, $value);
356 }
357 }
359 &send_msg_hash2address($out_hash, $to, $hostkey);
360 }
362 1;