1 /*
2  * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3  * Version 2, December 2004
4  *
5  * Copyright (C) 2012-2013 Sebastien Tricaud <sebastien@honeynet.org>
6  *
7  * Everyone is permitted to copy and distribute verbatim or modified
8  * copies of this license document, and changing it is allowed as long
9  * as the name is changed.
10  *
11  * DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
12  * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13  *
14  *  0. You just DO WHAT THE FUCK YOU WANT TO.
15  */
16 
17 #ifdef LINUX
18 #define _GNU_SOURCE
19 #endif
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <stdint.h>
26 
27 #include <faup/faup.h>
28 #include <faup/datadir.h>
29 #include <faup/modules.h>
30 #include <faup/output.h>
31 
faup_modules_new(faup_handler_t * fh)32 int faup_modules_new(faup_handler_t *fh)
33 {
34 	int count;
35 
36 	if (!fh->options) {
37 		fprintf(stderr, "Options have not been initialized! Make sure they are set before calling %s\n", __FUNCTION__);
38 		return -1;
39 	}
40 
41 	switch(fh->options->exec_modules) {
42 		case FAUP_MODULES_NOEXEC:
43 			fh->modules = NULL;
44 		break;
45 		case FAUP_MODULES_EXECPATH:
46 			fh->modules = faup_modules_load_from_datadir();
47 		break;
48 		case FAUP_MODULES_EXECARG:
49 			fh->modules = faup_modules_load_from_arg(fh->options->modules_argv, fh->options->modules_argc);
50 		break;
51 		default:
52 			fprintf(stderr, "*** Huh? We should never be there (%s)!\n", __FUNCTION__);
53 	}
54 
55 	return 0;
56 }
57 
faup_modules_terminate(faup_modules_t * modules)58 void faup_modules_terminate(faup_modules_t *modules)
59 {
60 	if (!modules) {
61 		return;
62 	}
63 
64 	int	count = 0;
65 	while (count < modules->nb_modules) {
66 		if (modules->module[count].lua_state) {
67 			lua_close(modules->module[count].lua_state);
68 		}
69 		if (modules->module[count].module_path) {
70 		  free(modules->module[count].module_path);
71 		}
72 		free(modules->module[count].module_name);
73 		count++;
74 	}
75 
76        	free(modules->module);
77 	free(modules);
78 }
79 
faup_modules_load_from_datadir(void)80 faup_modules_t *faup_modules_load_from_datadir(void)
81 {
82 	faup_modules_t *modules = NULL;
83 	int count = 0;
84 
85 	modules = malloc(sizeof(faup_modules_t));
86 	if (!modules) {
87 		fprintf(stderr, "Cannot allocate modules!\n");
88 		return NULL;
89 	}
90 	modules->nb_modules = faup_modules_foreach_filelist(NULL, NULL, NULL, NULL);
91 	if (modules->nb_modules <= 0) {
92 		// We have no modules enabled
93 		free(modules);
94 		return NULL;
95 	}
96 	modules->module = malloc(sizeof(faup_module_t) * modules->nb_modules);
97 	if (!modules->module) {
98 		fprintf(stderr, "Cannot allocate modules->module!\n");
99 		free(modules);
100 		return NULL;
101 	}
102 	faup_modules_foreach_filelist(modules, NULL, faup_module_register, (void *)(intptr_t)count);
103 
104 	return modules;
105 }
106 
faup_modules_load_from_arg(char ** argv,int argc)107 faup_modules_t *faup_modules_load_from_arg(char **argv, int argc)
108 {
109 	faup_modules_t *modules = NULL;
110 	FILE *fp;
111 	int count;
112 	int modules_that_do_not_count = 0;
113 	int retval;
114 
115 
116 	bool a_module_was_registered;
117 
118 	modules = malloc(sizeof(faup_modules_t));
119 	if (!modules) {
120 		fprintf(stderr, "Cannot allocate modules in %s\n", __FUNCTION__);
121 		return NULL;
122 	}
123 	modules->module = malloc(sizeof(faup_module_t) * argc);
124 	modules->nb_modules = 0;
125 	if (!modules->module) {
126 		fprintf(stderr, "Cannot allocate modules->module in %s\n", __FUNCTION__);
127 		free(modules);
128 		return NULL;
129 	}
130 	for (count = 0; count < argc; count++) {
131 		a_module_was_registered = false;
132 		// We try first to open a local file
133 		fp = fopen(argv[count], "r");
134 		if (fp) { // Found
135 			fclose(fp);
136 
137 			retval = faup_module_register(modules, NULL, argv[count], NULL, count - modules_that_do_not_count);
138 			if (retval == 0) {
139 				modules->nb_modules++;
140 				a_module_was_registered = true;
141 			}
142 		} else {
143 			// The module was not discovered localy, so we get it from "modules_available"
144 			char *load_path = NULL;
145 			char *available_module = NULL;
146 			char *module_to_load = argv[count];
147 
148 			load_path = malloc(17 /* modules_available */ + 1 /* FAUP_OS_DIRSEP */ + strlen(module_to_load));
149 			if (!load_path) {
150 			  fprintf(stderr, "Cannot Allocate Modules Loading Path!");
151 			  return NULL;
152 			}
153 			/* retval = asprintf(&load_path, "modules_available%s%s", FAUP_OS_DIRSEP, argv[count]); */
154 			retval = asprintf(&load_path, "modules_available");
155 			available_module = faup_datadir_get_file(load_path, false);
156 			free(load_path);
157 
158 			fp = fopen(available_module, "r");
159 			if (fp) {
160 				retval = faup_module_register(modules, NULL, available_module, NULL, count - modules_that_do_not_count);
161 				if (retval == 0) {
162 					modules->nb_modules++;
163 					a_module_was_registered = true;
164 
165 				}
166 				fclose(fp);
167 			} else {
168 				fprintf(stderr, "Cannot register the module '%s': Not found in modules_available nor local path!\n", argv[count]);
169 			}
170 
171 		}
172 
173 		if (!a_module_was_registered) {
174 			modules_that_do_not_count++;
175 		}
176 
177 	}
178 
179 	return modules;
180 }
181 
182 
faup_module_register(faup_modules_t * modules,char * modules_dir,char * module,void * user_data,int count)183 int faup_module_register(faup_modules_t *modules, char *modules_dir, char *module, void *user_data, int count)
184 {
185 	int retval;
186 
187 //	printf("Register module with module %s and count %d\n", module, count);
188 
189 	if (modules_dir) {
190 		retval = asprintf(&modules->module[count].module_path, "%s%s%s", modules_dir, FAUP_OS_DIRSEP, module);
191 		if (retval < 0) {
192 			fprintf(stderr, "Cannot allocate in %s with parameter '%s%s%s'\n", __FUNCTION__, modules_dir, FAUP_OS_DIRSEP, module);
193 			return -1;
194 		}
195 	} else {
196 		modules->module[count].module_path = strdup(module);
197 	}
198 
199 	modules->module[count].module_name = strdup(module);
200 
201 //#ifdef FAUP_DEBUG
202 //	printf("Loading module from path:%s\n", modules->module[count].module_path);
203 //#endif
204 
205 	modules->module[count].lua_state = luaL_newstate();
206 	luaL_openlibs(modules->module[count].lua_state);
207 
208 	retval = luaL_loadfile(modules->module[count].lua_state, modules->module[count].module_path);
209 	if (retval) goto err;
210 
211 	// Lua library requires that we load the file first
212 	retval = lua_pcall(modules->module[count].lua_state, 0, 0, 0);
213 	if (retval) goto err;
214 
215 	return 0;
216 
217 err:
218 	fprintf(stderr, "*** Error(%s): %s\n", __FUNCTION__, lua_tostring(modules->module[count].lua_state, -1));
219 	free(modules->module[count].module_path);
220 	return -1;
221 }
222 
223 
faup_modules_foreach_filelist(faup_modules_t * modules,char * force_path,int (* cb_modules_foreach)(faup_modules_t * modules,char * modules_dir,char * module,void * user_data,int count),void * user_data)224 int faup_modules_foreach_filelist(faup_modules_t *modules, char *force_path, int (*cb_modules_foreach)(faup_modules_t *modules, char *modules_dir, char *module, void *user_data, int count), void *user_data)
225 {
226 	char *modules_dir;
227 	DIR  *modules_dir_fp;
228 	struct dirent *modules_dir_file;
229 	int count = 0;
230 
231 	if (!force_path) {
232 		modules_dir = faup_datadir_get_file("modules_enabled", false);
233 	} else {
234 		modules_dir = force_path;
235 	}
236 	modules_dir_fp = opendir(modules_dir);
237 	if (!modules_dir_fp) {
238 		free(modules_dir);
239 		return -1;
240 	}
241 
242 	modules_dir_file = readdir(modules_dir_fp);
243 	while (modules_dir_file) {
244 		if (modules_dir_file->d_name[0] != '.') {
245 			size_t filelen = strlen(modules_dir_file->d_name);
246 			if (filelen > FAUP_MODULE_NAME_MAXLEN) {
247 				fprintf(stderr, "*** Error(%s): Module file name too long (>128). Won't execute!\n", __FUNCTION__);
248 				count++;
249 				continue;
250 			}
251 
252 			if (cb_modules_foreach) cb_modules_foreach(modules, modules_dir, modules_dir_file->d_name, user_data, count);
253 			count++;
254 		}
255 		modules_dir_file = readdir(modules_dir_fp);
256 	}
257 	closedir(modules_dir_fp);
258 
259 	if (!force_path) {
260 		free(modules_dir);
261 	}
262 
263 	return count;
264 }
265 
266 
faup_modules_list(faup_modules_t * modules,char * modules_dir,char * module,void * user_data,int count)267 void faup_modules_list(faup_modules_t *modules, char *modules_dir, char *module, void *user_data, int count)
268 {
269 	printf("%s\n", module);
270 }
271 
faup_modules_decode_url_start(faup_handler_t const * fh,const char * url,size_t url_len)272 faup_modules_transformed_url_t *faup_modules_decode_url_start(faup_handler_t const* fh, const char *url, size_t url_len)
273 {
274 	faup_modules_t *modules = (faup_modules_t *)fh->modules;
275 	faup_modules_transformed_url_t *transformed_url = NULL;
276 	const char *new_url = NULL;
277 	int count;
278 	int retval;
279 
280 	// No modules have been loaded, no need to go further!
281 	if (!modules) {
282 		return NULL;
283 	}
284 
285 	transformed_url = malloc(sizeof(faup_modules_transformed_url_t));
286 	if (!transformed_url) {
287 		fprintf(stderr, "(%s) Cannot allocate URL for transformed url by modules!\n", __FUNCTION__);
288 		return NULL;
289 	}
290 
291 	// For every loaded module, we run the function 'faup_url_in'
292 	for (count=0; count < modules->nb_modules; count++) {
293 			lua_getglobal(modules->module[count].lua_state, "faup_url_in");
294 			if (!new_url) {
295 				lua_pushstring(modules->module[count].lua_state, url);
296 			} else {
297 				lua_pushstring(modules->module[count].lua_state, new_url);
298 			}
299 			retval = lua_pcall(modules->module[count].lua_state, 1, 1, 0);
300 			if (retval) {
301 				// This module has no faup_url_in function. Nothing wrong here, we can continue
302 				continue;
303 				//fprintf(stderr, "*** Error(%s): %s\n", __FUNCTION__, lua_tostring(modules->module[count].lua_state, -1));
304 				//return NULL;
305 			}
306 
307 			new_url = lua_tostring(modules->module[count].lua_state, -1);
308 	}
309 
310 	if (new_url) {
311 		//printf("new url=%s, size=%zd\n", new_url, strlen(new_url));
312 		transformed_url->url = new_url;
313 		transformed_url->url_len = strlen(new_url);
314 	} else {
315 		transformed_url->url = url;
316 		transformed_url->url_len = url_len;
317 	}
318 
319 	return transformed_url;
320 }
321 
faup_modules_transformed_url_free(faup_modules_transformed_url_t * transformed_url)322 void faup_modules_transformed_url_free(faup_modules_transformed_url_t *transformed_url)
323 {
324 	//free((void *)transformed_url->url);
325 	free(transformed_url);
326 }
327 
_faup_add_keyval_dict(faup_modules_t * modules,int count,char * key,int val)328 void _faup_add_keyval_dict(faup_modules_t *modules, int count, char *key, int val)
329 {
330 	lua_pushstring(modules->module[count].lua_state, key); // -2
331 	lua_pushinteger(modules->module[count].lua_state, val); // -3
332 	lua_settable(modules->module[count].lua_state, -3);
333 
334 }
335 
_faup_add_keyvalstr_dict(faup_modules_t * modules,int count,char * key,char * val)336 void _faup_add_keyvalstr_dict(faup_modules_t *modules, int count, char *key, char *val)
337 {
338 	lua_pushstring(modules->module[count].lua_state, key); // -2
339 	lua_pushstring(modules->module[count].lua_state, val); // -2
340 	lua_settable(modules->module[count].lua_state, -3);
341 
342 }
343 
344 
_faup_add_feature(faup_modules_t * modules,int count,faup_feature_t feature,char * pos_key,char * size_key)345 void _faup_add_feature(faup_modules_t *modules, int count, faup_feature_t feature, char *pos_key, char *size_key)
346 {
347 		if (faup_features_exist(feature)) {
348 			_faup_add_keyval_dict(modules, count, pos_key, feature.pos);
349 			_faup_add_keyval_dict(modules, count, size_key, feature.size);
350 		} else {
351 			_faup_add_keyval_dict(modules, count, pos_key, -1);
352 			_faup_add_keyval_dict(modules, count, size_key, 0);
353 		}
354 }
355 
faup_modules_url_output(faup_handler_t * fh,FILE * out)356 bool faup_modules_url_output(faup_handler_t *fh, FILE* out)
357 {
358 	int retval;
359 	int count;
360 	faup_modules_t *modules = fh->modules;
361 	const char *transformed_url = NULL;
362 
363 	bool module_executed = false;
364 
365 	if (!modules) {
366 		return false;
367 	}
368 
369 	for (count = 0; count < modules->nb_modules; count++) {
370 		lua_getglobal(modules->module[count].lua_state, "faup_output");
371 		if(!lua_isfunction(modules->module[count].lua_state, -1)) {
372 			//printf("No such function: 'faup_output'\n");
373 			// Since that function does not exists in the module, we skip it!
374 			continue;
375 		}
376 
377 		lua_pushstring(modules->module[count].lua_state, fh->faup.org_str);
378 
379 		// Table for positions
380 		lua_newtable(modules->module[count].lua_state); // -1
381 
382 		_faup_add_feature(modules, count, fh->faup.features.scheme, "scheme.pos", "scheme.size");
383 		_faup_add_feature(modules, count, fh->faup.features.hierarchical, "hierarchical.pos", "hierarchical.size");
384 		_faup_add_feature(modules, count, fh->faup.features.credential, "credential.pos", "credential.size");
385 		_faup_add_feature(modules, count, fh->faup.features.host, "host.pos", "host.size");
386 		_faup_add_feature(modules, count, fh->faup.features.subdomain, "subdomain.pos", "subdomain.size");
387 		_faup_add_feature(modules, count, fh->faup.features.domain, "domain.pos", "domain.size");
388 		_faup_add_feature(modules, count, fh->faup.features.domain_without_tld, "domain_without_tld.pos", "domain_without_tld.size");
389 		_faup_add_feature(modules, count, fh->faup.features.tld, "tld.pos", "tld.size");
390 		_faup_add_feature(modules, count, fh->faup.features.port, "port.pos", "port.size");
391 		_faup_add_feature(modules, count, fh->faup.features.resource_path, "resource_path.pos", "resource_path.size");
392 		_faup_add_feature(modules, count, fh->faup.features.query_string, "query_string.pos", "query_string.size");
393 		_faup_add_feature(modules, count, fh->faup.features.fragment, "fragment.pos", "fragment.size");
394 
395 		_faup_add_keyvalstr_dict(modules, count, "url_type", faup_output_get_string_from_url_type(fh));
396 
397 
398 		// If the function does not exists, we just ignore it
399 		retval = lua_pcall(modules->module[count].lua_state, 2, 2, 0);
400 		if (retval == 0) {
401 			module_executed = true;
402 			transformed_url = lua_tostring(modules->module[count].lua_state, -1);
403 			if (transformed_url) {
404 				fh->faup.org_str = transformed_url;
405 			}
406 
407     		lua_pushnil(modules->module[count].lua_state);
408     		const char *k;
409     		int v;
410 
411    			while (lua_next(modules->module[count].lua_state, -2)) { // The table is is -2 in the stack
412         		v = lua_tointeger(modules->module[count].lua_state, -1);
413         		lua_pop(modules->module[count].lua_state, 1);
414         		k = lua_tostring(modules->module[count].lua_state, -1);
415 
416         		if (!strcmp(k, "scheme.pos")) {
417         			fh->faup.features.scheme.pos = v;
418         		}
419         		if (!strcmp(k, "scheme.size")) {
420         			fh->faup.features.scheme.size = v;
421 
422         		}
423         		if (!strcmp(k, "hierarchical.pos")) {
424         			fh->faup.features.hierarchical.pos = v;
425         		}
426         		if (!strcmp(k, "hierarchical.size")) {
427         			fh->faup.features.hierarchical.size = v;
428 
429         		}
430         		if (!strcmp(k, "credential.pos")) {
431         			fh->faup.features.credential.pos = v;
432         		}
433         		if (!strcmp(k, "credential.size")) {
434         			fh->faup.features.credential.size = v;
435 
436         		}
437         		if (!strcmp(k, "host.pos")) {
438         			fh->faup.features.host.pos = v;
439         		}
440         		if (!strcmp(k, "host.size")) {
441         			fh->faup.features.host.size = v;
442 
443         		}
444         		if (!strcmp(k, "subdomain.pos")) {
445         			fh->faup.features.subdomain.pos = v;
446         		}
447         		if (!strcmp(k, "subdomain.size")) {
448         			fh->faup.features.subdomain.size = v;
449 
450         		}
451         		if (!strcmp(k, "domain.pos")) {
452         			fh->faup.features.domain.pos = v;
453         		}
454         		if (!strcmp(k, "domain.size")) {
455         			fh->faup.features.domain.size = v;
456 
457         		}
458         		if (!strcmp(k, "domain_without_tld.pos")) {
459         			fh->faup.features.domain_without_tld.pos = v;
460         		}
461         		if (!strcmp(k, "domain_without_tld.size")) {
462         			fh->faup.features.domain_without_tld.size = v;
463 
464         		}
465         		if (!strcmp(k, "tld.pos")) {
466         			fh->faup.features.tld.pos = v;
467         		}
468         		if (!strcmp(k, "tld.size")) {
469         			fh->faup.features.tld.size = v;
470 
471         		}
472         		if (!strcmp(k, "port.pos")) {
473         			fh->faup.features.port.pos = v;
474         		}
475         		if (!strcmp(k, "port.size")) {
476         			fh->faup.features.port.size = v;
477 
478         		}
479         		if (!strcmp(k, "resource_path.pos")) {
480         			fh->faup.features.resource_path.pos = v;
481         		}
482         		if (!strcmp(k, "resource_path.size")) {
483         			fh->faup.features.resource_path.size = v;
484 
485         		}
486         		if (!strcmp(k, "query_string.pos")) {
487         			fh->faup.features.query_string.pos = v;
488         		}
489         		if (!strcmp(k, "query_string.size")) {
490         			fh->faup.features.query_string.size = v;
491 
492         		}
493         		if (!strcmp(k, "fragment.pos")) {
494         			fh->faup.features.fragment.pos = v;
495         		}
496         		if (!strcmp(k, "fragment.size")) {
497         			fh->faup.features.fragment.size = v;
498 
499         		}
500    			}
501 		} else { // if (retval == 0) {
502 			fprintf(stderr, "*** Error(%s)[in script:%s]: %s\n", __FUNCTION__, modules->module[count].module_name, lua_tostring(modules->module[count].lua_state, -1));
503 		}
504 	}
505 
506 	return module_executed;
507 }
508 
509