Project

General

Profile

Download (17.9 KB) Statistics
| Branch: | Tag: | Revision:

univnautes / usr / local / www / xmlrpc.php @ a1b66bec

1
<?php
2
/*
3
	$Id$
4

    
5
        xmlrpc.php
6
        Copyright (C) 2009, 2010 Scott Ullrich
7
        Copyright (C) 2005 Colin Smith
8
        All rights reserved.
9

    
10
        Redistribution and use in source and binary forms, with or without
11
        modification, are permitted provided that the following conditions are met:
12

    
13
        1. Redistributions of source code must retain the above copyright notice,
14
           this list of conditions and the following disclaimer.
15

    
16
        2. Redistributions in binary form must reproduce the above copyright
17
           notice, this list of conditions and the following disclaimer in the
18
           documentation and/or other materials provided with the distribution.
19

    
20
        THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
        INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
        AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
        AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
        OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
        SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
        INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
        CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
        ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
        POSSIBILITY OF SUCH DAMAGE.
30
*/
31

    
32
##|+PRIV
33
##|*IDENT=page-xmlrpclibrary
34
##|*NAME=XMLRPC Library page
35
##|*DESCR=Allow access to the 'XMLRPC Library' page.
36
##|*MATCH=xmlrpc.php*
37
##|-PRIV
38

    
39
require("config.inc");
40
require("functions.inc");
41
require_once("filter.inc");
42
require("ipsec.inc");
43
require("vpn.inc");
44
require("shaper.inc");
45
require("xmlrpc_server.inc");
46
require("xmlrpc.inc");
47
require("array_intersect_key.inc");
48

    
49
function xmlrpc_loop_detect() {
50
	global $config;
51

    
52
	/* grab sync to ip if enabled */
53
	if ($config['hasync'])
54
		$synchronizetoip = $config['hasync']['synchronizetoip'];
55
	if($synchronizetoip) {
56
		if($synchronizetoip == $_SERVER['REMOTE_ADDR'])
57
			return true;	
58
	}
59

    
60
	return false;
61
}
62

    
63
$xmlrpc_g = array(
64
	"return" => array(
65
		"true" => new XML_RPC_Response(new XML_RPC_Value(true, $XML_RPC_Boolean)),
66
		"false" => new XML_RPC_Response(new XML_RPC_Value(false, $XML_RPC_Boolean)),
67
		"authfail" => new XML_RPC_Response(new XML_RPC_Value(gettext("Authentication failed"), $XML_RPC_String))
68
	)
69
);
70

    
71
/*
72
 *   pfSense XMLRPC errors
73
 *   $XML_RPC_erruser + 1 = Auth failure
74
 */
75
$XML_RPC_erruser = 200;
76

    
77
/* EXPOSED FUNCTIONS */
78
$exec_php_doc = gettext("XMLRPC wrapper for eval(). This method must be called with two parameters: a string containing the local system\'s password followed by the PHP code to evaluate.");
79
$exec_php_sig = array(
80
	array(
81
		$XML_RPC_Boolean, // First signature element is return value.
82
		$XML_RPC_String, // password
83
		$XML_RPC_String, // shell code to exec
84
	)
85
);
86

    
87
function xmlrpc_authfail() {
88
	log_auth("webConfigurator authentication error for 'admin' from {$_SERVER['REMOTE_ADDR']}");
89
}
90

    
91
function exec_php_xmlrpc($raw_params) {
92
	global $config, $xmlrpc_g;
93

    
94
	$params = xmlrpc_params_to_php($raw_params);
95
	if(!xmlrpc_auth($params)) {
96
		xmlrpc_authfail();
97
		return $xmlrpc_g['return']['authfail'];
98
	}
99
	$exec_php = $params[0];
100
	eval($exec_php);
101
	if($toreturn) {
102
		$response = XML_RPC_encode($toreturn);
103
		return new XML_RPC_Response($response);
104
	} else
105
		return $xmlrpc_g['return']['true'];
106
}
107

    
108
/*****************************/
109
$exec_shell_doc = gettext("XMLRPC wrapper for mwexec(). This method must be called with two parameters: a string containing the local system\'s password followed by an shell command to execute.");
110
$exec_shell_sig = array(
111
	array(
112
		$XML_RPC_Boolean, // First signature element is return value.
113
		$XML_RPC_String, // password
114
		$XML_RPC_String, // shell code to exec
115
	)
116
);
117

    
118
function exec_shell_xmlrpc($raw_params) {
119
	global $config, $xmlrpc_g;
120

    
121
	$params = xmlrpc_params_to_php($raw_params);
122
	if(!xmlrpc_auth($params)) {
123
		xmlrpc_authfail();
124
		return $xmlrpc_g['return']['authfail'];
125
	}
126
	$shell_cmd = $params[0];
127
	mwexec($shell_cmd);
128

    
129
	return $xmlrpc_g['return']['true'];
130
}
131

    
132
/*****************************/
133
$backup_config_section_doc = gettext("XMLRPC wrapper for backup_config_section. This method must be called with two parameters: a string containing the local system\'s password followed by an array containing the keys to be backed up.");
134
$backup_config_section_sig = array(
135
	array(
136
		$XML_RPC_Struct, // First signature element is return value.
137
		$XML_RPC_String,
138
		$XML_RPC_Array
139
	)
140
);
141

    
142
function backup_config_section_xmlrpc($raw_params) {
143
	global $config, $xmlrpc_g;
144

    
145
	if (xmlrpc_loop_detect()) {
146
		log_error("Disallowing CARP sync loop");
147
		return;
148
	}
149

    
150
	$params = xmlrpc_params_to_php($raw_params);
151
	if(!xmlrpc_auth($params)) {
152
		xmlrpc_authfail();
153
		return $xmlrpc_g['return']['authfail'];
154
	}
155
	$val = array_intersect_key($config, array_flip($params[0]));
156

    
157
	return new XML_RPC_Response(XML_RPC_encode($val));
158
}
159

    
160
/*****************************/
161
$restore_config_section_doc = gettext("XMLRPC wrapper for restore_config_section. This method must be called with two parameters: a string containing the local system\'s password and an array to merge into the system\'s config. This function returns true upon completion.");
162
$restore_config_section_sig = array(
163
	array(
164
		$XML_RPC_Boolean,
165
		$XML_RPC_String,
166
		$XML_RPC_Struct
167
	)
168
);
169

    
170
function restore_config_section_xmlrpc($raw_params) {
171
	global $config, $xmlrpc_g;
172

    
173
	$old_config = $config;
174

    
175
	if (xmlrpc_loop_detect()) {
176
		log_error("Disallowing CARP sync loop");
177
		return;
178
	}
179

    
180
	$params = xmlrpc_params_to_php($raw_params);
181
	if(!xmlrpc_auth($params)) {
182
		xmlrpc_authfail();
183
		return $xmlrpc_g['return']['authfail'];
184
	}
185

    
186
	// Some sections should just be copied and not merged or we end
187
	//   up unable to sync the deletion of the last item in a section
188
	$sync_full = array('ipsec', 'aliases', 'wol', 'load_balancer', 'openvpn', 'cert', 'ca', 'crl', 'schedules', 'filter', 'nat', 'dhcpd', 'dhcpv6');
189
	$sync_full_done = array();
190
	foreach ($sync_full as $syncfull) {
191
		if (isset($params[0][$syncfull])) {
192
			$config[$syncfull] = $params[0][$syncfull];
193
			unset($params[0][$syncfull]);
194
			$sync_full_done[] = $syncfull;
195
		}
196
	}
197

    
198
	$vipbackup = array();
199
	$oldvips = array();
200
	if (isset($params[0]['virtualip'])) {
201
		if (is_array($config['virtualip']['vip'])) {
202
			foreach ($config['virtualip']['vip'] as $vipindex => $vip) {
203
				if ($vip['mode'] == "carp")
204
					$oldvips["{$vip['interface']}_vip{$vip['vhid']}"] = "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}";
205
				else if ($vip['mode'] == "ipalias" && (strstr($vip['interface'], "_vip") || strstr($vip['interface'], "lo0")))
206
					$oldvips[$vip['subnet']] = "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}";
207
				else if (($vip['mode'] == "ipalias" || $vip['mode'] == 'proxyarp') && !(strstr($vip['interface'], "_vip") || strstr($vip['interface'], "lo0")))
208
					$vipbackup[] = $vip;
209
			}
210
		}
211
	}
212

    
213
        // For vip section, first keep items sent from the master
214
	$config = array_merge_recursive_unique($config, $params[0]);
215

    
216
        /* Then add ipalias and proxyarp types already defined on the backup */
217
	if (is_array($vipbackup) && !empty($vipbackup)) {
218
		if (!is_array($config['virtualip']))
219
			$config['virtualip'] = array();
220
		if (!is_array($config['virtualip']['vip']))
221
			$config['virtualip']['vip'] = array();
222
		foreach ($vipbackup as $vip)
223
			array_unshift($config['virtualip']['vip'], $vip);
224
	}
225

    
226
	/* Log what happened */
227
	$mergedkeys = implode(",", array_merge(array_keys($params[0]), $sync_full_done));
228
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."),$mergedkeys));
229

    
230
	/* 
231
	 * The real work on handling the vips specially
232
	 * This is a copy of intefaces_vips_configure with addition of not reloading existing/not changed carps
233
	 */
234
	if (isset($params[0]['virtualip']) && is_array($config['virtualip']) && is_array($config['virtualip']['vip'])) {
235
		$carp_setuped = false;
236
		$anyproxyarp = false;
237
		foreach ($config['virtualip']['vip'] as $vip) {
238
			if ($vip['mode'] == "carp" && isset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"])) {
239
				if ($oldvips["{$vip['interface']}_vip{$vip['vhid']}"] == "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}") {
240
					if (does_vip_exist($vip)) {
241
						unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
242
						continue; // Skip reconfiguring this vips since nothing has changed.
243
					}
244
				}
245
				unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
246
			} else if ($vip['mode'] == "ipalias" && strstr($vip['interface'], "_vip") && isset($oldvips[$vip['subnet']])) {
247
				if ($oldvips[$vip['subnet']] == "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}") {
248
					if (does_vip_exist($vip)) {
249
						unset($oldvips[$vip['subnet']]);
250
						continue; // Skip reconfiguring this vips since nothing has changed.
251
					}
252
				}
253
				unset($oldvips[$vip['subnet']]);
254
			}
255

    
256
			switch ($vip['mode']) {
257
			case "proxyarp":
258
				$anyproxyarp = true;
259
				break;
260
			case "ipalias":
261
				interface_ipalias_configure($vip);
262
				break;
263
			case "carp":
264
				if ($carp_setuped == false)
265
                                        $carp_setuped = true;
266
				interface_carp_configure($vip);
267
				break;
268
			}
269
		}
270
		/* Cleanup remaining old carps */
271
		foreach ($oldvips as $oldvipif => $oldvippar) {
272
			$oldvipif = get_real_interface($oldvippar['interface']);
273
			if (!empty($oldvipif))
274
				pfSense_interface_deladdress($oldvipif, $oldvipar['subnet']);
275
		}
276
		if ($carp_setuped == true)
277
			interfaces_sync_setup();
278
		if ($anyproxyarp == true)
279
			interface_proxyarp_configure();
280
	}
281

    
282
	if (isset($old_config['ipsec']['enable']) !== isset($config['ipsec']['enable']))
283
		vpn_ipsec_configure();
284

    
285
	unset($old_config);
286

    
287
	return $xmlrpc_g['return']['true'];
288
}
289

    
290
/*****************************/
291
$merge_config_section_doc = gettext("XMLRPC wrapper for merging package sections. This method must be called with two parameters: a string containing the local system\'s password and an array to merge into the system\'s config. This function returns true upon completion.");
292
$merge_config_section_sig = array(
293
	array(
294
		$XML_RPC_Boolean,
295
		$XML_RPC_String,
296
		$XML_RPC_Struct
297
	)
298
);
299

    
300
function merge_installedpackages_section_xmlrpc($raw_params) {
301
	global $config, $xmlrpc_g;
302

    
303
	if (xmlrpc_loop_detect()) {
304
		log_error("Disallowing CARP sync loop");
305
		return;
306
	}
307

    
308
	$params = xmlrpc_params_to_php($raw_params);
309
	if(!xmlrpc_auth($params)) {
310
		xmlrpc_authfail();
311
		return $xmlrpc_g['return']['authfail'];
312
	}
313
	$config['installedpackages'] = array_merge($config['installedpackages'], $params[0]);
314
	$mergedkeys = implode(",", array_keys($params[0]));
315
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."),$mergedkeys));
316

    
317
	return $xmlrpc_g['return']['true'];
318
}
319

    
320
/*****************************/
321
$merge_config_section_doc = gettext("XMLRPC wrapper for merge_config_section. This method must be called with two parameters: a string containing the local system\'s password and an array to merge into the system\'s config. This function returns true upon completion.");
322
$merge_config_section_sig = array(
323
	array(
324
		$XML_RPC_Boolean,
325
		$XML_RPC_String,
326
		$XML_RPC_Struct
327
	)
328
);
329

    
330
function merge_config_section_xmlrpc($raw_params) {
331
	global $config, $xmlrpc_g;
332

    
333
	if (xmlrpc_loop_detect()) {
334
		log_error("Disallowing CARP sync loop");
335
		return;
336
	}
337

    
338
	$params = xmlrpc_params_to_php($raw_params);
339
	if(!xmlrpc_auth($params)) {
340
		xmlrpc_authfail();
341
		return $xmlrpc_g['return']['authfail'];
342
	}
343
	$config_new = array_overlay($config, $params[0]);
344
	$config = $config_new;
345
	$mergedkeys = implode(",", array_keys($params[0]));
346
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
347
	return $xmlrpc_g['return']['true'];
348
}
349

    
350
/*****************************/
351
$filter_configure_doc = gettext("Basic XMLRPC wrapper for filter_configure. This method must be called with one paramater: a string containing the local system\'s password. This function returns true upon completion.");
352
$filter_configure_sig = array(
353
	array(
354
		$XML_RPC_Boolean,
355
		$XML_RPC_String
356
	)
357
);
358

    
359
function filter_configure_xmlrpc($raw_params) {
360
	global $xmlrpc_g, $config;
361

    
362
	$params = xmlrpc_params_to_php($raw_params);
363
	if(!xmlrpc_auth($params)) {
364
		xmlrpc_authfail();
365
		return $xmlrpc_g['return']['authfail'];
366
	}
367
	filter_configure();
368
	system_routing_configure();
369
	setup_gateways_monitor();
370
	relayd_configure();
371
	require_once("openvpn.inc");
372
	openvpn_resync_all();
373
	if (isset($config['dnsmasq']['enable']))
374
		services_dnsmasq_configure();
375
	elseif (isset($config['unbound']['enable']))
376
		services_unbound_configure();
377
	else
378
		# Both calls above run services_dhcpd_configure(), then we just
379
		# need to call it when them are not called to avoid restart dhcpd
380
		# twice, as described on ticket #3797
381
		services_dhcpd_configure();
382
	local_sync_accounts();
383

    
384
	return $xmlrpc_g['return']['true'];
385
}
386

    
387
/*****************************/
388
$carp_configure_doc = gettext("Basic XMLRPC wrapper for configuring CARP interfaces.");
389
$carp_configure_sig = array(
390
	array(
391
		$XML_RPC_Boolean,
392
		$XML_RPC_String
393
	)
394
);
395

    
396
function interfaces_carp_configure_xmlrpc($raw_params) {
397
	global $xmlrpc_g;
398

    
399
	if (xmlrpc_loop_detect()) {
400
		log_error("Disallowing CARP sync loop");
401
		return;
402
	}
403

    
404
	$params = xmlrpc_params_to_php($raw_params);
405
	if(!xmlrpc_auth($params)) {
406
		xmlrpc_authfail();
407
		return $xmlrpc_g['return']['authfail'];
408
	}
409
	interfaces_vips_configure();
410

    
411
	return $xmlrpc_g['return']['true'];
412
}
413

    
414
/*****************************/
415
$check_firmware_version_doc = gettext("Basic XMLRPC wrapper for check_firmware_version. This function will return the output of check_firmware_version upon completion.");
416

    
417
$check_firmware_version_sig = array(
418
	array(
419
		$XML_RPC_String,
420
		$XML_RPC_String
421
	)
422
);
423

    
424
function check_firmware_version_xmlrpc($raw_params) {
425
	global $xmlrpc_g, $XML_RPC_String;
426

    
427
	$params = xmlrpc_params_to_php($raw_params);
428
	if(!xmlrpc_auth($params)) {
429
		xmlrpc_authfail();
430
		return $xmlrpc_g['return']['authfail'];
431
	}
432
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
433
}
434

    
435
/*****************************/
436
$pfsense_firmware_version_doc = gettext("Basic XMLRPC wrapper for check_firmware_version. This function will return the output of check_firmware_version upon completion.");
437

    
438
$pfsense_firmware_version_sig = array (
439
        array (
440
                $XML_RPC_Struct,
441
                $XML_RPC_String
442
        )
443
);
444

    
445
function pfsense_firmware_version_xmlrpc($raw_params) {
446
        global $xmlrpc_g;
447

    
448
        $params = xmlrpc_params_to_php($raw_params);
449
        if(!xmlrpc_auth($params)) {
450
			xmlrpc_authfail();
451
			return $xmlrpc_g['return']['authfail'];
452
		}
453
        return new XML_RPC_Response(XML_RPC_encode(host_firmware_version()));
454
}
455

    
456
/*****************************/
457
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
458
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
459
function reboot_xmlrpc($raw_params) {
460
	global $xmlrpc_g;
461

    
462
	$params = xmlrpc_params_to_php($raw_params);
463
	if(!xmlrpc_auth($params)) {
464
		xmlrpc_authfail();
465
		return $xmlrpc_g['return']['authfail'];
466
	}
467
	mwexec_bg("/etc/rc.reboot");
468

    
469
	return $xmlrpc_g['return']['true'];
470
}
471

    
472
/*****************************/
473
$get_notices_sig = array(
474
	array(
475
		$XML_RPC_Array,
476
		$XML_RPC_String
477
	),
478
	array(
479
		$XML_RPC_Array
480
	)
481
);
482

    
483
function get_notices_xmlrpc($raw_params) {
484
	global $g, $xmlrpc_g;
485

    
486
	$params = xmlrpc_params_to_php($raw_params);
487
	if(!xmlrpc_auth($params)) {
488
		xmlrpc_authfail();
489
		return $xmlrpc_g['return']['authfail'];
490
	}
491
	if(!function_exists("get_notices"))
492
		require("notices.inc");
493
	if(!$params) {
494
		$toreturn = get_notices();
495
	} else {
496
		$toreturn = get_notices($params);
497
	}
498
	$response = new XML_RPC_Response(XML_RPC_encode($toreturn));
499

    
500
	return $response;
501
}
502

    
503
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
504

    
505
/*****************************/
506
$server = new XML_RPC_Server(
507
        array(
508
		'pfsense.exec_shell' => array('function' => 'exec_shell_xmlrpc',
509
			'signature' => $exec_shell_sig,
510
			'docstring' => $exec_shell_doc),
511
		'pfsense.exec_php' => array('function' => 'exec_php_xmlrpc',
512
			'signature' => $exec_php_sig,
513
			'docstring' => $exec_php_doc),	
514
		'pfsense.filter_configure' => array('function' => 'filter_configure_xmlrpc',
515
			'signature' => $filter_configure_sig,
516
			'docstring' => $filter_configure_doc),
517
		'pfsense.interfaces_carp_configure' => array('function' => 'interfaces_carp_configure_xmlrpc',
518
			'docstring' => $carp_configure_sig),
519
		'pfsense.backup_config_section' => array('function' => 'backup_config_section_xmlrpc',
520
			'signature' => $backup_config_section_sig,
521
			'docstring' => $backup_config_section_doc),
522
		'pfsense.restore_config_section' => array('function' => 'restore_config_section_xmlrpc',
523
			'signature' => $restore_config_section_sig,
524
			'docstring' => $restore_config_section_doc),
525
		'pfsense.merge_config_section' => array('function' => 'merge_config_section_xmlrpc',
526
			'signature' => $merge_config_section_sig,
527
			'docstring' => $merge_config_section_doc),
528
		'pfsense.merge_installedpackages_section_xmlrpc' => array('function' => 'merge_installedpackages_section_xmlrpc',
529
			'signature' => $merge_config_section_sig,
530
			'docstring' => $merge_config_section_doc),							
531
		'pfsense.check_firmware_version' => array('function' => 'check_firmware_version_xmlrpc',
532
			'signature' => $check_firmware_version_sig,
533
			'docstring' => $check_firmware_version_doc),
534
		'pfsense.host_firmware_version' => array('function' => 'pfsense_firmware_version_xmlrpc',
535
			'signature' => $pfsense_firmware_version_sig,
536
			'docstring' => $host_firmware_version_doc),
537
		'pfsense.reboot' => array('function' => 'reboot_xmlrpc',
538
			'signature' => $reboot_sig,
539
			'docstring' => $reboot_doc),
540
		'pfsense.get_notices' => array('function' => 'get_notices_xmlrpc',
541
			'signature' => $get_notices_sig)
542
        )
543
);
544

    
545
unlock($xmlrpclockkey);
546

    
547
    function array_overlay($a1,$a2)
548
    {
549
        foreach($a1 as $k => $v) {
550
            if(!array_key_exists($k,$a2)) continue;
551
            if(is_array($v) && is_array($a2[$k])){
552
                $a1[$k] = array_overlay($v,$a2[$k]);
553
            }else{
554
                $a1[$k] = $a2[$k];
555
            }
556
        }
557
        return $a1;
558
    }
559

    
560
?>
(256-256/256)