Project

General

Profile

Download (18.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	xmlrpc.php
4
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
5
	Copyright (C) 2009, 2010 Scott Ullrich
6
	Copyright (C) 2005 Colin Smith
7
	All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14

    
15
	2. Redistributions in binary form must reproduce the above copyright
16
	   notice, this list of conditions and the following disclaimer in the
17
	   documentation and/or other materials provided with the distribution.
18

    
19
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29
*/
30

    
31
##|+PRIV
32
##|*IDENT=page-xmlrpclibrary
33
##|*NAME=XMLRPC Library page
34
##|*DESCR=Allow access to the 'XMLRPC Library' page.
35
##|*MATCH=xmlrpc.php*
36
##|-PRIV
37

    
38
require("config.inc");
39
require("functions.inc");
40
require_once("filter.inc");
41
require("ipsec.inc");
42
require("vpn.inc");
43
require("shaper.inc");
44
require("xmlrpc_server.inc");
45
require("xmlrpc.inc");
46
require("array_intersect_key.inc");
47

    
48
function xmlrpc_loop_detect() {
49
	global $config;
50

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

    
59
	return false;
60
}
61

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

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

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

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

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

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

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

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

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

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

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

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

    
144
	if (xmlrpc_loop_detect()) {
145
		log_error("Disallowing CARP sync loop");
146
		return;
147
	}
148

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

    
156
	return new XML_RPC_Response(XML_RPC_encode($val));
157
}
158

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

    
169
function restore_config_section_xmlrpc($raw_params) {
170
	global $config, $xmlrpc_g;
171

    
172
	$old_config = $config;
173

    
174
	if (xmlrpc_loop_detect()) {
175
		log_error("Disallowing CARP sync loop");
176
		return;
177
	}
178

    
179
	$params = xmlrpc_params_to_php($raw_params);
180
	if(!xmlrpc_auth($params)) {
181
		xmlrpc_authfail();
182
		return $xmlrpc_g['return']['authfail'];
183
	}
184

    
185
	/*
186
	 * Make sure it doesn't end up with both dnsmasq and unbound enabled
187
	 * simultaneously in secondary
188
	 * */
189
	if (isset($params[0]['unbound']['enable']) && isset($config['dnsmasq']['enable'])) {
190
		unset($config['dnsmasq']['enable']);
191
		services_dnsmasq_configure();
192
	} else if (isset($params[0]['dnsmasq']['enable']) && isset($config['unbound']['enable'])) {
193
		unset($config['unbound']['enable']);
194
		services_unbound_configure();
195
	}
196

    
197
	// Some sections should just be copied and not merged or we end
198
	//   up unable to sync the deletion of the last item in a section
199
	$sync_full = array('dnsmasq', 'unbound', 'ipsec', 'aliases', 'wol', 'load_balancer', 'openvpn', 'cert', 'ca', 'crl', 'schedules', 'filter', 'nat', 'dhcpd', 'dhcpv6');
200
	$sync_full_done = array();
201
	foreach ($sync_full as $syncfull) {
202
		if (isset($params[0][$syncfull])) {
203
			$config[$syncfull] = $params[0][$syncfull];
204
			unset($params[0][$syncfull]);
205
			$sync_full_done[] = $syncfull;
206
		}
207
	}
208

    
209
	$vipbackup = array();
210
	$oldvips = array();
211
	if (isset($params[0]['virtualip'])) {
212
		if (is_array($config['virtualip']['vip'])) {
213
			foreach ($config['virtualip']['vip'] as $vipindex => $vip) {
214
				if ($vip['mode'] == "carp")
215
					$oldvips["{$vip['interface']}_vip{$vip['vhid']}"] = "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}";
216
				else if ($vip['mode'] == "ipalias" && (strstr($vip['interface'], "_vip") || strstr($vip['interface'], "lo0")))
217
					$oldvips[$vip['subnet']] = "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}";
218
				else if (($vip['mode'] == "ipalias" || $vip['mode'] == 'proxyarp') && !(strstr($vip['interface'], "_vip") || strstr($vip['interface'], "lo0")))
219
					$vipbackup[] = $vip;
220
			}
221
		}
222
	}
223

    
224
        // For vip section, first keep items sent from the master
225
	$config = array_merge_recursive_unique($config, $params[0]);
226

    
227
        /* Then add ipalias and proxyarp types already defined on the backup */
228
	if (is_array($vipbackup) && !empty($vipbackup)) {
229
		if (!is_array($config['virtualip']))
230
			$config['virtualip'] = array();
231
		if (!is_array($config['virtualip']['vip']))
232
			$config['virtualip']['vip'] = array();
233
		foreach ($vipbackup as $vip)
234
			array_unshift($config['virtualip']['vip'], $vip);
235
	}
236

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

    
241
	/* 
242
	 * The real work on handling the vips specially
243
	 * This is a copy of intefaces_vips_configure with addition of not reloading existing/not changed carps
244
	 */
245
	if (isset($params[0]['virtualip']) && is_array($config['virtualip']) && is_array($config['virtualip']['vip'])) {
246
		$carp_setuped = false;
247
		$anyproxyarp = false;
248
		foreach ($config['virtualip']['vip'] as $vip) {
249
			if ($vip['mode'] == "carp" && isset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"])) {
250
				if ($oldvips["{$vip['interface']}_vip{$vip['vhid']}"] == "{$vip['password']}{$vip['advskew']}{$vip['subnet']}{$vip['subnet_bits']}{$vip['advbase']}") {
251
					if (does_vip_exist($vip)) {
252
						unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
253
						continue; // Skip reconfiguring this vips since nothing has changed.
254
					}
255
				}
256
				unset($oldvips["{$vip['interface']}_vip{$vip['vhid']}"]);
257
			} else if ($vip['mode'] == "ipalias" && strstr($vip['interface'], "_vip") && isset($oldvips[$vip['subnet']])) {
258
				if ($oldvips[$vip['subnet']] == "{$vip['interface']}{$vip['subnet']}{$vip['subnet_bits']}") {
259
					if (does_vip_exist($vip)) {
260
						unset($oldvips[$vip['subnet']]);
261
						continue; // Skip reconfiguring this vips since nothing has changed.
262
					}
263
				}
264
				unset($oldvips[$vip['subnet']]);
265
			}
266

    
267
			switch ($vip['mode']) {
268
			case "proxyarp":
269
				$anyproxyarp = true;
270
				break;
271
			case "ipalias":
272
				interface_ipalias_configure($vip);
273
				break;
274
			case "carp":
275
				if ($carp_setuped == false)
276
                                        $carp_setuped = true;
277
				interface_carp_configure($vip);
278
				break;
279
			}
280
		}
281
		/* Cleanup remaining old carps */
282
		foreach ($oldvips as $oldvipif => $oldvippar) {
283
			if (strstr($oldvippar['interface'], '_vip')) {
284
				$oldvipif = explode('_vip', $oldvippar['interface']);
285
				$oldvipif = $oldvipif[0];
286
			} else
287
				$oldvipif = get_real_interface($oldvippar['interface']);
288
			if (!empty($oldvipif)) {
289
				if (is_ipaddrv6($oldvipif))
290
					 mwexec("/sbin/ifconfig " . escapeshellarg($oldvipif) . " inet6 " . escapeshellarg($oldvipar['subnet']) . " delete");
291
				else
292
					pfSense_interface_deladdress($oldvipif, $oldvipar['subnet']);
293
			}
294
		}
295
		if ($carp_setuped == true)
296
			interfaces_sync_setup();
297
		if ($anyproxyarp == true)
298
			interface_proxyarp_configure();
299
	}
300

    
301
	if (isset($old_config['ipsec']['enable']) !== isset($config['ipsec']['enable']))
302
		vpn_ipsec_configure();
303

    
304
	unset($old_config);
305

    
306
	return $xmlrpc_g['return']['true'];
307
}
308

    
309
/*****************************/
310
$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.");
311
$merge_config_section_sig = array(
312
	array(
313
		$XML_RPC_Boolean,
314
		$XML_RPC_String,
315
		$XML_RPC_Struct
316
	)
317
);
318

    
319
function merge_installedpackages_section_xmlrpc($raw_params) {
320
	global $config, $xmlrpc_g;
321

    
322
	if (xmlrpc_loop_detect()) {
323
		log_error("Disallowing CARP sync loop");
324
		return;
325
	}
326

    
327
	$params = xmlrpc_params_to_php($raw_params);
328
	if(!xmlrpc_auth($params)) {
329
		xmlrpc_authfail();
330
		return $xmlrpc_g['return']['authfail'];
331
	}
332
	$config['installedpackages'] = array_merge($config['installedpackages'], $params[0]);
333
	$mergedkeys = implode(",", array_keys($params[0]));
334
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."),$mergedkeys));
335

    
336
	return $xmlrpc_g['return']['true'];
337
}
338

    
339
/*****************************/
340
$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.");
341
$merge_config_section_sig = array(
342
	array(
343
		$XML_RPC_Boolean,
344
		$XML_RPC_String,
345
		$XML_RPC_Struct
346
	)
347
);
348

    
349
function merge_config_section_xmlrpc($raw_params) {
350
	global $config, $xmlrpc_g;
351

    
352
	if (xmlrpc_loop_detect()) {
353
		log_error("Disallowing CARP sync loop");
354
		return;
355
	}
356

    
357
	$params = xmlrpc_params_to_php($raw_params);
358
	if(!xmlrpc_auth($params)) {
359
		xmlrpc_authfail();
360
		return $xmlrpc_g['return']['authfail'];
361
	}
362
	$config_new = array_overlay($config, $params[0]);
363
	$config = $config_new;
364
	$mergedkeys = implode(",", array_keys($params[0]));
365
	write_config(sprintf(gettext("Merged in config (%s sections) from XMLRPC client."), $mergedkeys));
366
	return $xmlrpc_g['return']['true'];
367
}
368

    
369
/*****************************/
370
$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.");
371
$filter_configure_sig = array(
372
	array(
373
		$XML_RPC_Boolean,
374
		$XML_RPC_String
375
	)
376
);
377

    
378
function filter_configure_xmlrpc($raw_params) {
379
	global $xmlrpc_g, $config;
380

    
381
	$params = xmlrpc_params_to_php($raw_params);
382
	if(!xmlrpc_auth($params)) {
383
		xmlrpc_authfail();
384
		return $xmlrpc_g['return']['authfail'];
385
	}
386
	filter_configure();
387
	system_routing_configure();
388
	setup_gateways_monitor();
389
	relayd_configure();
390
	require_once("openvpn.inc");
391
	openvpn_resync_all();
392
	if (isset($config['dnsmasq']['enable']))
393
		services_dnsmasq_configure();
394
	elseif (isset($config['unbound']['enable']))
395
		services_unbound_configure();
396
	else
397
		# Both calls above run services_dhcpd_configure(), then we just
398
		# need to call it when them are not called to avoid restart dhcpd
399
		# twice, as described on ticket #3797
400
		services_dhcpd_configure();
401
	local_sync_accounts();
402

    
403
	return $xmlrpc_g['return']['true'];
404
}
405

    
406
/*****************************/
407
$carp_configure_doc = gettext("Basic XMLRPC wrapper for configuring CARP interfaces.");
408
$carp_configure_sig = array(
409
	array(
410
		$XML_RPC_Boolean,
411
		$XML_RPC_String
412
	)
413
);
414

    
415
function interfaces_carp_configure_xmlrpc($raw_params) {
416
	global $xmlrpc_g;
417

    
418
	if (xmlrpc_loop_detect()) {
419
		log_error("Disallowing CARP sync loop");
420
		return;
421
	}
422

    
423
	$params = xmlrpc_params_to_php($raw_params);
424
	if(!xmlrpc_auth($params)) {
425
		xmlrpc_authfail();
426
		return $xmlrpc_g['return']['authfail'];
427
	}
428
	interfaces_vips_configure();
429

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

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

    
436
$check_firmware_version_sig = array(
437
	array(
438
		$XML_RPC_String,
439
		$XML_RPC_String
440
	)
441
);
442

    
443
function check_firmware_version_xmlrpc($raw_params) {
444
	global $xmlrpc_g, $XML_RPC_String;
445

    
446
	$params = xmlrpc_params_to_php($raw_params);
447
	if(!xmlrpc_auth($params)) {
448
		xmlrpc_authfail();
449
		return $xmlrpc_g['return']['authfail'];
450
	}
451
	return new XML_RPC_Response(new XML_RPC_Value(check_firmware_version(false), $XML_RPC_String));
452
}
453

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

    
457
$pfsense_firmware_version_sig = array (
458
        array (
459
                $XML_RPC_Struct,
460
                $XML_RPC_String
461
        )
462
);
463

    
464
function pfsense_firmware_version_xmlrpc($raw_params) {
465
        global $xmlrpc_g;
466

    
467
        $params = xmlrpc_params_to_php($raw_params);
468
        if(!xmlrpc_auth($params)) {
469
			xmlrpc_authfail();
470
			return $xmlrpc_g['return']['authfail'];
471
		}
472
        return new XML_RPC_Response(XML_RPC_encode(host_firmware_version()));
473
}
474

    
475
/*****************************/
476
$reboot_doc = gettext("Basic XMLRPC wrapper for rc.reboot.");
477
$reboot_sig = array(array($XML_RPC_Boolean, $XML_RPC_String));
478
function reboot_xmlrpc($raw_params) {
479
	global $xmlrpc_g;
480

    
481
	$params = xmlrpc_params_to_php($raw_params);
482
	if(!xmlrpc_auth($params)) {
483
		xmlrpc_authfail();
484
		return $xmlrpc_g['return']['authfail'];
485
	}
486
	mwexec_bg("/etc/rc.reboot");
487

    
488
	return $xmlrpc_g['return']['true'];
489
}
490

    
491
/*****************************/
492
$get_notices_sig = array(
493
	array(
494
		$XML_RPC_Array,
495
		$XML_RPC_String
496
	),
497
	array(
498
		$XML_RPC_Array
499
	)
500
);
501

    
502
function get_notices_xmlrpc($raw_params) {
503
	global $g, $xmlrpc_g;
504

    
505
	$params = xmlrpc_params_to_php($raw_params);
506
	if(!xmlrpc_auth($params)) {
507
		xmlrpc_authfail();
508
		return $xmlrpc_g['return']['authfail'];
509
	}
510
	if(!function_exists("get_notices"))
511
		require("notices.inc");
512
	if(!$params) {
513
		$toreturn = get_notices();
514
	} else {
515
		$toreturn = get_notices($params);
516
	}
517
	$response = new XML_RPC_Response(XML_RPC_encode($toreturn));
518

    
519
	return $response;
520
}
521

    
522
$xmlrpclockkey = lock('xmlrpc', LOCK_EX);
523

    
524
/*****************************/
525
$server = new XML_RPC_Server(
526
        array(
527
		'pfsense.exec_shell' => array('function' => 'exec_shell_xmlrpc',
528
			'signature' => $exec_shell_sig,
529
			'docstring' => $exec_shell_doc),
530
		'pfsense.exec_php' => array('function' => 'exec_php_xmlrpc',
531
			'signature' => $exec_php_sig,
532
			'docstring' => $exec_php_doc),	
533
		'pfsense.filter_configure' => array('function' => 'filter_configure_xmlrpc',
534
			'signature' => $filter_configure_sig,
535
			'docstring' => $filter_configure_doc),
536
		'pfsense.interfaces_carp_configure' => array('function' => 'interfaces_carp_configure_xmlrpc',
537
			'docstring' => $carp_configure_sig),
538
		'pfsense.backup_config_section' => array('function' => 'backup_config_section_xmlrpc',
539
			'signature' => $backup_config_section_sig,
540
			'docstring' => $backup_config_section_doc),
541
		'pfsense.restore_config_section' => array('function' => 'restore_config_section_xmlrpc',
542
			'signature' => $restore_config_section_sig,
543
			'docstring' => $restore_config_section_doc),
544
		'pfsense.merge_config_section' => array('function' => 'merge_config_section_xmlrpc',
545
			'signature' => $merge_config_section_sig,
546
			'docstring' => $merge_config_section_doc),
547
		'pfsense.merge_installedpackages_section_xmlrpc' => array('function' => 'merge_installedpackages_section_xmlrpc',
548
			'signature' => $merge_config_section_sig,
549
			'docstring' => $merge_config_section_doc),							
550
		'pfsense.check_firmware_version' => array('function' => 'check_firmware_version_xmlrpc',
551
			'signature' => $check_firmware_version_sig,
552
			'docstring' => $check_firmware_version_doc),
553
		'pfsense.host_firmware_version' => array('function' => 'pfsense_firmware_version_xmlrpc',
554
			'signature' => $pfsense_firmware_version_sig,
555
			'docstring' => $host_firmware_version_doc),
556
		'pfsense.reboot' => array('function' => 'reboot_xmlrpc',
557
			'signature' => $reboot_sig,
558
			'docstring' => $reboot_doc),
559
		'pfsense.get_notices' => array('function' => 'get_notices_xmlrpc',
560
			'signature' => $get_notices_sig)
561
        )
562
);
563

    
564
unlock($xmlrpclockkey);
565

    
566
    function array_overlay($a1,$a2)
567
    {
568
        foreach($a1 as $k => $v) {
569
            if(!array_key_exists($k,$a2)) continue;
570
            if(is_array($v) && is_array($a2[$k])){
571
                $a1[$k] = array_overlay($v,$a2[$k]);
572
            }else{
573
                $a1[$k] = $a2[$k];
574
            }
575
        }
576
        return $a1;
577
    }
578

    
579
?>
(256-256/256)