Project

General

Profile

Download (18.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * xmlrpc.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2005 Colin Smith
10
 * All rights reserved.
11
 *
12
 * 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
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * 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
 */
24

    
25
##|+PRIV
26
##|*IDENT=page-xmlrpclibrary
27
##|*NAME=XMLRPC Library
28
##|*DESCR=Allow access to the 'XMLRPC Library' page.
29
##|*MATCH=xmlrpc.php*
30
##|-PRIV
31

    
32
require_once("config.inc");
33
require_once("functions.inc");
34
require_once("auth.inc");
35
require_once("filter.inc");
36
require_once("ipsec.inc");
37
require_once("vpn.inc");
38
require_once("captiveportal.inc");
39
require_once("shaper.inc");
40
require_once("XML/RPC2/Server.php");
41

    
42
class pfsense_xmlrpc_server {
43

    
44
	private $loop_detected = false;
45
	private $remote_addr;
46

    
47
	private function auth() {
48
		global $config, $userindex;
49
		$userindex = index_users();
50

    
51
		$username = $_SERVER['PHP_AUTH_USER'];
52
		$password = $_SERVER['PHP_AUTH_PW'];
53

    
54
		$login_ok = false;
55
		if (!empty($username) && !empty($password)) {
56
			$attributes = array();
57
			$authcfg = auth_get_authserver(
58
			    $config['system']['webgui']['authmode']);
59

    
60
			if (authenticate_user($username, $password,
61
			    $authcfg, $attributes) ||
62
			    authenticate_user($username, $password)) {
63
				$login_ok = true;
64
			}
65
		}
66

    
67
		if (!$login_ok) {
68
			log_auth(sprintf(gettext("webConfigurator authentication error for user '%1\$s' from: %2\$s"),
69
			    $username,
70
			    $this->remote_addr));
71

    
72
			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
	}
97

    
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
	}
112

    
113
	public function __construct() {
114
		global $config;
115

    
116
		$this->remote_addr = $_SERVER['REMOTE_ADDR'];
117

    
118
		/* grab sync to ip if enabled */
119
		if (isset($config['hasync']['synchronizetoip']) &&
120
		    $config['hasync']['synchronizetoip'] == $this->remote_addr) {
121
			$this->loop_detected = true;
122
		}
123
	}
124

    
125
	/**
126
	 * Get host version information
127
	 *
128
	 * @return array
129
	 */
130
	public function host_firmware_version($dummy = 1) {
131
		$this->auth();
132
		return host_firmware_version();
133
	}
134

    
135
	/**
136
	 * Executes a PHP block of code
137
	 *
138
	 * @param string $code
139
	 *
140
	 * @return bool
141
	 */
142
	public function exec_php($code) {
143
		$this->auth();
144

    
145
		eval($code);
146
		if ($toreturn) {
147
			return $toreturn;
148
		}
149

    
150
		return true;
151
	}
152

    
153
	/**
154
	 * Executes shell commands
155
	 *
156
	 * @param string $code
157
	 *
158
	 * @return bool
159
	 */
160
	public function exec_shell($code) {
161
		$this->auth();
162

    
163
		mwexec($code);
164
		return true;
165
	}
166

    
167
	/**
168
	 * Backup chosen config sections
169
	 *
170
	 * @param array $section
171
	 *
172
	 * @return array
173
	 */
174
	public function backup_config_section($section) {
175
		$this->auth();
176

    
177
		global $config;
178

    
179
		return array_intersect_key($config, array_flip($section));
180
	}
181

    
182
	/**
183
	 * Restore defined config section into local config
184
	 *
185
	 * @param array $sections
186
	 *
187
	 * @return bool
188
	 */
189
	public function restore_config_section($sections) {
190
		$this->auth();
191

    
192
		global $config, $cpzone, $cpzoneid;
193

    
194
		$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
			'dnshaper',
214
			'dnsmasq',
215
			'filter',
216
			'ipsec',
217
			'nat',
218
			'openvpn',
219
			'schedules',
220
			'shaper',
221
			'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
		}
236

    
237
		/* Create a list of CP zones to be deleted locally */
238
		$cp_to_del = array();
239
		if (is_array($config['captiveportal'])) {
240
			if (is_array($sections['captiveportal'])) {
241
				$remote_cp = $sections['captiveportal'];
242
			} else {
243
				$remote_cp = array();
244
			}
245
			foreach ($config['captiveportal'] as $zone => $item) {
246
				if (!isset($remote_cp[$zone])) {
247
					$cp_to_del[] = $zone;
248
				}
249
			}
250
			unset($remote_cp);
251
		}
252

    
253
		/* Only touch users if users are set to synchronize from the primary node
254
		 * See https://redmine.pfsense.org/issues/8450
255
		 */
256
		if ($sections['system']['user'] && $sections['system']['group']) {
257
			$g2add = array();
258
			$g2del = array();
259
			$g2del_idx = array();
260
			$g2keep = array();
261
			if (is_array($sections['system']['group'])) {
262
				$local_groups = isset($config['system']['group'])
263
				    ? $config['system']['group']
264
				    : array();
265

    
266
				foreach ($sections['system']['group'] as $group) {
267
					$idx = array_search($group['name'],
268
					    array_column($local_groups, 'name'));
269

    
270
					if ($idx === false) {
271
						$g2add[] = $group;
272
					} else if ($group['gid'] < 1999) {
273
						$g2keep[] = $idx;
274
					} else if ($group != $local_groups[$idx]) {
275
						$g2add[] = $group;
276
						$g2del[] = $group;
277
						$g2del_idx[] = $idx;
278
					} else {
279
						$g2keep[] = $idx;
280
					}
281
				}
282
			}
283
			if (is_array($config['system']['group'])) {
284
				foreach ($config['system']['group'] as $idx => $group) {
285
					if (array_search($idx, $g2keep) === false &&
286
					    array_search($idx, $g2del_idx) === false) {
287
						$g2del[] = $group;
288
						$g2del_idx[] = $idx;
289
					}
290
				}
291
			}
292
			unset($sections['system']['group'], $g2keep, $g2del_idx);
293

    
294
			$u2add = array();
295
			$u2del = array();
296
			$u2del_idx = array();
297
			$u2keep = array();
298
			if (is_array($sections['system']['user'])) {
299
				$local_users = isset($config['system']['user'])
300
				    ? $config['system']['user']
301
				    : array();
302

    
303
				foreach ($sections['system']['user'] as $user) {
304
					$idx = array_search($user['name'],
305
					    array_column($local_users, 'name'));
306

    
307
					if ($idx === false) {
308
						$u2add[] = $user;
309
					} else if (($user['uid'] < 2000) && ($sections['hasync']['adminsync'] != 'on')) {
310
						$u2keep[] = $idx;
311
					} else if ($user != $local_users[$idx]) {
312
						$u2add[] = $user;
313
						$u2del[] = $user;
314
						$u2del_idx[] = $idx;
315
					} else {
316
						$u2keep[] = $idx;
317
					}
318
				}
319
			}
320
			if (is_array($config['system']['user'])) {
321
				foreach ($config['system']['user'] as $idx => $user) {
322
					if (array_search($idx, $u2keep) === false &&
323
					    array_search($idx, $u2del_idx) === false) {
324
						$u2del[] = $user;
325
						$u2del_idx[] = $idx;
326
					}
327
				}
328
			}
329
			unset($sections['system']['user'], $u2keep, $u2del_idx);
330
		}
331

    
332
		$voucher = array();
333
		if (is_array($sections['voucher'])) {
334
			/* Save voucher rolls to process after merge */
335
			$voucher = $sections['voucher'];
336

    
337
			foreach($sections['voucher'] as $zone => $item) {
338
				unset($sections['voucher'][$zone]['roll']);
339
				if (isset($config['voucher'][$zone]['vouchersyncdbip'])) {
340
					$sections['voucher'][$zone]['vouchersyncdbip'] =
341
					    $config['voucher'][$zone]['vouchersyncdbip'];
342
				} else {
343
					unset($sections['voucher'][$zone]['vouchersyncdbip']);
344
				}
345
				if (isset($config['voucher'][$zone]['vouchersyncport'])) {
346
					$sections['voucher'][$zone]['vouchersyncport'] =
347
					    $config['voucher'][$zone]['vouchersyncport'];
348
				} else {
349
					unset($sections['voucher'][$zone]['vouchersyncport']);
350
				}
351
				if (isset($config['voucher'][$zone]['vouchersyncusername'])) {
352
					$sections['voucher'][$zone]['vouchersyncusername'] =
353
					    $config['voucher'][$zone]['vouchersyncusername'];
354
				} else {
355
					unset($sections['voucher'][$zone]['vouchersyncusername']);
356
				}
357
				if (isset($config['voucher'][$zone]['vouchersyncpass'])) {
358
					$sections['voucher'][$zone]['vouchersyncpass'] =
359
					    $config['voucher'][$zone]['vouchersyncpass'];
360
				} else {
361
					unset($sections['voucher'][$zone]['vouchersyncpass']);
362
				}
363
			}
364
		}
365

    
366
		$vipbackup = array();
367
		$oldvips = array();
368
		if (isset($sections['virtualip']) &&
369
		    is_array($config['virtualip']['vip'])) {
370
			foreach ($config['virtualip']['vip'] as $vip) {
371
				if ($vip['mode'] == "carp") {
372
					$key = $vip['interface'] .
373
					    "_vip" . $vip['vhid'];
374

    
375
					$oldvips[$key]['content'] =
376
					    $vip['password'] .
377
					    $vip['advskew'] .
378
					    $vip['subnet'] .
379
					    $vip['subnet_bits'] .
380
					    $vip['advbase'];
381
					$oldvips[$key]['interface'] =
382
					    $vip['interface'];
383
					$oldvips[$key]['subnet'] =
384
					    $vip['subnet'];
385
				} else if ($vip['mode'] == "ipalias" &&
386
				    (substr($vip['interface'], 0, 4) == '_vip'
387
				    || strstr($vip['interface'], "lo0"))) {
388
					$oldvips[$vip['subnet']]['content'] =
389
					    $vip['interface'] .
390
					    $vip['subnet'] .
391
					    $vip['subnet_bits'];
392
					$oldvips[$vip['subnet']]['interface'] =
393
					    $vip['interface'];
394
					$oldvips[$vip['subnet']]['subnet'] =
395
					    $vip['subnet'];
396
				} else if (($vip['mode'] == "ipalias" ||
397
				    $vip['mode'] == 'proxyarp') &&
398
				    !(substr($vip['interface'], 0, 4) == '_vip')
399
				    || strstr($vip['interface'], "lo0")) {
400
					$vipbackup[] = $vip;
401
				}
402
			}
403
		}
404

    
405
		/* For vip section, first keep items sent from the master */
406
		$config = array_merge_recursive_unique($config, $sections);
407

    
408
		/* Remove local CP zones removed remote */
409
		foreach ($cp_to_del as $zone) {
410
			$cpzone = $zone;
411
			$cpzoneid = $config['captiveportal'][$cpzone]['zoneid'];
412
			unset($config['captiveportal'][$cpzone]['enable']);
413
			captiveportal_configure_zone(
414
			    $config['captiveportal'][$cpzone]);
415
			unset($config['captiveportal'][$cpzone]);
416
			if (isset($config['voucher'][$cpzone])) {
417
				unset($config['voucher'][$cpzone]);
418
			}
419
		}
420

    
421
		/* Remove locally items removed remote */
422
		foreach ($voucher as $zone => $item) {
423
			/* No rolls on master, delete local ones */
424
			if (!is_array($item['roll'])) {
425
				unset($config['voucher'][$zone]['roll']);
426
			}
427
		}
428

    
429
		$l_rolls = array();
430
		if (is_array($config['voucher'])) {
431
			foreach ($config['voucher'] as $zone => $item) {
432
				if (!is_array($item['roll'])) {
433
					continue;
434
				}
435
				foreach ($item['roll'] as $idx => $roll) {
436
					/* Make it easy to find roll by # */
437
					$l_rolls[$zone][$roll['number']] = $idx;
438
				}
439
			}
440
		}
441

    
442
		/*
443
		 * Process vouchers sent by primary node and:
444
		 * - Add new items
445
		 * - Update existing items based on 'lastsync' field
446
		 */
447
		foreach ($voucher as $zone => $item) {
448
			if (!is_array($item['roll'])) {
449
				continue;
450
			}
451
			foreach ($item['roll'] as $idx => $roll) {
452
				if (!isset($l_rolls[$zone][$roll['number']])) {
453
					$config['voucher'][$zone]['roll'][] =
454
					    $roll;
455
					continue;
456
				}
457
				$l_roll_idx = $l_rolls[$zone][$roll['number']];
458
				init_config_arr(array('voucher', $zone));
459
				$l_vouchers = &$config['voucher'][$zone];
460
				$l_roll = $l_vouchers['roll'][$l_roll_idx];
461
				if (!isset($l_roll['lastsync'])) {
462
					$l_roll['lastsync'] = 0;
463
				}
464

    
465
				if (isset($roll['lastsync']) &&
466
				    $roll['lastsync'] != $l_roll['lastsync']) {
467
					$l_vouchers['roll'][$l_roll_idx] =
468
					    $roll;
469
					unset($l_rolls[$zone][$roll['number']]);
470
				}
471
			}
472
		}
473

    
474
		/*
475
		 * At this point $l_rolls contains only items that are not
476
		 * present on primary node. They must be removed
477
		 */
478
		foreach ($l_rolls as $zone => $item) {
479
			foreach ($item as $number => $idx) {
480
				unset($config['voucher'][$zone][$idx]);
481
			}
482
		}
483

    
484
		/*
485
		 * Then add ipalias and proxyarp types already defined
486
		 * on the backup
487
		 */
488
		if (is_array($vipbackup) && !empty($vipbackup)) {
489
			if (!is_array($config['virtualip'])) {
490
				$config['virtualip'] = array();
491
			}
492
			if (!is_array($config['virtualip']['vip'])) {
493
				$config['virtualip']['vip'] = array();
494
			}
495
			foreach ($vipbackup as $vip) {
496
				array_unshift($config['virtualip']['vip'], $vip);
497
			}
498
		}
499

    
500
		/* Log what happened */
501
		$mergedkeys = implode(", ", array_merge(array_keys($sections),
502
		    $syncd_full_sections));
503
		write_config(sprintf(gettext(
504
		    "Merged in config (%s sections) from XMLRPC client."),
505
		    $mergedkeys));
506

    
507
		/*
508
		 * The real work on handling the vips specially
509
		 * This is a copy of intefaces_vips_configure with addition of
510
		 * not reloading existing/not changed carps
511
		 */
512
		if (isset($sections['virtualip']) &&
513
		    is_array($config['virtualip']) &&
514
		    is_array($config['virtualip']['vip'])) {
515
			$carp_setuped = false;
516
			$anyproxyarp = false;
517

    
518
			foreach ($config['virtualip']['vip'] as $vip) {
519
				$key = "{$vip['interface']}_vip{$vip['vhid']}";
520

    
521
				if ($vip['mode'] == "carp" &&
522
				    isset($oldvips[$key])) {
523
					if ($oldvips[$key]['content'] ==
524
					    $vip['password'] .
525
					    $vip['advskew'] .
526
					    $vip['subnet'] .
527
					    $vip['subnet_bits'] .
528
					    $vip['advbase'] &&
529
					    does_vip_exist($vip)) {
530
						unset($oldvips[$key]);
531
						/*
532
						 * Skip reconfiguring this vips
533
						 * since nothing has changed.
534
						 */
535
						continue;
536
					}
537

    
538
				} elseif ($vip['mode'] == "ipalias" &&
539
				    (substr($vip['interface'], 0, 4) == '_vip'
540
				    || strstr($vip['interface'], "lo0")) &&
541
				    isset($oldvips[$vip['subnet']])) {
542
					$key = $vip['subnet'];
543
					if ($oldvips[$key]['content'] ==
544
					    $vip['interface'] .
545
					    $vip['subnet'] .
546
					    $vip['subnet_bits'] &&
547
					    does_vip_exist($vip)) {
548
						unset($oldvips[$key]);
549
						/*
550
						 * Skip reconfiguring this vips
551
						 * since nothing has changed.
552
						 */
553
						continue;
554
					}
555
					unset($oldvips[$key]);
556
				}
557

    
558
				switch ($vip['mode']) {
559
				case "proxyarp":
560
					$anyproxyarp = true;
561
					break;
562
				case "ipalias":
563
					interface_ipalias_configure($vip);
564
					break;
565
				case "carp":
566
					$carp_setuped = true;
567
					interface_carp_configure($vip);
568
					break;
569
				}
570
			}
571

    
572
			/* Cleanup remaining old carps */
573
			foreach ($oldvips as $oldvipar) {
574
				$oldvipif = get_real_interface(
575
				    $oldvipar['interface']);
576

    
577
				if (empty($oldvipif)) {
578
					continue;
579
				}
580

    
581
				if (is_ipaddrv6($oldvipar['subnet'])) {
582
					 mwexec("/sbin/ifconfig " .
583
					     escapeshellarg($oldvipif) .
584
					     " inet6 " .
585
					     escapeshellarg($oldvipar['subnet']) .
586
					     " delete");
587
				} else {
588
					pfSense_interface_deladdress($oldvipif,
589
					    $oldvipar['subnet']);
590
				}
591
			}
592
			if ($carp_setuped == true) {
593
				interfaces_sync_setup();
594
			}
595
			if ($anyproxyarp == true) {
596
				interface_proxyarp_configure();
597
			}
598
		}
599

    
600
		if ($old_ipsec_enabled !== ipsec_enabled()) {
601
			ipsec_configure();
602
		}
603

    
604
		unset($old_config);
605

    
606
		local_sync_accounts($u2add, $u2del, $g2add, $g2del);
607
		$this->filter_configure(false);
608

    
609
		return true;
610
	}
611

    
612
	/**
613
	 * Merge items into installedpackages config section
614
	 *
615
	 * @param array $section
616
	 *
617
	 * @return bool
618
	 */
619
	public function merge_installedpackages_section($section) {
620
		$this->auth();
621

    
622
		global $config;
623

    
624
		if ($this->loop_detected) {
625
			log_error("Disallowing CARP sync loop");
626
			return true;
627
		}
628

    
629
		$config['installedpackages'] = array_merge(
630
		    $config['installedpackages'], $section);
631
		$mergedkeys = implode(", ", array_keys($section));
632
		write_config(sprintf(gettext(
633
		    "Merged in config (%s sections) from XMLRPC client."),
634
		    $mergedkeys));
635

    
636
		return true;
637
	}
638

    
639
	/**
640
	 * Merge items into config
641
	 *
642
	 * @param array $section
643
	 *
644
	 * @return bool
645
	 */
646
	public function merge_config_section($section) {
647
		$this->auth();
648

    
649
		global $config;
650

    
651
		if ($this->loop_detected) {
652
			log_error("Disallowing CARP sync loop");
653
			return true;
654
		}
655

    
656
		$config_new = $this->array_overlay($config, $section);
657
		$config = $config_new;
658
		$mergedkeys = implode(", ", array_keys($section));
659
		write_config(sprintf(gettext(
660
		    "Merged in config (%s sections) from XMLRPC client."),
661
		    $mergedkeys));
662

    
663
		return true;
664
	}
665

    
666
	/**
667
	 * Wrapper for filter_configure()
668
	 *
669
	 * @return bool
670
	 */
671
	private function filter_configure($reset_accounts = true) {
672
		global $g, $config;
673

    
674
		filter_configure();
675
		system_routing_configure();
676
		setup_gateways_monitor();
677
		require_once("openvpn.inc");
678
		openvpn_resync_all();
679

    
680
		/*
681
		 * The DNS Resolver and the DNS Forwarder may both be active so
682
		 * long as * they are running on different ports.
683
		 * See ticket #5882
684
		 */
685
		if (isset($config['dnsmasq']['enable'])) {
686
			/* Configure dnsmasq but tell it NOT to restart DHCP */
687
			services_dnsmasq_configure(false);
688
		} else {
689
			/* kill any running dnsmasq instance */
690
			if (isvalidpid("{$g['varrun_path']}/dnsmasq.pid")) {
691
				sigkillbypid("{$g['varrun_path']}/dnsmasq.pid",
692
				    "TERM");
693
			}
694
		}
695
		if (isset($config['unbound']['enable'])) {
696
			/* Configure unbound but tell it NOT to restart DHCP */
697
			services_unbound_configure(false);
698
		} else {
699
			/* kill any running Unbound instance */
700
			if (isvalidpid("{$g['varrun_path']}/unbound.pid")) {
701
				sigkillbypid("{$g['varrun_path']}/unbound.pid",
702
				    "TERM");
703
			}
704
		}
705

    
706
		/*
707
		 * Call this separately since the above are manually set to
708
		 * skip the DHCP restart they normally perform.
709
		 * This avoids restarting dhcpd twice as described on
710
		 * ticket #3797
711
		 */
712
		services_dhcpd_configure();
713

    
714
		if ($reset_accounts) {
715
			local_reset_accounts();
716
		}
717

    
718
		captiveportal_configure();
719

    
720
		return true;
721
	}
722

    
723
	/**
724
	 * Wrapper for configuring CARP interfaces
725
	 *
726
	 * @return bool
727
	 */
728
	public function interfaces_carp_configure() {
729
		$this->auth();
730

    
731
		if ($this->loop_detected) {
732
			log_error("Disallowing CARP sync loop");
733
			return true;
734
		}
735

    
736
		interfaces_vips_configure();
737

    
738
		return true;
739
	}
740

    
741
	/**
742
	 * Wrapper for rc.reboot
743
	 *
744
	 * @return bool
745
	 */
746
	public function reboot() {
747
		$this->auth();
748

    
749
		mwexec_bg("/etc/rc.reboot");
750

    
751
		return true;
752
	}
753
}
754

    
755
// run script until its done and can 'unlock' the xmlrpc.lock, this prevents hanging php-fpm / webgui
756
ignore_user_abort(true);
757
set_time_limit(0);
758

    
759
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
760

    
761
XML_RPC2_Backend::setBackend('php');
762
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
763

    
764
$options = array(
765
	'prefix' => 'pfsense.',
766
	'encoding' => 'utf-8',
767
	'autoDocument' => false,
768
);
769

    
770
$server = XML_RPC2_Server::create(new pfsense_xmlrpc_server(), $options);
771
$server->handleCall();
772

    
773
unlock($xmlrpclockkey);
774

    
775
?>
(227-227/227)