~ubuntu-branches/ubuntu/oneiric/jabberd2/oneiric

« back to all changes in this revision

Viewing changes to sx/sasl_scod.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2009-05-12 11:47:53 UTC
  • mfrom: (1.1.4 upstream) (0.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090512114753-jss6vqygkgnvtpbv
Tags: 2.2.8-1ubuntu1
* Merge from debian unstable, remaining changes:
 - debian/control:
    + Added Conflicts and Replaces: ..., jabber for jabberd2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * jabberd - Jabber Open Source Server
3
 
 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4
 
 *                    Ryan Eatmon, Robert Norris
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19
 
 */
20
 
 
21
 
/* SASL authentication handler */
22
 
 
23
 
#error SCOD implementation is currently broken. If you have the guts, please fix it and share your changes.
24
 
 
25
 
#include "sx.h"
26
 
#include "sasl.h"
27
 
#include "sx/scod/scod.h"
28
 
 
29
 
/** our context */
30
 
typedef struct _sx_sasl_st {
31
 
    scod_ctx_t                  scod_ctx;
32
 
 
33
 
    sx_sasl_callback_t          cb;
34
 
    void                        *cbarg;
35
 
 
36
 
    int                         flags;
37
 
} *_sx_sasl_t;
38
 
 
39
 
/* mechanisms to offer */
40
 
#define SX_SASL_MECH_ANONYMOUS  (1<<4)
41
 
#define SX_SASL_MECH_PLAIN      (1<<5)
42
 
#define SX_SASL_MECH_DIGESTMD5  (1<<6)
43
 
 
44
 
/** move the stream to the auth state */
45
 
void _sx_sasl_open(sx_t s, scod_t sd) {
46
 
    char *method;
47
 
    
48
 
    /* get the method */
49
 
    method = (char *) malloc(sizeof(char) * (strlen(sd->mech->name) + 6));
50
 
    sprintf(method, "SASL/%s", sd->mech->name);
51
 
 
52
 
    /* schwing! */
53
 
    sx_auth(s, method, sd->authzid);
54
 
 
55
 
    free(method);
56
 
}
57
 
 
58
 
/** make the stream suthenticated second time round */
59
 
static void _sx_sasl_stream(sx_t s, sx_plugin_t p) {
60
 
    scod_t sd = (scod_t) s->plugin_data[p->index];
61
 
 
62
 
    /* do nothing the first time */
63
 
    if(sd == NULL)
64
 
        return;
65
 
 
66
 
    /* are we auth'd? */
67
 
    if(!sd->authd) {
68
 
        _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet");
69
 
        return;
70
 
    }
71
 
 
72
 
    /* otherwise, its auth time */
73
 
    _sx_sasl_open(s, sd);
74
 
}
75
 
 
76
 
static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) {
77
 
    _sx_sasl_t ctx = (_sx_sasl_t) p->private;
78
 
    scod_t sd = (scod_t) s->plugin_data[p->index];
79
 
    int i, ns;
80
 
 
81
 
    if(s->type != type_SERVER)
82
 
        return;
83
 
 
84
 
    if(sd != NULL && sd->authd) {
85
 
        _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms");
86
 
        return;
87
 
    }
88
 
 
89
 
    if(!(s->flags & SX_SASL_OFFER)) {
90
 
        _sx_debug(ZONE, "application didn't ask us to offer sasl, so we won't");
91
 
        return;
92
 
    }
93
 
 
94
 
    if(!(s->flags & SX_SASL_MECH_ANONYMOUS || s->flags & SX_SASL_MECH_PLAIN || s->flags & SX_SASL_MECH_DIGESTMD5)) {
95
 
        _sx_debug(ZONE, "application didn't provide any mechanisms we can offer");
96
 
        return;
97
 
    }
98
 
 
99
 
#ifdef HAVE_SSL
100
 
    if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) {
101
 
        _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms");
102
 
        return;
103
 
    }
104
 
#endif
105
 
    
106
 
    _sx_debug(ZONE, "offering sasl mechanisms");
107
 
    
108
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
109
 
    nad_append_elem(nad, ns, "mechanisms", 1);
110
 
 
111
 
    for(i = 0; i < ctx->scod_ctx->nmechs; i++)
112
 
        if(ctx->scod_ctx->mechs[i]->flags == 0 || ctx->flags & ctx->scod_ctx->mechs[i]->flags) {
113
 
            if((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", ctx->scod_ctx->names[i]) == 0) ||
114
 
               (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", ctx->scod_ctx->names[i]) == 0) ||
115
 
               (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", ctx->scod_ctx->names[i]) == 0)) {
116
 
                _sx_debug(ZONE, "offering mechanism: %s", ctx->scod_ctx->names[i]);
117
 
 
118
 
                nad_append_elem(nad, ns, "mechanism", 2);
119
 
                nad_append_cdata(nad, ctx->scod_ctx->names[i], strlen(ctx->scod_ctx->names[i]), 3);
120
 
            }
121
 
        }
122
 
}
123
 
 
124
 
/** utility: generate a success nad */
125
 
static nad_t _sx_sasl_success(sx_t s) {
126
 
    nad_t nad;
127
 
    int ns;
128
 
 
129
 
    nad = nad_new(s->nad_cache);
130
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
131
 
 
132
 
    nad_append_elem(nad, ns, "success", 0);
133
 
 
134
 
    return nad;
135
 
}
136
 
 
137
 
/** utility: generate a failure nad */
138
 
static nad_t _sx_sasl_failure(sx_t s, const char *err) {
139
 
    nad_t nad;
140
 
    int ns;
141
 
 
142
 
    nad = nad_new(s->nad_cache);
143
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
144
 
 
145
 
    nad_append_elem(nad, ns, "failure", 0);
146
 
    if(err != NULL)
147
 
        nad_append_elem(nad, ns, err, 1);
148
 
 
149
 
    return nad;
150
 
}
151
 
 
152
 
/** utility: generate a challenge nad */
153
 
static nad_t _sx_sasl_challenge(sx_t s, char *data, int dlen) {
154
 
    nad_t nad;
155
 
    int ns;
156
 
 
157
 
    nad = nad_new(s->nad_cache);
158
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
159
 
 
160
 
    nad_append_elem(nad, ns, "challenge", 0);
161
 
    if(data != NULL)
162
 
        nad_append_cdata(nad, data, dlen, 1);
163
 
 
164
 
    return nad;
165
 
}
166
 
 
167
 
/** utility: generate a response nad */
168
 
static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) {
169
 
    nad_t nad;
170
 
    int ns;
171
 
 
172
 
    nad = nad_new(s->nad_cache);
173
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
174
 
 
175
 
    nad_append_elem(nad, ns, "response", 0);
176
 
    if(data != NULL)
177
 
        nad_append_cdata(nad, data, dlen, 1);
178
 
 
179
 
    return nad;
180
 
}
181
 
 
182
 
/** utility: generate an abort nad */
183
 
static nad_t _sx_sasl_abort(sx_t s) {
184
 
    nad_t nad;
185
 
    int ns;
186
 
 
187
 
    nad = nad_new(s->nad_cache);
188
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
189
 
 
190
 
    nad_append_elem(nad, ns, "abort", 0);
191
 
 
192
 
    return nad;
193
 
}
194
 
 
195
 
/** utility: decode incoming handshake data */
196
 
static void _sx_sasl_decode(char *in, int inlen, char **out, int *outlen) {
197
 
    *outlen = apr_base64_decode_len(in, inlen);
198
 
    *out = (char *) malloc(sizeof(char) * (*outlen + 1));
199
 
    apr_base64_decode(*out, in, inlen);
200
 
}
201
 
 
202
 
/** utility: encode outgoing handshake data */
203
 
static void _sx_sasl_encode(char *in, int inlen, char **out, int *outlen) {
204
 
    *outlen = apr_base64_encode_len(inlen);
205
 
    *out = (char *) malloc(sizeof(char) * *outlen);
206
 
    apr_base64_encode(*out, in, inlen);
207
 
    (*outlen)--;
208
 
}
209
 
 
210
 
/** auth done, restart the stream */
211
 
static void _sx_sasl_notify_success(sx_t s, void *arg) {
212
 
    _sx_debug(ZONE, "auth completed, resetting");
213
 
 
214
 
    _sx_reset(s);
215
 
 
216
 
    sx_server_init(s, s->flags);
217
 
}
218
 
 
219
 
/** process handshake packets from the client */
220
 
static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, scod_t sd, char *mech, char *in, int inlen) {
221
 
    _sx_sasl_t ctx = (_sx_sasl_t) p->private;
222
 
    char realm[256];
223
 
    char *buf = NULL, *out = NULL;
224
 
    int buflen, outlen, ret;
225
 
 
226
 
    if(mech != NULL) {
227
 
        _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech);
228
 
 
229
 
        if(!((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", mech) == 0) ||
230
 
             (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", mech) == 0) ||
231
 
             (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", mech) == 0))) {
232
 
             _sx_debug(ZONE, "client requested mechanism that we didn't offer");
233
 
             _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0);
234
 
             return;
235
 
        }
236
 
 
237
 
        /* startup */
238
 
        sd = scod_new(ctx->scod_ctx, sd_type_SERVER);
239
 
        if(sd == NULL) {
240
 
            _sx_debug(ZONE, "scod_new failed, no sasl for this conn");
241
 
            _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0);
242
 
            return;
243
 
        }
244
 
 
245
 
        _sx_debug(ZONE, "sasl context initialised for %d", s->tag);
246
 
 
247
 
        s->plugin_data[p->index] = (void *) sd;
248
 
 
249
 
        sd->app_private = (void *) s;
250
 
 
251
 
        /* get the realm */
252
 
        realm[0] = '\0';
253
 
        assert((ctx->cb != NULL));
254
 
        (ctx->cb)(sx_sasl_cb_GET_REALM, (void *) s, (void **) realm, s, ctx->cbarg);
255
 
 
256
 
        /* decode and process */
257
 
        _sx_sasl_decode(in, inlen, &buf, &buflen);
258
 
        ret = scod_server_start(sd, mech, realm, buf, buflen, &out, &outlen);
259
 
    }
260
 
 
261
 
    else {
262
 
        /* decode and process */
263
 
        _sx_sasl_decode(in, inlen, &buf, &buflen);
264
 
        if(!sd) {
265
 
            _sx_debug(ZONE, "response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
266
 
            _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MECH_TOO_WEAK), 0);
267
 
            if(buf != NULL) free(buf);
268
 
            return;
269
 
        }
270
 
        _sx_debug(ZONE, "response from client (decoded: %.*s)", buflen, buf);
271
 
        ret = scod_server_step(sd, buf, buflen, &out, &outlen);
272
 
    }
273
 
 
274
 
    if(buf != NULL) free(buf);
275
 
 
276
 
    /* auth completed */
277
 
    if(ret == sd_SUCCESS) {
278
 
        _sx_debug(ZONE, "sasl handshake completed");
279
 
 
280
 
        if(out != NULL) free(out);
281
 
 
282
 
        /* send success */
283
 
        _sx_nad_write(s, _sx_sasl_success(s), 0);
284
 
 
285
 
        /* set a notify on the success nad buffer */
286
 
        ((sx_buf_t) s->wbufq->front->data)->notify = _sx_sasl_notify_success;
287
 
        ((sx_buf_t) s->wbufq->front->data)->notify_arg = (void *) p;
288
 
 
289
 
        return;
290
 
    }
291
 
 
292
 
    /* in progress */
293
 
    if(ret == sd_CONTINUE) {
294
 
        _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out);
295
 
 
296
 
        /* encode the challenge */
297
 
        _sx_sasl_encode(out, outlen, &buf, &buflen);
298
 
        
299
 
        if(out != NULL) free(out);
300
 
 
301
 
        _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0);
302
 
 
303
 
        free(buf);
304
 
 
305
 
        return;
306
 
    }
307
 
 
308
 
    if(out != NULL) free(out);
309
 
 
310
 
    /* its over */
311
 
    _sx_debug(ZONE, "sasl handshake failed: (%d)", ret);
312
 
 
313
 
    /* !!! check ret and flag error appropriately */
314
 
    _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MALFORMED_REQUEST), 0);
315
 
}
316
 
 
317
 
/** process handshake packets from the server */
318
 
static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, scod_t sd, char *in, int inlen) {
319
 
    char *buf, *out;
320
 
    int buflen, outlen, ret;
321
 
 
322
 
    _sx_debug(ZONE, "challenge from client");
323
 
 
324
 
    /* decode the response */
325
 
    _sx_sasl_decode(in, inlen, &buf, &buflen);
326
 
 
327
 
    /* process the data */
328
 
    ret = scod_client_step(sd, buf, buflen, &out, &outlen);
329
 
    if(buf != NULL) free(buf);
330
 
 
331
 
    /* in progress */
332
 
    if(ret == sd_SUCCESS || ret == sd_CONTINUE) {
333
 
        _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out);
334
 
 
335
 
        /* encode the response */
336
 
        _sx_sasl_encode(out, outlen, &buf, &buflen);
337
 
 
338
 
        if(out != NULL) free(out);
339
 
 
340
 
        _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0);
341
 
 
342
 
        if(buf != NULL) free(buf);
343
 
 
344
 
        return;
345
 
    }
346
 
 
347
 
    if(out != NULL) free(out);
348
 
 
349
 
    /* its over */
350
 
    _sx_debug(ZONE, "sasl handshake aborted: (%d)", ret);
351
 
 
352
 
    _sx_nad_write(s, _sx_sasl_abort(s), 0);
353
 
}
354
 
 
355
 
/** main nad processor */
356
 
static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) {
357
 
    scod_t sd = (scod_t) s->plugin_data[p->index];
358
 
    int attr;
359
 
    char mech[128];
360
 
    sx_error_t sxe;
361
 
    int flags;
362
 
    char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
363
 
 
364
 
    /* only want sasl packets */
365
 
    if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_SASL) || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_SASL, strlen(uri_SASL)) != 0)
366
 
        return 1;
367
 
 
368
 
    /* quietly drop it if sasl is disabled, or if not ready */
369
 
    if(s->state != state_STREAM) {
370
 
        _sx_debug(ZONE, "not correct state for sasl, ignoring");
371
 
        nad_free(nad);
372
 
        return 0;
373
 
    }
374
 
 
375
 
    /* packets from the client */
376
 
    if(s->type == type_SERVER) {
377
 
        if(!(s->flags & SX_SASL_OFFER)) {
378
 
            _sx_debug(ZONE, "they tried to do sasl, but we never offered it, ignoring");
379
 
            nad_free(nad);
380
 
            return 0;
381
 
        }
382
 
 
383
 
#ifdef HAVE_SSL
384
 
        if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) {
385
 
            _sx_debug(ZONE, "they tried to do sasl, but they have to do starttls first, ignoring");
386
 
            nad_free(nad);
387
 
            return 0;
388
 
        }
389
 
#endif
390
 
 
391
 
        /* auth */
392
 
        if(NAD_ENAME_L(nad, 0) == 4 && strncmp("auth", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
393
 
            /* require mechanism */
394
 
            if((attr = nad_find_attr(nad, 0, -1, "mechanism", NULL)) < 0) {
395
 
                _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0);
396
 
                nad_free(nad);
397
 
                return 0;
398
 
            }
399
 
 
400
 
            /* extract */
401
 
            snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
402
 
 
403
 
            /* go */
404
 
            _sx_sasl_client_process(s, p, sd, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
405
 
 
406
 
            nad_free(nad);
407
 
            return 0;
408
 
        }
409
 
 
410
 
        /* response */
411
 
        else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
412
 
            /* process it */
413
 
            _sx_sasl_client_process(s, p, sd, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
414
 
 
415
 
            nad_free(nad);
416
 
            return 0;
417
 
        }
418
 
 
419
 
        /* abort */
420
 
        else if(NAD_ENAME_L(nad, 0) == 5 && strncmp("abort", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
421
 
            _sx_debug(ZONE, "sasl handshake aborted");
422
 
 
423
 
            _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_ABORTED), 0);
424
 
 
425
 
            nad_free(nad);
426
 
            return 0;
427
 
        }
428
 
    }
429
 
    
430
 
    /* packets from the server */
431
 
    else if(s->type == type_CLIENT) {
432
 
        if(sd == NULL) {
433
 
            _sx_debug(ZONE, "got sasl client packets, but they never started sasl, ignoring");
434
 
            nad_free(nad);
435
 
            return 0;
436
 
        }
437
 
 
438
 
        /* challenge */
439
 
        if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
440
 
            /* process it */
441
 
            _sx_sasl_server_process(s, p, sd, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
442
 
 
443
 
            nad_free(nad);
444
 
            return 0;
445
 
        }
446
 
 
447
 
        /* success */
448
 
        else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("success", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
449
 
            _sx_debug(ZONE, "sasl handshake completed, resetting");
450
 
            nad_free(nad);
451
 
 
452
 
            /* save interesting bits */
453
 
            flags = s->flags;
454
 
 
455
 
            if(s->ns != NULL) ns = strdup(s->ns);
456
 
 
457
 
            if(s->req_to != NULL) to = strdup(s->req_to);
458
 
            if(s->req_from != NULL) from = strdup(s->req_from);
459
 
            if(s->req_version != NULL) version = strdup(s->req_version);
460
 
 
461
 
            /* reset state */
462
 
            _sx_reset(s);
463
 
 
464
 
            _sx_debug(ZONE, "restarting stream with sasl layer established");
465
 
 
466
 
            /* second time round */
467
 
            sx_client_init(s, flags, ns, to, from, version);
468
 
 
469
 
            /* free bits */
470
 
            if(ns != NULL) free(ns);
471
 
            if(to != NULL) free(to);
472
 
            if(from != NULL) free(from);
473
 
            if(version != NULL) free(version);
474
 
 
475
 
            return 0;
476
 
        }
477
 
 
478
 
        /* failure */
479
 
        else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("failure", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
480
 
            /* fire the error */
481
 
            _sx_gen_error(sxe, SX_ERR_AUTH, "Authentication failed", NULL);
482
 
            _sx_event(s, event_ERROR, (void *) &sxe);
483
 
 
484
 
            /* cleanup */
485
 
            scod_free(sd);
486
 
 
487
 
            s->plugin_data[p->index] = NULL;
488
 
 
489
 
            nad_free(nad);
490
 
            return 0;
491
 
        }
492
 
    }
493
 
 
494
 
    /* invalid sasl command, quietly drop it */
495
 
    _sx_debug(ZONE, "unknown sasl command '%.*s', ignoring", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0));
496
 
 
497
 
    nad_free(nad);
498
 
    return 0;
499
 
}
500
 
 
501
 
/** cleanup */
502
 
static void _sx_sasl_free(sx_t s, sx_plugin_t p) {
503
 
    scod_t sd = (scod_t) s->plugin_data[p->index];
504
 
 
505
 
    if(sd == NULL)
506
 
        return;
507
 
 
508
 
    _sx_debug(ZONE, "cleaning up conn state");
509
 
 
510
 
    scod_free(sd);
511
 
    s->plugin_data[p->index] = NULL;
512
 
}
513
 
 
514
 
static int _sx_sasl_scod_callback(scod_t sd, int cb, void *arg, void **res, void *cbarg) {
515
 
    _sx_sasl_t ctx = (_sx_sasl_t) cbarg;
516
 
    xht realms;
517
 
 
518
 
    switch(cb) {
519
 
        case sd_cb_DIGEST_MD5_CHOOSE_REALM:
520
 
            realms = (xht) arg;
521
 
            if(xhash_iter_first(realms))
522
 
                xhash_iter_get(realms, (const char **) res, NULL);
523
 
            else
524
 
                *res = NULL;
525
 
            break;
526
 
 
527
 
        case sd_cb_GET_PASS:
528
 
            assert((ctx->cb != NULL));
529
 
            return (ctx->cb)(sx_sasl_cb_GET_PASS, arg, res, NULL, ctx->cbarg);
530
 
 
531
 
        case sd_cb_CHECK_PASS:
532
 
            assert((ctx->cb != NULL));
533
 
            return (ctx->cb)(sx_sasl_cb_CHECK_PASS, arg, res, NULL, ctx->cbarg);
534
 
 
535
 
        case sd_cb_CHECK_AUTHZID:
536
 
            assert((ctx->cb != NULL));
537
 
            return (ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, arg, res, NULL, ctx->cbarg);
538
 
 
539
 
        case sd_cb_ANONYMOUS_GEN_AUTHZID:
540
 
            assert((ctx->cb != NULL));
541
 
            return (ctx->cb)(sx_sasl_cb_GEN_AUTHZID, arg, res, NULL, ctx->cbarg);
542
 
 
543
 
        default:
544
 
            break;
545
 
    }
546
 
 
547
 
    return 0;
548
 
}
549
 
 
550
 
static void _sx_sasl_unload(sx_plugin_t p) {
551
 
    scod_ctx_free( ((_sx_sasl_t) p->private)->scod_ctx);
552
 
    free(p->private);
553
 
}
554
 
 
555
 
/** args: realm callback, cb arg, scod flags */
556
 
int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) {
557
 
    sx_sasl_callback_t cb;
558
 
    void *cbarg;
559
 
    int flags;
560
 
    _sx_sasl_t ctx;
561
 
 
562
 
    _sx_debug(ZONE, "initialising sasl plugin");
563
 
 
564
 
    cb = va_arg(args, sx_sasl_callback_t);
565
 
    cbarg = va_arg(args, void *);
566
 
    flags = va_arg(args, int);
567
 
 
568
 
    ctx = (_sx_sasl_t) calloc(1, sizeof(struct _sx_sasl_st));
569
 
 
570
 
    ctx->cb = cb;
571
 
    ctx->cbarg = cbarg;
572
 
    ctx->flags = flags;
573
 
 
574
 
    ctx->scod_ctx = scod_ctx_new(_sx_sasl_scod_callback, ctx);
575
 
    if(ctx->scod_ctx == NULL) {
576
 
        _sx_debug(ZONE, "couldn't create scod context, disabling");
577
 
        free(ctx);
578
 
        return 1;
579
 
    }
580
 
 
581
 
    _sx_debug(ZONE, "sasl context initialised");
582
 
 
583
 
    p->private = (void *) ctx;
584
 
 
585
 
    p->unload = _sx_sasl_unload;
586
 
 
587
 
    p->stream = _sx_sasl_stream;
588
 
    p->features = _sx_sasl_features;
589
 
    p->process = _sx_sasl_process;
590
 
 
591
 
    p->free = _sx_sasl_free;
592
 
 
593
 
    return 0;
594
 
}
595
 
 
596
 
/** kick off the auth handshake */
597
 
int sx_sasl_auth(sx_plugin_t p, sx_t s, char *appname, char *mech, char *user, char *pass) {
598
 
    _sx_sasl_t ctx = (_sx_sasl_t) p->private;
599
 
    scod_t sd;
600
 
    char *buf, *out;
601
 
    int ret, buflen, outlen, ns;
602
 
    nad_t nad;
603
 
 
604
 
    assert((p != NULL));
605
 
    assert((s != NULL));
606
 
    assert((mech != NULL));
607
 
    assert((user != NULL));
608
 
    assert((pass != NULL));
609
 
 
610
 
    if(s->type != type_CLIENT || s->state != state_STREAM) {
611
 
        _sx_debug(ZONE, "need client in stream state for sasl auth");
612
 
        return 1;
613
 
     }
614
 
    
615
 
    /* startup */
616
 
    sd = scod_new(ctx->scod_ctx, sd_type_CLIENT);
617
 
    if(sd == NULL) {
618
 
        _sx_debug(ZONE, "couldn't create scod instance, not authing");
619
 
        return 1;
620
 
    }
621
 
 
622
 
    /* handshake start */
623
 
    ret = scod_client_start(sd, mech, user, user, pass, &out, &outlen);
624
 
    if(ret != sd_SUCCESS && ret != sd_CONTINUE) {
625
 
        _sx_debug(ZONE, "scod_client_start failed (%d), not authing", ret);
626
 
 
627
 
        if(out != NULL) free(out);
628
 
        
629
 
        scod_free(sd);
630
 
 
631
 
        return 1;
632
 
    }
633
 
 
634
 
    /* save userdata */
635
 
    s->plugin_data[p->index] = (void *) sd;
636
 
 
637
 
    /* in progress */
638
 
    _sx_debug(ZONE, "sending auth request to server, mech '%s': %.*s", mech, outlen, out);
639
 
 
640
 
    /* encode the challenge */
641
 
    _sx_sasl_encode(out, outlen, &buf, &buflen);
642
 
    free(out);
643
 
 
644
 
    /* build the nad */
645
 
    nad = nad_new(s->nad_cache);
646
 
    ns = nad_add_namespace(nad, uri_SASL, NULL);
647
 
 
648
 
    nad_append_elem(nad, ns, "auth", 0);
649
 
    nad_append_attr(nad, -1, "mechanism", mech);
650
 
    if(buf != NULL) {
651
 
        nad_append_cdata(nad, buf, buflen, 1);
652
 
        free(buf);
653
 
    }
654
 
 
655
 
    /* its away */
656
 
    sx_nad_write(s, nad);
657
 
 
658
 
    return 0;
659
 
}