Try to improve the "Kerberos requested but not OpenSSL" message.
[jelmer/wireshark.git] / filters.c
1 /* filters.c
2  * Code for reading and writing the filters file.
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <errno.h>
29
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33
34 #include <glib.h>
35
36 #include <wsutil/file_util.h>
37 #include <wsutil/filesystem.h>
38
39 #include "filters.h"
40
41 /*
42  * Old filter file name.
43  */
44 #define FILTER_FILE_NAME        "filters"
45
46 /*
47  * Capture filter file name.
48  */
49 #define CFILTER_FILE_NAME       "cfilters"
50
51 /*
52  * Display filter file name.
53  */
54 #define DFILTER_FILE_NAME       "dfilters"
55
56 /*
57  * List of capture filters - saved.
58  */
59 static GList *capture_filters = NULL;
60
61 /*
62  * List of display filters - saved.
63  */
64 static GList *display_filters = NULL;
65
66 /*
67  * List of capture filters - currently edited.
68  */
69 static GList *capture_edited_filters = NULL;
70
71 /*
72  * List of display filters - currently edited.
73  */
74 static GList *display_edited_filters = NULL;
75
76 /*
77  * Read in a list of filters.
78  *
79  * On success, "*pref_path_return" is set to NULL.
80  * On error, "*pref_path_return" is set to point to the pathname of
81  * the file we tried to read - it should be freed by our caller -
82  * and "*errno_return" is set to the error.
83  */
84
85 #define INIT_BUF_SIZE   128
86
87 static GList *
88 add_filter_entry(GList *fl, const char *filt_name, const char *filt_expr)
89 {
90     filter_def *filt;
91
92     filt         = (filter_def *) g_malloc(sizeof(filter_def));
93     filt->name   = g_strdup(filt_name);
94     filt->strval = g_strdup(filt_expr);
95     return g_list_append(fl, filt);
96 }
97
98 static GList *
99 remove_filter_entry(GList *fl, GList *fl_entry)
100 {
101   filter_def *filt;
102
103   filt = (filter_def *) fl_entry->data;
104   g_free(filt->name);
105   g_free(filt->strval);
106   g_free(filt);
107   return g_list_remove_link(fl, fl_entry);
108 }
109
110 void
111 read_filter_list(filter_list_type_t list_type, char **pref_path_return,
112     int *errno_return)
113 {
114   const char *ff_name;
115   char       *ff_path;
116   FILE       *ff;
117   GList      **flpp;
118   int         c;
119   char       *filt_name, *filt_expr;
120   int         filt_name_len, filt_expr_len;
121   int         filt_name_index, filt_expr_index;
122   int         line = 1;
123
124   *pref_path_return = NULL;     /* assume no error */
125
126   switch (list_type) {
127
128   case CFILTER_LIST:
129     ff_name = CFILTER_FILE_NAME;
130     flpp = &capture_filters;
131     break;
132
133   case DFILTER_LIST:
134     ff_name = DFILTER_FILE_NAME;
135     flpp = &display_filters;
136     break;
137
138   default:
139     g_assert_not_reached();
140     return;
141   }
142
143   /* try to open personal "cfilters"/"dfilters" file */
144   ff_path = get_persconffile_path(ff_name, TRUE);
145   if ((ff = ws_fopen(ff_path, "r")) == NULL) {
146     /*
147      * Did that fail because the file didn't exist?
148      */
149     if (errno != ENOENT) {
150       /*
151        * No.  Just give up.
152        */
153       *pref_path_return = ff_path;
154       *errno_return = errno;
155       return;
156     }
157
158     /*
159      * Yes.  See if there's an "old style" personal "filters" file; if so, read it.
160      * This means that a user will start out with their capture and
161      * display filter lists being identical; each list may contain
162      * filters that don't belong in that list.  The user can edit
163      * the filter lists, and delete the ones that don't belong in
164      * a particular list.
165      */
166     g_free(ff_path);
167     ff_path = get_persconffile_path(FILTER_FILE_NAME, FALSE);
168     if ((ff = ws_fopen(ff_path, "r")) == NULL) {
169       /*
170        * Did that fail because the file didn't exist?
171        */
172         if (errno != ENOENT) {
173         /*
174          * No.  Just give up.
175          */
176           *pref_path_return = ff_path;
177           *errno_return = errno;
178           return;
179         }
180
181       /*
182        * Try to open the global "cfilters/dfilters" file */
183       g_free(ff_path);
184       ff_path = get_datafile_path(ff_name);
185       if ((ff = ws_fopen(ff_path, "r")) == NULL) {
186
187         /*
188          * Well, that didn't work, either.  Just give up.
189          * Return an error if the file existed but we couldn't open it.
190          */
191         if (errno != ENOENT) {
192           *pref_path_return = ff_path;
193           *errno_return = errno;
194         } else {
195           g_free(ff_path);
196         }
197         return;
198       }
199     }
200   }
201
202   /* If we already have a list of filters, discard it. */
203   /* this should never happen - this function is called only once for each list! */
204   while(*flpp) {
205     *flpp = remove_filter_entry(*flpp, g_list_first(*flpp));
206   }
207
208   /* Allocate the filter name buffer. */
209   filt_name_len = INIT_BUF_SIZE;
210   filt_name = (char *)g_malloc(filt_name_len + 1);
211   filt_expr_len = INIT_BUF_SIZE;
212   filt_expr = (char *)g_malloc(filt_expr_len + 1);
213
214   for (line = 1; ; line++) {
215     /* Lines in a filter file are of the form
216
217         "name" expression
218
219        where "name" is a name, in quotes - backslashes in the name
220        escape the next character, so quotes and backslashes can appear
221        in the name - and "expression" is a filter expression, not in
222        quotes, running to the end of the line. */
223
224     /* Skip over leading white space, if any. */
225     while ((c = getc(ff)) != EOF && isspace(c)) {
226       if (c == '\n') {
227         /* Blank line. */
228         continue;
229       }
230     }
231
232     if (c == EOF)
233       break;    /* Nothing more to read */
234
235     /* "c" is the first non-white-space character.
236        If it's not a quote, it's an error. */
237     if (c != '"') {
238       g_warning("'%s' line %d doesn't have a quoted filter name.", ff_path,
239                 line);
240       while (c != '\n')
241         c = getc(ff);   /* skip to the end of the line */
242       continue;
243     }
244
245     /* Get the name of the filter. */
246     filt_name_index = 0;
247     for (;;) {
248       c = getc(ff);
249       if (c == EOF || c == '\n')
250         break;  /* End of line - or end of file */
251       if (c == '"') {
252         /* Closing quote. */
253         if (filt_name_index >= filt_name_len) {
254           /* Filter name buffer isn't long enough; double its length. */
255           filt_name_len *= 2;
256           filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
257         }
258         filt_name[filt_name_index] = '\0';
259         break;
260       }
261       if (c == '\\') {
262         /* Next character is escaped */
263         c = getc(ff);
264         if (c == EOF || c == '\n')
265           break;        /* End of line - or end of file */
266       }
267       /* Add this character to the filter name string. */
268       if (filt_name_index >= filt_name_len) {
269         /* Filter name buffer isn't long enough; double its length. */
270         filt_name_len *= 2;
271         filt_name = (char *)g_realloc(filt_name, filt_name_len + 1);
272       }
273       filt_name[filt_name_index] = c;
274       filt_name_index++;
275     }
276
277     if (c == EOF) {
278       if (!ferror(ff)) {
279         /* EOF, not error; no newline seen before EOF */
280         g_warning("'%s' line %d doesn't have a newline.", ff_path,
281                   line);
282       }
283       break;    /* nothing more to read */
284     }
285
286     if (c != '"') {
287       /* No newline seen before end-of-line */
288       g_warning("'%s' line %d doesn't have a closing quote.", ff_path,
289                 line);
290       continue;
291     }
292
293     /* Skip over separating white space, if any. */
294     while ((c = getc(ff)) != EOF && isspace(c)) {
295       if (c == '\n')
296         break;
297     }
298
299     if (c == EOF) {
300       if (!ferror(ff)) {
301         /* EOF, not error; no newline seen before EOF */
302         g_warning("'%s' line %d doesn't have a newline.", ff_path,
303                   line);
304       }
305       break;    /* nothing more to read */
306     }
307
308     if (c == '\n') {
309       /* No filter expression */
310       g_warning("'%s' line %d doesn't have a filter expression.", ff_path,
311                 line);
312       continue;
313     }
314
315     /* "c" is the first non-white-space character; it's the first
316        character of the filter expression. */
317     filt_expr_index = 0;
318     for (;;) {
319       /* Add this character to the filter expression string. */
320       if (filt_expr_index >= filt_expr_len) {
321         /* Filter expressioin buffer isn't long enough; double its length. */
322         filt_expr_len *= 2;
323         filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
324       }
325       filt_expr[filt_expr_index] = c;
326       filt_expr_index++;
327
328       /* Get the next character. */
329       c = getc(ff);
330       if (c == EOF || c == '\n')
331         break;
332     }
333
334     if (c == EOF) {
335       if (!ferror(ff)) {
336         /* EOF, not error; no newline seen before EOF */
337         g_warning("'%s' line %d doesn't have a newline.", ff_path,
338                   line);
339       }
340       break;    /* nothing more to read */
341     }
342
343     /* We saw the ending newline; terminate the filter expression string */
344     if (filt_expr_index >= filt_expr_len) {
345       /* Filter expressioin buffer isn't long enough; double its length. */
346       filt_expr_len *= 2;
347       filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1);
348     }
349     filt_expr[filt_expr_index] = '\0';
350
351     /* Add the new filter to the list of filters */
352     *flpp = add_filter_entry(*flpp, filt_name, filt_expr);
353   }
354   if (ferror(ff)) {
355     *pref_path_return = ff_path;
356     *errno_return = errno;
357   } else
358     g_free(ff_path);
359   fclose(ff);
360   g_free(filt_name);
361   g_free(filt_expr);
362
363   /* init the corresponding edited list */
364   switch (list_type) {
365   case CFILTER_LIST:
366     copy_filter_list(CFILTER_EDITED_LIST, CFILTER_LIST);
367     break;
368   case DFILTER_LIST:
369     copy_filter_list(DFILTER_EDITED_LIST, DFILTER_LIST);
370     break;
371   default:
372     g_assert_not_reached();
373     return;
374   }
375 }
376
377 /*
378  * Get a pointer to a list of filters.
379  */
380 static GList **
381 get_filter_list(filter_list_type_t list_type)
382 {
383   GList **flpp;
384
385   switch (list_type) {
386
387   case CFILTER_LIST:
388     flpp = &capture_filters;
389     break;
390
391   case DFILTER_LIST:
392     flpp = &display_filters;
393     break;
394
395   case CFILTER_EDITED_LIST:
396     flpp = &capture_edited_filters;
397     break;
398
399   case DFILTER_EDITED_LIST:
400     flpp = &display_edited_filters;
401     break;
402
403   default:
404     g_assert_not_reached();
405     flpp = NULL;
406   }
407   return flpp;
408 }
409
410 /*
411  * Get a pointer to the first entry in a filter list.
412  */
413 GList *
414 get_filter_list_first(filter_list_type_t list_type)
415 {
416   GList      **flpp;
417
418   flpp = get_filter_list(list_type);
419   return g_list_first(*flpp);
420 }
421
422 /*
423  * Add a new filter to the end of a list.
424  * Returns a pointer to the newly-added entry.
425  */
426 GList *
427 add_to_filter_list(filter_list_type_t list_type, const char *name,
428     const char *expression)
429 {
430   GList      **flpp;
431
432   flpp = get_filter_list(list_type);
433   *flpp = add_filter_entry(*flpp, name, expression);
434
435   return g_list_last(*flpp);
436 }
437
438 /*
439  * Remove a filter from a list.
440  */
441 void
442 remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry)
443 {
444   GList      **flpp;
445
446   flpp = get_filter_list(list_type);
447   *flpp = remove_filter_entry(*flpp, fl_entry);
448 }
449
450 /*
451  * Write out a list of filters.
452  *
453  * On success, "*pref_path_return" is set to NULL.
454  * On error, "*pref_path_return" is set to point to the pathname of
455  * the file we tried to read - it should be freed by our caller -
456  * and "*errno_return" is set to the error.
457  */
458 void
459 save_filter_list(filter_list_type_t list_type, char **pref_path_return,
460     int *errno_return)
461 {
462   const gchar *ff_name;
463   gchar      *ff_path, *ff_path_new;
464   GList      *fl;
465   GList      *flpp;
466   filter_def *filt;
467   FILE       *ff;
468   guchar     *p, c;
469
470   *pref_path_return = NULL;     /* assume no error */
471
472   switch (list_type) {
473
474   case CFILTER_LIST:
475     ff_name = CFILTER_FILE_NAME;
476     fl = capture_filters;
477     break;
478
479   case DFILTER_LIST:
480     ff_name = DFILTER_FILE_NAME;
481     fl = display_filters;
482     break;
483
484   default:
485     g_assert_not_reached();
486     return;
487   }
488
489   ff_path = get_persconffile_path(ff_name, TRUE);
490
491   /* Write to "XXX.new", and rename if that succeeds.
492      That means we don't trash the file if we fail to write it out
493      completely. */
494   ff_path_new = g_strdup_printf("%s.new", ff_path);
495
496   if ((ff = ws_fopen(ff_path_new, "w")) == NULL) {
497     *pref_path_return = ff_path;
498     *errno_return = errno;
499     g_free(ff_path_new);
500     return;
501   }
502   flpp = g_list_first(fl);
503   while (flpp) {
504     filt = (filter_def *) flpp->data;
505
506     /* Write out the filter name as a quoted string; escape any quotes
507        or backslashes. */
508     putc('"', ff);
509     for (p = (guchar *)filt->name; (c = *p) != '\0'; p++) {
510       if (c == '"' || c == '\\')
511         putc('\\', ff);
512       putc(c, ff);
513     }
514     putc('"', ff);
515
516     /* Separate the filter name and value with a space. */
517     putc(' ', ff);
518
519     /* Write out the filter expression and a newline. */
520     fprintf(ff, "%s\n", filt->strval);
521     if (ferror(ff)) {
522       *pref_path_return = ff_path;
523       *errno_return = errno;
524       fclose(ff);
525       ws_unlink(ff_path_new);
526       g_free(ff_path_new);
527       return;
528     }
529     flpp = flpp->next;
530   }
531   if (fclose(ff) == EOF) {
532     *pref_path_return = ff_path;
533     *errno_return = errno;
534     ws_unlink(ff_path_new);
535     g_free(ff_path_new);
536     return;
537   }
538
539 #ifdef _WIN32
540   /* ANSI C doesn't say whether "rename()" removes the target if it
541      exists; the Win32 call to rename files doesn't do so, which I
542      infer is the reason why the MSVC++ "rename()" doesn't do so.
543      We must therefore remove the target file first, on Windows.
544
545      XXX - ws_rename() should be ws_stdio_rename() on Windows,
546      and ws_stdio_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING,
547      so it should remove the target if it exists, so this stuff
548      shouldn't be necessary.  Perhaps it dates back to when we were
549      calling rename(), with that being a wrapper around Microsoft's
550      _rename(), which didn't remove the target. */
551   if (ws_remove(ff_path) < 0 && errno != ENOENT) {
552     /* It failed for some reason other than "it's not there"; if
553        it's not there, we don't need to remove it, so we just
554        drive on. */
555     *pref_path_return = ff_path;
556     *errno_return = errno;
557     ws_unlink(ff_path_new);
558     g_free(ff_path_new);
559     return;
560   }
561 #endif
562
563   if (ws_rename(ff_path_new, ff_path) < 0) {
564     *pref_path_return = ff_path;
565     *errno_return = errno;
566     ws_unlink(ff_path_new);
567     g_free(ff_path_new);
568     return;
569   }
570   g_free(ff_path_new);
571   g_free(ff_path);
572 }
573
574 /*
575  * Copy a filter list into another.
576  */
577 void copy_filter_list(filter_list_type_t dest_type, filter_list_type_t src_type)
578 {
579     GList      **flpp_dest;
580     GList      **flpp_src;
581     GList      *flp_src;
582     filter_def *filt;
583
584     g_assert(dest_type != src_type);
585
586     flpp_dest = get_filter_list(dest_type);
587     flpp_src = get_filter_list(src_type);
588     /* throw away the "old" destination list - a NULL list is ok here */
589     while(*flpp_dest) {
590         *flpp_dest = remove_filter_entry(*flpp_dest, g_list_first(*flpp_dest));
591     }
592     g_assert(g_list_length(*flpp_dest) == 0);
593
594     /* copy the list entries */
595     for(flp_src = g_list_first(*flpp_src); flp_src; flp_src = g_list_next(flp_src)) {
596         filt = (filter_def *)(flp_src->data);
597
598         *flpp_dest = add_filter_entry(*flpp_dest, filt->name, filt->strval);
599     }
600 }
601