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