epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-pop.c
blob2c63b0dd425646796fed124130865f92b89fa09a
1 /* packet-pop.c
2 * Routines for pop packet dissection
3 * RFC 1939
4 * Copyright 1999, Richard Sharpe <rsharpe@ns.aus.com>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * Copied from packet-tftp.c
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
17 #include <stdlib.h>
19 #include <epan/packet.h>
20 #include <epan/strutil.h>
21 #include <epan/conversation.h>
22 #include <epan/prefs.h>
23 #include <epan/reassemble.h>
24 #include <epan/proto_data.h>
25 #include <epan/expert.h>
27 #include <wsutil/str_util.h>
28 #include <wsutil/strtoi.h>
30 #include <ui/tap-credentials.h>
31 #include <tap.h>
33 #include "packet-tls.h"
34 #include "packet-tls-utils.h"
36 void proto_register_pop(void);
37 void proto_reg_handoff_pop(void);
39 static int proto_pop;
41 static int credentials_tap;
43 static int hf_pop_response;
44 static int hf_pop_response_indicator;
45 static int hf_pop_response_description;
46 static int hf_pop_response_data;
48 static int hf_pop_request;
49 static int hf_pop_request_command;
50 static int hf_pop_request_parameter;
51 static int hf_pop_request_data;
53 static int hf_pop_data_fragments;
54 static int hf_pop_data_fragment;
55 static int hf_pop_data_fragment_overlap;
56 static int hf_pop_data_fragment_overlap_conflicts;
57 static int hf_pop_data_fragment_multiple_tails;
58 static int hf_pop_data_fragment_too_long_fragment;
59 static int hf_pop_data_fragment_error;
60 static int hf_pop_data_fragment_count;
61 static int hf_pop_data_reassembled_in;
62 static int hf_pop_data_reassembled_length;
64 static expert_field ei_pop_resp_tot_len_invalid;
66 static int ett_pop;
67 static int ett_pop_reqresp;
69 static int ett_pop_data_fragment;
70 static int ett_pop_data_fragments;
72 static dissector_handle_t pop_handle;
73 static dissector_handle_t imf_handle;
74 static dissector_handle_t tls_handle;
76 #define TCP_PORT_POP 110
77 #define TCP_PORT_SSL_POP 995
79 /* desegmentation of POP command and response lines */
80 static bool pop_data_desegment = true;
82 static reassembly_table pop_data_reassembly_table;
84 static const fragment_items pop_data_frag_items = {
85 /* Fragment subtrees */
86 &ett_pop_data_fragment,
87 &ett_pop_data_fragments,
88 /* Fragment fields */
89 &hf_pop_data_fragments,
90 &hf_pop_data_fragment,
91 &hf_pop_data_fragment_overlap,
92 &hf_pop_data_fragment_overlap_conflicts,
93 &hf_pop_data_fragment_multiple_tails,
94 &hf_pop_data_fragment_too_long_fragment,
95 &hf_pop_data_fragment_error,
96 &hf_pop_data_fragment_count,
97 /* Reassembled in field */
98 &hf_pop_data_reassembled_in,
99 /* Reassembled length field */
100 &hf_pop_data_reassembled_length,
101 /* Reassembled data field */
102 NULL,
103 /* Tag */
104 "DATA fragments"
107 struct pop_proto_data {
108 uint16_t conversation_id;
109 bool more_frags;
112 struct pop_data_val {
113 bool msg_request;
114 uint32_t msg_read_len; /* Length of RETR message read so far */
115 uint32_t msg_tot_len; /* Total length of RETR message */
116 bool stls_request; /* Received STLS request */
117 char* username;
118 unsigned username_num;
121 typedef enum {
122 pop_arg_type_unknown,
123 pop_arg_type_username,
124 pop_arg_type_password
125 } pop_arg_type_t;
127 static bool response_is_continuation(const unsigned char *data);
129 static int
130 dissect_pop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
132 struct pop_proto_data *frame_data_p;
133 bool is_request;
134 bool is_continuation;
135 proto_tree *pop_tree, *reqresp_tree;
136 proto_item *ti;
137 int offset = 0;
138 unsigned char *line;
139 int next_offset;
140 int linelen;
141 int tokenlen;
142 const unsigned char *next_token;
143 fragment_head *frag_msg = NULL;
144 tvbuff_t *next_tvb = NULL;
145 conversation_t *conversation = NULL;
146 struct pop_data_val *data_val = NULL;
147 int length_remaining;
148 pop_arg_type_t pop_arg_type = pop_arg_type_unknown;
150 col_set_str(pinfo->cinfo, COL_PROTOCOL, "POP");
152 frame_data_p = (struct pop_proto_data *)p_get_proto_data(wmem_file_scope(), pinfo, proto_pop, 0);
154 conversation = find_or_create_conversation(pinfo);
155 data_val = (struct pop_data_val *)conversation_get_proto_data(conversation, proto_pop);
156 if (!data_val) {
159 * No conversation - create one and attach it.
161 data_val = wmem_new0(wmem_file_scope(), struct pop_data_val);
163 conversation_add_proto_data(conversation, proto_pop, data_val);
167 * Find the end of the first line.
169 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false);
170 line = (unsigned char*)wmem_alloc(pinfo->pool, linelen+1);
171 tvb_memcpy(tvb, line, offset, linelen);
172 line[linelen] = '\0';
174 if (pinfo->match_uint == pinfo->destport) {
175 is_request = true;
176 is_continuation = false;
177 } else {
178 is_request = false;
179 is_continuation = response_is_continuation(line);
183 * Put the first line from the buffer into the summary
184 * if it's a POP request or reply (but leave out the
185 * line terminator).
186 * Otherwise, just call it a continuation.
188 if (is_continuation) {
189 length_remaining = tvb_reported_length_remaining(tvb, offset);
190 col_add_fstr(pinfo->cinfo, COL_INFO, "S: DATA fragment, %d byte%s",
191 length_remaining, plurality (length_remaining, "", "s"));
193 else
194 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s", is_request ? "C" : "S",
195 format_text(pinfo->pool, line, linelen));
197 ti = proto_tree_add_item(tree, proto_pop, tvb, offset, -1, ENC_NA);
198 pop_tree = proto_item_add_subtree(ti, ett_pop);
200 if (is_continuation) {
202 if (pop_data_desegment) {
204 if (!frame_data_p) {
206 data_val->msg_read_len += tvb_reported_length(tvb);
208 frame_data_p = wmem_new(wmem_file_scope(), struct pop_proto_data);
210 frame_data_p->conversation_id = conversation->conv_index;
211 frame_data_p->more_frags = data_val->msg_read_len < data_val->msg_tot_len;
213 p_add_proto_data(wmem_file_scope(), pinfo, proto_pop, 0, frame_data_p);
216 frag_msg = fragment_add_seq_next(&pop_data_reassembly_table, tvb, 0,
217 pinfo,
218 frame_data_p->conversation_id,
219 NULL,
220 tvb_reported_length(tvb),
221 frame_data_p->more_frags);
223 next_tvb = process_reassembled_data(tvb, offset, pinfo,
224 "Reassembled DATA",
225 frag_msg, &pop_data_frag_items,
226 NULL, pop_tree);
228 if (next_tvb) {
230 if (imf_handle)
231 call_dissector(imf_handle, next_tvb, pinfo, tree);
233 if (data_val) {
234 /* we have read everything - reset */
236 data_val->msg_read_len = 0;
237 data_val->msg_tot_len = 0;
239 pinfo->fragmented = false;
240 } else {
241 pinfo->fragmented = true;
244 } else {
247 * Put the whole packet into the tree as data.
249 call_data_dissector(tvb, pinfo, pop_tree);
252 return tvb_captured_length(tvb);
256 * Put the line into the protocol tree.
258 ti = proto_tree_add_string_format(pop_tree,
259 (is_request) ?
260 hf_pop_request :
261 hf_pop_response,
262 tvb, offset,
263 next_offset - offset,
264 "", "%s",
265 tvb_format_text(pinfo->pool, tvb, offset, next_offset - offset));
266 reqresp_tree = proto_item_add_subtree(ti, ett_pop_reqresp);
269 * Extract the first token, and, if there is a first
270 * token, add it as the request or reply code.
272 tokenlen = get_token_len(line, line + linelen, &next_token);
273 if (tokenlen != 0) {
274 proto_tree_add_item(reqresp_tree,
275 (is_request) ?
276 hf_pop_request_command :
277 hf_pop_response_indicator,
278 tvb, offset, tokenlen, ENC_ASCII|ENC_NA);
280 if (data_val) {
281 if (is_request) {
282 /* see if this is RETR or TOP command */
283 if (g_ascii_strncasecmp(line, "RETR", 4) == 0 ||
284 g_ascii_strncasecmp(line, "TOP", 3) == 0)
285 /* the next response will tell us how many bytes */
286 data_val->msg_request = true;
288 if (g_ascii_strncasecmp(line, "STLS", 4) == 0) {
289 data_val->stls_request = true;
292 if (g_ascii_strncasecmp(line, "USER", 4) == 0) {
293 pop_arg_type = pop_arg_type_username;
296 if (g_ascii_strncasecmp(line, "PASS", 4) == 0) {
297 pop_arg_type = pop_arg_type_password;
299 } else {
300 if (data_val->msg_request) {
301 /* this is a response to a RETR or TOP command */
303 if (g_ascii_strncasecmp(line, "+OK ", 4) == 0 && linelen > 4) {
304 /* the message will be sent - work out how many bytes */
305 data_val->msg_read_len = 0;
306 data_val->msg_tot_len = 0;
307 if (sscanf(line, "%*s %u %*s", &data_val->msg_tot_len) != 1)
308 expert_add_info(pinfo, ti, &ei_pop_resp_tot_len_invalid);
310 data_val->msg_request = false;
313 if (data_val->stls_request) {
314 if (g_ascii_strncasecmp(line, "+OK ", 4) == 0) {
315 /* This is the last non-TLS frame. */
316 ssl_starttls_ack(tls_handle, pinfo, pop_handle);
318 data_val->stls_request = false;
323 offset += (int) (next_token - line);
324 linelen -= (int) (next_token - line);
329 * Add the rest of the first line as request or
330 * reply param/description.
332 if (linelen != 0) {
333 tap_credential_t* auth;
334 proto_tree_add_item(reqresp_tree,
335 (is_request) ?
336 hf_pop_request_parameter :
337 hf_pop_response_description,
338 tvb, offset, linelen, ENC_ASCII|ENC_NA);
339 switch (pop_arg_type) {
340 case pop_arg_type_username:
341 if (!data_val->username && linelen > 0) {
342 data_val->username = tvb_get_string_enc(wmem_file_scope(), tvb, offset, linelen, ENC_NA|ENC_ASCII);
343 data_val->username_num = pinfo->num;
345 break;
346 case pop_arg_type_password:
347 auth = wmem_new0(pinfo->pool, tap_credential_t);
348 auth->num = pinfo->num;
349 auth->username_num = data_val->username_num;
350 auth->password_hf_id = hf_pop_request_parameter;
351 auth->username = data_val->username;
352 auth->proto = "POP3";
353 auth->info = wmem_strdup_printf(pinfo->pool, "Username in packet %u", data_val->username_num);
354 tap_queue_packet(credentials_tap, pinfo, auth);
355 break;
356 default:
357 break;
360 offset = next_offset;
363 * Show the rest of the request or response as text,
364 * a line at a time.
366 while (tvb_offset_exists(tvb, offset)) {
368 * Find the end of the line.
370 tvb_find_line_end(tvb, offset, -1, &next_offset, false);
373 * Put this line.
375 proto_tree_add_string_format(pop_tree,
376 (is_request) ?
377 hf_pop_request_data :
378 hf_pop_response_data,
379 tvb, offset,
380 next_offset - offset,
381 "", "%s",
382 tvb_format_text(pinfo->pool, tvb, offset, next_offset - offset));
383 offset = next_offset;
385 return tvb_captured_length(tvb);
388 static bool response_is_continuation(const unsigned char *data)
390 if (strncmp(data, "+OK", strlen("+OK")) == 0)
391 return false;
393 if (strncmp(data, "-ERR", strlen("-ERR")) == 0)
394 return false;
396 return true;
399 void
400 proto_register_pop(void)
402 expert_module_t* expert_pop;
404 static hf_register_info hf[] = {
405 { &hf_pop_response,
406 { "Response", "pop.response",
407 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
408 { &hf_pop_response_indicator,
409 { "Response indicator", "pop.response.indicator",
410 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
411 { &hf_pop_response_description,
412 { "Response description", "pop.response.description",
413 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
414 { &hf_pop_response_data,
415 { "Data", "pop.response.data",
416 FT_STRING, BASE_NONE, NULL, 0x0, "Response Data", HFILL }},
417 { &hf_pop_request,
418 { "Request", "pop.request",
419 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
420 { &hf_pop_request_command,
421 { "Request command", "pop.request.command",
422 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
423 { &hf_pop_request_parameter,
424 { "Request parameter", "pop.request.parameter",
425 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
426 { &hf_pop_request_data,
427 { "Data", "pop.request.data",
428 FT_STRING, BASE_NONE, NULL, 0x0, "Request data", HFILL }},
429 /* Fragment entries */
430 { &hf_pop_data_fragments,
431 { "DATA fragments", "pop.data.fragments", FT_NONE, BASE_NONE,
432 NULL, 0x00, "Message fragments", HFILL } },
433 { &hf_pop_data_fragment,
434 { "DATA fragment", "pop.data.fragment", FT_FRAMENUM, BASE_NONE,
435 NULL, 0x00, "Message fragment", HFILL } },
436 { &hf_pop_data_fragment_overlap,
437 { "DATA fragment overlap", "pop.data.fragment.overlap", FT_BOOLEAN,
438 BASE_NONE, NULL, 0x0, "Message fragment overlap", HFILL } },
439 { &hf_pop_data_fragment_overlap_conflicts,
440 { "DATA fragment overlapping with conflicting data",
441 "pop.data.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
442 0x0, "Message fragment overlapping with conflicting data", HFILL } },
443 { &hf_pop_data_fragment_multiple_tails,
444 { "DATA has multiple tail fragments",
445 "pop.data.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
446 NULL, 0x0, "Message has multiple tail fragments", HFILL } },
447 { &hf_pop_data_fragment_too_long_fragment,
448 { "DATA fragment too long", "pop.data.fragment.too_long_fragment",
449 FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Message fragment too long",
450 HFILL } },
451 { &hf_pop_data_fragment_error,
452 { "DATA defragmentation error", "pop.data.fragment.error", FT_FRAMENUM,
453 BASE_NONE, NULL, 0x00, "Message defragmentation error", HFILL } },
454 { &hf_pop_data_fragment_count,
455 { "DATA fragment count", "pop.data.fragment.count", FT_UINT32, BASE_DEC,
456 NULL, 0x00, NULL, HFILL } },
457 { &hf_pop_data_reassembled_in,
458 { "Reassembled DATA in frame", "pop.data.reassembled.in", FT_FRAMENUM, BASE_NONE,
459 NULL, 0x00, "This DATA fragment is reassembled in this frame", HFILL } },
460 { &hf_pop_data_reassembled_length,
461 { "Reassembled DATA length", "pop.data.reassembled.length", FT_UINT32, BASE_DEC,
462 NULL, 0x00, "The total length of the reassembled payload", HFILL } },
465 static ei_register_info ei[] = {
466 { &ei_pop_resp_tot_len_invalid, { "pop.response.tot_len.invalid", PI_MALFORMED, PI_ERROR,
467 "Length must be a string containing an integer", EXPFILL }}
470 static int *ett[] = {
471 &ett_pop,
472 &ett_pop_reqresp,
473 &ett_pop_data_fragment,
474 &ett_pop_data_fragments
476 module_t *pop_module;
479 proto_pop = proto_register_protocol("Post Office Protocol", "POP", "pop");
480 pop_handle = register_dissector("pop", dissect_pop, proto_pop);
481 proto_register_field_array(proto_pop, hf, array_length(hf));
482 proto_register_subtree_array(ett, array_length(ett));
484 reassembly_table_register (&pop_data_reassembly_table,
485 &addresses_ports_reassembly_table_functions);
487 /* Preferences */
488 pop_module = prefs_register_protocol(proto_pop, NULL);
490 prefs_register_bool_preference(pop_module, "desegment_data",
491 "Reassemble POP RETR and TOP responses spanning multiple TCP segments",
492 "Whether the POP dissector should reassemble RETR and TOP responses and spanning multiple TCP segments."
493 " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
494 &pop_data_desegment);
496 expert_pop = expert_register_protocol(proto_pop);
497 expert_register_field_array(expert_pop, ei, array_length(ei));
499 credentials_tap = register_tap("credentials");
502 void
503 proto_reg_handoff_pop(void)
505 dissector_add_uint_with_preference("tcp.port", TCP_PORT_POP, pop_handle);
506 ssl_dissector_add(TCP_PORT_SSL_POP, pop_handle);
508 /* find the IMF dissector */
509 imf_handle = find_dissector_add_dependency("imf", proto_pop);
511 /* find the TLS dissector */
512 tls_handle = find_dissector_add_dependency("tls", proto_pop);
516 * Editor modelines - https://www.wireshark.org/tools/modelines.html
518 * Local Variables:
519 * c-basic-offset: 2
520 * tab-width: 8
521 * indent-tabs-mode: nil
522 * End:
524 * ex: set shiftwidth=2 tabstop=8 expandtab:
525 * :indentSize=2:tabSize=8:noTabs=true: