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