]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
Fix compiler warning.
[people/ms/suricata.git] / src / app-layer-smtp.c
CommitLineData
576ec7da
AS
1/* Copyright (C) 2007-2010 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Anoop Saldanha <poonaatsoc@gmail.com>
22 */
23
24#include "suricata.h"
25#include "suricata-common.h"
26#include "debug.h"
27#include "decode.h"
28#include "threads.h"
29
30#include "stream-tcp-private.h"
31#include "stream-tcp-reassemble.h"
32#include "stream-tcp.h"
33#include "stream.h"
34
35#include "app-layer-protos.h"
36#include "app-layer-parser.h"
37#include "app-layer-smtp.h"
38
39#include "util-debug.h"
40#include "util-byte.h"
41#include "util-unittest.h"
42#include "util-byte.h"
43#include "util-unittest-helper.h"
44#include "util-memcmp.h"
45#include "flow-util.h"
46
47#include "detect-engine.h"
48#include "detect-engine-state.h"
49#include "detect-parse.h"
50
51#include "conf.h"
52
576ec7da
AS
53#define SMTP_MAX_REQUEST_AND_REPLY_LINE_LENGTH 510
54
55#define SMTP_COMMAND_BUFFER_STEPS 5
56
57/* we are in process of parsing a fresh command. Just a placeholder. If we
58 * are not in STATE_COMMAND_DATA_MODE, we have to be in this mode */
59#define SMTP_PARSER_STATE_COMMAND_MODE 0x00
60/* we are in mode of parsing a command's data. Used when we are parsing tls
61 * or accepting the rfc 2822 mail after DATA command */
62#define SMTP_PARSER_STATE_COMMAND_DATA_MODE 0x01
63/* Used when we are still in the process of parsing a server command. Used
64 * with multi-line replies and the stream is fragmented before all the lines
65 * for a response is seen */
66#define SMTP_PARSER_STATE_PARSING_SERVER_RESPONSE 0x02
67/* Used to indicate that the parser has seen the first reply */
68#define SMTP_PARSER_STATE_FIRST_REPLY_SEEN 0x04
69/* Used to indicate that the parser is parsing a multiline reply */
70#define SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY 0x08
71
72/* Various SMTP commands
73 * We currently have var-ified just STARTTLS and DATA, since we need to them
74 * for state transitions. The rest are just indicate as OTHER_CMD. Other
75 * commands would be introduced as and when needed */
76#define SMTP_COMMAND_STARTTLS 1
77#define SMTP_COMMAND_DATA 2
d3ca65de 78#define SMTP_COMMAND_BDAT 3
576ec7da
AS
79/* not an actual command per se, but the mode where we accept the mail after
80 * DATA has it's own reply code for completion, from the server. We give this
81 * stage a pseudo command of it's own, so that we can add this to the command
82 * buffer to match with the reply */
d3ca65de 83#define SMTP_COMMAND_DATA_MODE 4
576ec7da 84/* All other commands are represented by this var */
d3ca65de 85#define SMTP_COMMAND_OTHER_CMD 5
576ec7da
AS
86
87/* Different EHLO extensions. Not used now. */
88#define SMTP_EHLO_EXTENSION_PIPELINING
89#define SMTP_EHLO_EXTENSION_SIZE
90#define SMTP_EHLO_EXTENSION_DSN
91#define SMTP_EHLO_EXTENSION_STARTTLS
92#define SMTP_EHLO_EXTENSION_8BITMIME
93
94//static void SMTPParserReset(void)
95//{
96// return;
97//}
98
99/**
100 * \internal
101 * \brief Get the next line from input. It doesn't do any length validation.
102 *
103 * \param state The smtp state.
104 *
105 * \retval 0 On suceess.
106 * \retval -1 Either when we don't have any new lines to supply anymore or
107 * on failure.
108 */
109static int SMTPGetLine(SMTPState *state)
110{
88115902
AS
111 /* we have run out of input */
112 if (state->input_len <= 0)
576ec7da
AS
113 return -1;
114
88115902
AS
115 /* toserver */
116 if (state->direction == 0) {
117 if (state->ts_current_line_lf_seen == 1) {
118 /* we have seen the lf for the previous line. Clear the parser
119 * details to parse new line */
120 state->ts_current_line_lf_seen = 0;
121 if (state->ts_current_line_db == 1) {
122 state->ts_current_line_db = 0;
123 SCFree(state->ts_db);
124 state->ts_db = NULL;
125 state->current_line = NULL;
126 }
576ec7da 127 }
576ec7da 128
88115902 129 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
576ec7da 130
88115902
AS
131 if (lf_idx == NULL) {
132 /* set decoder event */
133 if (state->ts_current_line_db == 0) {
134 state->ts_current_line_db = 1;
135 state->ts_db = SCMalloc(state->input_len);
136 if (state->ts_db == NULL) {
137 return -1;
138 }
139 memcpy(state->ts_db, state->input, state->input_len);
140 state->ts_db_len = state->input_len;
141 } else {
142 state->ts_db = SCRealloc(state->ts_db, (state->ts_db_len +
143 state->input_len));
144 if (state->ts_db == NULL) {
145 return -1;
146 }
147 memcpy(state->ts_db + state->ts_db_len,
148 state->input, state->input_len);
149 state->ts_db_len += state->input_len;
150 } /* else */
151 state->input += state->input_len;
152 state->input_len = 0;
153
154 return -1;
576ec7da 155 } else {
88115902
AS
156 state->ts_current_line_lf_seen = 1;
157
158 /* We have CR-LF as the line delimiter */
159 if (*(lf_idx - 1) == 0x0d) {
160 if (state->ts_current_line_db == 1) {
161 state->ts_db = SCRealloc(state->ts_db,
162 (state->ts_db_len +
163 (lf_idx - state->input - 1)));
164 if (state->ts_db == NULL) {
165 return -1;
166 }
167 memcpy(state->ts_db + state->ts_db_len,
168 state->input, (lf_idx - state->input - 1));
169 state->ts_db_len += (lf_idx - state->input - 1);
170
171 state->current_line = state->ts_db;
172 state->current_line_len = state->ts_db_len;
173 } else {
174 state->current_line = state->input;
175 state->current_line_len = (lf_idx - state->input - 1);
176 }
576ec7da 177
d3ca65de 178 state->current_line_delimiter_len = 2;
88115902
AS
179 /* We have just LF as the line delimiter */
180 } else {
181 if (state->ts_current_line_db == 1) {
182 state->ts_db = SCRealloc(state->ts_db,
183 (state->ts_db_len +
184 (lf_idx - state->input)));
185 if (state->ts_db == NULL) {
186 return -1;
187 }
188 memcpy(state->ts_db + state->ts_db_len,
189 state->input, (lf_idx - state->input));
190 state->ts_db_len += (lf_idx - state->input);
191
192 state->current_line = state->ts_db;
193 state->current_line_len = state->ts_db_len;
194 } else {
195 state->current_line = state->input;
196 state->current_line_len = (lf_idx - state->input);
197 }
d3ca65de
AS
198
199 state->current_line_delimiter_len = 1;
88115902
AS
200 } /* else */
201
202 state->input_len -= (lf_idx - state->input) + 1;
203 state->input = lf_idx + 1;
204
205 return 0;
206 } /* else - if (lf_idx == NULL) */
207
208 /* toclient */
576ec7da 209 } else {
88115902
AS
210 if (state->tc_current_line_lf_seen == 1) {
211 /* we have seen the lf for the previous line. Clear the parser
212 * details to parse new line */
213 state->tc_current_line_lf_seen = 0;
214 if (state->tc_current_line_db == 1) {
215 state->tc_current_line_db = 0;
216 SCFree(state->tc_db);
217 state->tc_db = NULL;
218 state->current_line = NULL;
219 }
220 }
221
222 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
223
224 if (lf_idx == NULL) {
225 /* set decoder event */
226 if (state->tc_current_line_db == 0) {
227 state->tc_current_line_db = 1;
228 state->tc_db = SCMalloc(state->input_len);
229 if (state->tc_db == NULL) {
576ec7da
AS
230 return -1;
231 }
88115902
AS
232 memcpy(state->tc_db, state->input, state->input_len);
233 state->tc_db_len = state->input_len;
576ec7da 234 } else {
88115902
AS
235 state->tc_db = SCRealloc(state->tc_db, (state->tc_db_len +
236 state->input_len));
237 if (state->tc_db == NULL) {
238 return -1;
239 }
240 memcpy(state->tc_db + state->tc_db_len,
241 state->input, state->input_len);
242 state->tc_db_len += state->input_len;
243 } /* else */
244 state->input += state->input_len;
245 state->input_len = 0;
576ec7da 246
88115902 247 return -1;
576ec7da 248 } else {
88115902
AS
249 state->tc_current_line_lf_seen = 1;
250
251 /* We have CR-LF as the line delimiter */
252 if (*(lf_idx - 1) == 0x0d) {
253 if (state->tc_current_line_db == 1) {
254 state->tc_db = SCRealloc(state->tc_db,
255 (state->tc_db_len +
256 (lf_idx - state->input - 1)));
257 if (state->tc_db == NULL) {
258 return -1;
259 }
260 memcpy(state->tc_db + state->tc_db_len,
261 state->input, (lf_idx - state->input - 1));
262 state->tc_db_len += (lf_idx - state->input - 1);
263
264 state->current_line = state->tc_db;
265 state->current_line_len = state->tc_db_len;
266 } else {
267 state->current_line = state->input;
268 state->current_line_len = (lf_idx - state->input - 1);
576ec7da 269 }
88115902 270
d3ca65de 271 state->current_line_delimiter_len = 2;
88115902 272 /* We have just LF as the line delimiter */
576ec7da 273 } else {
88115902
AS
274 if (state->tc_current_line_db == 1) {
275 state->tc_db = SCRealloc(state->tc_db,
276 (state->tc_db_len +
277 (lf_idx - state->input)));
278 if (state->tc_db == NULL) {
279 return -1;
280 }
281 memcpy(state->tc_db + state->tc_db_len,
282 state->input, (lf_idx - state->input));
283 state->tc_db_len += (lf_idx - state->input);
284
285 state->current_line = state->tc_db;
286 state->current_line_len = state->tc_db_len;
287 } else {
288 state->current_line = state->input;
289 state->current_line_len = (lf_idx - state->input);
290 }
d3ca65de
AS
291
292 state->current_line_delimiter_len = 1;
88115902 293 } /* else */
576ec7da 294
88115902
AS
295 state->input_len -= (lf_idx - state->input) + 1;
296 state->input = lf_idx + 1;
297
298 return 0;
299 } /* else - if (lf_idx == NULL) */
300 }
576ec7da 301
576ec7da
AS
302}
303
304static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state)
305{
306 if (state->cmds_cnt >= state->cmds_buffer_len) {
bc5c9f4a
VJ
307 int increment = SMTP_COMMAND_BUFFER_STEPS;
308 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
309 increment = USHRT_MAX - state->cmds_buffer_len;
310 }
311
576ec7da
AS
312 state->cmds = SCRealloc(state->cmds,
313 sizeof(uint8_t) *
314 (state->cmds_buffer_len +
bc5c9f4a 315 increment));
576ec7da
AS
316 if (state->cmds == NULL) {
317 return -1;
318 }
bc5c9f4a 319 state->cmds_buffer_len += increment;
576ec7da
AS
320 }
321 if (state->cmds_cnt >= 1 &&
322 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
323 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
324 /* decoder event */
325 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
326 * STARTTLS as the last command in pipelined mode */
327 }
bc5c9f4a
VJ
328
329 /** \todo decoder event */
330 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX)
331 return -1;
332
576ec7da
AS
333 state->cmds[state->cmds_cnt] = command;
334 state->cmds_cnt++;
335
336 return 0;
337}
338
d3ca65de
AS
339static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
340 AppLayerParserState *pstate)
341{
342 state->bdat_chunk_idx += (state->current_line_len +
343 state->current_line_delimiter_len);
344 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
345 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
346 /* decoder event */
347 return -1;
348 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
349 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
350 }
351
352 return 0;
353}
354
576ec7da
AS
355static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
356 AppLayerParserState *pstate)
357{
358 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
359 /* looks like are still waiting for a confirmination from the server */
360 return 0;
361 }
362
363 if (state->current_line_len == 1 && state->current_line[0] == '.') {
364 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
365 /* kinda like a hack. The mail sent in DATA mode, would be
366 * acknowledged with a reply. We insert a dummy command to
367 * the command buffer to be used by the reply handler to match
368 * the reply received */
369 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state);
370 }
371
372 return 0;
373}
374
375static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
376 AppLayerParserState *pstate)
377{
378 return 0;
379}
380
381static int SMTPProcessReply(SMTPState *state, Flow *f,
382 AppLayerParserState *pstate)
383{
384 uint64_t reply_code = 0;
385
386 if (state->cmds_idx == state->cmds_cnt) {
387 /* decoder event - unable to match reply with request */
388 return -1;
389 }
390
391 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
392 * reply code */
393 if (state->current_line_len < 3) {
394 /* decoder event */
395 return -1;
396 }
397
398 if (state->current_line_len >= 4) {
399 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
400 if (state->current_line[3] != '-') {
401 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
402 }
403 } else {
404 if (state->current_line[3] == '-') {
405 state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
406 }
407 }
408 } else {
409 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
410 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
411 }
412 }
413
414 if (ByteExtractString(&reply_code, 10, 3,
415 (const char *)state->current_line) < 3) {
416 /* decoder event */
417 return -1;
418 }
419
420 /* kinda hack needed for us. Our parser logs commands, to be
421 * matched against server replies. SMTP is normally accompanied by a
422 * toclient welcome message, which would have had no command to
423 * accompany it with. And also alproto detection sees to it that the
424 * toserver stream is the first one to be processed by the app layer.
425 * Hence check the first reply and if it is a welcome message(220),
426 * leave without matching it against any buffered command */
427 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
428 state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
429 if (reply_code == 220) {
430 return 0;
431 }
432 }
433
434 if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
435 if (reply_code == 220) {
436 /* we are entering STARRTTLS data mode */
437 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
438 pstate->flags |= APP_LAYER_PARSER_DONE;
439 pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION;
440 pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY;
441 } else {
442 /* decoder event */
443 }
444 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
445 if (reply_code == 354) {
446 /* Next comes the mail for the DATA command in toserver direction */
447 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
448 } else {
449 /* decoder event */
450 }
451 } else {
452 /* we don't care for any other command */
453 }
454
455 /* if it is a multiline reply, we need to move the index only once for all
456 * the line of the reply. We unset the multiline flag on the last
457 * line of the multiline reply, following which we increment the index */
458 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
459 state->cmds_idx++;
460 }
461
462 /* if we have matched all the buffered commands, reset the cnt and index */
463 if (state->cmds_idx == state->cmds_cnt) {
464 state->cmds_cnt = 0;
465 state->cmds_idx = 0;
466 }
467
468 return 0;
469}
470
d3ca65de
AS
471static int SMTPParseCommandBDAT(SMTPState *state)
472{
473 int i = 4;
474 while (i < state->current_line_len) {
475 if (state->current_line[i] != ' ') {
476 break;
477 }
478 i++;
479 }
480 if (i == 4) {
481 /* decoder event */
482 return -1;
483 }
484 if (i == state->current_line_len) {
485 /* decoder event */
486 return -1;
487 }
488 uint8_t *endptr = NULL;
489 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
490 (char **)&endptr, 10);
491 if (endptr == state->current_line + i) {
492 /* decoder event */
493 return -1;
494 }
495
496 return 0;
497}
498
576ec7da
AS
499static int SMTPProcessRequest(SMTPState *state, Flow *f,
500 AppLayerParserState *pstate)
501{
502 /* there are 2 commands that can push it into this COMMAND_DATA mode -
503 * STARTTLS and DATA */
504 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
505 int r = 0;
506
576ec7da
AS
507 if (state->current_line_len >= 8 &&
508 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
509 state->current_command = SMTP_COMMAND_STARTTLS;
510 } else if (state->current_line_len >= 4 &&
511 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
512 state->current_command = SMTP_COMMAND_DATA;
d3ca65de
AS
513 } else if (state->current_line_len >= 4 &&
514 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
515 r = SMTPParseCommandBDAT(state);
516 if (r == -1)
517 return -1;
518 state->current_command = SMTP_COMMAND_BDAT;
519 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
576ec7da
AS
520 } else {
521 state->current_command = SMTP_COMMAND_OTHER_CMD;
522 }
523
524 /* Every command is inserted into a command buffer, to be matched
525 * against reply(ies) sent by the server */
526 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
527 state) == -1) {
528 return -1;
529 }
d3ca65de
AS
530
531 return r;
576ec7da
AS
532 }
533
534 switch (state->current_command) {
535 case SMTP_COMMAND_STARTTLS:
536 return SMTPProcessCommandSTARTTLS(state, f, pstate);
537
538 case SMTP_COMMAND_DATA:
539 return SMTPProcessCommandDATA(state, f, pstate);
540
d3ca65de
AS
541 case SMTP_COMMAND_BDAT:
542 return SMTPProcessCommandBDAT(state, f, pstate);
543
576ec7da
AS
544 default:
545 /* we have nothing to do with any other command at this instant.
546 * Just let it go through */
547 return 0;
548 }
549}
550
88115902
AS
551static int SMTPParse(int direction, Flow *f, SMTPState *state,
552 AppLayerParserState *pstate, uint8_t *input,
553 uint32_t input_len, AppLayerParserResult *output)
576ec7da 554{
576ec7da
AS
555 state->input = input;
556 state->input_len = input_len;
88115902 557 state->direction = direction;
576ec7da
AS
558
559 while (SMTPGetLine(state) >= 0) {
88115902
AS
560 /* toserver */
561 if (direction == 0) {
d3ca65de
AS
562 if (SMTPProcessRequest(state, f, pstate) == -1)
563 return -1;
88115902
AS
564
565 /* toclient */
566 } else {
d3ca65de
AS
567 if (SMTPProcessReply(state, f, pstate) == -1)
568 return -1;
88115902 569 }
576ec7da
AS
570 }
571
572 return 0;
573}
574
88115902 575static int SMTPParseClientRecord(Flow *f, void *alstate,
576ec7da
AS
576 AppLayerParserState *pstate,
577 uint8_t *input, uint32_t input_len,
578 AppLayerParserResult *output)
579{
88115902
AS
580 /* first arg 0 is toserver */
581 return SMTPParse(0, f, alstate, pstate, input, input_len, output);
582}
576ec7da 583
88115902
AS
584static int SMTPParseServerRecord(Flow *f, void *alstate,
585 AppLayerParserState *pstate,
586 uint8_t *input, uint32_t input_len,
587 AppLayerParserResult *output)
588{
589 /* first arg 1 is toclient */
590 return SMTPParse(1, f, alstate, pstate, input, input_len, output);
576ec7da
AS
591
592 return 0;
593}
594
595/**
596 * \internal
597 * \brief Function to allocate SMTP state memory.
598 */
599static void *SMTPStateAlloc(void)
600{
601 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
602 if (smtp_state == NULL)
603 return NULL;
604 memset(smtp_state, 0, sizeof(SMTPState));
605
606 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
607 SMTP_COMMAND_BUFFER_STEPS);
608 if (smtp_state->cmds == NULL) {
609 SCFree(smtp_state);
610 return NULL;
611 }
612 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
613
614 return smtp_state;
615}
616
617/**
618 * \internal
619 * \brief Function to free SMTP state memory.
620 */
621static void SMTPStateFree(void *p)
622{
623 SMTPState *smtp_state = (SMTPState *)p;
624
625 if (smtp_state->cmds != NULL) {
626 SCFree(smtp_state->cmds);
627 }
88115902
AS
628 if (smtp_state->ts_current_line_db) {
629 SCFree(smtp_state->ts_db);
630 }
631 if (smtp_state->tc_current_line_db) {
632 SCFree(smtp_state->tc_db);
633 }
576ec7da
AS
634
635 SCFree(smtp_state);
636
637 return;
638}
639
640/**
641 * \brief Register the SMPT Protocol parser.
642 */
643void RegisterSMTPParsers(void)
644{
645 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0,
646 STREAM_TOSERVER);
647 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0,
648 STREAM_TOSERVER);
649
650 AppLayerRegisterStateFuncs(ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
651
652 AppLayerRegisterProto("smtp", ALPROTO_SMTP, STREAM_TOSERVER,
653 SMTPParseClientRecord);
654 AppLayerRegisterProto("smtp", ALPROTO_SMTP, STREAM_TOCLIENT,
655 SMTPParseServerRecord);
656
657 return;
658}
659
660/***************************************Unittests******************************/
661
662/*
663 * \test Test STARTTLS.
664 */
665int SMTPParserTest01(void)
666{
667 int result = 0;
668 Flow f;
669 int r = 0;
670
671 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
672 uint8_t welcome_reply[] = {
673 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
674 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
675 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
676 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
677 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
678 0x0d, 0x0a
679 };
680 uint32_t welcome_reply_len = sizeof(welcome_reply);
681
682 /* EHLO [192.168.0.158]<CR><LF> */
683 uint8_t request1[] = {
684 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
685 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
686 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
687 };
688 uint32_t request1_len = sizeof(request1);
689 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
690 * 250-SIZE 35882577<CR><LF>
691 * 250-8BITMIME<CR><LF>
692 * 250-STARTTLS<CR><LF>
693 * 250 ENHANCEDSTATUSCODES<CR><LF>
694 */
695 uint8_t reply1[] = {
696 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
697 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
698 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
699 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
700 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
701 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
702 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
703 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
704 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
705 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
706 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
707 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
708 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
709 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
710 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
711 0x44, 0x45, 0x53, 0x0d, 0x0a
712 };
713 uint32_t reply1_len = sizeof(reply1);
714
715 /* STARTTLS<CR><LF> */
716 uint8_t request2[] = {
717 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
718 0x0d, 0x0a
719 };
720 uint32_t request2_len = sizeof(request2);
721 /* 220 2.0.0 Ready to start TLS<CR><LF> */
722 uint8_t reply2[] = {
723 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
724 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
725 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
726 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
727 };
728 uint32_t reply2_len = sizeof(reply2);
729
730 TcpSession ssn;
731
732 memset(&f, 0, sizeof(f));
733 memset(&ssn, 0, sizeof(ssn));
734
735 FLOW_INITIALIZE(&f);
736 f.protoctx = (void *)&ssn;
737
738 StreamTcpInitConfig(TRUE);
739 FlowL7DataPtrInit(&f);
740
741 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
742 request1, request1_len);
743 if (r != 0) {
744 printf("smtp check returned %" PRId32 ", expected 0: ", r);
745 goto end;
746 }
747 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
748 if (smtp_state == NULL) {
749 printf("no smtp state: ");
750 goto end;
751 }
752 if (smtp_state->input_len != 0 ||
576ec7da
AS
753 smtp_state->cmds_cnt != 1 ||
754 smtp_state->cmds_idx != 0 ||
755 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
756 smtp_state->parser_state != 0) {
757 printf("smtp parser in inconsistent state\n");
758 goto end;
759 }
760
761 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
762 welcome_reply, welcome_reply_len);
763 if (r != 0) {
764 printf("smtp check returned %" PRId32 ", expected 0: ", r);
765 goto end;
766 }
767 if (smtp_state->input_len != 0 ||
576ec7da
AS
768 smtp_state->cmds_cnt != 1 ||
769 smtp_state->cmds_idx != 0 ||
770 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
771 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
772 printf("smtp parser in inconsistent state\n");
773 goto end;
774 }
775
776 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
777 reply1, reply1_len);
778 if (r != 0) {
779 printf("smtp check returned %" PRId32 ", expected 0: ", r);
780 goto end;
781 }
782 if (smtp_state->input_len != 0 ||
576ec7da
AS
783 smtp_state->cmds_cnt != 0 ||
784 smtp_state->cmds_idx != 0 ||
785 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
786 printf("smtp parser in inconsistent state\n");
787 goto end;
788 }
789
790 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
791 request2, request2_len);
792 if (r != 0) {
793 printf("smtp check returned %" PRId32 ", expected 0: ", r);
794 goto end;
795 }
796 if (smtp_state->input_len != 0 ||
576ec7da
AS
797 smtp_state->cmds_cnt != 1 ||
798 smtp_state->cmds_idx != 0 ||
799 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
800 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
801 printf("smtp parser in inconsistent state\n");
802 goto end;
803 }
804
805 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
806 reply2, reply2_len);
807 if (r != 0) {
808 printf("smtp check returned %" PRId32 ", expected 0: ", r);
809 goto end;
810 }
811 if (smtp_state->input_len != 0 ||
576ec7da
AS
812 smtp_state->cmds_cnt != 0 ||
813 smtp_state->cmds_idx != 0 ||
814 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
815 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
816 printf("smtp parser in inconsistent state\n");
817 goto end;
818 }
819
820 if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
821 !(f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
822 !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
823 !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
824 goto end;
825 }
826
827 result = 1;
828end:
829 FlowL7DataPtrFree(&f);
830 StreamTcpFreeConfig(TRUE);
831 FLOW_DESTROY(&f);
832 return result;
833}
834
835/**
836 * \test Test multiple DATA commands(full mail transactions).
837 */
838int SMTPParserTest02(void)
839{
840 int result = 0;
841 Flow f;
842 int r = 0;
843
844 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
845 uint8_t welcome_reply[] = {
846 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
847 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
848 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
849 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
850 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
851 0x0d, 0x0a
852 };
853 uint32_t welcome_reply_len = sizeof(welcome_reply);
854
855 /* EHLO boo.com<CR><LF> */
856 uint8_t request1[] = {
857 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
858 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
859 };
860 uint32_t request1_len = sizeof(request1);
861 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
862 * 250-SIZE 35882577<CR><LF>
863 * 250-8BITMIME<CR><LF>
864 * 250-STARTTLS<CR><LF>
865 * 250 ENHANCEDSTATUSCODES<CR><LF>
866 */
867 uint8_t reply1[] = {
868 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
869 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
870 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
871 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
872 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
873 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
874 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
875 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
876 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
877 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
878 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
879 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
880 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
881 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
882 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
883 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
884 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
885 };
886 uint32_t reply1_len = sizeof(reply1);
887
888 /* MAIL FROM:asdff@asdf.com<CR><LF> */
889 uint8_t request2[] = {
890 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
891 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
892 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
893 0x0d, 0x0a
894 };
895 uint32_t request2_len = sizeof(request2);
896 /* 250 2.1.0 Ok<CR><LF> */
897 uint8_t reply2[] = {
898 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
899 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
900 };
901 uint32_t reply2_len = sizeof(reply2);
902
903 /* RCPT TO:bimbs@gmail.com<CR><LF> */
904 uint8_t request3[] = {
905 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
906 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
907 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
908 0x0a
909 };
910 uint32_t request3_len = sizeof(request3);
911 /* 250 2.1.5 Ok<CR><LF> */
912 uint8_t reply3[] = {
913 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
914 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
915 };
916 uint32_t reply3_len = sizeof(reply3);
917
918 /* DATA<CR><LF> */
919 uint8_t request4[] = {
920 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
921 };
922 uint32_t request4_len = sizeof(request4);
923 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
924 uint8_t reply4[] = {
925 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
926 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
927 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
928 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
929 0x4c, 0x46, 0x3e, 0x0d, 0x0a
930 };
931 uint32_t reply4_len = sizeof(reply4);
932
933 /* FROM:asdff@asdf.com<CR><LF> */
934 uint8_t request5_1[] = {
935 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
936 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
937 0x63, 0x6f, 0x6d, 0x0d, 0x0a
938 };
939 uint32_t request5_1_len = sizeof(request5_1);
940 /* TO:bimbs@gmail.com<CR><LF> */
941 uint8_t request5_2[] = {
942 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
943 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
944 0x6f, 0x6d, 0x0d, 0x0a
945 };
946 uint32_t request5_2_len = sizeof(request5_2);
947 /* <CR><LF> */
948 uint8_t request5_3[] = {
949 0x0d, 0x0a
950 };
951 uint32_t request5_3_len = sizeof(request5_3);
952 /* this is test mail1<CR><LF> */
953 uint8_t request5_4[] = {
954 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
955 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
956 0x6c, 0x31, 0x0d, 0x0a
957 };
958 uint32_t request5_4_len = sizeof(request5_4);
959 /* .<CR><LF> */
960 uint8_t request5_5[] = {
961 0x2e, 0x0d, 0x0a
962 };
963 uint32_t request5_5_len = sizeof(request5_5);
964 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
965 uint8_t reply5[] = {
966 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
967 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
968 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
969 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
970 0x46, 0x32, 0x0d, 0x0a
971 };
972 uint32_t reply5_len = sizeof(reply5);
973
974 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
975 uint8_t request6[] = {
976 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
977 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
978 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
979 0x0d, 0x0a
980 };
981 uint32_t request6_len = sizeof(request6);
982 /* 250 2.1.0 Ok<CR><LF> */
983 uint8_t reply6[] = {
984 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
985 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
986 };
987 uint32_t reply6_len = sizeof(reply6);
988
989 /* RCPT TO:bimbs@gmail.com<CR><LF> */
990 uint8_t request7[] = {
991 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
992 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
993 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
994 0x0a
995 };
996 uint32_t request7_len = sizeof(request7);
997 /* 250 2.1.5 Ok<CR><LF> */
998 uint8_t reply7[] = {
999 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1000 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1001 };
1002 uint32_t reply7_len = sizeof(reply7);
1003
1004 /* DATA<CR><LF> */
1005 uint8_t request8[] = {
1006 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1007 };
1008 uint32_t request8_len = sizeof(request8);
1009 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1010 uint8_t reply8[] = {
1011 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1012 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1013 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1014 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1015 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1016 };
1017 uint32_t reply8_len = sizeof(reply8);
1018
1019 /* FROM:asdfg@gmail.com<CR><LF> */
1020 uint8_t request9_1[] = {
1021 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1022 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
1023 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1024 };
1025 uint32_t request9_1_len = sizeof(request9_1);
1026 /* TO:bimbs@gmail.com<CR><LF> */
1027 uint8_t request9_2[] = {
1028 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1029 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1030 0x6f, 0x6d, 0x0d, 0x0a
1031 };
1032 uint32_t request9_2_len = sizeof(request9_2);
1033 /* <CR><LF> */
1034 uint8_t request9_3[] = {
1035 0x0d, 0x0a
1036 };
1037 uint32_t request9_3_len = sizeof(request9_3);
1038 /* this is test mail2<CR><LF> */
1039 uint8_t request9_4[] = {
1040 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1041 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1042 0x6c, 0x32, 0x0d, 0x0a
1043 };
1044 uint32_t request9_4_len = sizeof(request9_4);
1045 /* .<CR><LF> */
1046 uint8_t request9_5[] = {
1047 0x2e, 0x0d, 0x0a
1048 };
1049 uint32_t request9_5_len = sizeof(request9_5);
1050 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
1051 uint8_t reply9[] = {
1052 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1053 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1054 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1055 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
1056 0x46, 0x32, 0x0d, 0x0a
1057 };
1058 uint32_t reply9_len = sizeof(reply9);
1059
1060 /* QUIT<CR><LF> */
1061 uint8_t request10[] = {
1062 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1063 };
1064 uint32_t request10_len = sizeof(request10);
1065 /* 221 2.0.0 Bye<CR><LF> */
1066 uint8_t reply10[] = {
1067 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1068 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1069 };
1070 uint32_t reply10_len = sizeof(reply10);
1071
1072 TcpSession ssn;
1073
1074 memset(&f, 0, sizeof(f));
1075 memset(&ssn, 0, sizeof(ssn));
1076
1077 FLOW_INITIALIZE(&f);
1078 f.protoctx = (void *)&ssn;
1079
1080 StreamTcpInitConfig(TRUE);
1081 FlowL7DataPtrInit(&f);
1082
1083 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1084 request1, request1_len);
1085 if (r != 0) {
1086 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1087 goto end;
1088 }
1089 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
1090 if (smtp_state == NULL) {
1091 printf("no smtp state: ");
1092 goto end;
1093 }
1094 if (smtp_state->input_len != 0 ||
576ec7da
AS
1095 smtp_state->cmds_cnt != 1 ||
1096 smtp_state->cmds_idx != 0 ||
1097 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1098 smtp_state->parser_state != 0) {
1099 printf("smtp parser in inconsistent state\n");
1100 goto end;
1101 }
1102
1103 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1104 welcome_reply, welcome_reply_len);
1105 if (r != 0) {
1106 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1107 goto end;
1108 }
1109 if (smtp_state->input_len != 0 ||
576ec7da
AS
1110 smtp_state->cmds_cnt != 1 ||
1111 smtp_state->cmds_idx != 0 ||
1112 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1113 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1114 printf("smtp parser in inconsistent state\n");
1115 goto end;
1116 }
1117
1118 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1119 reply1, reply1_len);
1120 if (r != 0) {
1121 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1122 goto end;
1123 }
1124 if (smtp_state->input_len != 0 ||
576ec7da
AS
1125 smtp_state->cmds_cnt != 0 ||
1126 smtp_state->cmds_idx != 0 ||
1127 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1128 printf("smtp parser in inconsistent state\n");
1129 goto end;
1130 }
1131
1132 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1133 request2, request2_len);
1134 if (r != 0) {
1135 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1136 goto end;
1137 }
1138 if (smtp_state->input_len != 0 ||
576ec7da
AS
1139 smtp_state->cmds_cnt != 1 ||
1140 smtp_state->cmds_idx != 0 ||
1141 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1142 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1143 printf("smtp parser in inconsistent state\n");
1144 goto end;
1145 }
1146
1147 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1148 reply2, reply2_len);
1149 if (r != 0) {
1150 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1151 goto end;
1152 }
1153 if (smtp_state->input_len != 0 ||
576ec7da
AS
1154 smtp_state->cmds_cnt != 0 ||
1155 smtp_state->cmds_idx != 0 ||
1156 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1157 printf("smtp parser in inconsistent state\n");
1158 goto end;
1159 }
1160
1161 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1162 request3, request3_len);
1163 if (r != 0) {
1164 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1165 goto end;
1166 }
1167 if (smtp_state->input_len != 0 ||
576ec7da
AS
1168 smtp_state->cmds_cnt != 1 ||
1169 smtp_state->cmds_idx != 0 ||
1170 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1171 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1172 printf("smtp parser in inconsistent state\n");
1173 goto end;
1174 }
1175
1176 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1177 reply3, reply3_len);
1178 if (r != 0) {
1179 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1180 goto end;
1181 }
1182 if (smtp_state->input_len != 0 ||
576ec7da
AS
1183 smtp_state->cmds_cnt != 0 ||
1184 smtp_state->cmds_idx != 0 ||
1185 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1186 printf("smtp parser in inconsistent state\n");
1187 goto end;
1188 }
1189
1190 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1191 request4, request4_len);
1192 if (r != 0) {
1193 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1194 goto end;
1195 }
1196 if (smtp_state->input_len != 0 ||
576ec7da
AS
1197 smtp_state->cmds_cnt != 1 ||
1198 smtp_state->cmds_idx != 0 ||
1199 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1200 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1201 printf("smtp parser in inconsistent state\n");
1202 goto end;
1203 }
1204
1205 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1206 reply4, reply4_len);
1207 if (r != 0) {
1208 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1209 goto end;
1210 }
1211 if (smtp_state->input_len != 0 ||
576ec7da
AS
1212 smtp_state->cmds_cnt != 0 ||
1213 smtp_state->cmds_idx != 0 ||
1214 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1215 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1216 printf("smtp parser in inconsistent state\n");
1217 goto end;
1218 }
1219
1220 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1221 request5_1, request5_1_len);
1222 if (r != 0) {
1223 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1224 goto end;
1225 }
1226 if (smtp_state->input_len != 0 ||
576ec7da
AS
1227 smtp_state->cmds_cnt != 0 ||
1228 smtp_state->cmds_idx != 0 ||
1229 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1230 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1231
1232 printf("smtp parser in inconsistent state\n");
1233 goto end;
1234 }
1235
1236 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1237 request5_2, request5_2_len);
1238 if (r != 0) {
1239 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1240 goto end;
1241 }
1242 if (smtp_state->input_len != 0 ||
576ec7da
AS
1243 smtp_state->cmds_cnt != 0 ||
1244 smtp_state->cmds_idx != 0 ||
1245 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1246 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1247
1248 printf("smtp parser in inconsistent state\n");
1249 goto end;
1250 }
1251
1252 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1253 request5_3, request5_3_len);
1254 if (r != 0) {
1255 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1256 goto end;
1257 }
1258 if (smtp_state->input_len != 0 ||
576ec7da
AS
1259 smtp_state->cmds_cnt != 0 ||
1260 smtp_state->cmds_idx != 0 ||
1261 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1262 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1263
1264 printf("smtp parser in inconsistent state\n");
1265 goto end;
1266 }
1267
1268 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1269 request5_4, request5_4_len);
1270 if (r != 0) {
1271 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1272 goto end;
1273 }
1274 if (smtp_state->input_len != 0 ||
576ec7da
AS
1275 smtp_state->cmds_cnt != 0 ||
1276 smtp_state->cmds_idx != 0 ||
1277 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1278 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1279
1280 printf("smtp parser in inconsistent state\n");
1281 goto end;
1282 }
1283
1284 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1285 request5_5, request5_5_len);
1286 if (r != 0) {
1287 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1288 goto end;
1289 }
1290 if (smtp_state->input_len != 0 ||
576ec7da
AS
1291 smtp_state->cmds_cnt != 1 ||
1292 smtp_state->cmds_idx != 0 ||
1293 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1294 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1295 printf("smtp parser in inconsistent state\n");
1296 goto end;
1297 }
1298
1299 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1300 reply5, reply5_len);
1301 if (r != 0) {
1302 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1303 goto end;
1304 }
1305 if (smtp_state->input_len != 0 ||
576ec7da
AS
1306 smtp_state->cmds_cnt != 0 ||
1307 smtp_state->cmds_idx != 0 ||
1308 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1309 printf("smtp parser in inconsistent state\n");
1310 goto end;
1311 }
1312
1313 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1314 request6, request6_len);
1315 if (r != 0) {
1316 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1317 goto end;
1318 }
1319 if (smtp_state->input_len != 0 ||
576ec7da
AS
1320 smtp_state->cmds_cnt != 1 ||
1321 smtp_state->cmds_idx != 0 ||
1322 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1323 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1324 printf("smtp parser in inconsistent state\n");
1325 goto end;
1326 }
1327
1328 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1329 reply6, reply6_len);
1330 if (r != 0) {
1331 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1332 goto end;
1333 }
1334 if (smtp_state->input_len != 0 ||
576ec7da
AS
1335 smtp_state->cmds_cnt != 0 ||
1336 smtp_state->cmds_idx != 0 ||
1337 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1338 printf("smtp parser in inconsistent state\n");
1339 goto end;
1340 }
1341
1342 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1343 request7, request7_len);
1344 if (r != 0) {
1345 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1346 goto end;
1347 }
1348 if (smtp_state->input_len != 0 ||
576ec7da
AS
1349 smtp_state->cmds_cnt != 1 ||
1350 smtp_state->cmds_idx != 0 ||
1351 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1352 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1353 printf("smtp parser in inconsistent state\n");
1354 goto end;
1355 }
1356
1357 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1358 reply7, reply7_len);
1359 if (r != 0) {
1360 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1361 goto end;
1362 }
1363 if (smtp_state->input_len != 0 ||
576ec7da
AS
1364 smtp_state->cmds_cnt != 0 ||
1365 smtp_state->cmds_idx != 0 ||
1366 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1367 printf("smtp parser in inconsistent state\n");
1368 goto end;
1369 }
1370
1371 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1372 request8, request8_len);
1373 if (r != 0) {
1374 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1375 goto end;
1376 }
1377 if (smtp_state->input_len != 0 ||
576ec7da
AS
1378 smtp_state->cmds_cnt != 1 ||
1379 smtp_state->cmds_idx != 0 ||
1380 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1381 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1382 printf("smtp parser in inconsistent state\n");
1383 goto end;
1384 }
1385
1386 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1387 reply8, reply8_len);
1388 if (r != 0) {
1389 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1390 goto end;
1391 }
1392 if (smtp_state->input_len != 0 ||
576ec7da
AS
1393 smtp_state->cmds_cnt != 0 ||
1394 smtp_state->cmds_idx != 0 ||
1395 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1396 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1397 printf("smtp parser in inconsistent state\n");
1398 goto end;
1399 }
1400
1401 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1402 request9_1, request9_1_len);
1403 if (r != 0) {
1404 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1405 goto end;
1406 }
1407 if (smtp_state->input_len != 0 ||
576ec7da
AS
1408 smtp_state->cmds_cnt != 0 ||
1409 smtp_state->cmds_idx != 0 ||
1410 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1411 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1412
1413 printf("smtp parser in inconsistent state\n");
1414 goto end;
1415 }
1416
1417 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1418 request9_2, request9_2_len);
1419 if (r != 0) {
1420 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1421 goto end;
1422 }
1423 if (smtp_state->input_len != 0 ||
576ec7da
AS
1424 smtp_state->cmds_cnt != 0 ||
1425 smtp_state->cmds_idx != 0 ||
1426 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1427 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1428
1429 printf("smtp parser in inconsistent state\n");
1430 goto end;
1431 }
1432
1433 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1434 request9_3, request9_3_len);
1435 if (r != 0) {
1436 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1437 goto end;
1438 }
1439 if (smtp_state->input_len != 0 ||
576ec7da
AS
1440 smtp_state->cmds_cnt != 0 ||
1441 smtp_state->cmds_idx != 0 ||
1442 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1443 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1444
1445 printf("smtp parser in inconsistent state\n");
1446 goto end;
1447 }
1448
1449 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1450 request9_4, request9_4_len);
1451 if (r != 0) {
1452 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1453 goto end;
1454 }
1455 if (smtp_state->input_len != 0 ||
576ec7da
AS
1456 smtp_state->cmds_cnt != 0 ||
1457 smtp_state->cmds_idx != 0 ||
1458 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1459 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1460
1461 printf("smtp parser in inconsistent state\n");
1462 goto end;
1463 }
1464
1465 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1466 request9_5, request9_5_len);
1467 if (r != 0) {
1468 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1469 goto end;
1470 }
1471 if (smtp_state->input_len != 0 ||
576ec7da
AS
1472 smtp_state->cmds_cnt != 1 ||
1473 smtp_state->cmds_idx != 0 ||
1474 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1475 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1476 printf("smtp parser in inconsistent state\n");
1477 goto end;
1478 }
1479
1480 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1481 reply9, reply9_len);
1482 if (r != 0) {
1483 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1484 goto end;
1485 }
1486 if (smtp_state->input_len != 0 ||
576ec7da
AS
1487 smtp_state->cmds_cnt != 0 ||
1488 smtp_state->cmds_idx != 0 ||
1489 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1490 printf("smtp parser in inconsistent state\n");
1491 goto end;
1492 }
1493
1494 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1495 request10, request10_len);
1496 if (r != 0) {
1497 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1498 goto end;
1499 }
1500 if (smtp_state->input_len != 0 ||
576ec7da
AS
1501 smtp_state->cmds_cnt != 1 ||
1502 smtp_state->cmds_idx != 0 ||
1503 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1504 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1505 printf("smtp parser in inconsistent state\n");
1506 goto end;
1507 }
1508
1509 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1510 reply10, reply10_len);
1511 if (r != 0) {
1512 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1513 goto end;
1514 }
1515 if (smtp_state->input_len != 0 ||
576ec7da
AS
1516 smtp_state->cmds_cnt != 0 ||
1517 smtp_state->cmds_idx != 0 ||
1518 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1519 printf("smtp parser in inconsistent state\n");
1520 goto end;
1521 }
1522
1523 result = 1;
1524end:
1525 FlowL7DataPtrFree(&f);
1526 StreamTcpFreeConfig(TRUE);
1527 FLOW_DESTROY(&f);
1528 return result;
1529}
1530
1531/**
1532 * \test Testing parsing pipelined commands.
1533 */
1534int SMTPParserTest03(void)
1535{
1536 int result = 0;
1537 Flow f;
1538 int r = 0;
1539
1540 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1541 uint8_t welcome_reply[] = {
1542 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1543 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1544 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1545 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1546 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1547 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1548 };
1549 uint32_t welcome_reply_len = sizeof(welcome_reply);
1550
1551 /* EHLO boo.com<CR><LF> */
1552 uint8_t request1[] = {
1553 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1554 0x2e, 0x63, 0x6f, 0x6d, 0x0a
1555 };
1556 uint32_t request1_len = sizeof(request1);
1557 /* 250-poona_slack_vm1.localdomain<CR><LF>
1558 * 250-PIPELINING<CR><LF>
1559 * 250-SIZE 10240000<CR><LF>
1560 * 250-VRFY<CR><LF>
1561 * 250-ETRN<CR><LF>
1562 * 250-ENHANCEDSTATUSCODES<CR><LF>
1563 * 250-8BITMIME<CR><LF>
1564 * 250 DSN<CR><LF>
1565 */
1566 uint8_t reply1[] = {
1567 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1568 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1569 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1570 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1571 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1572 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1573 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1574 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1575 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1576 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1577 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1578 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1579 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1580 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1581 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1582 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1583 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1584 };
1585 uint32_t reply1_len = sizeof(reply1);
1586
1587 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
1588 * RCPT TO:pbsf@asdfs.com<CR><LF>
1589 * DATA<CR><LF>
1590 */
1591 uint8_t request2[] = {
1592 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1593 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1594 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1595 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
1596 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1597 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1598 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1599 };
1600 uint32_t request2_len = sizeof(request2);
1601 /* 250 2.1.0 Ok<CR><LF>
1602 * 250 2.1.5 Ok<CR><LF>
1603 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
1604 */
1605 uint8_t reply2[] = {
1606 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1607 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
1608 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
1609 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
1610 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
1611 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
1612 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
1613 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
1614 0x0a
1615 };
1616 uint32_t reply2_len = sizeof(reply2);
1617
1618 TcpSession ssn;
1619
1620 memset(&f, 0, sizeof(f));
1621 memset(&ssn, 0, sizeof(ssn));
1622
1623 FLOW_INITIALIZE(&f);
1624 f.protoctx = (void *)&ssn;
1625
1626 StreamTcpInitConfig(TRUE);
1627 FlowL7DataPtrInit(&f);
1628
1629 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1630 request1, request1_len);
1631 if (r != 0) {
1632 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1633 goto end;
1634 }
1635 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
1636 if (smtp_state == NULL) {
1637 printf("no smtp state: ");
1638 goto end;
1639 }
1640 if (smtp_state->input_len != 0 ||
576ec7da
AS
1641 smtp_state->cmds_cnt != 1 ||
1642 smtp_state->cmds_idx != 0 ||
1643 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1644 smtp_state->parser_state != 0) {
1645 printf("smtp parser in inconsistent state\n");
1646 goto end;
1647 }
1648
1649 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1650 welcome_reply, welcome_reply_len);
1651 if (r != 0) {
1652 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1653 goto end;
1654 }
1655 if (smtp_state->input_len != 0 ||
576ec7da
AS
1656 smtp_state->cmds_cnt != 1 ||
1657 smtp_state->cmds_idx != 0 ||
1658 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1659 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1660 printf("smtp parser in inconsistent state\n");
1661 goto end;
1662 }
1663
1664 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1665 reply1, reply1_len);
1666 if (r != 0) {
1667 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1668 goto end;
1669 }
1670 if (smtp_state->input_len != 0 ||
576ec7da
AS
1671 smtp_state->cmds_cnt != 0 ||
1672 smtp_state->cmds_idx != 0 ||
1673 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1674 printf("smtp parser in inconsistent state\n");
1675 goto end;
1676 }
1677
1678 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1679 request2, request2_len);
1680 if (r != 0) {
1681 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1682 goto end;
1683 }
1684 if (smtp_state->input_len != 0 ||
576ec7da
AS
1685 smtp_state->cmds_cnt != 3 ||
1686 smtp_state->cmds_idx != 0 ||
1687 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1688 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
1689 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
1690 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1691 printf("smtp parser in inconsistent state\n");
1692 goto end;
1693 }
1694
1695 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1696 reply2, reply2_len);
1697 if (r != 0) {
1698 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1699 goto end;
1700 }
1701 if (smtp_state->input_len != 0 ||
576ec7da
AS
1702 smtp_state->cmds_cnt != 0 ||
1703 smtp_state->cmds_idx != 0 ||
1704 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1705 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1706 printf("smtp parser in inconsistent state\n");
1707 goto end;
1708 }
1709
1710 result = 1;
1711end:
1712 FlowL7DataPtrFree(&f);
1713 StreamTcpFreeConfig(TRUE);
1714 FLOW_DESTROY(&f);
1715 return result;
1716}
1717
1718/*
1719 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
1720 */
1721int SMTPParserTest04(void)
1722{
1723 int result = 0;
1724 Flow f;
1725 int r = 0;
1726
1727 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1728 uint8_t welcome_reply[] = {
1729 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1730 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1731 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1732 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1733 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1734 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1735 };
1736 uint32_t welcome_reply_len = sizeof(welcome_reply);
1737
1738 /* EHLO boo.com<CR><LF> */
1739 uint8_t request1[] = {
1740 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1741 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1742 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1743 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1744 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1745 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1746 };
1747 uint32_t request1_len = sizeof(request1);
1748
1749 TcpSession ssn;
1750
1751 memset(&f, 0, sizeof(f));
1752 memset(&ssn, 0, sizeof(ssn));
1753
1754 FLOW_INITIALIZE(&f);
1755 f.protoctx = (void *)&ssn;
1756
1757 StreamTcpInitConfig(TRUE);
1758 FlowL7DataPtrInit(&f);
1759
1760 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1761 request1, request1_len);
1762 if (r != 0) {
1763 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1764 goto end;
1765 }
1766 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
1767 if (smtp_state == NULL) {
1768 printf("no smtp state: ");
1769 goto end;
1770 }
1771 if (smtp_state->input_len != 0 ||
576ec7da
AS
1772 smtp_state->cmds_cnt != 1 ||
1773 smtp_state->cmds_idx != 0 ||
1774 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1775 smtp_state->parser_state != 0) {
1776 printf("smtp parser in inconsistent state\n");
1777 goto end;
1778 }
1779
1780 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1781 welcome_reply, welcome_reply_len);
1782 if (r != 0) {
1783 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1784 goto end;
1785 }
1786 if (smtp_state->input_len != 0 ||
576ec7da
AS
1787 smtp_state->cmds_cnt != 1 ||
1788 smtp_state->cmds_idx != 0 ||
1789 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1790 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1791 printf("smtp parser in inconsistent state\n");
1792 goto end;
1793 }
1794
1795 result = 1;
1796end:
1797 FlowL7DataPtrFree(&f);
1798 StreamTcpFreeConfig(TRUE);
1799 FLOW_DESTROY(&f);
1800 return result;
1801}
1802
1803/*
1804 * \test Test STARTTLS fail.
1805 */
1806int SMTPParserTest05(void)
1807{
1808 int result = 0;
1809 Flow f;
1810 int r = 0;
1811
1812 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1813 uint8_t welcome_reply[] = {
1814 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1815 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1816 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1817 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1818 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1819 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1820 };
1821 uint32_t welcome_reply_len = sizeof(welcome_reply);
1822
1823 /* EHLO boo.com<CR><LF> */
1824 uint8_t request1[] = {
1825 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1826 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1827 };
1828 uint32_t request1_len = sizeof(request1);
1829 /* 250-poona_slack_vm1.localdomain<CR><LF>
1830 * 250-PIPELINING<CR><LF>
1831 * 250-SIZE 10240000<CR><LF>
1832 * 250-VRFY<CR><LF>
1833 * 250-ETRN<CR><LF>
1834 * 250-ENHANCEDSTATUSCODES<CR><LF>
1835 * 250-8BITMIME<CR><LF>
1836 * 250 DSN<CR><LF>
1837 */
1838 uint8_t reply1[] = {
1839 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1840 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1841 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1842 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1843 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1844 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1845 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1846 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1847 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1848 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1849 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1850 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1851 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1852 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1853 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1854 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1855 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1856 };
1857 uint32_t reply1_len = sizeof(reply1);
1858
1859 /* STARTTLS<CR><LF> */
1860 uint8_t request2[] = {
1861 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1862 0x0d, 0x0a
1863 };
1864 uint32_t request2_len = sizeof(request2);
1865 /* 502 5.5.2 Error: command not recognized<CR><LF> */
1866 uint8_t reply2[] = {
1867 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
1868 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
1869 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
1870 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
1871 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
1872 0x0a
1873 };
1874 uint32_t reply2_len = sizeof(reply2);
1875
1876 /* QUIT<CR><LF> */
1877 uint8_t request3[] = {
1878 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1879
1880 };
1881 uint32_t request3_len = sizeof(request3);
1882 /* 221 2.0.0 Bye<CR><LF> */
1883 uint8_t reply3[] = {
1884 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1885 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1886 };
1887 uint32_t reply3_len = sizeof(reply3);
1888
1889 TcpSession ssn;
1890
1891 memset(&f, 0, sizeof(f));
1892 memset(&ssn, 0, sizeof(ssn));
1893
1894 FLOW_INITIALIZE(&f);
1895 f.protoctx = (void *)&ssn;
1896
1897 StreamTcpInitConfig(TRUE);
1898 FlowL7DataPtrInit(&f);
1899
1900 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1901 request1, request1_len);
1902 if (r != 0) {
1903 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1904 goto end;
1905 }
1906 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
1907 if (smtp_state == NULL) {
1908 printf("no smtp state: ");
1909 goto end;
1910 }
1911 if (smtp_state->input_len != 0 ||
576ec7da
AS
1912 smtp_state->cmds_cnt != 1 ||
1913 smtp_state->cmds_idx != 0 ||
1914 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1915 smtp_state->parser_state != 0) {
1916 printf("smtp parser in inconsistent state\n");
1917 goto end;
1918 }
1919
1920 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1921 welcome_reply, welcome_reply_len);
1922 if (r != 0) {
1923 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1924 goto end;
1925 }
1926 if (smtp_state->input_len != 0 ||
576ec7da
AS
1927 smtp_state->cmds_cnt != 1 ||
1928 smtp_state->cmds_idx != 0 ||
1929 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1930 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1931 printf("smtp parser in inconsistent state\n");
1932 goto end;
1933 }
1934
1935 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1936 reply1, reply1_len);
1937 if (r != 0) {
1938 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1939 goto end;
1940 }
1941 if (smtp_state->input_len != 0 ||
576ec7da
AS
1942 smtp_state->cmds_cnt != 0 ||
1943 smtp_state->cmds_idx != 0 ||
1944 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1945 printf("smtp parser in inconsistent state\n");
1946 goto end;
1947 }
1948
1949 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1950 request2, request2_len);
1951 if (r != 0) {
1952 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1953 goto end;
1954 }
1955 if (smtp_state->input_len != 0 ||
576ec7da
AS
1956 smtp_state->cmds_cnt != 1 ||
1957 smtp_state->cmds_idx != 0 ||
1958 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
1959 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1960 printf("smtp parser in inconsistent state\n");
1961 goto end;
1962 }
1963
1964 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1965 reply2, reply2_len);
1966 if (r != 0) {
1967 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1968 goto end;
1969 }
1970 if (smtp_state->input_len != 0 ||
576ec7da
AS
1971 smtp_state->cmds_cnt != 0 ||
1972 smtp_state->cmds_idx != 0 ||
1973 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1974 printf("smtp parser in inconsistent state\n");
1975 goto end;
1976 }
1977
1978 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
1979 (f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
1980 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
1981 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
1982 goto end;
1983 }
1984
1985 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1986 request3, request3_len);
1987 if (r != 0) {
1988 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1989 goto end;
1990 }
1991 if (smtp_state->input_len != 0 ||
576ec7da
AS
1992 smtp_state->cmds_cnt != 1 ||
1993 smtp_state->cmds_idx != 0 ||
1994 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1995 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1996 printf("smtp parser in inconsistent state\n");
1997 goto end;
1998 }
1999
2000 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2001 reply3, reply3_len);
2002 if (r != 0) {
2003 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2004 goto end;
2005 }
2006 if (smtp_state->input_len != 0 ||
576ec7da
AS
2007 smtp_state->cmds_cnt != 0 ||
2008 smtp_state->cmds_idx != 0 ||
2009 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2010 printf("smtp parser in inconsistent state\n");
2011 goto end;
2012 }
2013
2014 result = 1;
2015end:
2016 FlowL7DataPtrFree(&f);
2017 StreamTcpFreeConfig(TRUE);
2018 FLOW_DESTROY(&f);
2019 return result;
2020}
2021
d3ca65de
AS
2022/**
2023 * \test Test multiple DATA commands(full mail transactions).
2024 */
2025int SMTPParserTest06(void)
2026{
2027 int result = 0;
2028 Flow f;
2029 int r = 0;
2030
2031 uint8_t welcome_reply[] = {
2032 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
2033 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2034 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2035 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2036 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
2037 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
2038 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
2039 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
2040 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
2041 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
2042 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
2043 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
2044 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
2045 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
2046 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
2047 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
2048 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
2049 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
2050 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
2051 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
2052 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
2053 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
2054 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
2055 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
2056 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
2057 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
2058 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
2059 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
2060 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
2061 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
2062 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
2063 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
2064 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
2065 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
2066 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
2067 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
2068 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
2069 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
2070 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
2071 };
2072 uint32_t welcome_reply_len = sizeof(welcome_reply);
2073
2074 uint8_t request1[] = {
2075 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
2076 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
2077 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
2078 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
2079 0x0a
2080 };
2081 uint32_t request1_len = sizeof(request1);
2082
2083 uint8_t reply1[] = {
2084 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
2085 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2086 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2087 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2088 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
2089 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
2090 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
2091 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
2092 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
2093 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
2094 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
2095 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
2096 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
2097 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
2098 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2099 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
2100 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2101 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
2102 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2103 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2104 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2105 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2106 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
2107 0x0d, 0x0a
2108 };
2109 uint32_t reply1_len = sizeof(reply1);
2110
2111 /* MAIL FROM:asdff@asdf.com<CR><LF> */
2112 uint8_t request2[] = {
2113 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2114 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2115 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2116 0x0d, 0x0a
2117 };
2118 uint32_t request2_len = sizeof(request2);
2119 /* 250 2.1.0 Ok<CR><LF> */
2120 uint8_t reply2[] = {
2121 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2122 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2123 };
2124 uint32_t reply2_len = sizeof(reply2);
2125
2126 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2127 uint8_t request3[] = {
2128 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2129 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2130 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2131 0x0a
2132 };
2133 uint32_t request3_len = sizeof(request3);
2134 /* 250 2.1.5 Ok<CR><LF> */
2135 uint8_t reply3[] = {
2136 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2137 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2138 };
2139 uint32_t reply3_len = sizeof(reply3);
2140
2141 /* BDAT 51<CR><LF> */
2142 uint8_t request4[] = {
2143 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
2144 0x0a,
2145 };
2146 uint32_t request4_len = sizeof(request4);
2147
2148 uint8_t request5[] = {
2149 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2150 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2151 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2152 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
2153 };
2154 uint32_t request5_len = sizeof(request5);
2155
2156 uint8_t request6[] = {
2157 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2158 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2159 0x66, 0x0d, 0x0a,
2160 };
2161 uint32_t request6_len = sizeof(request5);
2162
2163 TcpSession ssn;
2164
2165 memset(&f, 0, sizeof(f));
2166 memset(&ssn, 0, sizeof(ssn));
2167
2168 FLOW_INITIALIZE(&f);
2169 f.protoctx = (void *)&ssn;
2170
2171 StreamTcpInitConfig(TRUE);
2172 FlowL7DataPtrInit(&f);
2173
2174 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2175 request1, request1_len);
2176 if (r != 0) {
2177 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2178 goto end;
2179 }
2180 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2181 if (smtp_state == NULL) {
2182 printf("no smtp state: ");
2183 goto end;
2184 }
2185 if (smtp_state->input_len != 0 ||
2186 smtp_state->cmds_cnt != 1 ||
2187 smtp_state->cmds_idx != 0 ||
2188 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2189 smtp_state->parser_state != 0) {
2190 printf("smtp parser in inconsistent state\n");
2191 goto end;
2192 }
2193
2194 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2195 welcome_reply, welcome_reply_len);
2196 if (r != 0) {
2197 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2198 goto end;
2199 }
2200 if (smtp_state->input_len != 0 ||
2201 smtp_state->cmds_cnt != 1 ||
2202 smtp_state->cmds_idx != 0 ||
2203 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2204 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2205 printf("smtp parser in inconsistent state\n");
2206 goto end;
2207 }
2208
2209 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2210 reply1, reply1_len);
2211 if (r != 0) {
2212 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2213 goto end;
2214 }
2215 if (smtp_state->input_len != 0 ||
2216 smtp_state->cmds_cnt != 0 ||
2217 smtp_state->cmds_idx != 0 ||
2218 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2219 printf("smtp parser in inconsistent state\n");
2220 goto end;
2221 }
2222
2223 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2224 request2, request2_len);
2225 if (r != 0) {
2226 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2227 goto end;
2228 }
2229 if (smtp_state->input_len != 0 ||
2230 smtp_state->cmds_cnt != 1 ||
2231 smtp_state->cmds_idx != 0 ||
2232 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2233 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2234 printf("smtp parser in inconsistent state\n");
2235 goto end;
2236 }
2237
2238 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2239 reply2, reply2_len);
2240 if (r != 0) {
2241 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2242 goto end;
2243 }
2244 if (smtp_state->input_len != 0 ||
2245 smtp_state->cmds_cnt != 0 ||
2246 smtp_state->cmds_idx != 0 ||
2247 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2248 printf("smtp parser in inconsistent state\n");
2249 goto end;
2250 }
2251
2252 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2253 request3, request3_len);
2254 if (r != 0) {
2255 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2256 goto end;
2257 }
2258 if (smtp_state->input_len != 0 ||
2259 smtp_state->cmds_cnt != 1 ||
2260 smtp_state->cmds_idx != 0 ||
2261 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2262 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2263 printf("smtp parser in inconsistent state\n");
2264 goto end;
2265 }
2266
2267 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2268 reply3, reply3_len);
2269 if (r != 0) {
2270 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2271 goto end;
2272 }
2273 if (smtp_state->input_len != 0 ||
2274 smtp_state->cmds_cnt != 0 ||
2275 smtp_state->cmds_idx != 0 ||
2276 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2277 printf("smtp parser in inconsistent state\n");
2278 goto end;
2279 }
2280
2281 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2282 request4, request4_len);
2283 if (r != 0) {
2284 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2285 goto end;
2286 }
2287 if (smtp_state->input_len != 0 ||
2288 smtp_state->cmds_cnt != 1 ||
2289 smtp_state->cmds_idx != 0 ||
2290 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
2291 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2292 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2293 smtp_state->bdat_chunk_len != 51 ||
2294 smtp_state->bdat_chunk_idx != 0) {
2295 printf("smtp parser in inconsistent state\n");
2296 goto end;
2297 }
2298
2299 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2300 request5, request5_len);
2301 if (r != 0) {
2302 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2303 goto end;
2304 }
2305 if (smtp_state->input_len != 0 ||
2306 smtp_state->cmds_cnt != 1 ||
2307 smtp_state->cmds_idx != 0 ||
2308 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2309 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2310 smtp_state->bdat_chunk_len != 51 ||
2311 smtp_state->bdat_chunk_idx != 32) {
2312 printf("smtp parser in inconsistent state\n");
2313 goto end;
2314 }
2315
2316 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2317 request6, request6_len);
2318 if (r != 0) {
2319 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2320 goto end;
2321 }
2322 if (smtp_state->input_len != 0 ||
2323 smtp_state->cmds_cnt != 1 ||
2324 smtp_state->cmds_idx != 0 ||
2325 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
2326 smtp_state->bdat_chunk_len != 51 ||
2327 smtp_state->bdat_chunk_idx != 51) {
2328 printf("smtp parser in inconsistent state\n");
2329 goto end;
2330 }
2331
2332 result = 1;
2333end:
2334 FlowL7DataPtrFree(&f);
2335 StreamTcpFreeConfig(TRUE);
2336 FLOW_DESTROY(&f);
2337 return result;
2338}
2339
576ec7da
AS
2340void SMTPParserRegisterTests(void)
2341{
2342 UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1);
2343 UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1);
2344 UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1);
2345 UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1);
2346 UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1);
d3ca65de 2347 UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1);
576ec7da
AS
2348 return;
2349}