# ipsec-lib.pl # Common functions for managing the freeswan config file # XXX check for new errors in log after applying # XXX option to download connection as .conf file, and upload an existing # .conf file for addition BEGIN { push(@INC, ".."); }; use WebminCore; &init_config(); # get_config([file]) # Returns an array of configured connections sub get_config { local $file = $_[0] || $config{'file'}; local (@rv, $sect); local $lnum = 0; local $fh = "CONF".$get_config_fh++; open($fh, "<".$file); while(<$fh>) { s/\r|\n//g; s/#.*$//; if (/^\s*([^= ]+)\s*=\s*"([^"]*)"/ || /^\s*([^= ]+)\s*=\s*'([^"]*)'/ || /^\s*([^= ]+)\s*=\s*(\S+)/) { # Directive within a section if ($sect) { if ($sect->{'values'}->{lc($1)}) { $sect->{'values'}->{lc($1)} .= "\0".$2; } else { $sect->{'values'}->{lc($1)} = $2; } $sect->{'eline'} = $lnum; } } elsif (/^\s*include\s+(\S+)/) { # Including possibly multiple files local $inc = $1; if ($inc !~ /^\//) { $file =~ /^(.*)\//; $inc = "$1/$inc"; } local $g; foreach $g (glob($inc)) { local @inc = &get_config($g); map { $_->{'index'} += scalar(@rv) } @inc; push(@rv, @inc); } } elsif (/^\s*(\S+)\s+(\S+)/) { # Start of a section $sect = { 'name' => $1, 'value' => $2, 'line' => $lnum, 'eline' => $lnum, 'file' => $file, 'index' => scalar(@rv), 'values' => { } }; push(@rv, $sect); } $lnum++; } close($fh); return @rv; } # create_conn(&conn) # Add a new connection to the config file sub create_conn { local $lref = &read_file_lines($_[0]->{'file'} || $config{'file'}); push(@$lref, "", &conn_lines($_[0])); &flush_file_lines(); } # modify_conn(&conn) sub modify_conn { local $lref = &read_file_lines($_[0]->{'file'}); splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1, &conn_lines($_[0])); &flush_file_lines(); } # delete_conn(&conn) sub delete_conn { local $lref = &read_file_lines($_[0]->{'file'}); splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1); &flush_file_lines(); } # swap_conns(&conn1, &conn2) # Swaps two connections in the config file sub swap_conns { local ($first, $second) = @_; if ($first->{'line'} > $second->{'line'}) { ($first, $second) = ($second, $first); } local $lref1 = &read_file_lines($first->{'file'}); local $lref2 = &read_file_lines($second->{'file'}); splice(@$lref2, $second->{'line'}, $second->{'eline'} - $second->{'line'} + 1, @$lref1[$first->{'line'} .. $first->{'eline'}]); splice(@$lref2, $first->{'line'}, $first->{'eline'} - $first->{'line'} + 1, @$lref1[$second->{'line'} .. $second->{'eline'}]); &flush_file_lines(); } # conn_lines(&conn) sub conn_lines { local @rv; push(@rv, $_[0]->{'name'}." ".$_[0]->{'value'}); foreach $o (sort { $a cmp $b } keys %{$_[0]->{'values'}}) { local $v = $_[0]->{'values'}->{$o}; local $vv; foreach $vv (split(/\0/, $v)) { if ($vv =~ /\s|=/) { push(@rv, "\t".$o."=\"".$vv."\""); } else { push(@rv, "\t".$o."=".$vv); } } } return @rv; } # is_ipsec_running() sub is_ipsec_running { local $out = `$config{'ipsec'} auto --status 2>&1`; return $? || $out =~ /not running/i ? 0 : 1; } # get_public_key() # Returns this system's public key sub get_public_key { local $out = `$config{'ipsec'} showhostkey --file '$config{'secrets'}' --left 2>&1`; if ($out =~ /leftrsasigkey=(\S+)/) { return $1; } return undef; } # get_public_key_dns() # Returns the flags, protocol, algorithm and key data for the public key, # suitable for creating a DNS KEY record sub get_public_key_dns { local $out = `$config{'ipsec'} showhostkey --file '$config{'secrets'}' 2>&1`; if ($out =~ /KEY\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) { return ($1, $2, $3, $4); } else { # Try with new --key argument $out = `$config{'ipsec'} showhostkey --key --file '$config{'secrets'}' 2>&1`; if ($out =~ /KEY\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) { return ($1, $2, $3, $4); } } return (); } # list_policies() # Returns a list of all policy files sub list_policies { local ($f, @rv); opendir(DIR, $config{'policies_dir'}); while($f = readdir(DIR)) { push(@rv, $f) if ($f !~ /^\./ && $f !~ /\.rpmsave$/); } closedir(DIR); return @rv; } # read_policy(name) sub read_policy { local @rv; open(FILE, "<$config{'policies_dir'}/$_[0]"); while(<FILE>) { push(@rv, "$1/$2") if (/^\s*([0-9\.]+)\/(\d+)/); } close(FILE); return @rv; } # write_policy(name, &nets) sub write_policy { local $lref = &read_file_lines("$config{'policies_dir'}/$_[0]"); local $l = 0; foreach $p (@{$_[1]}) { while($l < @$lref && $lref->[$l] !~ /^\s*([0-9\.]+)\/(\d+)/) { $l++; } if ($l < @$lref) { # Found line to replace $lref->[$l] = $p; } else { # Add at end push(@$lref, $p); } $l++; } while($l < @$lref) { if ($lref->[$l] =~ /^\s*([0-9\.]+)\/(\d+)/) { splice(@$lref, $l, 1); } else { $l++; } } &flush_file_lines(); } # wrap_lines(text, width) # Given a multi-line string, return an array of lines wrapped to # the given width sub wrap_lines { local $rest = $_[0]; local @rv; while(length($rest) > $_[1]) { push(@rv, substr($rest, 0, $_[1])); $rest = substr($rest, $_[1]); } push(@rv, $rest) if ($rest ne ''); return @rv; } # before_start() # Work out which log file IPsec messages go to, and record the size sub before_start { @ipsec_logfiles = ( $config{'logfile'} ); if (&foreign_check("syslog")) { # Find all syslog logfiles &foreign_require("syslog", "syslog-lib.pl"); local $conf = &syslog::get_config(); foreach $c (@$conf) { push(@ipsec_logfiles, $c->{'file'}) if ($c->{'file'} && -f $c->{'file'}); } } @ipsec_logfiles = &unique(@ipsec_logfiles); @ipsec_logfile_sizes = map { local @st = stat($_); $st[7] } @ipsec_logfiles; } # after_start() # Check any new IPsec-related messages in the log for errors sub after_start { # Give the server a chance to start sleep(5); # Look for new error messages local $i; for($i=0; $i<@ipsec_logfiles; $i++) { open(LOG, "<".$ipsec_logfiles[$i]) || next; seek(LOG, $ipsec_logfile_sizes[$i], 0); while(<LOG>) { s/\r|\n//g; if (/ipsec/i && /error/i) { s/^(\S+)\s+(\d+)\s+(\d+:\d+:\d+)\s+(\S+)\s+//; push(@errs, $_); } } close(LOG); } # Fail if there were any if (@errs) { &error(&text('start_elog', "<p><tt>".join("<br>", @errs)."</tt><br>")); } } # get_ipsec_version(&out) sub get_ipsec_version { local $out = `$config{'ipsec'} --version 2>&1`; ${$_[0]} = $out; return $out =~ /(FreeS\/WAN|Openswan|StrongSWAN|Libreswan)\s+([^ \n\(]+)/i ? ($2,$1) : (undef); } # got_secret() # Returns 1 if a valid secret key file exists, 0 if not sub got_secret { local $gotkey; open(SEC, "<".$config{'secrets'}) || return 0; while(<SEC>) { s/\r|\n//g; s/#.*$//; if (/Modulus:\s*(\S+)/) { $gotkey = 1; } } close(SEC); return $gotkey; } # expand_conf(&config) sub expand_conf { my $conf = shift; for my $n (0..scalar(@$conf)-1) { $conn = @$conf[$n]; foreach my $key (keys(%{$conn->{'values'}})) { $expanded{$conn->{'value'}}->{$key} = $conn->{'values'}->{$key}; } } # now go through and expand alsos foreach my $k (keys(%expanded)) { $conn = \%{$expanded{$k}}; # XXX - only supporing a single level of redirection # - this should be moved into a function that could be called # recursively if ($$conn{'also'}) { foreach my $also (split(/\000/, $$conn{'also'})) { foreach my $i (keys(%{$expanded{$also}})) { $$conn{$i} = $expanded{$also}{$i}; } } # there is only one also key next; } } return %expanded; } # restart_ipsec() # Apply the current configuration, and return an error message on failure or # undef on success sub restart_ipsec { local $cmd = $config{'restart_cmd'} || "($config{'stop_cmd'} && $config{'start_cmd'})"; &before_start(); local $out = &backquote_logged("$cmd 2>&1"); if ($?) { return "<pre>$out</pre>"; } &after_start(); return undef; } # list_secrets() # Returns a list of IPsec secret keys sub list_secrets { if (!scalar(@list_secrets_cache)) { local (@lines); local $lnum = 0; open(SEC, "<".$config{'secrets'}); while(<SEC>) { s/\r|\n//g; s/^\s*#.*$//; if (/^(\S.*)$/) { push(@lines, { 'value' => $1, 'line' => $lnum, 'eline' => $lnum }); } elsif (/^\s+(.*)/ && @lines) { $lines[$#rv]->{'value'} .= "\n".$1; $lines[$#rv]->{'eline'} = $lnum; } $lnum++; } close(SEC); # Turn joined lines into secrets local $l; foreach $l (@lines) { $l->{'value'} =~ /^([^:]*)\s*:\s+(\S+)\s+((.|\n)*)$/ || next; local $sec = { 'type' => $2, 'name' => $1, 'value' => $3, 'line' => $l->{'line'}, 'eline' => $l->{'eline'}, 'idx' => scalar(@list_secrets_cache), }; $sec->{'name'} =~ s/\n/ /g; $sec->{'name'} =~ s/\s+$//; push(@list_secrets_cache, $sec); } } return @list_secrets_cache; } # delete_secret(&sec) # Removes one secret from the file sub delete_secret { local $lref = &read_file_lines($config{'secrets'}); local $lines = $_[0]->{'eline'} - $_[0]->{'line'} + 1; splice(@$lref, $_[0]->{'line'}, $lines); &flush_file_lines(); local $s; splice(@list_secrets_cache, $_[0]->{'idx'}, 1); foreach $s (@list_secrets_cache) { if ($s->{'line'} > $_[0]->{'line'}) { $s->{'line'} -= $lines; $s->{'eline'} -= $lines; } if ($s->{'idx'} > $_[0]->{'idx'}) { $s->{'idx'}--; } } } # create_secret(&sec) # Add one secret to the file sub create_secret { &list_secrets(); # force cache init local $lref = &read_file_lines($config{'secrets'}); $_[0]->{'line'} = scalar(@$lref); local @lines = &secret_lines($_[0]); push(@$lref, @lines); &flush_file_lines(); $_[0]->{'eline'} = scalar(@$lref)-1; $_[0]->{'idx'} = scalar(@list_secrets_cache); push(@list_secrets_cache, $_[0]); } # modify_secret(&sec) # Update one secret in the file sub modify_secret { local $lref = &read_file_lines($config{'secrets'}); local @newlines = &secret_lines($_[0]); local $oldlines = $_[0]->{'eline'} - $_[0]->{'line'} + 1; splice(@$lref, $_[0]->{'line'}, $oldlines, @newlines); &flush_file_lines(); local $s; foreach $s (@list_secrets_cache) { if ($s ne $_[0] && $s->{'line'} > $_[0]->{'line'}) { $s->{'line'} += @newlines - $oldlines; $s->{'eline'} += @newlines - $oldlines; } } $_[0]->{'eline'} += @newlines - $oldlines; } sub secret_lines { local $str = $_[0]->{'name'} ? $_[0]->{'name'}." : " : ": "; $str .= uc($_[0]->{'type'}); $str .= " ".$_[0]->{'value'}; return split(/\n/, $str); } @rsa_attribs = ( "Modulus", "PublicExponent", "PrivateExponent", "Prime1", "Prime2", "Exponent1", "Exponent2", "Coefficient" ); 1;
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
help | Folder | 0755 |
|
|
images | Folder | 0755 |
|
|
lang | Folder | 0755 |
|
|
CHANGELOG | File | 239 B | 0644 |
|
backup_config.pl | File | 694 B | 0755 |
|
bootup.cgi | File | 381 B | 0755 |
|
config | File | 241 B | 0644 |
|
config-AlmaLinux-7.0-ALL | File | 235 B | 0644 |
|
config-Amazon-Linux-2-ALL | File | 235 B | 0644 |
|
config-CentOS-Linux-7.0-ALL | File | 235 B | 0644 |
|
config-CentOS-Stream-Linux-8.0-ALL | File | 235 B | 0644 |
|
config-CloudLinux-8.0-ALL | File | 235 B | 0644 |
|
config-Oracle-Linux-8.0-ALL | File | 235 B | 0644 |
|
config-Redhat-Enterprise-Linux-7.0-ALL | File | 235 B | 0644 |
|
config-Rocky-Linux-7.0-ALL | File | 235 B | 0644 |
|
config-Scientific-Linux-7.0-ALL | File | 235 B | 0644 |
|
config-coherent-linux | File | 256 B | 0644 |
|
config-debian-linux | File | 235 B | 0644 |
|
config-mandrake-linux | File | 250 B | 0644 |
|
config-openSUSE-Linux-15.0-ALL | File | 229 B | 0644 |
|
config-openmamba-linux | File | 250 B | 0644 |
|
config-redhat-linux | File | 256 B | 0644 |
|
config-suse-linux-8.2-ALL | File | 235 B | 0644 |
|
config-syno-linux | File | 241 B | 0644 |
|
config-trustix-linux | File | 235 B | 0644 |
|
config.info | File | 342 B | 0644 |
|
config.info.ca | File | 381 B | 0644 |
|
config.info.de | File | 386 B | 0644 |
|
config.info.es | File | 401 B | 0644 |
|
config.info.fr | File | 371 B | 0644 |
|
config.info.nl | File | 388 B | 0644 |
|
config.info.no | File | 357 B | 0644 |
|
edit.cgi | File | 8.25 KB | 0755 |
|
edit_config.cgi | File | 3.6 KB | 0755 |
|
edit_policy.cgi | File | 1.3 KB | 0755 |
|
edit_secret.cgi | File | 2.1 KB | 0755 |
|
export.cgi | File | 934 B | 0755 |
|
export_form.cgi | File | 776 B | 0755 |
|
import.cgi | File | 1.61 KB | 0755 |
|
import_form.cgi | File | 776 B | 0755 |
|
index.cgi | File | 5.21 KB | 0755 |
|
install_check.pl | File | 450 B | 0755 |
|
ipsec-lib.pl | File | 10.33 KB | 0755 |
|
list_secrets.cgi | File | 1.08 KB | 0755 |
|
log_parser.pl | File | 820 B | 0755 |
|
module.info | File | 184 B | 0644 |
|
module.info.af | File | 0 B | 0644 |
|
module.info.af.auto | File | 130 B | 0644 |
|
module.info.ar | File | 0 B | 0644 |
|
module.info.ar.auto | File | 179 B | 0644 |
|
module.info.be | File | 0 B | 0644 |
|
module.info.be.auto | File | 160 B | 0644 |
|
module.info.bg | File | 0 B | 0644 |
|
module.info.bg.auto | File | 169 B | 0644 |
|
module.info.ca | File | 122 B | 0644 |
|
module.info.ca.auto | File | 14 B | 0644 |
|
module.info.cs | File | 29 B | 0644 |
|
module.info.cs.auto | File | 79 B | 0644 |
|
module.info.da | File | 0 B | 0644 |
|
module.info.da.auto | File | 133 B | 0644 |
|
module.info.de | File | 115 B | 0644 |
|
module.info.de.auto | File | 14 B | 0644 |
|
module.info.el | File | 0 B | 0644 |
|
module.info.el.auto | File | 221 B | 0644 |
|
module.info.es | File | 36 B | 0644 |
|
module.info.es.auto | File | 91 B | 0644 |
|
module.info.eu | File | 0 B | 0644 |
|
module.info.eu.auto | File | 136 B | 0644 |
|
module.info.fa | File | 0 B | 0644 |
|
module.info.fa.auto | File | 181 B | 0644 |
|
module.info.fi | File | 0 B | 0644 |
|
module.info.fi.auto | File | 122 B | 0644 |
|
module.info.fr | File | 0 B | 0644 |
|
module.info.fr.auto | File | 134 B | 0644 |
|
module.info.he | File | 0 B | 0644 |
|
module.info.he.auto | File | 129 B | 0644 |
|
module.info.hr | File | 0 B | 0644 |
|
module.info.hr.auto | File | 131 B | 0644 |
|
module.info.hu | File | 0 B | 0644 |
|
module.info.hu.auto | File | 148 B | 0644 |
|
module.info.it | File | 0 B | 0644 |
|
module.info.it.auto | File | 133 B | 0644 |
|
module.info.ja | File | 0 B | 0644 |
|
module.info.ja.auto | File | 164 B | 0644 |
|
module.info.ko | File | 0 B | 0644 |
|
module.info.ko.auto | File | 149 B | 0644 |
|
module.info.lt | File | 0 B | 0644 |
|
module.info.lt.auto | File | 146 B | 0644 |
|
module.info.lv | File | 0 B | 0644 |
|
module.info.lv.auto | File | 121 B | 0644 |
|
module.info.ms | File | 122 B | 0644 |
|
module.info.ms.auto | File | 14 B | 0644 |
|
module.info.mt | File | 0 B | 0644 |
|
module.info.mt.auto | File | 127 B | 0644 |
|
module.info.nl | File | 31 B | 0644 |
|
module.info.nl.auto | File | 88 B | 0644 |
|
module.info.no | File | 32 B | 0644 |
|
module.info.no.auto | File | 100 B | 0644 |
|
module.info.pl | File | 0 B | 0644 |
|
module.info.pl.auto | File | 123 B | 0644 |
|
module.info.pt | File | 0 B | 0644 |
|
module.info.pt.auto | File | 133 B | 0644 |
|
module.info.pt_BR | File | 0 B | 0644 |
|
module.info.pt_BR.auto | File | 142 B | 0644 |
|
module.info.ro | File | 0 B | 0644 |
|
module.info.ro.auto | File | 133 B | 0644 |
|
module.info.ru | File | 0 B | 0644 |
|
module.info.ru.auto | File | 180 B | 0644 |
|
module.info.sk | File | 0 B | 0644 |
|
module.info.sk.auto | File | 112 B | 0644 |
|
module.info.sl | File | 0 B | 0644 |
|
module.info.sl.auto | File | 126 B | 0644 |
|
module.info.sv | File | 0 B | 0644 |
|
module.info.sv.auto | File | 124 B | 0644 |
|
module.info.th | File | 0 B | 0644 |
|
module.info.th.auto | File | 225 B | 0644 |
|
module.info.tr | File | 0 B | 0644 |
|
module.info.tr.auto | File | 134 B | 0644 |
|
module.info.uk | File | 0 B | 0644 |
|
module.info.uk.auto | File | 178 B | 0644 |
|
module.info.ur | File | 0 B | 0644 |
|
module.info.ur.auto | File | 220 B | 0644 |
|
module.info.vi | File | 0 B | 0644 |
|
module.info.vi.auto | File | 131 B | 0644 |
|
module.info.zh | File | 0 B | 0644 |
|
module.info.zh.auto | File | 114 B | 0644 |
|
module.info.zh_TW | File | 0 B | 0644 |
|
module.info.zh_TW.auto | File | 123 B | 0644 |
|
newkey.cgi | File | 388 B | 0755 |
|
restart.cgi | File | 210 B | 0755 |
|
save.cgi | File | 4.8 KB | 0755 |
|
save_config.cgi | File | 1.8 KB | 0755 |
|
save_policy.cgi | File | 717 B | 0755 |
|
save_secret.cgi | File | 1.53 KB | 0755 |
|
showkey.cgi | File | 861 B | 0755 |
|
start.cgi | File | 281 B | 0755 |
|
stop.cgi | File | 243 B | 0755 |
|
up.cgi | File | 783 B | 0755 |
|