Project

General

Profile

Download (16.8 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['interface']}_vip{$vip['vhid']}"] = "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}";
189
				else if ($vip['mode'] == "ipalias" && strstr($vip['interface'], "_vip"))
190
					$oldvips[$vip['subnet']] = "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}";
191
				else if (($vip['mode'] == "ipalias" || $vip['mode'] == 'proxyarp') && !strstr($vip['interface'], "_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['interface']}_vip{$vip['vhid']}"])) {
223
				if ($oldvips["{$vip['interface']}_vip{$vip['vhid']}"] == "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}") {
224
					if (does_vip_exist($vip)) {
225
						unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
226
						continue; // Skip reconfiguring this vips since nothing has changed.
227
					}
228
				}
229
				unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
230
			} else if ($vip['mode'] == "ipalias" && strstr($vip['interface'], "_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
			}
253
		}
254
		/* Cleanup remaining old carps */
255
		foreach ($oldvips as $oldvipif => $oldvippar) {
256
			if (!is_ipaddr($oldvipif) && does_interface_exist($oldvipif))
257
					pfSense_interface_destroy($oldvipif);
258
		}
259
		if ($carp_setuped == true)
260
			interfaces_carp_setup();
261
		if ($anyproxyarp == true)
262
			interface_proxyarp_configure();
263
	}
264

    
265
	return $xmlrpc_g['return']['true'];
266
}
267

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

    
278
function merge_installedpackages_section_xmlrpc($raw_params) {
279
	global $config, $xmlrpc_g;
280

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

    
290
	return $xmlrpc_g['return']['true'];
291
}
292

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

    
303
function merge_config_section_xmlrpc($raw_params) {
304
	global $config, $xmlrpc_g;
305
	$params = xmlrpc_params_to_php($raw_params);
306
	if(!xmlrpc_auth($params)) {
307
		xmlrpc_authfail();
308
		return $xmlrpc_g['return']['authfail'];
309
	}
310
	$config_new = array_overlay($config, $params[0]);
311
	$config = $config_new;
312
	$mergedkeys = implode(",", array_keys($params[0]));
313
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
314
	return $xmlrpc_g['return']['true'];
315
}
316

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

    
326
function filter_configure_xmlrpc($raw_params) {
327
	global $xmlrpc_g;
328

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

    
344
	return $xmlrpc_g['return']['true'];
345
}
346

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

    
356
function interfaces_carp_configure_xmlrpc($raw_params) {
357
	global $xmlrpc_g;
358

    
359
	$params = xmlrpc_params_to_php($raw_params);
360
	if(!xmlrpc_auth($params)) {
361
		xmlrpc_authfail();
362
		return $xmlrpc_g['return']['authfail'];
363
	}
364
	interfaces_vips_configure();
365

    
366
	return $xmlrpc_g['return']['true'];
367
}
368

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

    
372
$check_firmware_version_sig = array(
373
	array(
374
		$XML_RPC_String,
375
		$XML_RPC_String
376
	)
377
);
378

    
379
function check_firmware_version_xmlrpc($raw_params) {
380
	global $xmlrpc_g, $XML_RPC_String;
381

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

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

    
393
$pfsense_firmware_version_sig = array (
394
        array (
395
                $XML_RPC_Struct,
396
                $XML_RPC_String
397
        )
398
);
399

    
400
function pfsense_firmware_version_xmlrpc($raw_params) {
401
        global $xmlrpc_g;
402

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

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

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

    
424
	return $xmlrpc_g['return']['true'];
425
}
426

    
427
/*****************************/
428
$get_notices_sig = array(
429
	array(
430
		$XML_RPC_Array,
431
		$XML_RPC_String
432
	),
433
	array(
434
		$XML_RPC_Array
435
	)
436
);
437

    
438
function get_notices_xmlrpc($raw_params) {
439
	global $g, $xmlrpc_g;
440

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

    
454
	return $response;
455
}
456

    
457
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
458

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

    
499
unlock($xmlrpclockkey);
500

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

    
514
?>
(248-248/248)