Project

General

Profile

Download (10.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	xmlparse.inc
4
	functions to parse/dump configuration files in XML format
5

    
6
	part of pfSense (https://www.pfsense.org)
7
	Copyright (c) 2004-2016 Electric Sheep Fencing, LLC.
8
	All rights reserved.
9

    
10
	originally part of m0n0wall (http://m0n0.ch/wall)
11
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
12
	All rights reserved.
13

    
14
	Redistribution and use in source and binary forms, with or without
15
	modification, are permitted provided that the following conditions are met:
16

    
17
	1. Redistributions of source code must retain the above copyright notice,
18
	   this list of conditions and the following disclaimer.
19

    
20
	2. Redistributions in binary form must reproduce the above copyright
21
	   notice, this list of conditions and the following disclaimer in
22
	   the documentation and/or other materials provided with the
23
	   distribution.
24

    
25
	3. All advertising materials mentioning features or use of this software
26
	   must display the following acknowledgment:
27
	   "This product includes software developed by the pfSense Project
28
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
29

    
30
	4. The names "pfSense" and "pfSense Project" must not be used to
31
	   endorse or promote products derived from this software without
32
	   prior written permission. For written permission, please contact
33
	   coreteam@pfsense.org.
34

    
35
	5. Products derived from this software may not be called "pfSense"
36
	   nor may "pfSense" appear in their names without prior written
37
	   permission of the Electric Sheep Fencing, LLC.
38

    
39
	6. Redistributions of any form whatsoever must retain the following
40
	   acknowledgment:
41

    
42
	"This product includes software developed by the pfSense Project
43
	for use in the pfSense software distribution (http://www.pfsense.org/).
44

    
45
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
46
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
49
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
54
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
56
	OF THE POSSIBILITY OF SUCH DAMAGE.
57
*/
58

    
59
/* The following items will be treated as arrays in config.xml */
60
function listtags() {
61
	/*
62
	 * Please keep this list alpha sorted and no longer than 80 characters
63
	 * I know it's a pain, but it's a pain to find stuff too if it's not
64
	 */
65
	$ret = array(
66
		'acls', 'alias', 'aliasurl', 'allowedip', 'allowedhostname', 'authserver',
67
		'bridged', 'build_port_path',
68
		'ca', 'cacert', 'cert', 'crl', 'clone', 'config', 'container', 'columnitem',
69
		'depends_on_package', 'disk', 'dnsserver', 'dnsupdate', 'domainoverrides', 'dyndns',
70
		'earlyshellcmd', 'element', 'encryption-algorithm-option',
71
		'field', 'fieldname',
72
		'gateway_item', 'gateway_group', 'gif', 'gre', 'group',
73
		'hash-algorithm-option', 'hosts', 'member', 'ifgroupentry', 'igmpentry', 'interface_array', 'item', 'key',
74
		'lagg', 'lbaction', 'lbpool', 'l7rules', 'lbprotocol',
75
		'member', 'menu', 'tab', 'mobilekey', 'monitor_type', 'mount',
76
		'npt', 'ntpserver',
77
		'onetoone', 'openvpn-server', 'openvpn-client', 'openvpn-csc', 'option',
78
		'package', 'passthrumac', 'phase1', 'phase2', 'ppp', 'pppoe', 'priv', 'proxyarpnet', 'pool',
79
		'qinqentry', 'queue',
80
		'pages', 'pipe', 'radnsserver', 'roll', 'route', 'row', 'rrddatafile', 'rule',
81
		'schedule', 'service', 'servernat', 'servers',
82
		'serversdisabled', 'shellcmd', 'staticmap', 'subqueue',
83
		'timerange', 'tunnel', 'user', 'vip', 'virtual_server', 'vlan',
84
		'winsserver', 'wolentry', 'widget'
85
	);
86
	return array_flip($ret);
87
}
88

    
89
/* Package XML tags that should be treated as a list not as a traditional array */
90
function listtags_pkg() {
91
	$ret = array('build_port_path', 'depends_on_package', 'onetoone', 'queue', 'rule', 'servernat', 'alias', 'additional_files_needed', 'tab', 'template', 'menu', 'rowhelperfield', 'service', 'step', 'package', 'columnitem', 'option', 'item', 'field', 'package', 'file');
92

    
93
	return array_flip($ret);
94
}
95

    
96
function startElement($parser, $name, $attrs) {
97
	global $parsedcfg, $depth, $curpath, $havedata, $listtags;
98

    
99
	array_push($curpath, strtolower($name));
100

    
101
	$ptr =& $parsedcfg;
102
	foreach ($curpath as $path) {
103
		$ptr =& $ptr[$path];
104
	}
105

    
106
	/* is it an element that belongs to a list? */
107
	if (isset($listtags[strtolower($name)])) {
108

    
109
		/* is there an array already? */
110
		if (!is_array($ptr)) {
111
			/* make an array */
112
			$ptr = array();
113
		}
114

    
115
		array_push($curpath, count($ptr));
116

    
117
	} else if (isset($ptr)) {
118
		/* multiple entries not allowed for this element, bail out */
119
		die(sprintf(gettext('XML error: %1$s at line %2$d cannot occur more than once') . "\n",
120
		    $name,
121
		    xml_get_current_line_number($parser)));
122
	}
123

    
124
	$depth++;
125
	$havedata = $depth;
126
}
127

    
128
function endElement($parser, $name) {
129
	global $depth, $curpath, $parsedcfg, $havedata, $listtags;
130

    
131
	if ($havedata == $depth) {
132
		$ptr =& $parsedcfg;
133
		foreach ($curpath as $path) {
134
			$ptr =& $ptr[$path];
135
		}
136
		$ptr = "";
137
	}
138

    
139
	array_pop($curpath);
140

    
141
	if (isset($listtags[strtolower($name)])) {
142
		array_pop($curpath);
143
	}
144

    
145
	$depth--;
146
}
147

    
148
function cData($parser, $data) {
149
	global $depth, $curpath, $parsedcfg, $havedata;
150

    
151
	$data = trim($data, "\t\n\r");
152

    
153
	if ($data != "") {
154
		$ptr =& $parsedcfg;
155
		foreach ($curpath as $path) {
156
			$ptr =& $ptr[$path];
157
		}
158

    
159
		if (is_string($ptr)) {
160
			$ptr .= html_entity_decode($data);
161
		} else {
162
			if (trim($data, " ") != "") {
163
				$ptr = html_entity_decode($data);
164
				$havedata++;
165
			}
166
		}
167
	}
168
}
169

    
170
function parse_xml_config($cffile, $rootobj, $isstring = "false") {
171
	global $listtags;
172
	$listtags = listtags();
173
	if (isset($GLOBALS['custom_listtags'])) {
174
		foreach ($GLOBALS['custom_listtags'] as $tag) {
175
			$listtags[$tag] = $tag;
176
		}
177
	}
178
	return parse_xml_config_raw($cffile, $rootobj, $isstring);
179
}
180

    
181
function parse_xml_config_pkg($cffile, $rootobj, $isstring = "false") {
182
	global $listtags;
183
	$listtags = listtags_pkg();
184
	if (isset($GLOBALS['custom_listtags_pkg'])) {
185
		foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
186
			$listtags[$tag] = $tag;
187
		}
188
	}
189
	$cfg =parse_xml_config_raw($cffile, $rootobj, $isstring);
190
	if ($cfg == -1) {
191
		return array();
192
	}
193

    
194
	return $cfg;
195
}
196

    
197
function parse_xml_config_raw($cffile, $rootobj, $isstring = "false") {
198

    
199
	global $depth, $curpath, $parsedcfg, $havedata, $listtags;
200
	$parsedcfg = array();
201
	$curpath = array();
202
	$depth = 0;
203
	$havedata = 0;
204

    
205
	$xml_parser = xml_parser_create();
206

    
207
	xml_set_element_handler($xml_parser, "startElement", "endElement");
208
	xml_set_character_data_handler($xml_parser, "cdata");
209
	xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 1);
210

    
211
	if (!($fp = fopen($cffile, "r"))) {
212
		log_error(gettext("Error: could not open XML input") . "\n");
213
		return -1;
214
	}
215

    
216
	while ($data = fread($fp, 4096)) {
217
		if (!xml_parse($xml_parser, $data, feof($fp))) {
218
			log_error(sprintf(gettext('XML error: %1$s at line %2$d in %3$s') . "\n",
219
				xml_error_string(xml_get_error_code($xml_parser)),
220
				xml_get_current_line_number($xml_parser),
221
				$cffile));
222
			return -1;
223
		}
224
	}
225
	xml_parser_free($xml_parser);
226

    
227
	if ($rootobj) {
228
		if (!is_array($rootobj)) {
229
			$rootobj = array($rootobj);
230
		}
231
		foreach ($rootobj as $rootobj_name) {
232
			if ($parsedcfg[$rootobj_name]) {
233
				break;
234
			}
235
		}
236

    
237
		if (!$parsedcfg[$rootobj_name]) {
238
			log_error(sprintf(gettext("XML error: no %s object found!") . "\n", implode(" or ", $rootobj)));
239
			return -1;
240
		}
241
		return $parsedcfg[$rootobj_name];
242
	} else {
243
		return $parsedcfg;
244
	}
245
}
246

    
247
function dump_xml_config_sub($arr, $indent) {
248

    
249
	global $listtags;
250

    
251
	$xmlconfig = "";
252

    
253
	foreach ($arr as $ent => $val) {
254
		if (is_array($val)) {
255
			/* is it just a list of multiple values? */
256
			if (isset($listtags[strtolower($ent)])) {
257
				foreach ($val as $cval) {
258
					if (is_array($cval)) {
259
						if (empty($cval)) {
260
							$xmlconfig .= str_repeat("\t", $indent);
261
							$xmlconfig .= "<$ent/>\n";
262
						} else {
263
							$xmlconfig .= str_repeat("\t", $indent);
264
							$xmlconfig .= "<$ent>\n";
265
							$xmlconfig .= dump_xml_config_sub($cval, $indent + 1);
266
							$xmlconfig .= str_repeat("\t", $indent);
267
							$xmlconfig .= "</$ent>\n";
268
						}
269
					} else {
270
						if ($cval === false) {
271
							continue;
272
						}
273
						$xmlconfig .= str_repeat("\t", $indent);
274
						if ((is_bool($cval) && $cval == true) || ($cval === "")) {
275
							$xmlconfig .= "<$ent/>\n";
276
						} else if ((substr($ent, 0, 5) == "descr") ||
277
						    (substr($ent, 0, 6) == "detail") ||
278
						    (substr($ent, 0, 12) == "login_banner") ||
279
						    (substr($ent, 0, 9) == "ldap_attr") ||
280
						    (substr($ent, 0, 9) == "ldap_bind") ||
281
						    (substr($ent, 0, 11) == "ldap_basedn") ||
282
						    (substr($ent, 0, 18) == "ldap_authcn") ||
283
						    (substr($ent, 0, 19) == "ldap_extended_query")) {
284
							$xmlconfig .= "<$ent><![CDATA[" . htmlentities($cval) . "]]></$ent>\n";
285
						} else {
286
							$xmlconfig .= "<$ent>" . htmlentities($cval) . "</$ent>\n";
287
						}
288
					}
289
				}
290
			} else if (empty($val)) {
291
				$xmlconfig .= str_repeat("\t", $indent);
292
				$xmlconfig .= "<$ent/>\n";
293
			} else {
294
				/* it's an array */
295
				$xmlconfig .= str_repeat("\t", $indent);
296
				$xmlconfig .= "<$ent>\n";
297
				$xmlconfig .= dump_xml_config_sub($val, $indent + 1);
298
				$xmlconfig .= str_repeat("\t", $indent);
299
				$xmlconfig .= "</$ent>\n";
300
			}
301
		} else {
302
			if ((is_bool($val) && ($val == true)) || ($val === "")) {
303
				$xmlconfig .= str_repeat("\t", $indent);
304
				$xmlconfig .= "<$ent/>\n";
305
			} else if (!is_bool($val)) {
306
				$xmlconfig .= str_repeat("\t", $indent);
307
				if ((substr($ent, 0, 5) == "descr") ||
308
				    (substr($ent, 0, 6) == "detail") ||
309
				    (substr($ent, 0, 12) == "login_banner") ||
310
				    (substr($ent, 0, 9) == "ldap_attr") ||
311
				    (substr($ent, 0, 9) == "ldap_bind") ||
312
				    (substr($ent, 0, 11) == "ldap_basedn") ||
313
				    (substr($ent, 0, 18) == "ldap_authcn") ||
314
				    (substr($ent, 0, 19) == "ldap_extended_query")) {
315
					$xmlconfig .= "<$ent><![CDATA[" . htmlentities($val) . "]]></$ent>\n";
316
				} else {
317
					$xmlconfig .= "<$ent>" . htmlentities($val) . "</$ent>\n";
318
				}
319
			}
320
		}
321
	}
322

    
323
	return $xmlconfig;
324
}
325

    
326
function dump_xml_config($arr, $rootobj) {
327
	global $listtags;
328
	$listtags = listtags();
329
	if (isset($GLOBALS['custom_listtags'])) {
330
		foreach ($GLOBALS['custom_listtags'] as $tag) {
331
			$listtags[$tag] = $tag;
332
		}
333
	}
334
	return dump_xml_config_raw($arr, $rootobj);
335
}
336

    
337
function dump_xml_config_pkg($arr, $rootobj) {
338
	global $listtags;
339
	$listtags = listtags_pkg();
340
	if (isset($GLOBALS['custom_listtags_pkg'])) {
341
		foreach ($GLOBALS['custom_listtags_pkg'] as $tag) {
342
			$listtags[$tag] = $tag;
343
		}
344
	}
345
	return dump_xml_config_raw($arr, $rootobj);
346
}
347

    
348
function dump_xml_config_raw($arr, $rootobj) {
349

    
350
	$xmlconfig = "<?xml version=\"1.0\"?" . ">\n";
351
	$xmlconfig .= "<$rootobj>\n";
352

    
353
	$xmlconfig .= dump_xml_config_sub($arr, 1);
354

    
355
	$xmlconfig .= "</$rootobj>\n";
356

    
357
	return $xmlconfig;
358
}
359

    
360
?>
(60-60/65)