diff --git a/src/etc/inc/system.inc b/src/etc/inc/system.inc index 33d674d9ff7..ceaf880784d 100644 --- a/src/etc/inc/system.inc +++ b/src/etc/inc/system.inc @@ -2327,6 +2327,7 @@ function system_ntp_configure() { $driftfile = "/var/db/ntpd.drift"; $statsdir = "/var/log/ntp"; $gps_device = '/dev/gps0'; + $ntp_keyid = config_get_path('ntpd/serverauthkeyid') ?? '1'; safe_mkdir($statsdir); @@ -2356,7 +2357,7 @@ function system_ntp_configure() { /* set NTP server authentication key */ if (config_get_path('ntpd/serverauth') == 'yes') { - $ntpkeyscfg = "1 " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n"; + $ntpkeyscfg = "{$ntp_keyid} " . strtoupper(config_get_path('ntpd/serverauthalgo')) . " " . base64_decode(config_get_path('ntpd/serverauthkey')) . "\n"; if (!@file_put_contents("{$g['varetc_path']}/ntp.keys", $ntpkeyscfg)) { log_error(sprintf(gettext("Could not open %s/ntp.keys for writing"), g_get('varetc_path'))); return; @@ -2373,9 +2374,9 @@ function system_ntp_configure() { if (config_get_path('ntpd/serverauth') == 'yes') { $ntpcfg .= "# Authentication settings \n"; $ntpcfg .= "keys /var/etc/ntp.keys \n"; - $ntpcfg .= "trustedkey 1 \n"; - $ntpcfg .= "requestkey 1 \n"; - $ntpcfg .= "controlkey 1 \n"; + $ntpcfg .= "trustedkey {$ntp_keyid} \n"; + $ntpcfg .= "requestkey {$ntp_keyid} \n"; + $ntpcfg .= "controlkey {$ntp_keyid} \n"; $ntpcfg .= "\n"; } @@ -2552,6 +2553,9 @@ function system_ntp_configure() { if (substr_count(config_get_path('ntpd/noselect'), $ts)) { $ntpcfg .= ' noselect'; } + if (config_get_path('ntpd/serverauth') == 'yes' && !substr_count(config_get_path('ntpd/ispool'), $ts) && substr_count(config_get_path('ntpd/isauth'), $ts)) { + $ntpcfg .= " key {$ntp_keyid} "; + } $ntpcfg .= "\n"; } unset($ts); diff --git a/src/usr/local/www/services_ntpd.php b/src/usr/local/www/services_ntpd.php index 6fd495ff2f8..4a47e42b1c0 100644 --- a/src/usr/local/www/services_ntpd.php +++ b/src/usr/local/www/services_ntpd.php @@ -84,6 +84,13 @@ (substr_compare($pconfig["server{$i}"], $auto_pool_suffix, strlen($pconfig["server{$i}"]) - strlen($auto_pool_suffix), strlen($auto_pool_suffix)) === 0))) { $input_errors[] = gettext("It is not possible to use 'No Select' for pools."); } + if (isset($pconfig["servauth{$i}"]) && (($pconfig["servistype{$i}"] == 'pool') || + (substr_compare($pconfig["server{$i}"], $auto_pool_suffix, strlen($pconfig["server{$i}"]) - strlen($auto_pool_suffix), strlen($auto_pool_suffix)) === 0))) { + $input_errors[] = gettext("It is not possible to use 'Authenticated' for pools."); + } + if (isset($pconfig["servauth{$i}"]) && empty($pconfig['serverauth'])) { + $input_errors[] = gettext("The NTP authentication key information must be set to use 'Authenticated' for a server or peer."); + } if (!empty($pconfig["server{$i}"]) && !is_domain($pconfig["server{$i}"]) && !is_ipaddr($pconfig["server{$i}"])) { $input_errors[] = gettext("NTP Time Server names must be valid domain names, IPv4 addresses, or IPv6 addresses"); @@ -99,6 +106,12 @@ if (isset($pconfig['serverauth'])) { if (empty($pconfig['serverauthkey'])) { $input_errors[] = gettext("The supplied value for NTP Authentication key can't be empty."); + } elseif (empty($pconfig['serverauthkeyid'])) { + $input_errors[] = gettext("The authentication Key ID can't be empty."); + } elseif (!ctype_digit($pconfig['serverauthkeyid'])) { + $input_errors[] = gettext("The authentication Key ID must be a positive integer."); + } elseif ($pconfig['serverauthkeyid'] < 1 || $pconfig['serverauthkeyid'] > 65535) { + $input_errors[] = gettext("The authentication Key ID must be between 1-65535."); } elseif (($pconfig['serverauthalgo'] == 'md5') && ((strlen($pconfig['serverauthkey']) > 20) || !ctype_print($pconfig['serverauthkey']))) { $input_errors[] = gettext("The supplied value for NTP Authentication key for MD5 digest must be from 1 to 20 printable characters."); @@ -123,6 +136,7 @@ config_del_path('ntpd/noselect'); config_del_path('ntpd/ispool'); config_del_path('ntpd/ispeer'); + config_del_path('ntpd/isauth'); $timeservers = ''; for ($i = 0; $i < NUMTIMESERVERS; $i++) { @@ -135,6 +149,9 @@ if (isset($_POST["servselect{$i}"])) { $config['ntpd']['noselect'] .= "{$tserver} "; } + if (isset($_POST["servauth{$i}"])) { + $config['ntpd']['isauth'] .= "{$tserver} "; + } if ($_POST["servistype{$i}"] == 'pool') { $config['ntpd']['ispool'] .= "{$tserver} "; } elseif ($_POST["servistype{$i}"] == 'peer') { @@ -212,10 +229,12 @@ if (!empty($_POST['serverauth'])) { config_set_path('ntpd/serverauth', $_POST['serverauth']); config_set_path('ntpd/serverauthkey', base64_encode(trim($_POST['serverauthkey']))); + config_set_path('ntpd/serverauthkeyid', $_POST['serverauthkeyid']); config_set_path('ntpd/serverauthalgo', $_POST['serverauthalgo']); } elseif (isset($config['ntpd']['serverauth'])) { config_del_path('ntpd/serverauth'); config_del_path('ntpd/serverauthkey'); + config_del_path('ntpd/serverauthkeyid'); config_del_path('ntpd/serverauthalgo'); } @@ -319,20 +338,27 @@ function build_interface_list() { ['placeholder' => 'Hostname'] ))->setWidth(3); - $group->add(new Form_Checkbox( + $group->add(new Form_Checkbox( 'servprefer' . $counter, null, null, isset($config['ntpd']['prefer']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['prefer'], $timeservers[$counter]) ))->sethelp('Prefer'); - $group->add(new Form_Checkbox( + $group->add(new Form_Checkbox( 'servselect' . $counter, null, null, isset($config['ntpd']['noselect']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['noselect'], $timeservers[$counter]) ))->sethelp('No Select'); + $group->add(new Form_Checkbox( + 'servauth' . $counter, + null, + null, + isset($config['ntpd']['isauth']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['isauth'], $timeservers[$counter]) + ))->setHelp('Authenticated'); + if ((substr_compare($timeservers[$counter], $auto_pool_suffix, strlen($timeservers[$counter]) - strlen($auto_pool_suffix), strlen($auto_pool_suffix)) === 0) || (isset($config['ntpd']['ispool']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['ispool'], $timeservers[$counter]))) { $servertype = 'pool'; } elseif (isset($config['ntpd']['ispeer']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['ispeer'], $timeservers[$counter])) { @@ -540,9 +566,18 @@ function build_interface_list() { $group = new Form_Group('Authentication key'); $group->addClass('ntpserverauth'); -$group->add(new Form_IpAddress( +$group->add(new Form_Input( + 'serverauthkeyid', + 'Key ID', + null, + $pconfig['serverauthkeyid'], + ['placeholder' => 'Key ID', 'type' => 'number', 'min' => 1, 'max' => 65535, 'step' => 1] +))->setWidth(2)->setHelp('ID associated with the authentication key'); + +$group->add(new Form_Input( 'serverauthkey', 'NTP Authentication key', + 'text', base64_decode($pconfig['serverauthkey']), ['placeholder' => 'NTP Authentication key'] ))->setHelp( @@ -557,7 +592,7 @@ function build_interface_list() { null, $pconfig['serverauthalgo'], $ntp_auth_halgos -))->setWidth(3)->setHelp('Digest algorithm'); +))->setWidth(2)->setHelp('Digest algorithm'); $section->add($group); diff --git a/src/usr/local/www/status_ntpd.php b/src/usr/local/www/status_ntpd.php index 0475344d2cb..2887edb293e 100644 --- a/src/usr/local/www/status_ntpd.php +++ b/src/usr/local/www/status_ntpd.php @@ -52,10 +52,28 @@ $inet_version = " -4"; } - exec('/usr/local/sbin/ntpq -pnw ' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output); + exec('/usr/local/sbin/ntpq -pnw' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]+/," ")}1\'', $ntpq_output); + exec('/usr/local/sbin/ntpq -c associations' . $inet_version . ' | /usr/bin/tail +3 | /usr/bin/awk -v RS= \'{gsub(/\n[[:space:]][[:space:]]\n+/," ")}1\'', $ntpq_associations_output); $ntpq_servers = array(); - foreach ($ntpq_output as $line) { + $ntpq_server_responses = array(); + + foreach ($ntpq_associations_output as $i => $line) { + $associations_response = array(); + $peerinfo = preg_split("/[\s\t]+/", $line); + $server['ind'] = $peerinfo[1]; + $associations_response['assid'] = $peerinfo[2]; + $associations_response['status_word'] = $peerinfo[3]; + $associations_response['conf'] = $peerinfo[4]; + $associations_response['reach'] = $peerinfo[5]; + $associations_response['auth'] = $peerinfo[6]; + $associations_response['condition'] = $peerinfo[7]; + $associations_response['last_event'] = $peerinfo[8]; + $associations_response['cnt'] = $peerinfo[9]; + $ntpq_server_responses[$i] = $associations_response; + } + + foreach ($ntpq_output as $i => $line) { $server = array(); $status_char = substr($line, 0, 1); $line = substr($line, 1); @@ -72,6 +90,15 @@ $server['offset'] = $peerinfo[8]; $server['jitter'] = $peerinfo[9]; + $server['ind'] = $ntpq_server_responses[$i]['ind']; + $server['assid'] = $ntpq_server_responses[$i]['assid']; + $server['status_word'] = $ntpq_server_responses[$i]['status_word']; + $server['conf'] = $ntpq_server_responses[$i]['conf']; + $server['auth'] = $ntpq_server_responses[$i]['auth']; + $server['condition'] = $ntpq_server_responses[$i]['condition']; + $server['last_event'] = $ntpq_server_responses[$i]['last_event']; + $server['cnt'] = $ntpq_server_responses[$i]['cnt']; + switch ($status_char) { case " ": if ($server['refid'] == ".POOL.") { @@ -252,6 +279,9 @@ function print_status() { print("