diff options
Diffstat (limited to 'src/usr/local/www')
-rw-r--r-- | src/usr/local/www/firewall_aliases_edit.php | 34 | ||||
-rw-r--r-- | src/usr/local/www/firewall_nat_edit.php | 15 | ||||
-rw-r--r-- | src/usr/local/www/firewall_nat_out_edit.php | 12 | ||||
-rw-r--r-- | src/usr/local/www/firewall_rules_edit.php | 40 | ||||
-rwxr-xr-x | src/usr/local/www/interfaces.php | 5 | ||||
-rw-r--r-- | src/usr/local/www/system_certmanager.php | 156 | ||||
-rw-r--r-- | src/usr/local/www/widgets/widgets/gateways.widget.php | 4 |
7 files changed, 232 insertions, 34 deletions
diff --git a/src/usr/local/www/firewall_aliases_edit.php b/src/usr/local/www/firewall_aliases_edit.php index fc4b8b0..4761d9f 100644 --- a/src/usr/local/www/firewall_aliases_edit.php +++ b/src/usr/local/www/firewall_aliases_edit.php @@ -611,6 +611,26 @@ $pattern_str = array( 'urltable_ports' => '.*' // Alias Name or URL ); +$title_str = array( + 'network' => 'An IPv4 network address like 1.2.3.0, an IPv6 network address like 1:2a:3b:ffff::0, IP address range, FQDN or an alias', + 'host' => 'An IPv4 address like 1.2.3.4, an IPv6 address like 1:2a:3b:ffff::1, IP address range, FQDN or an alias', + 'port' => 'A port number, port number range or an alias', + 'url' => 'URL', + 'url_ports' => 'URL', + 'urltable' => 'URL', + 'urltable_ports' => 'URL' +); + +$placeholder_str = array( + 'network' => 'Address', + 'host' => 'Address', + 'port' => 'Port', + 'url' => 'URL', + 'url_ports' => 'URL', + 'urltable' => 'URL', + 'urltable_ports' => 'URL' +); + $types = array( 'host' => gettext("Host(s)"), 'network' => gettext("Network(s)"), @@ -715,7 +735,7 @@ while ($counter < count($addresses)) { $group->add(new Form_IpAddress( 'address' . $counter, - $tab == 'port' ? 'Port':'Address', + 'Address', $address, 'ALIASV4V6' ))->addMask('address_subnet' . $counter, $address_subnet)->setWidth(4)->setPattern($pattern_str[$tab]); @@ -787,9 +807,15 @@ events.push(function() { // Set the input field pattern by tab type var patternstr = <?=json_encode($pattern_str);?>; - for (i = 0; i < <?=$counter;?>; i++) { - $('#address' + i).prop('pattern', patternstr[tab]); - } + var titlestr = <?=json_encode($title_str);?>; + var placeholderstr = <?=json_encode($placeholder_str);?>; + $("[id^='address']").each(function () { + if (/^address[0-9]+$/.test(this.id)) { + $('#' + this.id).prop('pattern', patternstr[tab]); + $('#' + this.id).prop('title', titlestr[tab]); + $('#' + this.id).prop('placeholder', placeholderstr[tab]); + } + }); // Hide and disable rows other than the first hideRowsAfter(1, (tab == 'urltable') || (tab == 'urltable_ports')); diff --git a/src/usr/local/www/firewall_nat_edit.php b/src/usr/local/www/firewall_nat_edit.php index 96869b5..83440ba 100644 --- a/src/usr/local/www/firewall_nat_edit.php +++ b/src/usr/local/www/firewall_nat_edit.php @@ -584,14 +584,16 @@ function build_dsttype_list() { $list[$ifent . 'ip'] = $ifdesc . ' address'; } } - + + //Temporary array so we can sort IPs + $templist = array(); if (is_array($config['virtualip']['vip'])) { foreach ($config['virtualip']['vip'] as $sn) { if (is_ipaddrv6($sn['subnet'])) { continue; } if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") { - $list[$sn['subnet'] . '/' . $sn['subnet_bits']] = 'Subnet: ' . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; + $templist[$sn['subnet'] . '/' . $sn['subnet_bits']] = 'Subnet: ' . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; if (isset($sn['noexpand'])) { continue; } @@ -602,13 +604,18 @@ function build_dsttype_list() { for ($i = 0; $i <= $len; $i++) { $snip = long2ip32($start+$i); - $list[$snip] = $snip . ' (' . $sn['descr'] . ')'; + $templist[$snip] = $snip . ' (' . $sn['descr'] . ')'; } } else { - $list[$sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; + $templist[$sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; } } } + + //Sort temp IP array and append onto main array + asort($templist); + $list = array_merge($list, $templist); + unset($templist); return($list); } diff --git a/src/usr/local/www/firewall_nat_out_edit.php b/src/usr/local/www/firewall_nat_out_edit.php index 92f9060..721eb9e 100644 --- a/src/usr/local/www/firewall_nat_out_edit.php +++ b/src/usr/local/www/firewall_nat_out_edit.php @@ -406,10 +406,12 @@ function build_target_list() { $list[""] = gettext('Interface Address'); + //Temporary array so we can sort IPs + $templist = array(); if (is_array($config['virtualip']['vip'])) { foreach ($config['virtualip']['vip'] as $sn) { if (($sn['mode'] == "proxyarp" || $sn['mode'] == "other") && $sn['type'] == "network") { - $list['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; + $templist['S' . $sn['subnet'] . '/' . $sn['subnet_bits']] = gettext('Subnet: ') . $sn['subnet'] . '/' . $sn['subnet_bits'] . ' (' . $sn['descr'] . ')'; if (isset($sn['noexpand'])) { continue; } @@ -419,13 +421,17 @@ function build_target_list() { for ($i = 0; $i <= $len; $i++) { $snip = long2ip32($start+$i); - $list['I' . $snip] = $snip . ' (' . $sn['descr'] . ')'; + $templist['I' . $snip] = $snip . ' (' . $sn['descr'] . ')'; } } else { - $list['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; + $templist['I' . $sn['subnet']] = $sn['subnet'] . ' (' . $sn['descr'] . ')'; } } } + asort($templist); + //Append sorted IP array onto main array + $list = array_merge($list, $templist); + unset($templist); foreach ($a_aliases as $alias) { if ($alias['type'] != "host") { diff --git a/src/usr/local/www/firewall_rules_edit.php b/src/usr/local/www/firewall_rules_edit.php index 171cab6..1c11768 100644 --- a/src/usr/local/www/firewall_rules_edit.php +++ b/src/usr/local/www/firewall_rules_edit.php @@ -295,6 +295,7 @@ if (isset($id) && $a_filter[$id]) { if ($_REQUEST['if']) { $pconfig['interface'] = $_REQUEST['if']; } + $pconfig['ipprotocol'] = "inet"; // other things depend on this, set a sensible default $pconfig['type'] = "pass"; $pconfig['proto'] = "tcp"; // for new blank rules, default=tcp, also ensures ports fields are visible $pconfig['src'] = "any"; @@ -319,6 +320,19 @@ if ($_POST['save']) { if (!array_key_exists($_POST['ipprotocol'], $icmplookup)) { $input_errors[] = gettext("The IP protocol is not recognized."); + unset($_POST['ipprotocol']); + } + + // add validation + input error for $_POST['interface'] + + $valid = ($_POST['interface'] == "FloatingRules" || isset($_POST['floating'])) ? ['pass','block','reject', 'match'] : ['pass','block','reject']; + if (!(is_string($_POST['type']) && in_array($_POST['type'], $valid))) { + $input_errors[] = gettext("A valid rule type is not selected."); + unset($_POST['type']); + } + + if (isset($_POST['tracker']) && !is_numericint($_POST['tracker'])) { + unset($_POST['tracker']); // silently unset hidden input if invalid } if (isset($a_filter[$id]['associated-rule-id'])) { @@ -328,7 +342,7 @@ if ($_POST['save']) { } } - if (($_POST['ipprotocol'] <> "") && ($_POST['gateway'] <> "")) { + if (isset($_POST['ipprotocol']) && $_POST['gateway'] <> '') { if (is_array($config['gateways']['gateway_group'])) { foreach ($config['gateways']['gateway_group'] as $gw_group) { if ($gw_group['name'] == $_POST['gateway'] && $_POST['ipprotocol'] != $a_gatewaygroups[$_POST['gateway']]['ipprotocol']) { @@ -423,6 +437,11 @@ if ($_POST['save']) { $pconfig = $_POST; + if (!isset($pconfig['ipprotocol'])) { + // other things depend on this, so ensure a valid value if none provided + $pconfig['ipprotocol'] = "inet"; + } + if (($_POST['proto'] == "icmp") && count($_POST['icmptype'])) { $pconfig['icmptype'] = implode(',', $_POST['icmptype']); } else { @@ -554,14 +573,14 @@ if ($_POST['save']) { } } if ((is_ipaddrv6($_POST['src']) || is_ipaddrv6($_POST['dst'])) && ($_POST['ipprotocol'] == "inet")) { - $input_errors[] = gettext("IPv6 addresses cannot be used in IPv4 rules."); + $input_errors[] = gettext("IPv6 addresses cannot be used in IPv4 rules (except within an alias)."); } if ((is_ipaddrv4($_POST['src']) || is_ipaddrv4($_POST['dst'])) && ($_POST['ipprotocol'] == "inet6")) { - $input_errors[] = gettext("IPv4 addresses can not be used in IPv6 rules."); + $input_errors[] = gettext("IPv4 addresses can not be used in IPv6 rules (except within an alias)."); } if ((is_ipaddr($_POST['src']) || is_ipaddr($_POST['dst'])) && ($_POST['ipprotocol'] == "inet46")) { - $input_errors[] = gettext("IPv4 and IPv6 addresses can not be used in rules that apply to both IPv4 and IPv6."); + $input_errors[] = gettext("IPv4 and IPv6 addresses can not be used in rules that apply to both IPv4 and IPv6 (except within an alias)."); } if ($_POST['srcbeginport'] > $_POST['srcendport']) { @@ -593,8 +612,8 @@ if ($_POST['save']) { } elseif (!isset($t) || count($t) == 0) { // not specified or none selected unset($_POST['icmptype']); - } else { - // check data + } elseif (isset($_POST['ipprotocol'])) { + // check data; if ipprotocol invalid then safe to skip this (we can't determine valid icmptypes, but input error already raised for ipprotocol) $bad_types = array(); if ((count($t) == 1 && !isset($t['any'])) || count($t) > 1) { // Only need to check valid if just one selected != "any", or >1 selected @@ -642,7 +661,7 @@ if ($_POST['save']) { $input_errors[] = gettext("Please select a gateway, normally the interface selected gateway, so the limiters work correctly"); } } - if (!empty($_POST['ruleid']) && !ctype_digit($_POST['ruleid'])) { + if (!empty($_POST['ruleid']) && !is_numericint($_POST['ruleid'])) { $input_errors[] = gettext('ID must be an integer'); } @@ -755,13 +774,12 @@ if ($_POST['save']) { $filterent['tracker'] = empty($_POST['tracker']) ? (int)microtime(true) : $_POST['tracker']; $filterent['type'] = $_POST['type']; + if (isset($_POST['interface'])) { $filterent['interface'] = $_POST['interface']; - } + } // FIXME: can $_POST['interface'] be unset at this point, if so then what? - if (isset($_POST['ipprotocol'])) { - $filterent['ipprotocol'] = $_POST['ipprotocol']; - } + $filterent['ipprotocol'] = $_POST['ipprotocol']; if ($_POST['tcpflags_any']) { $filterent['tcpflags_any'] = true; diff --git a/src/usr/local/www/interfaces.php b/src/usr/local/www/interfaces.php index e00856d..fd9965b 100755 --- a/src/usr/local/www/interfaces.php +++ b/src/usr/local/www/interfaces.php @@ -987,10 +987,7 @@ if ($_POST['apply']) { kill_dhclient_process($wancfg['if']); } if ($wancfg['ipaddrv6'] == "dhcp6") { - $pid = find_dhcp6c_process($wancfg['if']); - if ($pid) { - posix_kill($pid, SIGTERM); - } + kill_dhcp6client_process($wancfg['if'],true); } } $ppp = array(); diff --git a/src/usr/local/www/system_certmanager.php b/src/usr/local/www/system_certmanager.php index 777d416..7b5ea66 100644 --- a/src/usr/local/www/system_certmanager.php +++ b/src/usr/local/www/system_certmanager.php @@ -34,6 +34,7 @@ $cert_methods = array( "import" => gettext("Import an existing Certificate"), "internal" => gettext("Create an internal Certificate"), "external" => gettext("Create a Certificate Signing Request"), + "sign" => gettext("Sign a Certificate Signing Request") ); $cert_keylens = array("512", "1024", "2048", "3072", "4096", "7680", "8192", "15360", "16384"); @@ -81,7 +82,6 @@ foreach ($a_ca as $ca) { $act = $_REQUEST['act']; - if ($_POST['act'] == "del") { if (!isset($a_cert[$id])) { @@ -96,7 +96,6 @@ if ($_POST['act'] == "del") { exit; } - if ($act == "new") { $pconfig['method'] = $_POST['method']; $pconfig['keylen'] = "2048"; @@ -172,6 +171,7 @@ if ($act == "p12") { $args['friendly_name'] = $a_cert[$id]['descr']; $ca = lookup_ca($a_cert[$id]['caref']); + if ($ca) { $args['extracerts'] = openssl_x509_read(base64_decode($ca['crt'])); } @@ -212,6 +212,24 @@ if ($_POST['save']) { $pconfig = $_POST; /* input validation */ + if ($pconfig['method'] == "sign") { + $reqdfields = explode(" ", + "descr catosignwith"); + $reqdfieldsn = array( + gettext("Descriptive name"), + gettext("CA to sign with")); + + if (($_POST['csrtosign'] === "new") && (!strstr($_POST['csrpaste'], "BEGIN CERTIFICATE REQUEST") || !strstr($_POST['csrpaste'], "END CERTIFICATE REQUEST"))) { + $input_errors[] = gettext("This signing request does not appear to be valid."); + } + + if ( (($_POST['csrtosign'] === "new") && (strlen($_POST['keypaste']) > 0)) && (!strstr($_POST['keypaste'], "BEGIN PRIVATE KEY") || !strstr($_POST['keypaste'], "END PRIVATE KEY"))) { + $input_errors[] = gettext("This private does not appear to be valid."); + $input_errors[] = gettext("Key data field should be blank, or a valid x509 private key"); + } + + } + if ($pconfig['method'] == "import") { $reqdfields = explode(" ", "descr cert key"); @@ -222,6 +240,7 @@ if ($_POST['save']) { if ($_POST['cert'] && (!strstr($_POST['cert'], "BEGIN CERTIFICATE") || !strstr($_POST['cert'], "END CERTIFICATE"))) { $input_errors[] = gettext("This certificate does not appear to be valid."); } + if (cert_get_modulus($_POST['cert'], false) != prv_get_modulus($_POST['key'], false)) { $input_errors[] = gettext("The submitted private key does not match the submitted certificate data."); } @@ -267,6 +286,7 @@ if ($_POST['save']) { $altnames = array(); do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); + if ($pconfig['method'] != "import" && $pconfig['method'] != "existing") { /* subjectAltNames */ foreach ($_POST as $key => $value) { @@ -362,6 +382,48 @@ if ($_POST['save']) { if ($cert && $a_user) { $a_user[$userid]['cert'][] = $cert['refid']; } + } else if ($pconfig['method'] == "sign") { // Sign a CSR + $csrid = lookup_cert($pconfig['csrtosign']); + $caid = lookup_ca($pconfig['catosignwith']); + + // Read the CSR from $config, or if a new one, from the textarea + if ($pconfig['csrtosign'] === "new") { + $csr = $pconfig['csrpaste']; + } else { + $csr = base64_decode($csrid['csr']); + } + + $old_err_level = error_reporting(0); + + // Gather the information required for signed cert + $ca = base64_decode($caid['crt']); + $key = base64_decode($caid['prv']); + $duration = $pconfig['duration']; + $caref = $pconfig['catosignwith']; + $type = (cert_get_purpose($csrid)['server'] === "Yes") ? "server":"user"; + + // Sign the new cert and export it in x509 format + openssl_x509_export(openssl_csr_sign($csr, $ca, $key, $duration, ['x509_extensions' => 'v3_req']), $n509); + + // Gather the details required to save the new cert + $newcert = array(); + $newcert['refid'] = uniqid(); + $newcert['caref'] = $caref; + $newcert['descr'] = $pconfig['descr']; + $newcert['type'] = $type; + $newcert['crt'] = base64_encode($n509); + + if ($pconfig['csrtosign'] === "new") { + $newcert['prv'] = base64_encode($pconfig['keypaste']); + } else { + $newcert['prv'] = $csrid['prv']; + } + + // Add it to the config file + $config['cert'][] = $newcert; + + error_reporting($old_err_level); + } else { $cert = array(); $cert['refid'] = uniqid(); @@ -435,6 +497,7 @@ if ($_POST['save']) { } } } + error_reporting($old_err_level); if (isset($id) && $a_cert[$id]) { @@ -569,7 +632,7 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) { )); } - $section = new Form_Section('Add a New Certificate'); + $section = new Form_Section('Add/Sign a New Certificate'); if (!isset($id)) { $section->addInput(new Form_Select( @@ -588,6 +651,73 @@ if ($act == "new" || (($_POST['save'] == gettext("Save")) && $input_errors)) { ))->addClass('toggle-existing'); $form->add($section); + + // Return an array containing the IDs od all CAs + function list_cas() { + global $a_ca; + $allCas = array(); + + foreach ($a_ca as $ca) { + if ($ca['prv']) { + $allCas[$ca['refid']] = $ca['descr']; + } + } + + return $allCas; + } + + // Return an array containing the IDs od all CSRs + function list_csrs() { + global $config; + $allCsrs = array(); + + foreach ($config['cert'] as $cert) { + if ($cert['csr']) { + $allCsrs[$cert['refid']] = $cert['descr']; + } + } + + return ['new' => gettext('New CSR (Paste below)')] + $allCsrs; + } + + $section = new Form_Section('Sign CSR'); + $section->addClass('toggle-sign collapse'); + + $section->AddInput(new Form_Select( + 'catosignwith', + '*CA to sign with', + $pconfig['catosignwith'], + list_cas() + )); + + $section->AddInput(new Form_Select( + 'csrtosign', + '*CSR to sign', + isset($pconfig['csrtosign']) ? $pconfig['csrtosign'] : 'new', + list_csrs() + )); + + $section->addInput(new Form_Input( + 'duration', + '*Certificate duration (days)', + 'number', + $pconfig['duration'] ? $pconfig['duration']:'3650' + )); + + $section->addInput(new Form_Textarea( + 'csrpaste', + 'CSR data', + $pconfig['csrpaste'] + ))->setHelp('Paste a Certificate Signing Request in X.509 PEM format here.'); + + $section->addInput(new Form_Textarea( + 'keypaste', + 'Key data', + $pconfig['keypaste'] + ))->setHelp('Optionally paste a private key here. The key will be associated with the newly signed certificate in pfSense'); + + $form->add($section); + $section = new Form_Section('Import Certificate'); $section->addClass('toggle-import collapse'); @@ -1062,7 +1192,9 @@ foreach ($a_cert as $i => $cert): <td> <?php if (!$cert['csr']): ?> <a href="system_certmanager.php?act=exp&id=<?=$i?>" class="fa fa-certificate" title="<?=gettext("Export Certificate")?>"></a> - <a href="system_certmanager.php?act=key&id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a> + <?php if ($cert['prv']): ?> + <a href="system_certmanager.php?act=key&id=<?=$i?>" class="fa fa-key" title="<?=gettext("Export Key")?>"></a> + <?php endif?> <a href="system_certmanager.php?act=p12&id=<?=$i?>" class="fa fa-archive" title="<?=gettext("Export P12")?>"></a> <?php else: ?> <a href="system_certmanager.php?act=csr&id=<?=$i?>" class="fa fa-pencil" title="<?=gettext("Update CSR")?>"></a> @@ -1086,7 +1218,7 @@ foreach ($a_cert as $i => $cert): <nav class="action-buttons"> <a href="?act=new" class="btn btn-success btn-sm"> <i class="fa fa-plus icon-embed-btn"></i> - <?=gettext("Add")?> + <?=gettext("Add/Sign")?> </a> </nav> <?php @@ -1113,7 +1245,6 @@ events.push(function() { } $subject = cert_get_subject_array($ca['crt']); - ?> case "<?=$ca['refid'];?>": $('#dn_country').val("<?=$subject[0]['v'];?>"); @@ -1129,15 +1260,28 @@ events.push(function() { } } + function set_csr_ro() { + var newcsr = ($('#csrtosign').val() == "new"); + + $('#csrpaste').attr('readonly', !newcsr); + $('#keypaste').attr('readonly', !newcsr); + setRequired('csrpaste', newcsr); + } + // ---------- Click checkbox handlers --------------------------------------------------------- $('#caref').on('change', function() { internalca_change(); }); + $('#csrtosign').change(function () { + set_csr_ro(); + }); + // ---------- On initial page load ------------------------------------------------------------ internalca_change(); + set_csr_ro(); // Suppress "Delete row" button if there are fewer than two rows checkLastRow(); diff --git a/src/usr/local/www/widgets/widgets/gateways.widget.php b/src/usr/local/www/widgets/widgets/gateways.widget.php index d414a5e..355dd4a 100644 --- a/src/usr/local/www/widgets/widgets/gateways.widget.php +++ b/src/usr/local/www/widgets/widgets/gateways.widget.php @@ -310,8 +310,8 @@ function compose_table_body_contents() { $bgcolor = "info"; // lightblue } - $rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['delay']) : gettext("Pending")) . "</td>\n"; - $rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['stddev']) : gettext("Pending")) . "</td>\n"; + $rtnstr .= "<td>" . ($gateways_status[$gname] ? ($gateways_status[$gname]['delay'] ? htmlspecialchars(number_format((float)rtrim($gateways_status[$gname]['delay'], "ms"), 1)) . "ms" : '') : gettext("Pending")) . "</td>\n"; + $rtnstr .= "<td>" . ($gateways_status[$gname] ? ($gateways_status[$gname]['stddev'] ? htmlspecialchars(number_format((float)rtrim($gateways_status[$gname]['stddev'], "ms"), 1)) . "ms" : '') : gettext("Pending")) . "</td>\n"; $rtnstr .= "<td>" . ($gateways_status[$gname] ? htmlspecialchars($gateways_status[$gname]['loss']) : gettext("Pending")) . "</td>\n"; $rtnstr .= '<td class="bg-' . $bgcolor . '">' . $online . "</td>\n"; $rtnstr .= "</tr>\n"; |