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