diff --git a/src/agents/collector/CMakeLists.txt b/src/agents/collector/CMakeLists.txt index e180ab1..963a1a8 100644 --- a/src/agents/collector/CMakeLists.txt +++ b/src/agents/collector/CMakeLists.txt @@ -16,6 +16,7 @@ add_custom_command( add_executable(bongocollector collector.c external_accounts.c + external_store.c ${EXTERNAL_ACCOUNTS_SQL_C} ) diff --git a/src/agents/collector/external_store.c b/src/agents/collector/external_store.c new file mode 100644 index 0000000..c7c9d99 --- /dev/null +++ b/src/agents/collector/external_store.c @@ -0,0 +1,88 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "external_store.h" + +static int +SafeNmapToken(const char *value) +{ + return value != NULL && value[0] != '\0' && + strpbrk(value, "\r\n\"\\") == NULL; +} + +static void +SetError(char *error, size_t error_size, const char *message) +{ + if (error != NULL && error_size > 0) { + snprintf(error, error_size, "%s", message != NULL ? message : "unknown error"); + } +} + +int +CollectorStoreSubmitFile(const char *owner, const char *folder, + FILE *message, size_t message_size, + time_t received_at, char *error, + size_t error_size) +{ + struct sockaddr_in store_address; + Connection *connection = NULL; + char response[CONN_BUFSIZE + 1]; + int result = -1; + + if (!SafeNmapToken(owner) || !SafeNmapToken(folder) || message == NULL || + message_size == 0 || message_size > INT_MAX) { + SetError(error, error_size, "invalid external message submission parameters"); + return -1; + } + if (MsgAuthGetUserStore(owner, &store_address) != 0) { + SetError(error, error_size, "cannot locate the user's Bongo store"); + return -1; + } + connection = NMAPConnect(NULL, &store_address); + if (connection == NULL) { + SetError(error, error_size, "cannot connect to the user's Bongo store"); + return -1; + } + if (!NMAPAuthenticateThenUserAndStore(connection, (unsigned char *) owner)) { + SetError(error, error_size, "cannot authenticate to the user's Bongo store"); + goto done; + } + if (NMAPRunCommandF(connection, response, sizeof(response), + "WRITE \"/mail/%s\" %u %zu T%lu\r\n", folder, + STORE_DOCTYPE_MAIL, message_size, + (unsigned long) received_at) != 2002) { + SetError(error, error_size, "the Bongo store rejected the target folder"); + goto done; + } + rewind(message); + if (ConnWriteFromFile(connection, message, (int) message_size) != (int) message_size || + ConnFlush(connection) < 0) { + SetError(error, error_size, "cannot send the external message to the Bongo store"); + goto done; + } + if (NMAPReadAnswer(connection, response, sizeof(response), TRUE) != 1000) { + SetError(error, error_size, "the Bongo store could not import the external message"); + goto done; + } + SetError(error, error_size, ""); + result = 0; + +done: + NMAPQuit(connection); + ConnFree(connection); + return result; +} diff --git a/src/agents/collector/external_store.h b/src/agents/collector/external_store.h new file mode 100644 index 0000000..5cd9ee6 --- /dev/null +++ b/src/agents/collector/external_store.h @@ -0,0 +1,13 @@ +#ifndef BONGO_COLLECTOR_EXTERNAL_STORE_H +#define BONGO_COLLECTOR_EXTERNAL_STORE_H + +#include +#include +#include + +int CollectorStoreSubmitFile(const char *owner, const char *folder, + FILE *message, size_t message_size, + time_t received_at, char *error, + size_t error_size); + +#endif