d6a7f004480910fea67ad88e7028fd77cb9cb7fb
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);
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();
26 sub process_incoming_msg {
27 return;
28 }
30 sub daemon_log {
31 my ($msg, $level) = @_ ;
32 &main::daemon_log($msg, $level);
33 return;
34 }
37 ##=== FUNCTION ================================================================
38 ## NAME: logging
39 ## PARAMETERS: level - string - default 'info'
40 ## msg - string -
41 ## facility - string - default 'LOG_DAEMON'
42 ## RETURNS: nothing
43 ## DESCRIPTION: function for logging
44 ##===============================================================================
45 #my $log_file = $main::log_file;
46 #my $verbose = $main::verbose;
47 #my $foreground = $main::forground;
48 #sub daemon_log {
49 # # log into log_file
50 # my( $msg, $level ) = @_;
51 # if(not defined $msg) { return }
52 # if(not defined $level) { $level = 1 }
53 # if(defined $log_file){
54 # open(LOG_HANDLE, ">>$log_file");
55 # if(not defined open( LOG_HANDLE, ">>$log_file" )) {
56 # print STDERR "cannot open $log_file: $!";
57 # return }
58 # chomp($msg);
59 # if($level <= $verbose){
60 # print LOG_HANDLE "$level $msg\n";
61 # if(defined $foreground) { print $msg."\n" }
62 # }
63 # }
64 # close( LOG_HANDLE );
65 ##log into syslog
66 ## my ($msg, $level, $facility) = @_;
67 ## if(not defined $msg) {return}
68 ## if(not defined $level) {$level = "info"}
69 ## if(not defined $facility) {$facility = "LOG_DAEMON"}
70 ## openlog($0, "pid,cons,", $facility);
71 ## syslog($level, $msg);
72 ## closelog;
73 ## return;
74 #}
77 #=== FUNCTION ================================================================
78 # NAME: create_xml_hash
79 # PARAMETERS: header - string - message header (required)
80 # source - string - where the message come from (required)
81 # target - string - where the message should go to (required)
82 # [header_value] - string - something usefull (optional)
83 # RETURNS: hash - hash - nomen est omen
84 # DESCRIPTION: creates a key-value hash, all values are stored in a array
85 #===============================================================================
86 sub create_xml_hash {
87 my ($header, $source, $target, $header_value) = @_;
88 my $hash = {
89 header => [$header],
90 source => [$source],
91 target => [$target],
92 $header => [$header_value],
93 };
94 #daemon_log("create_xml_hash:", 7),
95 #chomp(my $tmp = Dumper $hash);
96 #daemon_log("\t$tmp", 7);
97 return $hash
98 }
101 sub transform_msg2hash {
102 my ($msg) = @_ ;
104 my $hash = $xml->XMLin($msg, ForceArray=>1);
105 return $hash;
106 }
109 #=== FUNCTION ================================================================
110 # NAME: send_msg_hash2address
111 # PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash
112 # PeerAddr string - socket address to send msg
113 # PeerPort string - socket port, if not included in socket address
114 # RETURNS: nothing
115 # DESCRIPTION: ????
116 #===============================================================================
117 sub send_msg_hash2address {
118 my ($msg_hash, $address, $passwd) = @_ ;
120 # fetch header for logging
121 my $header = @{$msg_hash->{header}}[0];
123 # generate xml string
124 my $msg_xml = &create_xml_string($msg_hash);
126 # fetch the appropriated passwd from hash
127 if(not defined $passwd) {
128 if(exists $main::known_daemons->{$address}) {
129 $passwd = $main::known_daemons->{$address}->{passwd};
130 } elsif(exists $main::known_clients->{$address}) {
131 $passwd = $main::known_clients->{$address}->{passwd};
133 } else {
134 daemon_log("$address not known, neither as server nor as client", 1);
135 return 1;
136 }
137 }
139 # create ciphering object
140 my $act_cipher = &create_ciphering($passwd);
142 # encrypt xml msg
143 my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
145 # opensocket
146 my $socket = &open_socket($address);
147 if(not defined $socket){
148 daemon_log("cannot send '$header'-msg to $address , server not reachable",
149 5);
151 if (exists $main::known_clients->{$address}) {
152 if ($main::known_clients->{$address}->{status} eq "down") {
153 # if status of not reachable client is already 'down',
154 # then delete client from known_clients
155 &clean_up_known_clients($address);
157 } else {
158 # update status to 'down'
159 &update_known_clients(hostname=>$address, status=>"down");
161 }
162 }
163 return 1;
164 }
166 # send xml msg
167 print $socket $crypted_msg."\n";
169 close $socket;
171 daemon_log("send '$header'-msg to $address", 1);
173 daemon_log("$msg_xml", 5);
175 #daemon_log("crypted message:",7);
176 #daemon_log("\t$crypted_msg", 7);
178 # update status of client in known_clients with last send msg
179 if(exists $main::known_daemons->{$address}) {
180 #&update_known_daemons();
181 } elsif(exists $main::known_clients->{$address}) {
182 &main::update_known_clients(hostname=>$address, status=>$header);
183 }
185 return 0;
186 }
189 #=== FUNCTION ================================================================
190 # NAME: get_content_from_xml_hash
191 # PARAMETERS: xml_ref - ref - reference of the xml hash
192 # element - string - key of the value you want
193 # RETURNS: value - string - if key is either header, target or source
194 # value - list - for all other keys in xml hash
195 # DESCRIPTION:
196 #===============================================================================
197 sub get_content_from_xml_hash {
198 my ($xml_ref, $element) = @_ ;
199 #my $result = $main::xml_ref->{$element};
200 #if( $element eq "header" || $element eq "target" || $element eq "source") {
201 # return @$result[0];
202 #}
203 my @result = $xml_ref->{$element};
204 return \@result;
205 }
208 #=== FUNCTION ================================================================
209 # NAME: add_content2xml_hash
210 # PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash
211 # element - string - key for the hash
212 # content - string - value for the hash
213 # RETURNS: nothing
214 # DESCRIPTION: add key-value pair to xml_ref, if key alread exists,
215 # then append value to list
216 #===============================================================================
217 sub add_content2xml_hash {
218 my ($xml_ref, $element, $content) = @_;
219 if(not exists $$xml_ref{$element} ) {
220 $$xml_ref{$element} = [];
221 }
222 my $tmp = $$xml_ref{$element};
223 push(@$tmp, $content);
224 return;
225 }
228 #=== FUNCTION ================================================================
229 # NAME: create_xml_string
230 # PARAMETERS: xml_hash - hash - hash from function create_xml_hash
231 # RETURNS: xml_string - string - xml string representation of the hash
232 # DESCRIPTION: transform the hash to a string using XML::Simple module
233 #===============================================================================
234 sub create_xml_string {
235 my ($xml_hash) = @_ ;
236 my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
237 #$xml_string =~ s/[\n]+//g;
238 #daemon_log("create_xml_string:",7);
239 #daemon_log("$xml_string\n", 7);
240 return $xml_string;
241 }
244 #=== FUNCTION ================================================================
245 # NAME: encrypt_msg
246 # PARAMETERS: msg - string - message to encrypt
247 # my_cipher - ref - reference to a Crypt::Rijndael object
248 # RETURNS: crypted_msg - string - crypted message
249 # DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module
250 #===============================================================================
251 sub encrypt_msg {
252 my ($msg, $my_cipher) = @_;
253 if(not defined $my_cipher) { print "no cipher object\n"; }
254 $msg = "\0"x(16-length($msg)%16).$msg;
255 my $crypted_msg = $my_cipher->encrypt($msg);
256 chomp($crypted_msg = &encode_base64($crypted_msg));
257 return $crypted_msg;
258 }
261 #=== FUNCTION ================================================================
262 # NAME: decrypt_msg
263 # PARAMETERS: crypted_msg - string - message to decrypt
264 # my_cipher - ref - reference to a Crypt::Rijndael object
265 # RETURNS: msg - string - decrypted message
266 # DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module
267 #===============================================================================
268 sub decrypt_msg {
269 my ($crypted_msg, $my_cipher) = @_ ;
270 $crypted_msg = &decode_base64($crypted_msg);
271 my $msg = $my_cipher->decrypt($crypted_msg);
272 $msg =~ s/\0*//g;
273 return $msg;
274 }
277 #=== FUNCTION ================================================================
278 # NAME: create_ciphering
279 # PARAMETERS: passwd - string - used to create ciphering
280 # RETURNS: cipher - object
281 # DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key
282 #===============================================================================
283 sub create_ciphering {
284 my ($passwd) = @_;
285 $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
286 my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
288 #daemon_log("iv: $iv", 7);
289 #daemon_log("key: $passwd", 7);
290 my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
291 $my_cipher->set_iv($iv);
292 return $my_cipher;
293 }
296 #=== FUNCTION ================================================================
297 # NAME: open_socket
298 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
299 # [PeerPort] string necessary if port not appended by PeerAddr
300 # RETURNS: socket IO::Socket::INET
301 # DESCRIPTION: open a socket to PeerAddr
302 #===============================================================================
303 sub open_socket {
304 my ($PeerAddr, $PeerPort) = @_ ;
305 if(defined($PeerPort)){
306 $PeerAddr = $PeerAddr.":".$PeerPort;
307 }
308 my $socket;
309 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr,
310 Porto => "tcp",
311 Type => SOCK_STREAM,
312 Timeout => 5,
313 );
314 if(not defined $socket) {
315 return;
316 }
317 &daemon_log("open_socket:", 7);
318 &daemon_log("\t$PeerAddr", 7);
319 return $socket;
320 }
323 #=== FUNCTION ================================================================
324 # NAME: send_msg
325 # DESCRIPTION: Send a message to a destination
326 # PARAMETERS: [header] Name of the header
327 # [from] sender ip
328 # [to] recipient ip
329 # [data] Hash containing additional attributes for the xml
330 # package
331 # RETURNS: nothing
332 #===============================================================================
333 sub send_msg ($$$$) {
334 my ($header, $from, $to, $data) = @_;
336 my $out_hash = &create_xml_hash($header, $from, $to);
338 while ( my ($key, $value) = each(%$data) ) {
339 if(ref($value) eq 'ARRAY'){
340 map(&add_content2xml_hash($out_hash, $key, $_), @$value);
341 } else {
342 &add_content2xml_hash($out_hash, $key, $value);
343 }
344 }
346 &send_msg_hash2address($out_hash, $to);
347 }
349 1;