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