Project

General

Profile

Download (18.8 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;
49
		$username = $_SERVER['PHP_AUTH_USER'];
50
		$password = $_SERVER['PHP_AUTH_PW'];
51

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

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

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

    
70
			require_once("XML/RPC2/Exception.php");
71
			throw new XML_RPC2_FaultException(gettext(
72
			    'Authentication failed: Invalid username or password'),
73
			    -1);
74
		}
75

    
76
		$user_entry = getUserEntry($username);
77
		/*
78
		 * admin (uid = 0) is allowed
79
		 * or regular user with necessary privilege
80
		 */
81
		if (isset($user_entry['uid']) && $user_entry['uid'] != '0' &&
82
		    !userHasPrivilege($user_entry, 'system-xmlrpc-ha-sync')) {
83
			log_auth("webConfigurator authentication error for '" .
84
			    $username . "' from " . $this->remote_addr .
85
			    " not enough privileges");
86

    
87
			require_once("XML/RPC2/Exception.php");
88
			throw new XML_RPC2_FaultException(gettext(
89
			    'Authentication failed: not enough privileges'),
90
			    -2);
91
		}
92

    
93
		return;
94
	}
95

    
96
	private function array_overlay($a1, $a2) {
97
		foreach ($a1 as $k => $v) {
98
			if (!array_key_exists($k, $a2)) {
99
				continue;
100
			}
101
			if (is_array($v) && is_array($a2[$k])) {
102
				$a1[$k] = $this->array_overlay($v, $a2[$k]);
103
			} else {
104
				$a1[$k] = $a2[$k];
105
			}
106
		}
107

    
108
		return $a1;
109
	}
110

    
111
	public function __construct() {
112
		global $config;
113

    
114
		$this->remote_addr = $_SERVER['REMOTE_ADDR'];
115

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

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

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

    
143
		eval($code);
144
		if ($toreturn) {
145
			return $toreturn;
146
		}
147

    
148
		return true;
149
	}
150

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

    
161
		mwexec($code);
162
		return true;
163
	}
164

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

    
175
		global $config;
176

    
177
		return array_intersect_key($config, array_flip($section));
178
	}
179

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

    
190
		global $config, $cpzone, $cpzoneid;
191

    
192
		$old_config = $config;
193
		$old_ipsec_enabled = ipsec_enabled();
194

    
195
		if ($this->loop_detected) {
196
			log_error("Disallowing CARP sync loop");
197
			return true;
198
		}
199

    
200
		/*
201
		 * Some sections should just be copied and not merged or we end
202
		 * up unable to sync the deletion of the last item in a section
203
		 */
204
		$sync_full_sections = array(
205
			'aliases',
206
			'ca',
207
			'cert',
208
			'crl',
209
			'dhcpd',
210
			'dhcpv6',
211
			'dnshaper',
212
			'dnsmasq',
213
			'filter',
214
			'ipsec',
215
			'nat',
216
			'openvpn',
217
			'schedules',
218
			'shaper',
219
			'unbound',
220
			'wol',
221
		);
222

    
223
		$syncd_full_sections = array();
224

    
225
		foreach ($sync_full_sections as $section) {
226
			if (!isset($sections[$section])) {
227
				continue;
228
			}
229

    
230
			$config[$section] = $sections[$section];
231
			unset($sections[$section]);
232
			$syncd_full_sections[] = $section;
233
		}
234

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

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

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

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

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

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

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

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

    
335
			foreach($sections['voucher'] as $zone => $item) {
336
				unset($sections['voucher'][$zone]['roll']);
337
				if (isset($config['voucher'][$zone]['vouchersyncdbip'])) {
338
					$sections['voucher'][$zone]['vouchersyncdbip'] =
339
					    $config['voucher'][$zone]['vouchersyncdbip'];
340
				} else {
341
					unset($sections['voucher'][$zone]['vouchersyncdbip']);
342
				}
343
				if (isset($config['voucher'][$zone]['vouchersyncport'])) {
344
					$sections['voucher'][$zone]['vouchersyncport'] =
345
					    $config['voucher'][$zone]['vouchersyncport'];
346
				} else {
347
					unset($sections['voucher'][$zone]['vouchersyncport']);
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
			}
362
		}
363

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
575
				if (empty($oldvipif)) {
576
					continue;
577
				}
578

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

    
598
		if ($old_ipsec_enabled !== ipsec_enabled()) {
599
			ipsec_configure();
600
		}
601

    
602
		unset($old_config);
603

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

    
607
		return true;
608
	}
609

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

    
620
		global $config;
621

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

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

    
634
		return true;
635
	}
636

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

    
647
		global $config;
648

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

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

    
661
		return true;
662
	}
663

    
664
	/**
665
	 * Wrapper for filter_configure()
666
	 *
667
	 * @return bool
668
	 */
669
	public function filter_configure($reset_accounts = true) {
670
		$this->auth();
671

    
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)