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