sasl-server.c revision 183bea41fa640dc8117f3eb45ff935cd81377a84
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "login-common.h"
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen#include "base64.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "buffer.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "hex-binary.h"
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen#include "istream.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "write-full.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "strescape.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "str-sanitize.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "anvil-client.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "auth-client.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "ssl-proxy.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "master-service.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "master-interface.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "master-auth.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include "client-common.h"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include <stdlib.h>
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#include <unistd.h>
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen#define ERR_TOO_MANY_USERIP_CONNECTIONS \
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen "Maximum number of connections from user+IP exceeded " \
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen "(mail_max_userip_connections=%u)"
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainenstruct anvil_request {
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen struct client *client;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen unsigned int auth_pid, auth_id;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen unsigned char cookie[MASTER_AUTH_COOKIE_SIZE];
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen};
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainenconst struct auth_mech_desc *
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainensasl_server_get_advertised_mechs(struct client *client, unsigned int *count_r)
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen{
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen const struct auth_mech_desc *mech;
84a5175b9768da401404635c9b606264585739bdTimo Sirainen struct auth_mech_desc *ret_mech;
84a5175b9768da401404635c9b606264585739bdTimo Sirainen unsigned int i, j, count;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen mech = auth_client_get_available_mechs(auth_client, &count);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen if (count == 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *count_r = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return NULL;
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen }
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen ret_mech = t_new(struct auth_mech_desc, count);
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen for (i = j = 0; i < count; i++) {
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen /* a) transport is secured
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen b) auth mechanism isn't plaintext
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen c) we allow insecure authentication
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen */
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainen if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen (client->secured || !client->set->disable_plaintext_auth ||
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen (mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen ret_mech[j++] = mech[i];
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *count_r = j;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return ret_mech;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainenstatic enum auth_request_flags
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainenclient_get_auth_flags(struct client *client)
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen{
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen enum auth_request_flags auth_flags = 0;
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen if (client->ssl_proxy != NULL &&
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen ssl_proxy_has_valid_client_cert(client->ssl_proxy))
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen if (client->secured)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen auth_flags |= AUTH_REQUEST_FLAG_SECURED;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->trusted) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* e.g. webmail */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen auth_flags |= AUTH_REQUEST_FLAG_NO_PENALTY;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return auth_flags;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
fcb5f4cd72b413a5356a8db55e679403c6a1adb5Timo Sirainencall_client_callback(struct client *client, enum sasl_server_reply reply,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *data, const char *const *args)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_server_callback_t *sasl_callback;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(reply != SASL_SERVER_REPLY_CONTINUE);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_callback = client->sasl_callback;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->sasl_callback = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_callback(client, reply, data, args);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* NOTE: client may be destroyed now */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenmaster_auth_callback(const struct master_auth_reply *reply, void *context)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct client *client = context;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen enum sasl_server_reply sasl_reply = SASL_SERVER_REPLY_MASTER_FAILED;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *data = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->master_tag = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->authenticating = FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (reply != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen switch (reply->status) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case MASTER_AUTH_STATUS_OK:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_reply = SASL_SERVER_REPLY_SUCCESS;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case MASTER_AUTH_STATUS_INTERNAL_ERROR:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_reply = SASL_SERVER_REPLY_MASTER_FAILED;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->mail_pid = reply->mail_pid;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen } else {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen auth_client_send_cancel(auth_client, client->master_auth_id);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen call_client_callback(client, sasl_reply, data, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void master_send_request(struct anvil_request *anvil_request)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct client *client = anvil_request->client;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct master_auth_request req;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const unsigned char *data;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen size_t size;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen buffer_t *buf;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen memset(&req, 0, sizeof(req));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req.auth_pid = anvil_request->auth_pid;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req.auth_id = anvil_request->auth_id;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req.local_ip = client->local_ip;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req.remote_ip = client->ip;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req.client_pid = getpid();
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->ssl_proxy != NULL &&
5f8d497e88fae77fbeb625246bc18260f6775b83Timo Sirainen ssl_proxy_get_compression(client->ssl_proxy))
5f8d497e88fae77fbeb625246bc18260f6775b83Timo Sirainen req.flags |= MAIL_AUTH_REQUEST_FLAG_TLS_COMPRESSION;
5f8d497e88fae77fbeb625246bc18260f6775b83Timo Sirainen memcpy(req.cookie, anvil_request->cookie, sizeof(req.cookie));
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen buffer_append(buf, client->master_data_prefix,
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen client->master_data_prefix_len);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen data = i_stream_get_data(client->input, &size);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen buffer_append(buf, data, size);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen req.data_size = buf->used;
84a5175b9768da401404635c9b606264585739bdTimo Sirainen
f2686912e0156c04296d6dc306f39d61089a1363Timo Sirainen client->master_auth_id = req.auth_id;
f2686912e0156c04296d6dc306f39d61089a1363Timo Sirainen master_auth_request(master_auth, client->fd, &req, buf->data,
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen master_auth_callback, client, &client->master_tag);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen}
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainenstatic void anvil_lookup_callback(const char *reply, void *context)
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen{
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen struct anvil_request *req = context;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen struct client *client = req->client;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen const struct login_settings *set = client->set;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen const char *errmsg;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen if (reply == NULL ||
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen strtoul(reply, NULL, 10) < set->mail_max_userip_connections)
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen master_send_request(req);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen else {
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen client->authenticating = FALSE;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen auth_client_send_cancel(auth_client, req->auth_id);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen errmsg = t_strdup_printf(ERR_TOO_MANY_USERIP_CONNECTIONS,
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen set->mail_max_userip_connections);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen call_client_callback(client, SASL_SERVER_REPLY_MASTER_FAILED,
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen errmsg, NULL);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen }
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen i_free(req);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen}
84a5175b9768da401404635c9b606264585739bdTimo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainenstatic void
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainenanvil_check_too_many_connections(struct client *client,
84a5175b9768da401404635c9b606264585739bdTimo Sirainen struct auth_client_request *request)
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen{
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen struct anvil_request *req;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen const char *query, *cookie;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen buffer_t buf;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req = i_new(struct anvil_request, 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req->client = client;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req->auth_pid = auth_client_request_get_server_pid(request);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen req->auth_id = auth_client_request_get_id(request);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen buffer_create_data(&buf, req->cookie, sizeof(req->cookie));
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen cookie = auth_client_request_get_cookie(request);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strlen(cookie) == MASTER_AUTH_COOKIE_SIZE*2)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (void)hex_to_binary(cookie, &buf);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->virtual_user == NULL ||
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->set->mail_max_userip_connections == 0) {
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen anvil_lookup_callback(NULL, req);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen return;
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen }
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen query = t_strconcat("LOOKUP\t", login_binary.protocol, "/",
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen net_ip2addr(&client->ip), "/",
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen str_tabescape(client->virtual_user), NULL);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen anvil_client_query(anvil, query, anvil_lookup_callback, req);
84a5175b9768da401404635c9b606264585739bdTimo Sirainen}
84a5175b9768da401404635c9b606264585739bdTimo Sirainen
84a5175b9768da401404635c9b606264585739bdTimo Sirainenstatic void
84a5175b9768da401404635c9b606264585739bdTimo Sirainenauthenticate_callback(struct auth_client_request *request,
84a5175b9768da401404635c9b606264585739bdTimo Sirainen enum auth_request_status status, const char *data_base64,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *const *args, void *context)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct client *client = context;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int i;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen bool nologin;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (!client->authenticating) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* client aborted */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(status < 0);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(client->auth_request == request);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen switch (status) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case AUTH_REQUEST_STATUS_CONTINUE:
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen /* continue */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen data_base64, NULL);
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen break;
9f0a996c22ebe39dcfe5cb84c8fd2f22ef5ce9d8Timo Sirainen case AUTH_REQUEST_STATUS_OK:
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen client->auth_request = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen nologin = FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (i = 0; args[i] != NULL; i++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strncmp(args[i], "user=", 5) == 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->virtual_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->virtual_user = i_strdup(args[i] + 5);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcmp(args[i], "nologin") == 0 ||
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen strcmp(args[i], "proxy") == 0) {
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen /* user can't login */
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen nologin = TRUE;
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen }
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen }
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainen if (nologin) {
2026684bfc269f4ab3196dea3594f9fe17b1238dTimo Sirainen client->authenticating = FALSE;
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen call_client_callback(client, SASL_SERVER_REPLY_SUCCESS,
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen NULL, args);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen } else {
60d1fdf2c17fd0c7020234590dbd73da81c3ce8fTimo Sirainen anvil_check_too_many_connections(client, request);
60d1fdf2c17fd0c7020234590dbd73da81c3ce8fTimo Sirainen }
60d1fdf2c17fd0c7020234590dbd73da81c3ce8fTimo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case AUTH_REQUEST_STATUS_FAIL:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->auth_request = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (args != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* parse our username if it's there */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (i = 0; args[i] != NULL; i++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strncmp(args[i], "user=", 5) == 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->virtual_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->virtual_user =
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_strdup(args[i] + 5);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->authenticating = FALSE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen call_client_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen NULL, args);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid sasl_server_auth_begin(struct client *client,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *service, const char *mech_name,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *initial_resp_base64,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_server_callback_t *callback)
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct auth_request_info info;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const struct auth_mech_desc *mech;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(auth_client_is_connected(auth_client));
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->auth_attempts++;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->authenticating = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->auth_mech_name);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->auth_mech_name = str_ucase(i_strdup(mech_name));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->sasl_callback = callback;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen mech = auth_client_find_mech(auth_client, mech_name);
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen if (mech == NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->auth_tried_unsupported_mech = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_server_auth_failed(client,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "Unsupported authentication mechanism.");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (!client->secured && client->set->disable_plaintext_auth &&
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->auth_tried_disabled_plaintext = TRUE;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen sasl_server_auth_failed(client,
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen "Plaintext authentication disabled.");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen memset(&info, 0, sizeof(info));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen info.mech = mech->name;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen info.service = service;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen info.cert_username = client->ssl_proxy == NULL ? NULL :
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen ssl_proxy_get_peer_name(client->ssl_proxy);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen info.flags = client_get_auth_flags(client);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen info.local_ip = client->local_ip;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen info.remote_ip = client->ip;
info.local_port = client->local_port;
info.remote_port = client->remote_port;
info.initial_resp_base64 = initial_resp_base64;
client->auth_request =
auth_client_request_new(auth_client, &info,
authenticate_callback, client);
}
static void sasl_server_auth_cancel(struct client *client, const char *reason,
enum sasl_server_reply reply)
{
i_assert(client->authenticating);
if (client->set->verbose_auth && reason != NULL) {
const char *auth_name =
str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
client_log(client, t_strdup_printf(
"Authenticate %s failed: %s", auth_name, reason));
}
client->authenticating = FALSE;
if (client->auth_request != NULL)
auth_client_request_abort(&client->auth_request);
call_client_callback(client, reply, reason, NULL);
}
void sasl_server_auth_failed(struct client *client, const char *reason)
{
sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED);
}
void sasl_server_auth_abort(struct client *client)
{
client->auth_try_aborted = TRUE;
sasl_server_auth_cancel(client, NULL, SASL_SERVER_REPLY_AUTH_ABORTED);
}