]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-smtp.c
update detection engine to compare flow alproto with sig_alproto, rather than sm...
[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
4d38a571
AS
94
95#define SMTP_MPM MPM_AC
96
97static MpmCtx *smtp_mpm_ctx = NULL;
98MpmThreadCtx *smtp_mpm_thread_ctx;
99
100/* smtp reply codes. If an entry is made here, please make a simultaneous
101 * entry in smtp_reply_map */
102enum {
103 SMTP_REPLY_211,
104 SMTP_REPLY_214,
105 SMTP_REPLY_220,
106 SMTP_REPLY_221,
107 SMTP_REPLY_250,
108 SMTP_REPLY_251,
109 SMTP_REPLY_252,
110
111 SMTP_REPLY_354,
112
113 SMTP_REPLY_421,
114 SMTP_REPLY_450,
115 SMTP_REPLY_451,
116 SMTP_REPLY_452,
117 SMTP_REPLY_455,
118
119 SMTP_REPLY_500,
120 SMTP_REPLY_501,
121 SMTP_REPLY_502,
122 SMTP_REPLY_503,
123 SMTP_REPLY_504,
124 SMTP_REPLY_550,
125 SMTP_REPLY_551,
126 SMTP_REPLY_552,
127 SMTP_REPLY_553,
128 SMTP_REPLY_554,
129 SMTP_REPLY_555,
130};
131
132SCEnumCharMap smtp_reply_map[ ] = {
133 { "211", SMTP_REPLY_211 },
134 { "214", SMTP_REPLY_214 },
135 { "220", SMTP_REPLY_220 },
136 { "221", SMTP_REPLY_221 },
137 { "250", SMTP_REPLY_250 },
138 { "251", SMTP_REPLY_251 },
139 { "252", SMTP_REPLY_252 },
140
141 { "354", SMTP_REPLY_354 },
142
143 { "421", SMTP_REPLY_421 },
144 { "450", SMTP_REPLY_450 },
145 { "451", SMTP_REPLY_451 },
146 { "452", SMTP_REPLY_452 },
147 { "455", SMTP_REPLY_455 },
148
149 { "500", SMTP_REPLY_500 },
150 { "501", SMTP_REPLY_501 },
151 { "502", SMTP_REPLY_502 },
152 { "503", SMTP_REPLY_503 },
153 { "504", SMTP_REPLY_504 },
154 { "550", SMTP_REPLY_550 },
155 { "551", SMTP_REPLY_551 },
156 { "552", SMTP_REPLY_552 },
157 { "553", SMTP_REPLY_553 },
158 { "554", SMTP_REPLY_554 },
159 { "555", SMTP_REPLY_555 },
160 { NULL, -1 },
161};
576ec7da
AS
162//static void SMTPParserReset(void)
163//{
164// return;
165//}
166
167/**
168 * \internal
169 * \brief Get the next line from input. It doesn't do any length validation.
170 *
171 * \param state The smtp state.
172 *
173 * \retval 0 On suceess.
174 * \retval -1 Either when we don't have any new lines to supply anymore or
175 * on failure.
176 */
177static int SMTPGetLine(SMTPState *state)
178{
88115902
AS
179 /* we have run out of input */
180 if (state->input_len <= 0)
576ec7da
AS
181 return -1;
182
88115902
AS
183 /* toserver */
184 if (state->direction == 0) {
185 if (state->ts_current_line_lf_seen == 1) {
186 /* we have seen the lf for the previous line. Clear the parser
187 * details to parse new line */
188 state->ts_current_line_lf_seen = 0;
189 if (state->ts_current_line_db == 1) {
190 state->ts_current_line_db = 0;
191 SCFree(state->ts_db);
192 state->ts_db = NULL;
4a6908d3 193 state->ts_db_len = 0;
88115902 194 state->current_line = NULL;
4a6908d3 195 state->current_line_len = 0;
88115902 196 }
576ec7da 197 }
576ec7da 198
88115902 199 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
576ec7da 200
88115902 201 if (lf_idx == NULL) {
4d38a571 202 /* Fragmented line - set decoder event */
88115902 203 if (state->ts_current_line_db == 0) {
88115902
AS
204 state->ts_db = SCMalloc(state->input_len);
205 if (state->ts_db == NULL) {
206 return -1;
207 }
4a6908d3 208 state->ts_current_line_db = 1;
88115902
AS
209 memcpy(state->ts_db, state->input, state->input_len);
210 state->ts_db_len = state->input_len;
211 } else {
212 state->ts_db = SCRealloc(state->ts_db, (state->ts_db_len +
213 state->input_len));
214 if (state->ts_db == NULL) {
215 return -1;
216 }
217 memcpy(state->ts_db + state->ts_db_len,
218 state->input, state->input_len);
219 state->ts_db_len += state->input_len;
220 } /* else */
221 state->input += state->input_len;
222 state->input_len = 0;
223
224 return -1;
4a6908d3 225
576ec7da 226 } else {
88115902
AS
227 state->ts_current_line_lf_seen = 1;
228
4a6908d3
AS
229 if (state->ts_current_line_db == 1) {
230 state->ts_db = SCRealloc(state->ts_db,
231 (state->ts_db_len +
232 (lf_idx + 1 - state->input)));
233 if (state->ts_db == NULL) {
234 return -1;
235 }
236 memcpy(state->ts_db + state->ts_db_len,
237 state->input, (lf_idx + 1 - state->input));
238 state->ts_db_len += (lf_idx + 1 - state->input);
239
240 if (state->ts_db_len > 1 &&
241 state->ts_db[state->ts_db_len - 2] == 0x0D) {
242 state->ts_db_len -= 2;
243 state->current_line_delimiter_len = 2;
88115902 244 } else {
4a6908d3
AS
245 state->ts_db_len -= 1;
246 state->current_line_delimiter_len = 1;
88115902 247 }
576ec7da 248
4a6908d3
AS
249 state->current_line = state->ts_db;
250 state->current_line_len = state->ts_db_len;
251
88115902 252 } else {
4a6908d3
AS
253 state->current_line = state->input;
254 state->current_line_len = lf_idx - state->input;
255
256 if (state->input != lf_idx &&
257 *(lf_idx - 1) == 0x0D) {
258 state->current_line_len--;
259 state->current_line_delimiter_len = 2;
88115902 260 } else {
4d38a571 261 /* set decoder event for just LF delimiter */
4a6908d3 262 state->current_line_delimiter_len = 1;
88115902 263 }
4a6908d3 264 }
88115902
AS
265
266 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 267 state->input = (lf_idx + 1);
88115902
AS
268
269 return 0;
4a6908d3 270 }
88115902
AS
271
272 /* toclient */
576ec7da 273 } else {
88115902
AS
274 if (state->tc_current_line_lf_seen == 1) {
275 /* we have seen the lf for the previous line. Clear the parser
276 * details to parse new line */
277 state->tc_current_line_lf_seen = 0;
278 if (state->tc_current_line_db == 1) {
279 state->tc_current_line_db = 0;
280 SCFree(state->tc_db);
281 state->tc_db = NULL;
4a6908d3 282 state->tc_db_len = 0;
88115902 283 state->current_line = NULL;
4a6908d3 284 state->current_line_len = 0;
88115902
AS
285 }
286 }
287
288 uint8_t *lf_idx = memchr(state->input, 0x0a, state->input_len);
289
290 if (lf_idx == NULL) {
4d38a571 291 /* Fragmented line - set decoder event */
88115902 292 if (state->tc_current_line_db == 0) {
88115902
AS
293 state->tc_db = SCMalloc(state->input_len);
294 if (state->tc_db == NULL) {
576ec7da
AS
295 return -1;
296 }
4a6908d3 297 state->tc_current_line_db = 1;
88115902
AS
298 memcpy(state->tc_db, state->input, state->input_len);
299 state->tc_db_len = state->input_len;
576ec7da 300 } else {
88115902
AS
301 state->tc_db = SCRealloc(state->tc_db, (state->tc_db_len +
302 state->input_len));
303 if (state->tc_db == NULL) {
304 return -1;
305 }
306 memcpy(state->tc_db + state->tc_db_len,
307 state->input, state->input_len);
308 state->tc_db_len += state->input_len;
309 } /* else */
310 state->input += state->input_len;
311 state->input_len = 0;
576ec7da 312
88115902 313 return -1;
4a6908d3 314
576ec7da 315 } else {
88115902
AS
316 state->tc_current_line_lf_seen = 1;
317
4a6908d3
AS
318 if (state->tc_current_line_db == 1) {
319 state->tc_db = SCRealloc(state->tc_db,
320 (state->tc_db_len +
321 (lf_idx + 1 - state->input)));
322 if (state->tc_db == NULL) {
323 return -1;
324 }
325 memcpy(state->tc_db + state->tc_db_len,
326 state->input, (lf_idx + 1 - state->input));
327 state->tc_db_len += (lf_idx + 1 - state->input);
328
329 if (state->tc_db_len > 1 &&
330 state->tc_db[state->tc_db_len - 2] == 0x0D) {
331 state->tc_db_len -= 2;
332 state->current_line_delimiter_len = 2;
88115902 333 } else {
4a6908d3
AS
334 state->tc_db_len -= 1;
335 state->current_line_delimiter_len = 1;
576ec7da 336 }
88115902 337
4a6908d3
AS
338 state->current_line = state->tc_db;
339 state->current_line_len = state->tc_db_len;
340
576ec7da 341 } else {
4a6908d3
AS
342 state->current_line = state->input;
343 state->current_line_len = lf_idx - state->input;
344
345 if (state->input != lf_idx &&
346 *(lf_idx - 1) == 0x0D) {
347 state->current_line_len--;
348 state->current_line_delimiter_len = 2;
88115902 349 } else {
4d38a571 350 /* set decoder event for just LF delimiter */
4a6908d3 351 state->current_line_delimiter_len = 1;
88115902 352 }
4a6908d3 353 }
576ec7da 354
88115902 355 state->input_len -= (lf_idx - state->input) + 1;
4a6908d3 356 state->input = (lf_idx + 1);
88115902
AS
357
358 return 0;
359 } /* else - if (lf_idx == NULL) */
360 }
576ec7da 361
576ec7da
AS
362}
363
364static int SMTPInsertCommandIntoCommandBuffer(uint8_t command, SMTPState *state)
365{
366 if (state->cmds_cnt >= state->cmds_buffer_len) {
bc5c9f4a
VJ
367 int increment = SMTP_COMMAND_BUFFER_STEPS;
368 if ((int)(state->cmds_buffer_len + SMTP_COMMAND_BUFFER_STEPS) > (int)USHRT_MAX) {
369 increment = USHRT_MAX - state->cmds_buffer_len;
370 }
371
576ec7da
AS
372 state->cmds = SCRealloc(state->cmds,
373 sizeof(uint8_t) *
374 (state->cmds_buffer_len +
bc5c9f4a 375 increment));
576ec7da
AS
376 if (state->cmds == NULL) {
377 return -1;
378 }
bc5c9f4a 379 state->cmds_buffer_len += increment;
576ec7da
AS
380 }
381 if (state->cmds_cnt >= 1 &&
382 ((state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_STARTTLS) ||
383 (state->cmds[state->cmds_cnt - 1] == SMTP_COMMAND_DATA))) {
384 /* decoder event */
385 /* we have to have EHLO, DATA, VRFY, EXPN, TURN, QUIT, NOOP,
386 * STARTTLS as the last command in pipelined mode */
387 }
bc5c9f4a
VJ
388
389 /** \todo decoder event */
390 if ((int)(state->cmds_cnt + 1) > (int)USHRT_MAX)
391 return -1;
392
576ec7da
AS
393 state->cmds[state->cmds_cnt] = command;
394 state->cmds_cnt++;
395
396 return 0;
397}
398
d3ca65de
AS
399static int SMTPProcessCommandBDAT(SMTPState *state, Flow *f,
400 AppLayerParserState *pstate)
401{
402 state->bdat_chunk_idx += (state->current_line_len +
403 state->current_line_delimiter_len);
404 if (state->bdat_chunk_idx > state->bdat_chunk_len) {
405 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
406 /* decoder event */
407 return -1;
408 } else if (state->bdat_chunk_idx == state->bdat_chunk_len) {
409 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
410 }
411
412 return 0;
413}
414
576ec7da
AS
415static int SMTPProcessCommandDATA(SMTPState *state, Flow *f,
416 AppLayerParserState *pstate)
417{
418 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
419 /* looks like are still waiting for a confirmination from the server */
420 return 0;
421 }
422
423 if (state->current_line_len == 1 && state->current_line[0] == '.') {
424 state->parser_state &= ~SMTP_PARSER_STATE_COMMAND_DATA_MODE;
425 /* kinda like a hack. The mail sent in DATA mode, would be
426 * acknowledged with a reply. We insert a dummy command to
427 * the command buffer to be used by the reply handler to match
428 * the reply received */
429 SMTPInsertCommandIntoCommandBuffer(SMTP_COMMAND_DATA_MODE, state);
430 }
431
432 return 0;
433}
434
435static int SMTPProcessCommandSTARTTLS(SMTPState *state, Flow *f,
436 AppLayerParserState *pstate)
437{
438 return 0;
439}
440
441static int SMTPProcessReply(SMTPState *state, Flow *f,
442 AppLayerParserState *pstate)
443{
444 uint64_t reply_code = 0;
445
576ec7da
AS
446 /* the reply code has to contain at least 3 bytes, to hold the 3 digit
447 * reply code */
448 if (state->current_line_len < 3) {
449 /* decoder event */
450 return -1;
451 }
452
453 if (state->current_line_len >= 4) {
454 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
455 if (state->current_line[3] != '-') {
456 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
457 }
458 } else {
459 if (state->current_line[3] == '-') {
460 state->parser_state |= SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
461 }
462 }
463 } else {
464 if (state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY) {
465 state->parser_state &= ~SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY;
466 }
467 }
468
4d38a571
AS
469 /* I don't like this pmq reset here. We'll devise a method later, that
470 * should make the use of the mpm very efficient */
471 PmqReset(state->pmq);
472 int mpm_cnt = mpm_table[SMTP_MPM].Search(smtp_mpm_ctx, smtp_mpm_thread_ctx,
473 state->pmq, state->current_line,
474 3);
475 if (mpm_cnt == 0) {
476 /* set decoder event - reply code invalid */
477 return -1;
478 }
479 reply_code = smtp_reply_map[state->pmq->pattern_id_array[0]].enum_value;
480
481 if (state->cmds_idx == state->cmds_cnt) {
482 /* decoder event - unable to match reply with request */
576ec7da
AS
483 return -1;
484 }
485
486 /* kinda hack needed for us. Our parser logs commands, to be
487 * matched against server replies. SMTP is normally accompanied by a
488 * toclient welcome message, which would have had no command to
489 * accompany it with. And also alproto detection sees to it that the
490 * toserver stream is the first one to be processed by the app layer.
491 * Hence check the first reply and if it is a welcome message(220),
492 * leave without matching it against any buffered command */
493 if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
494 state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
4d38a571 495 if (reply_code == SMTP_REPLY_220) {
576ec7da 496 return 0;
4d38a571
AS
497 } else {
498 /* set decoder event - first reply from server not a welcome message */
576ec7da
AS
499 }
500 }
501
502 if (state->cmds[state->cmds_idx] == SMTP_COMMAND_STARTTLS) {
4d38a571 503 if (reply_code == SMTP_REPLY_220) {
576ec7da
AS
504 /* we are entering STARRTTLS data mode */
505 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
506 pstate->flags |= APP_LAYER_PARSER_DONE;
507 pstate->flags |= APP_LAYER_PARSER_NO_INSPECTION;
508 pstate->flags |= APP_LAYER_PARSER_NO_REASSEMBLY;
509 } else {
510 /* decoder event */
511 }
512 } else if (state->cmds[state->cmds_idx] == SMTP_COMMAND_DATA) {
4d38a571 513 if (reply_code == SMTP_REPLY_354) {
576ec7da
AS
514 /* Next comes the mail for the DATA command in toserver direction */
515 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
516 } else {
517 /* decoder event */
518 }
519 } else {
4d38a571
AS
520 /* we don't care for any other command for now */
521 /* check if reply falls in the valid list of replies for SMTP. If not
522 * decoder event */
576ec7da
AS
523 }
524
4d38a571 525 /* if it is a multi-line reply, we need to move the index only once for all
576ec7da
AS
526 * the line of the reply. We unset the multiline flag on the last
527 * line of the multiline reply, following which we increment the index */
528 if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY)) {
529 state->cmds_idx++;
530 }
531
532 /* if we have matched all the buffered commands, reset the cnt and index */
533 if (state->cmds_idx == state->cmds_cnt) {
534 state->cmds_cnt = 0;
535 state->cmds_idx = 0;
536 }
537
538 return 0;
539}
540
d3ca65de
AS
541static int SMTPParseCommandBDAT(SMTPState *state)
542{
543 int i = 4;
544 while (i < state->current_line_len) {
545 if (state->current_line[i] != ' ') {
546 break;
547 }
548 i++;
549 }
550 if (i == 4) {
551 /* decoder event */
552 return -1;
553 }
554 if (i == state->current_line_len) {
555 /* decoder event */
556 return -1;
557 }
558 uint8_t *endptr = NULL;
559 state->bdat_chunk_len = strtoul((const char *)state->current_line + i,
560 (char **)&endptr, 10);
561 if (endptr == state->current_line + i) {
562 /* decoder event */
563 return -1;
564 }
565
566 return 0;
567}
568
576ec7da
AS
569static int SMTPProcessRequest(SMTPState *state, Flow *f,
570 AppLayerParserState *pstate)
571{
572 /* there are 2 commands that can push it into this COMMAND_DATA mode -
573 * STARTTLS and DATA */
574 if (!(state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
d3ca65de
AS
575 int r = 0;
576
576ec7da
AS
577 if (state->current_line_len >= 8 &&
578 SCMemcmpLowercase("starttls", state->current_line, 8) == 0) {
579 state->current_command = SMTP_COMMAND_STARTTLS;
580 } else if (state->current_line_len >= 4 &&
581 SCMemcmpLowercase("data", state->current_line, 4) == 0) {
582 state->current_command = SMTP_COMMAND_DATA;
d3ca65de
AS
583 } else if (state->current_line_len >= 4 &&
584 SCMemcmpLowercase("bdat", state->current_line, 4) == 0) {
585 r = SMTPParseCommandBDAT(state);
586 if (r == -1)
587 return -1;
588 state->current_command = SMTP_COMMAND_BDAT;
589 state->parser_state |= SMTP_PARSER_STATE_COMMAND_DATA_MODE;
576ec7da
AS
590 } else {
591 state->current_command = SMTP_COMMAND_OTHER_CMD;
592 }
593
594 /* Every command is inserted into a command buffer, to be matched
595 * against reply(ies) sent by the server */
596 if (SMTPInsertCommandIntoCommandBuffer(state->current_command,
597 state) == -1) {
598 return -1;
599 }
d3ca65de
AS
600
601 return r;
576ec7da
AS
602 }
603
604 switch (state->current_command) {
605 case SMTP_COMMAND_STARTTLS:
606 return SMTPProcessCommandSTARTTLS(state, f, pstate);
607
608 case SMTP_COMMAND_DATA:
609 return SMTPProcessCommandDATA(state, f, pstate);
610
d3ca65de
AS
611 case SMTP_COMMAND_BDAT:
612 return SMTPProcessCommandBDAT(state, f, pstate);
613
576ec7da
AS
614 default:
615 /* we have nothing to do with any other command at this instant.
616 * Just let it go through */
617 return 0;
618 }
619}
620
88115902
AS
621static int SMTPParse(int direction, Flow *f, SMTPState *state,
622 AppLayerParserState *pstate, uint8_t *input,
623 uint32_t input_len, AppLayerParserResult *output)
576ec7da 624{
576ec7da
AS
625 state->input = input;
626 state->input_len = input_len;
88115902 627 state->direction = direction;
576ec7da
AS
628
629 while (SMTPGetLine(state) >= 0) {
88115902
AS
630 /* toserver */
631 if (direction == 0) {
d3ca65de
AS
632 if (SMTPProcessRequest(state, f, pstate) == -1)
633 return -1;
88115902
AS
634
635 /* toclient */
636 } else {
d3ca65de
AS
637 if (SMTPProcessReply(state, f, pstate) == -1)
638 return -1;
88115902 639 }
576ec7da
AS
640 }
641
642 return 0;
643}
644
88115902 645static int SMTPParseClientRecord(Flow *f, void *alstate,
576ec7da
AS
646 AppLayerParserState *pstate,
647 uint8_t *input, uint32_t input_len,
648 AppLayerParserResult *output)
649{
88115902
AS
650 /* first arg 0 is toserver */
651 return SMTPParse(0, f, alstate, pstate, input, input_len, output);
652}
576ec7da 653
88115902
AS
654static int SMTPParseServerRecord(Flow *f, void *alstate,
655 AppLayerParserState *pstate,
656 uint8_t *input, uint32_t input_len,
657 AppLayerParserResult *output)
658{
659 /* first arg 1 is toclient */
660 return SMTPParse(1, f, alstate, pstate, input, input_len, output);
576ec7da
AS
661
662 return 0;
663}
664
665/**
666 * \internal
667 * \brief Function to allocate SMTP state memory.
668 */
669static void *SMTPStateAlloc(void)
670{
671 SMTPState *smtp_state = SCMalloc(sizeof(SMTPState));
672 if (smtp_state == NULL)
673 return NULL;
674 memset(smtp_state, 0, sizeof(SMTPState));
675
676 smtp_state->cmds = SCMalloc(sizeof(uint8_t) *
677 SMTP_COMMAND_BUFFER_STEPS);
678 if (smtp_state->cmds == NULL) {
679 SCFree(smtp_state);
680 return NULL;
681 }
682 smtp_state->cmds_buffer_len = SMTP_COMMAND_BUFFER_STEPS;
683
4d38a571
AS
684 smtp_state->pmq = SCMalloc(sizeof(PatternMatcherQueue));
685 if (smtp_state->pmq == NULL) {
686 /* we need to exit here, since it is load time */
687 exit(EXIT_FAILURE);
688 }
689 PmqSetup(smtp_state->pmq, 0,
690 sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 2);
691
576ec7da
AS
692 return smtp_state;
693}
694
695/**
696 * \internal
697 * \brief Function to free SMTP state memory.
698 */
699static void SMTPStateFree(void *p)
700{
701 SMTPState *smtp_state = (SMTPState *)p;
702
4d38a571
AS
703 if (smtp_state->pmq != NULL) {
704 PmqFree(smtp_state->pmq);
705 SCFree(smtp_state->pmq);
706 }
576ec7da
AS
707 if (smtp_state->cmds != NULL) {
708 SCFree(smtp_state->cmds);
709 }
88115902
AS
710 if (smtp_state->ts_current_line_db) {
711 SCFree(smtp_state->ts_db);
712 }
713 if (smtp_state->tc_current_line_db) {
714 SCFree(smtp_state->tc_db);
715 }
576ec7da
AS
716
717 SCFree(smtp_state);
718
719 return;
720}
721
4d38a571
AS
722static void SMTPSetMpmState(void)
723{
724 smtp_mpm_ctx = SCMalloc(sizeof(MpmCtx));
725 if (smtp_mpm_ctx == NULL) {
726 /* we need to exit here, since it is load time */
727 exit(EXIT_FAILURE);
728 }
729 memset(smtp_mpm_ctx, 0, sizeof(MpmCtx));
730
731 smtp_mpm_thread_ctx = SCMalloc(sizeof(MpmThreadCtx));
732 if (smtp_mpm_thread_ctx == NULL) {
733 /* we need to exit here, since it is load time */
734 exit(EXIT_FAILURE);
735 }
736 memset(smtp_mpm_thread_ctx, 0, sizeof(MpmThreadCtx));
737
738 mpm_table[SMTP_MPM].InitCtx(smtp_mpm_ctx, -1);
739 mpm_table[SMTP_MPM].InitThreadCtx(smtp_mpm_ctx, smtp_mpm_thread_ctx, 0);
740
741 uint32_t i = 0;
742 for (i = 0; i < sizeof(smtp_reply_map)/sizeof(SCEnumCharMap) - 1; i++) {
743 SCEnumCharMap *map = &smtp_reply_map[i];
744 mpm_table[SMTP_MPM].AddPatternNocase(smtp_mpm_ctx,
745 (uint8_t *)map->enum_name,
746 3 /* reply codes always 3 bytes */,
747 0 /* now defunct option */,
748 0 /* now defunct option */,
749 i /* pattern id */,
750 0 /* no sid */,
751 0 /* no flags */);
752 }
753
754 mpm_table[SMTP_MPM].Prepare(smtp_mpm_ctx);
755}
756
576ec7da
AS
757/**
758 * \brief Register the SMPT Protocol parser.
759 */
760void RegisterSMTPParsers(void)
761{
762 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "EHLO", 4, 0,
763 STREAM_TOSERVER);
764 AlpProtoAdd(&alp_proto_ctx, IPPROTO_TCP, ALPROTO_SMTP, "HELO", 4, 0,
765 STREAM_TOSERVER);
766
767 AppLayerRegisterStateFuncs(ALPROTO_SMTP, SMTPStateAlloc, SMTPStateFree);
768
769 AppLayerRegisterProto("smtp", ALPROTO_SMTP, STREAM_TOSERVER,
770 SMTPParseClientRecord);
771 AppLayerRegisterProto("smtp", ALPROTO_SMTP, STREAM_TOCLIENT,
772 SMTPParseServerRecord);
773
4d38a571
AS
774 SMTPSetMpmState();
775
576ec7da
AS
776 return;
777}
778
779/***************************************Unittests******************************/
780
781/*
782 * \test Test STARTTLS.
783 */
784int SMTPParserTest01(void)
785{
786 int result = 0;
787 Flow f;
788 int r = 0;
789
790 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
791 uint8_t welcome_reply[] = {
792 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
793 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
794 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
795 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
796 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
797 0x0d, 0x0a
798 };
799 uint32_t welcome_reply_len = sizeof(welcome_reply);
800
801 /* EHLO [192.168.0.158]<CR><LF> */
802 uint8_t request1[] = {
803 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x5b, 0x31, 0x39,
804 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e,
805 0x31, 0x35, 0x38, 0x5d, 0x0d, 0x0a
806 };
807 uint32_t request1_len = sizeof(request1);
808 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
809 * 250-SIZE 35882577<CR><LF>
810 * 250-8BITMIME<CR><LF>
811 * 250-STARTTLS<CR><LF>
812 * 250 ENHANCEDSTATUSCODES<CR><LF>
813 */
814 uint8_t reply1[] = {
815 0x32, 0x35, 0x30, 0x2d, 0x6d, 0x78, 0x2e, 0x67,
816 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
817 0x6d, 0x20, 0x61, 0x74, 0x20, 0x79, 0x6f, 0x75,
818 0x72, 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
819 0x65, 0x2c, 0x20, 0x5b, 0x31, 0x31, 0x37, 0x2e,
820 0x31, 0x39, 0x38, 0x2e, 0x31, 0x31, 0x35, 0x2e,
821 0x35, 0x30, 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30,
822 0x2d, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x33, 0x35,
823 0x38, 0x38, 0x32, 0x35, 0x37, 0x37, 0x0d, 0x0a,
824 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49, 0x54,
825 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35,
826 0x30, 0x2d, 0x53, 0x54, 0x41, 0x52, 0x54, 0x54,
827 0x4c, 0x53, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20,
828 0x45, 0x4e, 0x48, 0x41, 0x4e, 0x43, 0x45, 0x44,
829 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x43, 0x4f,
830 0x44, 0x45, 0x53, 0x0d, 0x0a
831 };
832 uint32_t reply1_len = sizeof(reply1);
833
834 /* STARTTLS<CR><LF> */
835 uint8_t request2[] = {
836 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
837 0x0d, 0x0a
838 };
839 uint32_t request2_len = sizeof(request2);
840 /* 220 2.0.0 Ready to start TLS<CR><LF> */
841 uint8_t reply2[] = {
842 0x32, 0x32, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
843 0x30, 0x20, 0x52, 0x65, 0x61, 0x64, 0x79, 0x20,
844 0x74, 0x6f, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74,
845 0x20, 0x54, 0x4c, 0x53, 0x0d, 0x0a
846 };
847 uint32_t reply2_len = sizeof(reply2);
848
849 TcpSession ssn;
850
851 memset(&f, 0, sizeof(f));
852 memset(&ssn, 0, sizeof(ssn));
853
854 FLOW_INITIALIZE(&f);
855 f.protoctx = (void *)&ssn;
856
857 StreamTcpInitConfig(TRUE);
576ec7da
AS
858
859 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
860 request1, request1_len);
861 if (r != 0) {
862 printf("smtp check returned %" PRId32 ", expected 0: ", r);
863 goto end;
864 }
06904c90 865 SMTPState *smtp_state = f.alstate;
576ec7da
AS
866 if (smtp_state == NULL) {
867 printf("no smtp state: ");
868 goto end;
869 }
870 if (smtp_state->input_len != 0 ||
576ec7da
AS
871 smtp_state->cmds_cnt != 1 ||
872 smtp_state->cmds_idx != 0 ||
873 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
874 smtp_state->parser_state != 0) {
875 printf("smtp parser in inconsistent state\n");
876 goto end;
877 }
878
879 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
880 welcome_reply, welcome_reply_len);
881 if (r != 0) {
882 printf("smtp check returned %" PRId32 ", expected 0: ", r);
883 goto end;
884 }
885 if (smtp_state->input_len != 0 ||
576ec7da
AS
886 smtp_state->cmds_cnt != 1 ||
887 smtp_state->cmds_idx != 0 ||
888 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
889 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
890 printf("smtp parser in inconsistent state\n");
891 goto end;
892 }
893
894 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
895 reply1, reply1_len);
896 if (r != 0) {
897 printf("smtp check returned %" PRId32 ", expected 0: ", r);
898 goto end;
899 }
900 if (smtp_state->input_len != 0 ||
576ec7da
AS
901 smtp_state->cmds_cnt != 0 ||
902 smtp_state->cmds_idx != 0 ||
903 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
904 printf("smtp parser in inconsistent state\n");
905 goto end;
906 }
907
908 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
909 request2, request2_len);
910 if (r != 0) {
911 printf("smtp check returned %" PRId32 ", expected 0: ", r);
912 goto end;
913 }
914 if (smtp_state->input_len != 0 ||
576ec7da
AS
915 smtp_state->cmds_cnt != 1 ||
916 smtp_state->cmds_idx != 0 ||
917 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
918 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
919 printf("smtp parser in inconsistent state\n");
920 goto end;
921 }
922
923 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
924 reply2, reply2_len);
925 if (r != 0) {
926 printf("smtp check returned %" PRId32 ", expected 0: ", r);
927 goto end;
928 }
929 if (smtp_state->input_len != 0 ||
576ec7da
AS
930 smtp_state->cmds_cnt != 0 ||
931 smtp_state->cmds_idx != 0 ||
932 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
933 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
934 printf("smtp parser in inconsistent state\n");
935 goto end;
936 }
937
938 if (!(f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
939 !(f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
940 !(((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
941 !(((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
942 goto end;
943 }
944
945 result = 1;
946end:
576ec7da
AS
947 StreamTcpFreeConfig(TRUE);
948 FLOW_DESTROY(&f);
949 return result;
950}
951
952/**
953 * \test Test multiple DATA commands(full mail transactions).
954 */
955int SMTPParserTest02(void)
956{
957 int result = 0;
958 Flow f;
959 int r = 0;
960
961 /* 220 mx.google.com ESMTP d15sm986283wfl.6<CR><LF> */
962 uint8_t welcome_reply[] = {
963 0x32, 0x32, 0x30, 0x20, 0x6d, 0x78, 0x2e, 0x67,
964 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
965 0x6d, 0x20, 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20,
966 0x64, 0x31, 0x35, 0x73, 0x6d, 0x39, 0x38, 0x36,
967 0x32, 0x38, 0x33, 0x77, 0x66, 0x6c, 0x2e, 0x36,
968 0x0d, 0x0a
969 };
970 uint32_t welcome_reply_len = sizeof(welcome_reply);
971
972 /* EHLO boo.com<CR><LF> */
973 uint8_t request1[] = {
974 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
975 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
976 };
977 uint32_t request1_len = sizeof(request1);
978 /* 250-mx.google.com at your service, [117.198.115.50]<CR><LF>
979 * 250-SIZE 35882577<CR><LF>
980 * 250-8BITMIME<CR><LF>
981 * 250-STARTTLS<CR><LF>
982 * 250 ENHANCEDSTATUSCODES<CR><LF>
983 */
984 uint8_t reply1[] = {
985 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
986 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
987 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
988 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
989 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
990 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
991 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
992 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
993 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
994 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
995 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
996 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
997 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
998 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
999 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1000 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1001 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1002 };
1003 uint32_t reply1_len = sizeof(reply1);
1004
1005 /* MAIL FROM:asdff@asdf.com<CR><LF> */
1006 uint8_t request2[] = {
1007 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1008 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
1009 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1010 0x0d, 0x0a
1011 };
1012 uint32_t request2_len = sizeof(request2);
1013 /* 250 2.1.0 Ok<CR><LF> */
1014 uint8_t reply2[] = {
1015 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1016 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1017 };
1018 uint32_t reply2_len = sizeof(reply2);
1019
1020 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1021 uint8_t request3[] = {
1022 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1023 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1024 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1025 0x0a
1026 };
1027 uint32_t request3_len = sizeof(request3);
1028 /* 250 2.1.5 Ok<CR><LF> */
1029 uint8_t reply3[] = {
1030 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1031 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1032 };
1033 uint32_t reply3_len = sizeof(reply3);
1034
1035 /* DATA<CR><LF> */
1036 uint8_t request4[] = {
1037 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1038 };
1039 uint32_t request4_len = sizeof(request4);
1040 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1041 uint8_t reply4[] = {
1042 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1043 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1044 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1045 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1046 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1047 };
1048 uint32_t reply4_len = sizeof(reply4);
1049
1050 /* FROM:asdff@asdf.com<CR><LF> */
1051 uint8_t request5_1[] = {
1052 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1053 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
1054 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1055 };
1056 uint32_t request5_1_len = sizeof(request5_1);
1057 /* TO:bimbs@gmail.com<CR><LF> */
1058 uint8_t request5_2[] = {
1059 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1060 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1061 0x6f, 0x6d, 0x0d, 0x0a
1062 };
1063 uint32_t request5_2_len = sizeof(request5_2);
1064 /* <CR><LF> */
1065 uint8_t request5_3[] = {
1066 0x0d, 0x0a
1067 };
1068 uint32_t request5_3_len = sizeof(request5_3);
1069 /* this is test mail1<CR><LF> */
1070 uint8_t request5_4[] = {
1071 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1072 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1073 0x6c, 0x31, 0x0d, 0x0a
1074 };
1075 uint32_t request5_4_len = sizeof(request5_4);
1076 /* .<CR><LF> */
1077 uint8_t request5_5[] = {
1078 0x2e, 0x0d, 0x0a
1079 };
1080 uint32_t request5_5_len = sizeof(request5_5);
1081 /* 250 2.0.0 Ok: queued as 6A1AF20BF2<CR><LF> */
1082 uint8_t reply5[] = {
1083 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1084 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1085 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1086 0x36, 0x41, 0x31, 0x41, 0x46, 0x32, 0x30, 0x42,
1087 0x46, 0x32, 0x0d, 0x0a
1088 };
1089 uint32_t reply5_len = sizeof(reply5);
1090
1091 /* MAIL FROM:asdfg@asdf.com<CR><LF> */
1092 uint8_t request6[] = {
1093 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1094 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x67, 0x40,
1095 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
1096 0x0d, 0x0a
1097 };
1098 uint32_t request6_len = sizeof(request6);
1099 /* 250 2.1.0 Ok<CR><LF> */
1100 uint8_t reply6[] = {
1101 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1102 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1103 };
1104 uint32_t reply6_len = sizeof(reply6);
1105
1106 /* RCPT TO:bimbs@gmail.com<CR><LF> */
1107 uint8_t request7[] = {
1108 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
1109 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
1110 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
1111 0x0a
1112 };
1113 uint32_t request7_len = sizeof(request7);
1114 /* 250 2.1.5 Ok<CR><LF> */
1115 uint8_t reply7[] = {
1116 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1117 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
1118 };
1119 uint32_t reply7_len = sizeof(reply7);
1120
1121 /* DATA<CR><LF> */
1122 uint8_t request8[] = {
1123 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1124 };
1125 uint32_t request8_len = sizeof(request8);
1126 /* 354 End data with <CR><LF>.<CR><LF>|<CR><LF>| */
1127 uint8_t reply8[] = {
1128 0x33, 0x35, 0x34, 0x20, 0x45, 0x6e, 0x64, 0x20,
1129 0x64, 0x61, 0x74, 0x61, 0x20, 0x77, 0x69, 0x74,
1130 0x68, 0x20, 0x3c, 0x43, 0x52, 0x3e, 0x3c, 0x4c,
1131 0x46, 0x3e, 0x2e, 0x3c, 0x43, 0x52, 0x3e, 0x3c,
1132 0x4c, 0x46, 0x3e, 0x0d, 0x0a
1133 };
1134 uint32_t reply8_len = sizeof(reply8);
1135
1136 /* FROM:asdfg@gmail.com<CR><LF> */
1137 uint8_t request9_1[] = {
1138 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
1139 0x66, 0x67, 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c,
1140 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1141 };
1142 uint32_t request9_1_len = sizeof(request9_1);
1143 /* TO:bimbs@gmail.com<CR><LF> */
1144 uint8_t request9_2[] = {
1145 0x54, 0x4f, 0x3a, 0x62, 0x69, 0x6d, 0x62, 0x73,
1146 0x40, 0x67, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63,
1147 0x6f, 0x6d, 0x0d, 0x0a
1148 };
1149 uint32_t request9_2_len = sizeof(request9_2);
1150 /* <CR><LF> */
1151 uint8_t request9_3[] = {
1152 0x0d, 0x0a
1153 };
1154 uint32_t request9_3_len = sizeof(request9_3);
1155 /* this is test mail2<CR><LF> */
1156 uint8_t request9_4[] = {
1157 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
1158 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x61, 0x69,
1159 0x6c, 0x32, 0x0d, 0x0a
1160 };
1161 uint32_t request9_4_len = sizeof(request9_4);
1162 /* .<CR><LF> */
1163 uint8_t request9_5[] = {
1164 0x2e, 0x0d, 0x0a
1165 };
1166 uint32_t request9_5_len = sizeof(request9_5);
1167 /* 250 2.0.0 Ok: queued as 28CFF20BF2<CR><LF> */
1168 uint8_t reply9[] = {
1169 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1170 0x30, 0x20, 0x4f, 0x6b, 0x3a, 0x20, 0x71, 0x75,
1171 0x65, 0x75, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20,
1172 0x32, 0x38, 0x43, 0x46, 0x46, 0x32, 0x30, 0x42,
1173 0x46, 0x32, 0x0d, 0x0a
1174 };
1175 uint32_t reply9_len = sizeof(reply9);
1176
1177 /* QUIT<CR><LF> */
1178 uint8_t request10[] = {
1179 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1180 };
1181 uint32_t request10_len = sizeof(request10);
1182 /* 221 2.0.0 Bye<CR><LF> */
1183 uint8_t reply10[] = {
1184 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1185 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1186 };
1187 uint32_t reply10_len = sizeof(reply10);
1188
1189 TcpSession ssn;
1190
1191 memset(&f, 0, sizeof(f));
1192 memset(&ssn, 0, sizeof(ssn));
1193
1194 FLOW_INITIALIZE(&f);
1195 f.protoctx = (void *)&ssn;
1196
1197 StreamTcpInitConfig(TRUE);
576ec7da
AS
1198
1199 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1200 request1, request1_len);
1201 if (r != 0) {
1202 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1203 goto end;
1204 }
06904c90 1205 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1206 if (smtp_state == NULL) {
1207 printf("no smtp state: ");
1208 goto end;
1209 }
1210 if (smtp_state->input_len != 0 ||
576ec7da
AS
1211 smtp_state->cmds_cnt != 1 ||
1212 smtp_state->cmds_idx != 0 ||
1213 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1214 smtp_state->parser_state != 0) {
1215 printf("smtp parser in inconsistent state\n");
1216 goto end;
1217 }
1218
1219 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1220 welcome_reply, welcome_reply_len);
1221 if (r != 0) {
1222 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1223 goto end;
1224 }
1225 if (smtp_state->input_len != 0 ||
576ec7da
AS
1226 smtp_state->cmds_cnt != 1 ||
1227 smtp_state->cmds_idx != 0 ||
1228 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1229 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1230 printf("smtp parser in inconsistent state\n");
1231 goto end;
1232 }
1233
1234 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1235 reply1, reply1_len);
1236 if (r != 0) {
1237 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1238 goto end;
1239 }
1240 if (smtp_state->input_len != 0 ||
576ec7da
AS
1241 smtp_state->cmds_cnt != 0 ||
1242 smtp_state->cmds_idx != 0 ||
1243 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1244 printf("smtp parser in inconsistent state\n");
1245 goto end;
1246 }
1247
1248 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1249 request2, request2_len);
1250 if (r != 0) {
1251 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1252 goto end;
1253 }
1254 if (smtp_state->input_len != 0 ||
576ec7da
AS
1255 smtp_state->cmds_cnt != 1 ||
1256 smtp_state->cmds_idx != 0 ||
1257 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1258 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1259 printf("smtp parser in inconsistent state\n");
1260 goto end;
1261 }
1262
1263 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1264 reply2, reply2_len);
1265 if (r != 0) {
1266 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1267 goto end;
1268 }
1269 if (smtp_state->input_len != 0 ||
576ec7da
AS
1270 smtp_state->cmds_cnt != 0 ||
1271 smtp_state->cmds_idx != 0 ||
1272 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1273 printf("smtp parser in inconsistent state\n");
1274 goto end;
1275 }
1276
1277 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1278 request3, request3_len);
1279 if (r != 0) {
1280 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1281 goto end;
1282 }
1283 if (smtp_state->input_len != 0 ||
576ec7da
AS
1284 smtp_state->cmds_cnt != 1 ||
1285 smtp_state->cmds_idx != 0 ||
1286 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1287 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1288 printf("smtp parser in inconsistent state\n");
1289 goto end;
1290 }
1291
1292 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1293 reply3, reply3_len);
1294 if (r != 0) {
1295 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1296 goto end;
1297 }
1298 if (smtp_state->input_len != 0 ||
576ec7da
AS
1299 smtp_state->cmds_cnt != 0 ||
1300 smtp_state->cmds_idx != 0 ||
1301 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1302 printf("smtp parser in inconsistent state\n");
1303 goto end;
1304 }
1305
1306 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1307 request4, request4_len);
1308 if (r != 0) {
1309 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1310 goto end;
1311 }
1312 if (smtp_state->input_len != 0 ||
576ec7da
AS
1313 smtp_state->cmds_cnt != 1 ||
1314 smtp_state->cmds_idx != 0 ||
1315 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1316 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1317 printf("smtp parser in inconsistent state\n");
1318 goto end;
1319 }
1320
1321 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1322 reply4, reply4_len);
1323 if (r != 0) {
1324 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1325 goto end;
1326 }
1327 if (smtp_state->input_len != 0 ||
576ec7da
AS
1328 smtp_state->cmds_cnt != 0 ||
1329 smtp_state->cmds_idx != 0 ||
1330 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1331 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1332 printf("smtp parser in inconsistent state\n");
1333 goto end;
1334 }
1335
1336 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1337 request5_1, request5_1_len);
1338 if (r != 0) {
1339 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1340 goto end;
1341 }
1342 if (smtp_state->input_len != 0 ||
576ec7da
AS
1343 smtp_state->cmds_cnt != 0 ||
1344 smtp_state->cmds_idx != 0 ||
1345 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1346 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1347
1348 printf("smtp parser in inconsistent state\n");
1349 goto end;
1350 }
1351
1352 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1353 request5_2, request5_2_len);
1354 if (r != 0) {
1355 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1356 goto end;
1357 }
1358 if (smtp_state->input_len != 0 ||
576ec7da
AS
1359 smtp_state->cmds_cnt != 0 ||
1360 smtp_state->cmds_idx != 0 ||
1361 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1362 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1363
1364 printf("smtp parser in inconsistent state\n");
1365 goto end;
1366 }
1367
1368 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1369 request5_3, request5_3_len);
1370 if (r != 0) {
1371 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1372 goto end;
1373 }
1374 if (smtp_state->input_len != 0 ||
576ec7da
AS
1375 smtp_state->cmds_cnt != 0 ||
1376 smtp_state->cmds_idx != 0 ||
1377 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1378 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1379
1380 printf("smtp parser in inconsistent state\n");
1381 goto end;
1382 }
1383
1384 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1385 request5_4, request5_4_len);
1386 if (r != 0) {
1387 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1388 goto end;
1389 }
1390 if (smtp_state->input_len != 0 ||
576ec7da
AS
1391 smtp_state->cmds_cnt != 0 ||
1392 smtp_state->cmds_idx != 0 ||
1393 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1394 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1395
1396 printf("smtp parser in inconsistent state\n");
1397 goto end;
1398 }
1399
1400 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1401 request5_5, request5_5_len);
1402 if (r != 0) {
1403 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1404 goto end;
1405 }
1406 if (smtp_state->input_len != 0 ||
576ec7da
AS
1407 smtp_state->cmds_cnt != 1 ||
1408 smtp_state->cmds_idx != 0 ||
1409 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1410 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1411 printf("smtp parser in inconsistent state\n");
1412 goto end;
1413 }
1414
1415 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1416 reply5, reply5_len);
1417 if (r != 0) {
1418 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1419 goto end;
1420 }
1421 if (smtp_state->input_len != 0 ||
576ec7da
AS
1422 smtp_state->cmds_cnt != 0 ||
1423 smtp_state->cmds_idx != 0 ||
1424 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1425 printf("smtp parser in inconsistent state\n");
1426 goto end;
1427 }
1428
1429 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1430 request6, request6_len);
1431 if (r != 0) {
1432 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1433 goto end;
1434 }
1435 if (smtp_state->input_len != 0 ||
576ec7da
AS
1436 smtp_state->cmds_cnt != 1 ||
1437 smtp_state->cmds_idx != 0 ||
1438 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1439 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1440 printf("smtp parser in inconsistent state\n");
1441 goto end;
1442 }
1443
1444 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1445 reply6, reply6_len);
1446 if (r != 0) {
1447 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1448 goto end;
1449 }
1450 if (smtp_state->input_len != 0 ||
576ec7da
AS
1451 smtp_state->cmds_cnt != 0 ||
1452 smtp_state->cmds_idx != 0 ||
1453 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1454 printf("smtp parser in inconsistent state\n");
1455 goto end;
1456 }
1457
1458 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1459 request7, request7_len);
1460 if (r != 0) {
1461 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1462 goto end;
1463 }
1464 if (smtp_state->input_len != 0 ||
576ec7da
AS
1465 smtp_state->cmds_cnt != 1 ||
1466 smtp_state->cmds_idx != 0 ||
1467 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1468 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1469 printf("smtp parser in inconsistent state\n");
1470 goto end;
1471 }
1472
1473 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1474 reply7, reply7_len);
1475 if (r != 0) {
1476 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1477 goto end;
1478 }
1479 if (smtp_state->input_len != 0 ||
576ec7da
AS
1480 smtp_state->cmds_cnt != 0 ||
1481 smtp_state->cmds_idx != 0 ||
1482 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1483 printf("smtp parser in inconsistent state\n");
1484 goto end;
1485 }
1486
1487 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1488 request8, request8_len);
1489 if (r != 0) {
1490 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1491 goto end;
1492 }
1493 if (smtp_state->input_len != 0 ||
576ec7da
AS
1494 smtp_state->cmds_cnt != 1 ||
1495 smtp_state->cmds_idx != 0 ||
1496 smtp_state->cmds[0] != SMTP_COMMAND_DATA ||
1497 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1498 printf("smtp parser in inconsistent state\n");
1499 goto end;
1500 }
1501
1502 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1503 reply8, reply8_len);
1504 if (r != 0) {
1505 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1506 goto end;
1507 }
1508 if (smtp_state->input_len != 0 ||
576ec7da
AS
1509 smtp_state->cmds_cnt != 0 ||
1510 smtp_state->cmds_idx != 0 ||
1511 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1512 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1513 printf("smtp parser in inconsistent state\n");
1514 goto end;
1515 }
1516
1517 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1518 request9_1, request9_1_len);
1519 if (r != 0) {
1520 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1521 goto end;
1522 }
1523 if (smtp_state->input_len != 0 ||
576ec7da
AS
1524 smtp_state->cmds_cnt != 0 ||
1525 smtp_state->cmds_idx != 0 ||
1526 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1527 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1528
1529 printf("smtp parser in inconsistent state\n");
1530 goto end;
1531 }
1532
1533 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1534 request9_2, request9_2_len);
1535 if (r != 0) {
1536 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1537 goto end;
1538 }
1539 if (smtp_state->input_len != 0 ||
576ec7da
AS
1540 smtp_state->cmds_cnt != 0 ||
1541 smtp_state->cmds_idx != 0 ||
1542 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1543 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1544
1545 printf("smtp parser in inconsistent state\n");
1546 goto end;
1547 }
1548
1549 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1550 request9_3, request9_3_len);
1551 if (r != 0) {
1552 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1553 goto end;
1554 }
1555 if (smtp_state->input_len != 0 ||
576ec7da
AS
1556 smtp_state->cmds_cnt != 0 ||
1557 smtp_state->cmds_idx != 0 ||
1558 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1559 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1560
1561 printf("smtp parser in inconsistent state\n");
1562 goto end;
1563 }
1564
1565 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1566 request9_4, request9_4_len);
1567 if (r != 0) {
1568 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1569 goto end;
1570 }
1571 if (smtp_state->input_len != 0 ||
576ec7da
AS
1572 smtp_state->cmds_cnt != 0 ||
1573 smtp_state->cmds_idx != 0 ||
1574 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1575 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1576
1577 printf("smtp parser in inconsistent state\n");
1578 goto end;
1579 }
1580
1581 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1582 request9_5, request9_5_len);
1583 if (r != 0) {
1584 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1585 goto end;
1586 }
1587 if (smtp_state->input_len != 0 ||
576ec7da
AS
1588 smtp_state->cmds_cnt != 1 ||
1589 smtp_state->cmds_idx != 0 ||
1590 smtp_state->cmds[0] != SMTP_COMMAND_DATA_MODE ||
1591 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1592 printf("smtp parser in inconsistent state\n");
1593 goto end;
1594 }
1595
1596 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1597 reply9, reply9_len);
1598 if (r != 0) {
1599 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1600 goto end;
1601 }
1602 if (smtp_state->input_len != 0 ||
576ec7da
AS
1603 smtp_state->cmds_cnt != 0 ||
1604 smtp_state->cmds_idx != 0 ||
1605 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1606 printf("smtp parser in inconsistent state\n");
1607 goto end;
1608 }
1609
1610 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1611 request10, request10_len);
1612 if (r != 0) {
1613 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1614 goto end;
1615 }
1616 if (smtp_state->input_len != 0 ||
576ec7da
AS
1617 smtp_state->cmds_cnt != 1 ||
1618 smtp_state->cmds_idx != 0 ||
1619 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1620 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1621 printf("smtp parser in inconsistent state\n");
1622 goto end;
1623 }
1624
1625 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1626 reply10, reply10_len);
1627 if (r != 0) {
1628 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1629 goto end;
1630 }
1631 if (smtp_state->input_len != 0 ||
576ec7da
AS
1632 smtp_state->cmds_cnt != 0 ||
1633 smtp_state->cmds_idx != 0 ||
1634 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1635 printf("smtp parser in inconsistent state\n");
1636 goto end;
1637 }
1638
1639 result = 1;
1640end:
576ec7da
AS
1641 StreamTcpFreeConfig(TRUE);
1642 FLOW_DESTROY(&f);
1643 return result;
1644}
1645
1646/**
1647 * \test Testing parsing pipelined commands.
1648 */
1649int SMTPParserTest03(void)
1650{
1651 int result = 0;
1652 Flow f;
1653 int r = 0;
1654
1655 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1656 uint8_t welcome_reply[] = {
1657 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1658 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1659 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1660 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1661 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1662 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1663 };
1664 uint32_t welcome_reply_len = sizeof(welcome_reply);
1665
1666 /* EHLO boo.com<CR><LF> */
1667 uint8_t request1[] = {
1668 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1669 0x2e, 0x63, 0x6f, 0x6d, 0x0a
1670 };
1671 uint32_t request1_len = sizeof(request1);
1672 /* 250-poona_slack_vm1.localdomain<CR><LF>
1673 * 250-PIPELINING<CR><LF>
1674 * 250-SIZE 10240000<CR><LF>
1675 * 250-VRFY<CR><LF>
1676 * 250-ETRN<CR><LF>
1677 * 250-ENHANCEDSTATUSCODES<CR><LF>
1678 * 250-8BITMIME<CR><LF>
1679 * 250 DSN<CR><LF>
1680 */
1681 uint8_t reply1[] = {
1682 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1683 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1684 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1685 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1686 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1687 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1688 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1689 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1690 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1691 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1692 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1693 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1694 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1695 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1696 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1697 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1698 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1699 };
1700 uint32_t reply1_len = sizeof(reply1);
1701
1702 /* MAIL FROM:pbsf@asdfs.com<CR><LF>
1703 * RCPT TO:pbsf@asdfs.com<CR><LF>
1704 * DATA<CR><LF>
1705 */
1706 uint8_t request2[] = {
1707 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
1708 0x4d, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1709 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1710 0x0d, 0x0a, 0x52, 0x43, 0x50, 0x54, 0x20, 0x54,
1711 0x4f, 0x3a, 0x70, 0x62, 0x73, 0x66, 0x40, 0x61,
1712 0x73, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
1713 0x0d, 0x0a, 0x44, 0x41, 0x54, 0x41, 0x0d, 0x0a
1714 };
1715 uint32_t request2_len = sizeof(request2);
1716 /* 250 2.1.0 Ok<CR><LF>
1717 * 250 2.1.5 Ok<CR><LF>
1718 * 354 End data with <CR><LF>.<CR><LF>|<CR><LF>|
1719 */
1720 uint8_t reply2[] = {
1721 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
1722 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a, 0x32, 0x35,
1723 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e, 0x35, 0x20,
1724 0x4f, 0x6b, 0x0d, 0x0a, 0x33, 0x35, 0x34, 0x20,
1725 0x45, 0x6e, 0x64, 0x20, 0x64, 0x61, 0x74, 0x61,
1726 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x3c, 0x43,
1727 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x2e, 0x3c,
1728 0x43, 0x52, 0x3e, 0x3c, 0x4c, 0x46, 0x3e, 0x0d,
1729 0x0a
1730 };
1731 uint32_t reply2_len = sizeof(reply2);
1732
1733 TcpSession ssn;
1734
1735 memset(&f, 0, sizeof(f));
1736 memset(&ssn, 0, sizeof(ssn));
1737
1738 FLOW_INITIALIZE(&f);
1739 f.protoctx = (void *)&ssn;
1740
1741 StreamTcpInitConfig(TRUE);
576ec7da
AS
1742
1743 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1744 request1, request1_len);
1745 if (r != 0) {
1746 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1747 goto end;
1748 }
06904c90 1749 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1750 if (smtp_state == NULL) {
1751 printf("no smtp state: ");
1752 goto end;
1753 }
1754 if (smtp_state->input_len != 0 ||
576ec7da
AS
1755 smtp_state->cmds_cnt != 1 ||
1756 smtp_state->cmds_idx != 0 ||
1757 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1758 smtp_state->parser_state != 0) {
1759 printf("smtp parser in inconsistent state\n");
1760 goto end;
1761 }
1762
1763 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1764 welcome_reply, welcome_reply_len);
1765 if (r != 0) {
1766 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1767 goto end;
1768 }
1769 if (smtp_state->input_len != 0 ||
576ec7da
AS
1770 smtp_state->cmds_cnt != 1 ||
1771 smtp_state->cmds_idx != 0 ||
1772 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1773 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1774 printf("smtp parser in inconsistent state\n");
1775 goto end;
1776 }
1777
1778 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1779 reply1, reply1_len);
1780 if (r != 0) {
1781 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1782 goto end;
1783 }
1784 if (smtp_state->input_len != 0 ||
576ec7da
AS
1785 smtp_state->cmds_cnt != 0 ||
1786 smtp_state->cmds_idx != 0 ||
1787 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1788 printf("smtp parser in inconsistent state\n");
1789 goto end;
1790 }
1791
1792 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1793 request2, request2_len);
1794 if (r != 0) {
1795 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1796 goto end;
1797 }
1798 if (smtp_state->input_len != 0 ||
576ec7da
AS
1799 smtp_state->cmds_cnt != 3 ||
1800 smtp_state->cmds_idx != 0 ||
1801 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1802 smtp_state->cmds[1] != SMTP_COMMAND_OTHER_CMD ||
1803 smtp_state->cmds[2] != SMTP_COMMAND_DATA ||
1804 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
1805 printf("smtp parser in inconsistent state\n");
1806 goto end;
1807 }
1808
1809 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1810 reply2, reply2_len);
1811 if (r != 0) {
1812 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1813 goto end;
1814 }
1815 if (smtp_state->input_len != 0 ||
576ec7da
AS
1816 smtp_state->cmds_cnt != 0 ||
1817 smtp_state->cmds_idx != 0 ||
1818 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
1819 SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
1820 printf("smtp parser in inconsistent state\n");
1821 goto end;
1822 }
1823
1824 result = 1;
1825end:
576ec7da
AS
1826 StreamTcpFreeConfig(TRUE);
1827 FLOW_DESTROY(&f);
1828 return result;
1829}
1830
1831/*
1832 * \test Test smtp with just <LF> delimter instead of <CR><LF>.
1833 */
1834int SMTPParserTest04(void)
1835{
1836 int result = 0;
1837 Flow f;
1838 int r = 0;
1839
1840 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1841 uint8_t welcome_reply[] = {
1842 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1843 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1844 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1845 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1846 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1847 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1848 };
1849 uint32_t welcome_reply_len = sizeof(welcome_reply);
1850
1851 /* EHLO boo.com<CR><LF> */
1852 uint8_t request1[] = {
1853 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1854 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1855 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1856 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1857 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1858 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1859 };
1860 uint32_t request1_len = sizeof(request1);
1861
1862 TcpSession ssn;
1863
1864 memset(&f, 0, sizeof(f));
1865 memset(&ssn, 0, sizeof(ssn));
1866
1867 FLOW_INITIALIZE(&f);
1868 f.protoctx = (void *)&ssn;
1869
1870 StreamTcpInitConfig(TRUE);
576ec7da
AS
1871
1872 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
1873 request1, request1_len);
1874 if (r != 0) {
1875 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1876 goto end;
1877 }
06904c90 1878 SMTPState *smtp_state = f.alstate;
576ec7da
AS
1879 if (smtp_state == NULL) {
1880 printf("no smtp state: ");
1881 goto end;
1882 }
1883 if (smtp_state->input_len != 0 ||
576ec7da
AS
1884 smtp_state->cmds_cnt != 1 ||
1885 smtp_state->cmds_idx != 0 ||
1886 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1887 smtp_state->parser_state != 0) {
1888 printf("smtp parser in inconsistent state\n");
1889 goto end;
1890 }
1891
1892 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
1893 welcome_reply, welcome_reply_len);
1894 if (r != 0) {
1895 printf("smtp check returned %" PRId32 ", expected 0: ", r);
1896 goto end;
1897 }
1898 if (smtp_state->input_len != 0 ||
576ec7da
AS
1899 smtp_state->cmds_cnt != 1 ||
1900 smtp_state->cmds_idx != 0 ||
1901 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
1902 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
1903 printf("smtp parser in inconsistent state\n");
1904 goto end;
1905 }
1906
1907 result = 1;
1908end:
576ec7da
AS
1909 StreamTcpFreeConfig(TRUE);
1910 FLOW_DESTROY(&f);
1911 return result;
1912}
1913
1914/*
1915 * \test Test STARTTLS fail.
1916 */
1917int SMTPParserTest05(void)
1918{
1919 int result = 0;
1920 Flow f;
1921 int r = 0;
1922
1923 /* 220 poona_slack_vm1.localdomain ESMTP Postfix<CR><LF> */
1924 uint8_t welcome_reply[] = {
1925 0x32, 0x32, 0x30, 0x20, 0x70, 0x6f, 0x6f, 0x6e,
1926 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1927 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1928 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x20,
1929 0x45, 0x53, 0x4d, 0x54, 0x50, 0x20, 0x50, 0x6f,
1930 0x73, 0x74, 0x66, 0x69, 0x78, 0x0d, 0x0a
1931 };
1932 uint32_t welcome_reply_len = sizeof(welcome_reply);
1933
1934 /* EHLO boo.com<CR><LF> */
1935 uint8_t request1[] = {
1936 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
1937 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a
1938 };
1939 uint32_t request1_len = sizeof(request1);
1940 /* 250-poona_slack_vm1.localdomain<CR><LF>
1941 * 250-PIPELINING<CR><LF>
1942 * 250-SIZE 10240000<CR><LF>
1943 * 250-VRFY<CR><LF>
1944 * 250-ETRN<CR><LF>
1945 * 250-ENHANCEDSTATUSCODES<CR><LF>
1946 * 250-8BITMIME<CR><LF>
1947 * 250 DSN<CR><LF>
1948 */
1949 uint8_t reply1[] = {
1950 0x32, 0x35, 0x30, 0x2d, 0x70, 0x6f, 0x6f, 0x6e,
1951 0x61, 0x5f, 0x73, 0x6c, 0x61, 0x63, 0x6b, 0x5f,
1952 0x76, 0x6d, 0x31, 0x2e, 0x6c, 0x6f, 0x63, 0x61,
1953 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x0d,
1954 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x50, 0x49, 0x50,
1955 0x45, 0x4c, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x0d,
1956 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53, 0x49, 0x5a,
1957 0x45, 0x20, 0x31, 0x30, 0x32, 0x34, 0x30, 0x30,
1958 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
1959 0x56, 0x52, 0x46, 0x59, 0x0d, 0x0a, 0x32, 0x35,
1960 0x30, 0x2d, 0x45, 0x54, 0x52, 0x4e, 0x0d, 0x0a,
1961 0x32, 0x35, 0x30, 0x2d, 0x45, 0x4e, 0x48, 0x41,
1962 0x4e, 0x43, 0x45, 0x44, 0x53, 0x54, 0x41, 0x54,
1963 0x55, 0x53, 0x43, 0x4f, 0x44, 0x45, 0x53, 0x0d,
1964 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x38, 0x42, 0x49,
1965 0x54, 0x4d, 0x49, 0x4d, 0x45, 0x0d, 0x0a, 0x32,
1966 0x35, 0x30, 0x20, 0x44, 0x53, 0x4e, 0x0d, 0x0a
1967 };
1968 uint32_t reply1_len = sizeof(reply1);
1969
1970 /* STARTTLS<CR><LF> */
1971 uint8_t request2[] = {
1972 0x53, 0x54, 0x41, 0x52, 0x54, 0x54, 0x4c, 0x53,
1973 0x0d, 0x0a
1974 };
1975 uint32_t request2_len = sizeof(request2);
1976 /* 502 5.5.2 Error: command not recognized<CR><LF> */
1977 uint8_t reply2[] = {
1978 0x35, 0x30, 0x32, 0x20, 0x35, 0x2e, 0x35, 0x2e,
1979 0x32, 0x20, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x3a,
1980 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
1981 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x63,
1982 0x6f, 0x67, 0x6e, 0x69, 0x7a, 0x65, 0x64, 0x0d,
1983 0x0a
1984 };
1985 uint32_t reply2_len = sizeof(reply2);
1986
1987 /* QUIT<CR><LF> */
1988 uint8_t request3[] = {
1989 0x51, 0x55, 0x49, 0x54, 0x0d, 0x0a
1990
1991 };
1992 uint32_t request3_len = sizeof(request3);
1993 /* 221 2.0.0 Bye<CR><LF> */
1994 uint8_t reply3[] = {
1995 0x32, 0x32, 0x31, 0x20, 0x32, 0x2e, 0x30, 0x2e,
1996 0x30, 0x20, 0x42, 0x79, 0x65, 0x0d, 0x0a
1997 };
1998 uint32_t reply3_len = sizeof(reply3);
1999
2000 TcpSession ssn;
2001
2002 memset(&f, 0, sizeof(f));
2003 memset(&ssn, 0, sizeof(ssn));
2004
2005 FLOW_INITIALIZE(&f);
2006 f.protoctx = (void *)&ssn;
2007
2008 StreamTcpInitConfig(TRUE);
576ec7da
AS
2009
2010 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2011 request1, request1_len);
2012 if (r != 0) {
2013 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2014 goto end;
2015 }
06904c90 2016 SMTPState *smtp_state = f.alstate;
576ec7da
AS
2017 if (smtp_state == NULL) {
2018 printf("no smtp state: ");
2019 goto end;
2020 }
2021 if (smtp_state->input_len != 0 ||
576ec7da
AS
2022 smtp_state->cmds_cnt != 1 ||
2023 smtp_state->cmds_idx != 0 ||
2024 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2025 smtp_state->parser_state != 0) {
2026 printf("smtp parser in inconsistent state\n");
2027 goto end;
2028 }
2029
2030 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2031 welcome_reply, welcome_reply_len);
2032 if (r != 0) {
2033 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2034 goto end;
2035 }
2036 if (smtp_state->input_len != 0 ||
576ec7da
AS
2037 smtp_state->cmds_cnt != 1 ||
2038 smtp_state->cmds_idx != 0 ||
2039 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2040 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2041 printf("smtp parser in inconsistent state\n");
2042 goto end;
2043 }
2044
2045 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2046 reply1, reply1_len);
2047 if (r != 0) {
2048 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2049 goto end;
2050 }
2051 if (smtp_state->input_len != 0 ||
576ec7da
AS
2052 smtp_state->cmds_cnt != 0 ||
2053 smtp_state->cmds_idx != 0 ||
2054 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2055 printf("smtp parser in inconsistent state\n");
2056 goto end;
2057 }
2058
2059 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2060 request2, request2_len);
2061 if (r != 0) {
2062 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2063 goto end;
2064 }
2065 if (smtp_state->input_len != 0 ||
576ec7da
AS
2066 smtp_state->cmds_cnt != 1 ||
2067 smtp_state->cmds_idx != 0 ||
2068 smtp_state->cmds[0] != SMTP_COMMAND_STARTTLS ||
2069 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2070 printf("smtp parser in inconsistent state\n");
2071 goto end;
2072 }
2073
2074 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2075 reply2, reply2_len);
2076 if (r != 0) {
2077 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2078 goto end;
2079 }
2080 if (smtp_state->input_len != 0 ||
576ec7da
AS
2081 smtp_state->cmds_cnt != 0 ||
2082 smtp_state->cmds_idx != 0 ||
2083 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2084 printf("smtp parser in inconsistent state\n");
2085 goto end;
2086 }
2087
2088 if ((f.flags & FLOW_NOPAYLOAD_INSPECTION) ||
2089 (f.flags & FLOW_NO_APPLAYER_INSPECTION) ||
2090 (((TcpSession *)f.protoctx)->server.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY) ||
2091 (((TcpSession *)f.protoctx)->client.flags & STREAMTCP_STREAM_FLAG_NOREASSEMBLY)) {
2092 goto end;
2093 }
2094
2095 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2096 request3, request3_len);
2097 if (r != 0) {
2098 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2099 goto end;
2100 }
2101 if (smtp_state->input_len != 0 ||
576ec7da
AS
2102 smtp_state->cmds_cnt != 1 ||
2103 smtp_state->cmds_idx != 0 ||
2104 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2105 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2106 printf("smtp parser in inconsistent state\n");
2107 goto end;
2108 }
2109
2110 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2111 reply3, reply3_len);
2112 if (r != 0) {
2113 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2114 goto end;
2115 }
2116 if (smtp_state->input_len != 0 ||
576ec7da
AS
2117 smtp_state->cmds_cnt != 0 ||
2118 smtp_state->cmds_idx != 0 ||
2119 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2120 printf("smtp parser in inconsistent state\n");
2121 goto end;
2122 }
2123
2124 result = 1;
2125end:
576ec7da
AS
2126 StreamTcpFreeConfig(TRUE);
2127 FLOW_DESTROY(&f);
2128 return result;
2129}
2130
d3ca65de
AS
2131/**
2132 * \test Test multiple DATA commands(full mail transactions).
2133 */
2134int SMTPParserTest06(void)
2135{
2136 int result = 0;
2137 Flow f;
2138 int r = 0;
2139
2140 uint8_t welcome_reply[] = {
2141 0x32, 0x32, 0x30, 0x20, 0x62, 0x61, 0x79, 0x30,
2142 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2143 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2144 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2145 0x6d, 0x20, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e,
2146 0x67, 0x20, 0x75, 0x6e, 0x73, 0x6f, 0x6c, 0x69,
2147 0x63, 0x69, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6f,
2148 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x69, 0x61, 0x6c,
2149 0x20, 0x6f, 0x72, 0x20, 0x62, 0x75, 0x6c, 0x6b,
2150 0x20, 0x65, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x20,
2151 0x74, 0x6f, 0x20, 0x4d, 0x69, 0x63, 0x72, 0x6f,
2152 0x73, 0x6f, 0x66, 0x74, 0x27, 0x73, 0x20, 0x63,
2153 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x20,
2154 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x20,
2155 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x68, 0x69,
2156 0x62, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x4f,
2157 0x74, 0x68, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73,
2158 0x74, 0x72, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e,
2159 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x66, 0x6f,
2160 0x75, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x20, 0x68,
2161 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x70, 0x72,
2162 0x69, 0x76, 0x61, 0x63, 0x79, 0x2e, 0x6d, 0x73,
2163 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, 0x6e,
2164 0x74, 0x69, 0x2d, 0x73, 0x70, 0x61, 0x6d, 0x2f,
2165 0x2e, 0x20, 0x56, 0x69, 0x6f, 0x6c, 0x61, 0x74,
2166 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c,
2167 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74,
2168 0x20, 0x69, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20,
2169 0x6f, 0x66, 0x20, 0x65, 0x71, 0x75, 0x69, 0x70,
2170 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x63,
2171 0x61, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20,
2172 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e,
2173 0x69, 0x61, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f,
2174 0x74, 0x68, 0x65, 0x72, 0x20, 0x73, 0x74, 0x61,
2175 0x74, 0x65, 0x73, 0x2e, 0x20, 0x46, 0x72, 0x69,
2176 0x2c, 0x20, 0x31, 0x36, 0x20, 0x46, 0x65, 0x62,
2177 0x20, 0x32, 0x30, 0x30, 0x37, 0x20, 0x30, 0x35,
2178 0x3a, 0x30, 0x33, 0x3a, 0x32, 0x33, 0x20, 0x2d,
2179 0x30, 0x38, 0x30, 0x30, 0x20, 0x0d, 0x0a
2180 };
2181 uint32_t welcome_reply_len = sizeof(welcome_reply);
2182
2183 uint8_t request1[] = {
2184 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x45, 0x58, 0x43,
2185 0x48, 0x41, 0x4e, 0x47, 0x45, 0x32, 0x2e, 0x63,
2186 0x67, 0x63, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x69,
2187 0x61, 0x6d, 0x69, 0x2e, 0x65, 0x64, 0x75, 0x0d,
2188 0x0a
2189 };
2190 uint32_t request1_len = sizeof(request1);
2191
2192 uint8_t reply1[] = {
2193 0x32, 0x35, 0x30, 0x2d, 0x62, 0x61, 0x79, 0x30,
2194 0x2d, 0x6d, 0x63, 0x36, 0x2d, 0x66, 0x31, 0x30,
2195 0x2e, 0x62, 0x61, 0x79, 0x30, 0x2e, 0x68, 0x6f,
2196 0x74, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f,
2197 0x6d, 0x20, 0x28, 0x33, 0x2e, 0x33, 0x2e, 0x31,
2198 0x2e, 0x34, 0x29, 0x20, 0x48, 0x65, 0x6c, 0x6c,
2199 0x6f, 0x20, 0x5b, 0x31, 0x32, 0x39, 0x2e, 0x31,
2200 0x37, 0x31, 0x2e, 0x33, 0x32, 0x2e, 0x35, 0x39,
2201 0x5d, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x53,
2202 0x49, 0x5a, 0x45, 0x20, 0x32, 0x39, 0x36, 0x39,
2203 0x36, 0x30, 0x30, 0x30, 0x0d, 0x0a, 0x32, 0x35,
2204 0x30, 0x2d, 0x50, 0x49, 0x50, 0x45, 0x4c, 0x49,
2205 0x4e, 0x49, 0x4e, 0x47, 0x0d, 0x0a, 0x32, 0x35,
2206 0x30, 0x2d, 0x38, 0x62, 0x69, 0x74, 0x6d, 0x69,
2207 0x6d, 0x65, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2208 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x4d, 0x49,
2209 0x4d, 0x45, 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d,
2210 0x43, 0x48, 0x55, 0x4e, 0x4b, 0x49, 0x4e, 0x47,
2211 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2212 0x54, 0x48, 0x20, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2213 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x2d, 0x41, 0x55,
2214 0x54, 0x48, 0x3d, 0x4c, 0x4f, 0x47, 0x49, 0x4e,
2215 0x0d, 0x0a, 0x32, 0x35, 0x30, 0x20, 0x4f, 0x4b,
2216 0x0d, 0x0a
2217 };
2218 uint32_t reply1_len = sizeof(reply1);
2219
2220 /* MAIL FROM:asdff@asdf.com<CR><LF> */
2221 uint8_t request2[] = {
2222 0x4d, 0x41, 0x49, 0x4c, 0x20, 0x46, 0x52, 0x4f,
2223 0x4d, 0x3a, 0x61, 0x73, 0x64, 0x66, 0x66, 0x40,
2224 0x61, 0x73, 0x64, 0x66, 0x2e, 0x63, 0x6f, 0x6d,
2225 0x0d, 0x0a
2226 };
2227 uint32_t request2_len = sizeof(request2);
2228 /* 250 2.1.0 Ok<CR><LF> */
2229 uint8_t reply2[] = {
2230 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2231 0x30, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2232 };
2233 uint32_t reply2_len = sizeof(reply2);
2234
2235 /* RCPT TO:bimbs@gmail.com<CR><LF> */
2236 uint8_t request3[] = {
2237 0x52, 0x43, 0x50, 0x54, 0x20, 0x54, 0x4f, 0x3a,
2238 0x62, 0x69, 0x6d, 0x62, 0x73, 0x40, 0x67, 0x6d,
2239 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2240 0x0a
2241 };
2242 uint32_t request3_len = sizeof(request3);
2243 /* 250 2.1.5 Ok<CR><LF> */
2244 uint8_t reply3[] = {
2245 0x32, 0x35, 0x30, 0x20, 0x32, 0x2e, 0x31, 0x2e,
2246 0x35, 0x20, 0x4f, 0x6b, 0x0d, 0x0a
2247 };
2248 uint32_t reply3_len = sizeof(reply3);
2249
2250 /* BDAT 51<CR><LF> */
2251 uint8_t request4[] = {
2252 0x42, 0x44, 0x41, 0x54, 0x20, 0x35, 0x31, 0x0d,
2253 0x0a,
2254 };
2255 uint32_t request4_len = sizeof(request4);
2256
2257 uint8_t request5[] = {
2258 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2259 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2260 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2261 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x0d, 0x0a,
2262 };
2263 uint32_t request5_len = sizeof(request5);
2264
2265 uint8_t request6[] = {
2266 0x46, 0x52, 0x4f, 0x4d, 0x3a, 0x61, 0x73, 0x64,
2267 0x66, 0x66, 0x40, 0x61, 0x73, 0x64, 0x66, 0x2e,
2268 0x66, 0x0d, 0x0a,
2269 };
561630d8 2270 uint32_t request6_len = sizeof(request6);
d3ca65de
AS
2271
2272 TcpSession ssn;
2273
2274 memset(&f, 0, sizeof(f));
2275 memset(&ssn, 0, sizeof(ssn));
2276
2277 FLOW_INITIALIZE(&f);
2278 f.protoctx = (void *)&ssn;
2279
2280 StreamTcpInitConfig(TRUE);
d3ca65de
AS
2281
2282 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2283 request1, request1_len);
2284 if (r != 0) {
2285 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2286 goto end;
2287 }
06904c90 2288 SMTPState *smtp_state = f.alstate;
d3ca65de
AS
2289 if (smtp_state == NULL) {
2290 printf("no smtp state: ");
2291 goto end;
2292 }
2293 if (smtp_state->input_len != 0 ||
2294 smtp_state->cmds_cnt != 1 ||
2295 smtp_state->cmds_idx != 0 ||
2296 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2297 smtp_state->parser_state != 0) {
2298 printf("smtp parser in inconsistent state\n");
2299 goto end;
2300 }
2301
2302 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2303 welcome_reply, welcome_reply_len);
2304 if (r != 0) {
2305 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2306 goto end;
2307 }
2308 if (smtp_state->input_len != 0 ||
2309 smtp_state->cmds_cnt != 1 ||
2310 smtp_state->cmds_idx != 0 ||
2311 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2312 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2313 printf("smtp parser in inconsistent state\n");
2314 goto end;
2315 }
2316
2317 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2318 reply1, reply1_len);
2319 if (r != 0) {
2320 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2321 goto end;
2322 }
2323 if (smtp_state->input_len != 0 ||
2324 smtp_state->cmds_cnt != 0 ||
2325 smtp_state->cmds_idx != 0 ||
2326 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2327 printf("smtp parser in inconsistent state\n");
2328 goto end;
2329 }
2330
2331 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2332 request2, request2_len);
2333 if (r != 0) {
2334 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2335 goto end;
2336 }
2337 if (smtp_state->input_len != 0 ||
2338 smtp_state->cmds_cnt != 1 ||
2339 smtp_state->cmds_idx != 0 ||
2340 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2341 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2342 printf("smtp parser in inconsistent state\n");
2343 goto end;
2344 }
2345
2346 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2347 reply2, reply2_len);
2348 if (r != 0) {
2349 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2350 goto end;
2351 }
2352 if (smtp_state->input_len != 0 ||
2353 smtp_state->cmds_cnt != 0 ||
2354 smtp_state->cmds_idx != 0 ||
2355 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2356 printf("smtp parser in inconsistent state\n");
2357 goto end;
2358 }
2359
2360 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2361 request3, request3_len);
2362 if (r != 0) {
2363 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2364 goto end;
2365 }
2366 if (smtp_state->input_len != 0 ||
2367 smtp_state->cmds_cnt != 1 ||
2368 smtp_state->cmds_idx != 0 ||
2369 smtp_state->cmds[0] != SMTP_COMMAND_OTHER_CMD ||
2370 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN) {
2371 printf("smtp parser in inconsistent state\n");
2372 goto end;
2373 }
2374
2375 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOCLIENT,
2376 reply3, reply3_len);
2377 if (r != 0) {
2378 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2379 goto end;
2380 }
2381 if (smtp_state->input_len != 0 ||
2382 smtp_state->cmds_cnt != 0 ||
2383 smtp_state->cmds_idx != 0 ||
2384 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
2385 printf("smtp parser in inconsistent state\n");
2386 goto end;
2387 }
2388
2389 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2390 request4, request4_len);
2391 if (r != 0) {
2392 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2393 goto end;
2394 }
2395 if (smtp_state->input_len != 0 ||
2396 smtp_state->cmds_cnt != 1 ||
2397 smtp_state->cmds_idx != 0 ||
2398 smtp_state->cmds[0] != SMTP_COMMAND_BDAT ||
2399 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2400 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2401 smtp_state->bdat_chunk_len != 51 ||
2402 smtp_state->bdat_chunk_idx != 0) {
2403 printf("smtp parser in inconsistent state\n");
2404 goto end;
2405 }
2406
2407 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2408 request5, request5_len);
2409 if (r != 0) {
2410 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2411 goto end;
2412 }
2413 if (smtp_state->input_len != 0 ||
2414 smtp_state->cmds_cnt != 1 ||
2415 smtp_state->cmds_idx != 0 ||
2416 smtp_state->parser_state != (SMTP_PARSER_STATE_FIRST_REPLY_SEEN |
2417 SMTP_PARSER_STATE_COMMAND_DATA_MODE) ||
2418 smtp_state->bdat_chunk_len != 51 ||
2419 smtp_state->bdat_chunk_idx != 32) {
2420 printf("smtp parser in inconsistent state\n");
2421 goto end;
2422 }
2423
2424 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2425 request6, request6_len);
2426 if (r != 0) {
2427 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2428 goto end;
2429 }
2430 if (smtp_state->input_len != 0 ||
2431 smtp_state->cmds_cnt != 1 ||
2432 smtp_state->cmds_idx != 0 ||
2433 smtp_state->parser_state != SMTP_PARSER_STATE_FIRST_REPLY_SEEN ||
2434 smtp_state->bdat_chunk_len != 51 ||
2435 smtp_state->bdat_chunk_idx != 51) {
2436 printf("smtp parser in inconsistent state\n");
2437 goto end;
2438 }
2439
2440 result = 1;
2441end:
d3ca65de
AS
2442 StreamTcpFreeConfig(TRUE);
2443 FLOW_DESTROY(&f);
2444 return result;
2445}
2446
4a6908d3
AS
2447/*
2448 * \test Test retrieving lines when frag'ed.
2449 */
2450int SMTPParserTest07(void)
2451{
2452 int result = 0;
2453 Flow f;
2454 int r = 0;
2455
2456 const char *request1_str = "EHLO boo.com";
2457 /* EHLO boo.com<CR> */
2458 uint8_t request1_1[] = {
2459 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2460 0x2e, 0x63, 0x6f, 0x6d, 0x0d,
2461 };
2462 int32_t request1_1_len = sizeof(request1_1);
2463
2464 /* <LF> */
2465 uint8_t request1_2[] = {
2466 0x0a
2467 };
2468 int32_t request1_2_len = sizeof(request1_2);
2469
2470 /* EHLO boo.com<CR><LF> */
2471 uint8_t request2[] = {
2472 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2473 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2474 };
2475 int32_t request2_len = sizeof(request2);
2476
2477 TcpSession ssn;
2478
2479 memset(&f, 0, sizeof(f));
2480 memset(&ssn, 0, sizeof(ssn));
2481
2482 FLOW_INITIALIZE(&f);
2483 f.protoctx = (void *)&ssn;
2484
2485 StreamTcpInitConfig(TRUE);
2486 FlowL7DataPtrInit(&f);
2487
2488 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2489 request1_1, request1_1_len);
2490 if (r != 0) {
2491 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2492 goto end;
2493 }
2494 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2495 if (smtp_state == NULL) {
2496 printf("no smtp state: ");
2497 goto end;
2498 }
2499 if (smtp_state->current_line != NULL ||
2500 smtp_state->current_line_len != 0 ||
2501 smtp_state->ts_current_line_db != 1 ||
2502 smtp_state->ts_db == NULL ||
2503 smtp_state->ts_db_len != request1_1_len ||
2504 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2505 printf("smtp parser in inconsistent state\n");
2506 goto end;
2507 }
2508
2509 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2510 request1_2, request1_2_len);
2511 if (r != 0) {
2512 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2513 goto end;
2514 }
2515 if (smtp_state->ts_current_line_db != 1 ||
2516 smtp_state->ts_db == NULL ||
2517 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2518 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2519 smtp_state->current_line != smtp_state->ts_db ||
2520 smtp_state->current_line_len != smtp_state->ts_db_len) {
2521 printf("smtp parser in inconsistent state\n");
2522 goto end;
2523 }
2524
2525 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2526 request2, request2_len);
2527 if (r != 0) {
2528 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2529 goto end;
2530 }
2531 if (smtp_state->ts_current_line_db != 0 ||
2532 smtp_state->ts_db != NULL ||
2533 smtp_state->ts_db_len != 0 ||
2534 smtp_state->current_line == NULL ||
2535 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
2536 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2537 printf("smtp parser in inconsistent state\n");
2538 goto end;
2539 }
2540
2541 result = 1;
2542end:
2543 FlowL7DataPtrFree(&f);
2544 StreamTcpFreeConfig(TRUE);
2545 FLOW_DESTROY(&f);
2546 return result;
2547}
2548
2549/*
2550 * \test Test retrieving lines when frag'ed.
2551 */
2552int SMTPParserTest08(void)
2553{
2554 int result = 0;
2555 Flow f;
2556 int r = 0;
2557
2558 const char *request1_str = "EHLO boo.com";
2559 /* EHLO boo.com */
2560 uint8_t request1_1[] = {
2561 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2562 0x2e, 0x63, 0x6f, 0x6d,
2563 };
2564 int32_t request1_1_len = sizeof(request1_1);
2565
2566 /* <CR><LF> */
2567 uint8_t request1_2[] = {
2568 0x0d, 0x0a
2569 };
2570 int32_t request1_2_len = sizeof(request1_2);
2571
2572 /* EHLO boo.com<CR><LF> */
2573 uint8_t request2[] = {
2574 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2575 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2576 };
2577 int32_t request2_len = sizeof(request2);
2578
2579 TcpSession ssn;
2580
2581 memset(&f, 0, sizeof(f));
2582 memset(&ssn, 0, sizeof(ssn));
2583
2584 FLOW_INITIALIZE(&f);
2585 f.protoctx = (void *)&ssn;
2586
2587 StreamTcpInitConfig(TRUE);
2588 FlowL7DataPtrInit(&f);
2589
2590 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2591 request1_1, request1_1_len);
2592 if (r != 0) {
2593 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2594 goto end;
2595 }
2596 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2597 if (smtp_state == NULL) {
2598 printf("no smtp state: ");
2599 goto end;
2600 }
2601 if (smtp_state->current_line != NULL ||
2602 smtp_state->current_line_len != 0 ||
2603 smtp_state->ts_current_line_db != 1 ||
2604 smtp_state->ts_db == NULL ||
2605 smtp_state->ts_db_len != request1_1_len ||
2606 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2607 printf("smtp parser in inconsistent state\n");
2608 goto end;
2609 }
2610
2611 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2612 request1_2, request1_2_len);
2613 if (r != 0) {
2614 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2615 goto end;
2616 }
2617 if (smtp_state->ts_current_line_db != 1 ||
2618 smtp_state->ts_db == NULL ||
2619 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2620 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2621 smtp_state->current_line != smtp_state->ts_db ||
2622 smtp_state->current_line_len != smtp_state->ts_db_len) {
2623 printf("smtp parser in inconsistent state\n");
2624 goto end;
2625 }
2626
2627 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2628 request2, request2_len);
2629 if (r != 0) {
2630 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2631 goto end;
2632 }
2633 if (smtp_state->ts_current_line_db != 0 ||
2634 smtp_state->ts_db != NULL ||
2635 smtp_state->ts_db_len != 0 ||
2636 smtp_state->current_line == NULL ||
2637 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
2638 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2639 printf("smtp parser in inconsistent state\n");
2640 goto end;
2641 }
2642
2643 result = 1;
2644end:
2645 FlowL7DataPtrFree(&f);
2646 StreamTcpFreeConfig(TRUE);
2647 FLOW_DESTROY(&f);
2648 return result;
2649}
2650
2651/*
2652 * \test Test retrieving lines when frag'ed.
2653 */
2654int SMTPParserTest09(void)
2655{
2656 int result = 0;
2657 Flow f;
2658 int r = 0;
2659
2660 const char *request1_str = "EHLO boo.com";
2661 /* EHLO boo. */
2662 uint8_t request1_1[] = {
2663 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2664 0x2e,
2665 };
2666 int32_t request1_1_len = sizeof(request1_1);
2667
2668 /* com<CR><LF> */
2669 uint8_t request1_2[] = {
2670 0x63, 0x6f, 0x6d, 0x0d, 0x0a
2671 };
2672 int32_t request1_2_len = sizeof(request1_2);
2673
2674 /* EHLO boo.com<CR><LF> */
2675 uint8_t request2[] = {
2676 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2677 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2678 };
2679 int32_t request2_len = sizeof(request2);
2680
2681 TcpSession ssn;
2682
2683 memset(&f, 0, sizeof(f));
2684 memset(&ssn, 0, sizeof(ssn));
2685
2686 FLOW_INITIALIZE(&f);
2687 f.protoctx = (void *)&ssn;
2688
2689 StreamTcpInitConfig(TRUE);
2690 FlowL7DataPtrInit(&f);
2691
2692 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2693 request1_1, request1_1_len);
2694 if (r != 0) {
2695 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2696 goto end;
2697 }
2698 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2699 if (smtp_state == NULL) {
2700 printf("no smtp state: ");
2701 goto end;
2702 }
2703 if (smtp_state->current_line != NULL ||
2704 smtp_state->current_line_len != 0 ||
2705 smtp_state->ts_current_line_db != 1 ||
2706 smtp_state->ts_db == NULL ||
2707 smtp_state->ts_db_len != request1_1_len ||
2708 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2709 printf("smtp parser in inconsistent state\n");
2710 goto end;
2711 }
2712
2713 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2714 request1_2, request1_2_len);
2715 if (r != 0) {
2716 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2717 goto end;
2718 }
2719 if (smtp_state->ts_current_line_db != 1 ||
2720 smtp_state->ts_db == NULL ||
2721 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2722 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2723 smtp_state->current_line != smtp_state->ts_db ||
2724 smtp_state->current_line_len != smtp_state->ts_db_len) {
2725 printf("smtp parser in inconsistent state\n");
2726 goto end;
2727 }
2728
2729 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2730 request2, request2_len);
2731 if (r != 0) {
2732 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2733 goto end;
2734 }
2735 if (smtp_state->ts_current_line_db != 0 ||
2736 smtp_state->ts_db != NULL ||
2737 smtp_state->ts_db_len != 0 ||
2738 smtp_state->current_line == NULL ||
2739 smtp_state->current_line_len != (int32_t)strlen(request1_str) ||
2740 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2741 printf("smtp parser in inconsistent state\n");
2742 goto end;
2743 }
2744
2745 result = 1;
2746end:
2747 FlowL7DataPtrFree(&f);
2748 StreamTcpFreeConfig(TRUE);
2749 FLOW_DESTROY(&f);
2750 return result;
2751}
2752
2753/*
2754 * \test Test retrieving lines when frag'ed.
2755 */
2756int SMTPParserTest10(void)
2757{
2758 int result = 0;
2759 Flow f;
2760 int r = 0;
2761
2762 const char *request1_str = "";
2763 /* EHLO boo. */
2764 uint8_t request1_1[] = {
2765 0x0d,
2766 };
2767 int32_t request1_1_len = sizeof(request1_1);
2768
2769 /* com<CR><LF> */
2770 uint8_t request1_2[] = {
2771 0x0a,
2772 };
2773 int32_t request1_2_len = sizeof(request1_2);
2774
2775 const char *request2_str = "EHLO boo.com";
2776 /* EHLO boo.com<CR><LF> */
2777 uint8_t request2[] = {
2778 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2779 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2780 };
2781 int32_t request2_len = sizeof(request2);
2782
2783 TcpSession ssn;
2784
2785 memset(&f, 0, sizeof(f));
2786 memset(&ssn, 0, sizeof(ssn));
2787
2788 FLOW_INITIALIZE(&f);
2789 f.protoctx = (void *)&ssn;
2790
2791 StreamTcpInitConfig(TRUE);
2792 FlowL7DataPtrInit(&f);
2793
2794 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2795 request1_1, request1_1_len);
2796 if (r != 0) {
2797 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2798 goto end;
2799 }
2800 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2801 if (smtp_state == NULL) {
2802 printf("no smtp state: ");
2803 goto end;
2804 }
2805 if (smtp_state->current_line != NULL ||
2806 smtp_state->current_line_len != 0 ||
2807 smtp_state->ts_current_line_db != 1 ||
2808 smtp_state->ts_db == NULL ||
2809 smtp_state->ts_db_len != request1_1_len ||
2810 memcmp(smtp_state->ts_db, request1_1, request1_1_len) != 0) {
2811 printf("smtp parser in inconsistent state\n");
2812 goto end;
2813 }
2814
2815 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2816 request1_2, request1_2_len);
2817 if (r != 0) {
2818 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2819 goto end;
2820 }
2821 if (smtp_state->ts_current_line_db != 1 ||
2822 smtp_state->ts_db == NULL ||
2823 smtp_state->ts_db_len != (int32_t)strlen(request1_str) ||
2824 memcmp(smtp_state->ts_db, request1_str, strlen(request1_str)) != 0 ||
2825 smtp_state->current_line != smtp_state->ts_db ||
2826 smtp_state->current_line_len != smtp_state->ts_db_len) {
2827 printf("smtp parser in inconsistent state\n");
2828 goto end;
2829 }
2830
2831 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2832 request2, request2_len);
2833 if (r != 0) {
2834 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2835 goto end;
2836 }
2837 if (smtp_state->ts_current_line_db != 0 ||
2838 smtp_state->ts_db != NULL ||
2839 smtp_state->ts_db_len != 0 ||
2840 smtp_state->current_line == NULL ||
2841 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
2842 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
2843 printf("smtp parser in inconsistent state\n");
2844 goto end;
2845 }
2846
2847 result = 1;
2848end:
2849 FlowL7DataPtrFree(&f);
2850 StreamTcpFreeConfig(TRUE);
2851 FLOW_DESTROY(&f);
2852 return result;
2853}
2854
2855/*
2856 * \test Test retrieving lines when frag'ed.
2857 */
2858int SMTPParserTest11(void)
2859{
2860 int result = 0;
2861 Flow f;
2862 int r = 0;
2863
2864 const char *request1_str = "";
2865 /* EHLO boo. */
2866 uint8_t request1[] = {
2867 0x0a,
2868 };
2869 int32_t request1_len = sizeof(request1);
2870
2871 const char *request2_str = "EHLO boo.com";
2872 /* EHLO boo.com<CR><LF> */
2873 uint8_t request2[] = {
2874 0x45, 0x48, 0x4c, 0x4f, 0x20, 0x62, 0x6f, 0x6f,
2875 0x2e, 0x63, 0x6f, 0x6d, 0x0d, 0x0a,
2876 };
2877 int32_t request2_len = sizeof(request2);
2878
2879 TcpSession ssn;
2880
2881 memset(&f, 0, sizeof(f));
2882 memset(&ssn, 0, sizeof(ssn));
2883
2884 FLOW_INITIALIZE(&f);
2885 f.protoctx = (void *)&ssn;
2886
2887 StreamTcpInitConfig(TRUE);
2888 FlowL7DataPtrInit(&f);
2889
2890 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2891 request1, request1_len);
2892 if (r != 0) {
2893 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2894 goto end;
2895 }
2896 SMTPState *smtp_state = f.aldata[AlpGetStateIdx(ALPROTO_SMTP)];
2897 if (smtp_state == NULL) {
2898 printf("no smtp state: ");
2899 goto end;
2900 }
2901 if (smtp_state->current_line == NULL ||
2902 smtp_state->current_line_len != 0 ||
2903 smtp_state->ts_current_line_db == 1 ||
2904 smtp_state->ts_db != NULL ||
2905 smtp_state->ts_db_len != 0 ||
2906 memcmp(smtp_state->current_line, request1_str, strlen(request1_str)) != 0) {
2907 printf("smtp parser in inconsistent state\n");
2908 goto end;
2909 }
2910
2911 r = AppLayerParse(&f, ALPROTO_SMTP, STREAM_TOSERVER,
2912 request2, request2_len);
2913 if (r != 0) {
2914 printf("smtp check returned %" PRId32 ", expected 0: ", r);
2915 goto end;
2916 }
2917 if (smtp_state->ts_current_line_db != 0 ||
2918 smtp_state->ts_db != NULL ||
2919 smtp_state->ts_db_len != 0 ||
2920 smtp_state->current_line == NULL ||
2921 smtp_state->current_line_len != (int32_t)strlen(request2_str) ||
2922 memcmp(smtp_state->current_line, request2_str, strlen(request2_str)) != 0) {
2923 printf("smtp parser in inconsistent state\n");
2924 goto end;
2925 }
2926
2927 result = 1;
2928end:
2929 FlowL7DataPtrFree(&f);
2930 StreamTcpFreeConfig(TRUE);
2931 FLOW_DESTROY(&f);
2932 return result;
2933}
2934
576ec7da
AS
2935void SMTPParserRegisterTests(void)
2936{
2937 UtRegisterTest("SMTPParserTest01", SMTPParserTest01, 1);
2938 UtRegisterTest("SMTPParserTest02", SMTPParserTest02, 1);
2939 UtRegisterTest("SMTPParserTest03", SMTPParserTest03, 1);
2940 UtRegisterTest("SMTPParserTest04", SMTPParserTest04, 1);
2941 UtRegisterTest("SMTPParserTest05", SMTPParserTest05, 1);
d3ca65de 2942 UtRegisterTest("SMTPParserTest06", SMTPParserTest06, 1);
4a6908d3
AS
2943 UtRegisterTest("SMTPParserTest07", SMTPParserTest07, 1);
2944 UtRegisterTest("SMTPParserTest08", SMTPParserTest08, 1);
2945 UtRegisterTest("SMTPParserTest09", SMTPParserTest09, 1);
2946 UtRegisterTest("SMTPParserTest10", SMTPParserTest10, 1);
2947 UtRegisterTest("SMTPParserTest11", SMTPParserTest11, 1);
2948
576ec7da
AS
2949 return;
2950}