Project

General

Profile

Download (23.4 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 7cab6335 Renato Botelho
				}
249
			}
250
		}
251
252 d3cc158c jim-p
		/* Only touch users if users are set to synchronize from the primary node
253
		 * See https://redmine.pfsense.org/issues/8450
254
		 */
255
		if ($sections['system']['user'] && $sections['system']['group']) {
256
			$g2add = array();
257
			$g2del = array();
258
			$g2del_idx = array();
259
			$g2keep = array();
260
			if (is_array($sections['system']['group'])) {
261
				$local_groups = isset($config['system']['group'])
262
				    ? $config['system']['group']
263
				    : array();
264
265
				foreach ($sections['system']['group'] as $group) {
266
					$idx = array_search($group['name'],
267
					    array_column($local_groups, 'name'));
268
269
					if ($idx === false) {
270
						$g2add[] = $group;
271
					} else if ($group['gid'] < 1999) {
272
						$g2keep[] = $idx;
273
					} else if ($group != $local_groups[$idx]) {
274
						$g2add[] = $group;
275
						$g2del[] = $group;
276
						$g2del_idx[] = $idx;
277
					} else {
278
						$g2keep[] = $idx;
279
					}
280 79f7bc7f Renato Botelho
				}
281
			}
282 d3cc158c jim-p
			if (is_array($config['system']['group'])) {
283
				foreach ($config['system']['group'] as $idx => $group) {
284
					if (array_search($idx, $g2keep) === false &&
285
					    array_search($idx, $g2del_idx) === false) {
286
						$g2del[] = $group;
287
						$g2del_idx[] = $idx;
288
					}
289 79f7bc7f Renato Botelho
				}
290
			}
291 d3cc158c jim-p
			unset($sections['system']['group'], $g2keep, $g2del_idx);
292
293
			$u2add = array();
294
			$u2del = array();
295
			$u2del_idx = array();
296
			$u2keep = array();
297
			if (is_array($sections['system']['user'])) {
298
				$local_users = isset($config['system']['user'])
299
				    ? $config['system']['user']
300
				    : array();
301
302
				foreach ($sections['system']['user'] as $user) {
303
					$idx = array_search($user['name'],
304
					    array_column($local_users, 'name'));
305
306
					if ($idx === false) {
307
						$u2add[] = $user;
308 f9ed5d57 James Webb
					} else if (($user['uid'] < 2000) && ($sections['hasync']['adminsync'] != 'on')) {
309 d3cc158c jim-p
						$u2keep[] = $idx;
310
					} else if ($user != $local_users[$idx]) {
311
						$u2add[] = $user;
312
						$u2del[] = $user;
313
						$u2del_idx[] = $idx;
314
					} else {
315
						$u2keep[] = $idx;
316
					}
317 79f7bc7f Renato Botelho
				}
318
			}
319 d3cc158c jim-p
			if (is_array($config['system']['user'])) {
320
				foreach ($config['system']['user'] as $idx => $user) {
321
					if (array_search($idx, $u2keep) === false &&
322
					    array_search($idx, $u2del_idx) === false) {
323
						$u2del[] = $user;
324
						$u2del_idx[] = $idx;
325
					}
326 79f7bc7f Renato Botelho
				}
327
			}
328 d3cc158c jim-p
			unset($sections['system']['user'], $u2keep, $u2del_idx);
329 79f7bc7f Renato Botelho
		}
330
331 b8963db6 Renato Botelho
		$voucher = array();
332
		if (is_array($sections['voucher'])) {
333
			/* Save voucher rolls to process after merge */
334
			$voucher = $sections['voucher'];
335
336
			foreach($sections['voucher'] as $zone => $item) {
337
				unset($sections['voucher'][$zone]['roll']);
338 06ef0830 Augustin-FL
				// Note : This code can be safely deleted once #97 fix has been applied and deployed to pfSense stable release.
339
				// Please do not delete this code before
340 b8963db6 Renato Botelho
				if (isset($config['voucher'][$zone]['vouchersyncdbip'])) {
341
					$sections['voucher'][$zone]['vouchersyncdbip'] =
342
					    $config['voucher'][$zone]['vouchersyncdbip'];
343
				} else {
344
					unset($sections['voucher'][$zone]['vouchersyncdbip']);
345
				}
346
				if (isset($config['voucher'][$zone]['vouchersyncusername'])) {
347
					$sections['voucher'][$zone]['vouchersyncusername'] =
348
					    $config['voucher'][$zone]['vouchersyncusername'];
349
				} else {
350
					unset($sections['voucher'][$zone]['vouchersyncusername']);
351
				}
352
				if (isset($config['voucher'][$zone]['vouchersyncpass'])) {
353
					$sections['voucher'][$zone]['vouchersyncpass'] =
354
					    $config['voucher'][$zone]['vouchersyncpass'];
355
				} else {
356
					unset($sections['voucher'][$zone]['vouchersyncpass']);
357
				}
358 06ef0830 Augustin-FL
				// End note.
359 b8963db6 Renato Botelho
			}
360
		}
361
362 06ef0830 Augustin-FL
		if (is_array($sections['captiveportal'])) {
363
			// Captiveportal : Backward HA settings should remain local.
364
			foreach ($sections['captiveportal'] as $zone => $cp) {
365
				if (isset($config['captiveportal'][$zone]['enablebackwardsync'])) {
366
					$sections['captiveportal'][$zone]['enablebackwardsync'] = $config['captiveportal'][$zone]['enablebackwardsync'];
367
				} else {
368
					unset($sections['captiveportal'][$zone]['enablebackwardsync']);
369
				}
370
				if (isset($config['captiveportal'][$zone]['backwardsyncip'])) {
371
					$sections['captiveportal'][$zone]['backwardsyncip'] = $config['captiveportal'][$zone]['backwardsyncip'];
372
				} else {
373
					unset($sections['captiveportal'][$zone]['backwardsyncip']);
374
				}
375
				if (isset($config['captiveportal'][$zone]['backwardsyncuser'])) {
376
					$sections['captiveportal'][$zone]['backwardsyncuser'] = $config['captiveportal'][$zone]['backwardsyncuser'];
377
				} else {
378
					unset($sections['captiveportal'][$zone]['backwardsyncuser']);
379
				}
380
				if (isset($config['captiveportal'][$zone]['backwardsyncpassword'])) {
381
					$sections['captiveportal'][$zone]['backwardsyncpassword'] = $config['captiveportal'][$zone]['backwardsyncpassword'];
382
				} else {
383
					unset($sections['captiveportal'][$zone]['vouchersyncpass']);
384
				}
385 b8963db6 Renato Botelho
			}
386 06ef0830 Augustin-FL
			$config['captiveportal'] = $sections['captiveportal'];
387
			unset($sections['captiveportal']);
388 b8963db6 Renato Botelho
		}
389
390 f81e7cc4 Renato Botelho
		$vipbackup = array();
391
		$oldvips = array();
392
		if (isset($sections['virtualip']) &&
393
		    is_array($config['virtualip']['vip'])) {
394
			foreach ($config['virtualip']['vip'] as $vip) {
395 c14781e3 Renato Botelho
				if ($vip['mode'] == "carp") {
396 f81e7cc4 Renato Botelho
					$key = $vip['interface'] .
397
					    "_vip" . $vip['vhid'];
398
399
					$oldvips[$key]['content'] =
400
					    $vip['password'] .
401
					    $vip['advskew'] .
402
					    $vip['subnet'] .
403
					    $vip['subnet_bits'] .
404
					    $vip['advbase'];
405
					$oldvips[$key]['interface'] =
406
					    $vip['interface'];
407
					$oldvips[$key]['subnet'] =
408
					    $vip['subnet'];
409
				} else if ($vip['mode'] == "ipalias" &&
410
				    (substr($vip['interface'], 0, 4) == '_vip'
411
				    || strstr($vip['interface'], "lo0"))) {
412
					$oldvips[$vip['subnet']]['content'] =
413
					    $vip['interface'] .
414
					    $vip['subnet'] .
415
					    $vip['subnet_bits'];
416
					$oldvips[$vip['subnet']]['interface'] =
417
					    $vip['interface'];
418
					$oldvips[$vip['subnet']]['subnet'] =
419
					    $vip['subnet'];
420
				} else if (($vip['mode'] == "ipalias" ||
421
				    $vip['mode'] == 'proxyarp') &&
422
				    !(substr($vip['interface'], 0, 4) == '_vip')
423
				    || strstr($vip['interface'], "lo0")) {
424 51611440 Ermal
					$vipbackup[] = $vip;
425 c14781e3 Renato Botelho
				}
426 51611440 Ermal
			}
427 19b5c3e7 Ermal
		}
428 f51d4f98 Ermal
429 f81e7cc4 Renato Botelho
		/* For vip section, first keep items sent from the master */
430
		$config = array_merge_recursive_unique($config, $sections);
431 51611440 Ermal
432 7cab6335 Renato Botelho
433 b8963db6 Renato Botelho
		/* Remove locally items removed remote */
434
		foreach ($voucher as $zone => $item) {
435
			/* No rolls on master, delete local ones */
436
			if (!is_array($item['roll'])) {
437
				unset($config['voucher'][$zone]['roll']);
438
			}
439
		}
440
441
		$l_rolls = array();
442
		if (is_array($config['voucher'])) {
443
			foreach ($config['voucher'] as $zone => $item) {
444
				if (!is_array($item['roll'])) {
445
					continue;
446
				}
447
				foreach ($item['roll'] as $idx => $roll) {
448
					/* Make it easy to find roll by # */
449
					$l_rolls[$zone][$roll['number']] = $idx;
450
				}
451
			}
452
		}
453
454
		/*
455
		 * Process vouchers sent by primary node and:
456
		 * - Add new items
457
		 * - Update existing items based on 'lastsync' field
458
		 */
459
		foreach ($voucher as $zone => $item) {
460
			if (!is_array($item['roll'])) {
461
				continue;
462
			}
463
			foreach ($item['roll'] as $idx => $roll) {
464
				if (!isset($l_rolls[$zone][$roll['number']])) {
465
					$config['voucher'][$zone]['roll'][] =
466
					    $roll;
467
					continue;
468
				}
469
				$l_roll_idx = $l_rolls[$zone][$roll['number']];
470 c6c398c6 jim-p
				init_config_arr(array('voucher', $zone));
471 b8963db6 Renato Botelho
				$l_vouchers = &$config['voucher'][$zone];
472
				$l_roll = $l_vouchers['roll'][$l_roll_idx];
473
				if (!isset($l_roll['lastsync'])) {
474
					$l_roll['lastsync'] = 0;
475
				}
476
477
				if (isset($roll['lastsync']) &&
478
				    $roll['lastsync'] != $l_roll['lastsync']) {
479
					$l_vouchers['roll'][$l_roll_idx] =
480
					    $roll;
481
					unset($l_rolls[$zone][$roll['number']]);
482
				}
483
			}
484
		}
485
486
		/*
487
		 * At this point $l_rolls contains only items that are not
488
		 * present on primary node. They must be removed
489
		 */
490
		foreach ($l_rolls as $zone => $item) {
491
			foreach ($item as $number => $idx) {
492
				unset($config['voucher'][$zone][$idx]);
493
			}
494
		}
495
496 f81e7cc4 Renato Botelho
		/*
497
		 * Then add ipalias and proxyarp types already defined
498
		 * on the backup
499
		 */
500
		if (is_array($vipbackup) && !empty($vipbackup)) {
501
			if (!is_array($config['virtualip'])) {
502
				$config['virtualip'] = array();
503
			}
504
			if (!is_array($config['virtualip']['vip'])) {
505
				$config['virtualip']['vip'] = array();
506
			}
507
			foreach ($vipbackup as $vip) {
508
				array_unshift($config['virtualip']['vip'], $vip);
509
			}
510 962f215d Phil Davis
		}
511 51611440 Ermal
512 f81e7cc4 Renato Botelho
		/* Log what happened */
513 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_merge(array_keys($sections),
514 f81e7cc4 Renato Botelho
		    $syncd_full_sections));
515
		write_config(sprintf(gettext(
516
		    "Merged in config (%s sections) from XMLRPC client."),
517
		    $mergedkeys));
518
519
		/*
520
		 * The real work on handling the vips specially
521 51b0b50b jim-p
		 * This is a copy of interfaces_vips_configure with addition of
522 f81e7cc4 Renato Botelho
		 * not reloading existing/not changed carps
523
		 */
524
		if (isset($sections['virtualip']) &&
525
		    is_array($config['virtualip']) &&
526
		    is_array($config['virtualip']['vip'])) {
527
			$carp_setuped = false;
528
			$anyproxyarp = false;
529
530
			foreach ($config['virtualip']['vip'] as $vip) {
531
				$key = "{$vip['interface']}_vip{$vip['vhid']}";
532
533
				if ($vip['mode'] == "carp" &&
534
				    isset($oldvips[$key])) {
535
					if ($oldvips[$key]['content'] ==
536
					    $vip['password'] .
537
					    $vip['advskew'] .
538
					    $vip['subnet'] .
539
					    $vip['subnet_bits'] .
540
					    $vip['advbase'] &&
541
					    does_vip_exist($vip)) {
542
						unset($oldvips[$key]);
543
						/*
544
						 * Skip reconfiguring this vips
545
						 * since nothing has changed.
546
						 */
547
						continue;
548 19ed1624 Ermal
					}
549 5fda51cd jim-p
550 f81e7cc4 Renato Botelho
				} elseif ($vip['mode'] == "ipalias" &&
551 5fda51cd jim-p
				    (substr($vip['interface'], 0, 4) == '_vip'
552
				    || strstr($vip['interface'], "lo0")) &&
553 f81e7cc4 Renato Botelho
				    isset($oldvips[$vip['subnet']])) {
554
					$key = $vip['subnet'];
555
					if ($oldvips[$key]['content'] ==
556
					    $vip['interface'] .
557
					    $vip['subnet'] .
558
					    $vip['subnet_bits'] &&
559
					    does_vip_exist($vip)) {
560
						unset($oldvips[$key]);
561
						/*
562
						 * Skip reconfiguring this vips
563
						 * since nothing has changed.
564
						 */
565
						continue;
566 2708a5cf Ermal
					}
567 f81e7cc4 Renato Botelho
					unset($oldvips[$key]);
568 2708a5cf Ermal
				}
569 51611440 Ermal
570 f81e7cc4 Renato Botelho
				switch ($vip['mode']) {
571 962f215d Phil Davis
				case "proxyarp":
572
					$anyproxyarp = true;
573
					break;
574
				case "ipalias":
575
					interface_ipalias_configure($vip);
576
					break;
577
				case "carp":
578 f81e7cc4 Renato Botelho
					$carp_setuped = true;
579 962f215d Phil Davis
					interface_carp_configure($vip);
580
					break;
581 f81e7cc4 Renato Botelho
				}
582 51611440 Ermal
			}
583 f81e7cc4 Renato Botelho
584
			/* Cleanup remaining old carps */
585
			foreach ($oldvips as $oldvipar) {
586
				$oldvipif = get_real_interface(
587
				    $oldvipar['interface']);
588
589
				if (empty($oldvipif)) {
590
					continue;
591
				}
592
593 962f215d Phil Davis
				if (is_ipaddrv6($oldvipar['subnet'])) {
594 f81e7cc4 Renato Botelho
					 mwexec("/sbin/ifconfig " .
595
					     escapeshellarg($oldvipif) .
596
					     " inet6 " .
597
					     escapeshellarg($oldvipar['subnet']) .
598
					     " delete");
599 962f215d Phil Davis
				} else {
600 f81e7cc4 Renato Botelho
					pfSense_interface_deladdress($oldvipif,
601
					    $oldvipar['subnet']);
602 962f215d Phil Davis
				}
603 e3cffd6c Ermal LUÇI
			}
604 f81e7cc4 Renato Botelho
			if ($carp_setuped == true) {
605
				interfaces_sync_setup();
606
			}
607
			if ($anyproxyarp == true) {
608
				interface_proxyarp_configure();
609
			}
610 51611440 Ermal
		}
611 f81e7cc4 Renato Botelho
612
		if ($old_ipsec_enabled !== ipsec_enabled()) {
613 c6220dcf jim-p
			ipsec_configure();
614 962f215d Phil Davis
		}
615 137f46d8 Ermal
616 f81e7cc4 Renato Botelho
		unset($old_config);
617
618 79f7bc7f Renato Botelho
		local_sync_accounts($u2add, $u2del, $g2add, $g2del);
619 7fead243 Renato Botelho
		$this->filter_configure(false);
620 79f7bc7f Renato Botelho
621 f81e7cc4 Renato Botelho
		return true;
622 962f215d Phil Davis
	}
623 d026178f Renato Botelho
624 f81e7cc4 Renato Botelho
	/**
625
	 * Merge items into installedpackages config section
626
	 *
627
	 * @param array $section
628
	 *
629
	 * @return bool
630
	 */
631 dc5f639f PiBa-NL
	public function merge_installedpackages_section($section) {
632
		$this->auth();
633 d026178f Renato Botelho
634 f81e7cc4 Renato Botelho
		global $config;
635 50d49018 Colin Smith
636 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
637
			log_error("Disallowing CARP sync loop");
638
			return true;
639
		}
640 82ae5cfc Scott Ullrich
641 f81e7cc4 Renato Botelho
		$config['installedpackages'] = array_merge(
642
		    $config['installedpackages'], $section);
643 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_keys($section));
644 f81e7cc4 Renato Botelho
		write_config(sprintf(gettext(
645
		    "Merged in config (%s sections) from XMLRPC client."),
646
		    $mergedkeys));
647 137f46d8 Ermal
648 f81e7cc4 Renato Botelho
		return true;
649 fb0eb20b Ermal
	}
650 c87f4b70 Ermal
651 f81e7cc4 Renato Botelho
	/**
652
	 * Merge items into config
653
	 *
654
	 * @param array $section
655
	 *
656
	 * @return bool
657
	 */
658 dc5f639f PiBa-NL
	public function merge_config_section($section) {
659
		$this->auth();
660 137f46d8 Ermal
661 f81e7cc4 Renato Botelho
		global $config;
662 82ae5cfc Scott Ullrich
663 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
664
			log_error("Disallowing CARP sync loop");
665
			return true;
666
		}
667 dc1cd85d Scott Ullrich
668 f81e7cc4 Renato Botelho
		$config_new = $this->array_overlay($config, $section);
669
		$config = $config_new;
670 8cb29dac doktornotor
		$mergedkeys = implode(", ", array_keys($section));
671 f81e7cc4 Renato Botelho
		write_config(sprintf(gettext(
672
		    "Merged in config (%s sections) from XMLRPC client."),
673
		    $mergedkeys));
674 c87f4b70 Ermal
675 f81e7cc4 Renato Botelho
		return true;
676 fb0eb20b Ermal
	}
677 c87f4b70 Ermal
678 f81e7cc4 Renato Botelho
	/**
679
	 * Wrapper for filter_configure()
680
	 *
681
	 * @return bool
682 57b5da70 jim-p
	 */
683 f9ed5d57 James Webb
	private function filter_configure($reset_accounts = true) {
684 f81e7cc4 Renato Botelho
		global $g, $config;
685
686
		filter_configure();
687
		system_routing_configure();
688
		setup_gateways_monitor();
689
		require_once("openvpn.inc");
690
		openvpn_resync_all();
691
692
		/*
693
		 * The DNS Resolver and the DNS Forwarder may both be active so
694
		 * long as * they are running on different ports.
695
		 * See ticket #5882
696
		 */
697
		if (isset($config['dnsmasq']['enable'])) {
698
			/* Configure dnsmasq but tell it NOT to restart DHCP */
699
			services_dnsmasq_configure(false);
700
		} else {
701
			/* kill any running dnsmasq instance */
702
			if (isvalidpid("{$g['varrun_path']}/dnsmasq.pid")) {
703
				sigkillbypid("{$g['varrun_path']}/dnsmasq.pid",
704
				    "TERM");
705
			}
706 57b5da70 jim-p
		}
707 f81e7cc4 Renato Botelho
		if (isset($config['unbound']['enable'])) {
708
			/* Configure unbound but tell it NOT to restart DHCP */
709
			services_unbound_configure(false);
710
		} else {
711
			/* kill any running Unbound instance */
712
			if (isvalidpid("{$g['varrun_path']}/unbound.pid")) {
713
				sigkillbypid("{$g['varrun_path']}/unbound.pid",
714
				    "TERM");
715
			}
716 57b5da70 jim-p
		}
717 137f46d8 Ermal
718 f81e7cc4 Renato Botelho
		/*
719
		 * Call this separately since the above are manually set to
720
		 * skip the DHCP restart they normally perform.
721
		 * This avoids restarting dhcpd twice as described on
722
		 * ticket #3797
723
		 */
724
		services_dhcpd_configure();
725 137f46d8 Ermal
726 79f7bc7f Renato Botelho
		if ($reset_accounts) {
727
			local_reset_accounts();
728
		}
729 c87f4b70 Ermal
730 7cab6335 Renato Botelho
		captiveportal_configure();
731 c392f1f5 Augustin-FL
		voucher_configure();
732 7cab6335 Renato Botelho
733 f81e7cc4 Renato Botelho
		return true;
734 3dd2a278 Scott Ullrich
	}
735 137f46d8 Ermal
736 24600471 Augustin-FL
	/**
737
	 * Wrapper for captiveportal connected users and
738
	 * active/expired vouchers synchronization
739
	 *
740
	 * @param array $arguments
741
	 *
742
	 * @return array
743
	 */
744
	public function captive_portal_sync($arguments) {
745
		$this->auth();
746
		// Note : no protection against CARP loop is done here, and this is in purpose.
747
		// This function is used for bi-directionnal sync, which is precisely what CARP loop protection is supposed to prevent.
748
		// CARP loop has to be managed within functions using captive_portal_sync()
749
		global $g, $config, $cpzone;
750
751
		if (empty($arguments['op']) || empty($arguments['zone']) || empty($config['captiveportal'][$arguments['zone']])) {
752
			return false;
753
		}
754
		$cpzone = $arguments['zone'];
755
756
		if ($arguments['op'] === 'get_databases') {
757
			$active_vouchers = array();
758
			$expired_vouchers = array();
759
760
			if (is_array($config['voucher'][$cpzone]['roll'])) {
761
				foreach($config['voucher'][$cpzone]['roll'] as $id => $roll) {
762
					$expired_vouchers[$roll['number']] = base64_encode(voucher_read_used_db($roll['number']));
763
					$active_vouchers[$roll['number']] = voucher_read_active_db($roll['number']);
764
				}
765
			}
766
			// base64 is here for safety reasons, as we don't fully control
767
			// the content of these arrays.
768
			$returndata = array('connected_users' => base64_encode(serialize(captiveportal_read_db())),
769
			'active_vouchers' => base64_encode(serialize($active_vouchers)),
770
			'expired_vouchers' => base64_encode(serialize($expired_vouchers)));
771
772
			return $returndata;
773
		} elseif ($arguments['op'] === 'connect_user') {
774
			$user = unserialize(base64_decode($arguments['user']));
775
			$user['attributes']['allow_time'] = $user['allow_time'];
776
777
			// pipeno might be different between primary and secondary
778
			$pipeno = captiveportal_get_next_dn_ruleno('auth');
779
			return portal_allow($user['clientip'], $user['clientmac'], $user['username'], $user['password'], null,
780
			    $user['attributes'], $pipeno, $user['authmethod'], $user['context'], $user['sessionid']);
781 4a778ba9 Augustin-FL
		} elseif ($arguments['op'] === 'disconnect_user') {
782
			$session = unserialize(base64_decode($arguments['session']));
783
			/* read database again, as pipeno might be different between primary & secondary */
784
			$sessionid = SQLite3::escapeString($session['sessionid']);
785
			$local_dbentry = captiveportal_read_db("WHERE sessionid = '{$sessionid}'");
786
787
			if (!empty($local_dbentry) && count($local_dbentry) == 1) {
788
				return captiveportal_disconnect($local_dbentry[0], $session['term_cause'], $session['stop_time'], true);
789
			} else {
790
				return false;
791
			}
792
		} elseif ($arguments['op'] === 'remove_entries') {
793
			$entries = unserialize(base64_decode($arguments['entries']));
794
795
			return captiveportal_remove_entries($entries, true);
796 78784180 Augustin-FL
		} elseif ($arguments['op'] === 'disconnect_all') {
797
			$arguments = unserialize(base64_decode($arguments['arguments']));
798
799
			return captiveportal_disconnect_all($arguments['term_cause'], $arguments['logout_reason'], true);
800 318e3f81 Augustin-FL
		} elseif ($arguments['op'] === 'write_vouchers') {
801
			$arguments = unserialize(base64_decode($arguments['arguments']));
802
803
			if (is_array($arguments['active_and_used_vouchers_bitmasks'])) {
804
				foreach ($arguments['active_and_used_vouchers_bitmasks'] as $roll => $used) {
805
					if (is_array($used)) {
806
						foreach ($used as $u) {
807
							voucher_write_used_db($roll, base64_encode($u));
808
						}
809
					} else {
810
						voucher_write_used_db($roll, base64_encode($used));
811
					}
812
				}
813
			}
814
			foreach ($arguments['active_vouchers'] as $roll => $active_vouchers) {
815
				voucher_write_active_db($roll, $active_vouchers);
816
			}
817
			return true;
818 24600471 Augustin-FL
		}
819
	}
820
821 f81e7cc4 Renato Botelho
	/**
822
	 * Wrapper for configuring CARP interfaces
823
	 *
824
	 * @return bool
825
	 */
826 dc5f639f PiBa-NL
	public function interfaces_carp_configure() {
827
		$this->auth();
828 efe7562e Scott Ullrich
829 f81e7cc4 Renato Botelho
		if ($this->loop_detected) {
830
			log_error("Disallowing CARP sync loop");
831
			return true;
832
		}
833 0567899d Ermal
834 f81e7cc4 Renato Botelho
		interfaces_vips_configure();
835 e501de37 Ermal
836 f81e7cc4 Renato Botelho
		return true;
837
	}
838 e501de37 Ermal
839 f81e7cc4 Renato Botelho
	/**
840
	 * Wrapper for rc.reboot
841
	 *
842
	 * @return bool
843
	 */
844 dc5f639f PiBa-NL
	public function reboot() {
845
		$this->auth();
846 e501de37 Ermal
847 f81e7cc4 Renato Botelho
		mwexec_bg("/etc/rc.reboot");
848 137f46d8 Ermal
849 f81e7cc4 Renato Botelho
		return true;
850 3dd2a278 Scott Ullrich
	}
851 d9064267 Colin Smith
}
852
853 f3f98e97 Phil Davis
// run script until its done and can 'unlock' the xmlrpc.lock, this prevents hanging php-fpm / webgui
854 179377b0 robjarsen
ignore_user_abort(true);
855 8239af2d PiBa-NL
set_time_limit(0);
856
857 67d78c87 Ermal
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
858
859 f81e7cc4 Renato Botelho
XML_RPC2_Backend::setBackend('php');
860
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
861
862
$options = array(
863
	'prefix' => 'pfsense.',
864
	'encoding' => 'utf-8',
865 4f78ae1d Renato Botelho
	'autoDocument' => false,
866 50d49018 Colin Smith
);
867 b298dd06 Scott Ullrich
868 f81e7cc4 Renato Botelho
$server = XML_RPC2_Server::create(new pfsense_xmlrpc_server(), $options);
869
$server->handleCall();
870 67d78c87 Ermal
871 f81e7cc4 Renato Botelho
unlock($xmlrpclockkey);
872 0b581a8a Scott Ullrich
873 de63649b Rafael Lucas
?>