1 /*
2     MiddleMan filtering proxy server
3     Copyright (C) 2002  Jason McLaughlin
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include "flags.h"
24 #include "proto.h"
25 #include "macros.h"
26 
27 /*
28 load an XML-ish file into a linked list
29 note: this is only a partial xml implementation, just enough to suit the needs of this program
30 */
xml_load(XML_LIST * xml_list,char * filename)31 XML_LIST *xml_load(XML_LIST * xml_list, char *filename)
32 {
33 	int i, line = 0, inside = FALSE, label = FALSE, special = FALSE;
34 	char buf[8192], tag[64], value[8192] = "", *bufpos, *vpos = value;
35 	FILE *fptr;
36 	STACK *stack = NULL;
37 	XML_LIST *new_list = xml_list;
38 
39 	if ((fptr = fopen(filename, "r")) == NULL)
40 		return NULL;
41 
42 	while (fgets(buf, sizeof(buf), fptr) != NULL) {
43 		line++;
44 		bufpos = buf;
45 
46 		while (*bufpos) {
47 			if (!strncmp(bufpos, "<!--", 4))
48 				label++;
49 			else if (!strncmp(bufpos, "-->", 3))
50 				label--;
51 			else if (*bufpos == '<' && (bufpos[1] == '?' || bufpos[1] == '!')) {
52 				label++;
53 				special = TRUE;
54 			} else if (*bufpos == '>' && special == TRUE) {
55 				label--;
56 				special = FALSE;
57 				bufpos++;
58 				continue;
59 			}
60 
61 
62 			if (!label && *bufpos == '<') {
63 
64 				s_strncpy(tag, bufpos, sizeof(tag));
65 				for (i = 0; tag[i] != '>' && tag[i]; i++);
66 
67 				if (i < 2 || !tag[i])
68 					goto error;
69 				else
70 					i++;
71 
72 				tag[i] = '\0';
73 
74 				bufpos += i;
75 
76 				if (tag[1] == '/') {
77 					if (stack == NULL || strcasecmp(&tag[2], &stack->data[1]))
78 						goto error;
79 
80 					if (!strcasecmp(stack->data, "<include>")) {
81 						*vpos = '\0';
82 						if (!strcasecmp(value, filename))
83 							goto error;
84 
85 						new_list = xml_load(new_list, value);
86 
87 						value[0] = '\0';
88 						vpos = value;
89 					}
90 
91 					inside = FALSE;
92 
93 					POP(stack);
94 
95 					if (*value) {
96 						*vpos = '\0';
97 						new_list = xml_list_add(new_list, value, XML_VALUE);
98 						*value = '\0';
99 					}
100 				} else {
101 					PUSH(stack, tag);
102 
103 					vpos = value;
104 					inside = TRUE;
105 				}
106 
107 				if (strcasecmp(tag, "<include>") && strcasecmp(tag, "</include>"))
108 					new_list = xml_list_add(new_list, tag, XML_TAG);
109 			} else {
110 				if (!label && inside) {
111 					if (*bufpos == '&') {
112 						if (!strncasecmp(&bufpos[1], "gt;", 3)) {
113 							bufpos += 3;
114 							*bufpos = '>';
115 						} else if (!strncasecmp(&bufpos[1], "lt;", 3)) {
116 							bufpos += 3;
117 							*bufpos = '<';
118 						} else if (!strncasecmp(&bufpos[1], "amp;", 4)) {
119 							bufpos += 4;
120 							*bufpos = '&';
121 						} else if (!strncasecmp(&bufpos[1], "quot;", 5)) {
122 							bufpos += 5;
123 							*bufpos = '\"';
124 						} else if (!strncasecmp(&bufpos[1], "apos;", 5)) {
125 							bufpos += 5;
126 							*bufpos = '\'';
127 						}
128 					}
129 
130 					if (vpos - value < sizeof(value))
131 						*(vpos++) = *bufpos;
132 
133 				}
134 
135 				bufpos++;
136 			}
137 
138 			if (xml_list == NULL)
139 				xml_list = new_list;
140 		}
141 	}
142 
143 	if (stack != NULL)
144 		goto error;
145 
146 	fclose(fptr);
147 
148 	return xml_list;
149       error:
150 
151 	fclose(fptr);
152 
153 	putlog(MMLOG_ERROR, "Parse error in %s on line %d", filename, line);
154 
155 	while (stack != NULL) {
156 		/* close off all open tags */
157 		s_strncpy(tag, stack->data, sizeof(tag) - 1);
158 		memmove(&tag[2], &tag[1], strlen(&tag[1]) + 1);
159 		tag[1] = '/';
160 		xml_list_add(new_list, tag, XML_TAG);
161 		POP(stack);
162 	}
163 
164 	return xml_list;
165 }
166 
167 /*
168 insert an XML tag or item at the end of a linked list
169 */
xml_list_add(XML_LIST * list,char * item,int type)170 XML_LIST *xml_list_add(XML_LIST * list, char *item, int type)
171 {
172 	if (list == NULL) {
173 		list = xmalloc(sizeof(XML_LIST));
174 		list->prev = NULL;
175 	} else {
176 		while (list->next != NULL)
177 			list = list->next;
178 		list->next = xmalloc(sizeof(XML_LIST));
179 		list->next->prev = list;
180 		list = list->next;
181 	}
182 
183 	list->item = xstrdup(item);
184 	list->type = type;
185 	list->next = NULL;
186 
187 	return list;
188 }
189 
190 /*
191 free memory used by an XML linked list
192 */
xml_list_free(XML_LIST * xml_list)193 void xml_list_free(XML_LIST * xml_list)
194 {
195 	XML_LIST *xml_list_temp;
196 
197 	while (xml_list != NULL) {
198 		xml_list_temp = xml_list->next;
199 		xfree(xml_list->item);
200 		xfree(xml_list);
201 		xml_list = xml_list_temp;
202 	}
203 }
204 
205 /*
206 return pointer where section begins
207 */
xml_section(XML_LIST * xml_list,char * section)208 XML_LIST *xml_section(XML_LIST * xml_list, char *section)
209 {
210 	int i = 0;
211 
212 	while (xml_list != NULL) {
213 		if (xml_list->type == XML_TAG) {
214 			if (i <= 1 && !strcasecmp(xml_list->item, section))
215 				return xml_list;
216 			if (xml_list->item[1] == '/')
217 				i--;
218 			else
219 				i++;
220 		}
221 
222 		xml_list = xml_list->next;
223 	}
224 
225 	return NULL;
226 }
227 
228 /*
229 save formatted xml-ish file from XML_LIST struct
230 */
xml_save(XML_LIST * xml_list,char * filename)231 int xml_save(XML_LIST * xml_list, char *filename)
232 {
233 	FILE *file;
234 	int i, ind = 1;
235 	char buf[8192];
236 
237 	file = fopen(filename, "w");
238 	if (file == NULL)
239 		return FALSE;
240 
241 	fprintf(file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
242 	fprintf(file, "<mman>\n");
243 
244 	for (; xml_list; xml_list = xml_list->next) {
245 		for (i = 0; i < ind; i++)
246 			buf[i] = '\t';
247 
248 
249 		if (ind <= 1 && xml_list->prev != NULL)
250 			fprintf(file, "\n");
251 
252 		if (xml_list->next != NULL && xml_list->next->type == XML_VALUE) {
253 			/* put the value on the same line as the opening and closing tags.. i.e. <foo>bar</foo> */
254 			snprintf(&buf[ind], sizeof(buf) - ind, "%s%s%s", xml_list->item, xml_list->next->item, xml_list->next->next->item);
255 			xml_list = xml_list->next->next;
256 		} else {
257 
258 			if (xml_list->type == XML_TAG) {
259 				if (xml_list->item[1] == '/') {
260 					ind--;
261 					snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
262 				} else {
263 					snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
264 					ind++;
265 				}
266 			} else
267 				snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
268 
269 		}
270 
271 		fprintf(file, "%s\n", buf);
272 	}
273 
274 	fprintf(file, "</mman>\n");
275 
276 	fclose(file);
277 
278 	return TRUE;
279 }
280