Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/lavabit/magma.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/check
diff options
context:
space:
mode:
authorjpadkins <jacobpadkins@gmail.com>2017-03-29 21:07:37 +0300
committerjpadkins <jacobpadkins@gmail.com>2017-03-29 21:07:37 +0300
commit38c6d9e19542ab16200986836af3b9af5a688057 (patch)
tree4cd39355fdf79d6f3bb25e4e5d31d9b9337f6c59 /check
parent35c5da118a6d93cc0ea66827bea24b494854ef4e (diff)
Added regressing test for dot stuffing
Diffstat (limited to 'check')
-rw-r--r--check/magma/regression/regression_check.c114
-rw-r--r--check/magma/regression/regression_check.h3
-rw-r--r--check/magma/servers/pop/pop_check.h3
-rw-r--r--check/magma/servers/pop/pop_check_network.c49
-rw-r--r--check/magma/servers/smtp/checkers_check.c1
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;