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