src/login-common/sasl-server.c
author Timo Sirainen <tss@iki.fi>
Mon Nov 05 20:23:32 2007 +0200 (2007-11-05)
branchbranch_1_0
changeset 5449 6df077099f0b
parent 5217 a30ef30c8f8e
child 5458 73a3a6b1af36
permissions -rw-r--r--
"Unsupported auth mechanism" and "Plaintext auth disabled" errors should
result in NO instead of BAD reply.
tss@2733
     1
/* Copyright (C) 2002-2004 Timo Sirainen */
tss@2733
     2
tss@2733
     3
#include "common.h"
tss@2733
     4
#include "base64.h"
tss@2733
     5
#include "buffer.h"
tss@2733
     6
#include "str-sanitize.h"
tss@2733
     7
#include "auth-client.h"
tss@2733
     8
#include "ssl-proxy.h"
tss@2733
     9
#include "client-common.h"
tss@2733
    10
#include "master.h"
tss@2733
    11
tss@2736
    12
static enum auth_request_flags
tss@2733
    13
client_get_auth_flags(struct client *client)
tss@2733
    14
{
tss@2736
    15
        enum auth_request_flags auth_flags = 0;
tss@2733
    16
tss@2733
    17
	if (client->proxy != NULL &&
tss@2733
    18
	    ssl_proxy_has_valid_client_cert(client->proxy))
tss@2736
    19
		auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
tss@2736
    20
	if (client->secured)
tss@2736
    21
		auth_flags |= AUTH_REQUEST_FLAG_SECURED;
tss@2733
    22
	return auth_flags;
tss@2733
    23
}
tss@2733
    24
tss@5070
    25
static void
tss@5070
    26
call_client_callback(struct client *client, enum sasl_server_reply reply,
tss@5070
    27
		     const char *data, const char *const *args)
tss@5070
    28
{
tss@5070
    29
	sasl_server_callback_t *sasl_callback;
tss@5070
    30
tss@5070
    31
	i_assert(reply != SASL_SERVER_REPLY_CONTINUE);
tss@5070
    32
tss@5070
    33
	sasl_callback = client->sasl_callback;
tss@5070
    34
	client->sasl_callback = NULL;
tss@5070
    35
tss@5070
    36
	sasl_callback(client, reply, data, args);
tss@5070
    37
	/* NOTE: client may be destroyed now */
tss@5070
    38
}
tss@5070
    39
tss@3863
    40
static void master_callback(struct client *client, bool success)
tss@2733
    41
{
tss@2733
    42
	client->authenticating = FALSE;
tss@5070
    43
	call_client_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
tss@5070
    44
			     SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
tss@2733
    45
}
tss@2733
    46
tss@2736
    47
static void authenticate_callback(struct auth_request *request, int status,
tss@2736
    48
				  const char *data_base64,
tss@2736
    49
				  const char *const *args, void *context)
tss@2733
    50
{
tss@2733
    51
	struct client *client = context;
tss@2766
    52
	unsigned int i;
tss@3863
    53
	bool nologin;
tss@2733
    54
tss@2733
    55
	if (!client->authenticating) {
tss@2733
    56
		/* client aborted */
tss@2736
    57
		i_assert(status < 0);
tss@2733
    58
		return;
tss@2733
    59
	}
tss@2733
    60
tss@4952
    61
	i_assert(client->auth_request == request);
tss@5216
    62
	client->waiting_auth_reply = FALSE;
tss@5216
    63
tss@2736
    64
	switch (status) {
tss@2736
    65
	case 0:
tss@2736
    66
		/* continue */
tss@2733
    67
		client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
tss@2766
    68
				      data_base64, NULL);
tss@2733
    69
		break;
tss@2736
    70
	case 1:
tss@2733
    71
		client->auth_request = NULL;
tss@2733
    72
tss@2766
    73
		nologin = FALSE;
tss@2766
    74
		for (i = 0; args[i] != NULL; i++) {
tss@2766
    75
			if (strncmp(args[i], "user=", 5) == 0) {
tss@2736
    76
				i_free(client->virtual_user);
tss@2766
    77
				client->virtual_user = i_strdup(args[i] + 5);
tss@2766
    78
			}
tss@4783
    79
			if (strcmp(args[i], "nologin") == 0 ||
tss@4783
    80
			    strcmp(args[i], "proxy") == 0) {
tss@2766
    81
				/* user can't login */
tss@2766
    82
				nologin = TRUE;
tss@2736
    83
			}
tss@2736
    84
		}
tss@2733
    85
tss@2766
    86
		if (nologin) {
tss@2766
    87
			client->authenticating = FALSE;
tss@5070
    88
			call_client_callback(client, SASL_SERVER_REPLY_SUCCESS,
tss@5070
    89
					     NULL, args);
tss@2766
    90
		} else {
tss@2766
    91
			master_request_login(client, master_callback,
tss@2733
    92
				auth_client_request_get_server_pid(request),
tss@2733
    93
				auth_client_request_get_id(request));
tss@2766
    94
		}
tss@2733
    95
		break;
tss@2736
    96
	case -1:
tss@2733
    97
		client->auth_request = NULL;
tss@2733
    98
tss@2768
    99
		if (args != NULL) {
tss@2772
   100
			/* parse our username if it's there */
tss@2768
   101
			for (i = 0; args[i] != NULL; i++) {
tss@2768
   102
				if (strncmp(args[i], "user=", 5) == 0) {
tss@2768
   103
					i_free(client->virtual_user);
tss@2768
   104
					client->virtual_user =
tss@2768
   105
						i_strdup(args[i] + 5);
tss@2768
   106
				}
tss@2768
   107
			}
tss@2768
   108
		}
tss@2768
   109
tss@2766
   110
		client->authenticating = FALSE;
tss@5070
   111
		call_client_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
tss@5070
   112
				     NULL, args);
tss@2733
   113
		break;
tss@2733
   114
	}
tss@2733
   115
}
tss@2733
   116
tss@2733
   117
void sasl_server_auth_begin(struct client *client,
tss@2781
   118
			    const char *service, const char *mech_name,
tss@2736
   119
			    const char *initial_resp_base64,
tss@2733
   120
			    sasl_server_callback_t *callback)
tss@2733
   121
{
tss@2733
   122
	struct auth_request_info info;
tss@2733
   123
	const struct auth_mech_desc *mech;
tss@2733
   124
	const char *error;
tss@2733
   125
tss@2733
   126
	client->authenticating = TRUE;
tss@2766
   127
	i_free(client->auth_mech_name);
tss@4768
   128
	client->auth_mech_name = str_ucase(i_strdup(mech_name));
tss@2733
   129
	client->sasl_callback = callback;
tss@2733
   130
tss@2733
   131
	mech = auth_client_find_mech(auth_client, mech_name);
tss@2733
   132
	if (mech == NULL) {
tss@5449
   133
		sasl_server_auth_failed(client,
tss@2733
   134
			"Unsupported authentication mechanism.");
tss@2733
   135
		return;
tss@2733
   136
	}
tss@2733
   137
tss@2736
   138
	if (!client->secured && disable_plaintext_auth &&
tss@2736
   139
	    (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
tss@5449
   140
		sasl_server_auth_failed(client,
tss@4311
   141
			"Plaintext authentication disabled.");
tss@2733
   142
		return;
tss@2733
   143
	}
tss@2733
   144
tss@2733
   145
	memset(&info, 0, sizeof(info));
tss@2733
   146
	info.mech = mech->name;
tss@2781
   147
	info.service = service;
tss@3635
   148
	info.cert_username = client->proxy == NULL ? NULL :
tss@3635
   149
		ssl_proxy_get_peer_name(client->proxy);
tss@2733
   150
	info.flags = client_get_auth_flags(client);
tss@2733
   151
	info.local_ip = client->local_ip;
tss@2733
   152
	info.remote_ip = client->ip;
tss@2736
   153
	info.initial_resp_base64 = initial_resp_base64;
tss@2733
   154
tss@2733
   155
	client->auth_request =
tss@2733
   156
		auth_client_request_new(auth_client, NULL, &info,
tss@2733
   157
					authenticate_callback, client, &error);
tss@2733
   158
	if (client->auth_request == NULL) {
tss@4311
   159
		sasl_server_auth_failed(client,
tss@2733
   160
			 t_strconcat("Authentication failed: ", error, NULL));
tss@2733
   161
	}
tss@2733
   162
}
tss@2733
   163
tss@4311
   164
static void sasl_server_auth_cancel(struct client *client, const char *reason,
tss@4311
   165
				    enum sasl_server_reply reply)
tss@2733
   166
{
tss@4991
   167
	i_assert(client->authenticating);
tss@4991
   168
tss@2733
   169
	if (verbose_auth && reason != NULL) {
tss@3384
   170
		const char *auth_name =
tss@3384
   171
			str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
tss@3384
   172
		client_syslog(client,
tss@3384
   173
			t_strdup_printf("Authenticate %s failed: %s",
tss@3384
   174
					auth_name, reason));
tss@2733
   175
	}
tss@2733
   176
tss@2733
   177
	client->authenticating = FALSE;
tss@5217
   178
	client->waiting_auth_reply = FALSE;
tss@2733
   179
tss@2733
   180
	if (client->auth_request != NULL) {
tss@2733
   181
		auth_client_request_abort(client->auth_request);
tss@2733
   182
		client->auth_request = NULL;
tss@2733
   183
	}
tss@2733
   184
tss@5070
   185
	call_client_callback(client, reply, reason, NULL);
tss@2733
   186
}
tss@4311
   187
tss@4311
   188
void sasl_server_auth_failed(struct client *client, const char *reason)
tss@4311
   189
{
tss@4311
   190
	sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED);
tss@4311
   191
}
tss@4311
   192
tss@4311
   193
void sasl_server_auth_client_error(struct client *client, const char *reason)
tss@4311
   194
{
tss@4311
   195
	sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_CLIENT_ERROR);
tss@4311
   196
}