Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / sharkd.c
blob8cfa76c0448cbc0718678433a04f8e0d275f7f2c
1 /* sharkd.c
3 * Daemon variant of Wireshark
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <config.h>
13 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <limits.h>
19 #include <signal.h>
21 #include <glib.h>
23 #include <epan/exceptions.h>
24 #include <epan/epan.h>
26 #include <wsutil/clopts_common.h>
27 #include <wsutil/cmdarg_err.h>
28 #include <wsutil/filesystem.h>
29 #include <wsutil/file_util.h>
30 #include <wsutil/privileges.h>
31 #include <wsutil/wslog.h>
32 #include <wsutil/version_info.h>
33 #include <wiretap/wtap_opttypes.h>
35 #include <epan/decode_as.h>
36 #include <epan/timestamp.h>
37 #include <epan/packet.h>
38 #include <epan/disabled_protos.h>
39 #include <epan/prefs.h>
40 #include <epan/column.h>
41 #include <epan/print.h>
42 #include <epan/addr_resolv.h>
43 #include "ui/util.h"
44 #include "ui/ws_ui_util.h"
45 #include "ui/decode_as_utils.h"
46 #include "wsutil/filter_files.h"
47 #include "ui/tap_export_pdu.h"
48 #include "ui/failure_message.h"
49 #include <wiretap/wtap.h>
50 #include <epan/epan_dissect.h>
51 #include <epan/tap.h>
52 #include <epan/uat-int.h>
53 #include <epan/secrets.h>
55 #include <wsutil/codecs.h>
57 #include <wsutil/str_util.h>
58 #include <wsutil/utf8_entities.h>
60 #ifdef HAVE_PLUGINS
61 #include <wsutil/plugins.h>
62 #endif
64 #include "sharkd.h"
66 #define SHARKD_INIT_FAILED 1
67 #define SHARKD_EPAN_INIT_FAIL 2
69 capture_file cfile;
71 static uint32_t cum_bytes;
72 static frame_data ref_frame;
74 static void
75 print_current_user(void)
77 char *cur_user, *cur_group;
79 if (started_with_special_privs()) {
80 cur_user = get_cur_username();
81 cur_group = get_cur_groupname();
82 fprintf(stderr, "Running as user \"%s\" and group \"%s\".",
83 cur_user, cur_group);
84 g_free(cur_user);
85 g_free(cur_group);
86 if (running_with_special_privs()) {
87 fprintf(stderr, " This could be dangerous.");
89 fprintf(stderr, "\n");
93 int
94 main(int argc, char *argv[])
96 char *configuration_init_error;
98 char *err_msg = NULL;
99 e_prefs *prefs_p;
100 int ret = EXIT_SUCCESS;
102 /* Set the program name. */
103 g_set_prgname("sharkd");
105 cmdarg_err_init(stderr_cmdarg_err, stderr_cmdarg_err_cont);
107 /* Initialize log handler early so we can have proper logging during startup. */
108 ws_log_init(vcmdarg_err);
110 /* Early logging command-line initialization. */
111 ws_log_parse_args(&argc, argv, vcmdarg_err, SHARKD_INIT_FAILED);
113 ws_noisy("Finished log init and parsing command line log arguments");
116 * Get credential information for later use, and drop privileges
117 * before doing anything else.
118 * Let the user know if anything happened.
120 init_process_policies();
121 relinquish_special_privs_perm();
122 print_current_user();
125 * Attempt to get the pathname of the executable file.
127 configuration_init_error = configuration_init(argv[0]);
128 if (configuration_init_error != NULL) {
129 fprintf(stderr, "sharkd: Can't get pathname of sharkd program: %s.\n",
130 configuration_init_error);
133 /* Initialize the version information. */
134 ws_init_version_info("Sharkd",
135 epan_gather_compile_info,
136 epan_gather_runtime_info);
138 if (sharkd_init(argc, argv) < 0)
140 fputs("Cannot initialize sharkd.\n", stderr);
141 ret = SHARKD_INIT_FAILED;
142 goto clean_exit;
145 init_report_failure_message("sharkd");
147 timestamp_set_type(TS_RELATIVE);
148 timestamp_set_precision(TS_PREC_AUTO);
149 timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
152 * Libwiretap must be initialized before libwireshark is, so that
153 * dissection-time handlers for file-type-dependent blocks can
154 * register using the file type/subtype value for the file type.
156 wtap_init(true);
158 /* Register all dissectors; we must do this before checking for the
159 "-G" flag, as the "-G" flag dumps information registered by the
160 dissectors, and we must do it before we read the preferences, in
161 case any dissectors register preferences. */
162 if (!epan_init(NULL, NULL, true)) {
163 ret = SHARKD_EPAN_INIT_FAIL;
164 goto clean_exit;
167 codecs_init();
169 /* Load libwireshark settings from the current profile. */
170 prefs_p = epan_load_settings();
172 if (!color_filters_init(&err_msg, NULL)) {
173 fprintf(stderr, "%s\n", err_msg);
174 g_free(err_msg);
177 cap_file_init(&cfile);
179 /* Notify all registered modules that have had any of their preferences
180 changed either from one of the preferences file or from the command
181 line that their preferences have changed. */
182 prefs_apply_all();
184 /* Build the column format array */
185 build_column_format_array(&cfile.cinfo, prefs_p->num_cols, true);
187 #ifdef HAVE_MAXMINDDB
188 /* mmdbresolve is started from mmdb_resolve_start(), which is called from epan_load_settings via: read_prefs -> (...) uat_load_all -> maxmind_db_post_update_cb.
189 * Need to stop it, otherwise all sharkd will have same mmdbresolve process, including pipe descriptors to read and write. */
190 uat_get_table_by_name("MaxMind Database Paths")->reset_cb();
191 #endif
193 ret = sharkd_loop(argc, argv);
194 clean_exit:
195 col_cleanup(&cfile.cinfo);
196 codecs_cleanup();
197 wtap_cleanup();
198 free_progdirs();
199 return ret;
202 static epan_t *
203 sharkd_epan_new(capture_file *cf)
205 static const struct packet_provider_funcs funcs = {
206 cap_file_provider_get_frame_ts,
207 cap_file_provider_get_interface_name,
208 cap_file_provider_get_interface_description,
209 cap_file_provider_get_modified_block
212 return epan_new(&cf->provider, &funcs);
215 static bool
216 process_packet(capture_file *cf, epan_dissect_t *edt,
217 int64_t offset, wtap_rec *rec, Buffer *buf)
219 frame_data fdlocal;
220 bool passed;
222 /* If we're not running a display filter and we're not printing any
223 packet information, we don't need to do a dissection. This means
224 that all packets can be marked as 'passed'. */
225 passed = true;
227 /* The frame number of this packet, if we add it to the set of frames,
228 would be one more than the count of frames in the file so far. */
229 frame_data_init(&fdlocal, cf->count + 1, rec, offset, cum_bytes);
231 /* If we're going to print packet information, or we're going to
232 run a read filter, or display filter, or we're going to process taps, set up to
233 do a dissection and do so. */
234 if (edt) {
235 if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
236 gbl_resolv_flags.transport_name)
237 /* Grab any resolved addresses */
238 host_name_lookup_process();
240 /* If we're running a read filter, prime the epan_dissect_t with that
241 filter. */
242 if (cf->rfcode)
243 epan_dissect_prime_with_dfilter(edt, cf->rfcode);
245 if (cf->dfcode)
246 epan_dissect_prime_with_dfilter(edt, cf->dfcode);
248 /* This is the first and only pass, so prime the epan_dissect_t
249 with the hfids postdissectors want on the first pass. */
250 prime_epan_dissect_with_postdissector_wanted_hfids(edt);
252 frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
253 &cf->provider.ref, cf->provider.prev_dis);
254 if (cf->provider.ref == &fdlocal) {
255 ref_frame = fdlocal;
256 cf->provider.ref = &ref_frame;
259 epan_dissect_run(edt, cf->cd_t, rec,
260 ws_buffer_start_ptr(buf),
261 &fdlocal, NULL);
263 /* Run the read filter if we have one. */
264 if (cf->rfcode)
265 passed = dfilter_apply_edt(cf->rfcode, edt);
268 if (passed) {
269 frame_data_set_after_dissect(&fdlocal, &cum_bytes);
270 cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.frames, &fdlocal);
272 /* If we're not doing dissection then there won't be any dependent frames.
273 * More importantly, edt.pi.fd.dependent_frames won't be initialized because
274 * epan hasn't been initialized.
275 * if we *are* doing dissection, then mark the dependent frames, but only
276 * if a display filter was given and it matches this packet.
278 if (edt && cf->dfcode) {
279 if (dfilter_apply_edt(cf->dfcode, edt) && edt->pi.fd->dependent_frames) {
280 g_hash_table_foreach(edt->pi.fd->dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames);
284 cf->count++;
285 } else {
286 /* if we don't add it to the frame_data_sequence, clean it up right now
287 * to avoid leaks */
288 frame_data_destroy(&fdlocal);
291 if (edt)
292 epan_dissect_reset(edt);
294 return passed;
298 static int
299 load_cap_file(capture_file *cf, int max_packet_count, int64_t max_byte_count)
301 int err;
302 char *err_info = NULL;
303 int64_t data_offset;
304 wtap_rec rec;
305 Buffer buf;
306 epan_dissect_t *edt = NULL;
309 /* Allocate a frame_data_sequence for all the frames. */
310 cf->provider.frames = new_frame_data_sequence();
313 bool create_proto_tree;
316 * Determine whether we need to create a protocol tree.
317 * We do if:
319 * we're going to apply a read filter;
321 * we're going to apply a display filter;
323 * a postdissector wants field values or protocols
324 * on the first pass.
326 create_proto_tree =
327 (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
329 /* We're not going to display the protocol tree on this pass,
330 so it's not going to be "visible". */
331 edt = epan_dissect_new(cf->epan, create_proto_tree, false);
334 wtap_rec_init(&rec);
335 ws_buffer_init(&buf, 1514);
337 while (wtap_read(cf->provider.wth, &rec, &buf, &err, &err_info, &data_offset)) {
338 if (process_packet(cf, edt, data_offset, &rec, &buf)) {
339 wtap_rec_reset(&rec);
340 /* Stop reading if we have the maximum number of packets;
341 * When the -c option has not been used, max_packet_count
342 * starts at 0, which practically means, never stop reading.
343 * (unless we roll over max_packet_count ?)
345 if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
346 err = 0; /* This is not an error */
347 break;
352 if (edt) {
353 epan_dissect_free(edt);
354 edt = NULL;
357 wtap_rec_cleanup(&rec);
358 ws_buffer_free(&buf);
360 /* Close the sequential I/O side, to free up memory it requires. */
361 wtap_sequential_close(cf->provider.wth);
363 /* Allow the protocol dissectors to free up memory that they
364 * don't need after the sequential run-through of the packets. */
365 postseq_cleanup_all_protocols();
367 cf->provider.prev_dis = NULL;
368 cf->provider.prev_cap = NULL;
371 if (err != 0) {
372 cfile_read_failure_message(cf->filename, err, err_info);
375 return err;
378 cf_status_t
379 cf_open(capture_file *cf, const char *fname, unsigned int type, bool is_tempfile, int *err)
381 wtap *wth;
382 char *err_info;
384 wth = wtap_open_offline(fname, type, err, &err_info, true);
385 if (wth == NULL)
386 goto fail;
388 /* The open succeeded. Fill in the information for this file. */
390 cf->provider.wth = wth;
391 cf->f_datalen = 0; /* not used, but set it anyway */
393 /* Set the file name because we need it to set the follow stream filter.
394 XXX - is that still true? We need it for other reasons, though,
395 in any case. */
396 cf->filename = g_strdup(fname);
398 /* Indicate whether it's a permanent or temporary file. */
399 cf->is_tempfile = is_tempfile;
401 /* No user changes yet. */
402 cf->unsaved_changes = false;
404 cf->cd_t = wtap_file_type_subtype(cf->provider.wth);
405 cf->open_type = type;
406 cf->count = 0;
407 cf->drops_known = false;
408 cf->drops = 0;
409 cf->snap = wtap_snapshot_length(cf->provider.wth);
410 nstime_set_zero(&cf->elapsed_time);
411 cf->provider.ref = NULL;
412 cf->provider.prev_dis = NULL;
413 cf->provider.prev_cap = NULL;
415 /* Create new epan session for dissection. */
416 epan_free(cf->epan);
417 cf->epan = sharkd_epan_new(cf);
419 cf->state = FILE_READ_IN_PROGRESS;
421 wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name);
422 wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name);
423 wtap_set_cb_new_secrets(cf->provider.wth, secrets_wtap_callback);
425 return CF_OK;
427 fail:
428 cfile_open_failure_message(fname, *err, err_info);
429 return CF_ERROR;
432 cf_status_t
433 sharkd_cf_open(const char *fname, unsigned int type, bool is_tempfile, int *err)
435 return cf_open(&cfile, fname, type, is_tempfile, err);
439 sharkd_load_cap_file(void)
441 return load_cap_file(&cfile, 0, 0);
444 frame_data *
445 sharkd_get_frame(uint32_t framenum)
447 return frame_data_sequence_find(cfile.provider.frames, framenum);
450 enum dissect_request_status
451 sharkd_dissect_request(uint32_t framenum, uint32_t frame_ref_num,
452 uint32_t prev_dis_num, wtap_rec *rec, Buffer *buf,
453 column_info *cinfo, uint32_t dissect_flags,
454 sharkd_dissect_func_t cb, void *data,
455 int *err, char **err_info)
457 frame_data *fdata;
458 epan_dissect_t edt;
459 bool create_proto_tree;
461 fdata = sharkd_get_frame(framenum);
462 if (fdata == NULL)
463 return DISSECT_REQUEST_NO_SUCH_FRAME;
465 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, rec, buf, err, err_info)) {
466 if (cinfo != NULL)
467 col_fill_in_error(cinfo, fdata, false, false /* fill_fd_columns */);
468 return DISSECT_REQUEST_READ_ERROR; /* error reading the record */
471 create_proto_tree = ((dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE) ||
472 ((dissect_flags & SHARKD_DISSECT_FLAG_COLOR) && color_filters_used()) ||
473 (cinfo && have_custom_cols(cinfo)));
474 epan_dissect_init(&edt, cfile.epan, create_proto_tree, (dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE));
476 if (dissect_flags & SHARKD_DISSECT_FLAG_COLOR) {
477 color_filters_prime_edt(&edt);
478 fdata->need_colorize = 1;
481 if (cinfo)
482 col_custom_prime_edt(&edt, cinfo);
485 * XXX - need to catch an OutOfMemoryError exception and
486 * attempt to recover from it.
488 fdata->ref_time = (framenum == frame_ref_num);
489 fdata->frame_ref_num = frame_ref_num;
490 fdata->prev_dis_num = prev_dis_num;
491 epan_dissect_run(&edt, cfile.cd_t, rec,
492 ws_buffer_start_ptr(buf),
493 fdata, cinfo);
495 if (cinfo) {
496 /* "Stringify" non frame_data vals */
497 epan_dissect_fill_in_columns(&edt, false, true/* fill_fd_columns */);
500 cb(&edt, (dissect_flags & SHARKD_DISSECT_FLAG_PROTO_TREE) ? edt.tree : NULL,
501 cinfo, (dissect_flags & SHARKD_DISSECT_FLAG_BYTES) ? edt.pi.data_src : NULL,
502 data);
504 wtap_rec_reset(rec);
505 epan_dissect_cleanup(&edt);
506 return DISSECT_REQUEST_SUCCESS;
510 sharkd_retap(void)
512 uint32_t framenum;
513 frame_data *fdata;
514 Buffer buf;
515 wtap_rec rec;
516 int err;
517 char *err_info = NULL;
519 unsigned tap_flags;
520 bool create_proto_tree;
521 epan_dissect_t edt;
522 column_info *cinfo;
524 /* Get the union of the flags for all tap listeners. */
525 tap_flags = union_of_tap_listener_flags();
527 /* If any tap listeners require the columns, construct them. */
528 cinfo = (tap_listeners_require_columns()) ? &cfile.cinfo : NULL;
531 * Determine whether we need to create a protocol tree.
532 * We do if:
534 * one of the tap listeners is going to apply a filter;
536 * one of the tap listeners requires a protocol tree.
538 create_proto_tree =
539 (have_filtering_tap_listeners() || (tap_flags & TL_REQUIRES_PROTO_TREE));
541 wtap_rec_init(&rec);
542 ws_buffer_init(&buf, 1514);
543 epan_dissect_init(&edt, cfile.epan, create_proto_tree, false);
545 reset_tap_listeners();
547 for (framenum = 1; framenum <= cfile.count; framenum++) {
548 fdata = sharkd_get_frame(framenum);
550 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
551 break;
553 fdata->ref_time = false;
554 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
555 fdata->prev_dis_num = framenum - 1;
556 epan_dissect_run_with_taps(&edt, cfile.cd_t, &rec,
557 ws_buffer_start_ptr(&buf),
558 fdata, cinfo);
559 wtap_rec_reset(&rec);
560 epan_dissect_reset(&edt);
563 wtap_rec_cleanup(&rec);
564 ws_buffer_free(&buf);
565 epan_dissect_cleanup(&edt);
567 draw_tap_listeners(true);
569 return 0;
573 sharkd_filter(const char *dftext, uint8_t **result)
575 dfilter_t *dfcode = NULL;
577 uint32_t framenum, prev_dis_num = 0;
578 uint32_t frames_count;
579 Buffer buf;
580 wtap_rec rec;
581 int err;
582 char *err_info = NULL;
584 uint8_t *result_bits;
585 uint8_t passed_bits;
587 epan_dissect_t edt;
589 if (!dfilter_compile(dftext, &dfcode, NULL)) {
590 return -1;
593 /* if dfilter_compile() success, but (dfcode == NULL) all frames are matching */
594 if (dfcode == NULL) {
595 *result = NULL;
596 return 0;
599 frames_count = cfile.count;
601 wtap_rec_init(&rec);
602 ws_buffer_init(&buf, 1514);
603 epan_dissect_init(&edt, cfile.epan, true, false);
605 passed_bits = 0;
606 result_bits = (uint8_t *) g_malloc(2 + (frames_count / 8));
608 for (framenum = 1; framenum <= frames_count; framenum++) {
609 frame_data *fdata = sharkd_get_frame(framenum);
611 if ((framenum & 7) == 0) {
612 result_bits[(framenum / 8) - 1] = passed_bits;
613 passed_bits = 0;
616 if (!wtap_seek_read(cfile.provider.wth, fdata->file_off, &rec, &buf, &err, &err_info))
617 break;
619 /* frame_data_set_before_dissect */
620 epan_dissect_prime_with_dfilter(&edt, dfcode);
622 fdata->ref_time = false;
623 fdata->frame_ref_num = (framenum != 1) ? 1 : 0;
624 fdata->prev_dis_num = prev_dis_num;
625 epan_dissect_run(&edt, cfile.cd_t, &rec,
626 ws_buffer_start_ptr(&cfile.buf),
627 fdata, NULL);
629 if (dfilter_apply_edt(dfcode, &edt)) {
630 passed_bits |= (1 << (framenum % 8));
631 prev_dis_num = framenum;
634 /* if passed or ref -> frame_data_set_after_dissect */
636 wtap_rec_reset(&rec);
637 epan_dissect_reset(&edt);
640 if ((framenum & 7) == 0)
641 framenum--;
642 result_bits[framenum / 8] = passed_bits;
644 wtap_rec_cleanup(&rec);
645 ws_buffer_free(&buf);
646 epan_dissect_cleanup(&edt);
648 dfilter_free(dfcode);
650 *result = result_bits;
652 return framenum;
656 * Get the modified block if available, nothing otherwise.
657 * Must be cloned if changes desired.
659 wtap_block_t
660 sharkd_get_modified_block(const frame_data *fd)
662 return cap_file_provider_get_modified_block(&cfile.provider, fd);
666 * Gets the modified block if available, otherwise the packet's default block,
667 * or a new packet block.
668 * User must wtap_block_unref() it when done.
670 wtap_block_t
671 sharkd_get_packet_block(const frame_data *fd)
673 if (fd->has_modified_block)
674 return wtap_block_ref(cap_file_provider_get_modified_block(&cfile.provider, fd));
675 else
677 wtap_rec rec; /* Record metadata */
678 Buffer buf; /* Record data */
679 wtap_block_t block;
680 int err;
681 char *err_info;
683 wtap_rec_init(&rec);
684 ws_buffer_init(&buf, 1514);
686 if (!wtap_seek_read(cfile.provider.wth, fd->file_off, &rec, &buf, &err, &err_info))
687 { /* XXX, what we can do here? */ }
689 /* rec.block is owned by the record, steal it before it is gone. */
690 block = wtap_block_ref(rec.block);
692 wtap_rec_cleanup(&rec);
693 ws_buffer_free(&buf);
694 return block;
699 sharkd_set_modified_block(frame_data *fd, wtap_block_t new_block)
701 cap_file_provider_set_modified_block(&cfile.provider, fd, new_block);
702 return 0;