Projet

Général

Profil

Télécharger (17,7 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / usr / local / www / xmlrpc.php @ 7486c1f6

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
			if (!is_ipaddr($oldvipif) && does_interface_exist($oldvipif))
273
					pfSense_interface_destroy($oldvipif);
274
		}
275
		if ($carp_setuped == true)
276
			interfaces_carp_setup();
277
		if ($anyproxyarp == true)
278
			interface_proxyarp_configure();
279
	}
280

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

    
284
	unset($old_config);
285

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

    
289
/*****************************/
290
$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.");
291
$merge_config_section_sig = array(
292
	array(
293
		$XML_RPC_Boolean,
294
		$XML_RPC_String,
295
		$XML_RPC_Struct
296
	)
297
);
298

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

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

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

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

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

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

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

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

    
349
/*****************************/
350
$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.");
351
$filter_configure_sig = array(
352
	array(
353
		$XML_RPC_Boolean,
354
		$XML_RPC_String
355
	)
356
);
357

    
358
function filter_configure_xmlrpc($raw_params) {
359
	global $xmlrpc_g;
360

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

    
381
	return $xmlrpc_g['return']['true'];
382
}
383

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

    
393
function interfaces_carp_configure_xmlrpc($raw_params) {
394
	global $xmlrpc_g;
395

    
396
	if (xmlrpc_loop_detect()) {
397
		log_error("Disallowing CARP sync loop");
398
		return;
399
	}
400

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

    
408
	return $xmlrpc_g['return']['true'];
409
}
410

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

    
414
$check_firmware_version_sig = array(
415
	array(
416
		$XML_RPC_String,
417
		$XML_RPC_String
418
	)
419
);
420

    
421
function check_firmware_version_xmlrpc($raw_params) {
422
	global $xmlrpc_g, $XML_RPC_String;
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
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
430
}
431

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

    
435
$pfsense_firmware_version_sig = array (
436
        array (
437
                $XML_RPC_Struct,
438
                $XML_RPC_String
439
        )
440
);
441

    
442
function pfsense_firmware_version_xmlrpc($raw_params) {
443
        global $xmlrpc_g;
444

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

    
453
/*****************************/
454
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
455
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
456
function reboot_xmlrpc($raw_params) {
457
	global $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
	mwexec_bg("/etc/rc.reboot");
465

    
466
	return $xmlrpc_g['return']['true'];
467
}
468

    
469
/*****************************/
470
$get_notices_sig = array(
471
	array(
472
		$XML_RPC_Array,
473
		$XML_RPC_String
474
	),
475
	array(
476
		$XML_RPC_Array
477
	)
478
);
479

    
480
function get_notices_xmlrpc($raw_params) {
481
	global $g, $xmlrpc_g;
482

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

    
496
	return $response;
497
}
498

    
499
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
500

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

    
541
unlock($xmlrpclockkey);
542

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

    
556
?>
(246-246/246)