df5c3a726c0962ceb2b1302e13f9b2ce25330d01
[metze/wireshark/wip.git] / extcap.c
1 /* extcap.c
2  *
3  * Routines for extcap external capture
4  * Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * SPDX-License-Identifier: GPL-2.0-or-later
11  */
12
13 #include <config.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #ifdef _WIN32
20 #include <windows.h>
21 #include <process.h>
22 #include <time.h>
23 #else
24 /* Include for unlink */
25 #include <unistd.h>
26 #endif
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #endif
34
35 #include <glib.h>
36 #include <log.h>
37
38 #include <epan/prefs.h>
39
40 #include "ui/iface_toolbar.h"
41
42 #include <wsutil/glib-compat.h>
43 #include <wsutil/file_util.h>
44 #include <wsutil/filesystem.h>
45 #include <wsutil/ws_pipe.h>
46 #include <wsutil/tempfile.h>
47
48 #include "capture_opts.h"
49
50 #include "extcap.h"
51 #include "extcap_parser.h"
52
53 #include "version_info.h"
54
55 #ifdef _WIN32
56 static HANDLE pipe_h = INVALID_HANDLE_VALUE;
57 #endif
58
59 static void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data);
60
61 /* internal container, for all the extcap executables that have been found.
62  * Will be resetted if extcap_clear_interfaces() is being explicitly called
63  * and is being used for printing information about all extcap interfaces found,
64  * as well as storing all sub-interfaces
65  */
66 static GHashTable * _loaded_interfaces = NULL;
67
68 /* Internal container, which maps each ifname to the tool providing it, for faster
69  * lookup. The key and string value are owned by this table.
70  */
71 static GHashTable * _tool_for_ifname = NULL;
72
73 /* internal container, for all the extcap executables that have been found
74  * and that provides a toolbar with controls to be added to a Interface Toolbar
75  */
76 static GHashTable *_toolbars = NULL;
77
78 /* internal container, to map preference names to pointers that hold preference
79  * values. These ensure that preferences can survive extcap if garbage
80  * collection, and does not lead to dangling pointers in the prefs subsystem.
81  */
82 static GHashTable *extcap_prefs_dynamic_vals = NULL;
83
84 typedef struct _extcap_callback_info_t
85 {
86     const gchar * extcap;
87     const gchar * ifname;
88     gchar * output;
89     void * data;
90     gchar ** err_str;
91 } extcap_callback_info_t;
92
93 /* Callback definition for extcap_foreach */
94 typedef gboolean(*extcap_cb_t)(extcap_callback_info_t info_structure);
95
96 static void extcap_load_interface_list(void);
97
98 GHashTable *
99 extcap_loaded_interfaces(void)
100 {
101     if (prefs.capture_no_extcap)
102         return NULL;
103
104     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
105         extcap_load_interface_list();
106
107     return _loaded_interfaces;
108 }
109
110 void
111 extcap_clear_interfaces(void)
112 {
113     if ( _loaded_interfaces )
114         g_hash_table_destroy(_loaded_interfaces);
115     _loaded_interfaces = NULL;
116
117     if ( _tool_for_ifname )
118         g_hash_table_destroy(_tool_for_ifname);
119     _tool_for_ifname = NULL;
120 }
121
122 guint extcap_count(void)
123 {
124     const char *dirname = get_extcap_dir();
125     GDir *dir;
126     guint count;
127
128     count = 0;
129
130     if ((dir = g_dir_open(dirname, 0, NULL)) != NULL)
131     {
132         GString *extcap_path = NULL;
133         const gchar *file;
134
135         extcap_path = g_string_new("");
136         while ((file = g_dir_read_name(dir)) != NULL)
137         {
138             /* full path to extcap binary */
139             g_string_printf(extcap_path, "%s" G_DIR_SEPARATOR_S "%s", dirname, file);
140             /* treat anything executable as an extcap binary */
141             if (g_file_test(extcap_path->str, G_FILE_TEST_IS_REGULAR) &&
142                 g_file_test(extcap_path->str, G_FILE_TEST_IS_EXECUTABLE))
143             {
144                 count++;
145             }
146         }
147
148         g_dir_close(dir);
149         g_string_free(extcap_path, TRUE);
150     }
151     return count;
152 }
153
154 static gboolean
155 extcap_if_exists(const gchar *ifname)
156 {
157     if (!ifname || !_tool_for_ifname)
158     {
159         return FALSE;
160     }
161
162     if (g_hash_table_lookup(_tool_for_ifname, ifname))
163     {
164         return TRUE;
165     }
166
167     return FALSE;
168 }
169
170 static extcap_interface *
171 extcap_find_interface_for_ifname(const gchar *ifname)
172 {
173     extcap_interface * result = NULL;
174
175     if ( !ifname || ! _tool_for_ifname || ! _loaded_interfaces )
176         return result;
177
178     gchar * extcap_util = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
179     if ( ! extcap_util )
180         return result;
181
182     extcap_info * element = (extcap_info *)g_hash_table_lookup(_loaded_interfaces, extcap_util);
183     if ( ! element )
184         return result;
185
186     GList * walker = element->interfaces;
187     while ( walker && walker->data && ! result )
188     {
189         extcap_interface * interface = (extcap_interface *)walker->data;
190         if ( g_strcmp0(interface->call, ifname) == 0 )
191         {
192             result = interface;
193             break;
194         }
195
196         walker = g_list_next ( walker );
197     }
198
199     return result;
200 }
201
202 static void
203 extcap_free_toolbar_value(iface_toolbar_value *value)
204 {
205     if (!value)
206     {
207         return;
208     }
209
210     g_free(value->value);
211     g_free(value->display);
212     g_free(value);
213 }
214
215 static void
216 extcap_free_toolbar_control(iface_toolbar_control *control)
217 {
218     if (!control)
219     {
220         return;
221     }
222
223     g_free(control->display);
224     g_free(control->validation);
225     g_free(control->tooltip);
226     if (control->ctrl_type == INTERFACE_TYPE_STRING) {
227         g_free(control->default_value.string);
228     }
229     g_list_foreach(control->values, (GFunc)extcap_free_toolbar_value, NULL);
230     g_list_free(control->values);
231     g_free(control);
232 }
233
234 static void
235 extcap_free_toolbar(gpointer data)
236 {
237     if (!data)
238     {
239         return;
240     }
241
242     iface_toolbar *toolbar = (iface_toolbar *)data;
243
244     g_free(toolbar->menu_title);
245     g_free(toolbar->help);
246     g_list_free_full(toolbar->ifnames, g_free);
247     g_list_foreach(toolbar->controls, (GFunc)extcap_free_toolbar_control, NULL);
248     g_list_free(toolbar->controls);
249     g_free(toolbar);
250 }
251
252 static gboolean
253 extcap_if_exists_for_extcap(const gchar *ifname, const gchar *extcap)
254 {
255     extcap_interface *entry = extcap_find_interface_for_ifname(ifname);
256
257     if (entry && strcmp(entry->extcap_path, extcap) == 0)
258     {
259         return TRUE;
260     }
261
262     return FALSE;
263 }
264
265 static gchar *
266 extcap_if_executable(const gchar *ifname)
267 {
268     extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
269     return interface != NULL ? interface->extcap_path : NULL;
270 }
271
272 static void
273 extcap_iface_toolbar_add(const gchar *extcap, iface_toolbar *toolbar_entry)
274 {
275     char *toolname;
276
277     if (!extcap || !toolbar_entry)
278     {
279         return;
280     }
281
282     toolname = g_path_get_basename(extcap);
283
284     if (!g_hash_table_lookup(_toolbars, toolname))
285     {
286         g_hash_table_insert(_toolbars, g_strdup(toolname), toolbar_entry);
287     }
288
289     g_free(toolname);
290 }
291
292 /* Note: args does not need to be NULL-terminated. */
293 static gboolean extcap_foreach(GList * arguments,
294                                       extcap_cb_t cb, extcap_callback_info_t cb_info)
295 {
296     GDir *dir;
297     gboolean keep_going;
298     const char *dirname = get_extcap_dir();
299
300     keep_going = TRUE;
301
302     if (arguments && (dir = g_dir_open(dirname, 0, NULL)) != NULL)
303     {
304         GString *extcap_path = NULL;
305         const gchar *file;
306
307         extcap_path = g_string_new("");
308         while (keep_going && (file = g_dir_read_name(dir)) != NULL)
309         {
310             gchar *command_output = NULL;
311             gchar ** args = (gchar **) g_malloc0(sizeof(gchar *) * (g_list_length(arguments)));
312             GList * walker = g_list_first(arguments);
313             int cnt = 0;
314             while(walker)
315             {
316                 args[cnt] = g_strdup((const gchar *)walker->data);
317                 walker = g_list_next(walker);
318                 cnt++;
319             }
320
321             /* full path to extcap binary */
322             g_string_printf(extcap_path, "%s" G_DIR_SEPARATOR_S "%s", dirname, file);
323             /* treat anything executable as an extcap binary */
324             if (g_file_test(extcap_path->str, G_FILE_TEST_IS_REGULAR) &&
325                 g_file_test(extcap_path->str, G_FILE_TEST_IS_EXECUTABLE))
326             {
327                 if (extcap_if_exists(cb_info.ifname) && !extcap_if_exists_for_extcap(cb_info.ifname, extcap_path->str))
328                 {
329                     continue;
330                 }
331
332                 if (ws_pipe_spawn_sync((gchar *) dirname, extcap_path->str, cnt, args, &command_output))
333                 {
334                     cb_info.output = command_output;
335                     cb_info.extcap = extcap_path->str;
336
337                     keep_going = cb(cb_info);
338                 }
339
340                 g_free(command_output);
341             }
342         }
343
344         g_dir_close(dir);
345         g_string_free(extcap_path, TRUE);
346     }
347
348     return keep_going;
349 }
350
351 static void extcap_free_dlt(gpointer d, gpointer user_data _U_)
352 {
353     if (d == NULL)
354     {
355         return;
356     }
357
358     g_free(((extcap_dlt *)d)->name);
359     g_free(((extcap_dlt *)d)->display);
360     g_free(d);
361 }
362
363 static void extcap_free_dlts(GList *dlts)
364 {
365     g_list_foreach(dlts, extcap_free_dlt, NULL);
366     g_list_free(dlts);
367 }
368
369 static gboolean cb_dlt(extcap_callback_info_t cb_info)
370 {
371     GList *dlts = NULL, *temp = NULL;
372
373     if_capabilities_t *caps;
374     GList *linktype_list = NULL;
375     data_link_info_t *data_link_info;
376     extcap_dlt *dlt_item;
377
378     dlts = extcap_parse_dlts(cb_info.output);
379     temp = dlts;
380
381     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", cb_info.extcap);
382
383     /*
384      * Allocate the interface capabilities structure.
385      */
386     caps = (if_capabilities_t *) g_malloc(sizeof * caps);
387     caps->can_set_rfmon = FALSE;
388     caps->timestamp_types = NULL;
389
390     while (dlts)
391     {
392         dlt_item = (extcap_dlt *)dlts->data;
393         if (dlt_item)
394         {
395             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
396                   "  DLT %d name=\"%s\" display=\"%s\" ", dlt_item->number,
397                   dlt_item->name, dlt_item->display);
398
399             data_link_info = g_new(data_link_info_t, 1);
400             data_link_info->dlt = dlt_item->number;
401             data_link_info->name = g_strdup(dlt_item->name);
402             data_link_info->description = g_strdup(dlt_item->display);
403             linktype_list = g_list_append(linktype_list, data_link_info);
404         }
405
406         dlts = g_list_next(dlts);
407     }
408
409     /* Check to see if we built a list */
410     if (linktype_list != NULL && cb_info.data != NULL)
411     {
412         caps->data_link_types = linktype_list;
413         *(if_capabilities_t **) cb_info.data = caps;
414     }
415     else
416     {
417         if (cb_info.err_str)
418         {
419             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  returned no DLTs");
420             *(cb_info.err_str) = g_strdup("Extcap returned no DLTs");
421         }
422         g_free(caps);
423     }
424
425     extcap_free_dlts(temp);
426
427     return FALSE;
428 }
429
430 if_capabilities_t *
431 extcap_get_if_dlts(const gchar *ifname, char **err_str)
432 {
433     GList * arguments = NULL;
434     if_capabilities_t *caps = NULL;
435
436     if (err_str != NULL)
437     {
438         *err_str = NULL;
439     }
440
441     if (extcap_if_exists(ifname))
442     {
443         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_LIST_DLTS) );
444         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_INTERFACE) );
445         arguments = g_list_append(arguments, g_strdup(ifname) );
446
447         extcap_callback_info_t cb_info;
448         cb_info.data = &caps;
449         cb_info.err_str = err_str;
450         cb_info.ifname = ifname;
451
452         extcap_foreach(arguments, cb_dlt, cb_info);
453
454         g_list_free_full(arguments, g_free);
455     }
456
457     return caps;
458 }
459
460 static void extcap_free_interface(gpointer i)
461 {
462
463     extcap_interface *interface = (extcap_interface *)i;
464
465     if (i == NULL)
466     {
467         return;
468     }
469
470     g_free(interface->call);
471     g_free(interface->display);
472     g_free(interface->version);
473     g_free(interface->help);
474     g_free(interface->extcap_path);
475     g_free(interface);
476 }
477
478 static void extcap_free_interfaces(GList *interfaces)
479 {
480     if (interfaces == NULL)
481     {
482         return;
483     }
484
485     g_list_foreach(interfaces, (GFunc)extcap_free_interface, NULL);
486     g_list_free(interfaces);
487 }
488
489 static gint
490 if_info_compare(gconstpointer a, gconstpointer b)
491 {
492     gint comp = 0;
493     const if_info_t *if_a = (const if_info_t *)a;
494     const if_info_t *if_b = (const if_info_t *)b;
495
496     if ((comp = g_strcmp0(if_a->name, if_b->name)) == 0)
497     {
498         return g_strcmp0(if_a->friendly_name, if_b->friendly_name);
499     }
500
501     return comp;
502 }
503
504 gchar *
505 extcap_get_help_for_ifname(const char *ifname)
506 {
507     extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
508     return interface != NULL ? interface->help : NULL;
509 }
510
511 GList *
512 append_extcap_interface_list(GList *list, char **err_str _U_)
513 {
514     GList *interface_list = NULL;
515     extcap_interface *data = NULL;
516     GList *ifutilkeys_head = NULL, *ifutilkeys = NULL;
517
518     if (prefs.capture_no_extcap)
519         return list;
520
521     /* Update the extcap interfaces and get a list of their if_infos */
522     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
523         extcap_load_interface_list();
524
525     ifutilkeys_head = g_hash_table_get_keys(_loaded_interfaces);
526     ifutilkeys = ifutilkeys_head;
527     while ( ifutilkeys && ifutilkeys->data )
528     {
529         extcap_info * extinfo =
530                 (extcap_info *) g_hash_table_lookup(_loaded_interfaces, (gchar *)ifutilkeys->data);
531         GList * walker = extinfo->interfaces;
532         while ( walker && walker->data )
533         {
534             interface_list = g_list_append(interface_list, walker->data);
535             walker = g_list_next(walker);
536         }
537
538         ifutilkeys = g_list_next(ifutilkeys);
539     }
540     g_list_free(ifutilkeys_head);
541
542     /* Sort that list */
543     interface_list = g_list_sort(interface_list, if_info_compare);
544
545     /* Append the interfaces in that list to the list we're handed. */
546     while (interface_list != NULL)
547     {
548         GList *entry = g_list_first(interface_list);
549         data = (extcap_interface *)entry->data;
550         interface_list = g_list_delete_link(interface_list, entry);
551
552         if_info_t * if_info = g_new0(if_info_t, 1);
553         if_info->name = g_strdup(data->call);
554         if_info->friendly_name = g_strdup(data->display);
555
556         if_info->type = IF_EXTCAP;
557
558         if_info->extcap = g_strdup(data->extcap_path);
559
560         list = g_list_append(list, if_info);
561     }
562
563     return list;
564 }
565
566 static void
567 extcap_register_preferences_callback(gpointer key, gpointer value _U_, gpointer user_data _U_)
568 {
569     GList *arguments;
570
571     arguments = extcap_get_if_configuration((gchar *)key);
572     /* Memory for prefs are external to an interface, they are part of
573      * extcap core, so the parsed arguments can be freed. */
574     extcap_free_if_configuration(arguments, TRUE);
575 }
576
577 void extcap_register_preferences(void)
578 {
579     if (prefs.capture_no_extcap)
580         return;
581
582     module_t *dev_module = prefs_find_module("extcap");
583
584     if (!dev_module)
585     {
586         return;
587     }
588
589     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
590         extcap_load_interface_list();
591
592
593     g_hash_table_foreach(_tool_for_ifname, extcap_register_preferences_callback, NULL);
594 }
595
596 /**
597  * Releases the dynamic preference value pointers. Must not be called before
598  * prefs_cleanup since these pointers could still be in use.
599  */
600 void extcap_cleanup(void)
601 {
602     if (extcap_prefs_dynamic_vals)
603         g_hash_table_destroy(extcap_prefs_dynamic_vals);
604
605     if (_loaded_interfaces)
606         g_hash_table_destroy(_loaded_interfaces);
607
608     if (_tool_for_ifname)
609         g_hash_table_destroy(_tool_for_ifname);
610 }
611
612 /**
613  * Obtains a pointer which can store a value for the given preference name.
614  * The preference name that can be passed to the prefs API is stored into
615  * 'prefs_name'.
616  *
617  * Extcap interfaces (and their preferences) are dynamic, they can be created
618  * and destroyed at will. Thus their data structures are insufficient to pass to
619  * the preferences APIs which require pointers which are valid until the
620  * preferences are removed (at exit).
621  */
622 static gchar **extcap_prefs_dynamic_valptr(const char *name, char **pref_name)
623 {
624     gchar **valp;
625     if (!extcap_prefs_dynamic_vals)
626     {
627         /* Initialize table only as needed, most preferences are not dynamic */
628         extcap_prefs_dynamic_vals = g_hash_table_new_full(g_str_hash, g_str_equal,
629                                     g_free, g_free);
630     }
631     if (!g_hash_table_lookup_extended(extcap_prefs_dynamic_vals, name,
632                                       (gpointer *)pref_name, (gpointer *)&valp))
633     {
634         /* New dynamic pref, allocate, initialize and store. */
635         valp = g_new0(gchar *, 1);
636         *pref_name = g_strdup(name);
637         g_hash_table_insert(extcap_prefs_dynamic_vals, *pref_name, valp);
638     }
639     return valp;
640 }
641
642 void extcap_free_if_configuration(GList *list, gboolean free_args)
643 {
644     GList *elem, *sl;
645
646     for (elem = g_list_first(list); elem; elem = elem->next)
647     {
648         if (elem->data != NULL)
649         {
650             sl = g_list_first((GList *)elem->data);
651             if (free_args)
652             {
653                 extcap_free_arg_list(sl);
654             }
655             else
656             {
657                 g_list_free(sl);
658             }
659         }
660     }
661     g_list_free(list);
662 }
663
664 struct preference *
665 extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg *arg)
666 {
667     struct preference *pref = NULL;
668
669     GRegex *regex_name = g_regex_new("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
670     GRegex *regex_ifname = g_regex_new("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
671     if (regex_name && regex_ifname)
672     {
673         if (prefs_find_module("extcap"))
674         {
675             gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
676             gchar *ifname_underscore = g_regex_replace(regex_ifname, ifname, strlen(ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
677             gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
678             gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
679
680             pref = prefs_find_preference(prefs_find_module("extcap"), pref_ifname);
681
682             g_free(pref_name);
683             g_free(ifname_underscore);
684             g_free(ifname_lowercase);
685             g_free(pref_ifname);
686         }
687     }
688     if (regex_name)
689     {
690         g_regex_unref(regex_name);
691     }
692     if (regex_ifname)
693     {
694         g_regex_unref(regex_ifname);
695     }
696
697     return pref;
698 }
699
700 static gboolean cb_preference(extcap_callback_info_t cb_info)
701 {
702     GList *arguments = NULL;
703     GList **il = (GList **) cb_info.data;
704     module_t *dev_module = NULL;
705
706     arguments = extcap_parse_args(cb_info.output);
707
708     dev_module = prefs_find_module("extcap");
709
710     if (dev_module)
711     {
712         GList *walker = arguments;
713
714         GRegex *regex_name = g_regex_new("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
715         GRegex *regex_ifname = g_regex_new("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
716         if (regex_name && regex_ifname)
717         {
718             while (walker != NULL)
719             {
720                 extcap_arg *arg = (extcap_arg *)walker->data;
721                 arg->device_name = g_strdup(cb_info.ifname);
722
723                 if (arg->save)
724                 {
725                     struct preference *pref = NULL;
726
727                     gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
728                     gchar *ifname_underscore = g_regex_replace(regex_ifname, cb_info.ifname, strlen(cb_info.ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
729                     gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
730                     gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
731
732                     if ((pref = prefs_find_preference(dev_module, pref_ifname)) == NULL)
733                     {
734                         char *pref_name_for_prefs;
735                         char *pref_title = wmem_strdup(wmem_epan_scope(), arg->display);
736
737                         arg->pref_valptr = extcap_prefs_dynamic_valptr(pref_ifname, &pref_name_for_prefs);
738                         /* Set an initial value if any (the string will be copied at registration) */
739                         if (arg->default_complex)
740                         {
741                             *arg->pref_valptr = arg->default_complex->_val;
742                         }
743
744                         prefs_register_string_preference(dev_module, pref_name_for_prefs,
745                                                          pref_title, pref_title, (const char **)arg->pref_valptr);
746                     }
747                     else
748                     {
749                         /* Been here before, restore stored value */
750                         if (arg->pref_valptr == NULL)
751                         {
752                             arg->pref_valptr = (gchar**)g_hash_table_lookup(extcap_prefs_dynamic_vals, pref_ifname);
753                         }
754                     }
755
756                     g_free(pref_name);
757                     g_free(ifname_underscore);
758                     g_free(ifname_lowercase);
759                     g_free(pref_ifname);
760                 }
761
762                 walker = g_list_next(walker);
763             }
764         }
765         if (regex_name)
766         {
767             g_regex_unref(regex_name);
768         }
769         if (regex_ifname)
770         {
771             g_regex_unref(regex_ifname);
772         }
773     }
774
775     *il = g_list_append(*il, arguments);
776
777     /* By returning false, extcap_foreach will break on first found */
778     return TRUE;
779 }
780
781 GList *
782 extcap_get_if_configuration(const char *ifname)
783 {
784     GList * arguments = NULL;
785     GList *ret = NULL;
786     gchar **err_str = NULL;
787
788     if (extcap_if_exists(ifname))
789     {
790         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
791               get_extcap_dir());
792
793         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_CONFIG) );
794         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_INTERFACE) );
795         arguments = g_list_append(arguments, g_strdup(ifname) );
796
797         extcap_callback_info_t cb_info;
798         cb_info.data = &ret;
799         cb_info.err_str = err_str;
800         cb_info.ifname = ifname;
801
802         extcap_foreach(arguments, cb_preference, cb_info);
803
804         g_list_free_full(arguments, g_free);
805     }
806
807     return ret;
808 }
809
810 /**
811  * If is_required is FALSE: returns TRUE if the extcap interface has
812  * configurable options.
813  * If is_required is TRUE: returns TRUE when the extcap interface has
814  * configurable options that required modification. (For example, when an
815  * argument is required but empty.)
816  */
817 gboolean
818 extcap_has_configuration(const char *ifname, gboolean is_required)
819 {
820     GList *arguments = 0;
821     GList *walker = 0, * item = 0;
822
823     gboolean found = FALSE;
824
825     arguments = extcap_get_if_configuration((const char *)(ifname));
826     walker = g_list_first(arguments);
827
828     while (walker != NULL && !found)
829     {
830         item = g_list_first((GList *)(walker->data));
831         while (item != NULL && !found)
832         {
833             if ((extcap_arg *)(item->data) != NULL)
834             {
835                 extcap_arg *arg = (extcap_arg *)(item->data);
836                 /* Should required options be present, or any kind of options */
837                 if (!is_required)
838                 {
839                     found = TRUE;
840                 }
841                 else if (arg->is_required)
842                 {
843                     const gchar *stored = NULL;
844                     const gchar *defval = NULL;
845
846                     if (arg->pref_valptr != NULL)
847                     {
848                         stored = *arg->pref_valptr;
849                     }
850
851                     if (arg->default_complex != NULL && arg->default_complex->_val != NULL)
852                     {
853                         defval = arg->default_complex->_val;
854                     }
855
856                     if (arg->is_required)
857                     {
858                         /* If stored and defval is identical and the argument is required,
859                          * configuration is needed */
860                         if (defval && stored && g_strcmp0(stored, defval) == 0)
861                         {
862                             found = TRUE;
863                         }
864                         else if (!defval && (!stored || !*stored))
865                         {
866                             found = TRUE;
867                         }
868                     }
869
870                     if (arg->arg_type == EXTCAP_ARG_FILESELECT)
871                     {
872                         if (arg->fileexists && !(file_exists(defval) || file_exists(stored)))
873                         {
874                             found = TRUE;
875                         }
876                     }
877                 }
878             }
879
880             item = item->next;
881         }
882         walker = walker->next;
883     }
884     extcap_free_if_configuration(arguments, TRUE);
885
886     return found;
887 }
888
889 static gboolean cb_verify_filter(extcap_callback_info_t cb_info)
890 {
891     extcap_filter_status *status = (extcap_filter_status *)cb_info.data;
892     size_t output_size, i;
893
894     output_size = strlen(cb_info.output);
895     if (output_size == 0) {
896         *status = EXTCAP_FILTER_VALID;
897     } else {
898         *status = EXTCAP_FILTER_INVALID;
899         for (i = 0; i < output_size; i++) {
900             if (cb_info.output[i] == '\n' || cb_info.output[i] == '\r') {
901                 cb_info.output[i] = '\0';
902                 break;
903             }
904         }
905         *cb_info.err_str = g_strdup(cb_info.output);
906     }
907
908     return TRUE;
909 }
910
911 extcap_filter_status
912 extcap_verify_capture_filter(const char *ifname, const char *filter, gchar **err_str)
913 {
914     GList * arguments = NULL;
915     extcap_filter_status status = EXTCAP_FILTER_UNKNOWN;
916
917     if (extcap_if_exists(ifname))
918     {
919         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
920               get_extcap_dir());
921
922         arguments = g_list_append(arguments, EXTCAP_ARGUMENT_CAPTURE_FILTER);
923         arguments = g_list_append(arguments, g_strdup(filter));
924         arguments = g_list_append(arguments, EXTCAP_ARGUMENT_INTERFACE);
925         arguments = g_list_append(arguments, g_strdup(ifname));
926
927         extcap_callback_info_t cb_info;
928         cb_info.data = &status;
929         cb_info.err_str = err_str;
930         cb_info.ifname = ifname;
931
932         extcap_foreach(arguments, cb_verify_filter, cb_info);
933         g_list_free_full(arguments, g_free);
934     }
935
936     return status;
937 }
938
939 gboolean
940 extcap_has_toolbar(const char *ifname)
941 {
942     if (!iface_toolbar_use())
943     {
944         return FALSE;
945     }
946
947     GList *toolbar_list = g_hash_table_get_values (_toolbars);
948     for (GList *walker = toolbar_list; walker; walker = walker->next)
949     {
950         iface_toolbar *toolbar = (iface_toolbar *) walker->data;
951         if (g_list_find_custom(toolbar->ifnames, ifname, (GCompareFunc) strcmp))
952         {
953             return TRUE;
954         }
955     }
956
957     return FALSE;
958 }
959
960 void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
961 {
962     interface_options *interface_opts;
963     ws_pipe_t *pipedata;
964     guint icnt = 0;
965     gboolean overwrite_exitcode;
966     gchar *buffer;
967 #define STDERR_BUFFER_SIZE 1024
968
969     for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++)
970     {
971         interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
972                                        icnt);
973
974         /* skip native interfaces */
975         if (interface_opts->if_type != IF_EXTCAP)
976         {
977             continue;
978         }
979
980         overwrite_exitcode = FALSE;
981
982         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
983               "Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts->name,
984               interface_opts->extcap_fifo, interface_opts->extcap_pid);
985 #ifdef _WIN32
986         if (interface_opts->extcap_pipe_h != INVALID_HANDLE_VALUE)
987         {
988             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
989                   "Extcap [%s] - Closing pipe", interface_opts->name);
990             FlushFileBuffers(interface_opts->extcap_pipe_h);
991             DisconnectNamedPipe(interface_opts->extcap_pipe_h);
992             CloseHandle(interface_opts->extcap_pipe_h);
993             interface_opts->extcap_pipe_h = INVALID_HANDLE_VALUE;
994         }
995         if (interface_opts->extcap_control_in_h != INVALID_HANDLE_VALUE)
996         {
997             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
998                   "Extcap [%s] - Closing control_in pipe", interface_opts->name);
999             FlushFileBuffers(interface_opts->extcap_control_in_h);
1000             DisconnectNamedPipe(interface_opts->extcap_control_in_h);
1001             CloseHandle(interface_opts->extcap_control_in_h);
1002             interface_opts->extcap_control_in_h = INVALID_HANDLE_VALUE;
1003         }
1004         if (interface_opts->extcap_control_out_h != INVALID_HANDLE_VALUE)
1005         {
1006             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1007                   "Extcap [%s] - Closing control_out pipe", interface_opts->name);
1008             FlushFileBuffers(interface_opts->extcap_control_out_h);
1009             DisconnectNamedPipe(interface_opts->extcap_control_out_h);
1010             CloseHandle(interface_opts->extcap_control_out_h);
1011             interface_opts->extcap_control_out_h = INVALID_HANDLE_VALUE;
1012         }
1013 #else
1014         if (interface_opts->extcap_fifo != NULL && file_exists(interface_opts->extcap_fifo))
1015         {
1016             /* the fifo will not be freed here, but with the other capture_opts in capture_sync */
1017             ws_unlink(interface_opts->extcap_fifo);
1018             interface_opts->extcap_fifo = NULL;
1019         }
1020         if (interface_opts->extcap_control_in && file_exists(interface_opts->extcap_control_in))
1021         {
1022             ws_unlink(interface_opts->extcap_control_in);
1023             interface_opts->extcap_control_in = NULL;
1024         }
1025         if (interface_opts->extcap_control_out && file_exists(interface_opts->extcap_control_out))
1026         {
1027             ws_unlink(interface_opts->extcap_control_out);
1028             interface_opts->extcap_control_out = NULL;
1029         }
1030 #endif
1031         /* Maybe the client closed and removed fifo, but ws should check if
1032          * pid should be closed */
1033         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1034               "Extcap [%s] - Closing spawned PID: %d", interface_opts->name,
1035               interface_opts->extcap_pid);
1036
1037         pipedata = (ws_pipe_t *) interface_opts->extcap_pipedata;
1038         if (pipedata)
1039         {
1040             if (pipedata->stderr_fd > 0 && ws_pipe_data_available(pipedata->stderr_fd))
1041             {
1042                 buffer = (gchar *)g_malloc0(STDERR_BUFFER_SIZE + 1);
1043                 ws_read_string_from_pipe(ws_get_pipe_handle(pipedata->stderr_fd), buffer, STDERR_BUFFER_SIZE + 1);
1044                 if (strlen(buffer) > 0)
1045                 {
1046                     pipedata->stderr_msg = g_strdup_printf("%s", buffer);
1047                     pipedata->exitcode = 1;
1048                 }
1049                 g_free(buffer);
1050             }
1051
1052 #ifndef _WIN32
1053             /* Final child watch may not have been called */
1054             if (interface_opts->extcap_child_watch != 0)
1055             {
1056                 extcap_child_watch_cb(pipedata->pid, 0, capture_opts);
1057                 /* it will have changed in extcap_child_watch_cb */
1058                 interface_opts = &g_array_index(capture_opts->ifaces, interface_options,
1059                                                icnt);
1060             }
1061 #endif
1062
1063             if (pipedata->stderr_msg != NULL)
1064             {
1065                 overwrite_exitcode = TRUE;
1066             }
1067
1068             if (overwrite_exitcode || pipedata->exitcode != 0)
1069             {
1070                 if (pipedata->stderr_msg != 0)
1071                 {
1072                     if (*errormsg == NULL)
1073                     {
1074                         *errormsg = g_strdup_printf("Error by extcap pipe: %s", pipedata->stderr_msg);
1075                     }
1076                     else
1077                     {
1078                         gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , pipedata->stderr_msg, NULL);
1079                         g_free(*errormsg);
1080                         *errormsg = temp;
1081                     }
1082                     g_free(pipedata->stderr_msg);
1083                 }
1084
1085                 pipedata->stderr_msg = NULL;
1086                 pipedata->exitcode = 0;
1087             }
1088         }
1089
1090         if (interface_opts->extcap_child_watch > 0)
1091         {
1092             g_source_remove(interface_opts->extcap_child_watch);
1093             interface_opts->extcap_child_watch = 0;
1094         }
1095
1096         if (interface_opts->extcap_pid != WS_INVALID_PID)
1097         {
1098 #ifdef _WIN32
1099             TerminateProcess(interface_opts->extcap_pid, 0);
1100 #endif
1101             g_spawn_close_pid(interface_opts->extcap_pid);
1102             interface_opts->extcap_pid = WS_INVALID_PID;
1103
1104             g_free(interface_opts->extcap_pipedata);
1105             interface_opts->extcap_pipedata = NULL;
1106         }
1107     }
1108 }
1109
1110 static gboolean
1111 extcap_add_arg_and_remove_cb(gpointer key, gpointer value, gpointer data)
1112 {
1113     GPtrArray *args = (GPtrArray *)data;
1114
1115     if (key != NULL)
1116     {
1117         g_ptr_array_add(args, g_strdup((const gchar *)key));
1118
1119         if (value != NULL)
1120         {
1121             g_ptr_array_add(args, g_strdup((const gchar *)value));
1122         }
1123
1124         return TRUE;
1125     }
1126
1127     return FALSE;
1128 }
1129
1130 void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
1131 {
1132     guint i;
1133     interface_options *interface_opts;
1134     ws_pipe_t *pipedata = NULL;
1135     capture_options *capture_opts = (capture_options *)(user_data);
1136
1137     if (capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0)
1138     {
1139         return;
1140     }
1141
1142     /* Close handle to child process. */
1143     g_spawn_close_pid(pid);
1144
1145     /* Update extcap_pid in interface options structure. */
1146     for (i = 0; i < capture_opts->ifaces->len; i++)
1147     {
1148         interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
1149         if (interface_opts->extcap_pid == pid)
1150         {
1151             pipedata = (ws_pipe_t *)interface_opts->extcap_pipedata;
1152             if (pipedata != NULL)
1153             {
1154                 interface_opts->extcap_pid = WS_INVALID_PID;
1155                 pipedata->exitcode = 0;
1156 #ifndef _WIN32
1157                 if (WIFEXITED(status))
1158                 {
1159                     if (WEXITSTATUS(status) != 0)
1160                     {
1161                         pipedata->exitcode = WEXITSTATUS(status);
1162                     }
1163                 }
1164                 else
1165                 {
1166                     pipedata->exitcode = G_SPAWN_ERROR_FAILED;
1167                 }
1168 #else
1169                 if (status != 0)
1170                 {
1171                     pipedata->exitcode = status;
1172                 }
1173 #endif
1174                 if (status == 0 && pipedata->stderr_msg != NULL)
1175                 {
1176                     pipedata->exitcode = 1;
1177                 }
1178             }
1179             g_source_remove(interface_opts->extcap_child_watch);
1180             interface_opts->extcap_child_watch = 0;
1181             break;
1182         }
1183     }
1184 }
1185
1186 static
1187 GPtrArray *extcap_prepare_arguments(interface_options *interface_opts)
1188 {
1189     GPtrArray *result = NULL;
1190
1191     if (interface_opts->if_type == IF_EXTCAP)
1192     {
1193         result = g_ptr_array_new();
1194
1195 #define add_arg(X) g_ptr_array_add(result, g_strdup(X))
1196
1197         add_arg(interface_opts->extcap);
1198         add_arg(EXTCAP_ARGUMENT_RUN_CAPTURE);
1199         add_arg(EXTCAP_ARGUMENT_INTERFACE);
1200         add_arg(interface_opts->name);
1201         if (interface_opts->cfilter && strlen(interface_opts->cfilter) > 0)
1202         {
1203             add_arg(EXTCAP_ARGUMENT_CAPTURE_FILTER);
1204             add_arg(interface_opts->cfilter);
1205         }
1206         add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
1207         add_arg(interface_opts->extcap_fifo);
1208         if (interface_opts->extcap_control_in)
1209         {
1210             add_arg(EXTCAP_ARGUMENT_CONTROL_OUT);
1211             add_arg(interface_opts->extcap_control_in);
1212         }
1213         if (interface_opts->extcap_control_out)
1214         {
1215             add_arg(EXTCAP_ARGUMENT_CONTROL_IN);
1216             add_arg(interface_opts->extcap_control_out);
1217         }
1218         if (interface_opts->extcap_args == NULL || g_hash_table_size(interface_opts->extcap_args) == 0)
1219         {
1220             /* User did not perform interface configuration.
1221              *
1222              * Check if there are any boolean flags that are set by default
1223              * and hence their argument should be added.
1224              */
1225             GList *arglist;
1226             GList *elem;
1227
1228             arglist = extcap_get_if_configuration(interface_opts->name);
1229             for (elem = g_list_first(arglist); elem; elem = elem->next)
1230             {
1231                 GList *arg_list;
1232                 extcap_arg *arg_iter;
1233
1234                 if (elem->data == NULL)
1235                 {
1236                     continue;
1237                 }
1238
1239                 arg_list = g_list_first((GList *)elem->data);
1240                 while (arg_list != NULL)
1241                 {
1242                     const gchar *stored = NULL;
1243                     /* In case of boolflags only first element in arg_list is relevant. */
1244                     arg_iter = (extcap_arg *)(arg_list->data);
1245                     if (arg_iter->pref_valptr != NULL)
1246                     {
1247                         stored = *arg_iter->pref_valptr;
1248                     }
1249
1250                     if (arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG)
1251                     {
1252                         if (extcap_complex_get_bool(arg_iter->default_complex))
1253                         {
1254                             add_arg(arg_iter->call);
1255                         }
1256                         else if (g_strcmp0(stored, "true") == 0)
1257                         {
1258                             add_arg(arg_iter->call);
1259                         }
1260                     }
1261                     else
1262                     {
1263                         if (stored && strlen(stored) > 0) {
1264                             add_arg(arg_iter->call);
1265                             add_arg(stored);
1266                         }
1267                     }
1268
1269                     arg_list = arg_list->next;
1270                 }
1271             }
1272
1273             extcap_free_if_configuration(arglist, TRUE);
1274         }
1275         else
1276         {
1277             g_hash_table_foreach_remove(interface_opts->extcap_args, extcap_add_arg_and_remove_cb, result);
1278         }
1279         add_arg(NULL);
1280 #undef add_arg
1281
1282     }
1283
1284     return result;
1285 }
1286
1287 /* call mkfifo for each extcap,
1288  * returns FALSE if there's an error creating a FIFO */
1289 gboolean
1290 extcap_init_interfaces(capture_options *capture_opts)
1291 {
1292     guint i;
1293     interface_options *interface_opts;
1294     ws_pipe_t *pipedata;
1295
1296     for (i = 0; i < capture_opts->ifaces->len; i++)
1297     {
1298         GPtrArray *args = NULL;
1299         GPid pid = WS_INVALID_PID;
1300
1301         interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
1302
1303         /* skip native interfaces */
1304         if (interface_opts->if_type != IF_EXTCAP)
1305         {
1306             continue;
1307         }
1308
1309         /* create control pipes if having toolbar */
1310         if (extcap_has_toolbar(interface_opts->name))
1311         {
1312             extcap_create_pipe(interface_opts->name, &interface_opts->extcap_control_in,
1313                                EXTCAP_CONTROL_IN_PREFIX, FALSE);
1314 #ifdef _WIN32
1315             interface_opts->extcap_control_in_h = pipe_h;
1316 #endif
1317             extcap_create_pipe(interface_opts->name, &interface_opts->extcap_control_out,
1318                                EXTCAP_CONTROL_OUT_PREFIX, FALSE);
1319 #ifdef _WIN32
1320             interface_opts->extcap_control_out_h = pipe_h;
1321 #endif
1322         }
1323
1324         /* create pipe for fifo */
1325         if (!extcap_create_pipe(interface_opts->name, &interface_opts->extcap_fifo,
1326                                 EXTCAP_PIPE_PREFIX, TRUE))
1327         {
1328             return FALSE;
1329         }
1330 #ifdef _WIN32
1331         interface_opts->extcap_pipe_h = pipe_h;
1332 #endif
1333
1334         /* Create extcap call */
1335         args = extcap_prepare_arguments(interface_opts);
1336
1337         pipedata = g_new0(ws_pipe_t, 1);
1338
1339         pid = ws_pipe_spawn_async(pipedata, args);
1340
1341         g_ptr_array_foreach(args, (GFunc)g_free, NULL);
1342         g_ptr_array_free(args, TRUE);
1343
1344         if (pid == WS_INVALID_PID)
1345         {
1346             g_free(pipedata);
1347             continue;
1348         }
1349
1350         ws_close(pipedata->stdin_fd);
1351         interface_opts->extcap_pid = pid;
1352
1353         interface_opts->extcap_child_watch =
1354             g_child_watch_add(pid, extcap_child_watch_cb, (gpointer)capture_opts);
1355
1356 #ifdef _WIN32
1357         /* On Windows, wait for extcap to connect to named pipe.
1358          * Some extcaps will present UAC screen to user.
1359          * 30 second timeout should be reasonable timeout for extcap to
1360          * connect to named pipe (including user interaction).
1361          * Wait on multiple object in case of extcap termination
1362          * without opening pipe.
1363          */
1364         if (pid != WS_INVALID_PID)
1365         {
1366             HANDLE pipe_handles[3];
1367             int num_pipe_handles = 1;
1368             pipe_handles[0] = interface_opts->extcap_pipe_h;
1369
1370             if (extcap_has_toolbar(interface_opts->name))
1371             {
1372                 pipe_handles[1] = interface_opts->extcap_control_in_h;
1373                 pipe_handles[2] = interface_opts->extcap_control_out_h;
1374                 num_pipe_handles += 2;
1375              }
1376
1377             ws_pipe_wait_for_pipe(pipe_handles, num_pipe_handles, pid);
1378         }
1379 #endif
1380
1381         interface_opts->extcap_pipedata = (gpointer) pipedata;
1382     }
1383
1384     return TRUE;
1385 }
1386
1387 #ifdef _WIN32
1388 gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix, gboolean byte_mode)
1389 {
1390     gchar timestr[ 14 + 1 ];
1391     time_t current_time;
1392     gchar *pipename = NULL;
1393     SECURITY_ATTRIBUTES security;
1394
1395     /* create pipename */
1396     current_time = time(NULL);
1397     /*
1398      * XXX - we trust Windows not to return a time before the Epoch here,
1399      * so we won't get a null pointer back from localtime().
1400      */
1401     strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
1402     pipename = g_strconcat("\\\\.\\pipe\\", pipe_prefix, "_", ifname, "_", timestr, NULL);
1403
1404     /* Security struct to enable Inheritable HANDLE */
1405     memset(&security, 0, sizeof(SECURITY_ATTRIBUTES));
1406     security.nLength = sizeof(SECURITY_ATTRIBUTES);
1407     security.bInheritHandle = TRUE;
1408     security.lpSecurityDescriptor = NULL;
1409
1410     /* create a namedPipe */
1411     pipe_h = CreateNamedPipe(
1412                  utf_8to16(pipename),
1413                  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
1414                  (byte_mode ? (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT) :
1415                               (PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT)),
1416                  1, 65536, 65536,
1417                  300,
1418                  &security);
1419
1420     if (pipe_h == INVALID_HANDLE_VALUE)
1421     {
1422         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
1423         g_free (pipename);
1424         return FALSE;
1425     }
1426     else
1427     {
1428         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nWireshark Created pipe =>(%s)", pipename);
1429         *fifo = g_strdup(pipename);
1430     }
1431
1432     return TRUE;
1433 }
1434 #else
1435 gboolean extcap_create_pipe(const gchar *ifname, gchar **fifo, const gchar *pipe_prefix, gboolean byte_mode _U_)
1436 {
1437     gchar *temp_name = NULL;
1438     int fd = 0;
1439
1440     gchar *pfx = g_strconcat(pipe_prefix, "_", ifname, NULL);
1441     if ((fd = create_tempfile(&temp_name, pfx, NULL)) < 0)
1442     {
1443         g_free(pfx);
1444         return FALSE;
1445     }
1446     g_free(pfx);
1447
1448     ws_close(fd);
1449
1450     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1451           "Extcap - Creating fifo: %s", temp_name);
1452
1453     if (file_exists(temp_name))
1454     {
1455         ws_unlink(temp_name);
1456     }
1457
1458     if (mkfifo(temp_name, 0600) == 0)
1459     {
1460         *fifo = g_strdup(temp_name);
1461     }
1462
1463     return TRUE;
1464 }
1465 #endif
1466
1467 /************* EXTCAP LOAD INTERFACE LIST ***************
1468  *
1469  * The following code handles loading and reloading the interface list. It is explicitly
1470  * kept separate from the rest
1471  */
1472
1473
1474 static void
1475 extcap_free_interface_info(gpointer data)
1476 {
1477     extcap_info *info = (extcap_info *)data;
1478
1479     g_free(info->basename);
1480     g_free(info->full_path);
1481     g_free(info->version);
1482     g_free(info->help);
1483
1484     extcap_free_interfaces(info->interfaces);
1485
1486     g_free(info);
1487 }
1488
1489 static extcap_info *
1490 extcap_ensure_interface(const gchar * toolname, gboolean create_if_nonexist)
1491 {
1492     extcap_info * element = 0;
1493
1494     if ( prefs.capture_no_extcap )
1495         return NULL;
1496
1497     if ( ! toolname )
1498         return element;
1499
1500     if ( ! _loaded_interfaces )
1501         _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface);
1502
1503     element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname );
1504     if ( ! element && create_if_nonexist )
1505     {
1506         g_hash_table_insert(_loaded_interfaces, g_strdup(toolname), g_new0(extcap_info, 1));
1507         element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname );
1508     }
1509
1510     return element;
1511 }
1512
1513 extcap_info *
1514 extcap_get_tool_by_ifname(const gchar *ifname)
1515 {
1516     if ( ifname && _tool_for_ifname )
1517     {
1518         gchar * toolname = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
1519         if ( toolname )
1520             return extcap_ensure_interface(toolname, FALSE);
1521     }
1522
1523     return NULL;
1524 }
1525
1526 extcap_info *
1527 extcap_get_tool_info(const gchar * toolname)
1528 {
1529     return extcap_ensure_interface(toolname, FALSE);
1530 }
1531
1532 static void remove_extcap_entry(gpointer entry, gpointer data _U_)
1533 {
1534     extcap_interface *int_iter = (extcap_interface*)entry;
1535
1536     if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1537         extcap_free_interface(entry);
1538 }
1539
1540 static gboolean cb_load_interfaces(extcap_callback_info_t cb_info)
1541 {
1542     GList * interfaces = NULL, * control_items = NULL, * walker = NULL;
1543     extcap_interface * int_iter = NULL;
1544     extcap_info * element = NULL;
1545     iface_toolbar * toolbar_entry = NULL;
1546     gchar * toolname = g_path_get_basename(cb_info.extcap);
1547
1548     GList * interface_keys = g_hash_table_get_keys(_loaded_interfaces);
1549
1550     /* Load interfaces from utility */
1551     interfaces = extcap_parse_interfaces(cb_info.output, &control_items);
1552
1553     if (control_items)
1554     {
1555         toolbar_entry = g_new0(iface_toolbar, 1);
1556         toolbar_entry->controls = control_items;
1557     }
1558
1559     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Loading interface list for %s ", cb_info.extcap);
1560
1561     /* Seems, that there where no interfaces to be loaded */
1562     if ( ! interfaces || g_list_length(interfaces) == 0 )
1563     {
1564         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Cannot load interfaces for %s", cb_info.extcap );
1565         /* Some utilities, androiddump for example, may actually don't present any interfaces, even
1566          * if the utility itself is present. In such a case, we return here, but do not return
1567          * FALSE, or otherwise further loading of other utilities will be stopped */
1568         g_list_free(interface_keys);
1569         g_free(toolname);
1570         return TRUE;
1571     }
1572
1573     /* Load or create the storage element for the tool */
1574     element = extcap_ensure_interface(toolname, TRUE);
1575     if ( element == NULL )
1576     {
1577         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR, "Cannot store interface %s, maybe duplicate?", cb_info.extcap );
1578         g_list_foreach(interfaces, remove_extcap_entry, NULL);
1579         g_list_free(interfaces);
1580         g_list_free(interface_keys);
1581         g_free(toolname);
1582         return FALSE;
1583     }
1584
1585     walker = interfaces;
1586     gchar* help = NULL;
1587     while (walker != NULL)
1588     {
1589         int_iter = (extcap_interface *)walker->data;
1590
1591         if (int_iter->call != NULL)
1592             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Interface found %s\n", int_iter->call);
1593
1594         /* Help is not necessarily stored with the interface, but rather with the version string.
1595          * As the version string allways comes in front of the interfaces, this ensures, that it get's
1596          * properly stored with the interface */
1597         if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1598         {
1599             if (int_iter->call != NULL)
1600                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Extcap [%s] ", int_iter->call);
1601
1602             /* Only initialize values if none are set. Need to check only one element here */
1603             if ( ! element->version )
1604             {
1605                 element->version = g_strdup(int_iter->version);
1606                 element->basename = g_strdup(toolname);
1607                 element->full_path = g_strdup(cb_info.extcap);
1608                 element->help = g_strdup(int_iter->help);
1609             }
1610
1611             help = int_iter->help;
1612             if (toolbar_entry)
1613             {
1614                 toolbar_entry->menu_title = g_strdup(int_iter->display);
1615                 toolbar_entry->help = g_strdup(int_iter->help);
1616             }
1617
1618             walker = g_list_next(walker);
1619             continue;
1620         }
1621
1622         /* Only interface definitions will be parsed here. help is already set by the extcap element,
1623          * which makes it necessary to have version in the list before the interfaces. This is normally
1624          * the case by design, but could be changed by separating the information in extcap-base. */
1625         if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE )
1626         {
1627             if ( g_list_find(interface_keys, int_iter->call) )
1628             {
1629                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
1630                       int_iter->call, (gchar *)extcap_if_executable(int_iter->call));
1631                 walker = g_list_next(walker);
1632                 continue;
1633             }
1634
1635             if ((int_iter->call != NULL) && (int_iter->display))
1636                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Interface [%s] \"%s\" ", int_iter->call, int_iter->display);
1637
1638             int_iter->extcap_path = g_strdup(cb_info.extcap);
1639
1640             /* Only set the help, if it exists and no parsed help information is present */
1641             if ( ! int_iter->help && help )
1642                 int_iter->help = g_strdup(help);
1643
1644             element->interfaces = g_list_append(element->interfaces, int_iter);
1645             g_hash_table_insert(_tool_for_ifname, g_strdup(int_iter->call), g_strdup(toolname));
1646
1647             if (toolbar_entry)
1648             {
1649                 if (!toolbar_entry->menu_title)
1650                 {
1651                     toolbar_entry->menu_title = g_strdup(int_iter->display);
1652                 }
1653                 toolbar_entry->ifnames = g_list_append(toolbar_entry->ifnames, g_strdup(int_iter->call));
1654             }
1655         }
1656
1657         walker = g_list_next(walker);
1658     }
1659
1660     if (toolbar_entry && toolbar_entry->menu_title)
1661     {
1662         iface_toolbar_add(toolbar_entry);
1663         extcap_iface_toolbar_add(cb_info.extcap, toolbar_entry);
1664     }
1665
1666     g_list_foreach(interfaces, remove_extcap_entry, NULL);
1667     g_list_free(interfaces);
1668     g_list_free(interface_keys);
1669     g_free(toolname);
1670     return TRUE;
1671 }
1672
1673
1674 /* Handles loading of the interfaces.
1675  *
1676  * A list of interfaces can be obtained by calling \ref extcap_loaded_interfaces
1677  */
1678 static void
1679 extcap_load_interface_list(void)
1680 {
1681     gchar *error = NULL;
1682
1683     if (prefs.capture_no_extcap)
1684         return;
1685
1686     if (_toolbars)
1687     {
1688         // Remove existing interface toolbars here instead of in extcap_clear_interfaces()
1689         // to avoid flicker in shown toolbars when refreshing interfaces.
1690         GList *toolbar_list = g_hash_table_get_values (_toolbars);
1691         for (GList *walker = toolbar_list; walker; walker = walker->next)
1692         {
1693             iface_toolbar *toolbar = (iface_toolbar *) walker->data;
1694             iface_toolbar_remove(toolbar->menu_title);
1695         }
1696         g_hash_table_remove_all(_toolbars);
1697     } else {
1698         _toolbars = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_toolbar);
1699     }
1700
1701     if (_loaded_interfaces == NULL)
1702     {
1703         GList * arguments = NULL;
1704         int major = 0;
1705         int minor = 0;
1706
1707         _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface_info);
1708         /* Cleanup lookup table */
1709         if ( _tool_for_ifname )
1710         {
1711             g_hash_table_remove_all(_tool_for_ifname);
1712             _tool_for_ifname = 0;
1713         } else {
1714             _tool_for_ifname = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1715         }
1716
1717         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_LIST_INTERFACES));
1718         arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_VERSION));
1719
1720         get_ws_version_number(&major, &minor, NULL);
1721
1722         arguments = g_list_append(arguments, g_strdup_printf("%d.%d", major, minor));
1723
1724         extcap_callback_info_t cb_info;
1725         cb_info.data = NULL;
1726         cb_info.ifname = NULL;
1727         cb_info.err_str = &error;
1728
1729         extcap_foreach(arguments, cb_load_interfaces, cb_info);
1730
1731         /* Compatibility mode. Utility did not accept version argument, therefore we just ask for the interfaces
1732          * and assume, that the utility will handle compatibility on it's end */
1733         if ( ! cb_info.data )
1734         {
1735             g_free(error);
1736             error = NULL;
1737
1738             g_list_free_full(arguments, g_free);
1739             arguments = NULL;
1740
1741             arguments = g_list_append(arguments, g_strdup(EXTCAP_ARGUMENT_LIST_INTERFACES));
1742             extcap_foreach(arguments, cb_load_interfaces, cb_info);
1743         }
1744
1745         g_list_free_full(arguments, g_free);
1746     }
1747 }
1748
1749 /*
1750  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1751  *
1752  * Local variables:
1753  * c-basic-offset: 4
1754  * tab-width: 8
1755  * indent-tabs-mode: nil
1756  * End:
1757  *
1758  * vi: set shiftwidth=4 tabstop=8 expandtab:
1759  * :indentSize=4:tabSize=8:noTabs=true:
1760  */