sasl-server.c revision 02ccba3d3be96444abd15b5254864c9151bbeb30
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "common.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "base64.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "buffer.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str-sanitize.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "auth-client.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ssl-proxy.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "client-common.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "master.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic enum auth_request_flags
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenclient_get_auth_flags(struct client *client)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen enum auth_request_flags auth_flags = 0;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->proxy != NULL &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ssl_proxy_has_valid_client_cert(client->proxy))
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->secured)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen auth_flags |= AUTH_REQUEST_FLAG_SECURED;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return auth_flags;
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainencall_client_callback(struct client *client, enum sasl_server_reply reply,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *data, const char *const *args)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_server_callback_t *sasl_callback;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(reply != SASL_SERVER_REPLY_CONTINUE);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_callback = client->sasl_callback;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->sasl_callback = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen sasl_callback(client, reply, data, args);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* NOTE: client may be destroyed now */
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenmaster_callback(struct client *client, enum master_login_status status)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen{
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen enum sasl_server_reply reply = SASL_SERVER_REPLY_MASTER_FAILED;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *data = NULL;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->authenticating = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen switch (status) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case MASTER_LOGIN_STATUS_OK:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen reply = SASL_SERVER_REPLY_SUCCESS;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case MASTER_LOGIN_STATUS_INTERNAL_ERROR:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case MASTER_LOGIN_STATUS_MAX_CONNECTIONS:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen data = "Maximum number of connections from user+IP exceeded";
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen call_client_callback(client, reply, data, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenstatic void authenticate_callback(struct auth_request *request, int status,
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen const char *data_base64,
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen const char *const *args, void *context)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct client *client = context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen bool nologin;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!client->authenticating) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* client aborted */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(status < 0);
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen return;
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen }
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen i_assert(client->auth_request == request);
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen switch (status) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case 0:
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen /* continue */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen data_base64, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case 1:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_request = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen nologin = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; args[i] != NULL; i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (strncmp(args[i], "user=", 5) == 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_free(client->virtual_user);
6389aeec8c26b585e583c364b48ad12adf741898Timo Sirainen client->virtual_user = i_strdup(args[i] + 5);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (strcmp(args[i], "nologin") == 0 ||
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen strcmp(args[i], "proxy") == 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* user can't login */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen nologin = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (nologin) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->authenticating = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen call_client_callback(client, SASL_SERVER_REPLY_SUCCESS,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen NULL, args);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen master_request_login(client, master_callback,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen auth_client_request_get_server_pid(request),
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen auth_client_request_get_id(request));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen case -1:
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_request = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (args != NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* parse our username if it's there */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen for (i = 0; args[i] != NULL; i++) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (strncmp(args[i], "user=", 5) == 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_free(client->virtual_user);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->virtual_user =
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_strdup(args[i] + 5);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->authenticating = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen call_client_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen NULL, args);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainenvoid sasl_server_auth_begin(struct client *client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *service, const char *mech_name,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *initial_resp_base64,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen sasl_server_callback_t *callback)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen struct auth_request_info info;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const struct auth_mech_desc *mech;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *error;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_attempts++;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->authenticating = TRUE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_free(client->auth_mech_name);
4c07b08af30e1065f7022980b60474f229d8cadfTimo Sirainen client->auth_mech_name = str_ucase(i_strdup(mech_name));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->sasl_callback = callback;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen mech = auth_client_find_mech(auth_client, mech_name);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (mech == NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_server_auth_failed(client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "Unsupported authentication mechanism.");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (!client->secured && disable_plaintext_auth &&
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_server_auth_failed(client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "Plaintext authentication disabled.");
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen memset(&info, 0, sizeof(info));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.mech = mech->name;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen info.service = service;
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen info.cert_username = client->proxy == NULL ? NULL :
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ssl_proxy_get_peer_name(client->proxy);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen info.flags = client_get_auth_flags(client);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.local_ip = client->local_ip;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.remote_ip = client->ip;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.local_port = client->local_port;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.remote_port = client->remote_port;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen info.initial_resp_base64 = initial_resp_base64;
2ae7cffa50608be0e1261e0a993333a8bdc0550dTimo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_request =
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen auth_client_request_new(auth_client, NULL, &info,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen authenticate_callback, client, &error);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->auth_request == NULL) {
07fe84e1db9fe5a79e815f000bd94ae61f5831dbTimo Sirainen sasl_server_auth_failed(client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen t_strconcat("Authentication failed: ", error, NULL));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void sasl_server_auth_cancel(struct client *client, const char *reason,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen enum sasl_server_reply reply)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen i_assert(client->authenticating);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (verbose_auth && reason != NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *auth_name =
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_syslog(client,
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen t_strdup_printf("Authenticate %s failed: %s",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen auth_name, reason));
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->authenticating = FALSE;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (client->auth_request != NULL) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen auth_client_request_abort(client->auth_request);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client->auth_request = NULL;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen call_client_callback(client, reply, reason, NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid sasl_server_auth_failed(struct client *client, const char *reason)
2ae7cffa50608be0e1261e0a993333a8bdc0550dTimo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenvoid sasl_server_auth_client_error(struct client *client, const char *reason)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen{
2ba4e9bedb0fa778dfbccec5370018b4d0040d9cTimo Sirainen sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_CLIENT_ERROR);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen