Trivial warning fixes
[obnox/wireshark/wip.git] / epan / dissectors / packet-smtp.c
1 /* packet-smtp.c
2  * Routines for SMTP packet disassembly
3  *
4  * $Id$
5  *
6  * Copyright (c) 2000 by Richard Sharpe <rsharpe@ns.aus.com>
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1999 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include <glib.h>
36 #include <string.h>
37 #include <epan/packet.h>
38 #include <epan/conversation.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/prefs.h>
41 #include <epan/strutil.h>
42 #include <epan/emem.h>
43 #include <epan/reassemble.h>
44
45 /* RFC 2821 */
46 #define TCP_PORT_SMTP 25
47
48 /* RFC 4409 */
49 #define TCP_PORT_SUBMISSION 587
50
51 static int proto_smtp = -1;
52
53 static int hf_smtp_req = -1;
54 static int hf_smtp_rsp = -1;
55 static int hf_smtp_req_command = -1;
56 static int hf_smtp_req_parameter = -1;
57 static int hf_smtp_rsp_code = -1;
58 static int hf_smtp_rsp_parameter = -1;
59
60 static int hf_smtp_data_fragments = -1;
61 static int hf_smtp_data_fragment = -1;
62 static int hf_smtp_data_fragment_overlap = -1;
63 static int hf_smtp_data_fragment_overlap_conflicts = -1;
64 static int hf_smtp_data_fragment_multiple_tails = -1;
65 static int hf_smtp_data_fragment_too_long_fragment = -1;
66 static int hf_smtp_data_fragment_error = -1;
67 static int hf_smtp_data_reassembled_in = -1;
68
69 static int ett_smtp = -1;
70 static int ett_smtp_cmdresp = -1;
71
72 static gint ett_smtp_data_fragment = -1;
73 static gint ett_smtp_data_fragments = -1;
74
75 /* desegmentation of SMTP command and response lines */
76 static gboolean smtp_desegment = TRUE;
77 static gboolean smtp_data_desegment = TRUE;
78
79 static GHashTable *smtp_data_segment_table = NULL;
80 static GHashTable *smtp_data_reassembled_table = NULL;
81
82 static const fragment_items smtp_data_frag_items = {
83         /* Fragment subtrees */
84         &ett_smtp_data_fragment,
85         &ett_smtp_data_fragments,
86         /* Fragment fields */
87         &hf_smtp_data_fragments,
88         &hf_smtp_data_fragment,
89         &hf_smtp_data_fragment_overlap,
90         &hf_smtp_data_fragment_overlap_conflicts,
91         &hf_smtp_data_fragment_multiple_tails,
92         &hf_smtp_data_fragment_too_long_fragment,
93         &hf_smtp_data_fragment_error,
94         /* Reassembled in field */
95         &hf_smtp_data_reassembled_in,
96         /* Tag */
97         "DATA fragments"
98 };
99
100 static  dissector_handle_t ssl_handle;
101 static  dissector_handle_t imf_handle;
102
103 /*
104  * A CMD is an SMTP command, MESSAGE is the message portion, and EOM is the
105  * last part of a message
106  */
107 #define SMTP_PDU_CMD     0
108 #define SMTP_PDU_MESSAGE 1
109 #define SMTP_PDU_EOM     2
110
111 struct smtp_proto_data {
112   guint16 pdu_type;
113   guint16 conversation_id;
114   gboolean more_frags;
115 };
116
117 /*
118  * State information stored with a conversation.
119  */
120 typedef enum {
121   READING_CMDS,              /* reading commands */
122   READING_DATA,              /* reading message data */
123   AWAITING_STARTTLS_RESPONSE /* sent STARTTLS, awaiting response */
124 } smtp_state_t;
125
126 struct smtp_session_state {
127   smtp_state_t smtp_state;   /* Current state */
128   gboolean crlf_seen;        /* Have we seen a CRLF on the end of a packet */
129   gboolean data_seen;        /* Have we seen a DATA command yet */
130   guint32 msg_read_len;      /* Length of BDAT message read so far */
131   guint32 msg_tot_len;       /* Total length of BDAT message */
132   gboolean msg_last;         /* Is this the last BDAT chunk */
133   guint32 last_nontls_frame; /* last non-TLS frame; 0 if not known or no TLS */
134 };
135
136 /*
137  * See
138  *
139  *      http://support.microsoft.com/default.aspx?scid=kb;[LN];812455
140  *
141  * for the Exchange extensions.
142  */
143 static const struct {
144   const char *command;
145   int len;
146 } commands[] = {
147   { "STARTTLS", 8 },            /* RFC 2487 */
148   { "X-EXPS", 6 },              /* Microsoft Exchange */
149   { "X-LINK2STATE", 12 },       /* Microsoft Exchange */
150   { "XEXCH50", 7 }              /* Microsoft Exchange */
151 };
152
153 #define NCOMMANDS       (sizeof commands / sizeof commands[0])
154
155 static gboolean
156 line_is_smtp_command(const guchar *command, int commandlen)
157 {
158   size_t i;
159
160   /*
161    * To quote RFC 821, "Command codes are four alphabetic
162    * characters".
163    *
164    * However, there are some SMTP extensions that involve commands
165    * longer than 4 characters and/or that contain non-alphabetic
166    * characters; we treat them specially.
167    *
168    * XXX - should we just have a table of known commands?  Or would
169    * that fail to catch some extensions we don't know about?
170    */
171   if (commandlen == 4 && g_ascii_isalpha(command[0]) &&
172       g_ascii_isalpha(command[1]) && g_ascii_isalpha(command[2]) &&
173       g_ascii_isalpha(command[3])) {
174     /* standard 4-alphabetic command */
175     return TRUE;
176   }
177
178   /*
179    * Check the list of non-4-alphabetic commands.
180    */
181   for (i = 0; i < NCOMMANDS; i++) {
182     if (commandlen == commands[i].len &&
183         g_ascii_strncasecmp(command, commands[i].command, commands[i].len) == 0)
184       return TRUE;
185   }
186   return FALSE;
187 }
188
189 static void
190 dissect_smtp_data(tvbuff_t *tvb, int offset, proto_tree *smtp_tree)
191 {
192   gint next_offset;
193
194   if (smtp_tree) {
195     while (tvb_offset_exists(tvb, offset)) {
196       /*
197        * Find the end of the line.
198        */
199       tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
200
201       /*
202        * Put this line.
203        */
204       proto_tree_add_text(smtp_tree, tvb, offset, next_offset - offset,
205                           "Message: %s",
206                           tvb_format_text(tvb, offset, next_offset - offset));
207
208       /*
209        * Step to the next line.
210        */
211       offset = next_offset;
212     }
213   }
214 }
215
216 static void
217 dissect_smtp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
218 {
219     struct smtp_proto_data    *frame_data;
220     proto_tree                *smtp_tree = NULL;
221     proto_tree                *cmdresp_tree;
222     proto_item                *ti, *hidden_item;
223     int                       offset = 0;
224     int                       request = 0;
225     conversation_t            *conversation;
226     struct smtp_session_state *session_state;
227     const guchar              *line, *linep, *lineend;
228     guchar                    c;
229     guint32                   code;
230     int                       linelen = 0;
231     gint                      length_remaining;
232     gboolean                  eom_seen = FALSE;
233     gint                      next_offset;
234     gint                      loffset = 0;
235     gboolean                  is_continuation_line;
236     int                       cmdlen;
237     fragment_data             *frag_msg = NULL;
238     tvbuff_t                  *next_tvb;
239
240     /* As there is no guarantee that we will only see frames in the
241      * the SMTP conversation once, and that we will see them in
242      * order - in Wireshark, the user could randomly click on frames
243      * in the conversation in any order in which they choose - we
244      * have to store information with each frame indicating whether
245      * it contains commands or data or an EOM indication.
246      *
247      * XXX - what about frames that contain *both*?  TCP is a
248      * byte-stream protocol, and there are no guarantees that
249      * TCP segment boundaries will correspond to SMTP commands
250      * or EOM indications.
251      *
252      * We only need that for the client->server stream; responses
253      * are easy to manage.
254      *
255      * If we have per frame data, use that, else, we must be on the first
256      * pass, so we figure it out on the first pass.
257      */
258
259     /*
260      * Find the conversation for this.
261      */
262     conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
263                                      pinfo->srcport, pinfo->destport, 0);
264     if (conversation == NULL) { /* No conversation, create one */
265       conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
266                                       pinfo->srcport, pinfo->destport, 0);
267     }
268
269     /*
270      * Is there a request structure attached to this conversation?
271      */
272     session_state = conversation_get_proto_data(conversation, proto_smtp);
273     if (!session_state) {
274       /*
275        * No - create one and attach it.
276        */
277       session_state = se_alloc(sizeof(struct smtp_session_state));
278       session_state->smtp_state = READING_CMDS;
279       session_state->crlf_seen = FALSE;
280       session_state->data_seen = FALSE;
281       session_state->msg_read_len = 0;
282       session_state->msg_tot_len = 0;
283       session_state->msg_last = TRUE;
284       session_state->last_nontls_frame = 0;
285
286       conversation_add_proto_data(conversation, proto_smtp, session_state);
287     }
288
289     /* Are we doing TLS? 
290      * FIXME In my understanding of RFC 2487 client and server can send SMTP cmds 
291      * after a rejected TLS negotiation
292     */
293     if (session_state->last_nontls_frame != 0 && pinfo->fd->num > session_state->last_nontls_frame) {
294       guint16 save_can_desegment;
295       /* This is TLS, not raw SMTP. TLS can desegment */
296       save_can_desegment = pinfo->can_desegment;
297       pinfo->can_desegment = pinfo->saved_can_desegment;
298       call_dissector(ssl_handle, tvb, pinfo, tree);
299       pinfo->can_desegment = save_can_desegment;
300       return;
301     }
302
303     /* Is this a request or a response? */
304     request = pinfo->destport == pinfo->match_port;
305
306     /*
307      * Is there any data attached to this frame?
308      */
309     frame_data = p_get_proto_data(pinfo->fd, proto_smtp);
310
311     if (!frame_data) {
312
313       /*
314        * No frame data.
315        */
316       if(request) {
317
318         /*
319          * Create a frame data structure and attach it to the packet.
320          */
321         frame_data = se_alloc0(sizeof(struct smtp_proto_data));
322
323         frame_data->conversation_id = conversation->index;
324         frame_data->more_frags = TRUE;
325
326         p_add_proto_data(pinfo->fd, proto_smtp, frame_data);        
327
328       }
329
330       /*
331        * Get the first line from the buffer.
332        *
333        * Note that "tvb_find_line_end()" will, if it doesn't return
334        * -1, return a value that is not longer than what's in the buffer,
335        * and "tvb_find_line_end()" will always return a value that is not
336        * longer than what's in the buffer, so the "tvb_get_ptr()" call
337        * won't throw an exception.
338        */
339       loffset = offset;
340       while (tvb_offset_exists(tvb, loffset)) {
341         linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset,
342                                     smtp_desegment && pinfo->can_desegment);
343         if (linelen == -1) {
344           if (offset == loffset) {
345             /*
346              * We didn't find a line ending, and we're doing desegmentation;
347              * tell the TCP dissector where the data for this message starts
348              * in the data it handed us, and tell it we need more bytes
349              */
350             pinfo->desegment_offset = loffset;
351             pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
352             return;
353           } else {
354             linelen = tvb_length_remaining(tvb, loffset);
355             next_offset = loffset + linelen;
356           }
357         }
358         line = tvb_get_ptr(tvb, loffset, linelen);
359
360         /*
361          * Check whether or not this packet is an end of message packet
362          * We should look for CRLF.CRLF and they may be split.
363          * We have to keep in mind that we may see what we want on
364          * two passes through here ...
365          */
366         if (session_state->smtp_state == READING_DATA) {
367           /*
368            * The order of these is important ... We want to avoid
369            * cases where there is a CRLF at the end of a packet and a
370            * .CRLF at the begining of the same packet.
371            */
372           if ((session_state->crlf_seen && tvb_strneql(tvb, loffset, ".\r\n", 3) == 0) ||
373                tvb_strneql(tvb, loffset, "\r\n.\r\n", 5) == 0)
374             eom_seen = TRUE;
375
376           length_remaining = tvb_length_remaining(tvb, loffset);
377           if (length_remaining == tvb_reported_length_remaining(tvb, loffset) &&
378               tvb_strneql(tvb, loffset + length_remaining - 2, "\r\n", 2) == 0)
379             session_state->crlf_seen = TRUE;
380           else
381             session_state->crlf_seen = FALSE;
382         }
383
384         /*
385          * OK, Check if we have seen a DATA request. We do it here for
386          * simplicity, but we have to be careful below.
387          */
388         if (request) {
389           if (session_state->smtp_state == READING_DATA) {
390             /*
391              * This is message data.
392              */
393             if (eom_seen) { /* Seen the EOM */
394               /*
395                * EOM.
396                * Everything that comes after it is commands.
397                */
398               frame_data->pdu_type = SMTP_PDU_EOM;
399               session_state->smtp_state = READING_CMDS;
400               break;
401             } else {
402               /*
403                * Message data with no EOM.
404                */
405               frame_data->pdu_type = SMTP_PDU_MESSAGE;
406
407               if (session_state->msg_tot_len > 0) {
408                 /* 
409                  * We are handling a BDAT message.
410                  * Check if we have reached end of the data chunk.
411                  */
412                 session_state->msg_read_len += tvb_length_remaining(tvb, loffset);
413
414                 if (session_state->msg_read_len == session_state->msg_tot_len) {
415                   /* 
416                    * We have reached end of BDAT data chunk.
417                    * Everything that comes after this is commands.
418                    */
419                   session_state->smtp_state = READING_CMDS;
420
421                   if (session_state->msg_last) {
422                     /* 
423                      * We have found the LAST data chunk.
424                      * The message can now be reassembled.
425                      */
426                     frame_data->more_frags = FALSE;
427                   }
428                 
429                   break; /* no need to go through the remaining lines */
430                 }
431               }
432             }
433           } else {
434             /*
435              * This is commands - unless the capture started in the
436              * middle of a session, and we're in the middle of data.
437              *
438              * Commands are not necessarily 4 characters; look
439              * for a space or the end of the line to see where
440              * the putative command ends.
441              */
442             linep = line;
443             lineend = line + linelen;
444             while (linep < lineend && (c = *linep) != ' ')
445               linep++;
446             cmdlen = linep - line;
447             if (line_is_smtp_command(line, cmdlen)) {
448               if (g_ascii_strncasecmp(line, "DATA", 4) == 0) {
449                 /*
450                  * DATA command.
451                  * This is a command, but everything that comes after it,
452                  * until an EOM, is data.
453                  */
454                 frame_data->pdu_type = SMTP_PDU_CMD;
455                 session_state->smtp_state = READING_DATA;
456                 session_state->data_seen = TRUE;
457               } else if (g_ascii_strncasecmp(line, "BDAT", 4) == 0) {
458                 /*
459                  * BDAT command.
460                  * This is a command, but everything that comes after it,
461                  * until given length is received, is data.
462                  */
463                 guint32 msg_len;
464
465                 msg_len = strtoul (line+5, NULL, 10);
466
467                 frame_data->pdu_type = SMTP_PDU_CMD;
468                 session_state->data_seen = TRUE;
469                 session_state->msg_tot_len += msg_len;
470
471                 if (msg_len == 0) {
472                   /* No data to read, next will be a command */
473                   session_state->smtp_state = READING_CMDS;
474                 } else {
475                   session_state->smtp_state = READING_DATA;
476                 }
477
478                 if (g_ascii_strncasecmp(line+linelen-4, "LAST", 4) == 0) {
479                   /*
480                    * This is the last data chunk.
481                    */
482                   session_state->msg_last = TRUE;
483
484                   if (msg_len == 0) {
485                     /* 
486                      * No more data to expect.
487                      * The message can now be reassembled.
488                      */
489                     frame_data->more_frags = FALSE;
490                   }
491                 } else {
492                   session_state->msg_last = FALSE;
493                 }
494               } else if (g_ascii_strncasecmp(line, "STARTTLS", 8) == 0) {
495                 /*
496                  * STARTTLS command.
497                  * This is a command, but if the response is 220,
498                  * everything after the response is TLS.
499                  */
500                 session_state->smtp_state = AWAITING_STARTTLS_RESPONSE;
501                 frame_data->pdu_type = SMTP_PDU_CMD;
502               } else {
503                 /*
504                  * Regular command.
505                  */
506                 frame_data->pdu_type = SMTP_PDU_CMD;
507               }
508             } else {
509               /*
510                * Assume it's message data.
511                */
512               frame_data->pdu_type = session_state->data_seen ? SMTP_PDU_MESSAGE : SMTP_PDU_CMD;
513             }
514           }
515         }
516
517         /*
518          * Step past this line.
519          */
520         loffset = next_offset;
521       }
522     }
523
524
525     /*
526      * From here, we simply add items to the tree and info to the info
527      * fields ...
528      */
529
530     if (check_col(pinfo->cinfo, COL_PROTOCOL))
531       col_set_str(pinfo->cinfo, COL_PROTOCOL, "SMTP");
532
533     if (check_col(pinfo->cinfo, COL_INFO)) {  /* Add the appropriate type here */
534       col_clear(pinfo->cinfo, COL_INFO);
535
536       /*
537        * If it is a request, we have to look things up, otherwise, just
538        * display the right things
539        */
540
541       if (request) {
542         /* We must have frame_data here ... */
543         switch (frame_data->pdu_type) {
544         case SMTP_PDU_MESSAGE:
545
546           length_remaining = tvb_length_remaining(tvb, offset);
547           col_set_str(pinfo->cinfo, COL_INFO, smtp_data_desegment ? "C: DATA fragment" : "C: Message Body");
548           col_append_fstr(pinfo->cinfo, COL_INFO, ", %d byte%s", length_remaining,
549                           plurality (length_remaining, "", "s"));
550           break;
551
552         case SMTP_PDU_EOM:
553           col_set_str(pinfo->cinfo, COL_INFO, "C: .");
554           break;
555
556         case SMTP_PDU_CMD:
557           loffset = offset;
558           while (tvb_offset_exists(tvb, loffset)) {
559             /*
560              * Find the end of the line.
561              */
562             linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
563             line = tvb_get_ptr(tvb, loffset, linelen);
564
565             if(loffset == offset) 
566               col_append_fstr(pinfo->cinfo, COL_INFO, "C: %s",
567                            format_text(line, linelen));
568             else {
569               col_append_fstr(pinfo->cinfo, COL_INFO, " | %s",
570                            format_text(line, linelen));
571             }
572
573             loffset = next_offset;
574           }
575           break;
576         }
577       } else {
578         loffset = offset;
579         while (tvb_offset_exists(tvb, loffset)) {
580           /*
581            * Find the end of the line.
582            */
583           linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
584           line = tvb_get_ptr(tvb, loffset, linelen);
585
586           if (loffset == offset) 
587             col_append_fstr(pinfo->cinfo, COL_INFO, "S: %s",
588                             format_text(line, linelen));
589           else {
590             col_append_fstr(pinfo->cinfo, COL_INFO, " | %s",
591                             format_text(line, linelen));
592           }
593
594           loffset = next_offset;
595         }
596       }
597     }
598
599     if (tree) { /* Build the tree info ... */
600       ti = proto_tree_add_item(tree, proto_smtp, tvb, offset, -1, FALSE);
601       smtp_tree = proto_item_add_subtree(ti, ett_smtp);
602     }
603
604     if (request) {
605         /*
606          * Check out whether or not we can see a command in there ...
607          * What we are looking for is not data_seen and the word DATA
608          * and not eom_seen.
609          *
610          * We will see DATA and session_state->data_seen when we process the
611          * tree view after we have seen a DATA packet when processing
612          * the packet list pane.
613          *
614          * On the first pass, we will not have any info on the packets
615          * On second and subsequent passes, we will.
616          */
617         switch (frame_data->pdu_type) {
618
619         case SMTP_PDU_MESSAGE:
620           if (smtp_data_desegment) {
621             frag_msg = fragment_add_seq_next(tvb, 0, pinfo, frame_data->conversation_id, 
622                                              smtp_data_segment_table, smtp_data_reassembled_table, 
623                                              tvb_length(tvb), frame_data->more_frags);
624           } else {
625             /*
626              * Message body.
627              * Put its lines into the protocol tree, a line at a time.
628              */
629             dissect_smtp_data(tvb, offset, smtp_tree);
630           }
631           break;
632
633         case SMTP_PDU_EOM:
634           /*
635            * End-of-message-body indicator.
636            *
637            * XXX - what about stuff after the first line?
638            * Unlikely, as the client should wait for a response to the
639            * DATA command this terminates before sending another
640            * request, but we should probably handle it.
641            */
642           proto_tree_add_text(smtp_tree, tvb, offset, linelen, "C: .");
643
644           if (smtp_data_desegment) {
645             /* add final data segment */
646             if (loffset)
647               fragment_add_seq_next(tvb, 0, pinfo, frame_data->conversation_id,
648                                     smtp_data_segment_table, smtp_data_reassembled_table,
649                                     loffset, frame_data->more_frags);
650
651             /* terminate the desegmentation */
652             frag_msg = fragment_end_seq_next (pinfo, frame_data->conversation_id, smtp_data_segment_table,
653                                               smtp_data_reassembled_table);
654           }
655           break;
656
657         case SMTP_PDU_CMD:
658           /*
659            * Command.
660            *
661            * XXX - what about stuff after the first line?
662            * Unlikely, as the client should wait for a response to the
663            * previous command before sending another request, but we
664            * should probably handle it.
665            */
666
667           loffset = offset;
668           while (tvb_offset_exists(tvb, loffset)) {
669             /*
670              * Find the end of the line.
671              */
672             linelen = tvb_find_line_end(tvb, loffset, -1, &next_offset, FALSE);
673
674             if (linelen >= 4)
675               cmdlen = 4;
676             else
677               cmdlen = linelen;
678             hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_req, tvb,
679                                                  0, 0, TRUE);
680             PROTO_ITEM_SET_HIDDEN(hidden_item);
681
682             /*
683              * Put the command line into the protocol tree.
684              */
685             ti = proto_tree_add_text(smtp_tree, tvb, loffset, next_offset - loffset,
686                 "Command: %s",
687                 tvb_format_text(tvb, loffset, next_offset - loffset));
688             cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp);
689
690             proto_tree_add_item(cmdresp_tree, hf_smtp_req_command, tvb,
691                                 loffset, cmdlen, FALSE);
692             if (linelen > 5) {
693               proto_tree_add_item(cmdresp_tree, hf_smtp_req_parameter, tvb,
694                                   loffset + 5, linelen - 5, FALSE);
695             }
696
697             if (smtp_data_desegment && !frame_data->more_frags) {
698               /* terminate the desegmentation */
699               frag_msg = fragment_end_seq_next (pinfo, frame_data->conversation_id, smtp_data_segment_table,
700                                                 smtp_data_reassembled_table);
701             }
702
703             /*
704              * Step past this line.
705              */
706             loffset = next_offset;
707           }
708         }
709
710         if (smtp_data_desegment) {
711           next_tvb = process_reassembled_data(tvb, offset, pinfo, "Reassembled DATA",
712                                               frag_msg, &smtp_data_frag_items, NULL, smtp_tree);
713           if (next_tvb) {
714             /* XXX: this is presumptious - we may have negotiated something else */
715             if (imf_handle) {
716               call_dissector(imf_handle, next_tvb, pinfo, tree);
717             } else {
718               /*
719                * Message body.
720                * Put its lines into the protocol tree, a line at a time.
721                */
722               dissect_smtp_data(tvb, offset, smtp_tree);
723             }
724             
725             pinfo->fragmented = FALSE;
726           } else {
727             pinfo->fragmented = TRUE;
728           }
729         }
730     } else {
731       /*
732        * Process the response, a line at a time, until we hit a line
733        * that doesn't have a continuation indication on it.
734        */
735       if (tree) {
736         hidden_item = proto_tree_add_boolean(smtp_tree, hf_smtp_rsp, tvb,
737                                              0, 0, TRUE);
738         PROTO_ITEM_SET_HIDDEN(hidden_item);
739       }
740
741       while (tvb_offset_exists(tvb, offset)) {
742         /*
743          * Find the end of the line.
744          */
745         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
746
747         if (tree) {
748           /*
749            * Put it into the protocol tree.
750            */
751           ti = proto_tree_add_text(smtp_tree, tvb, offset,
752                                    next_offset - offset, "Response: %s",
753                                    tvb_format_text(tvb, offset,
754                                                    next_offset - offset));
755           cmdresp_tree = proto_item_add_subtree(ti, ett_smtp_cmdresp);
756         } else
757           cmdresp_tree = NULL;
758
759         /*
760          * Is it a continuation line?
761          */
762         is_continuation_line =
763             (linelen >= 4 && tvb_get_guint8(tvb, offset + 3) == '-');
764
765         line = tvb_get_ptr(tvb, offset, linelen);
766         if (linelen >= 3 && isdigit(line[0]) && isdigit(line[1])
767                          && isdigit(line[2])) {
768           /*
769            * We have a 3-digit response code.
770            */
771           code = (line[0] - '0')*100 + (line[1] - '0')*10 + (line[2] - '0');
772
773           /*
774            * If we're awaiting the response to a STARTTLS code, this
775            * is it - if it's 220, all subsequent traffic will
776            * be TLS, otherwise we're back to boring old SMTP.
777            */
778           if (session_state->smtp_state == AWAITING_STARTTLS_RESPONSE) {
779             if (code == 220) {
780               /* This is the last non-TLS frame. */
781               session_state->last_nontls_frame = pinfo->fd->num;
782               session_state->smtp_state = READING_DATA;
783             } else
784               session_state->smtp_state = READING_CMDS;
785           }
786
787           if (tree) {
788             /*
789              * Put the response code and parameters into the protocol tree.
790              */
791             proto_tree_add_uint(cmdresp_tree, hf_smtp_rsp_code, tvb, offset, 3,
792                                 code);
793
794             if (linelen >= 4) {
795               proto_tree_add_item(cmdresp_tree, hf_smtp_rsp_parameter, tvb,
796                                   offset + 4, linelen - 4, FALSE);
797             }
798           }
799         }
800
801         /*
802          * Step past this line.
803          */
804         offset = next_offset;
805
806         /*
807          * If it's not a continuation line, quit.
808          */
809         /* if (!is_continuation_line)
810            break; */
811       }
812     }
813 }
814
815 static void smtp_data_reassemble_init (void)
816 {
817         fragment_table_init (&smtp_data_segment_table);
818         reassembled_table_init (&smtp_data_reassembled_table);
819 }
820
821
822 /* Register all the bits needed by the filtering engine */
823
824 void
825 proto_register_smtp(void)
826 {
827   static hf_register_info hf[] = {
828     { &hf_smtp_req,
829       { "Request", "smtp.req", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
830
831     { &hf_smtp_rsp,
832       { "Response", "smtp.rsp", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
833
834     { &hf_smtp_req_command,
835       { "Command", "smtp.req.command", FT_STRING,  BASE_NONE, NULL, 0x0,
836         "", HFILL }},
837
838     { &hf_smtp_req_parameter,
839       { "Request parameter", "smtp.req.parameter", FT_STRING, BASE_NONE, NULL, 0x0,
840         "", HFILL }},
841
842     { &hf_smtp_rsp_code,
843       { "Response code", "smtp.response.code", FT_UINT32, BASE_DEC, NULL, 0x0,
844         "", HFILL }},
845
846     { &hf_smtp_rsp_parameter,
847       { "Response parameter", "smtp.rsp.parameter", FT_STRING, BASE_NONE, NULL, 0x0,
848         "", HFILL }},
849
850     /* Fragment entries */
851     { &hf_smtp_data_fragments,
852       { "DATA fragments", "smtp.data.fragments", FT_NONE, BASE_NONE,
853         NULL, 0x00, "Message fragments", HFILL } },
854     { &hf_smtp_data_fragment,
855       { "DATA fragment", "smtp.data.fragment", FT_FRAMENUM, BASE_NONE,
856         NULL, 0x00, "Message fragment", HFILL } },
857     { &hf_smtp_data_fragment_overlap,
858       { "DATA fragment overlap", "smtp.data.fragment.overlap", FT_BOOLEAN,
859         BASE_NONE, NULL, 0x00, "Message fragment overlap", HFILL } },
860     { &hf_smtp_data_fragment_overlap_conflicts,
861       { "DATA fragment overlapping with conflicting data",
862         "smtp.data.fragment.overlap.conflicts", FT_BOOLEAN, BASE_NONE, NULL,
863         0x00, "Message fragment overlapping with conflicting data", HFILL } },
864     { &hf_smtp_data_fragment_multiple_tails,
865       { "DATA has multiple tail fragments",
866         "smtp.data.fragment.multiple_tails", FT_BOOLEAN, BASE_NONE,
867         NULL, 0x00, "Message has multiple tail fragments", HFILL } },
868     { &hf_smtp_data_fragment_too_long_fragment,
869       { "DATA fragment too long", "smtp.data.fragment.too_long_fragment",
870         FT_BOOLEAN, BASE_NONE, NULL, 0x00, "Message fragment too long",
871         HFILL } },
872     { &hf_smtp_data_fragment_error,
873       { "DATA defragmentation error", "smtp.data.fragment.error", FT_FRAMENUM,
874         BASE_NONE, NULL, 0x00, "Message defragmentation error", HFILL } },
875     { &hf_smtp_data_reassembled_in,
876       { "Reassembled DATA in frame", "smtp.data.reassembled.in", FT_FRAMENUM, BASE_NONE,
877         NULL, 0x00, "This DATA fragment is reassembled in this frame", HFILL } },
878   };
879   static gint *ett[] = {
880     &ett_smtp,
881     &ett_smtp_cmdresp,
882     &ett_smtp_data_fragment,
883     &ett_smtp_data_fragments,
884
885   };
886   module_t *smtp_module;
887
888   proto_smtp = proto_register_protocol("Simple Mail Transfer Protocol",
889                                        "SMTP", "smtp");
890
891   proto_register_field_array(proto_smtp, hf, array_length(hf));
892   proto_register_subtree_array(ett, array_length(ett));
893   register_init_routine (&smtp_data_reassemble_init);
894
895   /* Allow dissector to find be found by name. */
896   register_dissector("smtp", dissect_smtp, proto_smtp);
897
898   /* Preferences */
899   smtp_module = prefs_register_protocol(proto_smtp, NULL);
900   prefs_register_bool_preference(smtp_module, "desegment_lines",
901     "Reassemble SMTP command and response lines\nspanning multiple TCP segments",
902     "Whether the SMTP dissector should reassemble command and response lines spanning multiple TCP segments."
903     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
904     &smtp_desegment);
905
906   prefs_register_bool_preference(smtp_module, "desegment_data",
907     "Reassemble SMTP DATA commands spanning multiple TCP segments",
908     "Whether the SMTP dissector should reassemble DATA command and lines spanning multiple TCP segments."
909     " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
910     &smtp_data_desegment);
911
912 }
913
914 /* The registration hand-off routine */
915 void
916 proto_reg_handoff_smtp(void)
917 {
918   dissector_handle_t smtp_handle;
919
920   smtp_handle = find_dissector("smtp");
921   dissector_add("tcp.port", TCP_PORT_SMTP, smtp_handle);
922   dissector_add("tcp.port", TCP_PORT_SUBMISSION, smtp_handle);
923
924   /* find the IMF dissector */
925   imf_handle = find_dissector("imf");
926
927   /* find the SSL dissector */
928   ssl_handle = find_dissector("ssl");
929 }