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