Project

General

Profile

Download (28 KB) Statistics
| Branch: | Tag: | Revision:
1 50d49018 Colin Smith
<?php
2
/*
3 c5d81585 Renato Botelho
 * xmlrpc.php
4 191cb31d Stephen Beaver
 *
5 c5d81585 Renato Botelho
 * part of pfSense (https://www.pfsense.org)
6 38809d47 Renato Botelho do Couto
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8 8f2f85c3 Luiz Otavio O Souza
 * Copyright (c) 2014-2022 Rubicon Communications, LLC (Netgate)
9 c5d81585 Renato Botelho
 * Copyright (c) 2005 Colin Smith
10
 * All rights reserved.
11 191cb31d Stephen Beaver
 *
12 b12ea3fb Renato Botelho
 * 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 191cb31d Stephen Beaver
 *
16 b12ea3fb Renato Botelho
 * http://www.apache.org/licenses/LICENSE-2.0
17 191cb31d Stephen Beaver
 *
18 b12ea3fb Renato Botelho
 * 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 191cb31d Stephen Beaver
 */
24 50d49018 Colin Smith
25 6b07c15a Matthew Grooms
##|+PRIV
26
##|*IDENT=page-xmlrpclibrary
27 5230f468 jim-p
##|*NAME=XMLRPC Library
28 6b07c15a Matthew Grooms
##|*DESCR=Allow access to the 'XMLRPC Library' page.
29
##|*MATCH=xmlrpc.php*
30
##|-PRIV
31
32 c81ef6e2 Phil Davis
require_once("config.inc");
33
require_once("functions.inc");
34 f81e7cc4 Renato Botelho
require_once("auth.inc");
35 f6339216 jim-p
require_once("filter.inc");
36 c81ef6e2 Phil Davis
require_once("ipsec.inc");
37
require_once("vpn.inc");
38 23fcdccc Viktor G
require_once("openvpn.inc");
39 7cab6335 Renato Botelho
require_once("captiveportal.inc");
40 c81ef6e2 Phil Davis
require_once("shaper.inc");
41 f81e7cc4 Renato Botelho
require_once("XML/RPC2/Server.php");
42 50d49018 Colin Smith
43 f81e7cc4 Renato Botelho
class pfsense_xmlrpc_server {
44 c87f4b70 Ermal
45 f81e7cc4 Renato Botelho
	private $loop_detected = false;
46
	private $remote_addr;
47 c87f4b70 Ermal
48 dc5f639f PiBa-NL
	private function auth() {
49 c472f9a1 jim-p
		global $config, $userindex;
50
		$userindex = index_users();
51
52 dc5f639f PiBa-NL
		$username = $_SERVER['PHP_AUTH_USER'];
53
		$password = $_SERVER['PHP_AUTH_PW'];
54 8da3de34 Colin Smith
55 fb1234ab Renato Botelho
		$login_ok = false;
56 f81e7cc4 Renato Botelho
		if (!empty($username) && !empty($password)) {
57
			$attributes = array();
58
			$authcfg = auth_get_authserver(
59
			    $config['system']['webgui']['authmode']);
60 c3638879 Scott Ullrich
61 f81e7cc4 Renato Botelho
			if (authenticate_user($username, $password,
62
			    $authcfg, $attributes) ||
63
			    authenticate_user($username, $password)) {
64 fb1234ab Renato Botelho
				$login_ok = true;
65 f81e7cc4 Renato Botelho
			}
66
		}
67 3dd2a278 Scott Ullrich
68 fb1234ab Renato Botelho
		if (!$login_ok) {
69 6e0d4751 jim-p
			log_auth(sprintf(gettext("webConfigurator authentication error for user '%1\$s' from: %2\$s"),
70
			    $username,
71
			    $this->remote_addr));
72 137f46d8 Ermal
73 fb1234ab Renato Botelho
			require_once("XML/RPC2/Exception.php");
74
			throw new XML_RPC2_FaultException(gettext(
75
			    'Authentication failed: Invalid username or password'),
76
			    -1);
77
		}
78
79
		$user_entry = getUserEntry($username);
80
		/*
81
		 * admin (uid = 0) is allowed
82
		 * or regular user with necessary privilege
83
		 */
84
		if (isset($user_entry['uid']) && $user_entry['uid'] != '0' &&
85
		    !userHasPrivilege($user_entry, 'system-xmlrpc-ha-sync')) {
86
			log_auth("webConfigurator authentication error for '" .
87
			    $username . "' from " . $this->remote_addr .
88
			    " not enough privileges");
89
90
			require_once("XML/RPC2/Exception.php");
91
			throw new XML_RPC2_FaultException(gettext(
92
			    'Authentication failed: not enough privileges'),
93
			    -2);
94
		}
95
96
		return;
97 3dd2a278 Scott Ullrich
	}
98 f81e7cc4 Renato Botelho
99
	private function array_overlay($a1, $a2) {
100
		foreach ($a1 as $k => $v) {
101
			if (!array_key_exists($k, $a2)) {
102
				continue;
103
			}
104
			if (is_array($v) && is_array($a2[$k])) {
105
				$a1[$k] = $this->array_overlay($v, $a2[$k]);
106
			} else {
107
				$a1[$k] = $a2[$k];
108
			}
109
		}
110
111
		return $a1;
112 962f215d Phil Davis
	}
113 c3638879 Scott Ullrich
114 f81e7cc4 Renato Botelho
	public function __construct() {
115
		global $config;
116 c3638879 Scott Ullrich
117 f82f991c Renato Botelho
		$this->remote_addr = $_SERVER['REMOTE_ADDR'];
118 137f46d8 Ermal
119 f81e7cc4 Renato Botelho
		/* grab sync to ip if enabled */
120
		if (isset($config['hasync']['synchronizetoip']) &&
121 8d44b2cb PiBa-NL
		    $config['hasync']['synchronizetoip'] == $this->remote_addr) {
122 f81e7cc4 Renato Botelho
			$this->loop_detected = true;
123
		}
124 3dd2a278 Scott Ullrich
	}
125 137f46d8 Ermal
126 f81e7cc4 Renato Botelho
	/**
127
	 * Get host version information
128
	 *
129
	 * @return array
130
	 */
131 de3f6463 Reid Linnemann
	public function host_firmware_version($dummy, $timeout) {
132 4f26f187 Viktor G
		ini_set('default_socket_timeout', $timeout);
133 dc5f639f PiBa-NL
		$this->auth();
134 f81e7cc4 Renato Botelho
		return host_firmware_version();
135
	}
136 21dc3a7d Colin Smith
137 f81e7cc4 Renato Botelho
	/**
138
	 * Executes a PHP block of code
139
	 *
140
	 * @param string $code
141
	 *
142
	 * @return bool
143
	 */
144 dc5f639f PiBa-NL
	public function exec_php($code) {
145
		$this->auth();
146 137f46d8 Ermal
147 f81e7cc4 Renato Botelho
		eval($code);
148
		if ($toreturn) {
149
			return $toreturn;
150
		}
151 c87f4b70 Ermal
152 f81e7cc4 Renato Botelho
		return true;
153 3dd2a278 Scott Ullrich
	}
154 137f46d8 Ermal
155 f81e7cc4 Renato Botelho
	/**
156
	 * Executes shell commands
157
	 *
158
	 * @param string $code
159
	 *
160
	 * @return bool
161
	 */
162 dc5f639f PiBa-NL
	public function exec_shell($code) {
163
		$this->auth();
164 50d49018 Colin Smith
165 f81e7cc4 Renato Botelho
		mwexec($code);
166
		return true;
167
	}
168 21dc3a7d Colin Smith
169 f81e7cc4 Renato Botelho
	/**
170
	 * Backup chosen config sections
171
	 *
172
	 * @param array $section
173
	 *
174
	 * @return array
175
	 */
176 dc5f639f PiBa-NL
	public function backup_config_section($section) {
177
		$this->auth();
178 137f46d8 Ermal
179 f81e7cc4 Renato Botelho
		global $config;
180 d026178f Renato Botelho
181 f81e7cc4 Renato Botelho
		return array_intersect_key($config, array_flip($section));
182 fb0eb20b Ermal
	}
183 c87f4b70 Ermal
184 f81e7cc4 Renato Botelho
	/**
185
	 * Restore defined config section into local config
186
	 *
187
	 * @param array $sections
188
	 *
189
	 * @return bool
190
	 */
191 4f26f187 Viktor G
	public function restore_config_section($sections, $timeout) {
192
		ini_set('default_socket_timeout', $timeout);
193 dc5f639f PiBa-NL
		$this->auth();
194 f81e7cc4 Renato Botelho
195 23fcdccc Viktor G
		global $config, $cpzone, $cpzoneid, $old_config;
196 1b99e1e5 jim-p
197 f81e7cc4 Renato Botelho
		$old_config = $config;
198
199
		if ($this->loop_detected) {
200
			log_error("Disallowing CARP sync loop");
201
			return true;
202
		}
203
204
		/*
205
		 * Some sections should just be copied and not merged or we end
206
		 * up unable to sync the deletion of the last item in a section
207
		 */
208
		$sync_full_sections = array(
209
			'aliases',
210
			'ca',
211
			'cert',
212
			'crl',
213
			'dhcpd',
214 30169caa Viktor G
			'dhcrelay',
215
			'dhcrelay6',
216 c9a96f16 Viktor Gurov
			'dnshaper',
217 f81e7cc4 Renato Botelho
			'dnsmasq',
218
			'filter',
219
			'ipsec',
220
			'nat',
221
			'openvpn',
222
			'schedules',
223 c9a96f16 Viktor Gurov
			'shaper',
224 f81e7cc4 Renato Botelho
			'unbound',
225
			'wol',
226
		);
227
228
		$syncd_full_sections = array();
229
230
		foreach ($sync_full_sections as $section) {
231
			if (!isset($sections[$section])) {
232
				continue;
233
			}
234
235
			$config[$section] = $sections[$section];
236
			unset($sections[$section]);
237
			$syncd_full_sections[] = $section;
238 1b99e1e5 jim-p
		}
239
240 146b0a43 Augustin-FL
		/* If captive portal sync is enabled on primary node, remove local CP on the secondary */
241
		if (is_array($config['captiveportal']) && is_array($sections['captiveportal'])) {
242 7cab6335 Renato Botelho
			foreach ($config['captiveportal'] as $zone => $item) {
243 146b0a43 Augustin-FL
				if (!isset($sections['captiveportal'][$zone])) {
244
					$cpzone = $zone;
245
					unset($config['captiveportal'][$cpzone]['enable']);
246
					captiveportal_configure_zone($config['captiveportal'][$cpzone]);
247
					unset($config['captiveportal'][$cpzone]);
248
					if (isset($config['voucher'][$cpzone])) {
249
						unset($config['voucher'][$cpzone]);
250
					}
251 c31f4e95 Viktor G
					unlink_if_exists("/var/db/captiveportal{$cpzone}.db");
252
					unlink_if_exists("/var/db/captiveportal_usedmacs_{$cpzone}.db");
253
					unlink_if_exists("/var/db/voucher_{$cpzone}_*.db");
254 7cab6335 Renato Botelho
				}
255
			}
256
		}
257
258 d3cc158c jim-p
		/* Only touch users if users are set to synchronize from the primary node
259
		 * See https://redmine.pfsense.org/issues/8450
260
		 */
261
		if ($sections['system']['user'] && $sections['system']['group']) {
262
			$g2add = array();
263
			$g2del = array();
264
			$g2del_idx = array();
265
			$g2keep = array();
266
			if (is_array($sections['system']['group'])) {
267
				$local_groups = isset($config['system']['group'])
268
				    ? $config['system']['group']
269
				    : array();
270
271
				foreach ($sections['system']['group'] as $group) {
272
					$idx = array_search($group['name'],
273
					    array_column($local_groups, 'name'));
274
275
					if ($idx === false) {
276
						$g2add[] = $group;
277
					} else if ($group['gid'] < 1999) {
278
						$g2keep[] = $idx;
279
					} else if ($group != $local_groups[$idx]) {
280
						$g2add[] = $group;
281
						$g2del[] = $group;
282
						$g2del_idx[] = $idx;
283
					} else {
284
						$g2keep[] = $idx;
285
					}
286 79f7bc7f Renato Botelho
				}
287
			}
288 d3cc158c jim-p
			if (is_array($config['system']['group'])) {
289
				foreach ($config['system']['group'] as $idx => $group) {
290
					if (array_search($idx, $g2keep) === false &&
291
					    array_search($idx, $g2del_idx) === false) {
292
						$g2del[] = $group;
293
						$g2del_idx[] = $idx;
294
					}
295 79f7bc7f Renato Botelho
				}
296
			}
297 d3cc158c jim-p
			unset($sections['system']['group'], $g2keep, $g2del_idx);
298
299
			$u2add = array();
300
			$u2del = array();
301
			$u2del_idx = array();
302
			$u2keep = array();
303
			if (is_array($sections['system']['user'])) {
304
				$local_users = isset($config['system']['user'])
305
				    ? $config['system']['user']
306
				    : array();
307
308
				foreach ($sections['system']['user'] as $user) {
309
					$idx = array_search($user['name'],
310
					    array_column($local_users, 'name'));
311
312
					if ($idx === false) {
313
						$u2add[] = $user;
314 f9ed5d57 James Webb
					} else if (($user['uid'] < 2000) && ($sections['hasync']['adminsync'] != 'on')) {
315 d3cc158c jim-p
						$u2keep[] = $idx;
316
					} else if ($user != $local_users[$idx]) {
317
						$u2add[] = $user;
318
						$u2del[] = $user;
319
						$u2del_idx[] = $idx;
320
					} else {
321
						$u2keep[] = $idx;
322
					}
323 79f7bc7f Renato Botelho
				}
324
			}
325 d3cc158c jim-p
			if (is_array($config['system']['user'])) {
326
				foreach ($config['system']['user'] as $idx => $user) {
327
					if (array_search($idx, $u2keep) === false &&
328
					    array_search($idx, $u2del_idx) === false) {
329
						$u2del[] = $user;
330
						$u2del_idx[] = $idx;
331
					}
332 79f7bc7f Renato Botelho
				}
333
			}
334 d3cc158c jim-p
			unset($sections['system']['user'], $u2keep, $u2del_idx);
335 79f7bc7f Renato Botelho
		}
336
337 b8963db6 Renato Botelho
		$voucher = array();
338
		if (is_array($sections['voucher'])) {
339
			/* Save voucher rolls to process after merge */
340
			$voucher = $sections['voucher'];
341
342
			foreach($sections['voucher'] as $zone => $item) {
343
				unset($sections['voucher'][$zone]['roll']);
344 06ef0830 Augustin-FL
				// Note : This code can be safely deleted once #97 fix has been applied and deployed to pfSense stable release.
345
				// Please do not delete this code before
346 b8963db6 Renato Botelho
				if (isset($config['voucher'][$zone]['vouchersyncdbip'])) {
347
					$sections['voucher'][$zone]['vouchersyncdbip'] =
348
					    $config['voucher'][$zone]['vouchersyncdbip'];
349
				} else {
350
					unset($sections['voucher'][$zone]['vouchersyncdbip']);
351
				}
352
				if (isset($config['voucher'][$zone]['vouchersyncusername'])) {
353
					$sections['voucher'][$zone]['vouchersyncusername'] =
354
					    $config['voucher'][$zone]['vouchersyncusername'];
355
				} else {
356
					unset($sections['voucher'][$zone]['vouchersyncusername']);
357
				}
358
				if (isset($config['voucher'][$zone]['vouchersyncpass'])) {
359
					$sections['voucher'][$zone]['vouchersyncpass'] =
360
					    $config['voucher'][$zone]['vouchersyncpass'];
361
				} else {
362
					unset($sections['voucher'][$zone]['vouchersyncpass']);
363
				}
364 06ef0830 Augustin-FL
				// End note.
365 b8963db6 Renato Botelho
			}
366
		}
367
368 06ef0830 Augustin-FL
		if (is_array($sections['captiveportal'])) {
369
			// Captiveportal : Backward HA settings should remain local.
370
			foreach ($sections['captiveportal'] as $zone => $cp) {
371
				if (isset($config['captiveportal'][$zone]['enablebackwardsync'])) {
372
					$sections['captiveportal'][$zone]['enablebackwardsync'] = $config['captiveportal'][$zone]['enablebackwardsync'];
373
				} else {
374
					unset($sections['captiveportal'][$zone]['enablebackwardsync']);
375
				}
376
				if (isset($config['captiveportal'][$zone]['backwardsyncip'])) {
377
					$sections['captiveportal'][$zone]['backwardsyncip'] = $config['captiveportal'][$zone]['backwardsyncip'];
378
				} else {
379
					unset($sections['captiveportal'][$zone]['backwardsyncip']);
380
				}
381
				if (isset($config['captiveportal'][$zone]['backwardsyncuser'])) {
382
					$sections['captiveportal'][$zone]['backwardsyncuser'] = $config['captiveportal'][$zone]['backwardsyncuser'];
383
				} else {
384
					unset($sections['captiveportal'][$zone]['backwardsyncuser']);
385
				}
386
				if (isset($config['captiveportal'][$zone]['backwardsyncpassword'])) {
387
					$sections['captiveportal'][$zone]['backwardsyncpassword'] = $config['captiveportal'][$zone]['backwardsyncpassword'];
388
				} else {
389
					unset($sections['captiveportal'][$zone]['vouchersyncpass']);
390
				}
391 b8963db6 Renato Botelho
			}
392 06ef0830 Augustin-FL
			$config['captiveportal'] = $sections['captiveportal'];
393
			unset($sections['captiveportal']);
394 b8963db6 Renato Botelho
		}
395
396 f81e7cc4 Renato Botelho
		$vipbackup = array();
397
		$oldvips = array();
398
		if (isset($sections['virtualip']) &&
399
		    is_array($config['virtualip']['vip'])) {
400
			foreach ($config['virtualip']['vip'] as $vip) {
401 c14781e3 Renato Botelho
				if ($vip['mode'] == "carp") {
402 f81e7cc4 Renato Botelho
					$key = $vip['interface'] .
403
					    "_vip" . $vip['vhid'];
404
405
					$oldvips[$key]['content'] =
406
					    $vip['password'] .
407
					    $vip['advskew'] .
408
					    $vip['subnet'] .
409
					    $vip['subnet_bits'] .
410
					    $vip['advbase'];
411
					$oldvips[$key]['interface'] =
412
					    $vip['interface'];
413
					$oldvips[$key]['subnet'] =
414
					    $vip['subnet'];
415
				} else if ($vip['mode'] == "ipalias" &&
416
				    (substr($vip['interface'], 0, 4) == '_vip'
417
				    || strstr($vip['interface'], "lo0"))) {
418
					$oldvips[$vip['subnet']]['content'] =
419
					    $vip['interface'] .
420
					    $vip['subnet'] .
421
					    $vip['subnet_bits'];
422
					$oldvips[$vip['subnet']]['interface'] =
423
					    $vip['interface'];
424
					$oldvips[$vip['subnet']]['subnet'] =
425
					    $vip['subnet'];
426
				} else if (($vip['mode'] == "ipalias" ||
427
				    $vip['mode'] == 'proxyarp') &&
428
				    !(substr($vip['interface'], 0, 4) == '_vip')
429
				    || strstr($vip['interface'], "lo0")) {
430 51611440 Ermal
					$vipbackup[] = $vip;
431 c14781e3 Renato Botelho
				}
432 51611440 Ermal
			}
433 19b5c3e7 Ermal
		}
434 f51d4f98 Ermal
435 f81e7cc4 Renato Botelho
		/* For vip section, first keep items sent from the master */
436
		$config = array_merge_recursive_unique($config, $sections);
437 51611440 Ermal
438 7cab6335 Renato Botelho
439 b8963db6 Renato Botelho
		/* Remove locally items removed remote */
440
		foreach ($voucher as $zone => $item) {
441
			/* No rolls on master, delete local ones */
442
			if (!is_array($item['roll'])) {
443
				unset($config['voucher'][$zone]['roll']);
444
			}
445
		}
446
447
		$l_rolls = array();
448
		if (is_array($config['voucher'])) {
449
			foreach ($config['voucher'] as $zone => $item) {
450
				if (!is_array($item['roll'])) {
451
					continue;
452
				}
453
				foreach ($item['roll'] as $idx => $roll) {
454
					/* Make it easy to find roll by # */
455
					$l_rolls[$zone][$roll['number']] = $idx;
456
				}
457
			}
458
		}
459
460
		/*
461
		 * Process vouchers sent by primary node and:
462
		 * - Add new items
463
		 * - Update existing items based on 'lastsync' field
464
		 */
465
		foreach ($voucher as $zone => $item) {
466
			if (!is_array($item['roll'])) {
467
				continue;
468
			}
469 d35a18fc Christian McDonald
			foreach ($item['roll'] as $roll) {
470 b8963db6 Renato Botelho
				if (!isset($l_rolls[$zone][$roll['number']])) {
471
					$config['voucher'][$zone]['roll'][] =
472
					    $roll;
473
					continue;
474
				}
475
				$l_roll_idx = $l_rolls[$zone][$roll['number']];
476 c6c398c6 jim-p
				init_config_arr(array('voucher', $zone));
477 b8963db6 Renato Botelho
				$l_vouchers = &$config['voucher'][$zone];
478
				$l_roll = $l_vouchers['roll'][$l_roll_idx];
479
				if (!isset($l_roll['lastsync'])) {
480
					$l_roll['lastsync'] = 0;
481
				}
482
483
				if (isset($roll['lastsync']) &&
484
				    $roll['lastsync'] != $l_roll['lastsync']) {
485
					$l_vouchers['roll'][$l_roll_idx] =
486
					    $roll;
487
					unset($l_rolls[$zone][$roll['number']]);
488
				}
489
			}
490
		}
491
492
		/*
493
		 * At this point $l_rolls contains only items that are not
494
		 * present on primary node. They must be removed
495
		 */
496
		foreach ($l_rolls as $zone => $item) {
497 d35a18fc Christian McDonald
			foreach ($item as $idx) {
498 b8963db6 Renato Botelho
				unset($config['voucher'][$zone][$idx]);
499
			}
500
		}
501
502 f81e7cc4 Renato Botelho
		/*
503
		 * Then add ipalias and proxyarp types already defined
504
		 * on the backup
505
		 */
506
		if (is_array($vipbackup) && !empty($vipbackup)) {
507
			if (!is_array($config['virtualip'])) {
508
				$config['virtualip'] = array();
509
			}
510
			if (!is_array($config['virtualip']['vip'])) {
511
				$config['virtualip']['vip'] = array();
512
			}
513
			foreach ($vipbackup as $vip) {
514
				array_unshift($config['virtualip']['vip'], $vip);
515
			}
516 962f215d Phil Davis
		}
517 51611440 Ermal
518 f81e7cc4 Renato Botelho
		/* Log what happened */
519 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_merge(array_keys($sections),
520 f81e7cc4 Renato Botelho
		    $syncd_full_sections));
521
		write_config(sprintf(gettext(
522
		    "Merged in config (%s sections) from XMLRPC client."),
523
		    $mergedkeys));
524
525
		/*
526
		 * The real work on handling the vips specially
527 51b0b50b jim-p
		 * This is a copy of interfaces_vips_configure with addition of
528 f81e7cc4 Renato Botelho
		 * not reloading existing/not changed carps
529
		 */
530 23fcdccc Viktor G
		$force_filterconfigure = false;
531 f81e7cc4 Renato Botelho
		if (isset($sections['virtualip']) &&
532
		    is_array($config['virtualip']) &&
533
		    is_array($config['virtualip']['vip'])) {
534
			$carp_setuped = false;
535
			$anyproxyarp = false;
536
537
			foreach ($config['virtualip']['vip'] as $vip) {
538
				$key = "{$vip['interface']}_vip{$vip['vhid']}";
539
540
				if ($vip['mode'] == "carp" &&
541
				    isset($oldvips[$key])) {
542
					if ($oldvips[$key]['content'] ==
543
					    $vip['password'] .
544
					    $vip['advskew'] .
545
					    $vip['subnet'] .
546
					    $vip['subnet_bits'] .
547
					    $vip['advbase'] &&
548
					    does_vip_exist($vip)) {
549
						unset($oldvips[$key]);
550
						/*
551
						 * Skip reconfiguring this vips
552
						 * since nothing has changed.
553
						 */
554
						continue;
555 19ed1624 Ermal
					}
556 5fda51cd jim-p
557 f81e7cc4 Renato Botelho
				} elseif ($vip['mode'] == "ipalias" &&
558 5fda51cd jim-p
				    (substr($vip['interface'], 0, 4) == '_vip'
559
				    || strstr($vip['interface'], "lo0")) &&
560 f81e7cc4 Renato Botelho
				    isset($oldvips[$vip['subnet']])) {
561
					$key = $vip['subnet'];
562
					if ($oldvips[$key]['content'] ==
563
					    $vip['interface'] .
564
					    $vip['subnet'] .
565
					    $vip['subnet_bits'] &&
566
					    does_vip_exist($vip)) {
567
						unset($oldvips[$key]);
568
						/*
569
						 * Skip reconfiguring this vips
570
						 * since nothing has changed.
571
						 */
572
						continue;
573 2708a5cf Ermal
					}
574 f81e7cc4 Renato Botelho
					unset($oldvips[$key]);
575 2708a5cf Ermal
				}
576 51611440 Ermal
577 f81e7cc4 Renato Botelho
				switch ($vip['mode']) {
578 962f215d Phil Davis
				case "proxyarp":
579
					$anyproxyarp = true;
580
					break;
581
				case "ipalias":
582
					interface_ipalias_configure($vip);
583
					break;
584
				case "carp":
585 f81e7cc4 Renato Botelho
					$carp_setuped = true;
586 3c15b353 Viktor G
					if (does_vip_exist($vip) && isset($oldvips[$key]['vhid']) &&
587
					    ($oldvips[$key]['vhid'] ^ $vip['vhid'])) {
588
						/* properly remove the old VHID
589
						 * see https://redmine.pfsense.org/issues/12202 */
590
						$realif = get_real_interface($vip['interface']);
591
						mwexec("/sbin/ifconfig {$realif} " .
592
							escapeshellarg($vip['subnet']) . " -alias");
593
						$ipalias_reload = true;
594
					} else {
595
						$ipalias_reload = false;
596
					}
597
					interface_carp_configure($vip, false, $ipalias_reload);
598 962f215d Phil Davis
					break;
599 f81e7cc4 Renato Botelho
				}
600 23fcdccc Viktor G
				$force_filterconfigure = true;
601 51611440 Ermal
			}
602 f81e7cc4 Renato Botelho
603
			/* Cleanup remaining old carps */
604
			foreach ($oldvips as $oldvipar) {
605
				$oldvipif = get_real_interface(
606
				    $oldvipar['interface']);
607
608
				if (empty($oldvipif)) {
609
					continue;
610
				}
611
612 e7cac368 Viktor G
				/* do not remove VIP if the IP address remains the same */
613
				foreach ($config['virtualip']['vip'] as $vip) {
614
					if ($vip['subnet'] == $oldvipar['subnet']) {
615
						continue 2;
616
					}
617
				}
618
619 962f215d Phil Davis
				if (is_ipaddrv6($oldvipar['subnet'])) {
620 f81e7cc4 Renato Botelho
					 mwexec("/sbin/ifconfig " .
621
					     escapeshellarg($oldvipif) .
622
					     " inet6 " .
623
					     escapeshellarg($oldvipar['subnet']) .
624
					     " delete");
625 962f215d Phil Davis
				} else {
626 f81e7cc4 Renato Botelho
					pfSense_interface_deladdress($oldvipif,
627
					    $oldvipar['subnet']);
628 962f215d Phil Davis
				}
629 e3cffd6c Ermal LUÇI
			}
630 f81e7cc4 Renato Botelho
			if ($carp_setuped == true) {
631
				interfaces_sync_setup();
632
			}
633
			if ($anyproxyarp == true) {
634
				interface_proxyarp_configure();
635
			}
636 51611440 Ermal
		}
637 f81e7cc4 Renato Botelho
638 79f7bc7f Renato Botelho
		local_sync_accounts($u2add, $u2del, $g2add, $g2del);
639 23fcdccc Viktor G
		$this->filter_configure(false, $force_filterconfigure);
640
		unset($old_config);
641 79f7bc7f Renato Botelho
642 f81e7cc4 Renato Botelho
		return true;
643 962f215d Phil Davis
	}
644 d026178f Renato Botelho
645 f81e7cc4 Renato Botelho
	/**
646
	 * Merge items into installedpackages config section
647
	 *
648
	 * @param array $section
649
	 *
650
	 * @return bool
651
	 */
652 4f26f187 Viktor G
	public function merge_installedpackages_section($section, $timeout) {
653
		ini_set('default_socket_timeout', $timeout);
654 dc5f639f PiBa-NL
		$this->auth();
655 d026178f Renato Botelho
656 f81e7cc4 Renato Botelho
		global $config;
657 50d49018 Colin Smith
658 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
659
			log_error("Disallowing CARP sync loop");
660
			return true;
661
		}
662 82ae5cfc Scott Ullrich
663 f81e7cc4 Renato Botelho
		$config['installedpackages'] = array_merge(
664
		    $config['installedpackages'], $section);
665 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_keys($section));
666 f81e7cc4 Renato Botelho
		write_config(sprintf(gettext(
667
		    "Merged in config (%s sections) from XMLRPC client."),
668
		    $mergedkeys));
669 137f46d8 Ermal
670 f81e7cc4 Renato Botelho
		return true;
671 fb0eb20b Ermal
	}
672 c87f4b70 Ermal
673 f81e7cc4 Renato Botelho
	/**
674
	 * Merge items into config
675
	 *
676
	 * @param array $section
677
	 *
678
	 * @return bool
679
	 */
680 4f26f187 Viktor G
	public function merge_config_section($section, $timeout) {
681
		ini_set('default_socket_timeout', $timeout);
682 dc5f639f PiBa-NL
		$this->auth();
683 137f46d8 Ermal
684 f81e7cc4 Renato Botelho
		global $config;
685 82ae5cfc Scott Ullrich
686 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
687
			log_error("Disallowing CARP sync loop");
688
			return true;
689
		}
690 dc1cd85d Scott Ullrich
691 f81e7cc4 Renato Botelho
		$config_new = $this->array_overlay($config, $section);
692
		$config = $config_new;
693 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_keys($section));
694 f81e7cc4 Renato Botelho
		write_config(sprintf(gettext(
695
		    "Merged in config (%s sections) from XMLRPC client."),
696
		    $mergedkeys));
697 c87f4b70 Ermal
698 f81e7cc4 Renato Botelho
		return true;
699 fb0eb20b Ermal
	}
700 c87f4b70 Ermal
701 f81e7cc4 Renato Botelho
	/**
702
	 * Wrapper for filter_configure()
703
	 *
704
	 * @return bool
705 57b5da70 jim-p
	 */
706 23fcdccc Viktor G
	private function filter_configure($reset_accounts = true, $force = false) {
707
		global $g, $config, $old_config;
708 f81e7cc4 Renato Botelho
709
		filter_configure();
710
		system_routing_configure();
711
		setup_gateways_monitor();
712 23fcdccc Viktor G
713
		/* do not restart unchanged services on XMLRPC sync,
714
		 * see https://redmine.pfsense.org/issues/11082 
715
		 */
716
		if (is_array($config['openvpn']) || is_array($old_config['openvpn'])) {
717
			foreach (array("server", "client") as $type) {
718
				$remove_id = array();
719
				if (is_array($old_config['openvpn']["openvpn-{$type}"])) {
720
					foreach ($old_config['openvpn']["openvpn-{$type}"] as & $old_settings) {
721
						$remove_id[] = $old_settings['vpnid'];
722
					}
723
				}
724
				if (!is_array($config['openvpn']["openvpn-{$type}"])) {
725
					continue;
726
				}
727
				foreach ($config['openvpn']["openvpn-{$type}"] as & $settings) {
728
					$new_instance = true;
729
					if (in_array($settings['vpnid'], $remove_id)) {
730
						$remove_id = array_diff($remove_id, array($settings['vpnid']));
731
					}
732
					if (is_array($old_config['openvpn']["openvpn-{$type}"])) {
733
						foreach ($old_config['openvpn']["openvpn-{$type}"] as & $old_settings) {
734
							if ($settings['vpnid'] == $old_settings['vpnid']) {
735
								$new_instance = false;
736
								if (($settings != $old_settings) || $force) {
737
									/* restart changed openvpn instance */
738
									openvpn_resync($type, $settings);
739
									break;
740
								}
741
							}
742
						}
743
					}
744
					if ($new_instance) {
745
						/* start new openvpn instance */
746
						openvpn_resync($type, $settings);
747
					}
748
				}
749
				if (!empty($remove_id)) {
750
					foreach ($remove_id as $id) {
751
						/* stop/delete removed openvpn instances */
752
						openvpn_delete($type, array('vpnid' => $id));
753
					}
754
				}
755
			}
756
			/* no service restart required */
757
			openvpn_resync_csc_all();
758
		}
759 f81e7cc4 Renato Botelho
760 6ae26227 Viktor G
		/* run ipsec_configure() on any IPsec change, see https://redmine.pfsense.org/issues/12075 */
761
		if (((is_array($config['ipsec']) || is_array($old_config['ipsec'])) &&
762
		    ($config['ipsec'] != $old_config['ipsec'])) ||
763
		    $force) {
764
			ipsec_configure();
765
		}
766
767 f81e7cc4 Renato Botelho
		/*
768
		 * The DNS Resolver and the DNS Forwarder may both be active so
769
		 * long as * they are running on different ports.
770
		 * See ticket #5882
771
		 */
772 23fcdccc Viktor G
		if (((is_array($config['dnsmasq']) || is_array($old_config['dnsmasq'])) &&
773
		    ($config['dnsmasq'] != $old_config['dnsmasq'])) ||
774
		    $force) {
775
			if (isset($config['dnsmasq']['enable'])) {
776
				/* Configure dnsmasq but tell it NOT to restart DHCP */
777
				services_dnsmasq_configure(false);
778
			} else {
779
				/* kill any running dnsmasq instance */
780
				if (isvalidpid("{$g['varrun_path']}/dnsmasq.pid")) {
781
					sigkillbypid("{$g['varrun_path']}/dnsmasq.pid",
782
					    "TERM");
783
				}
784 f81e7cc4 Renato Botelho
			}
785 57b5da70 jim-p
		}
786 23fcdccc Viktor G
		if (((is_array($config['unbound']) || is_array($old_config['unbound'])) &&
787
		    ($config['unbound'] != $old_config['unbound'])) ||
788
		    $force) {
789
			if (isset($config['unbound']['enable'])) {
790
				/* Configure unbound but tell it NOT to restart DHCP */
791
				services_unbound_configure(false);
792
			} else {
793
				/* kill any running Unbound instance */
794
				if (isvalidpid("{$g['varrun_path']}/unbound.pid")) {
795
					sigkillbypid("{$g['varrun_path']}/unbound.pid",
796
					    "TERM");
797
				}
798 f81e7cc4 Renato Botelho
			}
799 57b5da70 jim-p
		}
800 137f46d8 Ermal
801 f81e7cc4 Renato Botelho
		/*
802
		 * Call this separately since the above are manually set to
803
		 * skip the DHCP restart they normally perform.
804
		 * This avoids restarting dhcpd twice as described on
805
		 * ticket #3797
806
		 */
807 23fcdccc Viktor G
		if (((is_array($config['dhcpd']) || is_array($old_config['dhcpd'])) &&
808
		    ($config['dhcpd'] != $old_config['dhcpd'])) ||
809
		    $force) {
810
			services_dhcpd_configure();
811
		}
812 137f46d8 Ermal
813 30169caa Viktor G
		if (((is_array($config['dhcrelay']) || is_array($old_config['dhcrelay'])) &&
814
		    ($config['dhcrelay'] != $old_config['dhcrelay'])) ||
815
		    $force) {
816
			services_dhcrelay_configure();
817
		}
818
819
		if (((is_array($config['dhcrelay6']) || is_array($old_config['dhcrelay6'])) &&
820
		    ($config['dhcrelay6'] != $old_config['dhcrelay6'])) ||
821
		    $force) {
822
			services_dhcrelay6_configure();
823
		}
824
825 79f7bc7f Renato Botelho
		if ($reset_accounts) {
826
			local_reset_accounts();
827
		}
828 c87f4b70 Ermal
829 23fcdccc Viktor G
		if ((is_array($config['captiveportal']) || is_array($old_config['captiveportal']) &&
830
		    ($config['captiveportal'] != $old_config['captiveportal'])) ||
831
		    $force) {
832
			captiveportal_configure();
833
		}
834
		if ((is_array($config['voucher']) || is_array($old_config['voucher']) &&
835
		    ($config['voucher'] != $old_config['voucher'])) ||
836
		    $force) {
837
			voucher_configure();
838
		}
839 7cab6335 Renato Botelho
840 f81e7cc4 Renato Botelho
		return true;
841 3dd2a278 Scott Ullrich
	}
842 137f46d8 Ermal
843 24600471 Augustin-FL
	/**
844
	 * Wrapper for captiveportal connected users and
845
	 * active/expired vouchers synchronization
846
	 *
847
	 * @param array $arguments
848
	 *
849
	 * @return array
850
	 */
851 4f26f187 Viktor G
	public function captive_portal_sync($arguments, $timeout) {
852
		ini_set('default_socket_timeout', $timeout);
853 24600471 Augustin-FL
		$this->auth();
854
		// Note : no protection against CARP loop is done here, and this is in purpose.
855
		// This function is used for bi-directionnal sync, which is precisely what CARP loop protection is supposed to prevent.
856
		// CARP loop has to be managed within functions using captive_portal_sync()
857
		global $g, $config, $cpzone;
858
859
		if (empty($arguments['op']) || empty($arguments['zone']) || empty($config['captiveportal'][$arguments['zone']])) {
860
			return false;
861
		}
862
		$cpzone = $arguments['zone'];
863
864
		if ($arguments['op'] === 'get_databases') {
865
			$active_vouchers = array();
866
			$expired_vouchers = array();
867 a81a6edc Viktor G
			$usedmacs = '';
868 24600471 Augustin-FL
869
			if (is_array($config['voucher'][$cpzone]['roll'])) {
870 d35a18fc Christian McDonald
				foreach($config['voucher'][$cpzone]['roll'] as $roll) {
871 24600471 Augustin-FL
					$expired_vouchers[$roll['number']] = base64_encode(voucher_read_used_db($roll['number']));
872
					$active_vouchers[$roll['number']] = voucher_read_active_db($roll['number']);
873
				}
874
			}
875 a81a6edc Viktor G
			if (!empty($config['captiveportal'][$cpzone]['freelogins_count']) &&
876
			    !empty($config['captiveportal'][$cpzone]['freelogins_resettimeout'])) {
877
				$usedmacs = captiveportal_read_usedmacs_db();
878
			}
879 24600471 Augustin-FL
			// base64 is here for safety reasons, as we don't fully control
880
			// the content of these arrays.
881
			$returndata = array('connected_users' => base64_encode(serialize(captiveportal_read_db())),
882
			'active_vouchers' => base64_encode(serialize($active_vouchers)),
883 a81a6edc Viktor G
			'expired_vouchers' => base64_encode(serialize($expired_vouchers)),
884
			'usedmacs' => base64_encode(serialize($usedmacs)));
885 24600471 Augustin-FL
886
			return $returndata;
887
		} elseif ($arguments['op'] === 'connect_user') {
888
			$user = unserialize(base64_decode($arguments['user']));
889
			$user['attributes']['allow_time'] = $user['allow_time'];
890
891
			// pipeno might be different between primary and secondary
892
			$pipeno = captiveportal_get_next_dn_ruleno('auth');
893
			return portal_allow($user['clientip'], $user['clientmac'], $user['username'], $user['password'], null,
894
			    $user['attributes'], $pipeno, $user['authmethod'], $user['context'], $user['sessionid']);
895 4a778ba9 Augustin-FL
		} elseif ($arguments['op'] === 'disconnect_user') {
896
			$session = unserialize(base64_decode($arguments['session']));
897
			/* read database again, as pipeno might be different between primary & secondary */
898
			$sessionid = SQLite3::escapeString($session['sessionid']);
899
			$local_dbentry = captiveportal_read_db("WHERE sessionid = '{$sessionid}'");
900
901
			if (!empty($local_dbentry) && count($local_dbentry) == 1) {
902
				return captiveportal_disconnect($local_dbentry[0], $session['term_cause'], $session['stop_time'], true);
903
			} else {
904
				return false;
905
			}
906
		} elseif ($arguments['op'] === 'remove_entries') {
907
			$entries = unserialize(base64_decode($arguments['entries']));
908
909
			return captiveportal_remove_entries($entries, true);
910 78784180 Augustin-FL
		} elseif ($arguments['op'] === 'disconnect_all') {
911
			$arguments = unserialize(base64_decode($arguments['arguments']));
912
913
			return captiveportal_disconnect_all($arguments['term_cause'], $arguments['logout_reason'], true);
914 318e3f81 Augustin-FL
		} elseif ($arguments['op'] === 'write_vouchers') {
915
			$arguments = unserialize(base64_decode($arguments['arguments']));
916
917
			if (is_array($arguments['active_and_used_vouchers_bitmasks'])) {
918
				foreach ($arguments['active_and_used_vouchers_bitmasks'] as $roll => $used) {
919
					if (is_array($used)) {
920
						foreach ($used as $u) {
921
							voucher_write_used_db($roll, base64_encode($u));
922
						}
923
					} else {
924
						voucher_write_used_db($roll, base64_encode($used));
925
					}
926
				}
927
			}
928
			foreach ($arguments['active_vouchers'] as $roll => $active_vouchers) {
929
				voucher_write_active_db($roll, $active_vouchers);
930
			}
931
			return true;
932 a81a6edc Viktor G
		} elseif ($arguments['op'] === 'write_usedmacs') {
933
			$arguments = unserialize(base64_decode($arguments['arguments']));
934
935
			captiveportal_write_usedmacs_db($arguments['usedmacs']); 
936
			return true;
937 24600471 Augustin-FL
		}
938
	}
939
940 f81e7cc4 Renato Botelho
	/**
941
	 * Wrapper for configuring CARP interfaces
942
	 *
943
	 * @return bool
944
	 */
945 dc5f639f PiBa-NL
	public function interfaces_carp_configure() {
946
		$this->auth();
947 efe7562e Scott Ullrich
948 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
949
			log_error("Disallowing CARP sync loop");
950
			return true;
951
		}
952 0567899d Ermal
953 f81e7cc4 Renato Botelho
		interfaces_vips_configure();
954 e501de37 Ermal
955 f81e7cc4 Renato Botelho
		return true;
956
	}
957 e501de37 Ermal
958 f81e7cc4 Renato Botelho
	/**
959
	 * Wrapper for rc.reboot
960
	 *
961
	 * @return bool
962
	 */
963 dc5f639f PiBa-NL
	public function reboot() {
964
		$this->auth();
965 e501de37 Ermal
966 f81e7cc4 Renato Botelho
		mwexec_bg("/etc/rc.reboot");
967 137f46d8 Ermal
968 f81e7cc4 Renato Botelho
		return true;
969 3dd2a278 Scott Ullrich
	}
970 d9064267 Colin Smith
}
971
972 f3f98e97 Phil Davis
// run script until its done and can 'unlock' the xmlrpc.lock, this prevents hanging php-fpm / webgui
973 179377b0 robjarsen
ignore_user_abort(true);
974 8239af2d PiBa-NL
set_time_limit(0);
975
976 67d78c87 Ermal
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
977
978 f81e7cc4 Renato Botelho
XML_RPC2_Backend::setBackend('php');
979
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
980
981
$options = array(
982
	'prefix' => 'pfsense.',
983
	'encoding' => 'utf-8',
984 4f78ae1d Renato Botelho
	'autoDocument' => false,
985 50d49018 Colin Smith
);
986 b298dd06 Scott Ullrich
987 f81e7cc4 Renato Botelho
$server = XML_RPC2_Server::create(new pfsense_xmlrpc_server(), $options);
988
$server->handleCall();
989 67d78c87 Ermal
990 f81e7cc4 Renato Botelho
unlock($xmlrpclockkey);
991 0b581a8a Scott Ullrich
992 de63649b Rafael Lucas
?>