ETH -> WS updates.
[obnox/wireshark/wip.git] / epan / plugins.c
1 /* plugins.c
2  * plugin routines
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1999 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include "plugins.h"
30
31 #ifdef HAVE_PLUGINS
32
33 #include <time.h>
34
35 #ifdef HAVE_DIRENT_H
36 #include <dirent.h>
37 #endif
38
39 #ifdef HAVE_DIRECT_H
40 #include <direct.h>
41 #endif
42
43 #include <string.h>
44 #include <stdlib.h>
45 #include <errno.h>
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include "filesystem.h"
52 #include <wsutil/privileges.h>
53 #include <wsutil/file_util.h>
54 #include "report_err.h"
55
56 /* linked list of all plugins */
57 plugin *plugin_list;
58
59 #define PLUGINS_DIR_NAME        "plugins"
60
61 /*
62  * add a new plugin to the list
63  * returns :
64  * - 0 : OK
65  * - ENOMEM : memory allocation problem
66  * - EEXIST : the same plugin (i.e. name/version) was already registered.
67  */
68 static int
69 add_plugin(void *handle, gchar *name, gchar *version,
70            void (*register_protoinfo)(void), void (*reg_handoff)(void),
71            void (*register_tap_listener)(void),
72            void (*register_wtap_module)(void),
73            void (*register_codec_module)(void))
74 {
75     plugin *new_plug, *pt_plug;
76
77     pt_plug = plugin_list;
78     if (!pt_plug) /* the list is empty */
79     {
80         new_plug = (plugin *)g_malloc(sizeof(plugin));
81         if (new_plug == NULL) return ENOMEM;
82         plugin_list = new_plug;
83     }
84     else
85     {
86         while (1)
87         {
88             /* check if the same name/version is already registered */
89             if (!strcmp(pt_plug->name, name) &&
90                 !strcmp(pt_plug->version, version))
91             {
92                 return EEXIST;
93             }
94
95             /* we found the last plugin in the list */
96             if (pt_plug->next == NULL) break;
97
98             pt_plug = pt_plug->next;
99         }
100         new_plug = (plugin *)g_malloc(sizeof(plugin));
101         if (new_plug == NULL) return ENOMEM;
102         pt_plug->next = new_plug;
103     }
104
105     new_plug->handle = handle;
106     new_plug->name = name;
107     new_plug->version = version;
108     new_plug->register_protoinfo = register_protoinfo;
109     new_plug->reg_handoff = reg_handoff;
110     new_plug->register_tap_listener = register_tap_listener;
111     new_plug->register_wtap_module = register_wtap_module;
112     new_plug->register_codec_module = register_codec_module;
113     new_plug->next = NULL;
114
115     return 0;
116 }
117
118 /*
119  * XXX - when we remove support for old-style plugins (which we should
120  * probably do eventually, as all plugins should be written as new-style
121  * ones), we may want to have "init_plugins()" merely save a pointer
122  * to the plugin's "init" routine, just as we save a pointer to its
123  * "reg_handoff" routine, and have a "register_all_plugins()" routine
124  * to go through the list of plugins and call all of them.
125  *
126  * Then we'd have "epan_init()", or perhaps even something higher up
127  * in the call tree, call "init_plugins()", and have "proto_init()"
128  * call "register_all_plugins()" right after calling "register_all_protocols()";
129  * this might be a bit cleaner.
130  */
131 static void
132 plugins_scan_dir(const char *dirname)
133 {
134 #define FILENAME_LEN    1024
135     WS_DIR        *dir;             /* scanned directory */
136     WS_DIRENT     *file;            /* current file */
137     const char    *name;
138     gchar          filename[FILENAME_LEN];   /* current file name */
139     GModule       *handle;          /* handle returned by dlopen */
140     gchar         *version;
141     gpointer       gp;
142     void         (*register_protoinfo)(void);
143     void         (*reg_handoff)(void);
144     void         (*register_tap_listener)(void);
145     void (*register_wtap_module)(void);
146     void (*register_codec_module)(void);
147
148     gchar         *dot;
149     int            cr;
150
151     if ((dir = ws_dir_open(dirname, 0, NULL)) != NULL)
152     {
153
154     while ((file = ws_dir_read_name(dir)) != NULL)
155         {
156             name = ws_dir_get_name(file);
157
158             /*
159              * GLib 2.x defines G_MODULE_SUFFIX as the extension used on
160              * this platform for loadable modules.
161              */
162             /* skip anything but files with G_MODULE_SUFFIX */
163             dot = strrchr(name, '.');
164             if (dot == NULL || strcmp(dot+1, G_MODULE_SUFFIX) != 0)
165                 continue;
166
167             g_snprintf(filename, FILENAME_LEN, "%s" G_DIR_SEPARATOR_S "%s",
168                 dirname, name);
169             if ((handle = g_module_open(filename, 0)) == NULL)
170             {
171                 report_failure("Couldn't load module %s: %s", filename,
172                           g_module_error());
173                 continue;
174             }
175
176             if (!g_module_symbol(handle, "version", &gp))
177             {
178                 report_failure("The plugin %s has no version symbol", name);
179                 g_module_close(handle);
180                 continue;
181             }
182             version = gp;
183
184             /*
185              * Do we have a register routine?
186              */
187             if (g_module_symbol(handle, "plugin_register", &gp))
188             {
189                 /*
190                  * Yes - this plugin includes one or more dissectors.
191                  */
192                 register_protoinfo = gp;
193             }
194             else
195             {
196                 /*
197                  * No - no dissectors.
198                  */
199                 register_protoinfo = NULL;
200             }
201
202             /*
203              * Do we have a reg_handoff routine?
204              */
205             if (g_module_symbol(handle, "plugin_reg_handoff", &gp))
206             {
207                 /*
208                  * Yes.
209                  */
210                 reg_handoff = gp;
211             }
212             else
213             {
214                 /*
215                  * No - that's OK even if we have dissectors, as long
216                  * as the plugin registers by name *and* there's
217                  * a caller looking for that name.
218                  */
219                 reg_handoff = NULL;
220             }
221
222             /*
223              * Do we have a register_tap_listener routine?
224              */
225             if (g_module_symbol(handle, "plugin_register_tap_listener", &gp))
226             {
227                 /*
228                  * Yes - this plugin includes one or more taps.
229                  */
230                 register_tap_listener = gp;
231             }
232             else
233             {
234                 /*
235                  * No - no taps here.
236                  */
237                 register_tap_listener = NULL;
238             }
239
240                 /*
241              * Do we have an old-style init routine?
242              */
243             if (g_module_symbol(handle, "plugin_init", &gp))
244             {
245                         /*
246                          * Yes - do we also have a register routine or a
247                          * register_tap_listener routine?  If so, this is a bogus
248                          * hybrid of an old-style and new-style plugin.
249                          */
250                         if (register_protoinfo != NULL || register_tap_listener != NULL)
251                         {
252                                 report_failure("The plugin '%s' has an old plugin init routine\nand a new register or register_tap_listener routine.",
253                                 name);
254                                 g_module_close(handle);
255                                 continue;
256                         }
257
258                         /*
259                          * It's just an unsupported old-style plugin;
260                          */
261                         report_failure("The plugin '%s' has an old plugin init routine. Support has been dropped.\n Information on how to update your plugin is available at \nhttp://anonsvn.wireshark.org/wireshark/trunk/doc/README.plugins",
262                                 name);
263                         g_module_close(handle);
264                         continue;
265             }
266
267             /*
268                  * Do we have a register_wtap_module routine?
269                  */
270            if (g_module_symbol(handle, "register_wtap_module", &gp))
271            {
272                register_wtap_module = gp;
273            } else {
274                register_wtap_module = NULL;
275            }
276
277             /*
278                  * Do we have a register_codec_module routine?
279                  */
280            if (g_module_symbol(handle, "register_codec_module", &gp))
281            {
282                register_codec_module = gp;
283            } else {
284                register_codec_module = NULL;
285            }
286
287            /*
288                 * Does this dissector do anything useful?
289                 */
290             if (register_protoinfo == NULL &&
291                     register_tap_listener == NULL &&
292                     register_wtap_module == NULL &&
293                     register_codec_module == NULL )
294             {
295                 /*
296                  * No.
297                  */
298                 report_failure("The plugin '%s' has neither a register routine, "
299                                            "a register_tap_listener or a register_wtap_module or a register_codec_module routine",
300                     name);
301                 g_module_close(handle);
302                 continue;
303             }
304
305             /*
306              * OK, attempt to add it to the list of plugins.
307              */
308             if ((cr = add_plugin(handle, g_strdup(name), version,
309                                  register_protoinfo, reg_handoff,
310                                  register_tap_listener,register_wtap_module,register_codec_module)))
311             {
312                 if (cr == EEXIST)
313                     fprintf(stderr, "The plugin %s, version %s\n"
314                             "was found in multiple directories\n", name, version);
315                 else
316                     fprintf(stderr, "Memory allocation problem\n"
317                             "when processing plugin %s, version %s\n",
318                             name, version);
319                 g_module_close(handle);
320                 continue;
321             }
322
323         }
324         ws_dir_close(dir);
325         }
326 }
327
328 /* get the personal plugin dir */
329 /* Return value is malloced so the caller should g_free() it. */
330 char *get_plugins_pers_dir(void)
331 {
332     return get_persconffile_path(PLUGINS_DIR_NAME, FALSE, FALSE);
333 }
334
335 /*
336  * init plugins
337  */
338 void
339 init_plugins(void)
340 {
341     const char *plugin_dir;
342     const char *name;
343     char *plugin_dir_path;
344     char *plugins_pers_dir;
345     WS_DIR *dir;                /* scanned directory */
346     WS_DIRENT *file;            /* current file */
347
348     if (plugin_list == NULL)      /* ensure init_plugins is only run once */
349     {
350         /*
351          * Scan the global plugin directory.
352          * If we're running from a build directory, scan the subdirectories
353          * of that directory, as the global plugin directory is the
354          * "plugins" directory of the source tree, and the subdirectories
355          * are the source directories for the plugins, with the plugins
356          * built in those subdirectories.
357          */
358         plugin_dir = get_plugin_dir();
359         if (running_in_build_directory()) {
360             if ((dir = ws_dir_open(plugin_dir, 0, NULL)) != NULL) {
361                 while ((file = ws_dir_read_name(dir)) != NULL)  {
362                     name = ws_dir_get_name(file);
363                     if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
364                         continue;       /* skip "." and ".." */
365                     /*
366                      * Get the full path of a ".libs" subdirectory of that
367                      * directory.
368                      */
369                     plugin_dir_path = g_strdup_printf(
370                         "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S ".libs",
371                         plugin_dir, name);
372                     if (test_for_directory(plugin_dir_path) != EISDIR) {
373                         /*
374                          * Either it doesn't refer to a directory or it
375                          * refers to something that doesn't exist.
376                          *
377                          * Assume that means that the plugins are in
378                          * the subdirectory of the plugin directory, not
379                          * a ".libs" subdirectory of that subdirectory.
380                          */
381                         g_free(plugin_dir_path);
382                         plugin_dir_path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
383                             plugin_dir, name);
384                     }
385                     plugins_scan_dir(plugin_dir_path);
386                     g_free(plugin_dir_path);
387                 }
388             }
389         } else
390             plugins_scan_dir(plugin_dir);
391
392         /*
393          * If the program wasn't started with special privileges,
394          * scan the users plugin directory.  (Even if we relinquish
395          * them, plugins aren't safe unless we've *permanently*
396          * relinquished them, and we can't do that in Wireshark as,
397          * if we need privileges to start capturing, we'd need to
398          * reclaim them before each time we start capturing.)
399          */
400         if (!started_with_special_privs()) {
401             plugins_pers_dir = get_plugins_pers_dir();
402             plugins_scan_dir(plugins_pers_dir);
403             g_free(plugins_pers_dir);
404         }
405     }
406         register_all_wiretap_modules();
407         register_all_codecs();
408 }
409
410 void
411 register_all_plugin_registrations(void)
412 {
413     plugin *pt_plug;
414
415     /*
416      * For all plugins with register-handoff routines, call the routines.
417      * This is called from "proto_init()"; it must be called after
418      * "register_all_protocols()" and "init_plugins()" are called,
419      * in case one plugin registers itself either with a built-in
420      * dissector or with another plugin; we must first register all
421      * dissectors, whether built-in or plugin, so their dissector tables
422      * are initialized, and only then register all handoffs.
423      */
424     for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next)
425     {
426                 if (pt_plug->register_protoinfo)
427                         (pt_plug->register_protoinfo)();
428     }
429 }
430
431 void
432 register_all_plugin_handoffs(void)
433 {
434     plugin *pt_plug;
435
436     /*
437      * For all plugins with register-handoff routines, call the routines.
438      * This is called from "proto_init()"; it must be called after
439      * "register_all_protocols()" and "init_plugins()" are called,
440      * in case one plugin registers itself either with a built-in
441      * dissector or with another plugin; we must first register all
442      * dissectors, whether built-in or plugin, so their dissector tables
443      * are initialized, and only then register all handoffs.
444      */
445     for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next)
446     {
447         if (pt_plug->reg_handoff)
448             (pt_plug->reg_handoff)();
449     }
450 }
451
452 void
453 register_all_plugin_tap_listeners(void)
454 {
455     plugin *pt_plug;
456
457     /*
458      * For all plugins with register-tap-listener routines, call the
459      * routines.
460      */
461     for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next)
462     {
463         if (pt_plug->register_tap_listener)
464             (pt_plug->register_tap_listener)();
465     }
466 }
467
468 void
469 register_all_wiretap_modules(void)
470 {
471     plugin *pt_plug;
472
473     /*
474      * For all plugins with register_wtap_module routines, call the
475      * routines.
476      */
477     for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next)
478     {
479                 if (pt_plug->register_wtap_module)
480                         (pt_plug->register_wtap_module)();
481     }
482 }
483
484 void
485 register_all_codecs(void)
486 {
487     plugin *pt_plug;
488
489     /*
490      * For all plugins with register_wtap_module routines, call the
491      * routines.
492      */
493     for (pt_plug = plugin_list; pt_plug != NULL; pt_plug = pt_plug->next)
494     {
495                 if (pt_plug->register_codec_module)
496                         (pt_plug->register_codec_module)();
497     }
498 }
499 #endif