Project

General

Profile

Download (21.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_ntpd.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2023 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2013 Dagorlad
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
##|+PRIV
26
##|*IDENT=page-services-ntpd
27
##|*NAME=Services: NTP Settings
28
##|*DESCR=Allow access to the 'Services: NTP Settings' page.
29
##|*MATCH=services_ntpd.php*
30
##|-PRIV
31

    
32
define('NUMTIMESERVERS', 10);		// The maximum number of configurable time servers
33
require_once("guiconfig.inc");
34
require_once('rrd.inc');
35
require_once("shaper.inc");
36

    
37
global $ntp_poll_min_default, $ntp_poll_max_default, $ntp_server_types;
38
$ntp_poll_values = system_ntp_poll_values();
39
$auto_pool_suffix = "pool.ntp.org";
40
$max_candidate_peers = 25;
41
$min_candidate_peers = 4;
42

    
43
if (!is_array($config['ntpd'])) {
44
	config_set_path('ntpd', array());
45
}
46

    
47
if (empty($config['ntpd']['interface'])) {
48
	$old_ifs = config_get_path('installedpackages/openntpd/config/0/interface');
49
	if (!empty($old_ifs)) {
50
		config_set_path('ntpd/interface', $old_ifs);
51
		$pconfig['interface'] = explode(",", $old_ifs);
52
		config_del_path('installedpackages/openntpd');
53
		write_config(gettext("Upgraded settings from openntpd"));
54
	} else {
55
		$pconfig['interface'] = array();
56
	}
57
} else {
58
	$pconfig['interface'] = explode(",", $config['ntpd']['interface']);
59
}
60

    
61
if ($_POST) {
62
	unset($input_errors);
63
	$pconfig = $_POST;
64

    
65
	if (!empty($_POST['ntpmaxpeers']) && (!is_numericint($_POST['ntpmaxpeers']) ||
66
	    ($_POST['ntpmaxpeers'] < $min_candidate_peers) || ($_POST['ntpmaxpeers'] > $max_candidate_peers))) {
67
		$input_errors[] = sprintf(gettext("Max candidate pool peers must be a number between %d and %d"), $min_candidate_peers, $max_candidate_peers);
68
	}
69
	
70
	if ((strlen($pconfig['ntporphan']) > 0) && (!is_numericint($pconfig['ntporphan']) || ($pconfig['ntporphan'] < 1) || ($pconfig['ntporphan'] > 15))) {
71
		$input_errors[] = gettext("The supplied value for NTP Orphan Mode is invalid.");
72
	}
73

    
74
	if (!array_key_exists($pconfig['ntpminpoll'], $ntp_poll_values)) {
75
		$input_errors[] = gettext("The supplied value for Minimum Poll Interval is invalid.");
76
	}
77

    
78
	if (!array_key_exists($pconfig['ntpmaxpoll'], $ntp_poll_values)) {
79
		$input_errors[] = gettext("The supplied value for Maximum Poll Interval is invalid.");
80
	}
81

    
82
	for ($i = 0; $i < NUMTIMESERVERS; $i++) {
83
		if (isset($pconfig["servselect{$i}"]) && (($pconfig["servistype{$i}"] == 'pool') || 
84
		    (substr_compare($pconfig["server{$i}"], $auto_pool_suffix, strlen($pconfig["server{$i}"]) - strlen($auto_pool_suffix), strlen($auto_pool_suffix)) === 0))) {
85
			$input_errors[] = gettext("It is not possible to use 'No Select' for pools.");
86
		}
87
		if (!empty($pconfig["server{$i}"]) && !is_domain($pconfig["server{$i}"]) &&
88
		    !is_ipaddr($pconfig["server{$i}"])) {
89
			$input_errors[] = gettext("NTP Time Server names must be valid domain names, IPv4 addresses, or IPv6 addresses");
90
		}
91
	}
92

    
93
	if (is_numericint($pconfig['ntpminpoll']) &&
94
	    is_numericint($pconfig['ntpmaxpoll']) &&
95
	    ($pconfig['ntpmaxpoll'] < $pconfig['ntpminpoll'])) {
96
		$input_errors[] = gettext("The supplied value for Minimum Poll Interval is higher than NTP Maximum Poll Interval.");
97
	}
98

    
99
	if (isset($pconfig['serverauth'])) {
100
		if (empty($pconfig['serverauthkey'])) {
101
			$input_errors[] = gettext("The supplied value for NTP Authentication key can't be empty.");
102
		} elseif (($pconfig['serverauthalgo'] == 'md5') && ((strlen($pconfig['serverauthkey']) > 20) ||
103
		    !ctype_print($pconfig['serverauthkey']))) {
104
			$input_errors[] = gettext("The supplied value for NTP Authentication key for MD5 digest must be from 1 to 20 printable characters.");
105
		} elseif (($pconfig['serverauthalgo'] == 'sha1') && ((strlen($pconfig['serverauthkey']) != 40) ||
106
		    !ctype_xdigit($pconfig['serverauthkey']))) {
107
			$input_errors[] = gettext("The supplied value for NTP Authentication key for SHA1 digest must be hex-encoded string of 40 characters.");
108
		} elseif (($pconfig['serverauthalgo'] == 'sha256') && ((strlen($pconfig['serverauthkey']) != 64) ||
109
		    !ctype_xdigit($pconfig['serverauthkey']))) {
110
			$input_errors[] = gettext("The supplied value for NTP Authentication key for SHA256 digest must be hex-encoded string of 64 characters.");
111
		}
112
	}
113

    
114
	if (!$input_errors) {
115
		config_set_path('ntpd/enable', isset($_POST['enable']) ? 'enabled' : 'disabled');
116
		if (is_array($_POST['interface'])) {
117
			config_set_path('ntpd/interface', implode(",", $_POST['interface']));
118
		} elseif (isset($config['ntpd']['interface'])) {
119
			config_del_path('ntpd/interface');
120
		}
121

    
122
		config_del_path('ntpd/prefer');
123
		config_del_path('ntpd/noselect');
124
		config_del_path('ntpd/ispool');
125
		config_del_path('ntpd/ispeer');
126
		$timeservers = '';
127

    
128
		for ($i = 0; $i < NUMTIMESERVERS; $i++) {
129
			$tserver = trim($_POST["server{$i}"]);
130
			if (!empty($tserver)) {
131
				$timeservers .= "{$tserver} ";
132
				if (isset($_POST["servprefer{$i}"])) {
133
					$config['ntpd']['prefer'] .= "{$tserver} ";
134
				}
135
				if (isset($_POST["servselect{$i}"])) {
136
					$config['ntpd']['noselect'] .= "{$tserver} ";
137
				}
138
				if ($_POST["servistype{$i}"] == 'pool') {
139
					$config['ntpd']['ispool'] .= "{$tserver} ";
140
				} elseif ($_POST["servistype{$i}"] == 'peer') {
141
					$config['ntpd']['ispeer'] .= "{$tserver} ";
142
				}
143
			}
144
		}
145
		if (trim($timeservers) == "") {
146
			$timeservers = "pool.ntp.org";
147
		}
148
		config_set_path('system/timeservers', trim($timeservers));
149

    
150
		if (!empty($pconfig['ntpmaxpeers'])) {
151
			config_set_path('ntpd/ntpmaxpeers', $pconfig['ntpmaxpeers']);
152
		} else {
153
			config_del_path('ntpd/ntpmaxpeers');
154
		}
155
		config_set_path('ntpd/orphan', trim($pconfig['ntporphan']));
156
		config_set_path('ntpd/ntpminpoll', $pconfig['ntpminpoll']);
157
		config_set_path('ntpd/ntpmaxpoll', $pconfig['ntpmaxpoll']);
158
		config_set_path('ntpd/dnsresolv', $pconfig['dnsresolv']);
159

    
160
		if (!empty($_POST['logpeer'])) {
161
			config_set_path('ntpd/logpeer', $_POST['logpeer']);
162
		} elseif (isset($config['ntpd']['logpeer'])) {
163
			config_del_path('ntpd/logpeer');
164
		}
165

    
166
		if (!empty($_POST['logsys'])) {
167
			config_set_path('ntpd/logsys', $_POST['logsys']);
168
		} elseif (isset($config['ntpd']['logsys'])) {
169
			config_del_path('ntpd/logsys');
170
		}
171

    
172
		if (!empty($_POST['clockstats'])) {
173
			config_set_path('ntpd/clockstats', $_POST['clockstats']);
174
		} elseif (isset($config['ntpd']['clockstats'])) {
175
			config_del_path('ntpd/clockstats');
176
		}
177

    
178
		if (!empty($_POST['loopstats'])) {
179
			config_set_path('ntpd/loopstats', $_POST['loopstats']);
180
		} elseif (isset($config['ntpd']['loopstats'])) {
181
			config_del_path('ntpd/loopstats');
182
		}
183

    
184
		if (!empty($_POST['peerstats'])) {
185
			config_set_path('ntpd/peerstats', $_POST['peerstats']);
186
		} elseif (isset($config['ntpd']['peerstats'])) {
187
			config_del_path('ntpd/peerstats');
188
		}
189

    
190
		if ((empty($_POST['statsgraph'])) == (isset($config['ntpd']['statsgraph']))) {
191
			$enable_rrd_graphing = true;
192
		}
193
		if (!empty($_POST['statsgraph'])) {
194
			config_set_path('ntpd/statsgraph', $_POST['statsgraph']);
195
		} elseif (isset($config['ntpd']['statsgraph'])) {
196
			config_del_path('ntpd/statsgraph');
197
		}
198
		if (isset($enable_rrd_graphing)) {
199
			enable_rrd_graphing();
200
		}
201

    
202
		if (!empty($_POST['leaptext'])) {
203
			config_set_path('ntpd/leapsec', base64_encode($_POST['leaptext']));
204
		} elseif (isset($config['ntpd']['leapsec'])) {
205
			config_del_path('ntpd/leapsec');
206
		}
207

    
208
		if (is_uploaded_file($_FILES['leapfile']['tmp_name'])) {
209
			config_set_path('ntpd/leapsec', base64_encode(file_get_contents($_FILES['leapfile']['tmp_name'])));
210
		}
211

    
212
		if (!empty($_POST['serverauth'])) {
213
			config_set_path('ntpd/serverauth', $_POST['serverauth']);
214
			config_set_path('ntpd/serverauthkey', base64_encode(trim($_POST['serverauthkey'])));
215
			config_set_path('ntpd/serverauthalgo', $_POST['serverauthalgo']);
216
		} elseif (isset($config['ntpd']['serverauth'])) {
217
			config_del_path('ntpd/serverauth');
218
			config_del_path('ntpd/serverauthkey');
219
			config_del_path('ntpd/serverauthalgo');
220
		}
221

    
222
		write_config("Updated NTP Server Settings");
223

    
224
		$changes_applied = true;
225
		$retval = 0;
226
		$retval |= system_ntp_configure();
227
	}
228
}
229

    
230
function build_interface_list() {
231
	global $pconfig;
232

    
233
	$iflist = array('options' => array(), 'selected' => array());
234

    
235
	$interfaces = get_configured_interface_with_descr();
236
	$interfaces['lo0'] = "Localhost";
237

    
238
	foreach ($interfaces as $iface => $ifacename) {
239
		if (!is_ipaddr(get_interface_ip($iface)) &&
240
		    !is_ipaddrv6(get_interface_ipv6($iface))) {
241
			continue;
242
		}
243

    
244
		$iflist['options'][$iface] = $ifacename;
245

    
246
		if (in_array($iface, $pconfig['interface'])) {
247
			array_push($iflist['selected'], $iface);
248
		}
249
	}
250

    
251
	return($iflist);
252
}
253

    
254
init_config_arr(array('ntpd'));
255
$pconfig = &$config['ntpd'];
256
$pconfig['enable'] = ($config['ntpd']['enable'] != 'disabled') ? 'enabled' : 'disabled';
257
if (empty($pconfig['interface'])) {
258
	$pconfig['interface'] = array();
259
} else {
260
	$pconfig['interface'] = explode(",", $pconfig['interface']);
261
}
262
$pgtitle = array(gettext("Services"), gettext("NTP"), gettext("Settings"));
263
$pglinks = array("", "@self", "@self");
264
$shortcut_section = "ntp";
265
include("head.inc");
266

    
267
if ($input_errors) {
268
	print_input_errors($input_errors);
269
}
270

    
271
if ($changes_applied) {
272
	print_apply_result_box($retval);
273
}
274

    
275
$tab_array = array();
276
$tab_array[] = array(gettext("Settings"), true, "services_ntpd.php");
277
$tab_array[] = array(gettext("ACLs"), false, "services_ntpd_acls.php");
278
$tab_array[] = array(gettext("Serial GPS"), false, "services_ntpd_gps.php");
279
$tab_array[] = array(gettext("PPS"), false, "services_ntpd_pps.php");
280
display_top_tabs($tab_array);
281

    
282
$form = new Form;
283
$form->setMultipartEncoding();	// Allow file uploads
284

    
285
$section = new Form_Section('NTP Server Configuration');
286

    
287
$section->addInput(new Form_Checkbox(
288
	'enable',
289
	'Enable',
290
	'Enable NTP Server',
291
	($pconfig['enable'] == 'enabled')
292
))->setHelp('You may need to disable NTP if %1$s is running in a virtual machine and the host is responsible for the clock.', g_get('product_label'));
293

    
294
$iflist = build_interface_list();
295

    
296
$section->addInput(new Form_Select(
297
	'interface',
298
	'Interface',
299
	$iflist['selected'],
300
	$iflist['options'],
301
	true
302
))->setHelp('Interfaces without an IP address will not be shown.%1$s' .
303
			'Selecting no interfaces will listen on all interfaces with a wildcard.%1$s' .
304
			'Selecting all interfaces will explicitly listen on only the interfaces/IPs specified.', '<br />');
305

    
306
$timeservers = explode(' ', $config['system']['timeservers']);
307
$maxrows = max(count($timeservers), 1);
308
for ($counter=0; $counter < $maxrows; $counter++) {
309
	$group = new Form_Group($counter == 0 ? 'Time Servers':'');
310
	$group->addClass('repeatable');
311
	$group->setAttribute('max_repeats', NUMTIMESERVERS);
312
	$group->setAttribute('max_repeats_alert', sprintf(gettext('%d is the maximum number of configured servers.'), NUMTIMESERVERS));
313

    
314
	$group->add(new Form_Input(
315
		'server' . $counter,
316
		null,
317
		'text',
318
		$timeservers[$counter],
319
		['placeholder' => 'Hostname']
320
	 ))->setWidth(3);
321

    
322
	 $group->add(new Form_Checkbox(
323
		'servprefer' . $counter,
324
		null,
325
		null,
326
		isset($config['ntpd']['prefer']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['prefer'], $timeservers[$counter])
327
	 ))->sethelp('Prefer');
328

    
329
	 $group->add(new Form_Checkbox(
330
		'servselect' . $counter,
331
		null,
332
		null,
333
		isset($config['ntpd']['noselect']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['noselect'], $timeservers[$counter])
334
	 ))->sethelp('No Select');
335

    
336
	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]))) {
337
		$servertype = 'pool';
338
	} elseif (isset($config['ntpd']['ispeer']) && isset($timeservers[$counter]) && substr_count($config['ntpd']['ispeer'], $timeservers[$counter])) {
339
		$servertype = 'peer';
340
	} else {
341
		$servertype = 'server';
342
	}
343

    
344
	$group->add(new Form_Select(
345
		'servistype' . $counter,
346
		null,
347
		$servertype,
348
		$ntp_server_types
349
	 ))->sethelp('Type')->setWidth(2);
350

    
351
	$group->add(new Form_Button(
352
		'deleterow' . $counter,
353
		'Delete',
354
		null,
355
		'fa-trash'
356
	))->addClass('btn-warning');
357

    
358
	 $section->add($group);
359
}
360

    
361
$section->addInput(new Form_Button(
362
	'addrow',
363
	'Add',
364
	null,
365
	'fa-plus'
366
))->addClass('btn-success');
367

    
368
$section->addInput(new Form_StaticText(
369
	null,
370
	$btnaddrow
371
))->setHelp(
372
	'NTP will only sync if a majority of the servers agree on the time.  For best results you should configure between 3 and 5 servers ' .
373
	'(%4$sNTP support pages recommend at least 4 or 5%5$s), or a pool. If only one server is configured, it %2$swill%3$s be believed, and if 2 servers ' .
374
	'are configured and they disagree, %2$sneither%3$s will be believed. Options:%1$s' .
375
	'%2$sPrefer%3$s - NTP should favor the use of this server more than all others.%1$s' .
376
	'%2$sNo Select%3$s - NTP should not use this server for time, but stats for this server will be collected and displayed.%1$s' .
377
	'%2$sType%3$s - Server, Peer or a Pool of NTP servers and not a single address. This is assumed for *.pool.ntp.org.',
378
	'<br />',
379
	'<b>',
380
	'</b>',
381
	'<a target="_blank" href="https://support.ntp.org/bin/view/Support/ConfiguringNTP">',
382
	'</a>'
383
	);
384

    
385
$section->addInput(new Form_Input(
386
	'ntpmaxpeers',
387
	'Max candidate pool peers',
388
	'number',
389
	$pconfig['ntpmaxpeers'],
390
	['min' => $min_candidate_peers, 'max' => $max_candidate_peers]
391
))->setHelp('Maximum number of candidate peers in the NTP pool. This value should be set low enough to provide sufficient alternate sources ' .
392
	    'while not contacting an excessively large number of peers. ' .
393
	    'Many servers inside public pools are provided by volunteers, ' .
394
	    'and a large candidate pool places unnecessary extra load ' .
395
	    'on the volunteer time servers for little to no added benefit. (Default: 5).');
396

    
397
$section->addInput(new Form_Input(
398
	'ntporphan',
399
	'Orphan Mode',
400
	'text',
401
	$pconfig['orphan'],
402
	['placeholder' => "12"]
403
))->setHelp('Orphan mode allows the system clock to be used when no other clocks are available. ' .
404
			'The number here specifies the stratum reported during orphan mode and should normally be set to a number high enough ' .
405
			'to insure that any other servers available to clients are preferred over this server (default: 12).');
406

    
407
$section->addInput(new Form_Select(
408
	'ntpminpoll',
409
	'Minimum Poll Interval',
410
	$pconfig['ntpminpoll'],
411
	$ntp_poll_values
412
))->setHelp('Minimum poll interval for NTP messages. If set, must be less than or equal to Maximum Poll Interval.');
413

    
414
$section->addInput(new Form_Select(
415
	'ntpmaxpoll',
416
	'Maximum Poll Interval',
417
	$pconfig['ntpmaxpoll'],
418
	$ntp_poll_values
419
))->setHelp('Maximum poll interval for NTP messages. If set, must be greater than or equal to Minimum Poll Interval.');
420

    
421
$section->addInput(new Form_Checkbox(
422
	'statsgraph',
423
	'NTP Graphs',
424
	'Enable RRD graphs of NTP statistics (default: disabled).',
425
	$pconfig['statsgraph']
426
));
427

    
428
$section->addInput(new Form_Checkbox(
429
	'logpeer',
430
	'Logging',
431
	'Log peer messages (default: disabled).',
432
	$pconfig['logpeer']
433
));
434

    
435
$section->addInput(new Form_Checkbox(
436
	'logsys',
437
	null,
438
	'Log system messages (default: disabled).',
439
	$pconfig['logsys']
440
))->setHelp('These options enable additional messages from NTP to be written to the System Log %1$sStatus > System Logs > NTP%2$s',
441
			'<a href="status_logs.php?logfile=ntpd">', '</a>.');
442

    
443
// Statistics logging section
444
$btnadv = new Form_Button(
445
	'btnadvstats',
446
	'Display Advanced',
447
	null,
448
	'fa-cog'
449
);
450

    
451
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
452

    
453
$section->addInput(new Form_StaticText(
454
	'Statistics Logging',
455
	$btnadv
456
))->setHelp('Warning: These options will create persistent daily log files in /var/log/ntp.');
457

    
458
$section->addInput(new Form_Checkbox(
459
	'clockstats',
460
	null,
461
	'Log reference clock statistics (default: disabled).',
462
	$pconfig['clockstats']
463
));
464

    
465
$section->addInput(new Form_Checkbox(
466
	'loopstats',
467
	null,
468
	'Log clock discipline statistics (default: disabled).',
469
	$pconfig['loopstats']
470
));
471

    
472
$section->addInput(new Form_Checkbox(
473
	'peerstats',
474
	null,
475
	'Log NTP peer statistics (default: disabled).',
476
	$pconfig['peerstats']
477
));
478

    
479
// Leap seconds section
480
$btnadv = new Form_Button(
481
	'btnadvleap',
482
	'Display Advanced',
483
	null,
484
	'fa-cog'
485
);
486

    
487
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
488

    
489
$section->addInput(new Form_StaticText(
490
	'Leap seconds',
491
	$btnadv
492
))->setHelp(
493
	'Leap seconds may be added or subtracted at the end of June or December. Leap seconds are administered by the ' .
494
	'%1$sIERS%2$s, who publish them in their Bulletin C approximately 6 - 12 months in advance.  Normally this correction ' .
495
	'should only be needed if the server is a stratum 1 NTP server, but many NTP servers do not advertise an upcoming leap ' .
496
	'second when other NTP servers synchronise to them.%3$s%4$sIf the leap second is important to your network services, ' .
497
	'it is %6$sgood practice%2$s to download and add the leap second file at least a day in advance of any time correction%5$s.%3$s ' .
498
	'More information and files for downloading can be found on their %1$swebsite%2$s, and also on the %7$sNIST%2$s and %8$sNTP%2$s websites.',
499
	'<a target="_blank" href="https://www.iers.org">',
500
	'</a>',
501
	'<br />',
502
	'<b>',
503
	'</b>',
504
	'<a target="_blank" href="https://support.ntp.org/bin/view/Support/ConfiguringNTP">',
505
	'<a target="_blank" href="https://www.nist.gov">',
506
	'<a target="_blank" href="https://www.ntp.org">'
507
);
508

    
509
$section->addInput(new Form_Textarea(
510
	'leaptext',
511
	null,
512
	base64_decode(chunk_split($pconfig['leapsec']))
513
))->setHelp('Enter Leap second configuration as text OR select a file to upload.');
514

    
515
$section->addInput(new Form_Input(
516
	'leapfile',
517
	null,
518
	'file'
519
))->addClass('btn-default');
520

    
521
$section->addInput(new Form_Select(
522
	'dnsresolv',
523
	'DNS Resolution',
524
	$pconfig['dnsresolv'],
525
	array(
526
		'auto' => 'Auto',
527
		'inet' => 'IPv4',
528
		'inet6' => 'IPv6',
529
	)
530
))->setHelp('Force NTP peers DNS resolution IP protocol. Do not affect pools.');
531

    
532
$section->addInput(new Form_Checkbox(
533
	'serverauth',
534
	'Enable NTP Server Authentication',
535
	'Enable NTPv3 authentication (RFC 1305)',
536
	$pconfig['serverauth']
537
))->setHelp('Authentication allows the NTP client to confirm it is communicating with the intended server, ' .
538
	    'which protects against man-in-the-middle attacks.');
539

    
540
$group = new Form_Group('Authentication key');
541
$group->addClass('ntpserverauth');
542

    
543
$group->add(new Form_IpAddress(
544
	'serverauthkey',
545
	'NTP Authentication key',
546
	base64_decode($pconfig['serverauthkey']),
547
	['placeholder' => 'NTP Authentication key']
548
))->setHelp(
549
	'Key format: %1$s MD5 - The key is 1 to 20 printable characters %1$s' .
550
	'SHA1 - The key is a hex-encoded ASCII string of 40 characters %1$s' .
551
	'SHA256 - The key is a hex-encoded ASCII string of 64 characters',
552
	'<br />'
553
);
554

    
555
$group->add(new Form_Select(
556
	'serverauthalgo',
557
	null,
558
	$pconfig['serverauthalgo'],
559
	$ntp_auth_halgos
560
))->setWidth(3)->setHelp('Digest algorithm');
561

    
562
$section->add($group);
563

    
564
$form->add($section);
565

    
566
print($form);
567

    
568
?>
569

    
570
<script type="text/javascript">
571
//<![CDATA[
572
	// If this variable is declared, any help text will not be deleted when rows are added
573
	// IOW the help text will appear on every row
574
	retainhelp = true;
575
</script>
576

    
577
<script type="text/javascript">
578
//<![CDATA[
579
events.push(function() {
580

    
581
	// Show advanced stats options ============================================
582
	var showadvstats = false;
583

    
584
	function show_advstats(ispageload) {
585
		var text;
586
		// On page load decide the initial state based on the data.
587
		if (ispageload) {
588
<?php
589
			if (!$pconfig['clockstats'] && !$pconfig['loopstats'] && !$pconfig['peerstats']) {
590
				$showadv = false;
591
			} else {
592
				$showadv = true;
593
			}
594
?>
595
			showadvstats = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
596
		} else {
597
			// It was a click, swap the state.
598
			showadvstats = !showadvstats;
599
		}
600

    
601
		hideCheckbox('clockstats', !showadvstats);
602
		hideCheckbox('loopstats', !showadvstats);
603
		hideCheckbox('peerstats', !showadvstats);
604

    
605
		if (showadvstats) {
606
			text = "<?=gettext('Hide Advanced');?>";
607
		} else {
608
			text = "<?=gettext('Display Advanced');?>";
609
		}
610
		$('#btnadvstats').html('<i class="fa fa-cog"></i> ' + text);
611
	}
612

    
613
	$('#btnadvstats').click(function(event) {
614
		show_advstats();
615
	});
616

    
617
	// Show advanced leap second options ======================================
618
	var showadvleap = false;
619

    
620
	function show_advleap(ispageload) {
621
		var text;
622
		// On page load decide the initial state based on the data.
623
		if (ispageload) {
624
<?php
625
			// Note: leapfile is not a field saved in the config, so no need to test for it here.
626
			// leapsec is the encoded text in the config, leaptext is not a pconfig[] key.
627
			if (empty($pconfig['leapsec'])) {
628
				$showadv = false;
629
			} else {
630
				$showadv = true;
631
			}
632
?>
633
			showadvleap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
634
		} else {
635
			// It was a click, swap the state.
636
			showadvleap = !showadvleap;
637
		}
638

    
639
		hideInput('leaptext', !showadvleap);
640
		hideInput('leapfile', !showadvleap);
641

    
642
		if (showadvleap) {
643
			text = "<?=gettext('Hide Advanced');?>";
644
		} else {
645
			text = "<?=gettext('Display Advanced');?>";
646
		}
647
		$('#btnadvleap').html('<i class="fa fa-cog"></i> ' + text);
648
	}
649

    
650
	function change_serverauth() {
651
		hideClass('ntpserverauth', !($('#serverauth').prop('checked')));
652
	}
653

    
654
	$('#btnadvleap').click(function(event) {
655
		show_advleap();
656
	});
657

    
658
	$('#serverauth').change(function () {
659
		change_serverauth();
660
	});
661

    
662
	// Set initial states
663
	show_advstats(true);
664
	show_advleap(true);
665
	change_serverauth();
666

    
667
	// Suppress "Delete row" button if there are fewer than two rows
668
	checkLastRow();
669
});
670
//]]>
671
</script>
672

    
673
<?php include("foot.inc");
(131-131/228)