1
/* $Cambridge: exim/exim-src/src/auths/cyrus_sasl.c,v 1.3 2005/04/05 14:33:27 ph10 Exp $ */
3
/*************************************************
4
* Exim - an Internet mail transport agent *
5
*************************************************/
7
/* Copyright (c) University of Cambridge 1995 - 2003 */
8
/* See the file NOTICE for conditions of use and distribution. */
10
/* This code was originally contributed by Matthew Byng-Maddick */
12
/* Copyright (c) A L Digital 2004 */
14
/* A generic (mechanism independent) Cyrus SASL authenticator. */
20
/* We can't just compile this code and allow the library mechanism to omit the
21
functions if they are not wanted, because we need to have the Cyrus SASL header
22
available for compiling. Therefore, compile these functions only if
23
AUTH_CYRUS_SASL is defined. However, some compilers don't like compiling empty
24
modules, so keep them happy with a dummy when skipping the rest. Make it
25
reference itself to stop picky compilers complaining that it is unused, and put
26
in a dummy argument to stop even pickier compilers complaining about infinite
29
#ifndef AUTH_CYRUS_SASL
30
static void dummy(int x) { dummy(x-1); }
34
#include <sasl/sasl.h>
35
#include "cyrus_sasl.h"
37
/* Options specific to the cyrus_sasl authentication mechanism. */
39
optionlist auth_cyrus_sasl_options[] = {
40
{ "server_hostname", opt_stringptr,
41
(void *)(offsetof(auth_cyrus_sasl_options_block, server_hostname)) },
42
{ "server_mech", opt_stringptr,
43
(void *)(offsetof(auth_cyrus_sasl_options_block, server_mech)) },
44
{ "server_realm", opt_stringptr,
45
(void *)(offsetof(auth_cyrus_sasl_options_block, server_realm)) },
46
{ "server_service", opt_stringptr,
47
(void *)(offsetof(auth_cyrus_sasl_options_block, server_service)) }
50
/* Size of the options list. An extern variable has to be used so that its
51
address can appear in the tables drtables.c. */
53
int auth_cyrus_sasl_options_count =
54
sizeof(auth_cyrus_sasl_options)/sizeof(optionlist);
56
/* Default private options block for the contidion authentication method. */
58
auth_cyrus_sasl_options_block auth_cyrus_sasl_option_defaults = {
59
US"smtp", /* server_service */
60
US"$primary_hostname", /* server_hostname */
61
NULL, /* server_realm */
62
NULL /* server_mech */
66
/*************************************************
67
* Initialization entry point *
68
*************************************************/
70
/* Called for each instance, after its options have been read, to
71
enable consistency checks to be done, or anything else that needs
75
/* Auxiliary function, passed in data to sasl_server_init(). */
78
mysasl_config(void *context,
79
const char *plugin_name,
84
if (context && !strcmp(option, "mech_list"))
87
if (len != NULL) *len = strlen(*result);
93
/* Here's the real function */
96
auth_cyrus_sasl_init(auth_instance *ablock)
98
auth_cyrus_sasl_options_block *ob =
99
(auth_cyrus_sasl_options_block *)(ablock->options_block);
100
uschar *list, *listptr, *buffer;
106
sasl_callback_t cbs[]={
107
{SASL_CB_GETOPT, NULL, NULL },
108
{SASL_CB_LIST_END, NULL, NULL}};
110
/* default the mechanism to our "public name" */
111
if(ob->server_mech == NULL)
112
ob->server_mech=string_copy(ablock->public_name);
114
/* we're going to initialise the library to check that there is an
115
* authenticator of type whatever mechanism we're using
118
cbs[0].proc = &mysasl_config;
119
cbs[0].context = ob->server_mech;
121
rc=sasl_server_init(cbs, "exim");
124
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
125
"couldn't initialise Cyrus SASL library.", ablock->name);
127
rc=sasl_server_new(CS ob->server_service, CS primary_hostname,
128
CS ob->server_realm, NULL, NULL, NULL, 0, &conn);
130
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
131
"couldn't initialise Cyrus SASL server connection.", ablock->name);
133
rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)(&list), &len, &i);
135
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
136
"couldn't get Cyrus SASL mechanism list.", ablock->name);
141
HDEBUG(D_auth) debug_printf("Cyrus SASL knows about: %s\n", list);
143
/* the store_get / store_reset mechanism is hierarchical
144
* the hierarchy is stored for us behind our back. This point
145
* creates a hierarchy point for this function.
147
rs_point=store_get(0);
149
/* loop until either we get to the end of the list, or we match the
150
* public name of this authenticator
152
while( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) &&
153
strcmpic(buffer,ob->server_mech) );
156
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
157
"Cyrus SASL doesn't know about mechanism %s.", ablock->name, ob->server_mech);
159
store_reset(rs_point);
161
HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name);
163
/* make sure that if we get here then we're allowed to advertise. */
164
ablock->server = TRUE;
170
/*************************************************
171
* Server entry point *
172
*************************************************/
174
/* For interface, see auths/README */
176
/* note, we don't care too much about memory allocation in this, because this is entirely
177
* within a shortlived child
181
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
183
auth_cyrus_sasl_options_block *ob =
184
(auth_cyrus_sasl_options_block *)(ablock->options_block);
185
uschar *output, *out2, *input, *clear, *hname;
186
uschar *debug = NULL; /* Stops compiler complaining */
187
sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
189
int rc, firsttime=1, clen;
190
unsigned int inlen, outlen;
195
HDEBUG(D_auth) debug=string_copy(data);
197
hname=expand_string(ob->server_hostname);
200
auth_defer_msg = expand_string_message;
206
clen=auth_b64decode(input, &clear);
215
rc=sasl_server_init(cbs, "exim");
218
auth_defer_msg = US"couldn't initialise Cyrus SASL library";
222
rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL,
223
NULL, NULL, 0, &conn);
227
auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
234
while(rc==SASL_CONTINUE)
239
HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
240
rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
241
(const char **)(&output), &outlen);
245
/* make sure that we have a null-terminated string */
246
out2=store_get(outlen+1);
247
memcpy(out2,output,outlen);
249
if((rc=auth_get_data(&input, out2, outlen))!=OK)
251
/* we couldn't get the data, so free up the library before
252
* returning whatever error we get */
257
inlen=Ustrlen(input);
259
HDEBUG(D_auth) debug=string_copy(input);
262
clen=auth_b64decode(input, &clear);
273
HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
274
rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
282
else if( rc==SASL_FAIL || rc==SASL_BUFOVER
283
|| rc==SASL_BADMAC || rc==SASL_BADAUTH
284
|| rc==SASL_NOAUTHZ || rc==SASL_ENCRYPT
285
|| rc==SASL_EXPIRED || rc==SASL_DISABLED
288
/* these are considered permanent failure codes */
290
debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
291
log_write(0, LOG_REJECT, "%s authenticator (%s):\n "
292
"Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
293
sasl_errstring(rc, NULL, NULL));
298
else if(rc==SASL_NOMECH)
300
/* this is a temporary failure, because the mechanism is not
301
* available for this user. If it wasn't available at all, we
302
* shouldn't have got here in the first place...
305
debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
307
string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
312
else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
314
/* Anything else is a temporary failure, and we'll let SASL print out
315
* the error string for us
318
debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
320
string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
327
/* get the username and copy it into $1 */
328
rc=sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
329
expand_nstring[1]=string_copy(out2);
330
expand_nlength[1]=Ustrlen(expand_nstring[1]);
334
debug_printf("Cyrus SASL %s authentiction succeeded for %s\n", ob->server_mech, out2);
335
/* close down the connection, freeing up library's memory */
342
return 0; /* Stop compiler complaints */
345
/*************************************************
346
* Client entry point *
347
*************************************************/
349
/* For interface, see auths/README */
352
auth_cyrus_sasl_client(
353
auth_instance *ablock, /* authenticator block */
354
smtp_inblock *inblock, /* input connection */
355
smtp_outblock *outblock, /* output connection */
356
int timeout, /* command timeout */
357
uschar *buffer, /* for reading response */
358
int buffsize) /* size of buffer */
360
/* We don't support clients (yet) in this implementation of cyrus_sasl */
364
#endif /* AUTH_CYRUS_SASL */
366
/* End of cyrus_sasl.c */