1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License as published by
3  * the Free Software Foundation; version 2 of the License. For a copy,
4  * see http://www.gnu.org/licenses/gpl-2.0.html.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  */
11 
12 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include "global.h"
18 #include "libstr.h"
19 #include "liblist.h"
20 #include "memdbg.h"
21 
22 /*---< headerlist >-----------------------------------------------------------*/
23 
24 /* Parse the HTTP http_headers from the received request.
25  */
parse_http_headers(char * line)26 t_http_header *parse_http_headers(char *line) {
27 	t_http_header *first, *http_header;
28 	char *value;
29 
30 	if (empty_string(line)) {
31 		return NULL;
32 	} else if (*line == '\0') {
33 		return NULL;
34 	}
35 
36 	if ((first = http_header = (t_http_header*)malloc(sizeof(t_http_header))) == NULL) {
37 		return NULL;
38 	}
39 	http_header->data = line;
40 	http_header->length = 0;
41 	http_header->next = NULL;
42 	while (*line != '\0') {
43 		if (*line == '\r') {
44 			*line = '\0';
45 			http_header->length = strlen(http_header->data);
46 			if (*(line + 1) == '\n') {
47 				if ((*(line + 2) != '\r') && (*(line + 2) != '\0')) {
48 					if ((http_header->next = (t_http_header*)malloc(sizeof(t_http_header))) == NULL) {
49 						return first;
50 					}
51 					http_header = http_header->next;
52 					http_header->next = NULL;
53 					http_header->data = line + 2;
54 					http_header->length = 0;
55 				} else {
56 					break;
57 				}
58 			} else {
59 				http_header->data = line + 1;
60 			}
61 		}
62 		line++;
63 	}
64 
65 	if (first->length == 0) {
66 		free(first);
67 		return NULL;
68 	}
69 
70 	if (http_header->length == 0) {
71 		http_header->length = strlen(http_header->data);
72 	}
73 
74 	http_header = first;
75 	while (http_header != NULL) {
76 		if ((value = strchr(http_header->data, ':')) != NULL) {
77 			do {
78 				value++;
79 			} while (*value == ' ');
80 			http_header->value_offset = (value - http_header->data);
81 		} else {
82 			http_header->value_offset = 0;
83 		}
84 		http_header = http_header->next;
85 	}
86 
87 	return first;
88 }
89 
90 /* Search for a http_header and return its value.
91  */
get_http_header(char * key,t_http_header * http_headers)92 char *get_http_header(char *key, t_http_header *http_headers) {
93 	int len;
94 
95 	if ((key == NULL) || (http_headers == NULL)) {
96 		return NULL;
97 	}
98 
99 	len = strlen(key);
100 	while (http_headers != NULL) {
101 		if (strncasecmp(http_headers->data, key, len) == 0) {
102 			return http_headers->data + http_headers->value_offset;
103 		}
104 		http_headers = http_headers->next;
105 	}
106 
107 	return NULL;
108 }
109 
110 /* Return the HTTP Origin or Referer header
111  */
get_referer_header(t_http_header * http_headers)112 char *get_referer_header(t_http_header *http_headers) {
113 	char *referer;
114 
115 	if ((referer = get_http_header("Origin:", http_headers)) == NULL) {
116 		referer = get_http_header("Referer:", http_headers);
117 	}
118 
119 	return referer;
120 }
121 
122 /* free() a list of http_headers.
123  */
remove_http_headers(t_http_header * http_headers)124 t_http_header *remove_http_headers(t_http_header *http_headers) {
125 	t_http_header *remove;
126 
127 	while (http_headers != NULL) {
128 		remove = http_headers;
129 		http_headers = http_headers->next;
130 
131 		free(remove);
132 	}
133 
134 	return NULL;
135 }
136 
137 /*---< charlist >-------------------------------------------------------------*/
138 
init_charlist(t_charlist * list)139 void init_charlist(t_charlist *list) {
140 	if (list != NULL) {
141 		list->size = 0;
142 		list->item = NULL;
143 	}
144 }
145 
parse_charlist(char * value,t_charlist * list)146 int parse_charlist(char *value, t_charlist *list) {
147 	char *scan, **new;
148 	int add = 1, i;
149 
150 	if (list == NULL) {
151 		return -1;
152 	} else if (empty_string(value)) {
153 		return -1;
154 	}
155 
156 	scan = value;
157 	while (*scan != '\0') {
158 		if (*scan == ',') {
159 			*scan = '\0';
160 			add++;
161 		}
162 		scan++;
163 	}
164 
165 	if ((new = (char**)realloc(list->item, (list->size + add) * sizeof(char*))) == NULL) {
166 		return -1;
167 	}
168 	list->item = new;
169 
170 	for (i = 0; i < add; i++) {
171 		*(list->item + list->size + i) = NULL;
172 	}
173 
174 	for (i = 0; i < add; i++) {
175 		if ((*(list->item + list->size + i) = strdup(remove_spaces(value))) == NULL) {
176 			remove_charlist(list);
177 			init_charlist(list);
178 			return -1;
179 		}
180 		value = value + strlen(value) + 1;
181 	}
182 
183 	list->size += add;
184 
185 	return 0;
186 }
187 
copy_charlist(t_charlist * dest,t_charlist * src)188 void copy_charlist(t_charlist *dest, t_charlist *src) {
189 	if ((dest != NULL) && (src != NULL)) {
190 		dest->size = src->size;
191 		dest->item = src->item;
192 	}
193 }
194 
in_charlist(char * item,t_charlist * list)195 bool in_charlist(char *item, t_charlist *list) {
196 	int i;
197 
198 	if ((item == NULL) || (list == NULL)) {
199 		return false;
200 	}
201 
202 	i = list->size;
203 	while (i-- > 0) {
204 		if (strcmp(*(list->item + i), item) == 0) {
205 			return true;
206 		}
207 	}
208 
209 	return false;
210 }
211 
matches_charlist(char * item,t_charlist * list)212 bool matches_charlist(char *item, t_charlist *list) {
213 	int i;
214 	size_t n;
215 
216 	if ((item == NULL) || (list == NULL)) {
217 		return false;
218 	}
219 
220 	n = strlen(item);
221 
222 	i = list->size;
223 	while (i-- > 0) {
224 		if (strncmp(*(list->item + i), item, n) == 0) {
225 			return true;
226 		}
227 	}
228 
229 	return false;
230 }
231 
remove_charlist(t_charlist * list)232 void remove_charlist(t_charlist *list) {
233 	if (list != NULL) {
234 		if (list->size > 0) {
235 			do {
236 				list->size--;
237 				check_free(*(list->item + list->size));
238 			} while (list->size > 0);
239 			check_free(list->item);
240 			list->item = NULL;
241 		}
242 	}
243 }
244 
245 /*---< accesslist >-----------------------------------------------------------*/
246 
247 /* Parse a list of access levels.
248  */
parse_accesslist(char * line,bool pwd_allowed,t_accesslist * list)249 t_accesslist *parse_accesslist(char *line, bool pwd_allowed, t_accesslist *list) {
250 	t_accesslist *new = NULL;
251 	char *rule, *ip, *mask;
252 	bool error = false;
253 
254 	if (empty_string(line)) {
255 		return remove_accesslist(list);
256 	}
257 
258 	if (list != NULL) {
259 		new = list;
260 		while (new->next != NULL) {
261 			new = new->next;
262 		}
263 	}
264 
265 	while (line != NULL) {
266 		split_string(line, &ip, &line, ',');
267 		if (split_string(ip, &rule, &ip, ' ') == 0) {
268 			if (list == NULL) {
269 				if ((list = new = (t_accesslist*)malloc(sizeof(t_accesslist))) == NULL) {
270 					break;
271 				}
272 			} else {
273 				if ((new->next = (t_accesslist*)malloc(sizeof(t_accesslist))) == NULL)  {
274 					error = true;
275 					break;
276 				}
277 				new = new->next;
278 			}
279 			new->next = NULL;
280 
281 			if (strcasecmp(rule, "allow") == 0) {
282 				new->access = allow;
283 			} else if (strcasecmp(rule, "deny") == 0) {
284 				new->access = deny;
285 			} else if (pwd_allowed && (strcasecmp(rule, "pwd") == 0)) {
286 				new->access = pwd;
287 			} else {
288 				error = true;
289 				break;
290 			}
291 			if (strcasecmp(ip, "all") == 0) {
292 				default_ipv4(&(new->ip));
293 				new->netmask = 0;
294 				new->all_ip = true;
295 			} else {
296 				new->all_ip = false;
297 				if (split_string(ip, &ip, &mask, '/') == 0) {
298 					if ((new->netmask = str_to_int(mask)) == -1) {
299 						error = true;
300 						break;
301 					}
302 				} else {
303 					new->netmask = -1;
304 				}
305 				if (parse_ip(ip, &(new->ip)) == -1) {
306 					error = true;
307 					break;
308 				}
309 
310 				if (new->netmask == -1) {
311 					/* Set netmask
312 					 */
313 					if (new->ip.family == AF_INET) {
314 						new->netmask = 8 * IPv4_LEN;
315 					} else if (new->ip.family == AF_INET6) {
316 						new->netmask = 8 * IPv6_LEN;
317 					} else {
318 						error = true;
319 						break;
320 					}
321 				} else {
322 					/* Check netmask
323 					 */
324 					if (new->ip.family == AF_INET) {
325 						if ((unsigned int)new->netmask > 8 * IPv4_LEN) {
326 							error = true;
327 							break;
328 						}
329 					} else if (new->ip.family == AF_INET6) {
330 						if ((unsigned int)new->netmask > 8 * IPv6_LEN) {
331 							error = true;
332 							break;
333 						}
334 					} else {
335 						error = true;
336 						break;
337 					}
338 				}
339 
340 				/* Apply subnetmask
341 				 */
342 				if (apply_netmask(&(new->ip), new->netmask) == -1) {
343 					error = true;
344 					break;
345 				}
346 			}
347 		} else {
348 			error = true;
349 			break;
350 		}
351 	}
352 
353 	if (error) {
354 		list = remove_accesslist(list);
355 	}
356 
357 	return list;
358 }
359 
360 /* Remove an accesslist.
361  */
remove_accesslist(t_accesslist * list)362 t_accesslist *remove_accesslist(t_accesslist *list) {
363 	t_accesslist *item;
364 
365 	while (list != NULL) {
366 		item = list;
367 		list = list->next;
368 
369 		free(item);
370 	}
371 
372 	return NULL;
373 }
374 
375 /* Return the access status of an IP address.
376  */
ip_allowed(t_ip_addr * ip,t_accesslist * list)377 t_access ip_allowed(t_ip_addr *ip, t_accesslist *list) {
378 	while (list != NULL) {
379 		if (list->all_ip) {
380 			return list->access;
381 		} else if (ip_in_subnet(ip, &(list->ip), list->netmask)) {
382 			return list->access;
383 		}
384 		list = list->next;
385 	}
386 
387 	return unspecified;
388 }
389 
390 /*---< key/value >-----------------------------------------------------------*/
391 
392 /* Parse a key/value combination.
393  */
parse_keyvalue(char * line,t_keyvalue ** kvlist,char * delimiter)394 int parse_keyvalue(char *line, t_keyvalue **kvlist, char *delimiter) {
395 	char *value;
396 	t_keyvalue *prev;
397 
398 	if ((kvlist == NULL) || (delimiter == NULL)) {
399 		return -1;
400 	} else if (empty_string(line)) {
401 		return -1;
402 	}
403 
404 	if ((value = strstr(line, delimiter)) == NULL) {
405 		return -1;
406 	}
407 
408 	*value = '\0';
409 	value += strlen(delimiter);
410 
411 	prev = *kvlist;
412 	if ((*kvlist = (t_keyvalue*)malloc(sizeof(t_keyvalue))) == NULL) {
413 		return -1;
414 	}
415 	(*kvlist)->next = prev;
416 
417 	(*kvlist)->value = NULL;
418 	if (((*kvlist)->key = strdup(remove_spaces(line))) == NULL) {
419 		free(*kvlist);
420 		return -1;
421 	}
422 	(*kvlist)->key_len = strlen((*kvlist)->key);
423 
424 	if (((*kvlist)->value = strdup(remove_spaces(value))) == NULL) {
425 		free((*kvlist)->key);
426 		free(*kvlist);
427 		return -1;
428 	}
429 	(*kvlist)->value_len = strlen((*kvlist)->value);
430 
431 	return 0;
432 }
433 
remove_keyvaluelist(t_keyvalue * list)434 t_keyvalue *remove_keyvaluelist(t_keyvalue *list) {
435 	t_keyvalue *remove;
436 
437 	while (list != NULL) {
438 		remove = list;
439 		list = list->next;
440 
441 		check_free(remove->key);
442 		check_free(remove->value);
443 		free(remove);
444 	}
445 
446 	return NULL;
447 }
448 
449 /*---< error handlers >------------------------------------------------------*/
450 
parse_error_handler(char * line,t_error_handler ** handlers)451 int parse_error_handler(char *line, t_error_handler **handlers) {
452 	t_error_handler *handler;
453 	char *param;
454 	int code;
455 
456 	if (empty_string(line)) {
457 		return -1;
458 	} else if ((handler = (t_error_handler*)malloc(sizeof(t_error_handler))) == NULL) {
459 		return -1;
460 	}
461 
462 	if (split_string(line, &param, &line, ':') != 0) {
463 		free(handler);
464 		return -1;
465 	}
466 
467 	switch (code = str_to_int(param)) {
468 		case 401:
469 		case 403:
470 		case 404:
471 		case 501:
472 		case 503:
473 			handler->code = code;
474 			break;
475 		default:
476 			free(handler);
477 			return -1;
478 	}
479 
480 	if ((strlen(line) > 128) || (*line != '/')) {
481 		free(handler);
482 		return -1;
483 	} else if ((handler->handler = strdup(line)) == NULL) {
484 		free(handler);
485 		return -1;
486 	}
487 
488 	if ((param = strchr(handler->handler, '?')) != NULL) {
489 		*param = '\0';
490 		handler->parameters = param + 1;
491 	} else {
492 		handler->parameters = NULL;
493 	}
494 
495 	handler->next = *handlers;
496 	*handlers = handler;
497 
498 	return 0;
499 }
500 
remove_error_handler(t_error_handler * handler)501 void remove_error_handler(t_error_handler *handler) {
502 	if (handler != NULL) {
503 		free(handler->handler);
504 		free(handler);
505 	}
506 }
507 
508 /*---< temporary data >------------------------------------------------------*/
509 
register_tempdata(t_tempdata ** tempdata,void * data,t_tempdata_type type)510 int register_tempdata(t_tempdata **tempdata, void *data, t_tempdata_type type) {
511 	t_tempdata *tdata;
512 
513 	if (tempdata == NULL) {
514 		return 0;
515 	} else if (data == NULL) {
516 		return -1;
517 	} else if ((tdata = (t_tempdata*)malloc(sizeof(t_tempdata))) == NULL) {
518 		return -1;
519 	}
520 
521 	tdata->content = data;
522 	tdata->type = type;
523 	tdata->next = *tempdata;
524 	*tempdata = tdata;
525 
526 	return 0;
527 }
528 
remove_tempdata(t_tempdata * tempdata)529 void remove_tempdata(t_tempdata *tempdata) {
530 	t_tempdata *tdata;
531 
532 	while (tempdata != NULL) {
533 		tdata = tempdata;
534 		tempdata = tempdata->next;
535 
536 		switch (tdata->type) {
537 			case tc_data:
538 				check_free(tdata->content);
539 				break;
540 			case tc_accesslist:
541 				remove_accesslist((t_accesslist*)tdata->content);
542 				break;
543 			case tc_keyvalue:
544 				free(((t_keyvalue*)(tdata->content))->key);
545 				free(((t_keyvalue*)(tdata->content))->value);
546 				free(tdata->content);
547 				break;
548 			case tc_charlist:
549 				remove_charlist((t_charlist*)tdata->content);
550 				break;
551 			case tc_errorhandler:
552 				remove_error_handler((t_error_handler*)tdata->content);
553 				break;
554 		}
555 
556 		free(tdata);
557 	}
558 }
559