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