Project

General

Profile

Download (16.7 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['hasync']) {
49
	$synchronizetoip = $hasync['synchronizetoip'];
50
}
51

    
52
if($synchronizetoip) {
53
	if($synchronizetoip == $_SERVER['REMOTE_ADDR']) {
54
		log_error(gettext("Disallowing CARP sync loop."));
55
		die;	
56
	}
57
}
58

    
59
$xmlrpc_g = array(
60
	"return" => array(
61
		"true" => new XML_RPC_Response(new XML_RPC_Value(true, $XML_RPC_Boolean)),
62
		"false" => new XML_RPC_Response(new XML_RPC_Value(false, $XML_RPC_Boolean)),
63
		"authfail" => new XML_RPC_Response(new XML_RPC_Value(gettext("Authentication failed"), $XML_RPC_String))
64
	)
65
);
66

    
67
/*
68
 *   pfSense XMLRPC errors
69
 *   $XML_RPC_erruser + 1 = Auth failure
70
 */
71
$XML_RPC_erruser = 200;
72

    
73
/* EXPOSED FUNCTIONS */
74
$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.");
75
$exec_php_sig = array(
76
	array(
77
		$XML_RPC_Boolean, // First signature element is return value.
78
		$XML_RPC_String, // password
79
		$XML_RPC_String, // shell code to exec
80
	)
81
);
82

    
83
function xmlrpc_authfail() {
84
	log_auth("webConfigurator authentication error for 'admin' from {$_SERVER['REMOTE_ADDR']}");
85
}
86

    
87
function exec_php_xmlrpc($raw_params) {
88
	global $config, $xmlrpc_g;
89

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

    
104
/*****************************/
105
$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.");
106
$exec_shell_sig = array(
107
	array(
108
		$XML_RPC_Boolean, // First signature element is return value.
109
		$XML_RPC_String, // password
110
		$XML_RPC_String, // shell code to exec
111
	)
112
);
113

    
114
function exec_shell_xmlrpc($raw_params) {
115
	global $config, $xmlrpc_g;
116

    
117
	$params = xmlrpc_params_to_php($raw_params);
118
	if(!xmlrpc_auth($params)) {
119
		xmlrpc_authfail();
120
		return $xmlrpc_g['return']['authfail'];
121
	}
122
	$shell_cmd = $params[0];
123
	mwexec($shell_cmd);
124

    
125
	return $xmlrpc_g['return']['true'];
126
}
127

    
128
/*****************************/
129
$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.");
130
$backup_config_section_sig = array(
131
	array(
132
		$XML_RPC_Struct, // First signature element is return value.
133
		$XML_RPC_String,
134
		$XML_RPC_Array
135
	)
136
);
137

    
138
function backup_config_section_xmlrpc($raw_params) {
139
	global $config, $xmlrpc_g;
140

    
141
	$params = xmlrpc_params_to_php($raw_params);
142
	if(!xmlrpc_auth($params)) {
143
		xmlrpc_authfail();
144
		return $xmlrpc_g['return']['authfail'];
145
	}
146
	$val = array_intersect_key($config, array_flip($params[0]));
147

    
148
	return new XML_RPC_Response(XML_RPC_encode($val));
149
}
150

    
151
/*****************************/
152
$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.");
153
$restore_config_section_sig = array(
154
	array(
155
		$XML_RPC_Boolean,
156
		$XML_RPC_String,
157
		$XML_RPC_Struct
158
	)
159
);
160

    
161
function restore_config_section_xmlrpc($raw_params) {
162
	global $config, $xmlrpc_g;
163

    
164
	$params = xmlrpc_params_to_php($raw_params);
165
	if(!xmlrpc_auth($params)) {
166
		xmlrpc_authfail();
167
		return $xmlrpc_g['return']['authfail'];
168
	}
169

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

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

    
197
        // For vip section, first keep items sent from the master
198
	$config = array_merge_recursive_unique($config, $params[0]);
199

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

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

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

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

    
268
	return $xmlrpc_g['return']['true'];
269
}
270

    
271
/*****************************/
272
$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.");
273
$merge_config_section_sig = array(
274
	array(
275
		$XML_RPC_Boolean,
276
		$XML_RPC_String,
277
		$XML_RPC_Struct
278
	)
279
);
280

    
281
function merge_installedpackages_section_xmlrpc($raw_params) {
282
	global $config, $xmlrpc_g;
283

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

    
293
	return $xmlrpc_g['return']['true'];
294
}
295

    
296
/*****************************/
297
$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.");
298
$merge_config_section_sig = array(
299
	array(
300
		$XML_RPC_Boolean,
301
		$XML_RPC_String,
302
		$XML_RPC_Struct
303
	)
304
);
305

    
306
function merge_config_section_xmlrpc($raw_params) {
307
	global $config, $xmlrpc_g;
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_new = array_overlay($config, $params[0]);
314
	$config = $config_new;
315
	$mergedkeys = implode(",", array_keys($params[0]));
316
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
317
	return $xmlrpc_g['return']['true'];
318
}
319

    
320
/*****************************/
321
$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.");
322
$filter_configure_sig = array(
323
	array(
324
		$XML_RPC_Boolean,
325
		$XML_RPC_String
326
	)
327
);
328

    
329
function filter_configure_xmlrpc($raw_params) {
330
	global $xmlrpc_g;
331

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

    
347
	return $xmlrpc_g['return']['true'];
348
}
349

    
350
/*****************************/
351
$carp_configure_doc = gettext("Basic XMLRPC wrapper for configuring CARP interfaces.");
352
$carp_configure_sig = array(
353
	array(
354
		$XML_RPC_Boolean,
355
		$XML_RPC_String
356
	)
357
);
358

    
359
function interfaces_carp_configure_xmlrpc($raw_params) {
360
	global $xmlrpc_g;
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
	interfaces_vips_configure();
368

    
369
	return $xmlrpc_g['return']['true'];
370
}
371

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

    
375
$check_firmware_version_sig = array(
376
	array(
377
		$XML_RPC_String,
378
		$XML_RPC_String
379
	)
380
);
381

    
382
function check_firmware_version_xmlrpc($raw_params) {
383
	global $xmlrpc_g, $XML_RPC_String;
384

    
385
	$params = xmlrpc_params_to_php($raw_params);
386
	if(!xmlrpc_auth($params)) {
387
		xmlrpc_authfail();
388
		return $xmlrpc_g['return']['authfail'];
389
	}
390
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
391
}
392

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

    
396
$pfsense_firmware_version_sig = array (
397
        array (
398
                $XML_RPC_Struct,
399
                $XML_RPC_String
400
        )
401
);
402

    
403
function pfsense_firmware_version_xmlrpc($raw_params) {
404
        global $xmlrpc_g;
405

    
406
        $params = xmlrpc_params_to_php($raw_params);
407
        if(!xmlrpc_auth($params)) {
408
			xmlrpc_authfail();
409
			return $xmlrpc_g['return']['authfail'];
410
		}
411
        return new XML_RPC_Response(XML_RPC_encode(host_firmware_version()));
412
}
413

    
414
/*****************************/
415
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
416
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
417
function reboot_xmlrpc($raw_params) {
418
	global $xmlrpc_g;
419

    
420
	$params = xmlrpc_params_to_php($raw_params);
421
	if(!xmlrpc_auth($params)) {
422
		xmlrpc_authfail();
423
		return $xmlrpc_g['return']['authfail'];
424
	}
425
	mwexec_bg("/etc/rc.reboot");
426

    
427
	return $xmlrpc_g['return']['true'];
428
}
429

    
430
/*****************************/
431
$get_notices_sig = array(
432
	array(
433
		$XML_RPC_Array,
434
		$XML_RPC_String
435
	),
436
	array(
437
		$XML_RPC_Array
438
	)
439
);
440

    
441
function get_notices_xmlrpc($raw_params) {
442
	global $g, $xmlrpc_g;
443

    
444
	$params = xmlrpc_params_to_php($raw_params);
445
	if(!xmlrpc_auth($params)) {
446
		xmlrpc_authfail();
447
		return $xmlrpc_g['return']['authfail'];
448
	}
449
	require("notices.inc");
450
	if(!$params) {
451
		$toreturn = get_notices();
452
	} else {
453
		$toreturn = get_notices($params);
454
	}
455
	$response = new XML_RPC_Response(XML_RPC_encode($toreturn));
456

    
457
	return $response;
458
}
459

    
460
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
461

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

    
502
unlock($xmlrpclockkey);
503

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

    
517
?>
(245-245/245)