Enforce app password service policies

This commit is contained in:
Mario Fetka
2026-07-17 06:20:54 +02:00
parent 1a461b71a6
commit 26c183b521
9 changed files with 117 additions and 15 deletions
+12 -1
View File
@@ -30,10 +30,22 @@
#include <msgdate.h>
// 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 */
+15 -5
View File
@@ -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;
+12 -3
View File
@@ -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;
+9 -4
View File
@@ -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) {
+6 -1
View File
@@ -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;
+41
View File
@@ -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
+3
View File
@@ -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);
+14
View File
@@ -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 */
/**
+5 -1
View File
@@ -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}
};