Project

General

Profile

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