diff --git a/include/msgapi.h b/include/msgapi.h index f24addc..d77a1e6 100644 --- a/include/msgapi.h +++ b/include/msgapi.h @@ -30,10 +30,22 @@ #include // Auth functions +enum { + MSG_AUTH_SERVICE_IMAP = 1U << 0, + MSG_AUTH_SERVICE_POP3 = 1U << 1, + MSG_AUTH_SERVICE_SMTP = 1U << 2, + MSG_AUTH_SERVICE_SIEVE = 1U << 3, + MSG_AUTH_SERVICE_CALDAV = 1U << 4, + MSG_AUTH_SERVICE_CARDDAV = 1U << 5 +}; + EXPORT int MsgAuthInit(void); EXPORT int MsgAuthInstall(void); EXPORT int MsgAuthFindUser(const char *user); EXPORT BOOL MsgAuthVerifyPassword(const char *user, const char *password); +EXPORT int MsgAuthVerifyServicePassword(const char *user, const char *password, + unsigned int service, + const char *source_address); EXPORT int MsgAuthChangePassword(const char *user, const char *oldpassword, const char *newpassword); EXPORT int MsgAuthSetPassword(const char *user, const char *password); EXPORT int MsgAuthGetUserStore(const char *user, struct sockaddr_in *store); @@ -260,4 +272,3 @@ EXPORT int MsgImportIcsUrl(const char *user, #endif #endif /* MSGAPI_H */ - diff --git a/src/agents/imap/session.c b/src/agents/imap/session.c index 717d4ce..9c5210e 100644 --- a/src/agents/imap/session.c +++ b/src/agents/imap/session.c @@ -34,11 +34,15 @@ static long UserAuthenticate(ImapSession *session, char **userName, char *password, struct sockaddr_in *storeAddress) { - UNUSED_PARAMETER(session) + char source[INET_ADDRSTRLEN]; + if (MsgAuthFindUser(*userName) != 0) return(STATUS_USERNAME_NOT_FOUND); - if (MsgAuthVerifyPassword(*userName, password) != 0) + if (!inet_ntop(AF_INET, &session->client.conn->socketAddress.sin_addr, + source, sizeof(source)) || + MsgAuthVerifyServicePassword(*userName, password, MSG_AUTH_SERVICE_IMAP, + source) != 0) return(STATUS_WRONG_PASSWORD); MsgAuthGetUserStore(*userName, storeAddress); @@ -49,16 +53,22 @@ static int ImapSaslVerify(void *context, const char *user, const char *password, size_t passwordLength) { + ImapSession *session = context; + char source[INET_ADDRSTRLEN]; char *copy; int valid; - UNUSED_PARAMETER(context) - if (!user || !password || !passwordLength || strlen(user) > MAXEMAILNAMESIZE) + if (!session || !user || !password || !passwordLength || + strlen(user) > MAXEMAILNAMESIZE || + !inet_ntop(AF_INET, &session->client.conn->socketAddress.sin_addr, + source, sizeof(source))) return 0; copy = MemMalloc(passwordLength + 1); if (!copy) return 0; memcpy(copy, password, passwordLength); copy[passwordLength] = '\0'; - valid = MsgAuthFindUser(user) == 0 && MsgAuthVerifyPassword(user, copy) == 0; + valid = MsgAuthFindUser(user) == 0 && + MsgAuthVerifyServicePassword(user, copy, MSG_AUTH_SERVICE_IMAP, + source) == 0; memset(copy, 0, passwordLength); MemFree(copy); return valid; diff --git a/src/agents/pop/pop3.c b/src/agents/pop/pop3.c index 0fea94e..65ba8cb 100644 --- a/src/agents/pop/pop3.c +++ b/src/agents/pop/pop3.c @@ -465,13 +465,17 @@ ConnectUserToNMAPServer(POP3Client *client, char *username, char *password) { BOOL result; struct sockaddr_in nmap; + char source[INET_ADDRSTRLEN]; if (MsgAuthFindUser(username) != 0) { Log(LOG_NOTICE, "Unknown user %s from host %s", username, LOGIP(client->conn->socketAddress)); return(POP3_NMAP_USER_UNKNOWN); } - if (MsgAuthVerifyPassword(username, password) != 0) { + if (!inet_ntop(AF_INET, &client->conn->socketAddress.sin_addr, source, + sizeof(source)) || + MsgAuthVerifyServicePassword(username, password, MSG_AUTH_SERVICE_POP3, + source) != 0) { XplSafeIncrement(POP3.stats.badPasswords); Log(LOG_NOTICE, "Incorrect password for user %s from host %s", username, LOGIP(client->conn->socketAddress)); @@ -503,15 +507,20 @@ POP3SaslVerify(void *context, const char *user, const char *password, size_t password_length) { POP3Client *client = context; + char source[INET_ADDRSTRLEN]; char *copy; int valid; if (!client || !user || !password || !password_length || - strlen(user) >= sizeof(client->user)) return 0; + strlen(user) >= sizeof(client->user) || + !inet_ntop(AF_INET, &client->conn->socketAddress.sin_addr, source, + sizeof(source))) return 0; copy = MemMalloc(password_length + 1); if (!copy) return 0; memcpy(copy, password, password_length); copy[password_length] = '\0'; - valid = MsgAuthFindUser(user) == 0 && MsgAuthVerifyPassword(user, copy) == 0; + valid = MsgAuthFindUser(user) == 0 && + MsgAuthVerifyServicePassword(user, copy, MSG_AUTH_SERVICE_POP3, + source) == 0; memset(copy, 0, password_length); MemFree(copy); return valid; diff --git a/src/agents/sieve/managesieved.c b/src/agents/sieve/managesieved.c index 39adee1..be3170f 100644 --- a/src/agents/sieve/managesieved.c +++ b/src/agents/sieve/managesieved.c @@ -81,15 +81,20 @@ static int capabilities(Connection *connection, int tls, const char *mechanisms) static int verify_password(void *context, const char *user, const char *password, size_t password_length) { + Connection *connection = context; + char source[INET_ADDRSTRLEN]; char *copy; int valid; - (void)context; - if (!user || !password || password_length > 4096) return 0; + if (!connection || !user || !password || password_length > 4096 || + !inet_ntop(AF_INET, &connection->socketAddress.sin_addr, source, + sizeof(source))) return 0; copy = malloc(password_length + 1); if (!copy) return 0; memcpy(copy, password, password_length); copy[password_length] = '\0'; - valid = MsgAuthFindUser(user) == 0 && MsgAuthVerifyPassword(user, copy) == 0; + valid = MsgAuthFindUser(user) == 0 && + MsgAuthVerifyServicePassword(user, copy, MSG_AUTH_SERVICE_SIEVE, + source) == 0; memset(copy, 0, password_length); free(copy); return valid; @@ -200,7 +205,7 @@ static void serve(Connection *connection) ConnFlush(connection); if (!ConnNegotiate(connection, tls_context) || !BongoSaslSessionCreate(&sasl, "sieve", NULL, NULL, NULL, 1, - verify_password, NULL) || + verify_password, connection) || !BongoSaslMechanisms(sasl, &mechanisms)) break; tls = 1; } else if (request.command == BONGO_MANAGESIEVE_AUTHENTICATE && tls && !user) { diff --git a/src/agents/smtp/smtpd.c b/src/agents/smtp/smtpd.c index 594dbd2..e7ddc67 100644 --- a/src/agents/smtp/smtpd.c +++ b/src/agents/smtp/smtpd.c @@ -499,8 +499,13 @@ IsTransportRecipient(const char *address) static BOOL AuthenticateUser(ConnectionStruct *client, const char *user, const char *password) { + char source[INET_ADDRSTRLEN]; + if (user == NULL || password == NULL || *user == '\0' || - MsgAuthFindUser(user) != 0 || MsgAuthVerifyPassword(user, password) != 0) { + !inet_ntop(AF_INET, &client->client.conn->socketAddress.sin_addr, + source, sizeof(source)) || MsgAuthFindUser(user) != 0 || + MsgAuthVerifyServicePassword(user, password, MSG_AUTH_SERVICE_SMTP, + source) != 0) { Log(LOG_NOTICE, "Authentication failed for user %s at host %s", user != NULL ? user : "", LOGIP(client->client.conn->socketAddress)); return FALSE; diff --git a/src/libs/msgapi/auth-backends/sqlite.c b/src/libs/msgapi/auth-backends/sqlite.c index ff05d36..b0977d3 100644 --- a/src/libs/msgapi/auth-backends/sqlite.c +++ b/src/libs/msgapi/auth-backends/sqlite.c @@ -83,6 +83,8 @@ AuthSqlite_Init(void) sqlite3 *database = NULL; int result = -1; + if (BongoAuthSecurityInit() != 0) + return -1; AuthSqlite_GetDbPath(path, sizeof(path)); if (access(path, F_OK) != 0 && errno == ENOENT) return 0; @@ -193,6 +195,45 @@ AuthSqlite_VerifyPassword(const char *user, const char *password) return result; } +int +AuthSqlite_VerifyServicePassword(const char *user, const char *password, + unsigned int service, const char *source_address) +{ + char database_path[XPL_MAX_PATH + 1]; + char key_path[XPL_MAX_PATH + 1]; + AuthSecurityStore store; + int totp_enabled; + int require_app_passwords; + int result = 1; + + if (!user || !password || !service) + return 1; + if (AuthSqlite_GetDbPath(database_path, sizeof(database_path)) < 0 || + snprintf(key_path, sizeof(key_path), "%s/auth.key", + XPL_DEFAULT_DBF_DIR) >= (int)sizeof(key_path) || + AuthSecurityStoreOpen(&store, database_path, key_path) != 0) + return 1; + if (AuthSecurityGetPolicy(&store, user, &totp_enabled, + &require_app_passwords) != 0) + goto done; + UNUSED_PARAMETER(totp_enabled) + if (strncmp(password, "bap-", 4) == 0) { + result = AuthSecurityVerifyAppPassword(&store, user, password, service, + source_address, time(NULL)) == 1 + ? 0 + : 1; + goto done; + } + if (!require_app_passwords) { + AuthSecurityStoreClose(&store); + return AuthSqlite_VerifyPassword(user, password); + } + +done: + AuthSecurityStoreClose(&store); + return result; +} + /* "Write" functions below */ int diff --git a/src/libs/msgapi/auth-backends/sqlite.h b/src/libs/msgapi/auth-backends/sqlite.h index 2c95948..1ecebf5 100644 --- a/src/libs/msgapi/auth-backends/sqlite.h +++ b/src/libs/msgapi/auth-backends/sqlite.h @@ -3,6 +3,9 @@ int AuthSqlite_GetDbPath(char *path, size_t size); int AuthSqlite_Install(void); int AuthSqlite_FindUser(const char *user); int AuthSqlite_VerifyPassword(const char *user, const char *password); +int AuthSqlite_VerifyServicePassword(const char *user, const char *password, + unsigned int service, + const char *source_address); int AuthSqlite_AddUser(const char *user); int AuthSqlite_SetPassword(const char *user, const char *password); int AuthSqlite_GetUserStore(const char *user, struct sockaddr_in *store); diff --git a/src/libs/msgapi/msgauth.c b/src/libs/msgapi/msgauth.c index 570ef3f..5ba171c 100644 --- a/src/libs/msgapi/msgauth.c +++ b/src/libs/msgapi/msgauth.c @@ -156,6 +156,20 @@ MsgAuthVerifyPassword(const char *user, const char *password) return result; } +int +MsgAuthVerifyServicePassword(const char *user, const char *password, + unsigned int service, const char *source_address) +{ + MsgAuthAPIFunction *function; + AuthPlugin_VerifyServicePassword *verify; + + function = &pluginapi[Func_VerifyServicePassword]; + if (!function->available) + return MsgAuthVerifyPassword(user, password); + verify = (AuthPlugin_VerifyServicePassword *)&function->func; + return (*verify)(user, password, service, source_address); +} + /* "Write" functions below */ /** diff --git a/src/libs/msgapi/plugin-api.h b/src/libs/msgapi/plugin-api.h index 7e557f6..37acc6e 100644 --- a/src/libs/msgapi/plugin-api.h +++ b/src/libs/msgapi/plugin-api.h @@ -10,6 +10,8 @@ typedef struct { typedef int (* AuthPlugin_InterfaceVersion)(void); typedef int (* AuthPlugin_FindUser)(const char *user); typedef int (* AuthPlugin_VerifyPassword)(const char *user, const char *password); +typedef int (* AuthPlugin_VerifyServicePassword)(const char *user, + const char *password, unsigned int service, const char *source_address); typedef int (* AuthPlugin_AddUser)(const char *user); typedef int (* AuthPlugin_ChangePassword)(const char *user, const char *oldpassword, const char *newpassword); typedef int (* AuthPlugin_SetPassword)(const char *user, const char *password); @@ -28,7 +30,8 @@ enum { Func_SetPassword = 6, Func_GetUserStore = 7, Func_Install = 8, - Func_Init = 9 + Func_Init = 9, + Func_VerifyServicePassword = 10 }; static MsgAuthAPIFunction pluginapi[] = { @@ -42,5 +45,6 @@ static MsgAuthAPIFunction pluginapi[] = { {0, 1, "GetUserStore", NULL}, {0, 0, "Install", NULL}, {0, 1, "Init", NULL}, + {0, 1, "VerifyServicePassword", NULL}, {0, 0, NULL, NULL} };