1 /*
2 ettercap -- plugin handling
3
4 Copyright (C) ALoR & NaGA
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include <ec.h>
23 #include <ec_plugins.h>
24
25 #include <dirent.h>
26
27 #ifndef HAVE_SCANDIR
28 #include <missing/scandir.h>
29 #endif
30
31 #ifdef HAVE_PLUGINS
32 #ifdef HAVE_LTDL_H
33 #include <ltdl.h>
34 #endif
35 #ifdef HAVE_DLFCN_H
36 #include <dlfcn.h>
37 #endif
38 #endif
39
40 /* symbol prefix for some OSes */
41 #ifdef NEED_USCORE
42 #define SYM_PREFIX "_"
43 #else
44 #define SYM_PREFIX ""
45 #endif
46
47
48 /* global data */
49
50 struct plugin_entry {
51 void *handle;
52 char activated; /* if the init fuction was already called */
53 struct plugin_ops *ops;
54 SLIST_ENTRY(plugin_entry) next;
55 };
56
57 static SLIST_HEAD(, plugin_entry) plugin_head;
58
59 /* mutexes */
60 static pthread_mutex_t kill_mutex = PTHREAD_MUTEX_INITIALIZER;
61 #define KILL_LOCK do { pthread_mutex_lock(&kill_mutex); } while (0)
62 #define KILL_UNLOCK do { pthread_mutex_unlock(&kill_mutex); } while (0)
63
64 static pthread_mutex_t plugin_list_mutex = PTHREAD_MUTEX_INITIALIZER;
65 #define PLUGIN_LIST_LOCK do { pthread_mutex_lock(&plugin_list_mutex); } \
66 while (0)
67 #define PLUGIN_LIST_UNLOCK do { pthread_mutex_unlock(&plugin_list_mutex); } \
68 while (0)
69
70 /* protos... */
71
72 void plugin_unload_all(void);
73 static void plugin_print(char active, struct plugin_ops *ops);
74 int plugin_filter(const struct dirent *d);
75
76 /*******************************************/
77
78 /*
79 * load a plugin given the full path
80 */
81
plugin_load_single(const char * path,char * name)82 int plugin_load_single(const char *path, char *name)
83 {
84 #ifdef HAVE_PLUGINS
85 char file[strlen(path)+strlen(name)+2];
86 void *handle;
87 int (*plugin_load)(void *);
88
89 snprintf(file, sizeof(file), "%s/%s", path, name);
90
91 DEBUG_MSG("plugin_load_single: %s", file);
92
93 /* load the plugin */
94 handle = dlopen(file, RTLD_NOW|RTLD_LOCAL);
95
96 if (handle == NULL) {
97 DEBUG_MSG("plugin_load_single - %s - dlopen() | %s", file, dlerror());
98 return -E_INVALID;
99 }
100
101 /* find the loading function */
102 plugin_load = dlsym(handle, SYM_PREFIX "plugin_load");
103
104 if (plugin_load == NULL) {
105 DEBUG_MSG("plugin_load_single - %s - lt_dlsym() | %s", file, dlerror());
106 dlclose(handle);
107 return -E_INVALID;
108 }
109
110 /*
111 * return the same value of plugin_register
112 * we pass the handle to the plugin, which
113 * in turn passes it to the plugin_register
114 * function
115 */
116 return plugin_load(handle);
117 #else
118 (void) path;
119 (void) name;
120 return -E_INVALID;
121 #endif
122 }
123
124 /*
125 * filter for the scandir function
126 */
plugin_filter(const struct dirent * d)127 int plugin_filter(const struct dirent *d)
128 {
129 if ( match_pattern(d->d_name, PLUGIN_PATTERN) )
130 return 1;
131
132 return 0;
133 }
134
135 /*
136 * search and load all plugins in INSTALL_PREFIX/lib
137 */
138
plugin_load_all(void)139 void plugin_load_all(void)
140 {
141 #ifdef HAVE_PLUGINS
142 struct dirent **namelist = NULL;
143 int n, i, ret;
144 int t = 0;
145 char *where;
146
147 DEBUG_MSG("plugin_loadall");
148
149 #ifdef OS_WINDOWS
150 /* Assume .DLLs are under "<ec_root>/lib". This should be unified for
151 * all; ec_get_lib_path()?
152 */
153 char path[PATH_MAX];
154
155 snprintf(path, sizeof(path), "%s%s", ec_win_get_ec_dir(), INSTALL_LIBDIR);
156 where = path;
157 #else
158 /* default path */
159 where = INSTALL_LIBDIR "/" PROGRAM;
160 #endif
161
162 /* first search in INSTALL_LIBDIR/ettercap" */
163 n = scandir(where, &namelist, plugin_filter, alphasort);
164 /* on error fall back to the current dir */
165 if (n <= 0) {
166 DEBUG_MSG("plugin_loadall: no plugin in %s searching locally...", where);
167 /* change the path to the local one */
168 where = "plug-ins";
169 n = scandir(where, &namelist, plugin_filter, alphasort);
170 DEBUG_MSG("plugin_loadall: %d found", n);
171 }
172
173 for(i = n-1; i >= 0; i--) {
174 ret = plugin_load_single(where, namelist[i]->d_name);
175 switch (ret) {
176 case E_SUCCESS:
177 t++;
178 break;
179 case -E_DUPLICATE:
180 USER_MSG("plugin %s already loaded...\n", namelist[i]->d_name);
181 DEBUG_MSG("plugin %s already loaded...", namelist[i]->d_name);
182 break;
183 case -E_VERSION:
184 USER_MSG("plugin %s was compiled for a different ettercap version...\n", namelist[i]->d_name);
185 DEBUG_MSG("plugin %s was compiled for a different ettercap version...", namelist[i]->d_name);
186 break;
187 case -E_INVALID:
188 default:
189 USER_MSG("plugin %s cannot be loaded...\n", namelist[i]->d_name);
190 DEBUG_MSG("plugin %s cannot be loaded...", namelist[i]->d_name);
191 break;
192 }
193 SAFE_FREE(namelist[i]);
194 }
195
196 USER_MSG("%4d plugins\n", t);
197
198 SAFE_FREE(namelist);
199
200 atexit(plugin_unload_all);
201 #else
202 USER_MSG(" 0 plugins (disabled by configure...)\n");
203 #endif
204 }
205
206
207 /*
208 * unload all the plugin
209 */
plugin_unload_all(void)210 void plugin_unload_all(void)
211 {
212 #ifdef HAVE_PLUGINS
213 struct plugin_entry *p;
214
215 DEBUG_MSG("ATEXIT: plugin_unload_all");
216
217 while (SLIST_FIRST(&plugin_head) != NULL) {
218 p = SLIST_FIRST(&plugin_head);
219 if(plugin_is_activated(p->ops->name) == 1)
220 plugin_fini(p->ops->name);
221 dlclose(p->handle);
222 SLIST_REMOVE_HEAD(&plugin_head, next);
223 SAFE_FREE(p);
224 }
225 #endif
226 }
227
228
229 /*
230 * function used by plugins to register themself
231 */
plugin_register(void * handle,struct plugin_ops * ops)232 int plugin_register(void *handle, struct plugin_ops *ops)
233 {
234 #ifdef HAVE_PLUGINS
235 struct plugin_entry *p, *pl;
236
237 /* check for ettercap API version */
238 if (strcmp(ops->ettercap_version, EC_VERSION)) {
239 dlclose(handle);
240 return -E_VERSION;
241 }
242
243 /* check that this plugin was not already loaded */
244 SLIST_FOREACH(pl, &plugin_head, next) {
245 /* same name and same version */
246 if (!strcmp(ops->name, pl->ops->name) && !strcmp(ops->version, pl->ops->version)) {
247 dlclose(handle);
248 return -E_DUPLICATE;
249 }
250 }
251
252 SAFE_CALLOC(p, 1, sizeof(struct plugin_entry));
253
254 p->handle = handle;
255 p->ops = ops;
256
257 SLIST_INSERT_HEAD(&plugin_head, p, next);
258
259 return E_SUCCESS;
260 #else
261 (void) handle;
262 (void) ops;
263 return -E_INVALID;
264 #endif
265 }
266
267
268 /*
269 * activate a plugin.
270 * it launch the plugin init function
271 */
plugin_init(char * name)272 int plugin_init(char *name)
273 {
274 struct plugin_entry *p;
275 int ret;
276
277 SLIST_FOREACH(p, &plugin_head, next) {
278 if (!strcmp(p->ops->name, name)) {
279 /* get the response from the plugin */
280 ret = p->ops->init(NULL);
281 /* if it is still running, mark it as active */
282 if (ret == PLUGIN_RUNNING)
283 p->activated = 1;
284 return ret;
285 }
286 }
287
288 return -E_NOTFOUND;
289 }
290
291
292 /*
293 * deactivate a plugin.
294 * it launch the plugin fini function
295 */
plugin_fini(char * name)296 int plugin_fini(char *name)
297 {
298 struct plugin_entry *p;
299 int ret;
300
301 SLIST_FOREACH(p, &plugin_head, next) {
302 if (p->activated == 1 && !strcmp(p->ops->name, name)) {
303 /* get the response from the plugin */
304 ret = p->ops->fini(NULL);
305 /* if it is still running, mark it as active */
306 if (ret == PLUGIN_FINISHED)
307 p->activated = 0;
308 return ret;
309 }
310 }
311
312 return -E_NOTFOUND;
313 }
314
315 /*
316 * self-destruct a plugin thread.
317 * it resets the activity state and destructs itself by calling the plugin fini function.
318 * it does not replace the <plugin>_fini standard function rather than it depends on it.
319 * this function does not do anything if not executed by a thread.
320 */
plugin_kill_thread(char * name,char * thread)321 int plugin_kill_thread(char *name, char *thread)
322 {
323 struct plugin_entry *p;
324 int ret;
325 pthread_t pid;
326
327 pid = ec_thread_getpid(thread);
328
329 /* do not execute if not being a thread */
330 if (pthread_equal(pid, ec_thread_getpid(NULL)))
331 return -E_INVALID;
332
333 /* the thread can only kill itself */
334 if (!pthread_equal(pid, pthread_self()))
335 return -E_INVALID;
336
337 DEBUG_MSG("plugin_kill_thread");
338
339 KILL_LOCK;
340 SLIST_FOREACH(p, &plugin_head, next) {
341 if (p->activated == 1 && !strcmp(p->ops->name, name)) {
342 /* flag plugin as inactive */
343 p->activated = 0;
344 /* update the UI */
345 ui_update(UI_UPDATE_PLUGINLIST);
346 /* release the lock */
347 KILL_UNLOCK;
348 /* call plugin's destruction routine */
349 ret = p->ops->fini(NULL);
350 /*
351 * normally the thread should not return from the call -
352 * just in case the thread wasn't destroyed in the fini callback
353 * destroy it here
354 */
355 ec_thread_destroy(pid);
356
357 /* should never be reached */
358 return ret;
359 }
360 }
361 KILL_UNLOCK;
362
363 return -E_NOTFOUND;
364 }
365
366 /*
367 * it print the list of the plugins.
368 *
369 * func is the callback function to which are passed
370 * - the plugin name
371 * - the plugin version
372 * - the plugin description
373 *
374 * min is the n-th plugin to start to print
375 * max it the n-th plugin to stop to print
376 */
377
plugin_list_walk(int min,int max,void (* func)(char,struct plugin_ops *))378 int plugin_list_walk(int min, int max, void (*func)(char, struct plugin_ops *))
379 {
380 struct plugin_entry *p;
381 int i = min;
382
383 SLIST_FOREACH(p, &plugin_head, next) {
384 if (i > max)
385 return (i-1);
386 if (i < min) {
387 i++;
388 continue;
389 }
390 func(p->activated, p->ops);
391 i++;
392 }
393
394 return (i == min) ? -E_NOTFOUND : (i-1);
395 }
396
397 /*
398 * returns the activation flag
399 */
400
plugin_is_activated(char * name)401 int plugin_is_activated(char *name)
402 {
403 struct plugin_entry *p;
404
405 SLIST_FOREACH(p, &plugin_head, next) {
406 if (!strcmp(p->ops->name, name)) {
407 return p->activated;
408 }
409 }
410
411 return 0;
412 }
413
414 /*
415 * search if a plugin exists
416 */
search_plugin(char * name)417 int search_plugin(char *name)
418 {
419 struct plugin_entry *p;
420
421 SLIST_FOREACH(p, &plugin_head, next) {
422 if (!strcmp(p->ops->name, name)) {
423 return E_SUCCESS;
424 }
425 }
426
427 return -E_NOTFOUND;
428 }
429
430 /*
431 * print the list of available plugins
432 */
plugin_list(void)433 void plugin_list(void)
434 {
435 int ret;
436
437 DEBUG_MSG("plugin_list");
438
439 /* load all the plugins */
440 plugin_load_all();
441
442 /* print the list */
443 fprintf(stdout, "\nAvailable plugins :\n\n");
444 ret = plugin_list_walk(PLP_MIN, PLP_MAX, &plugin_print);
445 if (ret == -E_NOTFOUND) {
446 fprintf(stdout, "No plugin found !\n\n");
447 return;
448 }
449 fprintf(stdout, "\n\n");
450
451 }
452
453 /*
454 * walk through the list of plugin names and free
455 */
free_plugin_list(struct plugin_list_t plugins)456 void free_plugin_list(struct plugin_list_t plugins)
457 {
458 struct plugin_list *plugin, *tmp;
459
460 PLUGIN_LIST_LOCK;
461
462 LIST_FOREACH_SAFE(plugin, &plugins, next, tmp) {
463 LIST_REMOVE(plugin, next);
464 SAFE_FREE(plugin->name);
465 SAFE_FREE(plugin);
466 }
467
468 PLUGIN_LIST_UNLOCK;
469 }
470
471 /*
472 * callback function for displaying the plugin list
473 */
plugin_print(char active,struct plugin_ops * ops)474 static void plugin_print(char active, struct plugin_ops *ops)
475 {
476 /* variable not used */
477 (void) active;
478
479 fprintf(stdout, " %15s %4s %s\n", ops->name, ops->version, ops->info);
480 }
481
482 /* EOF */
483
484 // vim:ts=3:expandtab
485
486