~ubuntu-branches/ubuntu/hardy/exim4/hardy-proposed

« back to all changes in this revision

Viewing changes to src/auths/cyrus_sasl.c

  • Committer: Bazaar Package Importer
  • Author(s): Marc Haber
  • Date: 2005-07-02 06:08:34 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050702060834-qk17pd52kb9nt3bj
Tags: 4.52-1
* new upstream version 4.51. (mh)
  * adapt 70_remove_exim-users_references
  * remove 37_gnutlsparams
  * adapt 36_pcre
  * adapt 31_eximmanpage
* fix package priorities to have them in sync with override again. (mh)
* Fix error in nb (Norwegian) translation.
  Thanks to Helge Hafting. (mh). Closes: #315775
* Standards-Version: 3.6.2, no changes needed. (mh)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Cambridge: exim/exim-src/src/auths/cyrus_sasl.c,v 1.3 2005/04/05 14:33:27 ph10 Exp $ */
 
2
 
 
3
/*************************************************
 
4
*     Exim - an Internet mail transport agent    *
 
5
*************************************************/
 
6
 
 
7
/* Copyright (c) University of Cambridge 1995 - 2003 */
 
8
/* See the file NOTICE for conditions of use and distribution. */
 
9
 
 
10
/* This code was originally contributed by Matthew Byng-Maddick */
 
11
 
 
12
/* Copyright (c) A L Digital 2004 */
 
13
 
 
14
/* A generic (mechanism independent) Cyrus SASL authenticator. */
 
15
 
 
16
 
 
17
#include "../exim.h"
 
18
 
 
19
 
 
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
 
27
loops. */
 
28
 
 
29
#ifndef AUTH_CYRUS_SASL
 
30
static void dummy(int x) { dummy(x-1); }
 
31
#else
 
32
 
 
33
 
 
34
#include <sasl/sasl.h>
 
35
#include "cyrus_sasl.h"
 
36
 
 
37
/* Options specific to the cyrus_sasl authentication mechanism. */
 
38
 
 
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)) }
 
48
};
 
49
 
 
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. */
 
52
 
 
53
int auth_cyrus_sasl_options_count =
 
54
  sizeof(auth_cyrus_sasl_options)/sizeof(optionlist);
 
55
 
 
56
/* Default private options block for the contidion authentication method. */
 
57
 
 
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 */
 
63
};
 
64
 
 
65
 
 
66
/*************************************************
 
67
*          Initialization entry point            *
 
68
*************************************************/
 
69
 
 
70
/* Called for each instance, after its options have been read, to
 
71
enable consistency checks to be done, or anything else that needs
 
72
to be set up. */
 
73
 
 
74
 
 
75
/* Auxiliary function, passed in data to sasl_server_init(). */
 
76
 
 
77
static int
 
78
mysasl_config(void *context,
 
79
              const char *plugin_name,
 
80
              const char *option,
 
81
              const char **result,
 
82
              unsigned int *len)
 
83
{
 
84
if (context && !strcmp(option, "mech_list"))
 
85
  {
 
86
  *result = context;
 
87
  if (len != NULL) *len = strlen(*result);
 
88
  return SASL_OK;
 
89
  }
 
90
return SASL_FAIL;
 
91
}
 
92
 
 
93
/* Here's the real function */
 
94
 
 
95
void
 
96
auth_cyrus_sasl_init(auth_instance *ablock)
 
97
{
 
98
auth_cyrus_sasl_options_block *ob =
 
99
  (auth_cyrus_sasl_options_block *)(ablock->options_block);
 
100
uschar *list, *listptr, *buffer;
 
101
int rc, i;
 
102
unsigned int len;
 
103
uschar *rs_point;
 
104
 
 
105
sasl_conn_t *conn;
 
106
sasl_callback_t cbs[]={
 
107
  {SASL_CB_GETOPT, NULL, NULL },
 
108
  {SASL_CB_LIST_END, NULL, NULL}};
 
109
 
 
110
/* default the mechanism to our "public name" */
 
111
if(ob->server_mech == NULL)
 
112
  ob->server_mech=string_copy(ablock->public_name);
 
113
 
 
114
/* we're going to initialise the library to check that there is an
 
115
 * authenticator of type whatever mechanism we're using
 
116
 */
 
117
 
 
118
cbs[0].proc = &mysasl_config;
 
119
cbs[0].context = ob->server_mech;
 
120
 
 
121
rc=sasl_server_init(cbs, "exim");
 
122
 
 
123
if( rc != SASL_OK )
 
124
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
 
125
      "couldn't initialise Cyrus SASL library.", ablock->name);
 
126
 
 
127
rc=sasl_server_new(CS ob->server_service, CS primary_hostname,
 
128
                   CS ob->server_realm, NULL, NULL, NULL, 0, &conn);
 
129
if( rc != SASL_OK )
 
130
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
 
131
      "couldn't initialise Cyrus SASL server connection.", ablock->name);
 
132
 
 
133
rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)(&list), &len, &i);
 
134
if( rc != SASL_OK )
 
135
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
 
136
      "couldn't get Cyrus SASL mechanism list.", ablock->name);
 
137
 
 
138
i=':';
 
139
listptr=list;
 
140
 
 
141
HDEBUG(D_auth) debug_printf("Cyrus SASL knows about: %s\n", list);
 
142
 
 
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.
 
146
 */
 
147
rs_point=store_get(0);
 
148
 
 
149
/* loop until either we get to the end of the list, or we match the
 
150
 * public name of this authenticator
 
151
 */
 
152
while( ( buffer = string_nextinlist(&listptr, &i, NULL, 0) ) &&
 
153
       strcmpic(buffer,ob->server_mech) );
 
154
 
 
155
if(!buffer)
 
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);
 
158
 
 
159
store_reset(rs_point);
 
160
 
 
161
HDEBUG(D_auth) debug_printf("Cyrus SASL driver %s: %s initialised\n", ablock->name, ablock->public_name);
 
162
 
 
163
/* make sure that if we get here then we're allowed to advertise. */
 
164
ablock->server = TRUE;
 
165
 
 
166
sasl_dispose(&conn);
 
167
sasl_done();
 
168
}
 
169
 
 
170
/*************************************************
 
171
*             Server entry point                 *
 
172
*************************************************/
 
173
 
 
174
/* For interface, see auths/README */
 
175
 
 
176
/* note, we don't care too much about memory allocation in this, because this is entirely
 
177
 * within a shortlived child
 
178
 */
 
179
 
 
180
int
 
181
auth_cyrus_sasl_server(auth_instance *ablock, uschar *data)
 
182
{
 
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}};
 
188
sasl_conn_t *conn;
 
189
int rc, firsttime=1, clen;
 
190
unsigned int inlen, outlen;
 
191
 
 
192
input=data;
 
193
inlen=Ustrlen(data);
 
194
 
 
195
HDEBUG(D_auth) debug=string_copy(data);
 
196
 
 
197
hname=expand_string(ob->server_hostname);
 
198
if(hname == NULL)
 
199
  {
 
200
  auth_defer_msg = expand_string_message;
 
201
  return DEFER;
 
202
  }
 
203
 
 
204
if(inlen)
 
205
  {
 
206
  clen=auth_b64decode(input, &clear);
 
207
  if(clen < 0)
 
208
    {
 
209
    return BAD64;
 
210
    }
 
211
  input=clear;
 
212
  inlen=clen;
 
213
  }
 
214
 
 
215
rc=sasl_server_init(cbs, "exim");
 
216
if (rc != SASL_OK)
 
217
  {
 
218
  auth_defer_msg = US"couldn't initialise Cyrus SASL library";
 
219
  return DEFER;
 
220
  }
 
221
 
 
222
rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL,
 
223
  NULL, NULL, 0, &conn);
 
224
 
 
225
if( rc != SASL_OK )
 
226
  {
 
227
  auth_defer_msg = US"couldn't initialise Cyrus SASL connection";
 
228
  sasl_done();
 
229
  return DEFER;
 
230
  }
 
231
 
 
232
rc=SASL_CONTINUE;
 
233
 
 
234
while(rc==SASL_CONTINUE)
 
235
  {
 
236
  if(firsttime)
 
237
    {
 
238
    firsttime=0;
 
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);
 
242
    }
 
243
  else
 
244
    {
 
245
    /* make sure that we have a null-terminated string */
 
246
    out2=store_get(outlen+1);
 
247
    memcpy(out2,output,outlen);
 
248
    out2[outlen]='\0';
 
249
    if((rc=auth_get_data(&input, out2, outlen))!=OK)
 
250
      {
 
251
      /* we couldn't get the data, so free up the library before
 
252
       * returning whatever error we get */
 
253
      sasl_dispose(&conn);
 
254
      sasl_done();
 
255
      return rc;
 
256
      }
 
257
    inlen=Ustrlen(input);
 
258
 
 
259
    HDEBUG(D_auth) debug=string_copy(input);
 
260
    if(inlen)
 
261
      {
 
262
      clen=auth_b64decode(input, &clear);
 
263
      if(clen < 0)
 
264
       {
 
265
        sasl_dispose(&conn);
 
266
        sasl_done();
 
267
       return BAD64;
 
268
       }
 
269
      input=clear;
 
270
      inlen=clen;
 
271
      }
 
272
 
 
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);
 
275
    }
 
276
  if(rc==SASL_BADPROT)
 
277
    {
 
278
    sasl_dispose(&conn);
 
279
    sasl_done();
 
280
    return UNEXPECTED;
 
281
    }
 
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
 
286
       || rc==SASL_NOUSER   )
 
287
    {
 
288
    /* these are considered permanent failure codes */
 
289
    HDEBUG(D_auth)
 
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));
 
294
    sasl_dispose(&conn);
 
295
    sasl_done();
 
296
    return FAIL;
 
297
    }
 
298
  else if(rc==SASL_NOMECH)
 
299
    {
 
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...
 
303
     */
 
304
    HDEBUG(D_auth)
 
305
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
 
306
    auth_defer_msg =
 
307
        string_sprintf("Cyrus SASL: mechanism %s not available", ob->server_mech);
 
308
    sasl_dispose(&conn);
 
309
    sasl_done();
 
310
    return DEFER;
 
311
    }
 
312
  else if(!(rc==SASL_OK || rc==SASL_CONTINUE))
 
313
    {
 
314
    /* Anything else is a temporary failure, and we'll let SASL print out
 
315
     * the error string for us
 
316
     */
 
317
    HDEBUG(D_auth)
 
318
      debug_printf("Cyrus SASL temporary failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
 
319
    auth_defer_msg =
 
320
        string_sprintf("Cyrus SASL: %s", sasl_errstring(rc, NULL, NULL));
 
321
    sasl_dispose(&conn);
 
322
    sasl_done();
 
323
    return DEFER;
 
324
    }
 
325
  else if(rc==SASL_OK)
 
326
    {
 
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]);
 
331
    expand_nmax=1;
 
332
 
 
333
    HDEBUG(D_auth)
 
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 */
 
336
    sasl_dispose(&conn);
 
337
    sasl_done();
 
338
    return OK;
 
339
    }
 
340
  }
 
341
/* NOTREACHED */
 
342
return 0;  /* Stop compiler complaints */
 
343
}
 
344
 
 
345
/*************************************************
 
346
*              Client entry point                *
 
347
*************************************************/
 
348
 
 
349
/* For interface, see auths/README */
 
350
 
 
351
int
 
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 */
 
359
{
 
360
/* We don't support clients (yet) in this implementation of cyrus_sasl */
 
361
return FAIL;
 
362
}
 
363
 
 
364
#endif  /* AUTH_CYRUS_SASL */
 
365
 
 
366
/* End of cyrus_sasl.c */