Project

General

Profile

Download (15.5 KB) Statistics
| Branch: | Tag: | Revision:
1 054f0ed0 Steve Beaver
<?php
2
/*
3 587315d5 Steve Beaver
 * services_acb.php
4 054f0ed0 Steve Beaver
 *
5
 * part of pfSense (https://www.pfsense.org)
6 38809d47 Renato Botelho do Couto
 * Copyright (c) 2008-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8 402c98a2 Reid Linnemann
 * Copyright (c) 2014-2023 Rubicon Communications, LLC (Netgate)
9 054f0ed0 Steve Beaver
 * All rights reserved.
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 * http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23 18c1de41 jim-p
24
##|+PRIV
25
##|*IDENT=page-services-acb
26
##|*NAME=Services: Auto Config Backup: Restore
27
##|*DESCR=Restore from auto config backup.
28
##|*MATCH=services_acb.php*
29
##|-PRIV
30
31 054f0ed0 Steve Beaver
require("guiconfig.inc");
32
require("acb.inc");
33
34
// Separator used during client / server communications
35
$oper_sep = "\|\|";
36
$exp_sep = '||';
37
38
// Encryption password
39 1e45d13f Christian McDonald
$decrypt_password = config_get_path('system/acb/encryption_password');
40 054f0ed0 Steve Beaver
41
// Defined username. Username must be sent lowercase. See Redmine #7127 and Netgate Redmine #163
42
$username = strtolower($config['system']['acb']['gold_username']);
43 1e45d13f Christian McDonald
$password = config_get_path('system/acb/gold_password');
44 054f0ed0 Steve Beaver
45
// Set hostname
46
if ($_REQUEST['hostname']) {
47
	$hostname = $_REQUEST['hostname'];
48
} else {
49
	$hostname = $config['system']['hostname'] . "." . $config['system']['domain'];
50
}
51
52
// Hostname of local machine
53
$myhostname = $config['system']['hostname'] . "." . $config['system']['domain'];
54
55
if (!$decrypt_password) {
56 af0edce6 Steve Beaver
	Header("Location: /services_acb_settings.php");
57 054f0ed0 Steve Beaver
	exit;
58
}
59
60
if ($_REQUEST['savemsg']) {
61
	$savemsg = htmlentities($_REQUEST['savemsg']);
62
}
63
64
if ($_REQUEST['download']) {
65
	$pgtitle = array("Services", "Auto Configuration Backup", "Revision Information");
66
} else {
67
	$pgtitle = array("Services", "Auto Configuration Backup", "Restore");
68
}
69
70
/* Set up time zones for conversion. See #5250 */
71
$acbtz = new DateTimeZone('America/Chicago');
72
$mytz = new DateTimeZone(date_default_timezone_get());
73
74
include("head.inc");
75
76
77
if ($_REQUEST['rmver'] != "") {
78
	$curl_session = curl_init();
79 f01c0991 Steve Beaver
	curl_setopt($curl_session, CURLOPT_URL, "https://acb.netgate.com/rmbkp");
80
	curl_setopt($curl_session, CURLOPT_POSTFIELDS, "userkey=" . $userkey .
81 054f0ed0 Steve Beaver
		"&revision=" . urlencode($_REQUEST['rmver']) .
82 2568e151 Christian McDonald
		"&version=" . g_get('product_version') .
83 054f0ed0 Steve Beaver
		"&uid=" . urlencode($uniqueID));
84
	curl_setopt($curl_session, CURLOPT_POST, 3);
85
	curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 1);
86
	curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
87 2568e151 Christian McDonald
	curl_setopt($curl_session, CURLOPT_USERAGENT, g_get('product_label') . '/' . rtrim(file_get_contents("/etc/version")));
88 054f0ed0 Steve Beaver
	// Proxy
89 75a3b0de Viktor G
	set_curlproxy($curl_session);
90 054f0ed0 Steve Beaver
91
	$data = curl_exec($curl_session);
92
	if (curl_errno($curl_session)) {
93
		$fd = fopen("/tmp/acb_deletedebug.txt", "w");
94 8a6d9d7f Steve Beaver
		fwrite($fd, "https://acb.netgate.com/rmbkp" . "" . "action=delete&hostname=" . urlencode($hostname) . "&revision=" . urlencode($_REQUEST['rmver']) . "\n\n");
95 054f0ed0 Steve Beaver
		fwrite($fd, $data);
96
		fwrite($fd, curl_error($curl_session));
97
		fclose($fd);
98 8a6d9d7f Steve Beaver
		$savemsg = "An error occurred while trying to remove the item from acb.netgate.com.";
99 054f0ed0 Steve Beaver
	} else {
100
		curl_close($curl_session);
101
		$budate = new DateTime($_REQUEST['rmver'], $acbtz);
102
		$budate->setTimezone($mytz);
103
		$savemsg = "Backup revision " . htmlspecialchars($budate->format(DATE_RFC2822)) . " has been removed.";
104
	}
105
}
106
107
if ($_REQUEST['newver'] != "") {
108
	// Phone home and obtain backups
109
	$curl_session = curl_init();
110
111 f01c0991 Steve Beaver
	curl_setopt($curl_session, CURLOPT_URL, "https://acb.netgate.com/getbkp");
112
	curl_setopt($curl_session, CURLOPT_POSTFIELDS, "userkey=" . $userkey .
113
		"&revision=" . urlencode($_REQUEST['newver']) .
114 2568e151 Christian McDonald
		"&version=" . g_get('product_version') .
115 f01c0991 Steve Beaver
		"&uid=" . urlencode($uniqueID));
116 054f0ed0 Steve Beaver
	curl_setopt($curl_session, CURLOPT_POST, 3);
117
	curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 1);
118
	curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
119 2568e151 Christian McDonald
	curl_setopt($curl_session, CURLOPT_USERAGENT, g_get('product_label') . '/' . rtrim(file_get_contents("/etc/version")));
120 054f0ed0 Steve Beaver
	// Proxy
121 75a3b0de Viktor G
	set_curlproxy($curl_session);
122 054f0ed0 Steve Beaver
	$data = curl_exec($curl_session);
123
	$data_split = explode('++++', $data);
124
	$sha256 = trim($data_split[0]);
125
	$data = $data_split[1];
126
127
	if (!tagfile_deformat($data, $data, "config.xml")) {
128
		$input_errors[] = "The downloaded file does not appear to contain an encrypted pfSense configuration.";
129
	}
130
131
	$out = decrypt_data($data, $decrypt_password);
132
133
	$pos = stripos($out, "</pfsense>");
134
	$data = substr($out, 0, $pos);
135
	$data = $data . "</pfsense>\n";
136
137
	$fd = fopen("/tmp/config_restore.xml", "w");
138
	fwrite($fd, $data);
139
	fclose($fd);
140
141
	if (strlen($data) < 50) {
142
		$input_errors[] = "The decrypted config.xml is under 50 characters, something went wrong. Aborting.";
143
	}
144
145
	$ondisksha256 = trim(shell_exec("/sbin/sha256 /tmp/config_restore.xml | /usr/bin/awk '{ print $4 }'"));
146
	// We might not have a sha256 on file for older backups
147
	if ($sha256 != "0" && $sha256 != "") {
148
		if ($ondisksha256 != $sha256) {
149
			$input_errors[] = "SHA256 values do not match, cannot restore. $ondisksha256 != $sha256";
150
		}
151
	}
152
	if (curl_errno($curl_session)) {
153 f3f98e97 Phil Davis
		/* If an error occurred, log the error in /tmp/ */
154 054f0ed0 Steve Beaver
		$fd = fopen("/tmp/acb_restoredebug.txt", "w");
155 8a6d9d7f Steve Beaver
		fwrite($fd, "https://acb.netgate.com/getbkp" . "" . "action=restore&hostname={$hostname}&revision=" . urlencode($_REQUEST['newver']) . "\n\n");
156 054f0ed0 Steve Beaver
		fwrite($fd, $data);
157
		fwrite($fd, curl_error($curl_session));
158
		fclose($fd);
159
	} else {
160
		curl_close($curl_session);
161
	}
162
163
	if (!$input_errors && $data) {
164
		if (config_restore("/tmp/config_restore.xml") == 0) {
165
			$savemsg = "Successfully reverted the pfSense configuration to revision " . urldecode($_REQUEST['newver']) . ".";
166
			$savemsg .= <<<EOF
167
			<br />
168
		<form action="diag_reboot.php" method="post">
169
			Reboot the firewall to full activate changes?
170 9b83e6fb Viktor G
			<input name="rebootmode" type="hidden" value="Reboot" />
171 054f0ed0 Steve Beaver
			<input name="Submit" type="submit" class="formbtn" value=" Yes " />
172
		</form>
173
EOF;
174
		} else {
175
			$savemsg = "Unable to revert to the selected configuration.";
176
		}
177
	} else {
178
		log_error("There was an error when restoring the AutoConfigBackup item");
179
	}
180
	unlink_if_exists("/tmp/config_restore.xml");
181
}
182
183
if ($_REQUEST['download']) {
184
	// Phone home and obtain backups
185
	$curl_session = curl_init();
186
187 f01c0991 Steve Beaver
	curl_setopt($curl_session, CURLOPT_URL, "https://acb.netgate.com/getbkp");
188
	curl_setopt($curl_session, CURLOPT_POSTFIELDS, "userkey=" . $userkey . "&revision=" . urlencode($_REQUEST['download']));
189 054f0ed0 Steve Beaver
	curl_setopt($curl_session, CURLOPT_POST, 3);
190
	curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 1);
191
	curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
192
193 2568e151 Christian McDonald
	curl_setopt($curl_session, CURLOPT_USERAGENT, g_get('product_label') . '/' . rtrim(file_get_contents("/etc/version")));
194 054f0ed0 Steve Beaver
	// Proxy
195 75a3b0de Viktor G
	set_curlproxy($curl_session);
196 054f0ed0 Steve Beaver
	$data = curl_exec($curl_session);
197
198 4174a828 Steve Beaver
	if (curl_errno($curl_session)) {
199
		$fd = fopen("/tmp/acb_backupdebug.txt", "w");
200
		fwrite($fd, "https://acb.netgate.com/getbkp" . "" . "action=sgetbackup" . "\n\n");
201
		fwrite($fd, $data);
202
		fwrite($fd, curl_error($curl_session));
203
		fclose($fd);
204
	} else {
205
		curl_close($curl_session);
206
	}
207
208 054f0ed0 Steve Beaver
	if (!tagfile_deformat($data, $data1, "config.xml")) {
209 f01c0991 Steve Beaver
		$input_errors[] = "The downloaded file does not appear to contain an encrypted pfSense configuration.";
210 054f0ed0 Steve Beaver
	} else {
211
		$ds = explode('++++', $data);
212
		$revision = $_REQUEST['download'];
213
		$sha256sum = $ds[0];
214
		if ($sha256sum == "0") {
215
			$sha256sum = "None on file.";
216
		}
217
		$data = $ds[1];
218
		$configtype = "Encrypted";
219
		if (!tagfile_deformat($data, $data, "config.xml")) {
220
			$input_errors[] = "The downloaded file does not appear to contain an encrypted pfSense configuration.";
221
		}
222
		$data = decrypt_data($data, $decrypt_password);
223
		if (!strstr($data, "pfsense")) {
224
			$data = "Could not decrypt. Different encryption key?";
225
			$input_errors[] = "Could not decrypt config.xml";
226
		}
227
	}
228
}
229
230
// $confvers must be populated viewing info but there were errors
231 bbb3bbeb Viktor G
$confvers = array();
232
if ((!($_REQUEST['download']) || $input_errors) && check_dnsavailable()) {
233 054f0ed0 Steve Beaver
	// Populate available backups
234
	$curl_session = curl_init();
235
236 f01c0991 Steve Beaver
	curl_setopt($curl_session, CURLOPT_URL, "https://acb.netgate.com/list");
237
	curl_setopt($curl_session, CURLOPT_POSTFIELDS, "userkey=" . $userkey .
238
		"&uid=eb6a4e6f76c10734b636" .
239 2568e151 Christian McDonald
		"&version=" . g_get('product_version') .
240 f01c0991 Steve Beaver
		"&uid=" . urlencode($uniqueID));
241 054f0ed0 Steve Beaver
	curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 1);
242
	curl_setopt($curl_session, CURLOPT_POST, 1);
243
	curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
244
245 2568e151 Christian McDonald
	curl_setopt($curl_session, CURLOPT_USERAGENT, g_get('product_label') . '/' . rtrim(file_get_contents("/etc/version")));
246 054f0ed0 Steve Beaver
	// Proxy
247 75a3b0de Viktor G
	set_curlproxy($curl_session);
248 054f0ed0 Steve Beaver
249
	$data = curl_exec($curl_session);
250
251 af0edce6 Steve Beaver
	if (curl_errno($curl_session)) {
252 054f0ed0 Steve Beaver
		$fd = fopen("/tmp/acb_backupdebug.txt", "w");
253 8a6d9d7f Steve Beaver
		fwrite($fd, "https://acb.netgate.com/list" . "" . "action=showbackups" . "\n\n");
254 054f0ed0 Steve Beaver
		fwrite($fd, $data);
255
		fwrite($fd, curl_error($curl_session));
256
		fclose($fd);
257
	} else {
258
		curl_close($curl_session);
259
	}
260
261
	// Loop through and create new confvers
262
	$data_split = explode("\n", $data);
263
264
	foreach ($data_split as $ds) {
265
		$ds_split = explode($exp_sep, $ds);
266
		$tmp_array = array();
267
		$tmp_array['username'] = $ds_split[0];
268
		$tmp_array['reason'] = $ds_split[1];
269
		$tmp_array['time'] = $ds_split[2];
270
271
		/* Convert the time from server time to local. See #5250 */
272
		$budate = new DateTime($tmp_array['time'], $acbtz);
273
		$budate->setTimezone($mytz);
274
		$tmp_array['localtime'] = $budate->format(DATE_RFC2822);
275
276
		if ($ds_split[2] && $ds_split[0]) {
277
			$confvers[] = $tmp_array;
278
		}
279
	}
280
}
281
282
if ($input_errors) {
283
	print_input_errors($input_errors);
284
}
285
if ($savemsg) {
286
	print_info_box($savemsg, 'success');
287
}
288
289
$tab_array = array();
290 587315d5 Steve Beaver
$tab_array[0] = array("Settings", false, "/services_acb_settings.php");
291 054f0ed0 Steve Beaver
if ($_REQUEST['download']) {
292
	$active = false;
293
} else {
294
	$active = true;
295
}
296
297 587315d5 Steve Beaver
$tab_array[1] = array("Restore", $active, "/services_acb.php");
298
299 054f0ed0 Steve Beaver
if ($_REQUEST['download']) {
300 ce77c104 jim-p
	$tab_array[] = array("Revision", true, "/services_acb.php?download=" . htmlspecialchars($_REQUEST['download']));
301 054f0ed0 Steve Beaver
}
302 587315d5 Steve Beaver
303
$tab_array[] = array("Backup now", false, "/services_acb_backup.php");
304 054f0ed0 Steve Beaver
305
display_top_tabs($tab_array);
306
?>
307
308
<div id="loading">
309
	<i class="fa fa-spinner fa-spin"></i> Loading, please wait...
310
</div>
311
312
313
<?php if ($_REQUEST['download'] && (!$input_errors)):
314
315
$form = new Form(false);
316
317
$section = new Form_Section('Backup Details');
318
319
$section->addInput(new Form_Input(
320
	'download',
321
	'Revision date/time',
322
	'text',
323
	$_REQUEST['download']
324
))->setWidth(7)->setReadOnly();
325
326
$section->addInput(new Form_Input(
327
	'reason',
328
	'Revision Reason',
329
	'text',
330
	$_REQUEST['reason']
331
))->setWidth(7)->setReadOnly();
332
333
$section->addInput(new Form_Input(
334
	'shasum',
335
	'SHA256 summary',
336
	'text',
337
	$sha256sum
338
))->setWidth(7)->setReadOnly();
339
340
$section->addInput(new Form_Textarea(
341
	'config_xml',
342
	'Encrypted config.xml',
343
	$ds[1]
344
))->setWidth(7)->setAttribute("rows", "40")->setAttribute("wrap", "off");
345
346
$section->addInput(new Form_Textarea(
347
	'dec_config_xml',
348
	'Decrypted config.xml',
349
	$data
350
))->setWidth(7)->setAttribute("rows", "40")->setAttribute("wrap", "off");
351
352
$form->add($section);
353
354
print($form);
355
356
?>
357 587315d5 Steve Beaver
<a class="btn btn-primary" title="<?=gettext('Restore this revision')?>" href="services_acb.php?newver=<?= urlencode($_REQUEST['download']) ?>" onclick="return confirm('<?=gettext("Are you sure you want to restore {$cv['localtime']}?")?>')"><i class="fa fa-undo"></i> Install this revision</a>
358 054f0ed0 Steve Beaver
359
<?php else:
360
361 f01c0991 Steve Beaver
$section2 = new Form_Section('Device key');
362
$group = new Form_Group("Device key");
363
364
$group->add(new Form_Input(
365
	'devkey',
366
	'Device key',
367
	'text',
368
	$userkey
369
))->setWidth(7)->setHelp("ID used to identify this firewall (derived from the SSH public key.) " .
370
	"See help below for more details. %sPlease make a safe copy of this ID value.%s If it is lost, your backups will" .
371
	" be lost too!", "<strong>", "</strong>");
372
373
$group->add(new Form_Button(
374
	'upduserkey',
375
	'Submit',
376
	null,
377
	'fa-save'
378
))->addClass('btn-success btn-xs');
379
380
$group->add(new Form_Button(
381
	'restore',
382
	'Reset',
383
	null,
384
	'fa-refresh'
385
))->addClass('btn-info btn-xs');
386
387
$section2->add($group);
388
print($section2);
389
390
print('<div class="infoblock">');
391
print_info_box(gettext("The Device key listed above is derived from the SSH public key of the firewall. When a configuration is saved, it is identified by this value." .
392
	" If you are restoring the configuration of another firewall, paste the Device key from that firewall into the Device ID field above and click \"Submit\"." .
393
	" This will temporarily override the ID for this session."), 'info', false);
394
print('</div>');
395 f0fdd1ab Steve Beaver
396 054f0ed0 Steve Beaver
?>
397
<div class="panel panel-default">
398
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Automatic Configuration Backups")?></h2></div>
399
	<div class="panel-body">
400
		<div class="table-responsive">
401
		</div>
402
		<div class="table-responsive">
403 21cd4a8b Viktor G
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" id="backups" data-sortable>
404 054f0ed0 Steve Beaver
				<thead>
405
					<tr>
406 21cd4a8b Viktor G
						<th data-sortable-type="date" width="30%"><?=gettext("Date")?></th>
407 054f0ed0 Steve Beaver
						<th width="60%"><?=gettext("Configuration Change")?></th>
408
						<th width="10%"><?=gettext("Actions")?></th>
409
					</tr>
410
				</thead>
411
				<tbody>
412
413
			<?php
414
				$counter = 0;
415 3f8e09a5 Christopher
				if ($config['system']['acb']['reverse'] == "yes"){
416
					$confvers = array_reverse($confvers);
417
				}
418
419 054f0ed0 Steve Beaver
				foreach ($confvers as $cv):
420
			?>
421
					<tr>
422
						<td><?= $cv['localtime']; ?></td>
423
						<td><?= $cv['reason']; ?></td>
424
						<td>
425 f01c0991 Steve Beaver
							<a class="fa fa-undo"		title="<?=gettext('Restore this revision')?>"	href="services_acb.php?hostname=<?=urlencode($hostname)?>&userkey=<?=urlencode($userkey)?>&newver=<?=urlencode($cv['time'])?>"	onclick="return confirm('<?=gettext("Are you sure you want to restore {$cv['localtime']}?")?>')"></a>
426
							<a class="fa fa-download"	title="<?=gettext('Show info')?>"	href="services_acb.php?download=<?=urlencode($cv['time'])?>&hostname=<?=urlencode($hostname)?>&userkey=<?=urlencode($userkey)?>&reason=<?=urlencode($cv['reason'])?>"></a>
427 3fd4f32c Steve Beaver
<?php
428
		if ($userkey == $origkey) {
429
?>
430 f01c0991 Steve Beaver
							<a class="fa fa-trash"		title="<?=gettext('Delete config')?>"	href="services_acb.php?hostname=<?=urlencode($hostname)?>&rmver=<?=urlencode($cv['time'])?>"></a>
431 3fd4f32c Steve Beaver
<?php 	} ?>
432 054f0ed0 Steve Beaver
						</td>
433
					</tr>
434
				<?php	$counter++;
435
				endforeach;
436 21cd4a8b Viktor G
				?>
437 054f0ed0 Steve Beaver
				</tbody>
438
			</table>
439 21cd4a8b Viktor G
			<table class="table table-striped table-hover table-condensed" id="backups" data-sortable>
440
			<?php if ($counter == 0): ?>
441
				<tr>
442
					<td colspan="3" align="center" class="text-danger"><strong>
443
						<?=gettext("No backups could be located for this device.")?>
444
						</strong>
445
					</td>
446
				</tr>
447
			<?php else: ?>
448
				<tr>
449
					<td colspan="3" align="center">
450
						<br /><?=gettext("Current count of hosted backups")?> : <?= $counter ?>
451
					</td>
452
				</tr>
453
			<?php endif; ?>
454
			</table>
455 054f0ed0 Steve Beaver
		</div>
456
	</div>
457
</div>
458
<?php
459
460
endif; ?>
461
462
</form>
463
464
<script type="text/javascript">
465
//<![CDATA[
466
events.push(function(){
467
	$('#loading').hide();
468
469
	// On clicking Submit", reload the page but with a POST parameter "userkey" set
470
	$('#upduserkey').click(function() {
471
		var $form = $('<form>');
472
		var newuserkey = $('#devkey').val();
473
474
		$form
475
			.attr("method", "POST")
476 587315d5 Steve Beaver
			.attr("action", '/services_acb.php')
477 054f0ed0 Steve Beaver
			// The CSRF magic is required because we will be viewing the results of the POST
478
			.append(
479
				$("<input>")
480
					.attr("type", "hidden")
481
					.attr("name", "__csrf_magic")
482
					.val(csrfMagicToken)
483
			)
484
			.append(
485
			$("<input>")
486
				.attr("type", "hidden")
487
				.attr("name", "userkey")
488
				.val(newuserkey)
489
			)
490
			.appendTo('body')
491
			.submit();
492
	});
493
494
	$('#restore').click(function() {
495
		$('#devkey').val("<?=$origkey?>");
496
	});
497
});
498
//]]>
499
</script>
500
501
<?php include("foot.inc"); ?>