1 /* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.4 2006/02/10 14:25:43 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 $auth1 and $1. The former is now the
328 preferred variable; the latter is the original variable. */
329 rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
330 auth_vars[0] = expand_nstring[1] = string_copy(out2);
331 expand_nlength[1] = Ustrlen(expand_nstring[1]);
335 debug_printf("Cyrus SASL %s authentiction succeeded for %s\n", ob->server_mech, out2);
336 /* close down the connection, freeing up library's memory */
343 return 0; /* Stop compiler complaints */
346 /*************************************************
347 * Client entry point *
348 *************************************************/
350 /* For interface, see auths/README */
353 auth_cyrus_sasl_client(
354 auth_instance *ablock, /* authenticator block */
355 smtp_inblock *inblock, /* input connection */
356 smtp_outblock *outblock, /* output connection */
357 int timeout, /* command timeout */
358 uschar *buffer, /* for reading response */
359 int buffsize) /* size of buffer */
361 /* We don't support clients (yet) in this implementation of cyrus_sasl */
365 #endif /* AUTH_CYRUS_SASL */
367 /* End of cyrus_sasl.c */