Project

General

Profile

Download (16.9 KB) Statistics
| Branch: | Tag: | Revision:
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("filter.inc");
42
require("shaper.inc");
43
require("xmlrpc_server.inc");
44
require("xmlrpc.inc");
45
require("array_intersect_key.inc");
46

    
47
/* grab sync to ip if enabled */
48
if($config['installedpackages']['carpsettings']) {
49
	if ($config['installedpackages']['carpsettings']['config']) {
50
		foreach ($config['installedpackages']['carpsettings']['config'] as $carp) {
51
			$synchronizetoip = $carp['synchronizetoip'];
52
		}
53
	}
54
}
55

    
56
if($synchronizetoip) {
57
	if($synchronizetoip == $_SERVER['REMOTE_ADDR']) {
58
		log_error(gettext("Disallowing CARP sync loop."));
59
		die;	
60
	}
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
	$params = xmlrpc_params_to_php($raw_params);
146
	if(!xmlrpc_auth($params)) {
147
		xmlrpc_authfail();
148
		return $xmlrpc_g['return']['authfail'];
149
	}
150
	$val = array_intersect_key($config, array_flip($params[0]));
151

    
152
	return new XML_RPC_Response(XML_RPC_encode($val));
153
}
154

    
155
/*****************************/
156
$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.");
157
$restore_config_section_sig = array(
158
	array(
159
		$XML_RPC_Boolean,
160
		$XML_RPC_String,
161
		$XML_RPC_Struct
162
	)
163
);
164

    
165
function restore_config_section_xmlrpc($raw_params) {
166
	global $config, $xmlrpc_g;
167

    
168
	$params = xmlrpc_params_to_php($raw_params);
169
	if(!xmlrpc_auth($params)) {
170
		xmlrpc_authfail();
171
		return $xmlrpc_g['return']['authfail'];
172
	}
173

    
174
	// Some sections should just be copied and not merged or we end
175
	//   up unable to sync the deletion of the last item in a section
176
	$sync_full = array('ipsec', 'aliases', 'wol', 'load_balancer', 'openvpn', 'cert', 'ca', 'crl', 'schedules');
177
	$sync_full_done = array();
178
	foreach ($sync_full as $syncfull) {
179
		if (isset($params[0][$syncfull])) {
180
			$config[$syncfull] = $params[0][$syncfull];
181
			unset($params[0][$syncfull]);
182
			$sync_full_done[] = $syncfull;
183
		}
184
	}
185

    
186
	$vipbackup = array();
187
	$oldvips = array();
188
	if (isset($params[0]['virtualip'])) {
189
		if(is_array($config['virtualip']['vip'])) {
190
			foreach ($config['virtualip']['vip'] as $vipindex => $vip) {
191
				if ($vip['mode'] == "carp")
192
					$oldvips[$vip['vhid']] = "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}";
193
				else if ($vip['mode'] == "ipalias" && substr($vip['interface'], 0, 3) == "vip")
194
					$oldvips[$vip['subnet']] = "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}";
195
				else if (($vip['mode'] == "ipalias" || $vip['mode'] == 'proxyarp') && substr($vip['interface'], 0, 3) != "vip")
196
					$vipbackup[] = $vip;
197
			}
198
		}
199
	}
200

    
201
        // For vip section, first keep items sent from the master
202
	$config = array_merge_recursive_unique($config, $params[0]);
203

    
204
        /* Then add ipalias and proxyarp types already defined on the backup */
205
	if (is_array($vipbackup) && !empty($vipbackup)) {
206
		if (!is_array($config['virtualip']))
207
			$config['virtualip'] = array();
208
		if (!is_array($config['virtualip']['vip']))
209
			$config['virtualip']['vip'] = array();
210
		foreach ($vipbackup as $vip)
211
			array_unshift($config['virtualip']['vip'], $vip);
212
	}
213

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

    
218
	/* 
219
	 * The real work on handling the vips specially
220
	 * This is a copy of intefaces_vips_configure with addition of not reloading existing/not changed carps
221
	 */
222
	if (isset($params[0]['virtualip']) && is_array($config['virtualip']) && is_array($config['virtualip']['vip'])) {
223
		$carp_setuped = false;
224
		$anyproxyarp = false;
225
		foreach ($config['virtualip']['vip'] as $vip) {
226
			if ($vip['mode'] == "carp" && isset($oldvips[$vip['vhid']])) {
227
				if ($oldvips[$vip['vhid']] == "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}") {
228
					if (does_vip_exist($vip)) {
229
						unset($oldvips[$vip['vhid']]);
230
						continue; // Skip reconfiguring this vips since nothing has changed.
231
					}
232
				}
233
				unset($oldvips[$vip['vhid']]);
234
			} else if ($vip['mode'] == "ipalias" && substr($vip['interface'], 0, 3) == "vip" && isset($oldvips[$vip['subnet']])) {
235
				if ($oldvips[$vip['subnet']] = "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}") {
236
					if (does_vip_exist($vip)) {
237
						unset($oldvips[$vip['subnet']]);
238
						continue; // Skip reconfiguring this vips since nothing has changed.
239
					}
240
				}
241
				unset($oldvips[$vip['subnet']]);
242
			}
243

    
244
			switch ($vip['mode']) {
245
			case "proxyarp":
246
				$anyproxyarp = true;
247
				break;
248
			case "ipalias":
249
				interface_ipalias_configure(&$vip);
250
				break;
251
			case "carp":
252
				if ($carp_setuped == false)
253
                                        $carp_setuped = true;
254
				interface_carp_configure($vip);
255
				break;
256
			case "carpdev-dhcp":
257
				interface_carpdev_configure($vip);
258
				break;
259
			}
260
		}
261
		/* Cleanup remaining old carps */
262
		foreach ($oldvips as $oldvipif => $oldvippar) {
263
			if (!is_ipaddr($oldvipif) && does_interface_exist("vip{$oldvipif}"))
264
				pfSense_interface_destroy("vip{$oldvipif}");
265
		}
266
		if ($carp_setuped == true)
267
			interfaces_carp_setup();
268
		if ($anyproxyarp == true)
269
			interface_proxyarp_configure();
270
	}
271

    
272
	return $xmlrpc_g['return']['true'];
273
}
274

    
275
/*****************************/
276
$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.");
277
$merge_config_section_sig = array(
278
	array(
279
		$XML_RPC_Boolean,
280
		$XML_RPC_String,
281
		$XML_RPC_Struct
282
	)
283
);
284

    
285
function merge_installedpackages_section_xmlrpc($raw_params) {
286
	global $config, $xmlrpc_g;
287

    
288
	$params = xmlrpc_params_to_php($raw_params);
289
	if(!xmlrpc_auth($params)) {
290
		xmlrpc_authfail();
291
		return $xmlrpc_g['return']['authfail'];
292
	}
293
	$config['installedpackages'] = array_merge($config['installedpackages'], $params[0]);
294
	$mergedkeys = implode(",", array_keys($params[0]));
295
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."),$mergedkeys));
296

    
297
	return $xmlrpc_g['return']['true'];
298
}
299

    
300
/*****************************/
301
$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.");
302
$merge_config_section_sig = array(
303
	array(
304
		$XML_RPC_Boolean,
305
		$XML_RPC_String,
306
		$XML_RPC_Struct
307
	)
308
);
309

    
310
function merge_config_section_xmlrpc($raw_params) {
311
	global $config, $xmlrpc_g;
312
	$params = xmlrpc_params_to_php($raw_params);
313
	if(!xmlrpc_auth($params)) {
314
		xmlrpc_authfail();
315
		return $xmlrpc_g['return']['authfail'];
316
	}
317
	$config_new = array_overlay($config, $params[0]);
318
	$config = $config_new;
319
	$mergedkeys = implode(",", array_keys($params[0]));
320
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
321
	return $xmlrpc_g['return']['true'];
322
}
323

    
324
/*****************************/
325
$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.");
326
$filter_configure_sig = array(
327
	array(
328
		$XML_RPC_Boolean,
329
		$XML_RPC_String
330
	)
331
);
332

    
333
function filter_configure_xmlrpc($raw_params) {
334
	global $xmlrpc_g;
335

    
336
	$params = xmlrpc_params_to_php($raw_params);
337
	if(!xmlrpc_auth($params)) {
338
		xmlrpc_authfail();
339
		return $xmlrpc_g['return']['authfail'];
340
	}
341
	filter_configure();
342
	system_routing_configure();
343
	setup_gateways_monitor();
344
	relayd_configure();
345
	require_once("openvpn.inc");
346
	openvpn_resync_all();
347
	services_dhcpd_configure();
348
	services_dnsmasq_configure();
349
	local_sync_accounts();
350

    
351
	return $xmlrpc_g['return']['true'];
352
}
353

    
354
/*****************************/
355
$carp_configure_doc = gettext("Basic XMLRPC wrapper for configuring CARP interfaces.");
356
$carp_configure_sig = array(
357
	array(
358
		$XML_RPC_Boolean,
359
		$XML_RPC_String
360
	)
361
);
362

    
363
function interfaces_carp_configure_xmlrpc($raw_params) {
364
	global $xmlrpc_g;
365

    
366
	$params = xmlrpc_params_to_php($raw_params);
367
	if(!xmlrpc_auth($params)) {
368
		xmlrpc_authfail();
369
		return $xmlrpc_g['return']['authfail'];
370
	}
371
	interfaces_vips_configure();
372

    
373
	return $xmlrpc_g['return']['true'];
374
}
375

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

    
379
$check_firmware_version_sig = array(
380
	array(
381
		$XML_RPC_String,
382
		$XML_RPC_String
383
	)
384
);
385

    
386
function check_firmware_version_xmlrpc($raw_params) {
387
	global $xmlrpc_g, $XML_RPC_String;
388

    
389
	$params = xmlrpc_params_to_php($raw_params);
390
	if(!xmlrpc_auth($params)) {
391
		xmlrpc_authfail();
392
		return $xmlrpc_g['return']['authfail'];
393
	}
394
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
395
}
396

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

    
400
$pfsense_firmware_version_sig = array (
401
        array (
402
                $XML_RPC_Struct,
403
                $XML_RPC_String
404
        )
405
);
406

    
407
function pfsense_firmware_version_xmlrpc($raw_params) {
408
        global $xmlrpc_g;
409

    
410
        $params = xmlrpc_params_to_php($raw_params);
411
        if(!xmlrpc_auth($params)) {
412
			xmlrpc_authfail();
413
			return $xmlrpc_g['return']['authfail'];
414
		}
415
        return new XML_RPC_Response(XML_RPC_encode(host_firmware_version()));
416
}
417

    
418
/*****************************/
419
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
420
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
421
function reboot_xmlrpc($raw_params) {
422
	global $xmlrpc_g;
423

    
424
	$params = xmlrpc_params_to_php($raw_params);
425
	if(!xmlrpc_auth($params)) {
426
		xmlrpc_authfail();
427
		return $xmlrpc_g['return']['authfail'];
428
	}
429
	mwexec_bg("/etc/rc.reboot");
430

    
431
	return $xmlrpc_g['return']['true'];
432
}
433

    
434
/*****************************/
435
$get_notices_sig = array(
436
	array(
437
		$XML_RPC_Array,
438
		$XML_RPC_String
439
	),
440
	array(
441
		$XML_RPC_Array
442
	)
443
);
444

    
445
function get_notices_xmlrpc($raw_params) {
446
	global $g, $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
	require("notices.inc");
454
	if(!$params) {
455
		$toreturn = get_notices();
456
	} else {
457
		$toreturn = get_notices($params);
458
	}
459
	$response = new XML_RPC_Response(XML_RPC_encode($toreturn));
460

    
461
	return $response;
462
}
463

    
464
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
465

    
466
/*****************************/
467
$server = new XML_RPC_Server(
468
        array(
469
		'pfsense.exec_shell' => array('function' => 'exec_shell_xmlrpc',
470
			'signature' => $exec_shell_sig,
471
			'docstring' => $exec_shell_doc),
472
		'pfsense.exec_php' => array('function' => 'exec_php_xmlrpc',
473
			'signature' => $exec_php_sig,
474
			'docstring' => $exec_php_doc),	
475
		'pfsense.filter_configure' => array('function' => 'filter_configure_xmlrpc',
476
			'signature' => $filter_configure_sig,
477
			'docstring' => $filter_configure_doc),
478
		'pfsense.interfaces_carp_configure' => array('function' => 'interfaces_carp_configure_xmlrpc',
479
			'docstring' => $carp_configure_sig),
480
		'pfsense.backup_config_section' => array('function' => 'backup_config_section_xmlrpc',
481
			'signature' => $backup_config_section_sig,
482
			'docstring' => $backup_config_section_doc),
483
		'pfsense.restore_config_section' => array('function' => 'restore_config_section_xmlrpc',
484
			'signature' => $restore_config_section_sig,
485
			'docstring' => $restore_config_section_doc),
486
		'pfsense.merge_config_section' => array('function' => 'merge_config_section_xmlrpc',
487
			'signature' => $merge_config_section_sig,
488
			'docstring' => $merge_config_section_doc),
489
		'pfsense.merge_installedpackages_section_xmlrpc' => array('function' => 'merge_installedpackages_section_xmlrpc',
490
			'signature' => $merge_config_section_sig,
491
			'docstring' => $merge_config_section_doc),							
492
		'pfsense.check_firmware_version' => array('function' => 'check_firmware_version_xmlrpc',
493
			'signature' => $check_firmware_version_sig,
494
			'docstring' => $check_firmware_version_doc),
495
		'pfsense.host_firmware_version' => array('function' => 'pfsense_firmware_version_xmlrpc',
496
			'signature' => $pfsense_firmware_version_sig,
497
			'docstring' => $host_firmware_version_doc),
498
		'pfsense.reboot' => array('function' => 'reboot_xmlrpc',
499
			'signature' => $reboot_sig,
500
			'docstring' => $reboot_doc),
501
		'pfsense.get_notices' => array('function' => 'get_notices_xmlrpc',
502
			'signature' => $get_notices_sig)
503
        )
504
);
505

    
506
unlock($xmlrpclockkey);
507

    
508
    function array_overlay($a1,$a2)
509
    {
510
        foreach($a1 as $k => $v) {
511
            if(!array_key_exists($k,$a2)) continue;
512
            if(is_array($v) && is_array($a2[$k])){
513
                $a1[$k] = array_overlay($v,$a2[$k]);
514
            }else{
515
                $a1[$k] = $a2[$k];
516
            }
517
        }
518
        return $a1;
519
    }
520

    
521
?>
(239-239/239)