package network::ipsec; use detect_devices; use network::netconnect; use run_program; use common; use log; use Data::Dumper; #- debugg functions ---------- sub recreate_ipsec_conf { my ($ipsec, $kernel_version) = @_; if ($kernel_version < 2.5) { #- kernel 2.4 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { print "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; foreach my $key2 (ikeys %{$ipsec->{$key1}}) { if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { print "\t$ipsec->{$key1}{$key2}[0]\n"; } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(conn|config|version)/) { print "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; } else { print "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; }; } } } else { #- kernel 2.6 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { print "$ipsec->{$key1}\n"; } else { print $ipsec->{$key1}{command} . " " . $ipsec->{$key1}{src_range} . " " . $ipsec->{$key1}{dst_range} . " " . $ipsec->{$key1}{upperspec} . " " . $ipsec->{$key1}{flag} . " " . $ipsec->{$key1}{direction} . " " . $ipsec->{$key1}{ipsec} . "\n\t" . $ipsec->{$key1}{protocol} . "/" . $ipsec->{$key1}{mode} . "/" . $ipsec->{$key1}{src_dest} . "/" . $ipsec->{$key1}{level} . ";\n" }; } } } sub recreate_racoon_conf { my ($racoon) = @_; my $in_a_section = "n"; my $in_a_proposal_section = "n"; foreach my $key1 (ikeys %$racoon) { if ($in_a_proposal_section eq "y") { print "\t}\n}\n$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; } elsif ($in_a_section eq "y") { print "}\n$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; } else { print "$racoon->{$key1}\n" if ! $racoon->{$key1}{1}; }; $in_a_section = "n"; $in_a_proposal_section = "n"; foreach my $key2 (ikeys %{$racoon->{$key1}}) { if ($racoon->{$key1}{$key2}[0] =~ /^path/) { print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2];\n"; } elsif ($racoon->{$key1}{$key2}[0] =~ /^remote/) { $in_a_section = "y"; $in_a_proposal_section = "n"; print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] {\n"; } elsif ($racoon->{$key1}{$key2}[0] =~ /^sainfo/) { $in_a_section = "y"; $in_a_proposal_section = "n"; if ($racoon->{$key1}{$key2}[2] && $racoon->{$key1}{$key2}[5]) { print "$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2] $racoon->{$key1}{$key2}[3] $racoon->{$key1}{$key2}[4] $racoon->{$key1}{$key2}[5] $racoon->{$key1}{$key2}[6] {\n"; } else { print "$racoon->{$key1}{$key2}[0] anonymous {\n"; } } elsif ($racoon->{$key1}{$key2}[0] =~ /^proposal /) { $in_a_proposal_section = "y"; print "\t$racoon->{$key1}{$key2}[0] {\n"; } elsif ($in_a_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^certificate_type/) { print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1] $racoon->{$key1}{$key2}[2] $racoon->{$key1}{$key2}[3];\n"; } elsif ($in_a_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^#/) { print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1]\n"; } elsif ($in_a_section eq "y") { print "\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1];\n"; } elsif ($in_a_proposal_section eq "y" && $racoon->{$key1}{$key2}[0] =~ /^#/) { print "\t\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1]\n"; } elsif ($in_a_proposal_section eq "y") { print "\t\t$racoon->{$key1}{$key2}[0] $racoon->{$key1}{$key2}[1];\n"; } } } print "}\n"; } sub recreate_ipsec_conf1_k24 { my ($ipsec) = @_; foreach my $key1 (ikeys %$ipsec) { print "$key1-->$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; foreach my $key2 (ikeys %{$ipsec->{$key1}}) { if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { print "\t$key2-->$ipsec->{$key1}{$key2}[0]\n"; } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(conn|config|version)/) { print "$key1-->$key2-->$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; } else { print "\t$key2-->$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; }; } } } #- end of debug functions -------- sub sys { system(@_) == 0 or log::l("[drakvpn] Warning, sys failed for $_[0]") } sub start_daemons () { return if $::testing; log::explanations("Starting daemons"); if (-e "/etc/rc.d/init.d/ipsec") { system("/etc/rc.d/init.d/ipsec status >/dev/null") == 0 and sys("/etc/rc.d/init.d/ipsec stop"); sys("/etc/rc.d/init.d/$_ start >/dev/null"), sys("/sbin/chkconfig --level 345 $_ on") foreach 'ipsec'; } else { }; sys("/etc/rc.d/init.d/$_ start >/dev/null"), sys("/sbin/chkconfig --level 345 $_ on") foreach 'shorewall'; } sub stop_daemons () { return if $::testing; log::explanations("Stopping daemons"); if (-e "/etc/rc.d/init.d/ipsec") { foreach (qw(ipsec)) { system("/etc/rc.d/init.d/$_ status >/dev/null 2>/dev/null") == 0 and sys("/etc/rc.d/init.d/$_ stop"); }; sys("/sbin/chkconfig --level 345 $_ off") && -e "/etc/rc.d/init.d/$_" foreach 'ipsec'; }; system("/etc/rc.d/init.d/shorewall status >/dev/null 2>/dev/null") == 0 and sys("/etc/rc.d/init.d/shorewall stop >/dev/null"); } sub set_config_file { my ($file, @l) = @_; my $done; substInFile { if (!$done && (/^#LAST LINE/ || eof)) { $_ = join('', map { join("\t", @$_) . "\n" } @l) . $_; $done = 1; } else { $_ = '' if /^[^#]/; } } "$::prefix/$file"; } sub get_config_file { my ($file) = @_; map { [ split ' ' ] } grep { !/^#/ } cat_("$::prefix/$file"); } #------------------------------------------------------------------- #---------------------- configure racoon_conf ----------------------- #------------------------------------------------------------------- sub read_racoon_conf { my ($racoon_conf) = @_; my %conf; my $nb = 0; #total number my $i = 0; #nb within a section my $in_a_section = "n"; my @line1; my $line = ""; local $_; open(my $LIST, "< $racoon_conf"); while (<$LIST>) { chomp($_); $line = $_; $in_a_section = "n" if $line =~ /}/ && $line !~ /^#/; $line =~ s/^\s+|\s*;|\s*{//g if $line !~ /^#/; $line =~ /(.*)#(.*)/ if $line !~ /^#/; #- define before and after comment # print "--line-->$line\n"; my $data_part = $1; my $comment_part = "#".$2; if ($data_part) { $data_part =~ s/,//g; # print "@@".$data_part."->".$comment_part."\n"; @line1 = split /\s+/,$data_part; @line1 = (@line1, $comment_part) if $comment_part; } else { @line1 = split /\s+/,$line; } if (!$line && $in_a_section eq "n") { $nb++; put_in_hash(\%conf, { $nb => $line }); $in_a_section = "n"; } elsif (!$line && $in_a_section eq "y") { put_in_hash($conf{$nb} ||= {}, { $i => [ '' ] }); $i++; } elsif ($line =~ /^path/) { $i=1; $nb++; put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); $in_a_section = "n"; $i++; } elsif ($line =~ /^#|^{|^}/) { if ($in_a_section eq "y") { put_in_hash($conf{$nb} ||= {}, { $i => [$line] }); $i++; } else { $nb++; put_in_hash(\%conf, { $nb => $line }); $in_a_section = "n"; }; } elsif ($line =~ /^sainfo|^remote|^listen|^timer|^padding/ && $in_a_section eq "n") { $i=1; $nb++; put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); $in_a_section = "y"; $i++; } elsif ($line eq "proposal" && $in_a_section eq "y") { $i=1; $nb++; put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); $in_a_section = "y"; $i++; } else { put_in_hash($conf{$nb} ||= {}, { $i => [@line1] }); $i++; }; }; \%conf; } sub display_racoon_conf { my ($racoon) = @_; my $display = ""; my $prefix_to_simple_line = ""; my $pt; foreach my $key1 (ikeys %$racoon) { if (!$racoon->{$key1}{1}) { $display .= $prefix_to_simple_line . $racoon->{$key1} . "\n"; $prefix_to_simple_line = ""; } else { foreach my $key2 (ikeys %{$racoon->{$key1}}) { if ($key2 > 1) { $pt = $racoon->{$key1}{$key2-1}[0]; } else { $pt = $racoon->{$key1}{1}[0]; }; my $t = $racoon->{$key1}{1}[0]; my $f = $racoon->{$key1}{$key2}[0]; my $list_length = scalar @{$racoon->{$key1}{$key2}}; my $already_read = 0; my $line = ""; if ($racoon->{$key1}{$key2}[0] eq "sainfo" && !$racoon->{$key1}{$key2}[2]) { $line = "sainfo anonymous"; } else { for (my $i = 0; $i <= $list_length-1; $i++) { my $c = $racoon->{$key1}{$key2}[$i]; my $n = $racoon->{$key1}{$key2}[$i+1]; if ($c =~ /^path|^log|^timer|^listen|^padding|^remote|^proposal|^sainfo/) { $line .= "$c "; } elsif ($i == $list_length-2 && $n =~ /^#/) { $line .= "$c; "; } elsif ($i == $list_length-1) { if ($f =~ /^#|^$|^timer|^listen|^padding|^remote|^proposal\s+|^sainfo/) { $line .= $c; } elsif ($c =~ /^#/) { $line .= "\t$c"; } else { $line .= "$c;"; } } else { $line .= "$c "; } $already_read = 1; } } if ($f =~ /^timer|^listen|^padding|^remote|^sainfo/) { $line .= " {"; $prefix_to_simple_line = ""; } elsif ($f eq "proposal") { $line = "\t" . $line . " {"; } elsif ($t eq "proposal") { $line = "\t\t" . $line if $line ne "proposal"; $prefix_to_simple_line = "\t"; } else { $line = "\t" . $line if $t !~ /^path|^log/; $prefix_to_simple_line = ""; } $display .= "$line\n"; } } } $display; } sub write_racoon_conf { my ($racoon_conf, $racoon) = @_; my $display = ""; my $prefix_to_simple_line = ""; my $pt; foreach my $key1 (ikeys %$racoon) { if (!$racoon->{$key1}{1}) { $display .= $prefix_to_simple_line . $racoon->{$key1} . "\n"; $prefix_to_simple_line = ""; } else { foreach my $key2 (ikeys %{$racoon->{$key1}}) { if ($key2 > 1) { $pt = $racoon->{$key1}{$key2-1}[0]; } else { $pt = $racoon->{$key1}{1}[0]; }; my $t = $racoon->{$key1}{1}[0]; my $f = $racoon->{$key1}{$key2}[0]; my $list_length = scalar @{$racoon->{$key1}{$key2}}; my $already_read = 0; my $line = ""; if ($racoon->{$key1}{$key2}[0] eq "sainfo" && !$racoon->{$key1}{$key2}[2]) { $line = "sainfo anonymous"; } else { for (my $i = 0; $i <= $list_length-1; $i++) { my $c = $racoon->{$key1}{$key2}[$i]; my $n = $racoon->{$key1}{$key2}[$i+1]; if ($c =~ /^path|^log|^timer|^listen|^padding|^remote|^proposal|^sainfo/) { $line .= "$c "; } elsif ($i == $list_length-2 && $n =~ /^#/) { $line .= "$c; "; } elsif ($i == $list_length-1) { if ($f =~ /^#|^$|^timer|^listen|^padding|^remote|^proposal\s+|^sainfo/) { $line .= $c; } elsif ($c =~ /^#/) { $line .= "\t$c"; } else { $line .= "$c;"; } } else { $line .= "$c "; } $already_read = 1; } } if ($f =~ /^timer|^listen|^padding|^remote|^sainfo/) { $line .= " {"; $prefix_to_simple_line = ""; } elsif ($f eq "proposal") { $line = "\t" . $line . " {"; } elsif ($t eq "proposal") { $line = "\t\t" . $line if $line ne "proposal"; $prefix_to_simple_line = "\t"; } else { $line = "\t" . $line if $t !~ /^path|^log/; $prefix_to_simple_line = ""; } $display .= "$line\n"; } } } open(my $ADD, "> $racoon_conf") or die "Can't open the $racoon_conf file for writing"; print $ADD "$display\n"; } sub get_section_names_racoon_conf { my ($racoon) = @_; my @section_names; foreach my $key1 (ikeys %$racoon) { if (!$racoon->{$key1}{1}) { next; } else { my $list_length = scalar @{$racoon->{$key1}{1}}; my $section_title = ""; my $separator = ""; for (my $i = 0; $i <= $list_length-1; $i++) { my $s = $racoon->{$key1}{1}[$i]; if ($s !~ /^#|^proposal/) { $section_title .= $separator . $s; $separator = " "; }; } push(@section_names, $section_title) if $section_title ne ""; } } @section_names; } sub add_section_racoon_conf { my ($new_section, $racoon) = @_; put_in_hash($racoon, { max(keys %$racoon) + 1 => '' }); put_in_hash($racoon, { max(keys %$racoon) + 1 => $new_section }); put_in_hash($racoon, { max(keys %$racoon) + 1 => '}' }) if $new_section->{1}[0] !~ /^path|^remote/; put_in_hash($racoon, { max(keys %$racoon) + 1 => '' }) if $new_section->{1}[0] =~ /^proposal/; put_in_hash($racoon, { max(keys %$racoon) + 1 => '}' }) if $new_section->{1}[0] =~ /^proposal/; } sub matched_section_key_number_racoon_conf { my ($section_name, $racoon) = @_; foreach my $key1 (ikeys %$racoon) { if (!$racoon->{$key1}{1}) { next; } else { my $list_length = scalar @{$racoon->{$key1}{1}}; my $section_title = ""; my $separator = ""; for (my $i = 0; $i <= $list_length-1; $i++) { my $s = $racoon->{$key1}{1}[$i]; if ($s !~ /^#|^proposal/) { $section_title .= $separator . $s; $separator = " "; }; }; if ($section_title eq $section_name) { return $key1; }; } } } sub already_existing_section_racoon_conf { my ($section_name, $racoon, $racoon_conf) = @_; if (-e $racoon_conf) { foreach my $key1 (ikeys %$racoon) { if (!$racoon->{$key1}{1}) { next; } elsif (find { my $list_length = scalar @{$racoon->{$key1}{1}}; my $section_title = ""; my $separator = ""; for (my $i = 0; $i <= $list_length-1; $i++) { my $s = $racoon->{$key1}{1}[$i]; if ($s !~ /^#|^proposal/) { $section_title .= $separator . $s; $separator = " "; }; } $section_title eq $section_name; } ikeys %{$racoon->{$key1}}) { return "already existing"; } } } } sub remove_section_racoon_conf { my ($section_name, $racoon, $k) = @_; if ($section_name =~ /^remote/) { delete $racoon->{$k} if $k > 1 && !$racoon->{$k-1}; my $closing_curly_bracket = 0; while ($closing_curly_bracket < 2) { print "-->$k\n"; $closing_curly_bracket++ if $racoon->{$k} eq "}"; delete $racoon->{$k}; $k++; } } elsif ($section_name =~ /^path/) { delete $racoon->{$k}; delete $racoon->{$k+1} if $racoon->{$k+1}{1} eq ""; } else { delete $racoon->{$k}; delete $racoon->{$k+1} if $racoon->{$k+1}{1} eq ""; delete $racoon->{$k+2} if $racoon->{$k+2}{1} eq ""; #- remove assoc } } } #------------------------------------------------------------------- #---------------------- configure ipsec_conf ----------------------- #------------------------------------------------------------------- sub read_ipsec_conf { my ($ipsec_conf, $kernel_version) = @_; my %conf; my $nb = 0; #total number my $i = 0; #nb within a connexion my $in_a_conn = "n"; my $line = ""; my @line1; local $_; if ($kernel_version < 2.5) { #- kernel 2.4 part ------------------------------- open(my $LIST, "< $ipsec_conf"); #or die "Can't open the $ipsec_conf file for reading"; while (<$LIST>) { chomp($_); $line = $_; $line =~ s/^\s+//; if (!$line) { $nb++; put_in_hash(\%conf, { $nb => $line }); $in_a_conn = "n"; } elsif ($line =~ /^#/) { if ($in_a_conn eq "y") { put_in_hash($conf{$nb} ||= {}, { $i => [$line] }); $i++; } else { $nb++; put_in_hash(\%conf, { $nb => $line }); $in_a_conn = "n"; }; } elsif ($line =~ /^conn|^config|^version/ && $in_a_conn eq "n") { @line1 = split /\s+/,$line; $i=1; $nb++; put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); $in_a_conn = "y" if $line !~ /^version/; $i++; } elsif ($line =~ /^conn|^config|^version/ && $in_a_conn eq "y") { @line1 = split /\s+/,$line; $i=1; $nb++; put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); $i++; } else { @line1 = split /=/,$line; put_in_hash($conf{$nb} ||= {}, { $i => [$line1[0], $line1[1]] }); $i++; }; }; } else { #- kernel 2.6 part ------------------------------- my @mylist; my $myline = ""; open(my $LIST, "< $ipsec_conf"); #or die "Can't open the $ipsec_conf file for reading"; while (<$LIST>) { chomp($_); $myline = $_; $myline =~ s/^\s+//; $myline =~ s/;$//; if ($myline =~ /^spdadd/) { @mylist = split /\s+/,$myline; $in_a_conn = "y"; $nb++; next; } elsif ($in_a_conn eq "y") { @mylist = (@mylist, split '\s+|/',$myline); put_in_hash(\%conf, { $nb => { command => $mylist[0], src_range => $mylist[1], dst_range => $mylist[2], upperspec => $mylist[3], flag => $mylist[4], direction => $mylist[5], ipsec => $mylist[6], protocol => $mylist[7], mode => $mylist[8], src_dest => $mylist[9], level => $mylist[10] } }); $in_a_conn = "n"; } else { $nb++; put_in_hash(\%conf, { $nb => $myline }); }; }; }; \%conf; } sub write_ipsec_conf { my ($ipsec_conf, $ipsec, $kernel_version) = @_; if ($kernel_version < 2.5) { #- kernel 2.4 part ------------------------------- open(my $ADD, "> $ipsec_conf") or die "Can't open the $ipsec_conf file for writing"; foreach my $key1 (ikeys %$ipsec) { print $ADD "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; foreach my $key2 (ikeys %{$ipsec->{$key1}}) { if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { print $ADD "\t$ipsec->{$key1}{$key2}[0]\n"; } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { print $ADD "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; } else { print $ADD "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n" if $ipsec->{$key1}{$key2}[0] && $ipsec->{$key1}{$key2}[1]; }; } } } else { #- kernel 2.6 part ------------------------------- my $display = ""; foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { $display .= "$ipsec->{$key1}\n"; } else { $display .= $ipsec->{$key1}{command} . " " . $ipsec->{$key1}{src_range} . " " . $ipsec->{$key1}{dst_range} . " " . $ipsec->{$key1}{upperspec} . " " . $ipsec->{$key1}{flag} . " " . $ipsec->{$key1}{direction} . " " . $ipsec->{$key1}{ipsec} . "\n\t" . $ipsec->{$key1}{protocol} . "/" . $ipsec->{$key1}{mode} . "/" . $ipsec->{$key1}{src_dest} . "/" . $ipsec->{$key1}{level} . ";\n" }; } open(my $ADD, "> $ipsec_conf") or die "Can't open the $ipsec_conf file for writing"; print $ADD $display; } } sub display_ipsec_conf { my ($ipsec, $kernel_version) = @_; my $display = ""; if ($kernel_version < 2.5) { #- kernel 2.4 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { $display .= "$ipsec->{$key1}\n" if ! $ipsec->{$key1}{1}; foreach my $key2 (ikeys %{$ipsec->{$key1}}) { if ($ipsec->{$key1}{$key2}[0] =~ m/^#/) { $display .= "\t$ipsec->{$key1}{$key2}[0]\n"; } elsif ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { $display .= "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]\n"; } else { $display .= "\t$ipsec->{$key1}{$key2}[0]=$ipsec->{$key1}{$key2}[1]\n"; }; } } } else { #- kernel 2.6 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { if (! $ipsec->{$key1}{command}) { $display .= "$ipsec->{$key1}\n"; } else { $display .= $ipsec->{$key1}{command} . " " . $ipsec->{$key1}{src_range} . " " . $ipsec->{$key1}{dst_range} . " " . $ipsec->{$key1}{upperspec} . " " . $ipsec->{$key1}{flag} . " " . $ipsec->{$key1}{direction} . " " . $ipsec->{$key1}{ipsec} . "\n\t" . $ipsec->{$key1}{protocol} . "/" . $ipsec->{$key1}{mode} . "/" . $ipsec->{$key1}{src_dest} . "/" . $ipsec->{$key1}{level} . ";\n"; } } } $display; } sub get_section_names_ipsec_conf { my ($ipsec, $kernel_version) = @_; my @section_names; if ($kernel_version < 2.5) { #- kernel 2.4 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { foreach my $key2 (ikeys %{$ipsec->{$key1}}) { if ($ipsec->{$key1}{$key2}[0] =~ m/(^conn|^config|^version)/) { push(@section_names, "$ipsec->{$key1}{$key2}[0] $ipsec->{$key1}{$key2}[1]"); }; } } } else { #- kernel 2.6 part ------------------------------- foreach my $key1 (ikeys %$ipsec) { if ($ipsec->{$key1}{command} =~ m/(^spdadd)/) { push(@section_names, "$ipsec->{$key1}{src_range} $ipsec->{$key1}{dst_range}"); }; } } @section_names; } sub remove_section_ipsec_conf { my ($section_name, $ipsec, $kernel_version) = @_; if ($kernel_version < Such licenses will in general prevent the transfer, duplication (except for backup purposes), redistribution, reverse engineering, de-assembly, de-compilation or modification of the component. Any breach of agreement will immediately terminate your rights under the specific license. Unless the specific license terms grant you such rights, you usually cannot install the programs on more than one system, or adapt it to be used on a network. In doubt, please contact directly the distributor or editor of the component. Transfer to third parties or copying of such components including the documentation is usually forbidden. All rights to the components of the next CD media belong to their respective authors and are protected by intellectual property and copyright laws applicable to software programs. "); } sub install_completed() { #-PO: keep the double empty lines between sections, this is formatted a la LaTeX N("Congratulations, installation is complete. Remove the boot media and press return to reboot. For information on fixes which are available for this release of Mandriva Linux, consult the Errata available from: %s Information on configuring your system is available in the post install chapter of the Official Mandriva Linux User's Guide.", N("http://www.mandrivalinux.com/en/errata.php3")); } 1;