Enforce app password service policies
This commit is contained in:
+12
-1
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user