1 /* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.2 2005/04/05 14:02:30 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 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 auth_cyrus_sasl_init(auth_instance *ablock)
77 auth_cyrus_sasl_options_block *ob =
78 (auth_cyrus_sasl_options_block *)(ablock->options_block);
79 sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
81 uschar *list, *listptr, *buffer;
86 /* default the mechanism to our "public name" */
87 if(ob->server_mech == NULL)
88 ob->server_mech=string_copy(ablock->public_name);
90 /* we're going to initialise the library to check that there is an
91 * authenticator of type whatever mechanism we're using
93 rc=sasl_server_init(cbs, "exim");
95 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
96 "couldn't initialise Cyrus SASL library.", ablock->name);
98 rc=sasl_server_new(CS ob->server_service, CS primary_hostname,
99 CS ob->server_realm, NULL, NULL, NULL, 0, &conn);
101 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
102 "couldn't initialise Cyrus SASL server connection.", ablock->name);
104 rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)(&list), &len, &i);
106 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
107 "couldn't get Cyrus SASL mechanism list.", ablock->name);
112 HDEBUG(D_auth) debug_printf("Cyrus SASL knows about: %s\n", list);
114 /* the store_get / store_reset mechanism is hierarchical
115 * the hierarchy is stored for us behind our back. This point
116 * creates a hierarchy point for this function.
118 rs_point=store_get(0);
120 /* loop until either we get to the end of the list, or we match the
121 * public name of this authenticator
123 while( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) &&
124 strcmpic(buffer,ob->server_mech) );
127 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
128 "Cyrus SASL doesn't know about mechanism %s.", ablock->name, ob->server_mech);
130 store_reset(rs_point);
132 HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name);
134 /* make sure that if we get here then we're allowed to advertise. */
135 ablock->server = TRUE;
141 /*************************************************
142 * Server entry point *
143 *************************************************/
145 /* For interface, see auths/README */
147 /* note, we don't care too much about memory allocation in this, because this is entirely
148 * within a shortlived child
152 auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
154 auth_cyrus_sasl_options_block *ob =
155 (auth_cyrus_sasl_options_block *)(ablock->options_block);
156 uschar *output, *out2, *input, *clear, *hname;
157 uschar *debug = NULL; /* Stops compiler complaining */
158 sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}};
160 int rc, firsttime=1, clen;
161 unsigned int inlen, outlen;
166 HDEBUG(D_auth) debug=string_copy(data);
168 hname=expand_string(ob->server_hostname);
171 auth_defer_msg = expand_string_message;
177 clen=auth_b64decode(input, &clear);
186 rc=sasl_server_init(cbs, "exim");
189 auth_defer_msg = US"couldn't initialise Cyrus SASL library";
193 rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL,
194 NULL, NULL, 0, &conn);
198 auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
205 while(rc==SASL_CONTINUE)
210 HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
211 rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
212 (const char **)(&output), &outlen);
216 /* make sure that we have a null-terminated string */
217 out2=store_get(outlen+1);
218 memcpy(out2,output,outlen);
220 if((rc=auth_get_data(&input, out2, outlen))!=OK)
222 /* we couldn't get the data, so free up the library before
223 * returning whatever error we get */
228 inlen=Ustrlen(input);
230 HDEBUG(D_auth) debug=string_copy(input);
233 clen=auth_b64decode(input, &clear);
244 HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
245 rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
253 else if( rc==SASL_FAIL || rc==SASL_BUFOVER
254 || rc==SASL_BADMAC || rc==SASL_BADAUTH
255 || rc==SASL_NOAUTHZ || rc==SASL_ENCRYPT
256 || rc==SASL_EXPIRED || rc==SASL_DISABLED
259 /* these are considered permanent failure codes */
261 debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
262 log_write(0, LOG_REJECT, "%s authenticator (%s):\n "
263 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
264 sasl_errstring(rc, NULL, NULL));
269 else if(rc==SASL_NOMECH)
271 /* this is a temporary failure, because the mechanism is not
272 * available for this user. If it wasn't available at all, we
273 * shouldn't have got here in the first place...
276 debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
278 string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
283 else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
285 /* Anything else is a temporary failure, and we'll let SASL print out
286 * the error string for us
289 debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
291 string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
298 /* get the username and copy it into $1 */
299 rc=sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
300 expand_nstring[1]=string_copy(out2);
301 expand_nlength[1]=Ustrlen(expand_nstring[1]);
305 debug_printf("Cyrus SASL %s authentiction succeeded for %s\n", ob->server_mech, out2);
306 /* close down the connection, freeing up library's memory */
313 return 0; /* Stop compiler complaints */
316 /*************************************************
317 * Client entry point *
318 *************************************************/
320 /* For interface, see auths/README */
323 auth_cyrus_sasl_client(
324 auth_instance *ablock, /* authenticator block */
325 smtp_inblock *inblock, /* input connection */
326 smtp_outblock *outblock, /* output connection */
327 int timeout, /* command timeout */
328 uschar *buffer, /* for reading response */
329 int buffsize) /* size of buffer */
331 /* We don't support clients (yet) in this implementation of cyrus_sasl */
335 #endif /* AUTH_CYRUS_SASL */
337 /* End of cyrus_sasl.c */