Use *, not *.*, as the wildcard pattern on UN*X.
[metze/wireshark/wip.git] / extcap.c
1 /* extcap.h
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  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #ifdef _WIN32
32 #include <windows.h>
33 #include <process.h>
34 #include <time.h>
35 #else
36 /* Include for unlink */
37 #include <unistd.h>
38 #endif
39
40 #include <glib.h>
41 #include <log.h>
42
43 #include <epan/prefs.h>
44 #include <epan/prefs-int.h>
45
46 #include <wsutil/file_util.h>
47 #include <wsutil/filesystem.h>
48 #include <wsutil/tempfile.h>
49
50 #include "capture_opts.h"
51
52 #ifdef HAVE_EXTCAP
53
54 #include "extcap.h"
55 #include "extcap_parser.h"
56
57 #ifdef _WIN32
58 static HANDLE pipe_h = NULL;
59 #endif
60
61 /* internal container, for all the extcap interfaces that have been found.
62  * will be resetted by every call to extcap_interface_list() and is being
63  * used in extcap_get_if_* as well as extcap_init_interfaces to ensure,
64  * that only extcap interfaces are being given to underlying extcap programs
65  */
66 static GHashTable *ifaces = NULL;
67
68 /* internal container, for all the extcap executables that have been found.
69  * will be resetted by every call to extcap_interface_list() and is being
70  * used for printing information about all extcap interfaces found
71  */
72 static GHashTable *tools = NULL;
73
74 /* Callback definition for extcap_foreach */
75 typedef gboolean (*extcap_cb_t)(const gchar *extcap, const gchar *ifname, gchar *output, void *data,
76         gchar **err_str);
77
78 /* #define ARG_DEBUG */
79 #if ARG_DEBUG
80 static void extcap_debug_arguments ( extcap_arg *arg_iter );
81 #endif
82
83 static gboolean
84 extcap_if_exists(const gchar *ifname)
85 {
86     if ( !ifname || !ifaces )
87         return FALSE;
88
89     if ( g_hash_table_lookup(ifaces, ifname) )
90         return TRUE;
91
92     return FALSE;
93 }
94
95 static gboolean
96 extcap_if_exists_for_extcap(const gchar *ifname, const gchar *extcap)
97 {
98     gchar *entry = (gchar *)g_hash_table_lookup(ifaces, ifname);
99
100     if ( entry && strcmp(entry, extcap) == 0 )
101         return TRUE;
102
103     return FALSE;
104 }
105
106 static gchar *
107 extcap_if_executable(const gchar *ifname)
108 {
109     return (gchar *)g_hash_table_lookup(ifaces, ifname);
110 }
111
112 static void
113 extcap_if_add(const gchar *ifname, const gchar *extcap)
114 {
115     if ( !g_hash_table_lookup(ifaces, ifname) )
116         g_hash_table_insert(ifaces, g_strdup(ifname), g_strdup(extcap));
117 }
118
119 static void
120 extcap_free_info (gpointer data) {
121     extcap_info * info = (extcap_info *)data;
122
123     g_free (info->basename);
124     g_free (info->full_path);
125     g_free (info->version);
126     g_free (info);
127 }
128
129 static void
130 extcap_tool_add(const gchar *extcap, const extcap_interface *interface)
131 {
132     char *toolname;
133
134     if ( !extcap || !interface )
135         return;
136
137     toolname = g_path_get_basename(extcap);
138
139     if ( !g_hash_table_lookup(tools, toolname) ) {
140         extcap_info * store = (extcap_info *)g_new0(extcap_info, 1);
141         store->version = g_strdup(interface->version);
142         store->full_path = g_strdup(extcap);
143         store->basename = g_strdup(toolname);
144
145         g_hash_table_insert(tools, g_strdup(toolname), store);
146     }
147
148     g_free(toolname);
149 }
150
151 /* Note: args does not need to be NULL-terminated. */
152 static void extcap_foreach(gint argc, gchar **args, extcap_cb_t cb,
153         void *cb_data, char **err_str, const char * ifname _U_) {
154     const char *dirname = get_extcap_dir();
155     GDir *dir;
156     const gchar *file;
157     gboolean keep_going;
158     gint i;
159     gchar **argv;
160 #ifdef _WIN32
161     gchar **dll_search_envp;
162     gchar *progfile_dir;
163 #endif
164
165     keep_going = TRUE;
166
167     argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
168
169 #ifdef _WIN32
170     /*
171      * Make sure executables can find dependent DLLs and that they're *our*
172      * DLLs: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586.aspx
173      * Alternatively we could create a simple wrapper exe similar to Create
174      * Hidden Process (http://www.commandline.co.uk/chp/).
175      */
176     dll_search_envp = g_get_environ();
177     progfile_dir = g_strdup_printf("%s;%s", get_progfile_dir(), g_environ_getenv(dll_search_envp, "Path"));
178     dll_search_envp = g_environ_setenv(dll_search_envp, "Path", progfile_dir, TRUE);
179     g_free(progfile_dir);
180 #endif
181
182     if ((dir = g_dir_open(dirname, 0, NULL)) != NULL) {
183         GString *extcap_path = NULL;
184
185         extcap_path = g_string_new("");
186         while (keep_going && (file = g_dir_read_name(dir)) != NULL ) {
187             gchar *command_output = NULL;
188             gboolean status = FALSE;
189             gint exit_status = 0;
190             gchar **envp = NULL;
191
192             /* full path to extcap binary */
193 #ifdef _WIN32
194             g_string_printf(extcap_path, "%s\\%s", dirname, file);
195             envp = dll_search_envp;
196 #else
197             g_string_printf(extcap_path, "%s/%s", dirname, file);
198 #endif
199             if ( extcap_if_exists(ifname) && !extcap_if_exists_for_extcap(ifname, extcap_path->str ) )
200                 continue;
201
202 #ifdef _WIN32
203             argv[0] = g_strescape(extcap_path->str, NULL);
204 #else
205             argv[0] = g_strdup(extcap_path->str);
206 #endif
207             for (i = 0; i < argc; ++i)
208                 argv[i+1] = args[i];
209             argv[argc+1] = NULL;
210
211             status = g_spawn_sync(dirname, argv, envp,
212                 (GSpawnFlags) 0, NULL, NULL,
213                     &command_output, NULL, &exit_status, NULL);
214
215             if (status && exit_status == 0)
216             keep_going = cb(extcap_path->str, ifname, command_output, cb_data, err_str);
217
218             g_free(argv[0]);
219             g_free(command_output);
220         }
221
222         g_dir_close(dir);
223         g_string_free(extcap_path, TRUE);
224     }
225
226 #ifdef _WIN32
227     g_strfreev(dll_search_envp);
228 #endif
229     g_free(argv);
230 }
231
232 static gboolean dlt_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data,
233         char **err_str) {
234     extcap_token_sentence *tokens;
235     extcap_dlt *dlts, *dlt_iter, *next;
236     if_capabilities_t *caps;
237     GList *linktype_list = NULL;
238     data_link_info_t *data_link_info;
239
240     tokens = extcap_tokenize_sentences(output);
241     extcap_parse_dlts(tokens, &dlts);
242
243     extcap_free_tokenized_sentence_list(tokens);
244
245     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
246
247     /*
248      * Allocate the interface capabilities structure.
249      */
250     caps = (if_capabilities_t *) g_malloc(sizeof *caps);
251     caps->can_set_rfmon = FALSE;
252
253     dlt_iter = dlts;
254     while (dlt_iter != NULL ) {
255         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
256                 "  DLT %d name=\"%s\" display=\"%s\" ", dlt_iter->number,
257                 dlt_iter->name, dlt_iter->display);
258
259         data_link_info = g_new(data_link_info_t, 1);
260         data_link_info->dlt = dlt_iter->number;
261         data_link_info->name = g_strdup(dlt_iter->name);
262         data_link_info->description = g_strdup(dlt_iter->display);
263         linktype_list = g_list_append(linktype_list, data_link_info);
264         dlt_iter = dlt_iter->next_dlt;
265     }
266
267     /* Check to see if we built a list */
268     if (linktype_list != NULL && data != NULL) {
269         caps->data_link_types = linktype_list;
270         *(if_capabilities_t **) data = caps;
271     } else {
272         if (err_str) {
273             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  returned no DLTs");
274             *err_str = g_strdup("Extcap returned no DLTs");
275         }
276         g_free(caps);
277     }
278
279     dlt_iter = dlts;
280     while (dlt_iter != NULL ) {
281         next = dlt_iter->next_dlt;
282         extcap_free_dlt(dlt_iter);
283         dlt_iter = next;
284     }
285
286     return FALSE;
287 }
288
289 if_capabilities_t *
290 extcap_get_if_dlts(const gchar *ifname, char **err_str) {
291     gchar *argv[3];
292     gint i;
293     if_capabilities_t *caps = NULL;
294
295     if (err_str != NULL)
296         *err_str = NULL;
297
298     if ( extcap_if_exists(ifname) )
299     {
300         argv[0] = g_strdup(EXTCAP_ARGUMENT_LIST_DLTS);
301         argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
302         argv[2] = g_strdup(ifname);
303
304         extcap_foreach(3, argv, dlt_cb, &caps, err_str, ifname);
305
306         for (i = 0; i < 3; ++i)
307             g_free(argv[i]);
308     }
309
310     return caps;
311 }
312
313 static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gchar *output, void *data,
314         char **err_str _U_) {
315     GList **il = (GList **) data;
316     extcap_token_sentence *tokens;
317     extcap_interface *interfaces, *int_iter; /*, *next; */
318     if_info_t *if_info;
319
320     tokens = extcap_tokenize_sentences(output);
321     extcap_parse_interfaces(tokens, &interfaces);
322
323     extcap_free_tokenized_sentence_list(tokens);
324
325     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
326
327     int_iter = interfaces;
328     while (int_iter != NULL ) {
329         if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE && extcap_if_exists(int_iter->call) )
330         {
331             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
332                     int_iter->call, (gchar *)extcap_if_executable(int_iter->call) );
333             int_iter = int_iter->next_interface;
334             continue;
335         }
336
337         if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE )
338             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Interface [%s] \"%s\" ",
339                     int_iter->call, int_iter->display);
340         else if ( int_iter->if_type == EXTCAP_SENTENCE_EXTCAP )
341             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Extcap [%s] ", int_iter->call);
342
343         if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE ) {
344             if (il != NULL) {
345                 if_info = g_new0(if_info_t, 1);
346                 if_info->name = g_strdup(int_iter->call);
347                 if_info->friendly_name = g_strdup(int_iter->display);
348
349                 if_info->type = IF_EXTCAP;
350
351                 if_info->extcap = g_strdup(extcap);
352                 *il = g_list_append(*il, if_info);
353             }
354
355             extcap_if_add(int_iter->call, extcap);
356         }
357
358         /* Call for interfaces and tools alike. Multiple calls (because a tool has multiple
359          * interfaces) are handled internally */
360         extcap_tool_add(extcap, int_iter);
361
362         int_iter = int_iter->next_interface;
363     }
364     extcap_free_interface(interfaces);
365
366     return TRUE;
367 }
368
369 static gint
370 if_info_compare(gconstpointer a, gconstpointer b)
371 {
372     gint comp = 0;
373     if_info_t * if_a = (if_info_t *)a;
374     if_info_t * if_b = (if_info_t *)b;
375
376     if ( (comp = g_strcmp0(if_a->name, if_b->name)) == 0 )
377         return g_strcmp0(if_a->friendly_name, if_b->friendly_name);
378
379     return comp;
380 }
381
382 static void
383 extcap_reload_interface_list(GList **retp, char **err_str) {
384     gchar *argv;
385
386     if (err_str != NULL)
387         *err_str = NULL;
388
389     /* ifaces is used as cache, do not destroy its contents when
390      * returning or no extcap interfaces can be queried for options */
391     if (ifaces == NULL)
392         ifaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
393     else
394         g_hash_table_remove_all(ifaces);
395
396     if (tools == NULL)
397         tools = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_info);
398     else
399         g_hash_table_remove_all(tools);
400
401     argv = g_strdup(EXTCAP_ARGUMENT_LIST_INTERFACES);
402
403     extcap_foreach(1, &argv, interfaces_cb, retp, err_str, NULL);
404
405     g_free(argv);
406 }
407
408 GHashTable *
409 extcap_tools_list(void) {
410     if ( tools == NULL || g_hash_table_size(tools) == 0 )
411         extcap_reload_interface_list(NULL, NULL);
412
413     return tools;
414 }
415
416 GList *
417 append_extcap_interface_list(GList *list, char **err_str) {
418     GList *ret = NULL;
419     GList *entry;
420     void *data;
421
422     /* Update the extcap interfaces and get a list of their if_infos */
423     extcap_reload_interface_list(&ret, err_str);
424
425     /* Sort that list */
426     ret = g_list_sort(ret, if_info_compare);
427
428     /* Append the interfaces in that list to the list we're handed. */
429     while (ret != NULL) {
430         entry = g_list_first(ret);
431         data = entry->data;
432         ret = g_list_delete_link(ret, entry);
433         list = g_list_append(list, data);
434     }
435     return list;
436 }
437
438 static void extcap_free_arg_elem(gpointer data, gpointer user_data _U_) {
439     extcap_free_arg((extcap_arg *) data);
440     g_free(data);
441 }
442
443 void extcap_register_preferences(void)
444 {
445     GList * interfaces = NULL;
446
447     module_t * dev_module = prefs_find_module("extcap");
448
449     if ( !dev_module )
450         return;
451
452     if ( ! ifaces || g_hash_table_size(ifaces) == 0 )
453         extcap_reload_interface_list(NULL, NULL);
454
455     interfaces = g_hash_table_get_keys(ifaces);
456
457     while ( interfaces ) {
458         extcap_get_if_configuration((gchar *)interfaces->data);
459
460         interfaces = g_list_next(interfaces);
461     }
462 }
463
464 static void extcap_free_if_configuration(GList *list)
465 {
466     GList *elem, *sl;
467
468     for (elem = g_list_first(list); elem; elem = elem->next)
469     {
470         if (elem->data != NULL) {
471             /* g_list_free_full() only exists since 2.28. */
472             sl = g_list_first((GList *)elem->data);
473             g_list_foreach(sl, (GFunc)extcap_free_arg_elem, NULL);
474             g_list_free(sl);
475         }
476     }
477     g_list_free(list);
478 }
479
480 gchar * extcap_settings_key(const gchar * ifname, const gchar * setting)
481 {
482     gchar * setting_nohyphen;
483     gchar * ifname_underscore;
484     gchar * ifname_lower;
485     gchar * key;
486     GRegex * regex = g_regex_new ("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
487
488     if (!regex)
489         return NULL;
490
491     setting_nohyphen =
492         g_regex_replace_literal(regex, setting, strlen(setting), 0,
493             "", (GRegexMatchFlags) 0, NULL );
494     ifname_underscore =
495         g_regex_replace_literal(regex, ifname, strlen(ifname), 0,
496             "_", (GRegexMatchFlags) 0, NULL );
497     ifname_lower = g_utf8_strdown(ifname_underscore, -1);
498     key = g_strconcat(ifname_lower, ".", setting_nohyphen, NULL);
499
500     g_free(setting_nohyphen);
501     g_free(ifname_underscore);
502     g_free(ifname_lower);
503     g_regex_unref(regex);
504
505     return key;
506 }
507
508 static gboolean search_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data,
509         char **err_str _U_) {
510     extcap_token_sentence *tokens = NULL;
511     GList *arguments = NULL;
512     GList **il = (GList **) data;
513     module_t * dev_module = NULL;
514
515     tokens = extcap_tokenize_sentences(output);
516     arguments = extcap_parse_args(tokens);
517
518     extcap_free_tokenized_sentence_list(tokens);
519
520 #if ARG_DEBUG
521     extcap_debug_arguments ( arguments );
522 #endif
523
524     dev_module = prefs_find_module("extcap");
525
526     if ( dev_module ) {
527         GList * walker = arguments;
528
529         while ( walker != NULL ) {
530             extcap_arg * arg = (extcap_arg *)walker->data;
531
532             if ( arg->save ) {
533                 struct preference * pref = NULL;
534                 gchar * pref_ifname = extcap_settings_key(ifname, arg->call);
535
536                 if ( ( pref = prefs_find_preference(dev_module, pref_ifname) ) == NULL ) {
537                     /* Set an initial value */
538                     if ( ! arg->storeval && arg->default_complex )
539                         arg->storeval = g_strdup(arg->default_complex->_val);
540
541                     prefs_register_string_preference(dev_module, g_strdup(pref_ifname),
542                             arg->display, arg->display, (const gchar **)&(arg->storeval));
543                 } else {
544                     /* Been here before, restore stored value */
545                     if (! arg->storeval && pref->varp.string)
546                         arg->storeval = g_strdup(*(pref->varp.string));
547                     }
548                 g_free(pref_ifname);
549             }
550
551             walker = g_list_next(walker);
552         }
553     }
554
555     *il = g_list_append(*il, arguments);
556
557     /* By returning false, extcap_foreach will break on first found */
558     return TRUE;
559 }
560
561 GList *
562 extcap_get_if_configuration(const char * ifname) {
563     gchar *argv[3];
564     GList *ret = NULL;
565     gchar **err_str = NULL;
566     int i;
567
568     if ( extcap_if_exists(ifname) )
569     {
570         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
571                 get_extcap_dir());
572
573         argv[0] = g_strdup(EXTCAP_ARGUMENT_CONFIG);
574         argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
575         argv[2] = g_strdup(ifname);
576
577         extcap_foreach(3, argv, search_cb, &ret, err_str, ifname);
578
579         for (i = 0; i < 3; i++)
580             g_free(argv[i]);
581     }
582
583     return ret;
584 }
585
586 gboolean
587 extcap_has_configuration(const char * ifname, gboolean is_required) {
588     GList * arguments = 0;
589     GList * walker = 0, * item = 0;
590
591     gboolean found = FALSE;
592
593     arguments = extcap_get_if_configuration((const char *)( ifname ) );
594     walker = g_list_first(arguments);
595
596     while ( walker != NULL && ! found ) {
597         item = g_list_first((GList *)(walker->data));
598         while ( item != NULL && ! found ) {
599             if ( (extcap_arg *)(item->data) != NULL ) {
600                 extcap_arg * arg = (extcap_arg *)(item->data);
601                 /* Should required options be present, or any kind of options */
602                 if ( ! is_required )
603                     found = TRUE;
604                 else if ( arg->is_required ) {
605                     gchar * stored = NULL;
606                     gchar * defval = NULL;
607
608                     if ( arg->storeval != NULL )
609                         stored = arg->storeval;
610
611                     if ( arg->default_complex != NULL && arg->default_complex->_val != NULL )
612                         defval = arg->default_complex->_val;
613
614                     if ( arg->is_required ) {
615                         /* If stored and defval is identical and the argument is required,
616                          * configuration is needed */
617                         if ( defval && stored && g_strcmp0(stored, defval) == 0 )
618                             found = TRUE;
619                         else if ( ! defval && (!stored || strlen(g_strchomp(stored)) <= (size_t)0) )
620                             found = TRUE;
621                     }
622
623                     if ( arg->arg_type == EXTCAP_ARG_FILESELECT ) {
624                         if ( arg->fileexists && ! ( file_exists(defval) || file_exists(stored) ) )
625                             found = TRUE;
626                     }
627                 }
628             }
629
630             item = item->next;
631         }
632         walker = walker->next;
633     }
634     extcap_free_if_configuration(arguments);
635
636     return found;
637 }
638
639 void extcap_cleanup(capture_options * capture_opts) {
640     interface_options interface_opts;
641     guint icnt = 0;
642
643     for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++) {
644         interface_opts = g_array_index(capture_opts->ifaces, interface_options,
645                 icnt);
646
647         /* skip native interfaces */
648         if (interface_opts.if_type != IF_EXTCAP)
649         continue;
650
651         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
652                 "Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts.name,
653                 interface_opts.extcap_fifo, interface_opts.extcap_pid);
654 #ifdef _WIN32
655         if (pipe_h)
656         {
657             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
658                 "Extcap [%s] - Closing pipe", interface_opts.name);
659             FlushFileBuffers(pipe_h);
660             DisconnectNamedPipe(pipe_h);
661             CloseHandle(pipe_h);
662         }
663 #else
664         if (interface_opts.extcap_fifo != NULL && file_exists(interface_opts.extcap_fifo))
665         {
666             /* the fifo will not be freed here, but with the other capture_opts in capture_sync */
667             ws_unlink(interface_opts.extcap_fifo);
668             interface_opts.extcap_fifo = NULL;
669         }
670 #endif
671         /* Maybe the client closed and removed fifo, but ws should check if
672          * pid should be closed */
673         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
674                 "Extcap [%s] - Closing spawned PID: %d", interface_opts.name,
675                 interface_opts.extcap_pid);
676
677         if (interface_opts.extcap_pid != INVALID_EXTCAP_PID)
678         {
679 #ifdef _WIN32
680             TerminateProcess(interface_opts.extcap_pid, 0);
681 #endif
682             g_spawn_close_pid(interface_opts.extcap_pid);
683             interface_opts.extcap_pid = INVALID_EXTCAP_PID;
684         }
685
686         /* Make sure modified interface_opts is saved in capture_opts. */
687         capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, icnt);
688         g_array_insert_val(capture_opts->ifaces, icnt, interface_opts);
689     }
690 }
691
692 static gboolean
693 extcap_add_arg_and_remove_cb(gpointer key, gpointer value, gpointer data) {
694     GPtrArray *args = (GPtrArray *)data;
695
696     if ( key != NULL )
697     {
698         g_ptr_array_add(args, g_strdup((const gchar*)key));
699
700         if ( value != NULL )
701             g_ptr_array_add(args, g_strdup((const gchar*)value));
702
703         return TRUE;
704     }
705
706     return FALSE;
707 }
708
709 static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
710 {
711     guint i;
712     interface_options interface_opts;
713     capture_options *capture_opts = (capture_options *)user_data;
714
715     /* Close handle to child process. */
716     g_spawn_close_pid(pid);
717
718     /* Update extcap_pid in interface options structure. */
719     for (i = 0; i < capture_opts->ifaces->len; i++)
720     {
721         interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
722         if (interface_opts.extcap_pid == pid)
723         {
724             interface_opts.extcap_pid = INVALID_EXTCAP_PID;
725             g_source_remove(interface_opts.extcap_child_watch);
726             interface_opts.extcap_child_watch = 0;
727
728             capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
729             g_array_insert_val(capture_opts->ifaces, i, interface_opts);
730             break;
731         }
732     }
733 }
734
735 /* call mkfifo for each extcap,
736  * returns FALSE if there's an error creating a FIFO */
737 gboolean
738 extcap_init_interfaces(capture_options *capture_opts)
739 {
740     guint i;
741     interface_options interface_opts;
742
743     for (i = 0; i < capture_opts->ifaces->len; i++)
744     {
745         GPtrArray *args = NULL;
746         GPid pid = INVALID_EXTCAP_PID;
747         gchar **tmp;
748         int tmp_i;
749
750         interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
751
752         /* skip native interfaces */
753         if (interface_opts.if_type != IF_EXTCAP )
754             continue;
755
756         /* create pipe for fifo */
757         if ( ! extcap_create_pipe ( &interface_opts.extcap_fifo ) )
758             return FALSE;
759
760         /* Create extcap call */
761         args = g_ptr_array_new();
762 #define add_arg(X) g_ptr_array_add(args, g_strdup(X))
763
764         add_arg(interface_opts.extcap);
765         add_arg(EXTCAP_ARGUMENT_RUN_CAPTURE);
766         add_arg(EXTCAP_ARGUMENT_INTERFACE);
767         add_arg(interface_opts.name);
768         if (interface_opts.cfilter && strlen(interface_opts.cfilter) > 0) {
769             add_arg(EXTCAP_ARGUMENT_CAPTURE_FILTER);
770             add_arg(interface_opts.cfilter);
771         }
772         add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
773         add_arg(interface_opts.extcap_fifo);
774         if (interface_opts.extcap_args == NULL || g_hash_table_size(interface_opts.extcap_args) == 0)
775         {
776             /* User did not perform interface configuration.
777              *
778              * Check if there are any boolean flags that are set by default
779              * and hence their argument should be added.
780              */
781             GList *arglist;
782             GList *elem;
783
784             arglist = extcap_get_if_configuration(interface_opts.name);
785             for (elem = g_list_first(arglist); elem; elem = elem->next)
786             {
787                 GList * arg_list;
788                 extcap_arg *arg_iter;
789
790                 if (elem->data == NULL)
791                 {
792                     continue;
793                 }
794
795                 arg_list = g_list_first((GList *)elem->data);
796                 while (arg_list != NULL) {
797                     gchar * stored = NULL, * defval = NULL;
798                     /* In case of boolflags only first element in arg_list is relevant. */
799                     arg_iter = (extcap_arg*) (arg_list->data);
800                     if ( arg_iter->storeval != NULL )
801                         stored = arg_iter->storeval;
802
803                     if ( arg_iter->default_complex != NULL && arg_iter->default_complex->_val != NULL )
804                         defval = arg_iter->default_complex->_val;
805
806                     /* Different data in storage then set for default */
807                     if ( g_strcmp0(stored, defval) != 0 ) {
808                         if ( arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG ) {
809                             if ( g_strcmp0(stored, "true") == 0 )
810                                 add_arg(arg_iter->call);
811                         } else {
812                             gchar * call = g_strconcat(arg_iter->call, " ", stored, NULL);
813                             add_arg(call);
814                             g_free(call);
815                         }
816                     } else if  (arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG) {
817                         if (extcap_complex_get_bool(arg_iter->default_complex))
818                             add_arg(arg_iter->call);
819                     }
820
821                     arg_list = arg_list->next;
822                 }
823             }
824
825             extcap_free_if_configuration(arglist);
826         }
827         else
828         {
829             g_hash_table_foreach_remove(interface_opts.extcap_args, extcap_add_arg_and_remove_cb, args);
830         }
831         add_arg(NULL);
832 #undef add_arg
833
834         /* Dump commandline parameters sent to extcap. */
835         for (tmp = (gchar **)args->pdata, tmp_i = 0; *tmp && **tmp; ++tmp_i, ++tmp)
836         {
837             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "argv[%d]: %s", tmp_i, *tmp);
838         }
839
840         /* Wireshark for windows crashes here sometimes *
841          * Access violation reading location 0x...      */
842         g_spawn_async(NULL, (gchar **)args->pdata, NULL,
843                     (GSpawnFlags) G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
844                     &pid,NULL);
845
846         g_ptr_array_foreach(args, (GFunc)g_free, NULL);
847         g_ptr_array_free(args, TRUE);
848         interface_opts.extcap_pid = pid;
849         interface_opts.extcap_child_watch =
850             g_child_watch_add(pid, extcap_child_watch_cb, (gpointer)capture_opts);
851         capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
852         g_array_insert_val(capture_opts->ifaces, i, interface_opts);
853
854 #ifdef _WIN32
855         /* On Windows, wait for extcap to connect to named pipe.
856          * Some extcaps will present UAC screen to user.
857          * 30 second timeout should be reasonable timeout for extcap to
858          * connect to named pipe (including user interaction).
859          * Wait on multiple object in case of extcap termination
860          * without opening pipe.
861          *
862          * Minimum supported version of Windows: XP / Server 2003.
863          */
864         if (pid != INVALID_EXTCAP_PID)
865         {
866             DWORD dw;
867             HANDLE handles[2];
868             OVERLAPPED ov;
869             ov.Pointer = 0;
870             ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
871
872             ConnectNamedPipe(pipe_h, &ov);
873             handles[0] = ov.hEvent;
874             handles[1] = pid;
875
876             if (GetLastError() == ERROR_PIPE_CONNECTED)
877             {
878                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap connected to pipe");
879             }
880             else
881             {
882                 dw = WaitForMultipleObjects(2, handles, FALSE, 30000);
883                 if (dw == WAIT_OBJECT_0)
884                 {
885                     /* ConnectNamedPipe finished. */
886                     DWORD code;
887
888                     code = GetLastError();
889                     if (code == ERROR_IO_PENDING)
890                     {
891                         DWORD dummy;
892                         if (!GetOverlappedResult(ov.hEvent, &ov, &dummy, TRUE))
893                         {
894                             code = GetLastError();
895                         }
896                         else
897                         {
898                             code = ERROR_SUCCESS;
899                         }
900                     }
901
902                     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "ConnectNamedPipe code: %d", code);
903                 }
904                 else if (dw == (WAIT_OBJECT_0 + 1))
905                 {
906                     /* extcap process terminated. */
907                     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap terminated without connecting to pipe!");
908                 }
909                 else if (dw == WAIT_TIMEOUT)
910                 {
911                     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "extcap didn't connect to pipe within 30 seconds!");
912                 }
913                 else
914                 {
915                     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "WaitForMultipleObjects returned 0x%08X. Error %d", dw, GetLastError());
916                 }
917             }
918
919             CloseHandle(ov.hEvent);
920         }
921 #endif
922     }
923
924     return TRUE;
925 }
926
927 #ifdef _WIN32
928 /* called by capture_sync to get the CreatNamedPipe handle*/
929 HANDLE
930 extcap_get_win32_handle()
931 {
932     return pipe_h;
933 }
934 #endif
935
936 gboolean extcap_create_pipe(char ** fifo)
937 {
938 #ifdef _WIN32
939     gchar timestr[ 14+1 ];
940     time_t current_time;
941
942     gchar *pipename = NULL;
943
944     SECURITY_ATTRIBUTES security;
945     /* create pipename */
946     current_time = time(NULL);
947     strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
948     pipename = g_strconcat ( "\\\\.\\pipe\\", EXTCAP_PIPE_PREFIX, "_", timestr, NULL );
949
950     /* Security struct to enable Inheritable HANDLE */
951     memset(&security, 0, sizeof(SECURITY_ATTRIBUTES));
952     security.nLength = sizeof(SECURITY_ATTRIBUTES);
953     security.bInheritHandle = TRUE;
954     security.lpSecurityDescriptor = NULL;
955
956     /* create a namedPipe*/
957     pipe_h = CreateNamedPipe(
958                 utf_8to16(pipename),
959                 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
960                 PIPE_TYPE_MESSAGE| PIPE_READMODE_MESSAGE | PIPE_WAIT,
961                 5, 65536, 65536,
962                 300,
963                 &security);
964
965     if (pipe_h == INVALID_HANDLE_VALUE)
966     {
967         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,"\nError creating pipe => (%d)", GetLastError());
968         return FALSE;
969     }
970     else
971     {
972         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,"\nWireshark Created pipe =>(%s)",pipename);
973         *fifo = g_strdup(pipename);
974     }
975 #else
976     gchar *temp_name = NULL;
977     int fd = 0;
978
979     if ((fd = create_tempfile(&temp_name, EXTCAP_PIPE_PREFIX)) < 0 )
980         return FALSE;
981
982     ws_close(fd);
983
984     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
985             "Extcap - Creating fifo: %s", temp_name);
986
987     if ( file_exists(temp_name) )
988         ws_unlink(temp_name);
989
990     if (mkfifo(temp_name, 0600) == 0)
991         *fifo = g_strdup(temp_name);
992 #endif
993
994     return TRUE;
995 }
996
997 #if ARG_DEBUG
998 void extcap_debug_arguments ( extcap_arg *arg_iter )
999 {
1000     extcap_value *v = NULL;
1001     GList *walker = NULL;
1002
1003     printf("debug - parser dump\n");
1004     while (arg_iter != NULL) {
1005         printf("ARG %d call=%s display=\"%s\" type=", arg_iter->arg_num, arg_iter->call, arg_iter->display);
1006
1007         switch (arg_iter->arg_type) {
1008             case EXTCAP_ARG_INTEGER:
1009             printf("int\n");
1010             break;
1011             case EXTCAP_ARG_UNSIGNED:
1012             printf("unsigned\n");
1013             break;
1014             case EXTCAP_ARG_LONG:
1015             printf("long\n");
1016             break;
1017             case EXTCAP_ARG_DOUBLE:
1018             printf("double\n");
1019             break;
1020             case EXTCAP_ARG_BOOLEAN:
1021             printf("boolean\n");
1022             break;
1023             case EXTCAP_ARG_MENU:
1024             printf("menu\n");
1025             break;
1026             case EXTCAP_ARG_RADIO:
1027             printf("radio\n");
1028             break;
1029             case EXTCAP_ARG_SELECTOR:
1030             printf("selctor\n");
1031             break;
1032             case EXTCAP_ARG_STRING:
1033             printf ( "string\n" );
1034             break;
1035             case EXTCAP_ARG_PASSWORD:
1036             printf ( "PASSWORD\n" );
1037             break;
1038             case EXTCAP_ARG_MULTICHECK:
1039             printf ( "unknown\n" );
1040             break;
1041             case EXTCAP_ARG_UNKNOWN:
1042             printf ( "unknown\n" );
1043             break;
1044         }
1045
1046         if (arg_iter->range_start != NULL && arg_iter->range_end != NULL) {
1047             printf("\tRange: ");
1048             extcap_printf_complex(arg_iter->range_start);
1049             printf(" - ");
1050             extcap_printf_complex(arg_iter->range_end);
1051             printf("\n");
1052         }
1053
1054         for ( walker = g_list_first ( arg_iter->value_list ); walker; walker = walker->next )
1055         {
1056             v = (extcap_value *)walker->data;
1057             if (v->is_default)
1058             printf("*");
1059             printf("\tcall=\"%p\" display=\"%p\"\n", v->call, v->display);
1060             printf("\tcall=\"%s\" display=\"%s\"\n", v->call, v->display);
1061         }
1062
1063         arg_iter = arg_iter->next_arg;
1064     }
1065 }
1066 #endif
1067 #endif
1068
1069 /*
1070  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1071  *
1072  * Local variables:
1073  * c-basic-offset: 4
1074  * tab-width: 8
1075  * indent-tabs-mode: nil
1076  * End:
1077  *
1078  * vi: set shiftwidth=4 tabstop=8 expandtab:
1079  * :indentSize=4:tabSize=8:noTabs=true:
1080  */