diff options
author | jpadkins <jacobpadkins@gmail.com> | 2017-03-29 21:07:37 +0300 |
---|---|---|
committer | jpadkins <jacobpadkins@gmail.com> | 2017-03-29 21:07:37 +0300 |
commit | 38c6d9e19542ab16200986836af3b9af5a688057 (patch) | |
tree | 4cd39355fdf79d6f3bb25e4e5d31d9b9337f6c59 /check | |
parent | 35c5da118a6d93cc0ea66827bea24b494854ef4e (diff) |
Added regressing test for dot stuffing
Diffstat (limited to 'check')
-rw-r--r-- | check/magma/regression/regression_check.c | 114 | ||||
-rw-r--r-- | check/magma/regression/regression_check.h | 3 | ||||
-rw-r--r-- | check/magma/servers/pop/pop_check.h | 3 | ||||
-rw-r--r-- | check/magma/servers/pop/pop_check_network.c | 49 | ||||
-rw-r--r-- | check/magma/servers/smtp/checkers_check.c | 1 |
5 files changed, 163 insertions, 7 deletions
diff --git a/check/magma/regression/regression_check.c b/check/magma/regression/regression_check.c index d60ee974..d7118893 100644 --- a/check/magma/regression/regression_check.c +++ b/check/magma/regression/regression_check.c @@ -31,6 +31,107 @@ void check_regression_file_descriptors_leak_test(void) { } +/** + * @brief Reads lines from a client_t* until a line is reached containing token, and if a line is reached + * that starts with a period, checks if the line starts with two periods. + * + * @param client The client_t* to read lines from. + * @param token A chr_t*. When a line is reached that contains with this token, the function returns. + * @return True if all lines read until token that start with '.' start with '..', false otherwise. + */ +bool_t check_client_dot_stuff(client_t *client, chr_t *token) { + + while (client_read_line(client) > 0 && st_search_cs(&(client->line), NULLER(token), NULL)) { + + if (st_cmp_cs_starts(&(client->line), NULLER(".")) == 0 && + st_cmp_cs_starts(&(client->line), NULLER("..")) != 0) { + + return false; + } + } + return true; +} + +bool_t check_regression_smtp_dot_stuffing_sthread(stringer_t *errmsg) { + + client_t *client = NULL; + server_t *server = NULL; + uint64_t message_num = 0; + stringer_t *top_command = NULL, *mailfrom = "magma@lavabit.com", *rcptto = NULLER("princess@example.com"), + *message = NULLER( + "To: \"Magma\" <magma@lavabit.com>\r\n"\ + "From: \"Princess\" <princess@example.com\r\n"\ + "Subject: Dot Stuffing Regression Test\r\n"\ + "This is an SMTP message whose body has a period at the start of a line\r\n"\ + ". In fact, there are two instances of this in the body of this message\r\n"\ + ". The SMTP client code should stuff an extra period after each of them.\r\n"\ + ".\r\n"); + + // First, send the message with periods at the beginning of lines in the body. + if (!(client = smtp_client_connect(0))) { + st_sprint(errmsg, "Failed to connect to an SMTP server."); + return false; + } + else if (smtp_client_send_helo(client) != 1) { + st_sprint(errmsg, "Failed to return successful state after HELO."); + smtp_client_close(client); + return false; + } + else if (smtp_client_send_mailfrom(client, mailfrom, 0) != 1) { + st_sprint(errmsg, "Failed to return successful state after MAIL FROM."); + smtp_client_close(client); + return false; + } + else if (smtp_client_send_rcptto(client, rcptto) != 1) { + st_sprint(errmsg, "Failed to return successful state after RCPT TO."); + smtp_client_close(client); + return false; + } + else if (smtp_client_send_data(client, message, false) != 1) { + st_sprint(errmsg, "Failed to return successful state after DATA."); + smtp_client_close(client); + return false; + } + + smtp_client_close(client); + + // Next, check if the entire message was sent to the recipient. + if (!(server = servers_get_by_protocol(POP, false)) || !(client = client_connect("localhost", server->network.port)) || + !net_set_timeout(client->sockd, 20, 20) || client_read_line(client) <= 0 || client_status(client) != 1 || + st_cmp_cs_starts(&(client->line), NULLER("+OK"))) { + + st_sprint(errmsg, "Failed to connect to POP server."); + return false; + } + else if (!check_pop_client_auth(client, "princess", "password", errmsg)) { + + client_close(client); + return false; + } + else if (client_print(client, "LIST\r\n") != 6 || (message_num = check_pop_client_read_list(client, errmsg)) == 0 || + client_status(client) != 1) { + + if (st_empty(errmsg)) st_sprint(errmsg, "Failed to return successful state after LIST."); + client_close(client); + return false; + } + else if (!(top_command = st_aprint_opts(MANAGED_T | CONTIGUOUS | STACK, "TOP %lu 0\r\n", message_num)) || + client_print(client, st_char_get(top_command)) != st_length_get(top_command) || client_status(client) != 1) { + + st_sprint(errmsg, "Failed to return successful status after TOP."); + client_close(client); + return false; + } + else if (!check_client_dot_stuff(client, "Date:")) { + + st_sprint(errmsg, "The received message failed to be properly dot stuffed."); + client_close(client); + return false; + } + + return true; +} + START_TEST (check_regression_file_descriptors_leak_m) { log_disable(); @@ -87,11 +188,24 @@ START_TEST (check_regression_file_descriptors_leak_m) { } END_TEST +START_TEST (check_regression_smtp_dot_stuffing_s) { + + bool_t outcome = true; + stringer_t *errmsg = MANAGEDBUF(1024); + + if (status()) outcome = check_regression_smtp_dot_stuffing_sthread(errmsg); + + log_test("REGRESSION / SMTP DOT STUFFING / SINGLE THREADED:", errmsg); + ck_assert_msg(outcome, st_char_get(errmsg)); +} +END_TEST + Suite * suite_check_regression(void) { Suite *s = suite_create("\tRegression"); suite_check_testcase(s, "REGRESSION", "Regression File Descriptors Leak/M", check_regression_file_descriptors_leak_m); + suite_check_testcase(s, "REGRESSION", "Regression SMTP Dot Stuffing/S", check_regression_smtp_dot_stuffing_s); return s; } diff --git a/check/magma/regression/regression_check.h b/check/magma/regression/regression_check.h index 963ab65d..69b85e58 100644 --- a/check/magma/regression/regression_check.h +++ b/check/magma/regression/regression_check.h @@ -9,6 +9,9 @@ /// regression_check.c void check_regression_file_descriptors_leak_test(void); +bool_t check_client_dot_stuff(client_t *client, chr_t *token); +bool_t check_regression_smtp_dot_stuffing_sthread(stringer_t *errmsg); + Suite * suite_check_regression(void); #endif diff --git a/check/magma/servers/pop/pop_check.h b/check/magma/servers/pop/pop_check.h index 003e13aa..a5ea7d8c 100644 --- a/check/magma/servers/pop/pop_check.h +++ b/check/magma/servers/pop/pop_check.h @@ -8,9 +8,10 @@ #define POP_CHECK_H /// pop_check_network.c -bool_t check_pop_client_read_end(client_t *client); uint64_t check_pop_client_read_list(client_t *client, stringer_t *errmsg); +bool_t check_pop_client_read_end(client_t *client, uint64_t* size, chr_t *token); bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t secure); +bool_t check_pop_client_auth(client_t *client, chr_t *user, chr_t *pass, stringer_t *errmsg); /// pop_check.c Suite * suite_check_pop(void); diff --git a/check/magma/servers/pop/pop_check_network.c b/check/magma/servers/pop/pop_check_network.c index e1761709..87cbc7ad 100644 --- a/check/magma/servers/pop/pop_check_network.c +++ b/check/magma/servers/pop/pop_check_network.c @@ -13,12 +13,23 @@ * the number of messages in the inbox. * * @param client The client_t* to read from (which should be connected to a POP server) + * @param size A uint64_t*. If not null, the total size of the lines read will be placed + * at this address. + * @param token If not NULL and size if not NULL, then size will only be incremented after + * reaching a line that begins with token. * @return true if a line containing a single period is found, false if not. */ -bool_t check_pop_client_read_end(client_t *client) { +bool_t check_pop_client_read_end(client_t *client, uint64_t *size, chr_t *token) { + + if (size) *size = 0; + bool_t token_found = false; while (client_read_line(client) > 0) { + if (!st_cmp_cs_eq(&(client->line), NULLER(".\r\n"))) return true; + else if (size && st_cmp_cs_starts(&(client->line), NULLER(token)) == 0) token_found = true; + + if (size && token_found) *size += pl_length_get(client->line); } return false; } @@ -34,16 +45,21 @@ bool_t check_pop_client_read_end(client_t *client) { uint64_t check_pop_client_read_list(client_t *client, stringer_t *errmsg) { placer_t fragment = pl_null(); - uint64_t counter = 0, sequence = 0; + uint64_t counter = 1, sequence = 0; + + client_read_line(client); while (client_read_line(client) > 0) { if (pl_starts_with_char(client->line, '.')) { - return counter-1; + return counter-2; } - else if (tok_get_st(&(client->line), ' ', 0, &fragment) >= 0 && !uint64_conv_pl(fragment, &sequence)) { + else if (tok_get_st(&(client->line), ' ', 0, &fragment) >= 0 && !uint64_conv_pl(fragment, &sequence) == 0) { if (sequence != counter) return 0; } + else { + return 0; + } counter++; } @@ -51,6 +67,26 @@ uint64_t check_pop_client_read_list(client_t *client, stringer_t *errmsg) { return 0; } +bool_t check_pop_client_auth(client_t *client, chr_t *user, chr_t *pass, stringer_t *errmsg) { + + stringer_t *user_command = st_aprint_opts(MANAGED_T | CONTIGUOUS | STACK, "USER %s\r\n", user), + *pass_command = st_aprint_opts(MANAGED_T | CONTIGUOUS | STACK, "PASS %s\r\n", pass); + + if (client_print(client, st_char_get(user_command)) != st_length_get(user_command) || client_read_line(client) <= 0 || + client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))) { + + st_sprint(errmsg, "Failed to return a successful state after USER."); + return false; + } + else if (client_print(client, st_char_get(pass_command)) != st_length_get(pass_command) || client_read_line(client) <= 0 || + client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))) { + + st_sprint(errmsg, "Failed to return a successful state after PASS."); + return false; + } + return true; +} + bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t secure) { uint64_t message_num; @@ -109,7 +145,7 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t } // Test the RETR command. - else if (client_print(client, "RETR 1\r\n") != 8 || !check_pop_client_read_end(client) || + else if (client_print(client, "RETR 1\r\n") != 8 || !check_pop_client_read_end(client, NULL, NULL) || client_status(client) != 1) { st_sprint(errmsg, "Failed to return a successful state after RETR."); @@ -138,7 +174,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t // Test the TOP command. else if (!(top_command = st_aprint_opts(MANAGED_T | CONTIGUOUS | STACK, "TOP %lu 0\r\n", message_num)) || client_print(client, st_char_get(top_command)) != st_length_get(top_command) || client_status(client) != 1 || - client_read_line(client) <= 0 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))|| !check_pop_client_read_end(client)) { + client_read_line(client) <= 0 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))|| + !check_pop_client_read_end(client, NULL, NULL)) { st_sprint(errmsg, "Failed to return a successful state after TOP."); client_close(client); diff --git a/check/magma/servers/smtp/checkers_check.c b/check/magma/servers/smtp/checkers_check.c index 2fb00adf..7b288803 100644 --- a/check/magma/servers/smtp/checkers_check.c +++ b/check/magma/servers/smtp/checkers_check.c @@ -40,6 +40,7 @@ bool_t check_smtp_checkers_greylist_sthread(stringer_t *errmsg) { if (!(addr = con_addr_reversed(&con, addr)) || st_sprint(key, "magma.greylist.%lu.%.*s", prefs.usernum, st_length_int(addr), st_char_get(addr)) <= 0) { + st_sprint(errmsg, "The SMTP greylist check failed to create a valid lookup key."); client_close(client); return false; |