Project

General

Profile

Download (17.1 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
function xmlrpc_loop_detect() {
48
	global $config;
49

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

    
58
	return false;
59
}
60

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

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

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

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

    
89
function exec_php_xmlrpc($raw_params) {
90
	global $config, $xmlrpc_g;
91

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

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

    
116
function exec_shell_xmlrpc($raw_params) {
117
	global $config, $xmlrpc_g;
118

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

    
127
	return $xmlrpc_g['return']['true'];
128
}
129

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

    
140
function backup_config_section_xmlrpc($raw_params) {
141
	global $config, $xmlrpc_g;
142

    
143
	if (xmlrpc_loop_detect())
144
		log_error("Disallowing CARP sync loop");
145

    
146
	$params = xmlrpc_params_to_php($raw_params);
147
	if(!xmlrpc_auth($params)) {
148
		xmlrpc_authfail();
149
		return $xmlrpc_g['return']['authfail'];
150
	}
151
	$val = array_intersect_key($config, array_flip($params[0]));
152

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

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

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

    
169
	if (xmlrpc_loop_detect())
170
		log_error("Disallowing CARP sync loop");
171

    
172
	$params = xmlrpc_params_to_php($raw_params);
173
	if(!xmlrpc_auth($params)) {
174
		xmlrpc_authfail();
175
		return $xmlrpc_g['return']['authfail'];
176
	}
177

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

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

    
205
        // For vip section, first keep items sent from the master
206
	$config = array_merge_recursive_unique($config, $params[0]);
207

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

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

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

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

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

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

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

    
289
	if (xmlrpc_loop_detect())
290
		log_error("Disallowing CARP sync loop");
291

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

    
301
	return $xmlrpc_g['return']['true'];
302
}
303

    
304
/*****************************/
305
$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.");
306
$merge_config_section_sig = array(
307
	array(
308
		$XML_RPC_Boolean,
309
		$XML_RPC_String,
310
		$XML_RPC_Struct
311
	)
312
);
313

    
314
function merge_config_section_xmlrpc($raw_params) {
315
	global $config, $xmlrpc_g;
316

    
317
	if (xmlrpc_loop_detect())
318
		log_error("Disallowing CARP sync loop");
319

    
320
	$params = xmlrpc_params_to_php($raw_params);
321
	if(!xmlrpc_auth($params)) {
322
		xmlrpc_authfail();
323
		return $xmlrpc_g['return']['authfail'];
324
	}
325
	$config_new = array_overlay($config, $params[0]);
326
	$config = $config_new;
327
	$mergedkeys = implode(",", array_keys($params[0]));
328
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
329
	return $xmlrpc_g['return']['true'];
330
}
331

    
332
/*****************************/
333
$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.");
334
$filter_configure_sig = array(
335
	array(
336
		$XML_RPC_Boolean,
337
		$XML_RPC_String
338
	)
339
);
340

    
341
function filter_configure_xmlrpc($raw_params) {
342
	global $xmlrpc_g;
343

    
344
	$params = xmlrpc_params_to_php($raw_params);
345
	if(!xmlrpc_auth($params)) {
346
		xmlrpc_authfail();
347
		return $xmlrpc_g['return']['authfail'];
348
	}
349
	filter_configure();
350
	system_routing_configure();
351
	setup_gateways_monitor();
352
	relayd_configure();
353
	require_once("openvpn.inc");
354
	openvpn_resync_all();
355
	services_dhcpd_configure();
356
	services_dnsmasq_configure();
357
	local_sync_accounts();
358

    
359
	return $xmlrpc_g['return']['true'];
360
}
361

    
362
/*****************************/
363
$carp_configure_doc = gettext("Basic XMLRPC wrapper for configuring CARP interfaces.");
364
$carp_configure_sig = array(
365
	array(
366
		$XML_RPC_Boolean,
367
		$XML_RPC_String
368
	)
369
);
370

    
371
function interfaces_carp_configure_xmlrpc($raw_params) {
372
	global $xmlrpc_g;
373

    
374
	if (xmlrpc_loop_detect())
375
		log_error("Disallowing CARP sync loop");
376

    
377
	$params = xmlrpc_params_to_php($raw_params);
378
	if(!xmlrpc_auth($params)) {
379
		xmlrpc_authfail();
380
		return $xmlrpc_g['return']['authfail'];
381
	}
382
	interfaces_vips_configure();
383

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

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

    
390
$check_firmware_version_sig = array(
391
	array(
392
		$XML_RPC_String,
393
		$XML_RPC_String
394
	)
395
);
396

    
397
function check_firmware_version_xmlrpc($raw_params) {
398
	global $xmlrpc_g, $XML_RPC_String;
399

    
400
	$params = xmlrpc_params_to_php($raw_params);
401
	if(!xmlrpc_auth($params)) {
402
		xmlrpc_authfail();
403
		return $xmlrpc_g['return']['authfail'];
404
	}
405
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
406
}
407

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

    
411
$pfsense_firmware_version_sig = array (
412
        array (
413
                $XML_RPC_Struct,
414
                $XML_RPC_String
415
        )
416
);
417

    
418
function pfsense_firmware_version_xmlrpc($raw_params) {
419
        global $xmlrpc_g;
420

    
421
        $params = xmlrpc_params_to_php($raw_params);
422
        if(!xmlrpc_auth($params)) {
423
			xmlrpc_authfail();
424
			return $xmlrpc_g['return']['authfail'];
425
		}
426
        return new XML_RPC_Response(XML_RPC_encode(host_firmware_version()));
427
}
428

    
429
/*****************************/
430
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
431
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
432
function reboot_xmlrpc($raw_params) {
433
	global $xmlrpc_g;
434

    
435
	$params = xmlrpc_params_to_php($raw_params);
436
	if(!xmlrpc_auth($params)) {
437
		xmlrpc_authfail();
438
		return $xmlrpc_g['return']['authfail'];
439
	}
440
	mwexec_bg("/etc/rc.reboot");
441

    
442
	return $xmlrpc_g['return']['true'];
443
}
444

    
445
/*****************************/
446
$get_notices_sig = array(
447
	array(
448
		$XML_RPC_Array,
449
		$XML_RPC_String
450
	),
451
	array(
452
		$XML_RPC_Array
453
	)
454
);
455

    
456
function get_notices_xmlrpc($raw_params) {
457
	global $g, $xmlrpc_g;
458

    
459
	$params = xmlrpc_params_to_php($raw_params);
460
	if(!xmlrpc_auth($params)) {
461
		xmlrpc_authfail();
462
		return $xmlrpc_g['return']['authfail'];
463
	}
464
	require("notices.inc");
465
	if(!$params) {
466
		$toreturn = get_notices();
467
	} else {
468
		$toreturn = get_notices($params);
469
	}
470
	$response = new XML_RPC_Response(XML_RPC_encode($toreturn));
471

    
472
	return $response;
473
}
474

    
475
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
476

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

    
517
unlock($xmlrpclockkey);
518

    
519
    function array_overlay($a1,$a2)
520
    {
521
        foreach($a1 as $k => $v) {
522
            if(!array_key_exists($k,$a2)) continue;
523
            if(is_array($v) && is_array($a2[$k])){
524
                $a1[$k] = array_overlay($v,$a2[$k]);
525
            }else{
526
                $a1[$k] = $a2[$k];
527
            }
528
        }
529
        return $a1;
530
    }
531

    
532
?>
(249-249/249)