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