view src/login-common/sasl-server.c @ 2768:d344be0bb70f HEAD

Added IMAP and POP3 proxying support.
author Timo Sirainen <tss@iki.fi>
date Mon, 18 Oct 2004 22:21:40 +0300
parents 26a091f3add6
children 7ac5ee00278c
line wrap: on
line source

/* Copyright (C) 2002-2004 Timo Sirainen */

#include "common.h"
#include "base64.h"
#include "buffer.h"
#include "str-sanitize.h"
#include "auth-client.h"
#include "ssl-proxy.h"
#include "client-common.h"
#include "master.h"

/* Used only for string sanitization while verbose_auth is set. */
#define MAX_MECH_NAME 64

static enum auth_request_flags
client_get_auth_flags(struct client *client)
{
        enum auth_request_flags auth_flags = 0;

	if (client->proxy != NULL &&
	    ssl_proxy_has_valid_client_cert(client->proxy))
		auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
	if (client->secured)
		auth_flags |= AUTH_REQUEST_FLAG_SECURED;
	return auth_flags;
}

static void master_callback(struct client *client, int success)
{
	client->authenticating = FALSE;
	client->sasl_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
			      SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
}

static void authenticate_callback(struct auth_request *request, int status,
				  const char *data_base64,
				  const char *const *args, void *context)
{
	struct client *client = context;
	unsigned int i;
	int nologin;

	if (!client->authenticating) {
		/* client aborted */
		i_assert(status < 0);
		return;
	}

	switch (status) {
	case 0:
		/* continue */
		if (client->auth_request != NULL) {
			i_assert(client->auth_request == request);
		} else {
			i_assert(client->auth_request == NULL);

			client->auth_request = request;
		}

		client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
				      data_base64, NULL);
		break;
	case 1:
		client->auth_request = NULL;

		nologin = FALSE;
		for (i = 0; args[i] != NULL; i++) {
			if (strncmp(args[i], "user=", 5) == 0) {
				i_free(client->virtual_user);
				client->virtual_user = i_strdup(args[i] + 5);
			}
			if (strcmp(args[i], "nologin") == 0) {
				/* user can't login */
				nologin = TRUE;
			}
		}

		if (nologin) {
			client->authenticating = FALSE;
			client->sasl_callback(client, SASL_SERVER_REPLY_SUCCESS,
					      NULL, args);
		} else {
			master_request_login(client, master_callback,
				auth_client_request_get_server_pid(request),
				auth_client_request_get_id(request));
		}
		break;
	case -1:
		client->auth_request = NULL;

		if (args != NULL) {
			for (i = 0; args[i] != NULL; i++) {
				if (strncmp(args[i], "user=", 5) == 0) {
					i_free(client->virtual_user);
					client->virtual_user =
						i_strdup(args[i] + 5);
				}
			}
		}

		/* base64 contains error message, if there is one */
		if (verbose_auth && data_base64 != NULL) {
			client_syslog(client, "Authenticate %s failed: %s",
				      str_sanitize(client->auth_mech_name,
						   MAX_MECH_NAME),
				      (const char *)data_base64);
		}

		client->authenticating = FALSE;
		client->sasl_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
				      (const char *)data_base64, args);
		break;
	}
}

void sasl_server_auth_begin(struct client *client,
			    const char *protocol, const char *mech_name,
			    const char *initial_resp_base64,
			    sasl_server_callback_t *callback)
{
	struct auth_request_info info;
	const struct auth_mech_desc *mech;
	const char *error;

	client->authenticating = TRUE;
	i_free(client->auth_mech_name);
	client->auth_mech_name = i_strdup(mech_name);
	client->sasl_callback = callback;

	mech = auth_client_find_mech(auth_client, mech_name);
	if (mech == NULL) {
		sasl_server_auth_cancel(client, 
			"Unsupported authentication mechanism.");
		return;
	}

	if (!client->secured && disable_plaintext_auth &&
	    (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
		sasl_server_auth_cancel(client,
					"Plaintext authentication disabled.");
		return;
	}

	memset(&info, 0, sizeof(info));
	info.mech = mech->name;
	info.protocol = protocol;
	info.flags = client_get_auth_flags(client);
	info.local_ip = client->local_ip;
	info.remote_ip = client->ip;
	info.initial_resp_base64 = initial_resp_base64;

	client->auth_request =
		auth_client_request_new(auth_client, NULL, &info,
					authenticate_callback, client, &error);
	if (client->auth_request == NULL) {
		sasl_server_auth_cancel(client,
			 t_strconcat("Authentication failed: ", error, NULL));
	}
}

void sasl_server_auth_cancel(struct client *client, const char *reason)
{
	if (verbose_auth && reason != NULL) {
		client_syslog(client, "Authenticate %s failed: %s",
			      str_sanitize(client->auth_mech_name,
					   MAX_MECH_NAME), reason);
	}

	client->authenticating = FALSE;

	if (client->auth_request != NULL) {
		auth_client_request_abort(client->auth_request);
		client->auth_request = NULL;
	}

	client->sasl_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
			      reason, NULL);
}