radiotap: Updates to the radiotap dissector to avoid confusion.
[metze/wireshark/wip.git] / epan / disabled_protos.c
1 /* disabled_protos.c
2  * Declarations of routines for reading and writing protocols file that determine
3  * enabling and disabling of protocols.
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include <glib.h>
31
32 #include <wsutil/filesystem.h>
33 #include <epan/proto.h>
34 #include <epan/packet.h>
35
36 #include "disabled_protos.h"
37 #include <wsutil/file_util.h>
38 #include <wsutil/ws_printf.h> /* ws_g_warning */
39 #include <wsutil/report_message.h>
40
41 #define ENABLED_PROTOCOLS_FILE_NAME     "enabled_protos"
42 #define DISABLED_PROTOCOLS_FILE_NAME    "disabled_protos"
43 #define HEURISTICS_FILE_NAME            "heuristic_protos"
44
45 /*
46  * Item in a list of disabled protocols.
47  */
48 typedef struct {
49   char *name;           /* protocol name */
50 } protocol_def;
51
52 /*
53  * Item in a list of heuristic dissectors and their enabled state.
54  */
55 typedef struct {
56   char *name;           /* heuristic short name */
57   gboolean enabled;     /* heuristc enabled */
58 } heur_protocol_def;
59
60 /*
61  * List of disabled protocols
62  */
63 static GList *global_disabled_protos = NULL;
64 static GList *disabled_protos = NULL;
65 /*
66  * List of enabled protocols (that are disabled by default)
67  */
68 static GList *global_enabled_protos = NULL;
69 static GList *enabled_protos = NULL;
70 /*
71  * List of disabled heuristics
72  */
73 static GList *global_disabled_heuristics = NULL;
74 static GList *disabled_heuristics = NULL;
75
76 #define INIT_BUF_SIZE   128
77
78 static void
79 discard_existing_list (GList **flp)
80 {
81   GList      *fl_ent;
82   protocol_def *prot;
83
84   if (*flp != NULL) {
85     fl_ent = g_list_first(*flp);
86     while (fl_ent != NULL) {
87       prot = (protocol_def *) fl_ent->data;
88       g_free(prot->name);
89       g_free(prot);
90       fl_ent = fl_ent->next;
91     }
92     g_list_free(*flp);
93     *flp = NULL;
94   }
95 }
96
97 static void
98 heur_discard_existing_list (GList **flp)
99 {
100   GList      *fl_ent;
101   heur_protocol_def *prot;
102
103   if (*flp != NULL) {
104     fl_ent = g_list_first(*flp);
105     while (fl_ent != NULL) {
106       prot = (heur_protocol_def *) fl_ent->data;
107       g_free(prot->name);
108       g_free(prot);
109       fl_ent = fl_ent->next;
110     }
111     g_list_free(*flp);
112     *flp = NULL;
113   }
114 }
115
116 /*
117  * Enable/Disable protocols as per the stored configuration
118  */
119 static void
120 set_protos_list(GList *protos_list, GList *global_protos_list, gboolean enable)
121 {
122   gint i;
123   GList *fl_ent;
124   protocol_def *prot;
125
126   /*
127    * Assume no protocols disabled by default wants to be enabled
128    */
129   if (protos_list == NULL)
130     goto skip;
131
132   fl_ent = g_list_first(protos_list);
133
134   while (fl_ent != NULL) {
135     prot = (protocol_def *) fl_ent->data;
136     i = proto_get_id_by_filter_name(prot->name);
137     if (i == -1) {
138       /* XXX - complain here? */
139     } else {
140       if (proto_can_toggle_protocol(i))
141         proto_set_decoding(i, enable);
142     }
143
144     fl_ent = fl_ent->next;
145   }
146
147 skip:
148   if (global_protos_list == NULL)
149     return;
150
151   fl_ent = g_list_first(global_protos_list);
152
153   while (fl_ent != NULL) {
154     prot = (protocol_def *) fl_ent->data;
155     i = proto_get_id_by_filter_name(prot->name);
156     if (i == -1) {
157       /* XXX - complain here? */
158     } else {
159       if (proto_can_toggle_protocol(i)) {
160         proto_set_decoding(i, enable);
161         proto_set_cant_toggle(i);
162       }
163     }
164
165     fl_ent = fl_ent->next;
166   }
167 }
168
169 /*
170  * Write out a list of protocols based on condition
171  *
172  * On success, "*pref_path_return" is set to NULL.
173  * On error, "*pref_path_return" is set to point to the pathname of
174  * the file we tried to read - it should be freed by our caller -
175  * and "*errno_return" is set to the error.
176  */
177 static void
178 save_protos_list(char **pref_path_return, int *errno_return, const char* filename,
179                 const char* header_comment, gboolean (*protocol_check)(protocol_t  *protocol))
180 {
181   gchar       *ff_path, *ff_path_new;
182   FILE        *ff;
183   gint         i;
184   protocol_t  *protocol;
185   void        *cookie;
186   gboolean    first = TRUE;
187
188   *pref_path_return = NULL;     /* assume no error */
189
190   ff_path = get_persconffile_path(filename, TRUE);
191
192   /* Write to "XXX.new", and rename if that succeeds.
193      That means we don't trash the file if we fail to write it out
194      completely. */
195   ff_path_new = g_strdup_printf("%s.new", ff_path);
196
197   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
198     *pref_path_return = ff_path;
199     *errno_return = errno;
200     g_free(ff_path_new);
201     return;
202   }
203
204   /* Iterate over all the protocols */
205   for (i = proto_get_first_protocol(&cookie); i != -1;
206        i = proto_get_next_protocol(&cookie)) {
207
208     if (!proto_can_toggle_protocol(i)) {
209       continue;
210     }
211
212     protocol = find_protocol_by_id(i);
213     if (protocol_check(protocol) == FALSE)
214       continue;
215
216     if (first) {
217       if (header_comment != NULL) {
218         /* Write out a comment explaining what the file is */
219         fprintf(ff, "%s\n", header_comment);
220       }
221       first = FALSE;
222     }
223
224     /* Write out the protocol name. */
225     fprintf(ff, "%s\n", proto_get_protocol_filter_name(i));
226   }
227
228   if (fclose(ff) == EOF) {
229     *pref_path_return = ff_path;
230     *errno_return = errno;
231     ws_unlink(ff_path_new);
232     g_free(ff_path_new);
233     return;
234   }
235
236 #ifdef _WIN32
237   /* ANSI C doesn't say whether "rename()" removes the target if it
238      exists; the Win32 call to rename files doesn't do so, which I
239      infer is the reason why the MSVC++ "rename()" doesn't do so.
240      We must therefore remove the target file first, on Windows.
241
242      XXX - ws_rename() should be ws_stdio_rename() on Windows,
243      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
244      so it should remove the target if it exists, so this stuff
245      shouldn't be necessary.  Perhaps it dates back to when we were
246      calling rename(), with that being a wrapper around Microsoft's
247      _rename(), which didn't remove the target. */
248   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
249     /* It failed for some reason other than "it's not there"; if
250        it's not there, we don't need to remove it, so we just
251        drive on. */
252     *pref_path_return = ff_path;
253     *errno_return = errno;
254     ws_unlink(ff_path_new);
255     g_free(ff_path_new);
256     return;
257   }
258 #endif
259
260   if (ws_rename(ff_path_new, ff_path) < 0) {
261     *pref_path_return = ff_path;
262     *errno_return = errno;
263     ws_unlink(ff_path_new);
264     g_free(ff_path_new);
265     return;
266   }
267   g_free(ff_path_new);
268   g_free(ff_path);
269 }
270
271 static int
272 read_protos_list_file(const char *ff_path, FILE *ff, GList **flp)
273 {
274   protocol_def *prot;
275   int         c;
276   char       *prot_name;
277   int         prot_name_len;
278   int         prot_name_index;
279   int         line = 1;
280   gboolean    in_comment = FALSE;
281
282
283   /* Allocate the protocol name buffer. */
284   prot_name_len = INIT_BUF_SIZE;
285   prot_name = (char *)g_malloc(prot_name_len + 1);
286
287   for (line = 1; ; line++) {
288     /* Lines in a protocol file contain the "filter name" of a protocol
289        to be enabled or disabled. */
290
291     /* Skip over leading white space, if any. */
292     while ((c = ws_getc_unlocked(ff)) != EOF && g_ascii_isspace(c)) {
293       if (c == '\n') {
294         /* Blank line. */
295         continue;
296       }
297     }
298
299     if (c == EOF) {
300       if (ferror(ff))
301         goto error;     /* I/O error */
302       else
303         break;  /* Nothing more to read */
304     }
305     ungetc(c, ff);      /* Unread the non-white-space character. */
306
307     /* Get the name of the protocol. */
308     prot_name_index = 0;
309     for (;;) {
310       c = ws_getc_unlocked(ff);
311       if (c == EOF)
312         break;  /* End of file, or I/O error */
313       if (g_ascii_isspace(c))
314         break;  /* Trailing white space, or end of line. */
315       if (c == '#') {
316         in_comment = TRUE;
317         break;  /* Start of comment, running to end of line. */
318       }
319       /* Add this character to the protocol name string. */
320       if (prot_name_index >= prot_name_len) {
321         /* protocol name buffer isn't long enough; double its length. */
322         prot_name_len *= 2;
323         prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
324       }
325       prot_name[prot_name_index] = c;
326       prot_name_index++;
327     }
328
329     if (g_ascii_isspace(c) && c != '\n') {
330       /* Skip over trailing white space. */
331       while ((c = ws_getc_unlocked(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
332         ;
333       if (c != EOF && c != '\n' && c != '#') {
334         /* Non-white-space after the protocol name; warn about it,
335            in case we come up with a reason to use it. */
336         ws_g_warning("'%s' line %d has extra stuff after the protocol name.",
337                   ff_path, line);
338       }
339     }
340     if (c != EOF && c != '\n' && in_comment == TRUE) {
341       /* Skip to end of line. */
342       while ((c = ws_getc_unlocked(ff)) != EOF && c != '\n')
343         ;
344     }
345
346     if (c == EOF) {
347       if (ferror(ff))
348         goto error;     /* I/O error */
349       else {
350         /* EOF, not error; no newline seen before EOF */
351         ws_g_warning("'%s' line %d doesn't have a newline.", ff_path,
352                   line);
353       }
354       break;    /* nothing more to read */
355     }
356
357     if (in_comment) {
358       in_comment = FALSE;
359       continue;
360     }
361
362     /* Null-terminate the protocol name. */
363     if (prot_name_index >= prot_name_len) {
364       /* protocol name buffer isn't long enough; double its length. */
365       prot_name_len *= 2;
366       prot_name = (char *)g_realloc(prot_name, prot_name_len + 1);
367     }
368     prot_name[prot_name_index] = '\0';
369
370     /* Add the new protocol to the list of disabled protocols */
371     prot         = (protocol_def *) g_malloc(sizeof(protocol_def));
372     prot->name   = g_strdup(prot_name);
373     *flp = g_list_append(*flp, prot);
374   }
375   g_free(prot_name);
376   return 0;
377
378 error:
379   g_free(prot_name);
380   return errno;
381 }
382
383 /*
384  * Read in global and personal versions of a list of protocols.
385  *
386  * If we can open and read the global version, *gpath_return is set to
387  * NULL.  Otherwise, *gpath_return is set to point to the pathname of
388  * the file we tried to read - it should be freed by our caller - and
389  * *gopen_errno_return is set to the error if an open failed or
390  * *gread_errno_return is set to the error if a read failed.
391  *
392  * If we can open and read the personal version, *path_return is set to
393  * NULL.  Otherwise, *path_return is set to point to the pathname of
394  * the file we tried to read - it should be freed by our caller - and
395  * *open_errno_return is set to the error if an open failed or
396  * *read_errno_return is set to the error if a read failed.
397  */
398 static void
399 read_protos_list(char **gpath_return, int *gopen_errno_return,
400                  int *gread_errno_return,
401                  char **path_return, int *open_errno_return,
402                  int *read_errno_return,
403                  const char* filename,
404                  GList **global_protos_list, GList **protos_list)
405 {
406   int         err;
407   char       *gff_path, *ff_path;
408   FILE       *ff;
409
410   /* Construct the pathname of the global disabled protocols file. */
411   gff_path = get_datafile_path(filename);
412
413   /* If we already have a list of protocols, discard it. */
414   discard_existing_list (global_protos_list);
415
416   /* Read the global disabled protocols file, if it exists. */
417   *gpath_return = NULL;
418   if ((ff = ws_fopen(gff_path, "r")) != NULL) {
419     /* We succeeded in opening it; read it. */
420     err = read_protos_list_file(gff_path, ff, global_protos_list);
421     if (err != 0) {
422       /* We had an error reading the file; return the errno and the
423          pathname, so our caller can report the error. */
424       *gopen_errno_return = 0;
425       *gread_errno_return = err;
426       *gpath_return = gff_path;
427     } else
428       g_free(gff_path);
429     fclose(ff);
430   } else {
431     /* We failed to open it.  If we failed for some reason other than
432        "it doesn't exist", return the errno and the pathname, so our
433        caller can report the error. */
434     if (errno != ENOENT) {
435       *gopen_errno_return = errno;
436       *gread_errno_return = 0;
437       *gpath_return = gff_path;
438     } else
439       g_free(gff_path);
440   }
441
442   /* Construct the pathname of the user's disabled protocols file. */
443   ff_path = get_persconffile_path(filename, TRUE);
444
445   /* If we already have a list of protocols, discard it. */
446   discard_existing_list (protos_list);
447
448   /* Read the user's disabled protocols file, if it exists. */
449   *path_return = NULL;
450   if ((ff = ws_fopen(ff_path, "r")) != NULL) {
451     /* We succeeded in opening it; read it. */
452     err = read_protos_list_file(ff_path, ff, protos_list);
453     if (err != 0) {
454       /* We had an error reading the file; return the errno and the
455          pathname, so our caller can report the error. */
456       *open_errno_return = 0;
457       *read_errno_return = err;
458       *path_return = ff_path;
459     } else
460       g_free(ff_path);
461     fclose(ff);
462   } else {
463     /* We failed to open it.  If we failed for some reason other than
464        "it doesn't exist", return the errno and the pathname, so our
465        caller can report the error. */
466     if (errno != ENOENT) {
467       *open_errno_return = errno;
468       *read_errno_return = 0;
469       *path_return = ff_path;
470     } else
471       g_free(ff_path);
472   }
473 }
474
475 /************************************************************************
476  * Disabling dissectors
477  ************************************************************************/
478
479 /*
480  * Disable a particular protocol by name
481  */
482 void
483 proto_disable_proto_by_name(const char *name)
484 {
485     protocol_t *protocol;
486     int proto_id;
487
488     proto_id = proto_get_id_by_filter_name(name);
489     if (proto_id >= 0 ) {
490         protocol = find_protocol_by_id(proto_id);
491         if (proto_is_protocol_enabled(protocol) == TRUE) {
492             if (proto_can_toggle_protocol(proto_id) == TRUE) {
493                 proto_set_decoding(proto_id, FALSE);
494             }
495         }
496     }
497 }
498
499 static gboolean disable_proto_list_check(protocol_t  *protocol)
500 {
501     if (proto_is_protocol_enabled(protocol) == FALSE)
502       return TRUE;
503
504     return FALSE;
505 }
506
507 /************************************************************************
508  * Enabling dissectors (that are disabled by default)
509  ************************************************************************/
510
511 WS_DLL_PUBLIC void
512 proto_enable_proto_by_name(const char *name)
513 {
514   protocol_t *protocol;
515   int proto_id;
516
517   proto_id = proto_get_id_by_filter_name(name);
518   if (proto_id >= 0 ) {
519     protocol = find_protocol_by_id(proto_id);
520     if ((proto_is_protocol_enabled_by_default(protocol) == FALSE) &&
521         (proto_is_protocol_enabled(protocol) == FALSE)) {
522       if (proto_can_toggle_protocol(proto_id) == TRUE) {
523         proto_set_decoding(proto_id, TRUE);
524       }
525     }
526   }
527 }
528
529 static gboolean enable_proto_list_check(protocol_t  *protocol)
530 {
531   if ((proto_is_protocol_enabled_by_default(protocol) == FALSE) &&
532       (proto_is_protocol_enabled(protocol) == TRUE))
533     return TRUE;
534
535   return FALSE;
536 }
537
538 /************************************************************************
539  * Heuristic dissectors
540  ************************************************************************/
541
542
543 static void
544 set_disabled_heur_dissector_list(void)
545 {
546   GList *fl_ent;
547   heur_protocol_def *heur;
548   heur_dtbl_entry_t* h;
549
550   if (disabled_heuristics == NULL)
551     goto skip;
552
553   fl_ent = g_list_first(disabled_heuristics);
554
555   while (fl_ent != NULL) {
556     heur = (heur_protocol_def *) fl_ent->data;
557     h = find_heur_dissector_by_unique_short_name(heur->name);
558     if (h != NULL) {
559       h->enabled = heur->enabled;
560     }
561
562     fl_ent = fl_ent->next;
563   }
564
565 skip:
566   if (global_disabled_heuristics == NULL)
567     return;
568
569   fl_ent = g_list_first(global_disabled_heuristics);
570
571   while (fl_ent != NULL) {
572     heur = (heur_protocol_def *) fl_ent->data;
573
574     h = find_heur_dissector_by_unique_short_name(heur->name);
575     if (h != NULL) {
576       h->enabled = heur->enabled;
577     }
578
579     fl_ent = fl_ent->next;
580   }
581 }
582
583 static int
584 read_heur_dissector_list_file(const char *ff_path, FILE *ff, GList **flp)
585 {
586   heur_protocol_def *heur;
587   int         c;
588   char       *heuristic_name;
589   int         heuristic_name_len;
590   int         name_index;
591   gboolean    parse_enabled;
592   gboolean    enabled;
593   int         line = 1;
594
595
596   /* Allocate the protocol name buffer. */
597   heuristic_name_len = INIT_BUF_SIZE;
598   heuristic_name = (char *)g_malloc(heuristic_name_len + 1);
599
600   for (line = 1; ; line++) {
601     /* Lines in a disabled protocol file contain the "filter name" of
602        a protocol to be disabled. */
603
604     /* Skip over leading white space, if any. */
605     while ((c = ws_getc_unlocked(ff)) != EOF && g_ascii_isspace(c)) {
606       if (c == '\n') {
607         /* Blank line. */
608         continue;
609       }
610     }
611
612     if (c == EOF) {
613       if (ferror(ff))
614         goto error;     /* I/O error */
615       else
616         break;  /* Nothing more to read */
617     }
618     ungetc(c, ff);      /* Unread the non-white-space character. */
619
620     /* Get the name of the protocol. */
621     name_index = 0;
622     enabled = FALSE;
623     parse_enabled = FALSE;
624     for (;;) {
625       c = ws_getc_unlocked(ff);
626       if (c == EOF)
627         break;  /* End of file, or I/O error */
628       if (g_ascii_isspace(c))
629         break;  /* Trailing white space, or end of line. */
630       if (c == ',') {/* Separator for enable/disable */
631         parse_enabled = TRUE;
632         continue;
633       }
634       if (c == '#')
635         break;  /* Start of comment, running to end of line. */
636       if (parse_enabled) {
637           enabled = ((c == '1') ? TRUE : FALSE);
638           break;
639       }
640       /* Add this character to the protocol name string. */
641       if (name_index >= heuristic_name_len) {
642         /* protocol name buffer isn't long enough; double its length. */
643         heuristic_name_len *= 2;
644         heuristic_name = (char *)g_realloc(heuristic_name, heuristic_name_len + 1);
645       }
646       heuristic_name[name_index] = c;
647       name_index++;
648     }
649
650     if (g_ascii_isspace(c) && c != '\n') {
651       /* Skip over trailing white space. */
652       while ((c = ws_getc_unlocked(ff)) != EOF && c != '\n' && g_ascii_isspace(c))
653         ;
654       if (c != EOF && c != '\n' && c != '#') {
655         /* Non-white-space after the protocol name; warn about it,
656            in case we come up with a reason to use it. */
657         ws_g_warning("'%s' line %d has extra stuff after the protocol name.",
658                   ff_path, line);
659       }
660     }
661     if (c != EOF && c != '\n') {
662       /* Skip to end of line. */
663       while ((c = ws_getc_unlocked(ff)) != EOF && c != '\n')
664         ;
665     }
666
667     if (c == EOF) {
668       if (ferror(ff))
669         goto error;     /* I/O error */
670       else {
671         /* EOF, not error; no newline seen before EOF */
672         ws_g_warning("'%s' line %d doesn't have a newline.", ff_path,
673                   line);
674       }
675       break;    /* nothing more to read */
676     }
677
678     /* Null-terminate the protocol name. */
679     if (name_index >= heuristic_name_len) {
680       /* protocol name buffer isn't long enough; double its length. */
681       heuristic_name_len *= 2;
682       heuristic_name = (char *)g_realloc(heuristic_name, heuristic_name_len + 1);
683     }
684     heuristic_name[name_index] = '\0';
685
686     /* Add the new protocol to the list of protocols */
687     heur         = (heur_protocol_def *) g_malloc(sizeof(heur_protocol_def));
688     heur->name   = g_strdup(heuristic_name);
689     heur->enabled = enabled;
690     *flp = g_list_append(*flp, heur);
691   }
692   g_free(heuristic_name);
693   return 0;
694
695 error:
696   g_free(heuristic_name);
697   return errno;
698 }
699
700 static void
701 read_heur_dissector_list(char **gpath_return, int *gopen_errno_return,
702                          int *gread_errno_return,
703                          char **path_return, int *open_errno_return,
704                          int *read_errno_return)
705 {
706   int         err;
707   char       *gff_path, *ff_path;
708   FILE       *ff;
709
710   /* If we already have a list of protocols, discard it. */
711   heur_discard_existing_list(&global_disabled_heuristics);
712
713   /* Construct the pathname of the global disabled heuristic dissectors file. */
714   gff_path = get_datafile_path(HEURISTICS_FILE_NAME);
715
716   /* Read the global disabled protocols file, if it exists. */
717   *gpath_return = NULL;
718   if ((ff = ws_fopen(gff_path, "r")) != NULL) {
719     /* We succeeded in opening it; read it. */
720     err = read_heur_dissector_list_file(gff_path, ff,
721                                         &global_disabled_heuristics);
722     if (err != 0) {
723       /* We had an error reading the file; return the errno and the
724          pathname, so our caller can report the error. */
725       *gopen_errno_return = 0;
726       *gread_errno_return = err;
727       *gpath_return = gff_path;
728     } else
729       g_free(gff_path);
730     fclose(ff);
731   } else {
732     /* We failed to open it.  If we failed for some reason other than
733        "it doesn't exist", return the errno and the pathname, so our
734        caller can report the error. */
735     if (errno != ENOENT) {
736       *gopen_errno_return = errno;
737       *gread_errno_return = 0;
738       *gpath_return = gff_path;
739     } else
740       g_free(gff_path);
741   }
742
743   /* Construct the pathname of the user's disabled protocols file. */
744   ff_path = get_persconffile_path(HEURISTICS_FILE_NAME, TRUE);
745
746   /* If we already have a list of protocols, discard it. */
747   heur_discard_existing_list (&disabled_heuristics);
748
749   /* Read the user's disabled protocols file, if it exists. */
750   *path_return = NULL;
751   if ((ff = ws_fopen(ff_path, "r")) != NULL) {
752     /* We succeeded in opening it; read it. */
753     err = read_heur_dissector_list_file(ff_path, ff, &disabled_heuristics);
754     if (err != 0) {
755       /* We had an error reading the file; return the errno and the
756          pathname, so our caller can report the error. */
757       *open_errno_return = 0;
758       *read_errno_return = err;
759       *path_return = ff_path;
760     } else
761       g_free(ff_path);
762     fclose(ff);
763   } else {
764     /* We failed to open it.  If we failed for some reason other than
765        "it doesn't exist", return the errno and the pathname, so our
766        caller can report the error. */
767     if (errno != ENOENT) {
768       *open_errno_return = errno;
769       *read_errno_return = 0;
770       *path_return = ff_path;
771     } else
772       g_free(ff_path);
773   }
774 }
775
776 static gint
777 heur_compare(gconstpointer a, gconstpointer b)
778 {
779   return strcmp(((const heur_dtbl_entry_t *)a)->short_name,
780                 ((const heur_dtbl_entry_t *)b)->short_name);
781 }
782
783 static void
784 write_heur_dissector(gpointer data, gpointer user_data)
785 {
786   heur_dtbl_entry_t* dtbl_entry = (heur_dtbl_entry_t*)data;
787   FILE *ff = (FILE*)user_data;
788
789   /* Write out the heuristic short name and its enabled state */
790   fprintf(ff, "%s,%d\n", dtbl_entry->short_name, dtbl_entry->enabled ? 1 : 0);
791 }
792
793 static void
794 sort_dissector_table_entries(const char *table_name _U_,
795     heur_dtbl_entry_t *dtbl_entry, gpointer user_data)
796 {
797   GSList **list = (GSList**)user_data;
798   *list = g_slist_insert_sorted(*list, dtbl_entry, heur_compare);
799 }
800
801 static void
802 sort_heur_dissector_tables(const char *table_name, struct heur_dissector_list *list, gpointer w)
803 {
804   if (list) {
805     heur_dissector_table_foreach(table_name, sort_dissector_table_entries, w);
806   }
807 }
808
809 static void
810 save_disabled_heur_dissector_list(char **pref_path_return, int *errno_return)
811 {
812   gchar       *ff_path, *ff_path_new;
813   GSList      *sorted_heur_list = NULL;
814   FILE        *ff;
815
816   *pref_path_return = NULL;     /* assume no error */
817
818   ff_path = get_persconffile_path(HEURISTICS_FILE_NAME, TRUE);
819
820   /* Write to "XXX.new", and rename if that succeeds.
821      That means we don't trash the file if we fail to write it out
822      completely. */
823   ff_path_new = g_strdup_printf("%s.new", ff_path);
824
825   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
826     *pref_path_return = ff_path;
827     *errno_return = errno;
828     g_free(ff_path_new);
829     return;
830   }
831
832   /* Iterate over all the heuristic dissectors to sort them in alphabetical order by short name */
833   dissector_all_heur_tables_foreach_table(sort_heur_dissector_tables, &sorted_heur_list, NULL);
834
835   /* Write the list */
836   g_slist_foreach(sorted_heur_list, write_heur_dissector, ff);
837   g_slist_free(sorted_heur_list);
838
839   if (fclose(ff) == EOF) {
840     *pref_path_return = ff_path;
841     *errno_return = errno;
842     ws_unlink(ff_path_new);
843     g_free(ff_path_new);
844     return;
845   }
846
847 #ifdef _WIN32
848   /* ANSI C doesn't say whether "rename()" removes the target if it
849      exists; the Win32 call to rename files doesn't do so, which I
850      infer is the reason why the MSVC++ "rename()" doesn't do so.
851      We must therefore remove the target file first, on Windows.
852
853      XXX - ws_rename() should be ws_stdio_rename() on Windows,
854      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
855      so it should remove the target if it exists, so this stuff
856      shouldn't be necessary.  Perhaps it dates back to when we were
857      calling rename(), with that being a wrapper around Microsoft's
858      _rename(), which didn't remove the target. */
859   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
860     /* It failed for some reason other than "it's not there"; if
861        it's not there, we don't need to remove it, so we just
862        drive on. */
863     *pref_path_return = ff_path;
864     *errno_return = errno;
865     ws_unlink(ff_path_new);
866     g_free(ff_path_new);
867     return;
868   }
869 #endif
870
871   if (ws_rename(ff_path_new, ff_path) < 0) {
872     *pref_path_return = ff_path;
873     *errno_return = errno;
874     ws_unlink(ff_path_new);
875     g_free(ff_path_new);
876     return;
877   }
878   g_free(ff_path_new);
879   g_free(ff_path);
880 }
881
882 gboolean
883 proto_enable_heuristic_by_name(const char *name, gboolean enable)
884 {
885   heur_dtbl_entry_t* heur = find_heur_dissector_by_unique_short_name(name);
886   if (heur != NULL) {
887       heur->enabled = enable;
888       return TRUE;
889   } else {
890       return FALSE;
891   }
892 }
893
894 static void
895 disabled_protos_free(gpointer p, gpointer user_data _U_)
896 {
897   protocol_def* pd = (protocol_def*)p;
898   g_free(pd->name);
899   g_free(p);
900 }
901
902 /*
903  * Read the files that enable and disable protocols and heuristic
904  * dissectors.  Report errors through the UI.
905  */
906 void
907 read_enabled_and_disabled_lists(void)
908 {
909   char *gpath, *path;
910   int gopen_errno, gread_errno;
911   int open_errno, read_errno;
912
913   /*
914    * Read the global and personal disabled protocols files.
915    */
916   read_protos_list(&gpath, &gopen_errno, &gread_errno,
917                    &path, &open_errno, &read_errno,
918                    DISABLED_PROTOCOLS_FILE_NAME,
919                    &global_disabled_protos, &disabled_protos);
920   if (gpath != NULL) {
921     if (gopen_errno != 0) {
922       report_warning("Could not open global disabled protocols file\n\"%s\": %s.",
923                      gpath, g_strerror(gopen_errno));
924     }
925     if (gread_errno != 0) {
926       report_warning("I/O error reading global disabled protocols file\n\"%s\": %s.",
927                      gpath, g_strerror(gread_errno));
928     }
929     g_free(gpath);
930     gpath = NULL;
931   }
932   if (path != NULL) {
933     if (open_errno != 0) {
934       report_warning("Could not open your disabled protocols file\n\"%s\": %s.",
935                      path, g_strerror(open_errno));
936     }
937     if (read_errno != 0) {
938       report_warning("I/O error reading your disabled protocols file\n\"%s\": %s.",
939                      path, g_strerror(read_errno));
940     }
941     g_free(path);
942     path = NULL;
943   }
944
945   /*
946    * Read the global and personal enabled protocols files.
947    */
948   read_protos_list(&gpath, &gopen_errno, &gread_errno,
949                    &path, &open_errno, &read_errno,
950                    ENABLED_PROTOCOLS_FILE_NAME,
951                    &global_enabled_protos, &enabled_protos);
952   if (gpath != NULL) {
953     if (gopen_errno != 0) {
954       report_warning("Could not open global enabled protocols file\n\"%s\": %s.",
955                      gpath, g_strerror(gopen_errno));
956     }
957     if (gread_errno != 0) {
958       report_warning("I/O error reading global enabled protocols file\n\"%s\": %s.",
959                      gpath, g_strerror(gread_errno));
960     }
961     g_free(gpath);
962     gpath = NULL;
963   }
964   if (path != NULL) {
965     if (open_errno != 0) {
966       report_warning("Could not open your enabled protocols file\n\"%s\": %s.",
967                      path, g_strerror(open_errno));
968     }
969     if (read_errno != 0) {
970       report_warning("I/O error reading your enabled protocols file\n\"%s\": %s.",
971                      path, g_strerror(read_errno));
972     }
973     g_free(path);
974     path = NULL;
975   }
976
977   /*
978    * Read the global and personal heuristic dissector list files.
979    */
980   read_heur_dissector_list(&gpath, &gopen_errno, &gread_errno,
981                            &path, &open_errno, &read_errno);
982   if (gpath != NULL) {
983     if (gopen_errno != 0) {
984       report_warning("Could not open global heuristic dissectors file\n\"%s\": %s.",
985                      gpath, g_strerror(gopen_errno));
986     }
987     if (gread_errno != 0) {
988       report_warning("I/O error reading global heuristic dissectors file\n\"%s\": %s.",
989                      gpath, g_strerror(gread_errno));
990     }
991     g_free(gpath);
992     gpath = NULL;
993   }
994   if (path != NULL) {
995     if (open_errno != 0) {
996       report_warning("Could not open your heuristic dissectors file\n\"%s\": %s.",
997                      path, g_strerror(open_errno));
998     }
999     if (read_errno != 0) {
1000       report_warning("I/O error reading your heuristic dissectors file\n\"%s\": %s.",
1001                      path, g_strerror(read_errno));
1002     }
1003     g_free(path);
1004     path = NULL;
1005   }
1006
1007   /*
1008    * Enable/disable protocols and heuristic dissectors as per the
1009    * contents of the files we just read.
1010    */
1011   set_protos_list(disabled_protos, global_disabled_protos, FALSE);
1012   set_protos_list(enabled_protos, global_enabled_protos, TRUE);
1013   set_disabled_heur_dissector_list();
1014 }
1015
1016 /*
1017  * Write out the lists of enabled and disabled protocols and heuristic
1018  * dissectors to the corresponding files.  Report errors through the UI.
1019  */
1020 void
1021 save_enabled_and_disabled_lists(void)
1022 {
1023   char *pf_dir_path;
1024   char *pf_path;
1025   int pf_save_errno;
1026
1027   /* Create the directory that holds personal configuration files, if
1028      necessary.  */
1029   if (create_persconffile_dir(&pf_dir_path) == -1) {
1030     report_failure("Can't create directory\n\"%s\"\nfor disabled protocols file: %s.",
1031                    pf_dir_path, g_strerror(errno));
1032     g_free(pf_dir_path);
1033     return;
1034   }
1035
1036   save_protos_list(&pf_path, &pf_save_errno, DISABLED_PROTOCOLS_FILE_NAME,
1037                    NULL, disable_proto_list_check);
1038   if (pf_path != NULL) {
1039     report_failure("Could not save to your disabled protocols file\n\"%s\": %s.",
1040                    pf_path, g_strerror(pf_save_errno));
1041     g_free(pf_path);
1042   }
1043
1044   save_protos_list(&pf_path, &pf_save_errno, ENABLED_PROTOCOLS_FILE_NAME,
1045                    "#This file is for enabling protocols that are disabled by default",
1046                    enable_proto_list_check);
1047   if (pf_path != NULL) {
1048     report_failure("Could not save to your enabled protocols file\n\"%s\": %s.",
1049                    pf_path, g_strerror(pf_save_errno));
1050     g_free(pf_path);
1051   }
1052
1053   save_disabled_heur_dissector_list(&pf_path, &pf_save_errno);
1054   if (pf_path != NULL) {
1055     report_failure("Could not save to your disabled heuristic protocol file\n\"%s\": %s.",
1056                    pf_path, g_strerror(pf_save_errno));
1057     g_free(pf_path);
1058   }
1059 }
1060
1061 void
1062 cleanup_enabled_and_disabled_lists(void)
1063 {
1064   g_list_foreach(global_disabled_heuristics, disabled_protos_free, NULL);
1065   g_list_free(global_disabled_heuristics);
1066   g_list_foreach(disabled_heuristics, disabled_protos_free, NULL);
1067   g_list_free(disabled_heuristics);
1068   g_list_foreach(global_disabled_protos, disabled_protos_free, NULL);
1069   g_list_free(global_disabled_protos);
1070   g_list_foreach(disabled_protos, disabled_protos_free, NULL);
1071   g_list_free(disabled_protos);
1072 }
1073
1074 /*
1075  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1076  *
1077  * Local Variables:
1078  * c-basic-offset: 2
1079  * tab-width: 8
1080  * indent-tabs-mode: nil
1081  * End:
1082  *
1083  * ex: set shiftwidth=2 tabstop=8 expandtab:
1084  * :indentSize=2:tabSize=8:noTabs=true:
1085  */