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
diff options
context:
space:
mode:
authorjpadkins <jacobpadkins@gmail.com>2017-03-17 22:32:44 +0300
committerjpadkins <jacobpadkins@gmail.com>2017-03-17 22:32:44 +0300
commit19e125587589d435a711594d9cd3860ae4c72d47 (patch)
treeb9faafb3c36ac74ac7ee49e5a28e8178103fa4bd
parent8e8ddcc2a23abafff04f5b0efdd3a5b42d394ad2 (diff)
parentb6772e9aade6c99ca248363f457ba95eda4a12e6 (diff)
Merge remote-tracking branch 'upstream/feature/tls-error-investigation' into feature/smtp-auth-test
-rw-r--r--check/magma/core/system_check.c5
-rw-r--r--check/magma/servers/imap/imap_check.h4
-rw-r--r--check/magma/servers/imap/imap_check_network.c29
-rw-r--r--check/magma/servers/pop/pop_check.c37
-rw-r--r--check/magma/servers/pop/pop_check.h2
-rw-r--r--check/magma/servers/pop/pop_check_network.c32
-rw-r--r--check/magma/servers/smtp/checkers_check.c87
-rw-r--r--check/magma/servers/smtp/smtp_check.c10
-rw-r--r--check/magma/servers/smtp/smtp_check_network.c5
-rw-r--r--lib/.cproject2
-rw-r--r--src/core/host/host.h21
-rw-r--r--src/core/host/tcp.c103
-rw-r--r--src/core/strings/strings.h1
-rw-r--r--src/network/addresses.c5
-rw-r--r--src/network/clients.c19
-rw-r--r--src/network/connections.c17
-rw-r--r--src/network/network.h25
-rw-r--r--src/network/read.c55
-rw-r--r--src/network/write.c45
-rw-r--r--src/objects/sessions/sessions.c3
-rw-r--r--src/providers/checkers/checkers.h6
-rw-r--r--src/providers/checkers/spf.c9
-rw-r--r--src/providers/cryptography/cryptography.h19
-rw-r--r--src/providers/cryptography/openssl.c3
-rw-r--r--src/providers/cryptography/tls.c302
-rw-r--r--src/providers/dime/common/crypto.c2
-rw-r--r--src/providers/dime/signet/keys.c3
-rw-r--r--src/providers/symbols.c2
-rw-r--r--src/providers/symbols.h2
-rw-r--r--src/servers/imap/fetch.c6
-rw-r--r--src/servers/imap/imap.c2
-rw-r--r--src/servers/imap/parse.c2
-rw-r--r--src/servers/smtp/smtp.c8
33 files changed, 550 insertions, 323 deletions
diff --git a/check/magma/core/system_check.c b/check/magma/core/system_check.c
index 0812cb3a..6d5c4617 100644
--- a/check/magma/core/system_check.c
+++ b/check/magma/core/system_check.c
@@ -27,8 +27,8 @@ bool_t check_system_signames(void) {
bool_t check_system_errnonames(void) {
- chr_t buf[1024];
bool_t result = true;
+ chr_t *buffer1 = MEMORYBUF(1024), *buffer2 = MEMORYBUF(1024);
if (!status()) {
return result;
@@ -37,7 +37,8 @@ bool_t check_system_errnonames(void) {
for (uint64_t i = 1; i < _sys_nerr; i++) {
// Errors 41 and 58 are aliases, and strerror will return unknown instead of the alias name..
- if (st_cmp_ci_starts(NULLER(strerror(i)), PLACER("Unknown", 7)) && st_cmp_cs_eq(NULLER(errno_name(i, buf, 1024)), NULLER(strerror(i)))) {
+ if (st_cmp_ci_starts(NULLER(strerror_r(i, buffer1, 1024)), PLACER("Unknown", 7)) &&
+ st_cmp_cs_eq(NULLER(errno_name(i, buffer2, 1024)), NULLER(strerror_r(i, buffer2, 1024)))) {
result = false;
}
}
diff --git a/check/magma/servers/imap/imap_check.h b/check/magma/servers/imap/imap_check.h
index 402faf6a..8ea8c10f 100644
--- a/check/magma/servers/imap/imap_check.h
+++ b/check/magma/servers/imap/imap_check.h
@@ -8,8 +8,8 @@
#define IMAP_CHECK_H
/// imap_check_network.c
-bool_t check_imap_client_read_lines_to_end(client_t* client, chr_t* token);
-bool_t check_imap_network_basic_sthread(stringer_t* errmsg, uint32_t port);
+bool_t check_imap_client_read_lines_to_end(client_t *client, chr_t *tag);
+bool_t check_imap_network_basic_sthread(stringer_t *errmsg, uint32_t port);
Suite * suite_check_imap(void);
diff --git a/check/magma/servers/imap/imap_check_network.c b/check/magma/servers/imap/imap_check_network.c
index 66781ebd..21192b51 100644
--- a/check/magma/servers/imap/imap_check_network.c
+++ b/check/magma/servers/imap/imap_check_network.c
@@ -1,5 +1,6 @@
+
/**
- * @file /magma/check/magma/servers/smtp/smtp_check_helpers.c
+ * @file /magma/check/magma/servers/imap/imap_check_helpers.c
*
* @brief Functions used to test IMAP connections over a network connection.
*
@@ -8,20 +9,19 @@
#include "magma_check.h"
/**
- * Calls client_read_line on a client until it finds a line matching "<token> OK"
+ * @brief Calls client_read_line on a client until it finds a line matching "<token> OK"
*
* @param client The client to read from (which should be connected to an IMAP server).
* @param token The unique token that identifies the current imap command dialogue.
*
* @return Returns true if client_read_line was successful until the last line was found.
- * specified in num and there was no error. Otherwise returns false.
+ * specified in num and there was no error. Otherwise returns false.
*/
-bool_t check_imap_client_read_lines_to_end(client_t *client, chr_t *token) {
+bool_t check_imap_client_read_lines_to_end(client_t *client, chr_t *tag) {
bool_t outcome = false;
- stringer_t *last_line = st_merge("ss", NULLER(token), NULLER(" OK"));
+ stringer_t *last_line = st_merge("ss", NULLER(tag), NULLER(" OK"));
- // TODO: Add a timeout mechanism to client_read_line and update this function.
while (!outcome && client_read_line(client) > 0) {
if (!st_cmp_cs_starts(&client->line, last_line)) outcome = true;
}
@@ -35,8 +35,8 @@ bool_t check_imap_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
client_t *client = NULL;
// Check the initial response.
- if (!(client = client_connect("localhost", port)) || client_read_line(client) <= 0 || (client->status != 1) ||
- st_cmp_cs_starts(&(client->line), NULLER("* OK"))) {
+ if (!(client = client_connect("localhost", port)) || !net_set_timeout(client->sockd, 20, 20) ||
+ client_read_line(client) <= 0 || (client->status != 1) || st_cmp_cs_starts(&(client->line), NULLER("* OK"))) {
st_sprint(errmsg, "Failed to connect with the IMAP server.");
client_close(client);
@@ -70,10 +70,19 @@ bool_t check_imap_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
return false;
}
- // Test the LOGOUT command.
- else if (client_print(client, "A4 LOGOUT\r\n") <= 0 || !check_imap_client_read_lines_to_end(client, "A4") ||
+ // Test the CLOSE command.
+ else if (client_print(client, "A4 CLOSE\r\n") <= 0 || !check_imap_client_read_lines_to_end(client, "A4") ||
client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("A4 OK"))) {
+ st_sprint(errmsg, "Failed to return a successful state after CLOSE.");
+ client_close(client);
+ return false;
+ }
+
+ // Test the LOGOUT command.
+ else if (client_print(client, "A5 LOGOUT\r\n") <= 0 || !check_imap_client_read_lines_to_end(client, "A5") ||
+ client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("A5 OK"))) {
+
st_sprint(errmsg, "Failed to return a successful state after LOGOUT.");
client_close(client);
return false;
diff --git a/check/magma/servers/pop/pop_check.c b/check/magma/servers/pop/pop_check.c
index d70ff331..613eb2d6 100644
--- a/check/magma/servers/pop/pop_check.c
+++ b/check/magma/servers/pop/pop_check.c
@@ -6,22 +6,42 @@
#include "magma_check.h"
-START_TEST (check_pop_network_basic_s) {
+START_TEST (check_pop_network_basic_tcp_s) {
log_disable();
bool_t outcome = true;
- server_t *server = NULL;
+ server_t *tcp = NULL;
stringer_t *errmsg = MANAGEDBUF(1024);
- if (!(server = servers_get_by_protocol(POP, false))) {
- st_sprint(errmsg, "No POP servers were configured and available for testing.");
+ if (status() && !(tcp = servers_get_by_protocol(POP, false))) {
+ st_sprint(errmsg, "No POP servers were configured to support TCP connections.");
outcome = false;
}
- else if (status()) {
- outcome = check_pop_network_basic_sthread(errmsg, server->network.port);
+ else if (status() && check_pop_network_basic_sthread(errmsg, tcp->network.port, false)) {
+ outcome = false;
+ }
+
+ log_test("POP / NETWORK / BASIC / TCP / SINGLE THREADED:", errmsg);
+ ck_assert_msg(outcome, st_char_get(errmsg));
+}
+END_TEST
+
+START_TEST (check_pop_network_basic_tls_s) {
+
+ log_disable();
+ bool_t outcome = true;
+ server_t *tls = NULL;
+ stringer_t *errmsg = MANAGEDBUF(1024);
+
+ if (status() && !(tls = servers_get_by_protocol(POP, true))) {
+ st_sprint(errmsg, "No POP servers were configured to support TLS connections.");
+ outcome = false;
+ }
+ else if (status() && !check_pop_network_basic_sthread(errmsg, tls->network.port, true)) {
+ outcome = false;
}
- log_test("POP / NETWORK / BASIC / SINGLE THREADED:", errmsg);
+ log_test("POP / NETWORK / BASIC / TLS / SINGLE THREADED:", errmsg);
ck_assert_msg(outcome, st_char_get(errmsg));
}
END_TEST
@@ -30,7 +50,8 @@ Suite * suite_check_pop(void) {
Suite *s = suite_create("\tPOP");
- suite_check_testcase(s, "POP", "POP Network Basic/S", check_pop_network_basic_s);
+ suite_check_testcase(s, "POP", "POP Network Basic / TCP/S", check_pop_network_basic_tcp_s);
+ suite_check_testcase(s, "POP", "POP Network Basic / TLS/S", check_pop_network_basic_tls_s);
return s;
}
diff --git a/check/magma/servers/pop/pop_check.h b/check/magma/servers/pop/pop_check.h
index ba55f524..dbc09d6c 100644
--- a/check/magma/servers/pop/pop_check.h
+++ b/check/magma/servers/pop/pop_check.h
@@ -9,7 +9,7 @@
/// pop_check_network.c
bool_t check_pop_client_read_lines_to_end(client_t *client);
-bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port);
+bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t secure);
/// 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 48c1dc58..16d84fc3 100644
--- a/check/magma/servers/pop/pop_check_network.c
+++ b/check/magma/servers/pop/pop_check_network.c
@@ -16,20 +16,20 @@
*/
bool_t check_pop_client_read_lines_to_end(client_t *client) {
- // TODO: Add a timeout mechanism to client_read_line and update this function.
while (client_read_line(client) > 0) {
if (!st_cmp_cs_eq(&(client->line), NULLER(".\r\n"))) return true;
}
return false;
}
-bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
+bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port, bool_t secure) {
client_t *client = NULL;
// Connect the client.
- if (!(client = client_connect("localhost", port)) || client_read_line(client) <= 0 ||
- client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))) {
+ if (!(client = client_connect("localhost", port)) || (secure && client_secure(client)) ||
+ !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 with the POP server.");
client_close(client);
@@ -37,8 +37,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the USER command.
- if (client_print(client, "USER princess\r\n") <= 0 || client_read_line(client) <= 0 ||
- client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))) {
+ else if (client_print(client, "USER princess\r\n") != 15 || 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.");
client_close(client);
@@ -46,8 +46,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the PASS command.
- if (client_print(client, "PASS password\r\n") <= 0 || client_read_line(client) <= 0 ||
- client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("+OK"))) {
+ else if (client_print(client, "PASS password\r\n") != 15 || 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.");
client_close(client);
@@ -55,8 +55,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the LIST command.
- if (client_print(client, "LIST\r\n") <= 0 || !check_pop_client_read_lines_to_end(client) ||
- client_status(client) != 1) {
+ else if (client_print(client, "LIST\r\n") != 6 || !check_pop_client_read_lines_to_end(client) ||
+ client_status(client) != 1) {
st_sprint(errmsg, "Failed to return a successful state after LIST.");
client_close(client);
@@ -64,8 +64,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the RETR command.
- if (client_print(client, "RETR 1\r\n") <= 0 || !check_pop_client_read_lines_to_end(client) ||
- client_status(client) != 1) {
+ else if (client_print(client, "RETR 1\r\n") != 8 || !check_pop_client_read_lines_to_end(client) ||
+ client_status(client) != 1) {
st_sprint(errmsg, "Failed to return a successful state after RETR.");
client_close(client);
@@ -73,8 +73,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the DELE command.
- if (client_print(client, "DELE 1\r\n") <= 0 || client_read_line(client) <= 0 || client_status(client) != 1 ||
- st_cmp_cs_starts(&(client->line), NULLER("+OK"))) {
+ else if (client_print(client, "DELE 1\r\n") != 8 || 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 DELE.");
client_close(client);
@@ -82,8 +82,8 @@ bool_t check_pop_network_basic_sthread(stringer_t *errmsg, uint32_t port) {
}
// Test the QUIT command.
- if (client_print(client, "QUIT 1\r\n") <= 0 || client_read_line(client) <= 0 || client_status(client) != 1 ||
- st_cmp_cs_starts(&(client->line), NULLER("+OK"))) {
+ else if (client_print(client, "QUIT 1\r\n") <= 0 || 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 QUIT.");
client_close(client);
diff --git a/check/magma/servers/smtp/checkers_check.c b/check/magma/servers/smtp/checkers_check.c
index aa9c3fbc..2fb00adf 100644
--- a/check/magma/servers/smtp/checkers_check.c
+++ b/check/magma/servers/smtp/checkers_check.c
@@ -90,63 +90,62 @@ bool_t check_smtp_checkers_greylist_sthread(stringer_t *errmsg) {
bool_t check_smtp_checkers_regex_sthread(stringer_t *errmsg) {
+ struct re_pattern_buffer regbuff;
+ mm_wipe(&regbuff, sizeof(struct re_pattern_buffer));
chr_t *expressions[] = {
- "85\\.155\\.166\\.44\\.dyn\\.user\\.ono\\.com\\",
- "http\\:\\/\\/www\\.yourlogcabins\\.com\\",
- "82\\.128\\.33\\.161\\]\\ \\(port\\=2680\\ helo\\=User\\)\\ by\\ 4\\.mx\\.freenet\\.de\\ with\\ esmtpa\\ \\(ID\\ danielch",
- "\\[41\\.222\\.192\\.83\\]\\ \\(helo\\=User\\)\\ by\\ server45\\.serverparksteenbergen\\.nl\\ with\\ esmtpa\\ \\(Exim\\",
- "server45\\.serverparksteenbergen\\.nl\\ \\(77\\.243\\.231\\.36",
- "LU7FDZ\\",
- "fresh\\",
- "redbox\\",
- "tiger\\",
- "Vicodin\\ fling\\ medications\\",
- "noreply\\@message\\.myspace\\.com\\",
- "Subscription\\",
- "Unsubscribe\\",
- "http\\:\\/\\/www\\.ameba\\.jp\\/\\",
- "lblanchard\\@ocean\\-institute\\.org\\",
- "email\\.tcm\\.com\\",
- "\\*\\.tcm\\.com\\",
- "tcm\\.com\\",
- "Turner\\ Classic\\",
- "Turner\\ Classic\\",
+ "\\/\\^From\\:\\.\\*\\(gmxmagazin\\\\\\@gmx\\\\\\-gmbh\\\\\\.de\\|mailings\\\\\\@gmx\\\\\\-gmbh\\\\\\.de\\|\\.\\*gmxred\\.\\*\\|elsa",
+ "online836745\\@telkomsa\\.net\\,\\ adbplc78\\@gmail\\.com\\,\\ inside\\.all\\@uol\\.com\\.br\\,\\ a2\\-shark1\\.uol\\",
+ "ashley\\ madison\\ married\\ affair\\ wives\\ pleasurable\\ gal\\ nsa\\ fun\\ dangerous\\ risky\\ scared\\ cost\\",
+ "verify\\ credit\\ free\\ account\\ anonymous\\ info\\ revealing\\ phone\\ picture\\ Whats\\ whats\\ wats\\ wat\\",
+ "2\\.128\\.128\\.1\\]\\ \\(port\\=680\\ helo\\=User\\)\\ by\\ 4\\.mx\\.freenet\\.us\\ with\\ esmtpa\\ \\(ID\\ ch",
+ "\\[41\\.222\\.192\\.83\\]\\ \\(helo\\=User\\)\\ by\\ server45\\.serverpark\\.nl\\ with\\ esmtpa\\ \\(Exim\\",
"LOTTERY\\ WINNER\\ WINNING\\ BLACKHOLED\\ SCAM\\ LUCKY\\ \\/LUCKY\\ WINNER\\/\\ WON\\ ONLINE\\",
"lucky\\+winner\\ CONGRATULATION\\ CONGRATULATIONS\\ DEAL\\ CHEAP\\ WIN\\",
- "Linda\\ Blanchard\\",
- "online836745\\@telkomsa\\.net\\,\\ adbplc78\\@gmail\\.com\\,\\ inside\\.all\\@uol\\.com\\.br\\,\\ a2\\-shark1\\.uol\\",
- "bra\\",
- "\\ an\\",
- "MortgageAssistance411\\",
- "weekend\\ cash\\",
+ "\\\"Woodcraft\\\"\\ \\<Woodcraft\\@woodcraftnews\\.com\\>\\",
+ "server45\\.serverfarm\\.nl\\ \\(17\\.31\\.21\\.69",
+ "Receipt\\ for\\ your\\ PayPal\\ payment\\ to\\",
+ "45\\.155\\.169\\.44\\.dyn\\.user\\.com\\",
+ "Stop\\ paying\\ off\\ the\\ tobacco\\",
+ "noreply\\@message\\.myspace\\.com\\",
+ "http\\:\\/\\/www\\.ameba\\.com\\/\\",
+ "http\\:\\/\\/www\\.mycabin\\.com\\",
+ "Vicodin\\ fling\\ medications\\",
+ "obama\\@tax\\-institute\\.org\\",
+ "Start\\ on\\ a\\ new\\-career\\",
+ "R\\-help\\ Digest\\,\\ Vol\\",
+ "The\\ Pimsleur\\ Approach\\",
"Manner\\ Shultz\\ Group\\",
- "Finance\\ Depat\\.\\",
- "LUMINEERS\\",
+ "Gordon\\,\\ you\\ have\\",
+ "Cambridge\\ SoundWorks\\",
+ "MortgageAssistance411\\",
"Auto\\ Price\\ Finder\\",
+ "Mailer\\'s\\ graphics\\",
+ "Finance\\ Depat\\.\\",
"flight\\ simulator\\",
- "The\\ Pimsleur\\ Approach\\",
- "Start\\ on\\ a\\ new\\-career\\",
+ "email\\.tcm\\.com\\",
+ "Linda\\ Blanchard\\",
"World\\ Marketing\\",
- "Stop\\ paying\\ off\\ the\\ tobacco\\",
- "Mailer\\'s\\ graphics\\",
+ "Turner\\ Classic\\",
+ "\\*\\.tcm\\.com\\",
"Dr\\.Oz\\-watch\\",
- "verify\\ credit\\ free\\ account\\ anonymous\\ info\\ revealing\\ phone\\ picture\\ Whats\\ whats\\ wats\\ wat\\",
"Do\\ you\\ know\\",
- "Gordon\\,\\ you\\ have\\",
- "rich\\",
"Do\\ you\\ know\\",
- "R\\-help\\ Digest\\,\\ Vol\\",
- "\\\"Woodcraft\\\"\\ \\<Woodcraft\\@woodcraftnews\\.com\\>\\",
- "Cambridge\\ SoundWorks\\",
- "IZUALO\\",
- "Receipt\\ for\\ your\\ PayPal\\ payment\\ to\\",
- "ashley\\ madison\\ married\\ affair\\ wives\\ pleasurable\\ gal\\ nsa\\ fun\\ dangerous\\ risky\\ scared\\ cost\\",
+ "weekend\\ cash\\",
+ "Subscription\\",
"eLoan\\ Plus\\",
+ "Unsubscribe\\",
+ "tcm\\.com\\",
+ "LUMINEERS\\",
"cafepress\\",
- "\\/\\^From\\:\\.\\*\\(gmxmagazin\\\\\\@gmx\\\\\\-gmbh\\\\\\.de\\|mailings\\\\\\@gmx\\\\\\-gmbh\\\\\\.de\\|\\.\\*gmxred\\.\\*\\|elsa"
+ "LU7FDZ\\",
+ "redbox\\",
+ "IZUALO\\",
+ "fresh\\",
+ "tiger\\",
+ "\\ an\\",
+ "rich\\",
+ "bra\\"
};
- struct re_pattern_buffer regbuff;
- mm_wipe(&regbuff, sizeof(struct re_pattern_buffer));
for (size_t i = 0; i < (sizeof(expressions)/sizeof(chr_t*)); i++) {
if (regcomp(&regbuff, expressions[i], REG_ICASE) != 0) {
diff --git a/check/magma/servers/smtp/smtp_check.c b/check/magma/servers/smtp/smtp_check.c
index 6d1a1267..cd5b169b 100644
--- a/check/magma/servers/smtp/smtp_check.c
+++ b/check/magma/servers/smtp/smtp_check.c
@@ -59,11 +59,11 @@ START_TEST (check_smtp_checkers_filters_s) {
bool_t outcome = true;
stringer_t *errmsg = MANAGEDBUF(1024);
- if (status()) outcome = check_smtp_checkers_regex_sthread(errmsg);
- if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_DELETE, -2);
- if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_MOVE, 2);
- if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_LABEL, 3);
- if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_MARK_READ, 4);
+ if (status()) outcome = check_smtp_checkers_regex_sthread(errmsg);
+ if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_DELETE, -2);
+ if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_MOVE, 2);
+ if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_LABEL, 3);
+ if (status() && outcome) outcome = check_smtp_checkers_filters_sthread(errmsg, SMTP_FILTER_ACTION_MARK_READ, 4);
log_test("SMTP / CHECKERS / FILTERS / SINGLE THREADED:", errmsg);
ck_assert_msg(outcome, st_char_get(errmsg));
diff --git a/check/magma/servers/smtp/smtp_check_network.c b/check/magma/servers/smtp/smtp_check_network.c
index 4c6b9b42..30ecb66a 100644
--- a/check/magma/servers/smtp/smtp_check_network.c
+++ b/check/magma/servers/smtp/smtp_check_network.c
@@ -18,7 +18,6 @@
*/
bool_t check_smtp_client_read_line_to_end(client_t *client) {
- // TODO: Add a timeout mechanism to client_read_line and update this function.
while (client_read_line(client) > 0) {
if (pl_char_get(client->line)[3] == ' ') return true;
}
@@ -31,8 +30,8 @@ bool_t check_smtp_network_simple_sthread(stringer_t *errmsg, uint32_t port) {
client_t *client = NULL;
// Test the connect banner.
- if (!(client = client_connect("localhost", port)) || client_read_line(client) <= 0 ||
- client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("220")) ||
+ if (!(client = client_connect("localhost", port)) || !net_set_timeout(client->sockd, 20, 20) ||
+ client_read_line(client) <= 0 || client_status(client) != 1 || st_cmp_cs_starts(&(client->line), NULLER("220")) ||
!st_search_cs(&(client->line), NULLER(" ESMTP "), &location)) {
st_sprint(errmsg, "Failed to connect with the SMTP server.");
diff --git a/lib/.cproject b/lib/.cproject
index 4ce0714b..faf7ff38 100644
--- a/lib/.cproject
+++ b/lib/.cproject
@@ -64,7 +64,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
- <entry excluding="sources|check/|archives/|logs/|objects/|patches/|sources/clamav/libclamav/c++/llvm/|sources/mysql/vio/viosocket.c|sources/mysql/libmysql_r/viosocket.c|sources/clamav/win32/|sources/mysql/include/config-win.h|sources/mysql/include/config-netware.h|local/include/spf2/|sources/spf2/" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+ <entry excluding="check/|archives/|logs/|objects/|patches/|sources/clamav/libclamav/c++/llvm/|sources/mysql/vio/viosocket.c|sources/mysql/libmysql_r/viosocket.c|sources/clamav/win32/|sources/mysql/include/config-win.h|sources/mysql/include/config-netware.h|local/include/spf2/|sources/spf2/" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
diff --git a/src/core/host/host.h b/src/core/host/host.h
index 1a74b8bb..d1e296d7 100644
--- a/src/core/host/host.h
+++ b/src/core/host/host.h
@@ -52,6 +52,20 @@
#define MAGMA_PROC_PATH "/proc"
+typedef struct {
+ sa_family_t family;
+ union {
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ void *ip;
+ };
+} ip_t;
+
+typedef struct {
+ uint32_t mask;
+ ip_t address;
+} subnet_t;
+
// The spool_start function uses a for loop to validate the spool directory tree. If additional spool locations are enumerated, make sure that function is updated.
enum {
MAGMA_SPOOL_BASE = 0,
@@ -98,7 +112,6 @@ const chr_t * color_yellow_intense(void);
const chr_t * color_yellow_intense_bold(void);
const chr_t * color_yellow_underline(void);
-
/// files.c
stringer_t * file_load(char *name);
int_t file_read(char *name, stringer_t *output);
@@ -107,6 +120,12 @@ bool_t file_accessible(const chr_t *path);
bool_t file_readwritable(const chr_t *path);
bool_t file_world_accessible(const chr_t *path);
+/// tcp.c
+ip_t * tcp_addr_ip(int sockd, ip_t *output);
+stringer_t * tcp_addr_st(int sockd, stringer_t *output);
+int_t tcp_error(int error);
+int_t tcp_status(int sockd);
+
/// host.c
stringer_t * host_platform(stringer_t *output);
stringer_t * host_version(stringer_t *output);
diff --git a/src/core/host/tcp.c b/src/core/host/tcp.c
new file mode 100644
index 00000000..ee9e6345
--- /dev/null
+++ b/src/core/host/tcp.c
@@ -0,0 +1,103 @@
+
+/**
+ * @file /magma/src/core/host/tcp.c
+ *
+ * @brief Generic fuctions for interaction with TCP/IP socket connections.
+ *
+ */
+
+#include "magma.h"
+
+/**
+ * @brief Determine whether the error is a permanent/fatal failure, or a transient error.
+ * @return return 0 for errors we should ignore, and -1 for permanent/fatal failures.
+ */
+int_t tcp_error(int error) {
+
+ int_t result = 0;
+
+ // These error numbers indicate a network connection issue.
+ if (error == EPIPE || error == ENETDOWN || error == ENETUNREACH || error == ENETUNREACH ||
+ error == ENETRESET || error == ECONNABORTED || error == ECONNRESET || error == ENOTCONN ||
+ error == ESHUTDOWN || error == ETIMEDOUT) {
+ result = -1;
+ }
+
+ // Otherwise if recv returns a negative number, we log the result, while assuming the connection is still valid. Note
+ // that on some platforms EWOULDBLOCK and EAGAIN are technically identical, but we explicitly check for both so
+ // logic remains compatible with systems where they differ.
+ else if (result < 0 && (error != EWOULDBLOCK || error != EAGAIN || error != EINTR)) {
+ log_pedantic("Ambiguous TCP error code. { errno = %i / error = %s }",
+ error, strerror_r(error, MEMORYBUF(1024), 1024));
+ }
+
+ return result;
+}
+
+/**
+ * @brief Determine whether the socket connection provided by sockd is still valid.
+ * @param sockd The socket connection being checked.
+ * @return return 0 for valid connections
+ */
+int_t tcp_status(int sockd) {
+
+ struct stat info;
+ int result = 0, holder = 0, error = 0;
+
+ errno = 0;
+
+ if (sockd < 0 || fstat(sockd, &info) || !S_ISSOCK(info.st_mode)) {
+ result = -1;
+ }
+
+ // In theory the PEEK flag will prevent this call from altering the socket buffer state, while the NOSIGNAL flag
+ // should cause it to return EPIPE if the connection is no longer valid.
+ else if ((holder = recv(sockd, MANAGEDBUF(64), 64, MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL)) <= 0) {
+
+ // Duplicate the errno so the log pedantic statement below doesn't accidently overwrite it.
+ error = errno;
+
+ // Determine whether the error number is fatal.
+ result = tcp_error(error);
+ }
+
+ log_pedantic("tcp status = %i / errno = %i", result, error);
+
+ return result;
+}
+
+ip_t * tcp_addr_ip(int sockd, ip_t *output) {
+
+ ip_t *result = NULL;
+ socklen_t len = sizeof(struct sockaddr_in6);
+ struct sockaddr *address = MEMORYBUF(sizeof(struct sockaddr_in6));
+
+ // Extract the socket structure.
+ if (getpeername(sockd, address, &len)) {
+ return NULL;
+ }
+
+ // Allocate memory for the result, if necessary.
+ else if (!(result = output) && !(result = mm_alloc(sizeof(ip_t)))) {
+ return NULL;
+ }
+
+ // Classify and copy to the IP information.
+ else if (len == sizeof(struct sockaddr_in6) && ((struct sockaddr_in6 *)address)->sin6_family == AF_INET6) {
+ mm_copy(&(result->ip6), &(((struct sockaddr_in6 *)address)->sin6_addr), sizeof(struct in6_addr));
+ result->family = AF_INET6;
+ }
+ else if (len == sizeof(struct sockaddr_in) && ((struct sockaddr_in *)address)->sin_family == AF_INET) {
+ mm_copy(&(result->ip4), &(((struct sockaddr_in *)address)->sin_addr), sizeof(struct in_addr));
+ result->family = AF_INET;
+ }
+
+ return result;
+}
+
+stringer_t * tcp_addr_st(int sockd, stringer_t *output) {
+
+ ip_t ip;
+
+ return ip_presentation(tcp_addr_ip(sockd, &ip), output);
+}
diff --git a/src/core/strings/strings.h b/src/core/strings/strings.h
index bf36de5f..3e0418bb 100644
--- a/src/core/strings/strings.h
+++ b/src/core/strings/strings.h
@@ -124,7 +124,6 @@ uchr_t * st_uchar_get(stringer_t *s);
void st_wipe(stringer_t *s);
stringer_t * st_set(stringer_t *s, uint8_t set, size_t len);
-
// Creation/Destruction
void st_free(stringer_t *s);
//void st_cleanup(stringer_t *s);
diff --git a/src/network/addresses.c b/src/network/addresses.c
index a3909d6c..1fec8454 100644
--- a/src/network/addresses.c
+++ b/src/network/addresses.c
@@ -208,6 +208,7 @@ stringer_t * ip_presentation(ip_t *address, stringer_t *output) {
if (!output || st_valid_tracked(opts)) {
st_length_set(result, ns_length_get(st_char_get(result)));
}
+
return result;
}
@@ -393,7 +394,7 @@ ip_t * con_addr(connection_t *con, ip_t *output) {
socklen_t len = sizeof(struct sockaddr_in6);
if (!(result = output) && !(result = mm_alloc(sizeof(ip_t)))) {
- log_pedantic("The output buffer memory allocation request failed. {requested = %zu}", sizeof(ip_t));
+ log_pedantic("The output buffer memory allocation request failed. { requested = %zu }", sizeof(ip_t));
return NULL;
}
@@ -407,7 +408,7 @@ ip_t * con_addr(connection_t *con, ip_t *output) {
return NULL;
}
- // Classify and copy to the result.
+ // Classify and copy to the IP information.
else if (len == sizeof(struct sockaddr_in6) && ((struct sockaddr_in6 *)address)->sin6_family == AF_INET6) {
mm_copy(&(result->ip6), &(((struct sockaddr_in6 *)address)->sin6_addr), sizeof(struct in6_addr));
result->family = AF_INET6;
diff --git a/src/network/clients.c b/src/network/clients.c
index 090e5944..bb01ba59 100644
--- a/src/network/clients.c
+++ b/src/network/clients.c
@@ -7,11 +7,10 @@
#include "magma.h"
-
/**
* @brief Get the status of a network client.
* @param client a pointer to the network client object to be queried.
- * @return -1 on error state, 0 for unknown status, or 1 if connected.
+ * @return -1 on network errors, 0 for an unknown status, 1 for connected, and 2 for a graceful shutdown.
*/
int_t client_status(client_t *client) {
@@ -21,11 +20,25 @@ int_t client_status(client_t *client) {
result = client->status;
}
+
+ // If the status is positive, and tls_status returns 0, we use the existing status state.
+ if (client && client->tls && client->status >= 0 && !tls_status(client->tls)) {
+ result = client->status;
+ }
+ // If the status is positive, and tcp_status returns 0, we use the existing status state.
+ else if (client && client->sockd != -1 && client->status >= 0 && !tcp_status(client->sockd)) {
+ result = client->status;
+ }
+ // We return -1 if the status is already negative, or connection is otherwise invalid.
+ else {
+ result = client->status = -1;
+ }
+
return result;
}
/**
- * @brief Establish an ssl connection with a network client instance.
+ * @brief Establish an TLS connection with a network client instance.
* @param client a pointer to the network client object to have its transport security upgraded.
* @return -1 on failure or 0 on success.
*/
diff --git a/src/network/connections.c b/src/network/connections.c
index af79933d..51f4853a 100644
--- a/src/network/connections.c
+++ b/src/network/connections.c
@@ -27,15 +27,24 @@ int_t con_secure(connection_t *con) {
/**
* @brief Return the status of a specified connection.
* @param con the input client connection.
- * @return -1 on error, 0 for unknown status, 1 for connected, or 2 if the socket has been shutting down.
+ * @return -1 on network errors, 0 for an unknown status, 1 for connected, and 2 for a graceful shutdown.
*/
int_t con_status(connection_t *con) {
int_t result = -1;
- if (con && con->network.sockd != -1) {
+ // If the status is positive, and tls_status returns 0, we use the existing status state.
+ if (con && con->network.tls && con->network.status >= 0 && !tls_status(con->network.tls)) {
result = con->network.status;
}
+ // If the status is positive, and tcp_status returns 0, we use the existing status state.
+ else if (con && con->network.sockd >= -1 && con->network.status >= 0 && !tcp_status(con->network.sockd)) {
+ result = con->network.status;
+ }
+ // We return -1 if the status is already negative, or connection is otherwise invalid.
+ else {
+ result = con->network.status = -1;
+ }
return result;
}
@@ -120,6 +129,7 @@ void con_destroy(connection_t *con) {
}
st_cleanup(con->network.buffer);
+ mm_cleanup(con->network.reverse.ip);
st_cleanup(con->network.reverse.domain);
mutex_destroy(&(con->lock));
mm_free(con);
@@ -201,8 +211,9 @@ connection_t * con_init(int cond, server_t *server) {
return NULL;
}
- con->network.sockd = cond;
con->server = server;
+ con->network.sockd = cond;
+ con->network.reverse.ip = tcp_addr_ip(cond, NULL);
con_increment_refs(con);
return con;
diff --git a/src/network/network.h b/src/network/network.h
index 54e276d3..73d3ceed 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -5,29 +5,7 @@
* @brief The types and functions for abstracting access to network functionality.
*/
-#if defined(GET_IP_T_DEFINITION) || !defined(MAGMA_NETWORK_H)
- #ifndef GOT_IP_T_DEFINITION
- typedef struct {
- sa_family_t family;
- union {
- struct in_addr ip4;
- struct in6_addr ip6;
- void *ip;
- };
- } ip_t;
-
- typedef struct {
- uint32_t mask;
- ip_t address;
- } subnet_t;
- #define GOT_IP_T_DEFINITION
- #endif
-#endif
-
-
-#ifdef GET_IP_T_DEFINITION
-#undef GET_IP_T_DEFINITION
-#elif !defined(MAGMA_NETWORK_H)
+#ifndef MAGMA_NETWORK_H
#define MAGMA_NETWORK_H
#include "meta.h"
@@ -85,6 +63,7 @@ typedef struct {
stringer_t *buffer; /* The connection buffer. */
struct {
+ ip_t *ip;
int_t status;
stringer_t *domain;
} reverse;
diff --git a/src/network/read.c b/src/network/read.c
index 223e18ec..f259eb62 100644
--- a/src/network/read.c
+++ b/src/network/read.c
@@ -22,10 +22,11 @@
*/
int64_t con_read_line(connection_t *con, bool_t block) {
- ssize_t bytes;
+ int_t counter = 0;
+ ssize_t bytes = 0;
bool_t line = false;
- if (!con || con->network.sockd == -1) {
+ if (!con || con->network.sockd == -1 || con_status(con) < 0) {
if (con) con->network.status = -1;
return -1;
}
@@ -66,30 +67,23 @@ int64_t con_read_line(connection_t *con, bool_t block) {
if (con->network.tls) {
// If bytes is zero or below and the library isn't asking for another read, then an error occurred.
- bytes = ssl_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
+ bytes = tls_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), block);
- if (bytes <= 0 && bytes != SSL_ERROR_WANT_READ) {
+ if (bytes < 0) {
con->network.status = -1;
return -1;
}
- else if (bytes <= 0) {
- return 0;
- }
}
else {
bytes = recv(con->network.sockd, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), (block ? 0 : MSG_DONTWAIT));
// Check for errors on non-SSL reads in the traditional way.
- if (bytes <= 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
+ if (bytes <= 0 && tcp_status(con->network.sockd)) {
con->network.status = -1;
return -1;
}
- else if (!bytes) {
- con->network.status = 2;
- return -2;
- }
}
@@ -102,7 +96,7 @@ int64_t con_read_line(connection_t *con, bool_t block) {
line = true;
}
- } while (!line && st_length_get(con->network.buffer) != st_avail_get(con->network.buffer));
+ } while (!line && block && counter++ < 128 && st_length_get(con->network.buffer) != st_avail_get(con->network.buffer) && status());
if (st_length_get(con->network.buffer) > 0) {
con->network.status = 1;
@@ -120,10 +114,11 @@ int64_t con_read_line(connection_t *con, bool_t block) {
*/
int64_t con_read(connection_t *con) {
- ssize_t bytes;
- bool_t blocking;
+ int_t counter = 0;
+ ssize_t bytes = 0;
+ bool_t blocking = true;
- if (!con || con->network.sockd == -1) {
+ if (!con || con->network.sockd == -1 || con_status(con) < 0) {
if (con) con->network.status = -1;
return -1;
}
@@ -147,7 +142,9 @@ int64_t con_read(connection_t *con) {
// Clear the line buffer.
con->network.line = pl_null();
- return st_length_get(con->network.buffer);
+ if (st_length_get(con->network.buffer)) {
+ return st_length_get(con->network.buffer);
+ }
}
// Otherwise reset the buffer and line lengths to zero.
@@ -163,10 +160,10 @@ int64_t con_read(connection_t *con) {
// Read bytes off the network. If data is already in the buffer this should be a non-blocking read operation so we can
// return the already buffered data without delay.
if (con->network.tls) {
- bytes = ssl_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
- st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), blocking);
+ bytes = tls_read(con->network.tls, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
+ st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), true);
- if (!bytes && tls_status(con->network.tls)) {
+ if (bytes < 0) {
con->network.status = -1;
return -1;
}
@@ -175,20 +172,17 @@ int64_t con_read(connection_t *con) {
bytes = recv(con->network.sockd, st_char_get(con->network.buffer) + st_length_get(con->network.buffer),
st_avail_get(con->network.buffer) - st_length_get(con->network.buffer), blocking ? 0 : MSG_DONTWAIT);
- if (bytes < 0 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
- con->network.status = -1;
- return -1;
- }
+ if (bytes <= 0 && tcp_status(con->network.sockd)) {
+ con->network.status = -1;
+ return -1;
+ }
}
if (bytes > 0) {
st_length_set(con->network.buffer, st_length_get(con->network.buffer) + bytes);
- // Or break out of the loop because we've been shutdown.
- } else if (!bytes) {
- break;
}
- } while (blocking && !st_length_get(con->network.buffer));
+ } while (blocking && counter++ < 128 && !st_length_get(con->network.buffer) && status());
// If there is data in the buffer process it. Otherwise if the buffer is empty and the connection appears to be closed
// (as indicated by a return value of 0), then return -1 to let the caller know the connection is dead.
@@ -203,7 +197,6 @@ int64_t con_read(connection_t *con) {
return st_length_get(con->network.buffer);
}
-// LOW: If the buffer already contains a complete line and the socket status indicates a connection we should still perform a non-blocking read.
/**
* @brief Read a line of input from a network client session.
*
@@ -247,7 +240,7 @@ int64_t client_read_line(client_t *client) {
// Read bytes off the network. Skip past any existing data in the buffer.
if (client->tls) {
- bytes = ssl_read(client->tls, st_char_get(client->buffer) + st_length_get(client->buffer), st_avail_get(client->buffer) - st_length_get(client->buffer), true);
+ bytes = tls_read(client->tls, st_char_get(client->buffer) + st_length_get(client->buffer), st_avail_get(client->buffer) - st_length_get(client->buffer), true);
sslerr = SSL_get_error_d(client->tls, bytes);
}
else {
@@ -331,7 +324,7 @@ int64_t client_read(client_t *client) {
// Read bytes off the network. If data is already in the buffer this should be a non-blocking read operation so we can
// return the already buffered data without delay.
if (client->tls) {
- bytes = ssl_read(client->tls, st_char_get(client->buffer) + st_length_get(client->buffer), st_avail_get(client->buffer) - st_length_get(client->buffer), blocking);
+ bytes = tls_read(client->tls, st_char_get(client->buffer) + st_length_get(client->buffer), st_avail_get(client->buffer) - st_length_get(client->buffer), blocking);
sslerr = SSL_get_error_d(client->tls, bytes);
}
else {
diff --git a/src/network/write.c b/src/network/write.c
index c14e02a4..7964df04 100644
--- a/src/network/write.c
+++ b/src/network/write.c
@@ -22,11 +22,10 @@
*/
int64_t con_write_bl(connection_t *con, char *block, size_t length) {
+ int_t counter = 0;
ssize_t written, position = 0;
- int sslerr = -1;
- if (!con || con->network.sockd == -1) {
- if (con) con->network.status = -1;
+ if (!con || con->network.sockd == -1 || con_status(con) < 0) {
return -1;
}
else if (!block || !length) {
@@ -34,54 +33,36 @@ int64_t con_write_bl(connection_t *con, char *block, size_t length) {
return 0;
}
- // Loop until bytes have been written to the socket.
+ // Loop until all of the bytes have been sent to the client.
do {
if (con->network.tls) {
- written = ssl_write(con->network.tls, block + position, length);
- sslerr = SSL_get_error_d(con->network.tls, written);
- }
- else {
- written = send(con->network.sockd, block + position, length, 0);
- }
- // Check for errors on SSL writes.
- if (con->network.tls) {
+ written = tls_write(con->network.tls, block + position, length);
- // If 0 bytes were written, and it wasn't related to a shutdown, or if < 0 was returned and there was no more data waiting to be written, it's an error.
- if ((!written && sslerr != SSL_ERROR_NONE && sslerr != SSL_ERROR_ZERO_RETURN) || ((written < 0) && sslerr != SSL_ERROR_WANT_WRITE)) {
+ // Check for errors on SSL writes.
+ if (written < 0) {
con->network.status = -1;
return -1;
}
- else if (!written) {
- con->network.status = 2;
- return -2;
- }
- // Check for errors on non-SSL writes in the traditional way.
}
- else if (written < 0) {
+ else {
+ written = send(con->network.sockd, block + position, length, 0);
- if (errno == ECONNRESET) {
- con->network.status = 2;
- return -2;
- }
- else if (errno != EAGAIN) {
+ // Check for errors on non-SSL writes in the traditional way.
+ if (written <= 0 && tcp_status(con->network.sockd)) {
con->network.status = -1;
return -1;
}
-
}
+ // Handle progress by advancing our position tracker.
if (written > 0) {
length -= written;
position += written;
}
- } while (length);
-
-#ifdef MAGMA_PEDANTIC
- if (written < 0) log_pedantic("write = %li {%s}", written, strerror_r(errno, bufptr, buflen));
-#endif
+ } while (length && counter++ < 128 && status());
if (written > 0) {
con->network.status = 1;
@@ -211,7 +192,7 @@ int64_t client_write(client_t *client, stringer_t *s) {
do {
if (client->tls) {
- written = ssl_write(client->tls, block + position, length);
+ written = tls_write(client->tls, block + position, length);
sslerr = SSL_get_error_d(client->tls, written);
}
else {
diff --git a/src/objects/sessions/sessions.c b/src/objects/sessions/sessions.c
index 974ba14f..488366a3 100644
--- a/src/objects/sessions/sessions.c
+++ b/src/objects/sessions/sessions.c
@@ -385,7 +385,8 @@ session_t *sess_create(connection_t *con, stringer_t *path, stringer_t *applicat
log_pedantic("Unable to initialize reference lock for new user session.");
mm_free(output);
return NULL;
- } else if (!(output->compositions = inx_alloc(M_INX_LINKED, &sess_release_composition))) {
+ }
+ else if (!(output->compositions = inx_alloc(M_INX_LINKED, &sess_release_composition))) {
log_pedantic("Unable to allocate space for user session's compositions.");
mm_free(output);
return NULL;
diff --git a/src/providers/checkers/checkers.h b/src/providers/checkers/checkers.h
index 70d2c279..4efe1976 100644
--- a/src/providers/checkers/checkers.h
+++ b/src/providers/checkers/checkers.h
@@ -8,9 +8,6 @@
#ifndef MAGMA_PROVIDERS_CHECKERS_H
#define MAGMA_PROVIDERS_CHECKERS_H
-#define GET_IP_T_DEFINITION
-#include "network/network.h"
-
#define IP_RANDOMIZER_POOL 1024
#define IP_RANDOMIZER_PUSH_MIN 4
@@ -32,7 +29,6 @@ enum {
FOREIGN = 1
};
-
/// clamav.c
bool_t lib_load_clamav(void);
bool_t virus_start(void);
@@ -67,7 +63,7 @@ chr_t * lib_version_dspam(void);
bool_t lib_load_spf(void);
const chr_t * lib_version_spf(void);
bool_t spf_start(void);
-int_t spf_check(ip_t *ip, stringer_t *helo, stringer_t *mailfrom);
+int_t spf_check(void *ip, stringer_t *helo, stringer_t *mailfrom);
void spf_stop(void);
#endif
diff --git a/src/providers/checkers/spf.c b/src/providers/checkers/spf.c
index 5e798ddb..4e4875cd 100644
--- a/src/providers/checkers/spf.c
+++ b/src/providers/checkers/spf.c
@@ -109,10 +109,11 @@ void spf_stop(void) {
* TODO: We really need to change these return values to account for 0
* @return -2 on spf check fail, -1 on other failure, and 1 on spf pass.
*/
-int_t spf_check(ip_t *ip, stringer_t *helo, stringer_t *mailfrom) {
+int_t spf_check(void *ip, stringer_t *helo, stringer_t *mailfrom) {
uint32_t item;
placer_t domain;
+ ip_t *addr = ip;
#ifdef MAGMA_SPF_DEBUG
SPF_reason_t reason;
#endif
@@ -144,9 +145,9 @@ int_t spf_check(ip_t *ip, stringer_t *helo, stringer_t *mailfrom) {
}
// Set the IP address for the request.
- else if ((ip->family == AF_INET && (error = SPF_request_set_ipv4_d(spf_request, ip->ip4)) != SPF_E_SUCCESS) ||
- (ip->family == AF_INET6 && (error = SPF_request_set_ipv6_d(spf_request, ip->ip6)) != SPF_E_SUCCESS) ||
- (ip->family != AF_INET && ip->family != AF_INET6)) {
+ else if ((addr->family == AF_INET && (error = SPF_request_set_ipv4_d(spf_request, addr->ip4)) != SPF_E_SUCCESS) ||
+ (addr->family == AF_INET6 && (error = SPF_request_set_ipv6_d(spf_request, addr->ip6)) != SPF_E_SUCCESS) ||
+ (addr->family != AF_INET && addr->family != AF_INET6)) {
SPF_request_free_d(spf_request);
pool_release(spf_pool, item);
log_pedantic("SPF context configuration error. { error = %s }", SPF_strerror_d(error));
diff --git a/src/providers/cryptography/cryptography.h b/src/providers/cryptography/cryptography.h
index b25b270c..aaae679a 100644
--- a/src/providers/cryptography/cryptography.h
+++ b/src/providers/cryptography/cryptography.h
@@ -86,6 +86,13 @@ typedef void * cipher_t;
typedef char * cryptex_t;
typedef stringer_t scramble_t;
+// Allows the inclusion of this PRIME header without having to include the OpenSSL headers.
+#ifdef HEADER_OPENSSL_TYPES_H
+typedef SSL TLS;
+#else
+typedef void TLS;
+#endif
+
/// ciphers.c
cipher_t * cipher_id(int_t id);
cipher_t * cipher_name(stringer_t *name);
@@ -167,15 +174,15 @@ void ssl_thread_stop(void);
bool_t ssl_verify_privkey(const char *keyfile);
/// tls.c
-int ssl_print(SSL *ssl, const char *format, va_list args);
-int ssl_read(SSL *ssl, void *buffer, int length, bool_t block);
+int tls_print(TLS *tls, const char *format, va_list args);
+int tls_read(TLS *tls, void *buffer, int length, bool_t block);
bool_t ssl_server_create(void *server, uint_t security_level);
void ssl_server_destroy(void *server);
-int ssl_write(SSL *ssl, const void *buffer, int length);
+int tls_write(TLS *tls, const void *buffer, int length);
void * tls_client_alloc(int_t sockd);
-void tls_free(SSL *ssl);
-SSL * tls_server_alloc(void *server, int sockd, int flags);
-int tls_status(SSL *ssl);
+void tls_free(TLS *tls);
+TLS * tls_server_alloc(void *server, int sockd, int flags);
+int tls_status(TLS *tls);
/// random.c
bool_t rand_start(void);
diff --git a/src/providers/cryptography/openssl.c b/src/providers/cryptography/openssl.c
index 9e57e939..4b6c1ee8 100644
--- a/src/providers/cryptography/openssl.c
+++ b/src/providers/cryptography/openssl.c
@@ -81,7 +81,8 @@ bool_t lib_load_openssl(void) {
M_BIND(ERR_put_error), M_BIND(EVP_aes_256_gcm), M_BIND(EC_KEY_get_conv_form), M_BIND(EC_KEY_set_conv_form), M_BIND(BN_bn2mpi),
M_BIND(BN_mpi2bn), M_BIND(BN_bn2dec), M_BIND(EC_POINT_mul), M_BIND(BN_CTX_new), M_BIND(BN_CTX_start), M_BIND(BN_CTX_free),
M_BIND(EC_POINT_cmp), M_BIND(BN_cmp), M_BIND(ED25519_keypair), M_BIND(ED25519_sign), M_BIND(ED25519_verify), M_BIND(ED25519_keypair_from_seed),
- M_BIND(CRYPTO_set_mem_functions), M_BIND(CRYPTO_set_locked_mem_functions), M_BIND(DH_check)
+ M_BIND(CRYPTO_set_mem_functions), M_BIND(CRYPTO_set_locked_mem_functions), M_BIND(DH_check), M_BIND(SSL_get_read_ahead),
+ M_BIND(SSL_set_read_ahead), M_BIND(SSL_peek)
};
if (!lib_symbols(sizeof(openssl) / sizeof(symbol_t), openssl)) {
diff --git a/src/providers/cryptography/tls.c b/src/providers/cryptography/tls.c
index 1549ef00..fcc3e27c 100644
--- a/src/providers/cryptography/tls.c
+++ b/src/providers/cryptography/tls.c
@@ -8,13 +8,13 @@
#include "magma.h"
/**
- * @brief Setup an SSL CTX for a server.
+ * @brief Setup an TLS CTX for a server.
*
* @note The server is passed as a void pointer because the provider layer doesn't comprehend protocol specific
* server instances.
*
- * @param server_t the SSL context will be assigned to the provided server context.
- * @param security_level an integer which will be used to control how the SSL context is configured:
+ * @param server_t the TLS context will be assigned to the provided server context.
+ * @param security_level an integer which will be used to control how the TLS context is configured:
* 0 = accept any type of SSL or TLS protocol version, and offer broad cipher support.
* 1 = require TLSv1 and above, refuse SSLv2 and SSLv3 connections, use any reasonably secure cipher.
* (reccomended) 2 = require TLSv1 and above, refuse SSLv2 and SSLv3 connections, only use ciphers which provide forward secrecy.
@@ -83,6 +83,10 @@ bool_t ssl_server_create(void *server, uint_t security_level) {
log_critical("Could not enable the automatic, default selection of the strongest curve.");
return false;
}
+ else if (SSL_CTX_ctrl_d(local->tls.context, SSL_CTRL_MODE, SSL_MODE_AUTO_RETRY, NULL) != SSL_MODE_AUTO_RETRY) {
+ log_critical("Could not enable automatic retry for read and write operations.");
+ return false;
+ }
// High security connections get 4096 bit prime when generating a DH session key.
else if (magma.iface.cryptography.dhparams_rotate && magma.iface.cryptography.dhparams_large_keys) {
@@ -107,7 +111,7 @@ bool_t ssl_server_create(void *server, uint_t security_level) {
}
/**
- * @brief Destroy an SSL context associated with a server.
+ * @brief Destroy an TLS context associated with a server.
* @param server the server to be deactivated.
* @return This function returns no value.
*/
@@ -127,14 +131,14 @@ void ssl_server_destroy(void *server) {
}
/**
- * @brief Create an SSL session for a file descriptor, and accept the client TLS/SSL handshake.
+ * @brief Create a TLS session for a file descriptor, and accept the client TLS/SSL handshake.
* @see SSL_accept()
* @see BIO_new_socket()
* @param server a server object which contains the underlying SSL context.
* @param sockd the file descriptor of the TCP connection to be made SSL-ready.
* @param flags passed to BIO_new_socket(), determines whether the socket is shut down when the BIO is freed.
*/
-SSL * tls_server_alloc(void *server, int sockd, int flags) {
+TLS * tls_server_alloc(void *server, int sockd, int flags) {
SSL *tls;
BIO *bio;
@@ -144,18 +148,20 @@ SSL * tls_server_alloc(void *server, int sockd, int flags) {
#ifdef MAGMA_PEDANTIC
if (!local) {
log_pedantic("Passed a NULL server pointer.");
- } else if (!local->tls.context) {
+ }
+ else if (!local->tls.context) {
log_pedantic("Passed a NULL SSL context pointer.");
}
else if (sockd < 0) {
- log_pedantic("Passed an invalid socket. {sockd = %i}", sockd);
+ log_pedantic("Passed an invalid socket. { sockd = %i }", sockd);
}
#endif
if (!local || !local->tls.context || sockd < 0) {
return NULL;
- } else if (!(tls = SSL_new_d(local->tls.context)) || !(bio = BIO_new_socket_d(sockd, flags))) {
- log_pedantic("SSL/BIO allocation error. {error = %s}", ssl_error_string(MEMORYBUF(256), 256));
+ }
+ else if (!(tls = SSL_new_d(local->tls.context)) || !(bio = BIO_new_socket_d(sockd, flags))) {
+ log_pedantic("TLS/BIO allocation error. { error = %s }", ssl_error_string(MEMORYBUF(256), 256));
if (tls) {
SSL_free_d(tls);
@@ -167,7 +173,7 @@ SSL * tls_server_alloc(void *server, int sockd, int flags) {
SSL_set_bio_d(tls, bio, bio);
if ((result = SSL_accept_d(tls)) != 1) {
- log_pedantic("SSL accept error. { accept = %i / error = %s }", result, ssl_error_string(MEMORYBUF(256), 256));
+ log_pedantic("TLS accept error. { accept = %i / error = %s }", result, ssl_error_string(MEMORYBUF(256), 256));
SSL_free_d(tls);
return NULL;
}
@@ -176,7 +182,7 @@ SSL * tls_server_alloc(void *server, int sockd, int flags) {
}
/**
- * @brief Establish an SSL client wrapper around a socket descriptor.
+ * @brief Establish an TLS client wrapper around a socket descriptor.
* @param sockd the file descriptor of the socket to have its transport security level upgraded.
* @return NULL on failure or a pointer to the SSL handle of the file descriptor if SSL negotiation was successful.
*/
@@ -188,11 +194,11 @@ void * tls_client_alloc(int_t sockd) {
long options = (SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_MODE_AUTO_RETRY);
if (!(ctx = SSL_CTX_new_d(SSLv23_client_method_d()))) {
- log_pedantic("Could not create a valid SSL context. {error = %s}", ssl_error_string(MEMORYBUF(512), 512));
+ log_pedantic("Could not create a valid TLS context. { error = %s }", ssl_error_string(MEMORYBUF(512), 512));
return NULL;
}
else if ((SSL_CTX_ctrl_d(ctx, SSL_CTRL_OPTIONS, options, NULL) & options) != options) {
- log_pedantic("Could set the options mask on the SSL context. {error = %s}", ssl_error_string(MEMORYBUF(512), 512));
+ log_pedantic("Could set the options mask on the TLS context. { error = %s }", ssl_error_string(MEMORYBUF(512), 512));
SSL_CTX_free_d(ctx);
return NULL;
}
@@ -206,12 +212,12 @@ void * tls_client_alloc(int_t sockd) {
// SSL_CTX_set_verify(result.context, mode, cert_verify_callback);
else if (!(result = SSL_new_d(ctx))) {
- log_pedantic("Could create the SSL client connection context. {error = %s}", ssl_error_string(MEMORYBUF(512), 512));
+ log_pedantic("Could create the TLS client connection context. { error = %s }", ssl_error_string(MEMORYBUF(512), 512));
SSL_CTX_free_d(ctx);
return NULL;
}
else if (!(bio = BIO_new_socket_d(sockd, BIO_NOCLOSE))) {
- log_pedantic("Could not create the SSL client BIO context. {error = %s}", ssl_error_string(MEMORYBUF(512), 512));
+ log_pedantic("Could not create the TLS client BIO context. { error = %s }", ssl_error_string(MEMORYBUF(512), 512));
SSL_free_d(result);
SSL_CTX_free_d(ctx);
return NULL;
@@ -221,7 +227,7 @@ void * tls_client_alloc(int_t sockd) {
SSL_CTX_free_d(ctx);
if (SSL_connect_d(result) != 1) {
- log_pedantic("Could not establish an SSL connection with the client. {error = %s}", ssl_error_string(MEMORYBUF(512), 512));
+ log_pedantic("Could not establish an TLS connection with the client. { error = %s }", ssl_error_string(MEMORYBUF(512), 512));
SSL_free_d(result);
return NULL;
}
@@ -230,182 +236,260 @@ void * tls_client_alloc(int_t sockd) {
}
/**
- * @brief Shutdown and free an SSL connection.
- * @param ssl the SSL connection to be shut down.
+ * @brief Shutdown and free an TLS connection.
+ * @param TLS the TLS connection to be shut down.
* @return This function returns no value.
*/
-void tls_free(SSL *ssl) {
+void tls_free(TLS *tls) {
#ifdef MAGMA_PEDANTIC
- if (!ssl) {
- log_pedantic("Passed a NULL SSL pointer.");
+ if (!tls) {
+ log_pedantic("Passed an invalid TLS pointer.");
}
#endif
- if (ssl) {
+ if (tls) {
ERR_remove_thread_state_d(0);
- SSL_shutdown_d(ssl);
- SSL_free_d(ssl);
+ SSL_shutdown_d(tls);
+ SSL_free_d(tls);
}
return;
}
/**
- * @brief Checks whether an SSL tunnel has been shut down or not.
+ * @brief Checks whether a TLS connection has been shut down or not.
* @see SSL_get_shutdown()
- * @param ssl the SSL connection to be shut down.
+ * @param tls the TLS connection to be shut down.
* @return 0 if the connection is alive and well, or SSL_SENT_SHUTDOWN/SSL_RECEIVED_SHUTDOWN
*/
-int tls_status(SSL *ssl) {
+int tls_status(TLS *tls) {
int_t result = 0;
- if (ssl) {
- result = SSL_get_shutdown_d(ssl);
+
+ // Look for a clean shut down of the TLS connection.
+ if (tls) {
+ result = SSL_get_shutdown_d(tls);
}
+
return result;
}
-
/**
- * @brief Read data from an SSL connection.
- * @param ssl the SSL connection from which the data will be read.
+ * @brief Read data from a TLS connection.
+ * @param tls the TLS connection from which the data will be read.
* @param buffer a pointer to the buffer where the read data will be stored.
* @param length the length, in bytes, of the amount of data to be read.
* @param block a boolean variable specifying whether the read operation should block.
* @return -1 on failure, 0 if the connection has been closed, or the number of bytes read from the connection on success.
*/
-int ssl_read(SSL *ssl, void *buffer, int length, bool_t block) {
+int tls_read(TLS *tls, void *buffer, int length, bool_t block) {
- int result = 0, sslerr;
+ long popped = 0;
+ chr_t *message = MEMORYBUF(1024);
+ int result = 0, err = 0, local = 0;
+ stringer_t *merged = NULL, *ip = NULL;
- if (!ssl || !buffer || !length) {
- log_pedantic("Passed invalid data for the SSL_read function.");
+ errno = 0;
+ ERR_clear_error_d();
+
+ if (!tls || !buffer || !length) {
+ log_pedantic("Passed invalid parameters for a call to the TLS read function.");
return -1;
}
- if (!block) {
+ // In the future, when we switch to OpenSSL v1.1.0 around the year ~2032, we should look into using an
+ // asynchronous SSL context to facilitate our non-blocking read/write operations. Look to configure the
+ // context using SSL_CTX_set_mode(SSL_CTX *ctx, long mode) with mode set to SSL_MODE_ASYNC.
+ else if (!block && (result = SSL_read_d(tls, buffer, length)) <= 0) {
+
+ // Consult SSL_peek / SSL_want / SSL_get_read_ahead / SSL_set_read_ahead
- // In the future, when we switch to OpenSSL v1.1.0 around the year ~2032, we should look into using an
- // asynchronous SSL context to facilitate our non-blocking read/write operations. Look to configure the
- // context using SSL_CTX_set_mode(SSL_CTX *ctx, long mode) with mode set to SSL_MODE_ASYNC.
+ log_pedantic("Non-blocking TLS read calls aren't fully implemented yet.");
- // Method One.
- //int fd = SSL_get_rfd_d(ssl);
- //if (recv(fd, buffer, length, MSG_PEEK | MSG_DONTWAIT) != 0) {
- result = SSL_read_d(ssl, buffer, length);
- if (result <= 0 && (sslerr = SSL_get_error_d(ssl, result)) != SSL_ERROR_WANT_READ) {
- ERR_error_string_n_d(sslerr, bufptr, buflen);
- log_pedantic("SSL_read error. { result = %i / error = %s }", result, bufptr);
+ if ((err = SSL_get_error_d(tls, result)) != SSL_ERROR_WANT_READ) {
+ if ((local = errno) != 0) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / errno = %i / message = %s }",
+ st_length_int(ip), st_char_get(ip), result, local, strerror_r(local, message, 1024));
+ result = tcp_error(local);
}
else if (result < 0) {
- result = 0;
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / errno = 0 }", st_length_int(ip), st_char_get(ip), result);
+ }
+ else {
+
+ // Loop through and create an error message using all of the errors in the TLS error queue.
+ while ((popped = ERR_get_error_d())) {
+ ERR_error_string_n_d(err, message, 1024);
+ merged = st_append_opts(1024, merged, st_quick(MANAGEDBUF(256), "%s( error = %li / message = %s ) ",
+ (merged ? "/ " : ""), popped, message));
+ }
+
+ if (!merged) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / error = %i / message = NULL }",
+ st_length_int(ip), st_char_get(ip), result, err);
+ }
+ else {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / error = %i / message = %.*s }",
+ st_length_int(ip), st_char_get(ip), result, err, st_length_int(merged), st_char_get(merged));
+ st_free(merged);
+ }
}
- //}
- //else {
- // result = 0;
- //}
-
- // Method two.
-// if (SSL_want_d(ssl) == SSL_READING || SSL_pending_d(ssl) > 0) {
-// result = SSL_read_d(ssl, buffer, length);
-// }
-
- // If our socket is blocking and we get this error it's not really an error.. it just means we need to try again.
-
-
- }
- else if (block && (result = SSL_read_d(ssl, buffer, length)) <= 0) {
- if ((sslerr = SSL_get_error_d(ssl, result)) != SSL_ERROR_WANT_READ) {
- ERR_error_string_n_d(sslerr, bufptr, buflen);
- log_pedantic("SSL_read error. { result = %i / error = %s }", result, bufptr);
- }
- else {
- result = 0;
}
-
}
- else if (result < 0) {
- log_pedantic("SSL connection cleanly shutdown.");
+ else if (block && (result = SSL_read_d(tls, buffer, length)) <= 0) {
+ if ((err = SSL_get_error_d(tls, result)) != SSL_ERROR_WANT_READ) {
+ if ((local = errno) != 0) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / errno = %i / message = %s }",
+ st_length_int(ip), st_char_get(ip), result, local, strerror_r(local, message, 1024));
+ result = tcp_error(local);
+ }
+ else if (result < 0) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / errno = 0 }",
+ st_length_int(ip), st_char_get(ip), result);
+ }
+ else {
+
+ // Loop through and create an error message using all of the errors in the TLS error queue.
+ while ((popped = ERR_get_error_d())) {
+ ERR_error_string_n_d(err, message, 1024);
+ merged = st_append_opts(1024, merged, st_quick(MANAGEDBUF(256), "%s( error = %li / message = %s ) ", (merged ? "/ " : ""), popped, message));
+ }
+
+ if (!merged) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / error = %i / message = NULL }",
+ st_length_int(ip), st_char_get(ip), result, err);
+ }
+ else {
+ log_pedantic("TLS read error. { ip = %.*s / result = %i / error = %i / message = %.*s }",
+ st_length_int(ip), st_char_get(ip), result, err, st_length_int(merged), st_char_get(merged));
+ st_free(merged);
+ }
+ }
+ }
}
return result;
}
/**
- * @brief Write data to an open SSL connection.
- * @param ssl the SSL connection to which the data will be written.
+ * @brief Write data to an open TLS connection.
+ * @param tls the TLS connection to which the data will be written.
* @param buffer a pointer to the buffer containing the data to be written.
* @param length the length, in bytes, of the data to be written.
- * @return -1 on error, or the number of bytes written to the SSL connection.
+ * @return -1 on error, or the number of bytes written to the TLS connection.
*/
-int ssl_write(SSL *ssl, const void *buffer, int length) {
+int tls_write(TLS *tls, const void *buffer, int length) {
+
+ long popped = 0;
+ chr_t *message = MEMORYBUF(1024);
+ int result = -1, err = 0, local = 0;
+ stringer_t *merged = NULL, *ip = NULL;
- int result = -1, sslerr;
+ errno = 0;
+ ERR_clear_error_d();
- if (!ssl || !buffer || !length) {
- log_pedantic("Passed invalid data for the SSL_write function.");
+ if (!tls || !buffer || !length) {
+ log_pedantic("Passed invalid parameters for a call to the TLS write function.");
return -1;
}
- else if ((result = SSL_write_d(ssl, buffer, length)) <= 0) {
+ else if ((result = SSL_write_d(tls, buffer, length)) <= 0) {
- // This might not really be an "error" ...
- if ((sslerr = SSL_get_error_d(ssl, result)) != SSL_ERROR_WANT_WRITE) {
- log_pedantic("SSL_write error. {sslerr = %i / error = %s}", sslerr, ssl_error_string(bufptr, buflen));
+ if ((err = SSL_get_error_d(tls, result)) != SSL_ERROR_WANT_WRITE) {
+ if ((local = errno) != 0) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS write error. { ip = %.*s / result = %i / errno = %i / message = %s }",
+ st_length_int(ip), st_char_get(ip), result, local, strerror_r(local, message, 1024));
+ result = tcp_error(local);
+ }
+ else if (result < 0) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS write error. { ip = %.*s / result = %i / errno = 0 }", st_length_int(ip), st_char_get(ip), result);
+ }
+ else {
+
+ // Loop through and create an error message using all of the errors in the TLS error queue.
+ while ((popped = ERR_get_error_d())) {
+ ERR_error_string_n_d(err, message, 1024);
+ merged = st_append_opts(1024, merged, st_quick(MANAGEDBUF(256), "%s( error = %li / message = %s ) ", (merged ? "/ " : ""), popped, message));
+ }
+
+ if (!merged) {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS write error. { ip = %.*s / result = %i / error = %i / message = NULL }", st_length_int(ip), st_char_get(ip), result, err);
+ }
+ else {
+ ip = tcp_addr_st(SSL_get_fd_d(tls), MANAGEDBUF(256));
+ log_pedantic("TLS write error. { ip = %.*s / result = %i / error = %i / message = %.*s }",
+ st_length_int(ip), st_char_get(ip), result, err, st_length_int(merged), st_char_get(merged));
+ st_free(merged);
+ }
+ }
}
-
- }
- else if (!result) {
- log_pedantic("SSL connection cleanly shutdown.");
}
return result;
}
/**
- * @brief Write formatted data to an SSL connection.
- * @param ssl the SSL connection to which the data will be written.
+ * @brief Write formatted data to an TLS connection.
+ * @param tls the SSL connection to which the data will be written.
* @param format a format string specifying the data to be written to the SSL connection.
* @param va_list a variable argument list containing the data parameters associated with the format string.
* @return -1 on error, or the number of bytes written to the SSL connection.
*/
-int ssl_print(SSL *ssl, const char *format, va_list args) {
+int tls_print(SSL *tls, const char *format, va_list args) {
- int result;
- char *buffer;
- size_t length;
va_list copy;
+ size_t length = 0;
+ chr_t *buffer = NULL;
+ int result = 0, counter = 0, bytes = 0, position = 0;
- if (!ssl) {
- return -1;
- } else if (!format) {
- return 0;
+ if (!tls || !format) {
+ return (!tls ? -1 : 0);
}
- // We need to make a copy of the arguments list in case we need to run vsnprintf twice.
+ // We need to make a copy of the arguments so we can run vsnprintf twice.
va_copy(copy, args);
- // See if the string will fit inside the standard thread buffer.
- if ((length = vsnprintf(bufptr, buflen, format, args)) < buflen) {
- va_end(copy);
- return ssl_write(ssl, bufptr, length);
+ // Calculate the length of the result so we can allocate an appropriately sized buffer.
+ length = vsnprintf(NULL, 0, format, copy);
+ va_end(copy);
+
+ // Make sure the print function succeeded.
+ if (length <= 0) {
+ return length;
}
// Allocate a large enough buffer.
else if (!(buffer = mm_alloc(length + 1))) {
- va_end(copy);
return -1;
}
- // Try building the string again.
- else if (vsnprintf(buffer, length, format, copy) != length) {
+ // Build the output string.
+ else if (vsnprintf(buffer, length + 1, format, args) != length) {
mm_free(buffer);
- va_end(copy);
return -1;
}
- result = ssl_write(ssl, buffer, length);
- va_end(copy);
+ do {
+
+ if ((bytes = tls_write(tls, buffer + position, length - position)) < 0) {
+ mm_free(buffer);
+ return -1;
+ }
+
+ position += bytes;
+
+ } while (position != length && counter++ < 128 && status());
+
mm_free(buffer);
return result;
diff --git a/src/providers/dime/common/crypto.c b/src/providers/dime/common/crypto.c
index e1aeceff..35fbc794 100644
--- a/src/providers/dime/common/crypto.c
+++ b/src/providers/dime/common/crypto.c
@@ -5,6 +5,8 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
#include "core/core.h"
#include "providers/symbols.h"
diff --git a/src/providers/dime/signet/keys.c b/src/providers/dime/signet/keys.c
index 25454df1..8eab36dd 100644
--- a/src/providers/dime/signet/keys.c
+++ b/src/providers/dime/signet/keys.c
@@ -1,4 +1,5 @@
-
+#include <arpa/inet.h>
+#include <sys/socket.h>
#include "core/core.h"
#include "dime/common/misc.h"
diff --git a/src/providers/symbols.c b/src/providers/symbols.c
index 69e31e56..4327b8f3 100644
--- a/src/providers/symbols.c
+++ b/src/providers/symbols.c
@@ -228,6 +228,7 @@ BIO * (*SSL_get_wbio_d)(const SSL * ssl) = NULL;
void (*EC_GROUP_free_d)(EC_GROUP *group) = NULL;
void (*EC_POINT_free_d)(EC_POINT *point) = NULL;
void (*X509_STORE_free_d)(X509_STORE *v) = NULL;
+int (*SSL_get_read_ahead_d)(const SSL *s) = NULL;
int (*DH_check_d)(const DH *dh, int *ret) = NULL;
int (*EC_KEY_generate_key_d)(EC_KEY *key) = NULL;
void (*ASN1_STRING_TABLE_cleanup_d)(void) = NULL;
@@ -243,6 +244,7 @@ void (*OCSP_REQUEST_free_d)(OCSP_REQUEST *a) = NULL;
const EVP_CIPHER * (*EVP_aes_256_gcm_d)(void) = NULL;
int (*SSL_peek_d)(SSL *ssl,void *buf,int num) = NULL;
const EVP_CIPHER * (*EVP_aes_256_cbc_d)(void) = NULL;
+void (*SSL_set_read_ahead_d)(SSL *s, int yes) = NULL;
EVP_CIPHER_CTX * (*EVP_CIPHER_CTX_new_d)(void) = NULL;
int (*OCSP_check_nonce_d)(void *req, void *bs) = NULL;
int (*X509_verify_cert_d)(X509_STORE_CTX *ctx) = NULL;
diff --git a/src/providers/symbols.h b/src/providers/symbols.h
index 0f07a283..2fe4da9c 100644
--- a/src/providers/symbols.h
+++ b/src/providers/symbols.h
@@ -328,6 +328,7 @@ extern BIO * (*SSL_get_wbio_d)(const SSL * ssl);
extern void (*EC_GROUP_free_d)(EC_GROUP *group);
extern void (*EC_POINT_free_d)(EC_POINT *point);
extern void (*X509_STORE_free_d)(X509_STORE *v);
+extern int (*SSL_get_read_ahead_d)(const SSL *s);
extern int (*DH_check_d)(const DH *dh, int *ret);
extern int (*EC_KEY_generate_key_d)(EC_KEY *key);
extern void (*ASN1_STRING_TABLE_cleanup_d)(void);
@@ -343,6 +344,7 @@ extern void (*OCSP_REQUEST_free_d)(OCSP_REQUEST *a);
extern const EVP_CIPHER * (*EVP_aes_256_gcm_d)(void);
extern const EVP_CIPHER * (*EVP_aes_256_cbc_d)(void);
extern int (*SSL_peek_d)(SSL *ssl,void *buf,int num);
+extern void (*SSL_set_read_ahead_d)(SSL *s, int yes);
extern EVP_CIPHER_CTX * (*EVP_CIPHER_CTX_new_d)(void);
extern int (*OCSP_check_nonce_d)(void *req, void *bs);
extern int (*X509_verify_cert_d)(X509_STORE_CTX *ctx);
diff --git a/src/servers/imap/fetch.c b/src/servers/imap/fetch.c
index 2768f7b4..cfad6bcf 100644
--- a/src/servers/imap/fetch.c
+++ b/src/servers/imap/fetch.c
@@ -1360,9 +1360,11 @@ inx_t * imap_narrow_messages(inx_t *messages, uint64_t selected, stringer_t *ran
// Parse the end.
if (!pl_empty(end_token) && *(pl_char_get(end_token)) == '*') {
asterisk = 1;
- } else if (pl_empty(end_token)) {
+ }
+ else if (pl_empty(end_token)) {
end = start;
- } else {
+ }
+ else {
if (!uint64_conv_st(&end_token, &end)) {
log_pedantic("range parsing error = %.*s", st_length_int(range), st_char_get(range));
diff --git a/src/servers/imap/imap.c b/src/servers/imap/imap.c
index 23403cf8..080cac18 100644
--- a/src/servers/imap/imap.c
+++ b/src/servers/imap/imap.c
@@ -1825,7 +1825,7 @@ void imap_capability(connection_t *con) {
}
/**
- * @brief The main imap entry point for all inbound client connections, as dispatched by the generic protocol handler (display
+ * @brief The main IMAP entry point for all inbound client connections, as dispatched by the generic protocol handler (display
* banner greeting).
*
* @param con a pointer to the connection object of the newly connected client.
diff --git a/src/servers/imap/parse.c b/src/servers/imap/parse.c
index e0e41cfc..73704333 100644
--- a/src/servers/imap/parse.c
+++ b/src/servers/imap/parse.c
@@ -119,6 +119,7 @@ imap_arguments_t * imap_get_ar_ar(imap_arguments_t *array, size_t element) {
return result;
}
+
/*
// Mailbox names can contain base64 data that needs to be decoded. Base64 data is inside the &- characters.
stringer_t * imap_string_to_mailbox(stringer_t *string) {
@@ -138,7 +139,6 @@ stringer_t * imap_mailbox_to_string(stringer_t *mailbox) {
*/
-
/**
* @brief Extract the contents of an atomic string and advance the position of the parser stream.
* @note This function scans a string, expecting printable ASCII characters until it encounters a space, \r, \n, (, or [.
diff --git a/src/servers/smtp/smtp.c b/src/servers/smtp/smtp.c
index 48b40ac6..c36c7c0f 100644
--- a/src/servers/smtp/smtp.c
+++ b/src/servers/smtp/smtp.c
@@ -193,10 +193,10 @@ void smtp_quit(connection_t *con) {
if (con_status(con) == 2) {
con_write_bl(con, "451 Unexpected connection shutdown detected. Goodbye.\r\n", 55);
}
- else if (con_status(con) >= 0) {
+ else if (con_status(con) > 0) {
con_write_bl(con, "221 BYE\r\n", 9);
}
- else {
+ else if (con_status(con) == 0){
con_write_bl(con, "421 Network connection failure.\r\n", 33);
}
@@ -832,7 +832,7 @@ int_t smtp_data_read(connection_t *con, stringer_t **message) {
buffer = st_char_get(result);
read = con_read(con);
- while (checker != 4 && status() && read > 0) {
+ while (checker != 4 && read > 0 && status()) {
// Setup the stream.
stream = st_data_get(con->network.buffer);
@@ -937,7 +937,7 @@ int_t smtp_data_read(connection_t *con, stringer_t **message) {
}
// The server is shutting down or the client disconnected.
- if (status() != 1) {
+ if (!status()) {
st_free(result);
return -3;
}