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