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