a92ef00a19a4ea807691a8d5f8ec696b6a8c4f03
1 package 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;
16 BEGIN {}
18 END {}
20 ### Start ######################################################################
22 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) = @_ ;
103 my $hash = $xml->XMLin($msg, ForceArray=>1);
104 return $hash;
105 }
108 #=== FUNCTION ================================================================
109 # NAME: send_msg_hash2address
110 # PARAMETERS: msg_hash - hash - xml_hash created with function create_xml_hash
111 # PeerAddr string - socket address to send msg
112 # PeerPort string - socket port, if not included in socket address
113 # RETURNS: nothing
114 # DESCRIPTION: ????
115 #===============================================================================
116 sub send_msg_hash2address {
117 my ($msg_hash, $address, $passwd) = @_ ;
119 # fetch header for logging
120 my $header = @{$msg_hash->{header}}[0];
122 # generate xml string
123 my $msg_xml = &create_xml_string($msg_hash);
125 # fetch the appropriated passwd from hash
126 if(not defined $passwd) {
127 if(exists $main::known_daemons->{$address}) {
128 $passwd = $main::known_daemons->{$address}->{passwd};
129 } elsif(exists $main::known_clients->{$address}) {
130 $passwd = $main::known_clients->{$address}->{passwd};
132 } else {
133 daemon_log("$address not known, neither as server nor as client", 1);
134 return 1;
135 }
136 }
138 # create ciphering object
139 my $act_cipher = &create_ciphering($passwd);
141 # encrypt xml msg
142 my $crypted_msg = &encrypt_msg($msg_xml, $act_cipher);
144 # opensocket
145 my $socket = &open_socket($address);
146 if(not defined $socket){
147 daemon_log("cannot send '$header'-msg to $address , server not reachable",
148 5);
150 if (exists $main::known_clients->{$address}) {
151 if ($main::known_clients->{$address}->{status} eq "down") {
152 # if status of not reachable client is already 'down',
153 # then delete client from known_clients
154 &clean_up_known_clients($address);
156 } else {
157 # update status to 'down'
158 &update_known_clients(hostname=>$address, status=>"down");
160 }
161 }
162 return 1;
163 }
165 # send xml msg
166 print $socket $crypted_msg."\n";
168 close $socket;
170 daemon_log("send '$header'-msg to $address", 1);
172 daemon_log("$msg_xml", 5);
174 #daemon_log("crypted message:",7);
175 #daemon_log("\t$crypted_msg", 7);
177 # update status of client in known_clients with last send msg
178 if(exists $main::known_daemons->{$address}) {
179 #&update_known_daemons();
180 } elsif(exists $main::known_clients->{$address}) {
181 &main::update_known_clients(hostname=>$address, status=>$header);
182 }
184 return 0;
185 }
188 #=== FUNCTION ================================================================
189 # NAME: get_content_from_xml_hash
190 # PARAMETERS: xml_ref - ref - reference of the xml hash
191 # element - string - key of the value you want
192 # RETURNS: value - string - if key is either header, target or source
193 # value - list - for all other keys in xml hash
194 # DESCRIPTION:
195 #===============================================================================
196 sub get_content_from_xml_hash {
197 my ($xml_ref, $element) = @_ ;
198 #my $result = $main::xml_ref->{$element};
199 #if( $element eq "header" || $element eq "target" || $element eq "source") {
200 # return @$result[0];
201 #}
202 my @result = $xml_ref->{$element};
203 return \@result;
204 }
207 #=== FUNCTION ================================================================
208 # NAME: add_content2xml_hash
209 # PARAMETERS: xml_ref - ref - reference to a hash from function create_xml_hash
210 # element - string - key for the hash
211 # content - string - value for the hash
212 # RETURNS: nothing
213 # DESCRIPTION: add key-value pair to xml_ref, if key alread exists,
214 # then append value to list
215 #===============================================================================
216 sub add_content2xml_hash {
217 my ($xml_ref, $element, $content) = @_;
218 if(not exists $$xml_ref{$element} ) {
219 $$xml_ref{$element} = [];
220 }
221 my $tmp = $$xml_ref{$element};
222 push(@$tmp, $content);
223 return;
224 }
227 #=== FUNCTION ================================================================
228 # NAME: create_xml_string
229 # PARAMETERS: xml_hash - hash - hash from function create_xml_hash
230 # RETURNS: xml_string - string - xml string representation of the hash
231 # DESCRIPTION: transform the hash to a string using XML::Simple module
232 #===============================================================================
233 sub create_xml_string {
234 my ($xml_hash) = @_ ;
235 my $xml_string = $xml->XMLout($xml_hash, RootName => 'xml');
236 $xml_string =~ s/[\n]+//g;
237 #daemon_log("create_xml_string:",7);
238 #daemon_log("$xml_string\n", 7);
239 return $xml_string;
240 }
243 #=== FUNCTION ================================================================
244 # NAME: encrypt_msg
245 # PARAMETERS: msg - string - message to encrypt
246 # my_cipher - ref - reference to a Crypt::Rijndael object
247 # RETURNS: crypted_msg - string - crypted message
248 # DESCRIPTION: crypts the incoming message with the Crypt::Rijndael module
249 #===============================================================================
250 sub encrypt_msg {
251 my ($msg, $my_cipher) = @_;
252 if(not defined $my_cipher) { print "no cipher object\n"; }
253 $msg = "\0"x(16-length($msg)%16).$msg;
254 my $crypted_msg = $my_cipher->encrypt($msg);
255 chomp($crypted_msg = &encode_base64($crypted_msg));
256 return $crypted_msg;
257 }
260 #=== FUNCTION ================================================================
261 # NAME: decrypt_msg
262 # PARAMETERS: crypted_msg - string - message to decrypt
263 # my_cipher - ref - reference to a Crypt::Rijndael object
264 # RETURNS: msg - string - decrypted message
265 # DESCRIPTION: decrypts the incoming message with the Crypt::Rijndael module
266 #===============================================================================
267 sub decrypt_msg {
268 my ($crypted_msg, $my_cipher) = @_ ;
269 $crypted_msg = &decode_base64($crypted_msg);
270 my $msg = $my_cipher->decrypt($crypted_msg);
271 $msg =~ s/\0*//g;
272 return $msg;
273 }
276 #=== FUNCTION ================================================================
277 # NAME: create_ciphering
278 # PARAMETERS: passwd - string - used to create ciphering
279 # RETURNS: cipher - object
280 # DESCRIPTION: creates a Crypt::Rijndael::MODE_CBC object with passwd as key
281 #===============================================================================
282 sub create_ciphering {
283 my ($passwd) = @_;
284 $passwd = substr(md5_hex("$passwd") x 32, 0, 32);
285 my $iv = substr(md5_hex('GONICUS GmbH'),0, 16);
287 #daemon_log("iv: $iv", 7);
288 #daemon_log("key: $passwd", 7);
289 my $my_cipher = Crypt::Rijndael->new($passwd , Crypt::Rijndael::MODE_CBC());
290 $my_cipher->set_iv($iv);
291 return $my_cipher;
292 }
295 #=== FUNCTION ================================================================
296 # NAME: open_socket
297 # PARAMETERS: PeerAddr string something like 192.168.1.1 or 192.168.1.1:10000
298 # [PeerPort] string necessary if port not appended by PeerAddr
299 # RETURNS: socket IO::Socket::INET
300 # DESCRIPTION: open a socket to PeerAddr
301 #===============================================================================
302 sub open_socket {
303 my ($PeerAddr, $PeerPort) = @_ ;
304 if(defined($PeerPort)){
305 $PeerAddr = $PeerAddr.":".$PeerPort;
306 }
307 my $socket;
308 $socket = new IO::Socket::INET(PeerAddr => $PeerAddr,
309 Porto => "tcp",
310 Type => SOCK_STREAM,
311 Timeout => 5,
312 );
313 if(not defined $socket) {
314 return;
315 }
316 &daemon_log("open_socket:", 7);
317 &daemon_log("\t$PeerAddr", 7);
318 return $socket;
319 }