Project

General

Profile

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

    
22
require_once("filter.inc");
23
require_once("notices.inc");
24

    
25
// If there is no ssh key in the system to identify this firewall, generate a pair now
26
function get_device_key() {
27
	if (!file_exists("/etc/ssh/ssh_host_ed25519_key.pub")) {
28
		exec("/usr/bin/nice -n20 /usr/bin/ssh-keygen -t ed25519 -b 4096 -N '' -f /etc/ssh//ssh_host_ed25519_key");
29
	}
30

    
31
	// The userkey (firewall identifier) is an MD5 has of the ed25519 public key
32
	return hash("sha256", file_get_contents("/etc/ssh/ssh_host_ed25519_key.pub"));
33
}
34

    
35
$origkey = get_device_key();
36

    
37
if (isset($_REQUEST['userkey']) && !empty($_REQUEST['userkey'])) {
38
	$userkey = htmlentities($_REQUEST['userkey']);
39
} else {
40
	$userkey = get_device_key();
41
}
42

    
43
// Defined username. Username must be sent lowercase. See Redmine #7127 and Netgate Redmine #163
44
$username = strtolower($config['system']['acb']['gold_username']);
45

    
46
// Defined password
47
$password = $config['system']['acb']['gold_password'];
48

    
49
$uniqueID = system_get_uniqueid();
50

    
51
/* Check whether ACB is enabled */
52
function acb_enabled() {
53
	global $config;
54
	$acb_enabled = false;
55

    
56
	if (is_array($config['system']['acb'])) {
57
		if ($config['system']['acb']['enable'] == "yes") {
58
			$acb_enabled = true;
59
		}
60
	}
61

    
62
	return $acb_enabled;
63
}
64

    
65
// Ensures patches match
66
function acb_custom_php_validation_command($post, &$input_errors) {
67
	global $_POST, $savemsg, $config;
68

    
69
	// Do nothing when ACB is disabled in configuration
70
	// This also makes it possible to delete the credentials from config.xml
71
	if (!acb_enabled()) {
72
		// We do not need to store this value.
73
		unset($_POST['testconnection']);
74
		return;
75
	}
76

    
77
	if (!$post['crypto_password'] or !$post['crypto_password2']) {
78
		$input_errors[] = "The encryption password is required.";
79
	}
80

    
81
	if ($post['crypto_password'] <> $post['crypto_password2']) {
82
		$input_errors[] = "Sorry, the entered encryption passwords do not match.";
83
	}
84

    
85
	if ($post['testconnection']) {
86
		$status = test_connection($post);
87
		if ($status) {
88
			$savemsg = "Connection to the ACB server was tested with no errors.";
89
		}
90
	}
91

    
92
	// We do not need to store this value.
93
	unset($_POST['testconnection']);
94
}
95

    
96
function acb_custom_php_resync_config_command() {
97
	// Do nothing when ACB is disabled in configuration
98
	if (!acb_enabled()) {
99
		return;
100
	}
101

    
102
	if (is_file("/cf/conf/lastpfSbackup.txt")) {
103
		conf_mount_rw();
104
		unlink("/cf/conf/lastpfSbackup.txt");
105
		conf_mount_ro();
106
	}
107

    
108
	if (!function_exists("filter_configure")) {
109
		require_once("filter.inc");
110
	}
111

    
112
	filter_configure();
113

    
114
	if ($savemsg) {
115
		$savemsg .= "<br/>";
116
	}
117

    
118
	$savemsg .= "A configuration backup has been queued.";
119
}
120

    
121
function configure_proxy() {
122
	global $config;
123
	$ret = array();
124
	if (!empty($config['system']['proxyurl'])) {
125
		$ret[CURLOPT_PROXY] = $config['system']['proxyurl'];
126
		if (!empty($config['system']['proxyport'])) {
127
			$ret[CURLOPT_PROXYPORT] = $config['system']['proxyport'];
128
		}
129
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
130
			$ret[CURLOPT_PROXYAUTH] = CURLAUTH_ANY | CURLAUTH_ANYSAFE;
131
			$ret[CURLOPT_PROXYUSERPWD] = "{$config['system']['proxyuser']}:{$config['system']['proxypass']}";
132
		}
133
	}
134
	return $ret;
135
}
136

    
137
function test_connection($post) {
138
	global $savemsg, $config, $g, $legacy;
139

    
140
	// Do nothing when booting or when not enabled
141
	if (platform_booting() || !acb_enabled()) {
142
		return;
143
	}
144

    
145
	// Seperator used during client / server communications
146
	$oper_sep = "\|\|";
147

    
148
	// Encryption password
149
	$decrypt_password = $post['crypto_password'];
150

    
151
	// Defined username. Username must be sent lowercase. See Redmine #7127 and Netgate Redmine #163
152
	$username = strtolower($post['username']);
153

    
154
	// Defined password
155
	$password = $post['password'];
156

    
157
	// Set hostname
158
	$hostname = $config['system']['hostname'] . "." . $config['system']['domain'];
159

    
160
	// URL to restore.php
161
	$get_url = $legacy ? "https://portal.pfsense.org/pfSconfigbackups/restore.php":"https://acb.netgate.com/getbkp";
162

    
163
	// Populate available backups
164
	$curl_session = curl_init();
165
	curl_setopt($curl_session, CURLOPT_URL, $get_url);
166

    
167
	if ($legacy) {
168
		curl_setopt($curl_session, CURLOPT_HTTPHEADER, array("Authorization: Basic " . base64_encode("{$username}:{$password}")));
169
	}
170

    
171
	curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 1);
172
	curl_setopt($curl_session, CURLOPT_POST, 1);
173
	curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
174
	curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, 55);
175
	curl_setopt($curl_session, CURLOPT_TIMEOUT, 30);
176
	curl_setopt($curl_session, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version")));
177
	// Proxy
178
	curl_setopt_array($curl_session, configure_proxy());
179

    
180
	curl_setopt($curl_session, CURLOPT_POSTFIELDS, "action=showbackups&hostname={$hostname}");
181
	$data = curl_exec($curl_session);
182

    
183
	if (curl_errno($curl_session)) {
184
		return("An error occurred " . curl_error($curl_session));
185
	} else {
186
		curl_close($curl_session);
187
	}
188

    
189
	return;
190
}
191

    
192
function upload_config($reasonm = "") {
193
	global $config, $g, $input_errors, $userkey, $uniqueID;
194

    
195
	if (empty($userkey)) {
196
		$userkey = get_device_key();
197
	}
198

    
199
	if (empty($uniqueID)) {
200
		$uniqueID = system_get_uniqueid();
201
	}
202

    
203
	// Do nothing when booting or when not enabled
204
	if (platform_booting() || !acb_enabled()) {
205
		return;
206
	}
207

    
208
	/*
209
	 * pfSense upload config to pfSense.org script
210
	 * This file plugs into config.inc (/usr/local/pkg/parse_config)
211
	 * and runs every time the running firewall filter changes.
212
	 *
213
	 */
214

    
215
	if (file_exists("/tmp/acb_nooverwrite")) {
216
		unlink("/tmp/acb_nooverwrite");
217
		$nooverwrite = "true";
218
	} else {
219
		$nooverwrite = "false";
220
	}
221

    
222
	// Define some needed variables
223
	if (file_exists("/cf/conf/lastpfSbackup.txt")) {
224
		$last_backup_date = str_replace("\n", "", file_get_contents("/cf/conf/lastpfSbackup.txt"));
225
	} else {
226
		$last_backup_date = "";
227
	}
228

    
229
	$last_config_change = $config['revision']['time'];
230
	$hostname = $config['system']['hostname'] . "." . $config['system']['domain'];
231

    
232
	if ($reasonm) {
233
		$reason = $reasonm;
234
	} else {
235
		$reason	= $config['revision']['description'];
236
	}
237

    
238
	/*
239
	* Syncing vouchers happens every minute and sometimes multiple times. We don't
240
	* want to fill up our db with a lot of the same config so just ignore that case.
241
	*/
242
	if((strpos($reason, 'Syncing vouchers') !== false ||
243
		strpos($reason, 'Captive Portal Voucher database synchronized') !== false) ) {
244
		return;
245
	}
246

    
247

    
248
	$encryptpw = $config['system']['acb']['encryption_password'];
249

    
250
	// Define upload_url, must be present after other variable definitions due to username, password
251
	$upload_url = "https://acb.netgate.com/save";
252

    
253
	if (!$encryptpw) {
254
		if (!file_exists("/cf/conf/autoconfigback.notice")) {
255
			$notice_text = "The encryption password is not set for Automatic Configuration Backup.";
256
			$notice_text .= " Please correct this in Services -> AutoConfigBackup -> Settings.";
257
			//log_error($notice_text);
258
			//file_notice("AutoConfigBackup", $notice_text, $notice_text, "");
259
			conf_mount_rw();
260
			touch("/cf/conf/autoconfigback.notice");
261
			conf_mount_ro();
262
		}
263
	} else {
264
		/* If configuration has changed, upload to pfS */
265
		if ($last_backup_date <> $last_config_change) {
266

    
267
			// Mount RW (if needed)
268
			conf_mount_rw();
269

    
270
			$notice_text = "Beginning configuration backup to ." . $upload_url;
271
			log_error($notice_text);
272
			update_filter_reload_status($notice_text);
273

    
274
			// Encrypt config.xml
275
			$data = file_get_contents("/cf/conf/config.xml");
276
			$raw_config_sha256_hash = trim(shell_exec("/sbin/sha256 /cf/conf/config.xml | /usr/bin/awk '{ print $4 }'"));
277
			$data = encrypt_data($data, $encryptpw);
278
			$tmpname = "/tmp/" . $raw_config_sha256_hash . ".tmp";
279
			tagfile_reformat($data, $data, "config.xml");
280
			file_put_contents($tmpname, $data);
281

    
282
			$post_fields = array(
283
				'reason' => htmlspecialchars($reason),
284
				'uid' => $uniqueID,
285
				'file' => curl_file_create($tmpname, 'image/jpg', 'config.jpg'),
286
				'userkey' => htmlspecialchars($userkey),
287
				'sha256_hash' => $raw_config_sha256_hash,
288
				'version' => $g['product_version'],
289
				'hint' => $config['system']['acb']['hint']
290
			);
291

    
292
			// Check configuration into the ESF repo
293
			$curl_session = curl_init();
294

    
295
			curl_setopt($curl_session, CURLOPT_URL, "https://acb.netgate.com/save");
296
			curl_setopt($curl_session, CURLOPT_POST, count($post_fields));
297
			curl_setopt($curl_session, CURLOPT_POSTFIELDS, $post_fields);
298
			curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, 1);
299
			curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, 0);
300
			curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, 55);
301
			curl_setopt($curl_session, CURLOPT_TIMEOUT, 30);
302
			curl_setopt($curl_session, CURLOPT_USERAGENT, $g['product_name'] . '/' . rtrim(file_get_contents("/etc/version")));
303
			// Proxy
304
			curl_setopt_array($curl_session, configure_proxy());
305

    
306
			$data = curl_exec($curl_session);
307

    
308
			unlink_if_exists($tmpname);
309

    
310
			if (curl_errno($curl_session)) {
311
				$fd = fopen("/tmp/backupdebug.txt", "w");
312
				fwrite($fd, $upload_url . "" . $fields_string . "\n\n");
313
				fwrite($fd, $data);
314
				fwrite($fd, curl_error($curl_session));
315
				fclose($fd);
316
			} else {
317
				curl_close($curl_session);
318
			}
319

    
320
			if (strpos($data, "500") != false) {
321
				$notice_text = "An error occurred while uploading your pfSense configuration to " . $upload_url . " (" . htmlspecialchars($data) . ")";
322
				log_error($notice_text . " - " . $data);
323
				file_notice("AutoConfigBackup", $notice_text, "Backup Failure", "/pkg_edit.php?xml=autoconfigbackup.xml&id=0");
324
				update_filter_reload_status($notice_text);
325
				$input_errors["acb_upload"] = $notice_text;
326
			} else {
327
				// Update last pfS backup time
328
				$fd = fopen("/cf/conf/lastpfSbackup.txt", "w");
329
				fwrite($fd, $config['revision']['time']);
330
				fclose($fd);
331
				$notice_text = "End of configuration backup to " . $upload_url . " (success).";
332
				log_error($notice_text);
333
				update_filter_reload_status($notice_text);
334
			}
335

    
336
			// Mount image RO (if needed)
337
			conf_mount_ro();
338

    
339
		} else {
340
			// Debugging
341
			//log_error("No https://portal.pfsense.org backup required.");
342
		}
343
	}
344
}
(1-1/60)