jabberd2  2.2.17
sasl_cyrus.c
Go to the documentation of this file.
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 Cyrus SASL implementation is not supported! It is included here only for the brave ones, that do know what they are doing. You need to remove this line to compile it.
24 
25 #include "sx.h"
26 #include "sasl.h"
27 
28 /* Gack - need this otherwise SASL's MD5 definitions conflict with OpenSSLs */
29 #ifdef HEADER_MD5_H
30 # define MD5_H
31 #endif
32 #ifdef _WIN32
33 # include <sasl.h>
34 # include <saslutil.h>
35 # include <saslplug.h>
36 #else /* _WIN32 */
37 # include <sasl/sasl.h>
38 # include <sasl/saslutil.h>
39 # include <sasl/saslplug.h>
40 #endif /* _WIN32 */
41 
43 typedef struct _sx_sasl_st {
44  char *appname;
45  sasl_security_properties_t sec_props;
46 
48  void *cbarg;
49 
50  sasl_callback_t *saslcallbacks;
51 } *_sx_sasl_t;
52 
53 /* data for per-conncetion sasl handshakes */
54 typedef struct _sx_sasl_data_st {
55  char *user;
56  sasl_secret_t *psecret;
57 
58  sasl_callback_t *callbacks;
59 
61  sasl_conn_t *sasl;
64 
65 
66 /* Forward definitions */
67 static void _sx_sasl_free(sx_t, sx_plugin_t);
68 
69 static int _sx_sasl_getopt(void * glob_context,
70  const char *plugin_name,
71  const char *option,
72  const char **result,
73  unsigned *len)
74 {
75  if (strcmp(option,"auxprop_plugin") == 0) {
76  *result = "jabberdsx";
77  if (len)
78  *len = strlen("jabberdsx");
79  return SASL_OK;
80  }
81  return SASL_FAIL;
82 }
83 
84 #ifdef _WIN32
85 /* This handles returning library path on Windows to current directory.
86  */
87 #include <windows.h>
88 static int _sx_sasl_getpath(void *glob_context, const char **path_dest) {
89  static char win32_path[MAX_PATH] = "\0";
90 
91  if(!path_dest) {
92  return SASL_BADPARAM;
93  }
94 
95  if(!*win32_path) {
96  char *r;
97  GetModuleFileName(NULL, win32_path, MAX_PATH - 5);
98  if(!*win32_path || !(r = strrchr(win32_path, '\\')))
99  return SASL_NOMEM;
100  strcpy(r + 1, "sasl");
101  }
102 
103  *path_dest = win32_path;
104  return SASL_OK;
105 }
106 #endif /* _WIN32 */
107 
108 /* Support auxprop so that we can use the standard Jabber authreg plugins
109  * with SASL mechanisms requiring passwords
110  */
111 static void _sx_auxprop_lookup(void *glob_context,
112  sasl_server_params_t *sparams,
113  unsigned flags,
114  const char *user,
115  unsigned ulen) {
116  const char *realm = NULL;
117  char *c;
118  const struct propval *to_fetch, *current;
119  char *user_buf = NULL;
120  char *value;
121  _sx_sasl_t ctx = (_sx_sasl_t) glob_context;
122  struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL};
123 
124  if (!sparams || !user)
125  return;
126 
127  /* It would appear that there's no guarantee that 'user' is NULL
128  * terminated, so we'd better terminate it ...
129  */
130 
131  user_buf = sparams->utils->malloc(ulen + 1);
132  if (!user_buf)
133  goto done;
134 
135  memcpy(user_buf, user, ulen);
136  user_buf[ulen] = '\0';
137 
138  c = strchr(user_buf, '@');
139  if (!c) {
140  if (sparams->user_realm && sparams->user_realm[0])
141  realm = sparams->user_realm;
142  else
143  realm = sparams->serverFQDN;
144  } else {
145  *c = '\0';
146  realm = c+1;
147  }
148 
149  /* At present, we only handle fetching the user's password */
150  to_fetch = sparams->utils->prop_get(sparams->propctx);
151  if (!to_fetch)
152  goto done;
153  for (current = to_fetch; current->name; current++) {
154  if (strncmp(current->name, SASL_AUX_PASSWORD, sizeof(SASL_AUX_PASSWORD)) == 0) {
155  /* If we've already got a value, see if we can override it */
156  if (current->values) {
157  if (flags & SASL_AUXPROP_OVERRIDE)
158  sparams->utils->prop_erase(sparams->propctx, current->name);
159  else
160  continue;
161  }
162 
163  creds.authnid = user_buf;
164  creds.realm = realm;
165  if ((ctx->cb)(sx_sasl_cb_GET_PASS, &creds, (void **)&value,
166  NULL, ctx->cbarg) == sx_sasl_ret_OK) {
167  sparams->utils->prop_set(sparams->propctx, current->name,
168  value, strlen(value));
169  }
170  }
171  }
172  done:
173  if (user_buf) sparams->utils->free(user_buf);
174 }
175 
176 static sasl_auxprop_plug_t _sx_auxprop_plugin =
177  {0, 0, NULL, NULL, _sx_auxprop_lookup, "jabberdsx", NULL};
178 
179 static int
180 sx_auxprop_init(const sasl_utils_t *utils, int max_version, int *out_version,
181  sasl_auxprop_plug_t **plug, const char *plugname) {
182 
183  if (!out_version || !plug)
184  return SASL_BADPARAM;
185  if (max_version < SASL_AUXPROP_PLUG_VERSION )
186  return SASL_BADVERS;
187 
188  *out_version = SASL_AUXPROP_PLUG_VERSION;
189  *plug = &_sx_auxprop_plugin;
190 
191  return SASL_OK;
192 }
193 
194 /* This handles those authreg plugins which won't provide plaintext access
195  * to the user's password. Note that there are very few mechanisms which
196  * call the verify function, rather than asking for the password
197  */
198 static int _sx_sasl_checkpass(sasl_conn_t *conn, void *ctx, const char *user, const char *pass, unsigned passlen, struct propctx *propctx) {
200  struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL};
201  char *c;
202  char *buf;
203 
204  /* SASL doesn't seem to pass us the username and realm as seperate items,
205  * instead it combines them into the 'user' variable. In order to preserve
206  * the existing behaviour, we need to split them up again ...
207  */
208 
209  buf = strdup(user);
210  c = strchr(buf,'@');
211  if (c) {
212  *c = '\0';
213  creds.realm = c+1;
214  }
215  creds.authnid = buf;
216  creds.pass = pass;
217 
218  if (sd->ctx->cb(sx_sasl_cb_CHECK_PASS, &creds, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) {
219  free(buf);
220  return SASL_OK;
221  } else {
222  free(buf);
223  return SASL_BADAUTH;
224  }
225 }
226 
227 /* Canonicalize the username. Normally this does nothing, but if we're
228  * calling from an anonymous plugin, then we need to generate a JID for
229  * the user
230  */
231 
232 static int _sx_sasl_canon_user(sasl_conn_t *conn, void *ctx, const char *user, unsigned ulen, unsigned flags, const char *user_realm, char *out_user, unsigned out_umax, unsigned *out_ulen) {
233  char *buf;
235  sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf);
236  if (strncmp(buf, "ANONYMOUS", 10) == 0) {
237  sd->ctx->cb(sx_sasl_cb_GEN_AUTHZID, NULL, (void **)&buf, sd->stream, sd->ctx->cbarg);
238  strncpy(out_user, buf, out_umax);
239  out_user[out_umax]='\0';
240  *out_ulen=strlen(out_user);
241  } else {
242  memcpy(out_user,user,ulen);
243  *out_ulen = ulen;
244  }
245  return SASL_OK;
246 }
247 
248 /* Need to make sure that
249  * *) The authnid is permitted to become the given authzid
250  * *) The authnid is included in the given authreg systems DB
251  */
252 static int _sx_sasl_proxy_policy(sasl_conn_t *conn, void *ctx, const char *requested_user, int rlen, const char *auth_identity, int alen, const char *realm, int urlen, struct propctx *propctx) {
253  _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx;
254  struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL};
255  char *buf, *c;
256  size_t len;
257  int ret;
258 
259  sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf);
260  if (strncmp(buf, "ANONYMOUS", 10) == 0) {
261  /* If they're anonymous, their ID comes from us, so it must be OK! */
262  return SASL_OK;
263  } else {
264  /* This will break with clients that give requested user as a JID,
265  * where requested_user != auth_identity */
266  if (!requested_user || !auth_identity || rlen == 0 || alen==0) {
267  sasl_seterror(conn, 0,
268  "Bad identities provided");
269  return SASL_BADAUTH;
270  }
271 
272  /* No guarantee that realm is NULL terminated - so make a terminated
273  * version before we do anything */
274 
275  /* XXX - Do we also need to check if realm contains NULL values,
276  * and complain if it does?
277  */
278 
279  buf = malloc(urlen + 1);
280  strncpy(buf, realm?realm:"", urlen);
281  buf[urlen] = '\0';
282  creds.realm = buf;
283 
284  /* By this point, SASL's default canon_user plugin has appended the
285  * realm to both the auth_identity, and the requested_user. This
286  * isn't what we want.
287  * auth_identity should be a bare username
288  * requested_user should be a JID
289  *
290  * We can't just remove everything after the '@' as some mechanisms
291  * (such as GSSAPI) use the @ to denote users in foreign realms.
292  */
293 
294  buf = malloc(alen + 1);
295  strncpy(buf, auth_identity, alen);
296  buf[alen] = '\0';
297  c = strrchr(buf, '@');
298  if (c && strcmp(c+1, creds.realm) == 0)
299  *c = '\0';
300  creds.authnid = buf;
301 
302  /* Now, we need to turn requested_user into a JID
303  * (if it isn't already)
304  *
305  * XXX - This will break with s2s SASL, where the authzid is a domain
306  */
307  len = rlen;
308  if (sd->stream->req_to)
309  len+=strlen(sd->stream->req_to) + 2;
310  buf = malloc(len + 1);
311  strncpy(buf, requested_user, rlen);
312  buf[rlen] = '\0';
313  c = strrchr(buf, '@');
314  if (c && strcmp(c + 1, creds.realm) == 0)
315  *c = '\0';
316  if (sd->stream->req_to && strchr(buf, '@') == 0) {
317  strcat(buf, "@");
318  strcat(buf, sd->stream->req_to);
319  }
320  creds.authzid = buf;
321 
322  /* If we start being fancy and allow auth_identity to be different from
323  * requested_user, then this will need to be changed to permit it!
324  */
325  ret = (sd->ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, sd->stream, sd->ctx->cbarg);
326 
327  free((void *)creds.authnid);
328  free((void *)creds.authzid);
329  free((void *)creds.realm);
330 
331  if (ret == sx_sasl_ret_OK) {
332  return SASL_OK;
333  } else {
334  sasl_seterror(conn, 0, "Requested identity not permitted for authorization identity");
335  return SASL_BADAUTH;
336  }
337  }
338 }
339 
340 static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) {
341  sasl_conn_t *sasl;
342  int *x, len, pos, reslen, maxbuf;
343  char *out, *result;
344 
345  sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl;
346 
347  /* if there's no security layer, don't bother */
348  sasl_getprop(sasl, SASL_SSF, (const void **) &x);
349  if(*x == 0)
350  return 1;
351 
352  _sx_debug(ZONE, "doing sasl encode");
353 
354  /* can only encode x bytes at a time */
355  sasl_getprop(sasl, SASL_MAXOUTBUF, (const void **) &x);
356  maxbuf = *x;
357 
358  /* encode the output */
359  pos = 0;
360  result = NULL; reslen = 0;
361  while(pos < buf->len) {
362  if((buf->len - pos) < maxbuf)
363  maxbuf = buf->len - pos;
364 
365  sasl_encode(sasl, &buf->data[pos], maxbuf, (const char **) &out, &len);
366 
367  result = (char *) realloc(result, sizeof(char) * (reslen + len));
368  memcpy(&result[reslen], out, len);
369  reslen += len;
370 
371  pos += maxbuf;
372  }
373 
374  /* replace the buffer */
375  _sx_buffer_set(buf, result, reslen, result);
376 
377  _sx_debug(ZONE, "%d bytes encoded for sasl channel", buf->len);
378 
379  return 1;
380 }
381 
382 static int _sx_sasl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) {
383  sasl_conn_t *sasl;
384  sx_error_t sxe;
385  int *x, len;
386  char *out;
387 
388  sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl;
389 
390  /* if there's no security layer, don't bother */
391  sasl_getprop(sasl, SASL_SSF, (const void **) &x);
392  if(*x == 0)
393  return 1;
394 
395  _sx_debug(ZONE, "doing sasl decode");
396 
397  /* decode the input */
398  if (sasl_decode(sasl, buf->data, buf->len, (const char **) &out, &len)
399  != SASL_OK) {
400  /* Fatal error */
401  _sx_gen_error(sxe, SX_ERR_AUTH, "SASL Stream decoding failed", NULL);
402  _sx_event(s, event_ERROR, (void *) &sxe);
403  return -1;
404  }
405 
406  /* replace the buffer */
407  _sx_buffer_set(buf, out, len, NULL);
408 
409  _sx_debug(ZONE, "%d bytes decoded from sasl channel", len);
410 
411  return 1;
412 }
413 
415 void _sx_sasl_open(sx_t s, sasl_conn_t *sasl) {
416  char *method;
417  char *buf, *c;
418  char *authzid;
419  size_t len;
420  int *ssf;
421 
422  /* get the method */
423  sasl_getprop(sasl, SASL_MECHNAME, (const void **) &buf);
424 
425  method = (char *) malloc(sizeof(char) * (strlen(buf) + 17));
426  sprintf(method, "SASL/%s", buf);
427 
428  /* get the ssf */
429  if(s->ssf == 0) {
430  sasl_getprop(sasl, SASL_SSF, (const void **) &ssf);
431  s->ssf = *ssf;
432  }
433 
434  /* and the authenticated id */
435  sasl_getprop(sasl, SASL_USERNAME, (const void **) &buf);
436 
437  if (s->type == type_SERVER) {
438  /* Now, we need to turn the id into a JID
439  * (if it isn't already)
440  *
441  * XXX - This will break with s2s SASL, where the authzid is a domain
442  */
443 
444  len = strlen(buf);
445  if (s->req_to)
446  len+=strlen(s->req_to) + 2;
447  authzid = malloc(len + 1);
448  strcpy(authzid, buf);
449 
450  sasl_getprop(sasl, SASL_DEFUSERREALM, (const void **) &buf);
451 
452  c = strrchr(authzid, '@');
453  if (c && buf && strcmp(c+1, buf) == 0)
454  *c = '\0';
455  if (s->req_to && strchr(authzid, '@') == 0) {
456  strcat(authzid, "@");
457  strcat(authzid, s->req_to);
458  }
459 
460  /* schwing! */
461  sx_auth(s, method, authzid);
462  free(authzid);
463  } else {
464  sx_auth(s, method, buf);
465  }
466 
467  free(method);
468 }
469 
471 static void _sx_sasl_stream(sx_t s, sx_plugin_t p) {
472  _sx_sasl_t ctx = (_sx_sasl_t) p->private;
473  sasl_conn_t *sasl;
474  _sx_sasl_data_t sd;
475  int ret, i;
476  char *realm = NULL, *ext_id, *mech;
477  sasl_security_properties_t sec_props;
478 
479  /* First time around, we need to set up our SASL connection, otherwise
480  * features will fall flat on its face */
481  if (s->plugin_data[p->index] == NULL) {
482  if(s->type == type_SERVER) {
483 
484  if(!(s->flags & SX_SASL_OFFER)) {
485  _sx_debug(ZONE, "application did not request sasl offer, not offering for this conn");
486  return;
487  }
488 
489  _sx_debug(ZONE, "setting up sasl for this server conn");
490 
491  /* Initialise our data object */
492  sd = (_sx_sasl_data_t) calloc(1, sizeof(struct _sx_sasl_data_st));
493 
494  /* get the realm */
495  if(ctx->cb != NULL)
496  (ctx->cb)(sx_sasl_cb_GET_REALM, NULL, (void **) &realm, s, ctx->cbarg);
497 
498  /* Initialize our callbacks */
499  sd->callbacks = calloc(sizeof(sasl_callback_t),4);
500 
501  sd->callbacks[0].id = SASL_CB_PROXY_POLICY;
502  sd->callbacks[0].proc = &_sx_sasl_proxy_policy;
503  sd->callbacks[0].context = sd;
504 
505  sd->callbacks[1].id = SASL_CB_CANON_USER;
506  sd->callbacks[1].proc = &_sx_sasl_canon_user;
507  sd->callbacks[1].context = sd;
508 
509  sd->callbacks[2].id = SASL_CB_SERVER_USERDB_CHECKPASS;
510  sd->callbacks[2].proc = &_sx_sasl_checkpass;
511  sd->callbacks[2].context = sd;
512 
513  sd->callbacks[3].id = SASL_CB_LIST_END;
514 
515  /* startup */
516  ret = sasl_server_new(ctx->appname, NULL,
517  realm ? (realm[0] == '\0' ? NULL : realm) : NULL,
518  NULL, NULL, sd->callbacks,
519  ctx->sec_props.security_flags, &sasl);
520  if(ret != SASL_OK) {
521  _sx_debug(ZONE, "sasl_server_new failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
522  free(sd->callbacks);
523  free(sd);
524  return;
525  }
526 
527  /* get external data from the ssl plugin */
528  ext_id = NULL;
529 #ifdef HAVE_SSL
530  for(i = 0; i < s->env->nplugins; i++)
531  if(s->env->plugins[i]->magic == SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
532  ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
533 
534  /* if we've got some, setup for external auth */
535  if(ext_id != NULL) {
536  ret = sasl_setprop(sasl, SASL_AUTH_EXTERNAL, ext_id);
537  if(ret == SASL_OK)
538  ret = sasl_setprop(sasl, SASL_SSF_EXTERNAL, &s->ssf);
539  }
540 #endif /* HAVE_SSL */
541 
542  /* security properties */
543  sec_props = ctx->sec_props;
544  if(s->ssf > 0)
545  /* if we're already encrypted, then no security layers */
546  sec_props.max_ssf = 0;
547 
548  if(ret == SASL_OK)
549  ret = sasl_setprop(sasl, SASL_SEC_PROPS, &sec_props);
550 
551  if(ret != SASL_OK) {
552  _sx_debug(ZONE, "sasl_setprop failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
553  free(sd->callbacks);
554  free(sd);
555  return;
556  }
557 
558  sd->sasl = sasl;
559  sd->stream = s;
560  sd->ctx = ctx;
561 
562  _sx_debug(ZONE, "sasl context initialised for %d", s->tag);
563 
564  s->plugin_data[p->index] = (void *) sd;
565 
566  }
567 
568  return;
569  }
570 
571  sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl;
572 
573  /* are we auth'd? */
574  if (sasl_getprop(sasl, SASL_MECHNAME, (void *) &mech) == SASL_NOTDONE) {
575  _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet");
576  return;
577  }
578 
579  /* otherwise, its auth time */
580  _sx_sasl_open(s, sasl);
581 }
582 
583 static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) {
585  int ret, nmechs, ns;
586  char *mechs, *mech, *c;
587 
588  if(s->type != type_SERVER || sd == NULL || sd->sasl == NULL)
589  return;
590 
591  if((ret = sasl_getprop(sd->sasl, SASL_MECHNAME, (void *) &mech)) != SASL_NOTDONE) {
592  _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms");
593  return;
594  }
595 
596  if(!(s->flags & SX_SASL_OFFER)) {
597  _sx_debug(ZONE, "application didn't ask us to offer sasl, so we won't");
598  return;
599  }
600 
601 #ifdef HAVE_SSL
602  if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) {
603  _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms");
604  return;
605  }
606 #endif
607 
608  _sx_debug(ZONE, "offering sasl mechanisms");
609 
610  ret = sasl_listmech(sd->sasl, NULL, "", "|", "", (const char **) &mechs, NULL, &nmechs);
611  if(ret != SASL_OK) {
612  _sx_debug(ZONE, "sasl_listmech failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL));
613  _sx_sasl_free(s,p);
614  return;
615  }
616 
617  if(nmechs <= 0) {
618  _sx_debug(ZONE, "sasl_listmech returned no mechanisms, not offering sasl for this conn");
619  _sx_sasl_free(s,p);
620  return;
621  }
622 
623  mech = mechs;
624  nmechs = 0;
625  while(mech != NULL) {
626  c = strchr(mech, '|');
627  if(c != NULL)
628  *c = '\0';
629 
630  if ((sd->ctx->cb)(sx_sasl_cb_CHECK_MECH, mech, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) {
631  if (nmechs == 0) {
632  ns = nad_add_namespace(nad, uri_SASL, NULL);
633  nad_append_elem(nad, ns, "mechanisms", 1);
634  }
635  _sx_debug(ZONE, "offering mechanism: %s", mech);
636 
637  nad_append_elem(nad, ns, "mechanism", 2);
638  nad_append_cdata(nad, mech, strlen(mech), 3);
639  nmechs++;
640  }
641 
642  if(c == NULL)
643  mech = NULL;
644  else
645  mech = ++c;
646  }
647 }
648 
651  nad_t nad;
652  int ns;
653 
654  nad = nad_new();
655  ns = nad_add_namespace(nad, uri_SASL, NULL);
656 
657  nad_append_elem(nad, ns, "success", 0);
658 
659  return nad;
660 }
661 
663 static nad_t _sx_sasl_failure(sx_t s, const char *err) {
664  nad_t nad;
665  int ns;
666 
667  nad = nad_new();
668  ns = nad_add_namespace(nad, uri_SASL, NULL);
669 
670  nad_append_elem(nad, ns, "failure", 0);
671  if(err != NULL)
672  nad_append_elem(nad, ns, err, 1);
673 
674  return nad;
675 }
676 
678 static nad_t _sx_sasl_challenge(sx_t s, char *data, int dlen) {
679  nad_t nad;
680  int ns;
681 
682  nad = nad_new();
683  ns = nad_add_namespace(nad, uri_SASL, NULL);
684 
685  nad_append_elem(nad, ns, "challenge", 0);
686  if(data != NULL)
687  nad_append_cdata(nad, data, dlen, 1);
688 
689  return nad;
690 }
691 
693 static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) {
694  nad_t nad;
695  int ns;
696 
697  nad = nad_new();
698  ns = nad_add_namespace(nad, uri_SASL, NULL);
699 
700  nad_append_elem(nad, ns, "response", 0);
701  if(data != NULL)
702  nad_append_cdata(nad, data, dlen, 1);
703 
704  return nad;
705 }
706 
709  nad_t nad;
710  int ns;
711 
712  nad = nad_new();
713  ns = nad_add_namespace(nad, uri_SASL, NULL);
714 
715  nad_append_elem(nad, ns, "abort", 0);
716 
717  return nad;
718 }
719 
721 static void _sx_sasl_decode(char *in, int inlen, char **out, int *outlen) {
722  *out = (char *) malloc(sizeof(char) * (2 * inlen));
723  sasl_decode64(in,inlen,*out,2*inlen,outlen);
724 }
725 
727 static void _sx_sasl_encode(char *in, int inlen, char **out, int *outlen) {
728  *out = (char *) malloc(sizeof(char) * (2 * inlen));
729  sasl_encode64(in,inlen,*out,2*inlen,outlen);
730 }
731 
733 static void _sx_sasl_notify_success(sx_t s, void *arg) {
734  sx_plugin_t p = (sx_plugin_t) arg;
735 
736  _sx_chain_io_plugin(s, p);
737  _sx_debug(ZONE, "auth completed, resetting");
738 
739  _sx_reset(s);
740 
741  sx_server_init(s, s->flags);
742 }
743 
745 static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, char *mech, char *in, int inlen) {
747  char *buf = NULL, *out = NULL;
748  int buflen, outlen, ret;
749 
750  /* decode the response */
751  _sx_sasl_decode(in, inlen, &buf, &buflen);
752 
753  if(mech != NULL) {
754  _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech);
755  } else {
756  _sx_debug(ZONE, "response from client (response: %.*s)", buflen, buf);
757  }
758 
759  /* process the data */
760  if(mech != NULL)
761  ret = sasl_server_start(sd->sasl, mech, buf, buflen, (const char **) &out, &outlen);
762  else {
763  if(!sd->sasl) {
764  _sx_debug(ZONE, "response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf);
766  if(buf != NULL) free(buf);
767  return;
768  }
769  ret = sasl_server_step(sd->sasl, buf, buflen, (const char **) &out, &outlen);
770  }
771 
772  if(buf != NULL) free(buf);
773 
774  /* auth completed */
775  if(ret == SASL_OK) {
776  _sx_debug(ZONE, "sasl handshake completed");
777 
778  /* send success */
780 
781  /* set a notify on the success nad buffer */
782  ((sx_buf_t) s->wbufq->front->data)->notify = _sx_sasl_notify_success;
783  ((sx_buf_t) s->wbufq->front->data)->notify_arg = (void *) p;
784 
785  return;
786  }
787 
788  /* in progress */
789  if(ret == SASL_CONTINUE) {
790  _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out);
791 
792  /* encode the challenge */
793  _sx_sasl_encode(out, outlen, &buf, &buflen);
794 
795  _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0);
796 
797  free(buf);
798 
799  return;
800  }
801 
802  /* its over */
803  buf = (char *) sasl_errdetail(sd->sasl);
804  if(buf == NULL)
805  buf = "[no error message available]";
806 
807  _sx_debug(ZONE, "sasl handshake failed: %s", buf);
808 
810 }
811 
813 static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, char *in, int inlen) {
815  char *buf, *out;
816  int buflen, outlen, ret;
817  const char *err_buf;
818 
819  _sx_debug(ZONE, "challenge from client");
820 
821  /* decode the response */
822  _sx_sasl_decode(in, inlen, &buf, &buflen);
823 
824  /* process the data */
825  ret = sasl_client_step(sd->sasl, buf, buflen, NULL, (const char **) &out, &outlen);
826  if(buf != NULL) free(buf);
827 
828  /* in progress */
829  if(ret == SASL_OK || ret == SASL_CONTINUE) {
830  _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out);
831 
832  /* encode the response */
833  _sx_sasl_encode(out, outlen, &buf, &buflen);
834 
835  _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0);
836 
837  if(buf != NULL) free(buf);
838 
839  return;
840  }
841 
842  /* its over */
843  err_buf = sasl_errdetail(sd->sasl);
844  if (err_buf == NULL)
845  err_buf = "[no error message available]";
846 
847  _sx_debug(ZONE, "sasl handshake aborted: %s", err_buf);
848 
849  _sx_nad_write(s, _sx_sasl_abort(s), 0);
850 }
851 
853 static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) {
855  int attr;
856  char mech[128];
857  sx_error_t sxe;
858  int flags;
859  char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;
860 
861  /* only want sasl packets */
862  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)
863  return 1;
864 
865  /* quietly drop it if sasl is disabled, or if not ready */
866  if(s->state != state_STREAM || sd == NULL) {
867  _sx_debug(ZONE, "not correct state for sasl, ignoring");
868  nad_free(nad);
869  return 0;
870  }
871 
872  /* packets from the client */
873  if(s->type == type_SERVER) {
874  if(!(s->flags & SX_SASL_OFFER)) {
875  _sx_debug(ZONE, "they tried to do sasl, but we never offered it, ignoring");
876  nad_free(nad);
877  return 0;
878  }
879 
880 #ifdef HAVE_SSL
881  if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) {
882  _sx_debug(ZONE, "they tried to do sasl, but they have to do starttls first, ignoring");
883  nad_free(nad);
884  return 0;
885  }
886 #endif
887 
888  /* auth */
889  if(NAD_ENAME_L(nad, 0) == 4 && strncmp("auth", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
890  /* require mechanism */
891  if((attr = nad_find_attr(nad, 0, -1, "mechanism", NULL)) < 0) {
893  nad_free(nad);
894  return 0;
895  }
896 
897  /* extract */
898  snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
899 
900  /* go */
901  _sx_sasl_client_process(s, p, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
902 
903  nad_free(nad);
904  return 0;
905  }
906 
907  /* response */
908  else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
909  /* process it */
910  _sx_sasl_client_process(s, p, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
911 
912  nad_free(nad);
913  return 0;
914  }
915 
916  /* abort */
917  else if(NAD_ENAME_L(nad, 0) == 5 && strncmp("abort", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
918  _sx_debug(ZONE, "sasl handshake aborted");
919 
921 
922  nad_free(nad);
923  return 0;
924  }
925  }
926 
927  /* packets from the server */
928  else if(s->type == type_CLIENT) {
929  if(sd == NULL) {
930  _sx_debug(ZONE, "got sasl client packets, but they never started sasl, ignoring");
931  nad_free(nad);
932  return 0;
933  }
934 
935  /* challenge */
936  if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
937  /* process it */
938  _sx_sasl_server_process(s, p, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0));
939 
940  nad_free(nad);
941  return 0;
942  }
943 
944  /* success */
945  else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("success", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
946  _sx_debug(ZONE, "sasl handshake completed, resetting");
947  nad_free(nad);
948 
949  /* save interesting bits */
950  flags = s->flags;
951 
952  if(s->ns != NULL) ns = strdup(s->ns);
953 
954  if(s->req_to != NULL) to = strdup(s->req_to);
955  if(s->req_from != NULL) from = strdup(s->req_from);
956  if(s->req_version != NULL) version = strdup(s->req_version);
957 
958  /* setup the encoder */
959  _sx_chain_io_plugin(s, p);
960 
961  /* reset state */
962  _sx_reset(s);
963 
964  _sx_debug(ZONE, "restarting stream with sasl layer established");
965 
966  /* second time round */
967  sx_client_init(s, flags, ns, to, from, version);
968 
969  /* free bits */
970  if(ns != NULL) free(ns);
971  if(to != NULL) free(to);
972  if(from != NULL) free(from);
973  if(version != NULL) free(version);
974 
975  return 0;
976  }
977 
978  /* failure */
979  else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("failure", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) {
980  /* fire the error */
981  _sx_gen_error(sxe, SX_ERR_AUTH, "Authentication failed", NULL);
982  _sx_event(s, event_ERROR, (void *) &sxe);
983 
984  /* cleanup */
985  _sx_sasl_free(s,p);
986 
987  nad_free(nad);
988  return 0;
989  }
990  }
991 
992  /* invalid sasl command, quietly drop it */
993  _sx_debug(ZONE, "unknown sasl command '%.*s', ignoring", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0));
994 
995  nad_free(nad);
996  return 0;
997 }
998 
1000 static void _sx_sasl_free(sx_t s, sx_plugin_t p) {
1002 
1003  if(sd == NULL)
1004  return;
1005 
1006  _sx_debug(ZONE, "cleaning up conn state");
1007 
1008  if(sd->sasl != NULL) sasl_dispose(&sd->sasl);
1009  if(sd->user != NULL) free(sd->user);
1010  if(sd->psecret != NULL) free(sd->psecret);
1011  if(sd->callbacks != NULL) free(sd->callbacks);
1012 
1013  free(sd);
1014 
1015  s->plugin_data[p->index] = NULL;
1016 }
1017 
1019  _sx_sasl_t ctx;
1020 
1021  ctx = (_sx_sasl_t) p->private;
1022 
1023  if (ctx->appname != NULL) free(ctx->appname);
1024  if (ctx->saslcallbacks != NULL) free(ctx->saslcallbacks);
1025 
1026  if (p->private != NULL) free(p->private);
1027 }
1028 
1030 int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) {
1031  char *appname;
1032  sx_sasl_callback_t cb;
1033  void *cbarg;
1034  int ret;
1035  _sx_sasl_t ctx;
1036 
1037  _sx_debug(ZONE, "initialising sasl plugin");
1038 
1039  appname = va_arg(args, char *);
1040  if(appname == NULL) {
1041  _sx_debug(ZONE, "appname was NULL, failing");
1042  return 1;
1043  }
1044 
1045  cb = va_arg(args, sx_sasl_callback_t);
1046  cbarg = va_arg(args, void *);
1047 
1048  /* Set up the auxiliary property plugin, which we use to gave SASL
1049  * mechanism plugins access to our passwords
1050  */
1051  sasl_auxprop_add_plugin("jabbersx", sx_auxprop_init);
1052 
1053  ctx = (_sx_sasl_t) calloc(1, sizeof(struct _sx_sasl_st));
1054 
1055  ctx->sec_props.min_ssf = 0;
1056  ctx->sec_props.max_ssf = -1; /* sasl_ssf_t is typedef'd to unsigned, so -1 gets us the max possible ssf */
1057  ctx->sec_props.maxbufsize = 1024;
1058  ctx->sec_props.security_flags = 0;
1059 
1060  ctx->appname = strdup(appname);
1061  ctx->cb = cb;
1062  ctx->cbarg = cbarg;
1063 
1064  /* Push the location of our callbacks into the auxprop structure */
1065 
1066  _sx_auxprop_plugin.glob_context = (void *) ctx;
1067 
1068 #ifdef _WIN32
1069  ctx->saslcallbacks = calloc(sizeof(sasl_callback_t), 3);
1070 #else
1071  ctx->saslcallbacks = calloc(sizeof(sasl_callback_t), 2);
1072 #endif
1073  ctx->saslcallbacks[0].id = SASL_CB_GETOPT;
1074  ctx->saslcallbacks[0].proc = &_sx_sasl_getopt;
1075  ctx->saslcallbacks[0].context = NULL;
1076 #ifdef _WIN32
1077  ctx->saslcallbacks[1].id = SASL_CB_GETPATH;
1078  ctx->saslcallbacks[1].proc = &_sx_sasl_getpath;
1079  ctx->saslcallbacks[1].context = NULL;
1080 
1081  ctx->saslcallbacks[2].id = SASL_CB_LIST_END;
1082 #else
1083  ctx->saslcallbacks[1].id = SASL_CB_LIST_END;
1084 #endif
1085 
1086  ret = sasl_server_init(ctx->saslcallbacks, appname);
1087  if(ret != SASL_OK) {
1088  _sx_debug(ZONE, "sasl_server_init() failed (%s), disabling", sasl_errstring(ret, NULL, NULL));
1089  free(ctx->saslcallbacks);
1090  free(ctx);
1091  return 1;
1092  }
1093 
1094  _sx_debug(ZONE, "sasl context initialised; appname=%s", appname);
1095 
1096  p->private = (void *) ctx;
1097 
1098  p->unload = _sx_sasl_unload;
1099  p->wio = _sx_sasl_wio;
1100  p->rio = _sx_sasl_rio;
1101 
1102  p->stream = _sx_sasl_stream;
1105 
1106  p->free = _sx_sasl_free;
1107 
1108  return 0;
1109 }
1110 
1111 /* callback functions for client auth */
1112 static int _sx_sasl_cb_get_simple(void *ctx, int id, const char **result, unsigned *len)
1113 {
1114  _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx;
1115 
1116  _sx_debug(ZONE, "in _sx_sasl_cb_get_simple (id 0x%x)", id);
1117 
1118  *result = sd->user;
1119  if(len != NULL)
1120  *len = strlen(*result);
1121 
1122  return SASL_OK;
1123 }
1124 
1125 static int _sx_sasl_cb_get_secret(sasl_conn_t *conn, void *ctx, int id, sasl_secret_t **psecret)
1126 {
1127  _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx;
1128 
1129  _sx_debug(ZONE, "in _sx_sasl_cb_get_secret (id 0x%x)", id);
1130 
1131  /* sanity check */
1132  if(conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1133  return SASL_BADPARAM;
1134 
1135  *psecret = sd->psecret;
1136 
1137  return SASL_OK;
1138 }
1139 
1141 int sx_sasl_auth(sx_plugin_t p, sx_t s, char *appname, char *mech, char *user, char *pass) {
1142  _sx_sasl_t ctx = (_sx_sasl_t) p->private;
1143  _sx_sasl_data_t sd;
1144  char *buf, *out, *ext_id;
1145  int i, ret, buflen, outlen, ns;
1146  sasl_security_properties_t sec_props;
1147  nad_t nad;
1148 #ifdef _WIN32
1149  static sasl_callback_t win32_callbacks[2] = {
1150  {SASL_CB_GETPATH, &_sx_sasl_getpath, NULL},
1151  {SASL_CB_LIST_END, NULL, NULL}};
1152 #endif
1153 
1154  assert((int) (p != NULL));
1155  assert((int) (s != NULL));
1156  assert((int) (appname != NULL));
1157  assert((int) (mech != NULL));
1158 
1159  if(s->type != type_CLIENT || s->state != state_STREAM) {
1160  _sx_debug(ZONE, "need client in stream state for sasl auth");
1161  return 1;
1162  }
1163 
1164  /* startup */
1165 #ifdef _WIN32
1166  ret = sasl_client_init(win32_callbacks);
1167 #else
1168  ret = sasl_client_init(NULL);
1169 #endif
1170  if(ret != SASL_OK) {
1171  _sx_debug(ZONE, "sasl_client_init() failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1172  return 1;
1173  }
1174 
1175  sd = (_sx_sasl_data_t) calloc(1, sizeof(struct _sx_sasl_data_st));
1176 
1177  if(user != NULL)
1178  sd->user = strdup(user);
1179 
1180  if(pass != NULL) {
1181  sd->psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + strlen(pass) + 1);
1182  strcpy(sd->psecret->data, pass);
1183  sd->psecret->len = strlen(pass);
1184  }
1185 
1186  sd->callbacks=calloc(sizeof(sasl_callback_t),4);
1187 
1188  /* authentication name callback */
1189  sd->callbacks[0].id = SASL_CB_AUTHNAME;
1190  sd->callbacks[0].proc = &_sx_sasl_cb_get_simple;
1191  sd->callbacks[0].context = (void *) sd;
1192 
1193  /* password callback */
1194  sd->callbacks[1].id = SASL_CB_PASS;
1195  sd->callbacks[1].proc = &_sx_sasl_cb_get_secret;
1196  sd->callbacks[1].context = (void *) sd;
1197 
1198  /* user identity callback */
1199  sd->callbacks[2].id = SASL_CB_USER;
1200  sd->callbacks[2].proc = &_sx_sasl_cb_get_simple;
1201  sd->callbacks[2].context = (void *) sd;
1202 
1203  /* end of callbacks */
1204  sd->callbacks[3].id = SASL_CB_LIST_END;
1205  sd->callbacks[3].proc = NULL;
1206  sd->callbacks[3].context = NULL;
1207 
1208  /* handshake start */
1209  ret = sasl_client_new(appname, (s->req_to != NULL) ? s->req_to : "", NULL, NULL, sd->callbacks, 0, &sd->sasl);
1210  if(ret != SASL_OK) {
1211  _sx_debug(ZONE, "sasl_client_new failed, (%s), not authing", sasl_errstring(ret, NULL, NULL));
1212 
1213  if (sd->user != NULL) free(sd->user);
1214  if (sd->psecret != NULL) free(sd->psecret);
1215  free(sd->callbacks);
1216  free(sd);
1217 
1218  return 1;
1219  }
1220 
1221  /* get external data from the ssl plugin */
1222  ext_id = NULL;
1223 #ifdef HAVE_SSL
1224  for(i = 0; i < s->env->nplugins; i++)
1225  if(s->env->plugins[i]->magic == SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL)
1226  ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id;
1227 
1228  /* !!! XXX certs */
1229  /*
1230  if(ext != NULL) {
1231  ext->external_id = strdup("foo");
1232  ext->external_ssf = 20;
1233  }
1234  */
1235 
1236  /* if we've got some, setup for external auth */
1237  if(ext_id != NULL) {
1238  ret = sasl_setprop(sd->sasl, SASL_AUTH_EXTERNAL, ext_id);
1239  if(ret == SASL_OK) ret = sasl_setprop(sd->sasl, SASL_SSF_EXTERNAL, &s->ssf);
1240  }
1241 #endif /* HAVE_SSL */
1242 
1243  /* setup security properties */
1244  sec_props = ctx->sec_props;
1245  if(s->ssf > 0)
1246  /* if we're already encrypted, then no security layers */
1247  sec_props.max_ssf = 0;
1248 
1249  ret = sasl_setprop(sd->sasl, SASL_SEC_PROPS, &sec_props);
1250  if(ret != SASL_OK) {
1251  _sx_debug(ZONE, "sasl_setprop failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1252 
1253  sasl_dispose(&sd->sasl);
1254 
1255  if (sd->user != NULL) free(sd->user);
1256  if (sd->psecret != NULL) free(sd->psecret);
1257  free(sd->callbacks);
1258  free(sd);
1259 
1260  return 1;
1261  }
1262 
1263  /* handshake start */
1264  ret = sasl_client_start(sd->sasl, mech, NULL, (const char **) &out, &outlen, NULL);
1265  if(ret != SASL_OK && ret != SASL_CONTINUE) {
1266  _sx_debug(ZONE, "sasl_client_start failed (%s), not authing", sasl_errstring(ret, NULL, NULL));
1267 
1268  sasl_dispose(&sd->sasl);
1269 
1270  if (sd->user != NULL) free(sd->user);
1271  if (sd->psecret != NULL) free(sd->psecret);
1272  free(sd->callbacks);
1273  free(sd);
1274 
1275  return 1;
1276  }
1277 
1278  /* save userdata */
1279  s->plugin_data[p->index] = (void *) sd;
1280 
1281  /* in progress */
1282  _sx_debug(ZONE, "sending auth request to server, mech '%s': %.*s", mech, outlen, out);
1283 
1284  /* encode the challenge */
1285  _sx_sasl_encode(out, outlen, &buf, &buflen);
1286 
1287  /* build the nad */
1288  nad = nad_new();
1289  ns = nad_add_namespace(nad, uri_SASL, NULL);
1290 
1291  nad_append_elem(nad, ns, "auth", 0);
1292  nad_append_attr(nad, -1, "mechanism", mech);
1293  if(buf != NULL) {
1294  nad_append_cdata(nad, buf, buflen, 1);
1295  free(buf);
1296  }
1297 
1298  /* its away */
1299  sx_nad_write(s, nad);
1300 
1301  return 0;
1302 }