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