1 /* $Cambridge: exim/src/src/auths/cyrus_sasl.c,v 1.1 2004/10/07 13:10:01 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 ob->server_hostname,
194 CS ob->server_realm, NULL, NULL, NULL, 0, &conn);
197 auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
204 while(rc==SASL_CONTINUE)
209 HDEBUG(D_auth) debug_printf("Calling sasl_server_start(%s,\"%s\")\n", ob->server_mech, debug);
210 rc=sasl_server_start(conn, CS ob->server_mech, inlen?CS input:NULL, inlen,
211 (const char **)(&output), &outlen);
215 /* make sure that we have a null-terminated string */
216 out2=store_get(outlen+1);
217 memcpy(out2,output,outlen);
219 if((rc=auth_get_data(&input, out2, outlen))!=OK)
221 /* we couldn't get the data, so free up the library before
222 * returning whatever error we get */
227 inlen=Ustrlen(input);
229 HDEBUG(D_auth) debug=string_copy(input);
232 clen=auth_b64decode(input, &clear);
243 HDEBUG(D_auth) debug_printf("Calling sasl_server_step(\"%s\")\n", debug);
244 rc=sasl_server_step(conn, CS input, inlen, (const char **)(&output), &outlen);
252 else if( rc==SASL_FAIL || rc==SASL_BUFOVER
253 || rc==SASL_BADMAC || rc==SASL_BADAUTH
254 || rc==SASL_NOAUTHZ || rc==SASL_ENCRYPT
255 || rc==SASL_EXPIRED || rc==SASL_DISABLED
258 /* these are considered permanent failure codes */
260 debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
261 log_write(0, LOG_REJECT, "%s authenticator (%s):\n "
262 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
263 sasl_errstring(rc, NULL, NULL));
268 else if(rc==SASL_NOMECH)
270 /* this is a temporary failure, because the mechanism is not
271 * available for this user. If it wasn't available at all, we
272 * shouldn't have got here in the first place...
275 debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
277 string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
282 else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
284 /* Anything else is a temporary failure, and we'll let SASL print out
285 * the error string for us
288 debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
290 string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
297 /* get the username and copy it into $1 */
298 rc=sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2));
299 expand_nstring[1]=string_copy(out2);
300 expand_nlength[1]=Ustrlen(expand_nstring[1]);
304 debug_printf("Cyrus SASL %s authentiction succeeded for %s\n", ob->server_mech, out2);
305 /* close down the connection, freeing up library's memory */
312 return 0; /* Stop compiler complaints */
315 /*************************************************
316 * Client entry point *
317 *************************************************/
319 /* For interface, see auths/README */
322 auth_cyrus_sasl_client(
323 auth_instance *ablock, /* authenticator block */
324 smtp_inblock *inblock, /* input connection */
325 smtp_outblock *outblock, /* output connection */
326 int timeout, /* command timeout */
327 uschar *buffer, /* for reading response */
328 int buffsize) /* size of buffer */
330 /* We don't support clients (yet) in this implementation of cyrus_sasl */
334 #endif /* AUTH_CYRUS_SASL */
336 /* End of cyrus_sasl.c */