jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 /* SASL authentication handler */ 00022 00023 #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. 00024 00025 #include "sx.h" 00026 #include "sasl.h" 00027 00028 /* Gack - need this otherwise SASL's MD5 definitions conflict with OpenSSLs */ 00029 #ifdef HEADER_MD5_H 00030 # define MD5_H 00031 #endif 00032 #ifdef _WIN32 00033 # include <sasl.h> 00034 # include <saslutil.h> 00035 # include <saslplug.h> 00036 #else /* _WIN32 */ 00037 # include <sasl/sasl.h> 00038 # include <sasl/saslutil.h> 00039 # include <sasl/saslplug.h> 00040 #endif /* _WIN32 */ 00041 00043 typedef struct _sx_sasl_st { 00044 char *appname; 00045 sasl_security_properties_t sec_props; 00046 00047 sx_sasl_callback_t cb; 00048 void *cbarg; 00049 00050 sasl_callback_t *saslcallbacks; 00051 } *_sx_sasl_t; 00052 00053 /* data for per-conncetion sasl handshakes */ 00054 typedef struct _sx_sasl_data_st { 00055 char *user; 00056 sasl_secret_t *psecret; 00057 00058 sasl_callback_t *callbacks; 00059 00060 _sx_sasl_t ctx; 00061 sasl_conn_t *sasl; 00062 sx_t stream; 00063 } *_sx_sasl_data_t; 00064 00065 00066 /* Forward definitions */ 00067 static void _sx_sasl_free(sx_t, sx_plugin_t); 00068 00069 static int _sx_sasl_getopt(void * glob_context, 00070 const char *plugin_name, 00071 const char *option, 00072 const char **result, 00073 unsigned *len) 00074 { 00075 if (strcmp(option,"auxprop_plugin") == 0) { 00076 *result = "jabberdsx"; 00077 if (len) 00078 *len = strlen("jabberdsx"); 00079 return SASL_OK; 00080 } 00081 return SASL_FAIL; 00082 } 00083 00084 #ifdef _WIN32 00085 /* This handles returning library path on Windows to current directory. 00086 */ 00087 #include <windows.h> 00088 static int _sx_sasl_getpath(void *glob_context, const char **path_dest) { 00089 static char win32_path[MAX_PATH] = "\0"; 00090 00091 if(!path_dest) { 00092 return SASL_BADPARAM; 00093 } 00094 00095 if(!*win32_path) { 00096 char *r; 00097 GetModuleFileName(NULL, win32_path, MAX_PATH - 5); 00098 if(!*win32_path || !(r = strrchr(win32_path, '\\'))) 00099 return SASL_NOMEM; 00100 strcpy(r + 1, "sasl"); 00101 } 00102 00103 *path_dest = win32_path; 00104 return SASL_OK; 00105 } 00106 #endif /* _WIN32 */ 00107 00108 /* Support auxprop so that we can use the standard Jabber authreg plugins 00109 * with SASL mechanisms requiring passwords 00110 */ 00111 static void _sx_auxprop_lookup(void *glob_context, 00112 sasl_server_params_t *sparams, 00113 unsigned flags, 00114 const char *user, 00115 unsigned ulen) { 00116 const char *realm = NULL; 00117 char *c; 00118 const struct propval *to_fetch, *current; 00119 char *user_buf = NULL; 00120 char *value; 00121 _sx_sasl_t ctx = (_sx_sasl_t) glob_context; 00122 struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; 00123 00124 if (!sparams || !user) 00125 return; 00126 00127 /* It would appear that there's no guarantee that 'user' is NULL 00128 * terminated, so we'd better terminate it ... 00129 */ 00130 00131 user_buf = sparams->utils->malloc(ulen + 1); 00132 if (!user_buf) 00133 goto done; 00134 00135 memcpy(user_buf, user, ulen); 00136 user_buf[ulen] = '\0'; 00137 00138 c = strchr(user_buf, '@'); 00139 if (!c) { 00140 if (sparams->user_realm && sparams->user_realm[0]) 00141 realm = sparams->user_realm; 00142 else 00143 realm = sparams->serverFQDN; 00144 } else { 00145 *c = '\0'; 00146 realm = c+1; 00147 } 00148 00149 /* At present, we only handle fetching the user's password */ 00150 to_fetch = sparams->utils->prop_get(sparams->propctx); 00151 if (!to_fetch) 00152 goto done; 00153 for (current = to_fetch; current->name; current++) { 00154 if (strncmp(current->name, SASL_AUX_PASSWORD, sizeof(SASL_AUX_PASSWORD)) == 0) { 00155 /* If we've already got a value, see if we can override it */ 00156 if (current->values) { 00157 if (flags & SASL_AUXPROP_OVERRIDE) 00158 sparams->utils->prop_erase(sparams->propctx, current->name); 00159 else 00160 continue; 00161 } 00162 00163 creds.authnid = user_buf; 00164 creds.realm = realm; 00165 if ((ctx->cb)(sx_sasl_cb_GET_PASS, &creds, (void **)&value, 00166 NULL, ctx->cbarg) == sx_sasl_ret_OK) { 00167 sparams->utils->prop_set(sparams->propctx, current->name, 00168 value, strlen(value)); 00169 } 00170 } 00171 } 00172 done: 00173 if (user_buf) sparams->utils->free(user_buf); 00174 } 00175 00176 static sasl_auxprop_plug_t _sx_auxprop_plugin = 00177 {0, 0, NULL, NULL, _sx_auxprop_lookup, "jabberdsx", NULL}; 00178 00179 static int 00180 sx_auxprop_init(const sasl_utils_t *utils, int max_version, int *out_version, 00181 sasl_auxprop_plug_t **plug, const char *plugname) { 00182 00183 if (!out_version || !plug) 00184 return SASL_BADPARAM; 00185 if (max_version < SASL_AUXPROP_PLUG_VERSION ) 00186 return SASL_BADVERS; 00187 00188 *out_version = SASL_AUXPROP_PLUG_VERSION; 00189 *plug = &_sx_auxprop_plugin; 00190 00191 return SASL_OK; 00192 } 00193 00194 /* This handles those authreg plugins which won't provide plaintext access 00195 * to the user's password. Note that there are very few mechanisms which 00196 * call the verify function, rather than asking for the password 00197 */ 00198 static int _sx_sasl_checkpass(sasl_conn_t *conn, void *ctx, const char *user, const char *pass, unsigned passlen, struct propctx *propctx) { 00199 _sx_sasl_data_t sd = (_sx_sasl_data_t)ctx; 00200 struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; 00201 char *c; 00202 char *buf; 00203 00204 /* SASL doesn't seem to pass us the username and realm as seperate items, 00205 * instead it combines them into the 'user' variable. In order to preserve 00206 * the existing behaviour, we need to split them up again ... 00207 */ 00208 00209 buf = strdup(user); 00210 c = strchr(buf,'@'); 00211 if (c) { 00212 *c = '\0'; 00213 creds.realm = c+1; 00214 } 00215 creds.authnid = buf; 00216 creds.pass = pass; 00217 00218 if (sd->ctx->cb(sx_sasl_cb_CHECK_PASS, &creds, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) { 00219 free(buf); 00220 return SASL_OK; 00221 } else { 00222 free(buf); 00223 return SASL_BADAUTH; 00224 } 00225 } 00226 00227 /* Canonicalize the username. Normally this does nothing, but if we're 00228 * calling from an anonymous plugin, then we need to generate a JID for 00229 * the user 00230 */ 00231 00232 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) { 00233 char *buf; 00234 _sx_sasl_data_t sd = (_sx_sasl_data_t)ctx; 00235 sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf); 00236 if (strncmp(buf, "ANONYMOUS", 10) == 0) { 00237 sd->ctx->cb(sx_sasl_cb_GEN_AUTHZID, NULL, (void **)&buf, sd->stream, sd->ctx->cbarg); 00238 strncpy(out_user, buf, out_umax); 00239 out_user[out_umax]='\0'; 00240 *out_ulen=strlen(out_user); 00241 } else { 00242 memcpy(out_user,user,ulen); 00243 *out_ulen = ulen; 00244 } 00245 return SASL_OK; 00246 } 00247 00248 /* Need to make sure that 00249 * *) The authnid is permitted to become the given authzid 00250 * *) The authnid is included in the given authreg systems DB 00251 */ 00252 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) { 00253 _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; 00254 struct sx_sasl_creds_st creds = {NULL, NULL, NULL, NULL}; 00255 char *buf, *c; 00256 size_t len; 00257 int ret; 00258 00259 sasl_getprop(conn, SASL_MECHNAME, (const void **) &buf); 00260 if (strncmp(buf, "ANONYMOUS", 10) == 0) { 00261 /* If they're anonymous, their ID comes from us, so it must be OK! */ 00262 return SASL_OK; 00263 } else { 00264 /* This will break with clients that give requested user as a JID, 00265 * where requested_user != auth_identity */ 00266 if (!requested_user || !auth_identity || rlen == 0 || alen==0) { 00267 sasl_seterror(conn, 0, 00268 "Bad identities provided"); 00269 return SASL_BADAUTH; 00270 } 00271 00272 /* No guarantee that realm is NULL terminated - so make a terminated 00273 * version before we do anything */ 00274 00275 /* XXX - Do we also need to check if realm contains NULL values, 00276 * and complain if it does? 00277 */ 00278 00279 buf = malloc(urlen + 1); 00280 strncpy(buf, realm?realm:"", urlen); 00281 buf[urlen] = '\0'; 00282 creds.realm = buf; 00283 00284 /* By this point, SASL's default canon_user plugin has appended the 00285 * realm to both the auth_identity, and the requested_user. This 00286 * isn't what we want. 00287 * auth_identity should be a bare username 00288 * requested_user should be a JID 00289 * 00290 * We can't just remove everything after the '@' as some mechanisms 00291 * (such as GSSAPI) use the @ to denote users in foreign realms. 00292 */ 00293 00294 buf = malloc(alen + 1); 00295 strncpy(buf, auth_identity, alen); 00296 buf[alen] = '\0'; 00297 c = strrchr(buf, '@'); 00298 if (c && strcmp(c+1, creds.realm) == 0) 00299 *c = '\0'; 00300 creds.authnid = buf; 00301 00302 /* Now, we need to turn requested_user into a JID 00303 * (if it isn't already) 00304 * 00305 * XXX - This will break with s2s SASL, where the authzid is a domain 00306 */ 00307 len = rlen; 00308 if (sd->stream->req_to) 00309 len+=strlen(sd->stream->req_to) + 2; 00310 buf = malloc(len + 1); 00311 strncpy(buf, requested_user, rlen); 00312 buf[rlen] = '\0'; 00313 c = strrchr(buf, '@'); 00314 if (c && strcmp(c + 1, creds.realm) == 0) 00315 *c = '\0'; 00316 if (sd->stream->req_to && strchr(buf, '@') == 0) { 00317 strcat(buf, "@"); 00318 strcat(buf, sd->stream->req_to); 00319 } 00320 creds.authzid = buf; 00321 00322 /* If we start being fancy and allow auth_identity to be different from 00323 * requested_user, then this will need to be changed to permit it! 00324 */ 00325 ret = (sd->ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, &creds, NULL, sd->stream, sd->ctx->cbarg); 00326 00327 free((void *)creds.authnid); 00328 free((void *)creds.authzid); 00329 free((void *)creds.realm); 00330 00331 if (ret == sx_sasl_ret_OK) { 00332 return SASL_OK; 00333 } else { 00334 sasl_seterror(conn, 0, "Requested identity not permitted for authorization identity"); 00335 return SASL_BADAUTH; 00336 } 00337 } 00338 } 00339 00340 static int _sx_sasl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) { 00341 sasl_conn_t *sasl; 00342 int *x, len, pos, reslen, maxbuf; 00343 char *out, *result; 00344 00345 sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; 00346 00347 /* if there's no security layer, don't bother */ 00348 sasl_getprop(sasl, SASL_SSF, (const void **) &x); 00349 if(*x == 0) 00350 return 1; 00351 00352 _sx_debug(ZONE, "doing sasl encode"); 00353 00354 /* can only encode x bytes at a time */ 00355 sasl_getprop(sasl, SASL_MAXOUTBUF, (const void **) &x); 00356 maxbuf = *x; 00357 00358 /* encode the output */ 00359 pos = 0; 00360 result = NULL; reslen = 0; 00361 while(pos < buf->len) { 00362 if((buf->len - pos) < maxbuf) 00363 maxbuf = buf->len - pos; 00364 00365 sasl_encode(sasl, &buf->data[pos], maxbuf, (const char **) &out, &len); 00366 00367 result = (char *) realloc(result, sizeof(char) * (reslen + len)); 00368 memcpy(&result[reslen], out, len); 00369 reslen += len; 00370 00371 pos += maxbuf; 00372 } 00373 00374 /* replace the buffer */ 00375 _sx_buffer_set(buf, result, reslen, result); 00376 00377 _sx_debug(ZONE, "%d bytes encoded for sasl channel", buf->len); 00378 00379 return 1; 00380 } 00381 00382 static int _sx_sasl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) { 00383 sasl_conn_t *sasl; 00384 sx_error_t sxe; 00385 int *x, len; 00386 char *out; 00387 00388 sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; 00389 00390 /* if there's no security layer, don't bother */ 00391 sasl_getprop(sasl, SASL_SSF, (const void **) &x); 00392 if(*x == 0) 00393 return 1; 00394 00395 _sx_debug(ZONE, "doing sasl decode"); 00396 00397 /* decode the input */ 00398 if (sasl_decode(sasl, buf->data, buf->len, (const char **) &out, &len) 00399 != SASL_OK) { 00400 /* Fatal error */ 00401 _sx_gen_error(sxe, SX_ERR_AUTH, "SASL Stream decoding failed", NULL); 00402 _sx_event(s, event_ERROR, (void *) &sxe); 00403 return -1; 00404 } 00405 00406 /* replace the buffer */ 00407 _sx_buffer_set(buf, out, len, NULL); 00408 00409 _sx_debug(ZONE, "%d bytes decoded from sasl channel", len); 00410 00411 return 1; 00412 } 00413 00415 void _sx_sasl_open(sx_t s, sasl_conn_t *sasl) { 00416 char *method; 00417 char *buf, *c; 00418 char *authzid; 00419 size_t len; 00420 int *ssf; 00421 00422 /* get the method */ 00423 sasl_getprop(sasl, SASL_MECHNAME, (const void **) &buf); 00424 00425 method = (char *) malloc(sizeof(char) * (strlen(buf) + 17)); 00426 sprintf(method, "SASL/%s", buf); 00427 00428 /* get the ssf */ 00429 if(s->ssf == 0) { 00430 sasl_getprop(sasl, SASL_SSF, (const void **) &ssf); 00431 s->ssf = *ssf; 00432 } 00433 00434 /* and the authenticated id */ 00435 sasl_getprop(sasl, SASL_USERNAME, (const void **) &buf); 00436 00437 if (s->type == type_SERVER) { 00438 /* Now, we need to turn the id into a JID 00439 * (if it isn't already) 00440 * 00441 * XXX - This will break with s2s SASL, where the authzid is a domain 00442 */ 00443 00444 len = strlen(buf); 00445 if (s->req_to) 00446 len+=strlen(s->req_to) + 2; 00447 authzid = malloc(len + 1); 00448 strcpy(authzid, buf); 00449 00450 sasl_getprop(sasl, SASL_DEFUSERREALM, (const void **) &buf); 00451 00452 c = strrchr(authzid, '@'); 00453 if (c && buf && strcmp(c+1, buf) == 0) 00454 *c = '\0'; 00455 if (s->req_to && strchr(authzid, '@') == 0) { 00456 strcat(authzid, "@"); 00457 strcat(authzid, s->req_to); 00458 } 00459 00460 /* schwing! */ 00461 sx_auth(s, method, authzid); 00462 free(authzid); 00463 } else { 00464 sx_auth(s, method, buf); 00465 } 00466 00467 free(method); 00468 } 00469 00471 static void _sx_sasl_stream(sx_t s, sx_plugin_t p) { 00472 _sx_sasl_t ctx = (_sx_sasl_t) p->private; 00473 sasl_conn_t *sasl; 00474 _sx_sasl_data_t sd; 00475 int ret, i; 00476 char *realm = NULL, *ext_id, *mech; 00477 sasl_security_properties_t sec_props; 00478 00479 /* First time around, we need to set up our SASL connection, otherwise 00480 * features will fall flat on its face */ 00481 if (s->plugin_data[p->index] == NULL) { 00482 if(s->type == type_SERVER) { 00483 00484 if(!(s->flags & SX_SASL_OFFER)) { 00485 _sx_debug(ZONE, "application did not request sasl offer, not offering for this conn"); 00486 return; 00487 } 00488 00489 _sx_debug(ZONE, "setting up sasl for this server conn"); 00490 00491 /* Initialise our data object */ 00492 sd = (_sx_sasl_data_t) calloc(1, sizeof(struct _sx_sasl_data_st)); 00493 00494 /* get the realm */ 00495 if(ctx->cb != NULL) 00496 (ctx->cb)(sx_sasl_cb_GET_REALM, NULL, (void **) &realm, s, ctx->cbarg); 00497 00498 /* Initialize our callbacks */ 00499 sd->callbacks = calloc(sizeof(sasl_callback_t),4); 00500 00501 sd->callbacks[0].id = SASL_CB_PROXY_POLICY; 00502 sd->callbacks[0].proc = &_sx_sasl_proxy_policy; 00503 sd->callbacks[0].context = sd; 00504 00505 sd->callbacks[1].id = SASL_CB_CANON_USER; 00506 sd->callbacks[1].proc = &_sx_sasl_canon_user; 00507 sd->callbacks[1].context = sd; 00508 00509 sd->callbacks[2].id = SASL_CB_SERVER_USERDB_CHECKPASS; 00510 sd->callbacks[2].proc = &_sx_sasl_checkpass; 00511 sd->callbacks[2].context = sd; 00512 00513 sd->callbacks[3].id = SASL_CB_LIST_END; 00514 00515 /* startup */ 00516 ret = sasl_server_new(ctx->appname, NULL, 00517 realm ? (realm[0] == '\0' ? NULL : realm) : NULL, 00518 NULL, NULL, sd->callbacks, 00519 ctx->sec_props.security_flags, &sasl); 00520 if(ret != SASL_OK) { 00521 _sx_debug(ZONE, "sasl_server_new failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); 00522 free(sd->callbacks); 00523 free(sd); 00524 return; 00525 } 00526 00527 /* get external data from the ssl plugin */ 00528 ext_id = NULL; 00529 #ifdef HAVE_SSL 00530 for(i = 0; i < s->env->nplugins; i++) 00531 if(s->env->plugins[i]->magic == SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL) 00532 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id; 00533 00534 /* if we've got some, setup for external auth */ 00535 if(ext_id != NULL) { 00536 ret = sasl_setprop(sasl, SASL_AUTH_EXTERNAL, ext_id); 00537 if(ret == SASL_OK) 00538 ret = sasl_setprop(sasl, SASL_SSF_EXTERNAL, &s->ssf); 00539 } 00540 #endif /* HAVE_SSL */ 00541 00542 /* security properties */ 00543 sec_props = ctx->sec_props; 00544 if(s->ssf > 0) 00545 /* if we're already encrypted, then no security layers */ 00546 sec_props.max_ssf = 0; 00547 00548 if(ret == SASL_OK) 00549 ret = sasl_setprop(sasl, SASL_SEC_PROPS, &sec_props); 00550 00551 if(ret != SASL_OK) { 00552 _sx_debug(ZONE, "sasl_setprop failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); 00553 free(sd->callbacks); 00554 free(sd); 00555 return; 00556 } 00557 00558 sd->sasl = sasl; 00559 sd->stream = s; 00560 sd->ctx = ctx; 00561 00562 _sx_debug(ZONE, "sasl context initialised for %d", s->tag); 00563 00564 s->plugin_data[p->index] = (void *) sd; 00565 00566 } 00567 00568 return; 00569 } 00570 00571 sasl = ((_sx_sasl_data_t) s->plugin_data[p->index])->sasl; 00572 00573 /* are we auth'd? */ 00574 if (sasl_getprop(sasl, SASL_MECHNAME, (void *) &mech) == SASL_NOTDONE) { 00575 _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet"); 00576 return; 00577 } 00578 00579 /* otherwise, its auth time */ 00580 _sx_sasl_open(s, sasl); 00581 } 00582 00583 static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) { 00584 _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; 00585 int ret, nmechs, ns; 00586 char *mechs, *mech, *c; 00587 00588 if(s->type != type_SERVER || sd == NULL || sd->sasl == NULL) 00589 return; 00590 00591 if((ret = sasl_getprop(sd->sasl, SASL_MECHNAME, (void *) &mech)) != SASL_NOTDONE) { 00592 _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms"); 00593 return; 00594 } 00595 00596 if(!(s->flags & SX_SASL_OFFER)) { 00597 _sx_debug(ZONE, "application didn't ask us to offer sasl, so we won't"); 00598 return; 00599 } 00600 00601 #ifdef HAVE_SSL 00602 if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { 00603 _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms"); 00604 return; 00605 } 00606 #endif 00607 00608 _sx_debug(ZONE, "offering sasl mechanisms"); 00609 00610 ret = sasl_listmech(sd->sasl, NULL, "", "|", "", (const char **) &mechs, NULL, &nmechs); 00611 if(ret != SASL_OK) { 00612 _sx_debug(ZONE, "sasl_listmech failed (%s), not offering sasl for this conn", sasl_errstring(ret, NULL, NULL)); 00613 _sx_sasl_free(s,p); 00614 return; 00615 } 00616 00617 if(nmechs <= 0) { 00618 _sx_debug(ZONE, "sasl_listmech returned no mechanisms, not offering sasl for this conn"); 00619 _sx_sasl_free(s,p); 00620 return; 00621 } 00622 00623 mech = mechs; 00624 nmechs = 0; 00625 while(mech != NULL) { 00626 c = strchr(mech, '|'); 00627 if(c != NULL) 00628 *c = '\0'; 00629 00630 if ((sd->ctx->cb)(sx_sasl_cb_CHECK_MECH, mech, NULL, sd->stream, sd->ctx->cbarg)==sx_sasl_ret_OK) { 00631 if (nmechs == 0) { 00632 ns = nad_add_namespace(nad, uri_SASL, NULL); 00633 nad_append_elem(nad, ns, "mechanisms", 1); 00634 } 00635 _sx_debug(ZONE, "offering mechanism: %s", mech); 00636 00637 nad_append_elem(nad, ns, "mechanism", 2); 00638 nad_append_cdata(nad, mech, strlen(mech), 3); 00639 nmechs++; 00640 } 00641 00642 if(c == NULL) 00643 mech = NULL; 00644 else 00645 mech = ++c; 00646 } 00647 } 00648 00650 static nad_t _sx_sasl_success(sx_t s) { 00651 nad_t nad; 00652 int ns; 00653 00654 nad = nad_new(); 00655 ns = nad_add_namespace(nad, uri_SASL, NULL); 00656 00657 nad_append_elem(nad, ns, "success", 0); 00658 00659 return nad; 00660 } 00661 00663 static nad_t _sx_sasl_failure(sx_t s, const char *err) { 00664 nad_t nad; 00665 int ns; 00666 00667 nad = nad_new(); 00668 ns = nad_add_namespace(nad, uri_SASL, NULL); 00669 00670 nad_append_elem(nad, ns, "failure", 0); 00671 if(err != NULL) 00672 nad_append_elem(nad, ns, err, 1); 00673 00674 return nad; 00675 } 00676 00678 static nad_t _sx_sasl_challenge(sx_t s, char *data, int dlen) { 00679 nad_t nad; 00680 int ns; 00681 00682 nad = nad_new(); 00683 ns = nad_add_namespace(nad, uri_SASL, NULL); 00684 00685 nad_append_elem(nad, ns, "challenge", 0); 00686 if(data != NULL) 00687 nad_append_cdata(nad, data, dlen, 1); 00688 00689 return nad; 00690 } 00691 00693 static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) { 00694 nad_t nad; 00695 int ns; 00696 00697 nad = nad_new(); 00698 ns = nad_add_namespace(nad, uri_SASL, NULL); 00699 00700 nad_append_elem(nad, ns, "response", 0); 00701 if(data != NULL) 00702 nad_append_cdata(nad, data, dlen, 1); 00703 00704 return nad; 00705 } 00706 00708 static nad_t _sx_sasl_abort(sx_t s) { 00709 nad_t nad; 00710 int ns; 00711 00712 nad = nad_new(); 00713 ns = nad_add_namespace(nad, uri_SASL, NULL); 00714 00715 nad_append_elem(nad, ns, "abort", 0); 00716 00717 return nad; 00718 } 00719 00721 static void _sx_sasl_decode(char *in, int inlen, char **out, int *outlen) { 00722 *out = (char *) malloc(sizeof(char) * (2 * inlen)); 00723 sasl_decode64(in,inlen,*out,2*inlen,outlen); 00724 } 00725 00727 static void _sx_sasl_encode(char *in, int inlen, char **out, int *outlen) { 00728 *out = (char *) malloc(sizeof(char) * (2 * inlen)); 00729 sasl_encode64(in,inlen,*out,2*inlen,outlen); 00730 } 00731 00733 static void _sx_sasl_notify_success(sx_t s, void *arg) { 00734 sx_plugin_t p = (sx_plugin_t) arg; 00735 00736 _sx_chain_io_plugin(s, p); 00737 _sx_debug(ZONE, "auth completed, resetting"); 00738 00739 _sx_reset(s); 00740 00741 sx_server_init(s, s->flags); 00742 } 00743 00745 static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, char *mech, char *in, int inlen) { 00746 _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; 00747 char *buf = NULL, *out = NULL; 00748 int buflen, outlen, ret; 00749 00750 /* decode the response */ 00751 _sx_sasl_decode(in, inlen, &buf, &buflen); 00752 00753 if(mech != NULL) { 00754 _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech); 00755 } else { 00756 _sx_debug(ZONE, "response from client (response: %.*s)", buflen, buf); 00757 } 00758 00759 /* process the data */ 00760 if(mech != NULL) 00761 ret = sasl_server_start(sd->sasl, mech, buf, buflen, (const char **) &out, &outlen); 00762 else { 00763 if(!sd->sasl) { 00764 _sx_debug(ZONE, "response send before auth request enabling mechanism (decoded: %.*s)", buflen, buf); 00765 _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MECH_TOO_WEAK), 0); 00766 if(buf != NULL) free(buf); 00767 return; 00768 } 00769 ret = sasl_server_step(sd->sasl, buf, buflen, (const char **) &out, &outlen); 00770 } 00771 00772 if(buf != NULL) free(buf); 00773 00774 /* auth completed */ 00775 if(ret == SASL_OK) { 00776 _sx_debug(ZONE, "sasl handshake completed"); 00777 00778 /* send success */ 00779 _sx_nad_write(s, _sx_sasl_success(s), 0); 00780 00781 /* set a notify on the success nad buffer */ 00782 ((sx_buf_t) s->wbufq->front->data)->notify = _sx_sasl_notify_success; 00783 ((sx_buf_t) s->wbufq->front->data)->notify_arg = (void *) p; 00784 00785 return; 00786 } 00787 00788 /* in progress */ 00789 if(ret == SASL_CONTINUE) { 00790 _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out); 00791 00792 /* encode the challenge */ 00793 _sx_sasl_encode(out, outlen, &buf, &buflen); 00794 00795 _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0); 00796 00797 free(buf); 00798 00799 return; 00800 } 00801 00802 /* its over */ 00803 buf = (char *) sasl_errdetail(sd->sasl); 00804 if(buf == NULL) 00805 buf = "[no error message available]"; 00806 00807 _sx_debug(ZONE, "sasl handshake failed: %s", buf); 00808 00809 _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_MALFORMED_REQUEST), 0); 00810 } 00811 00813 static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, char *in, int inlen) { 00814 _sx_sasl_data_t sd = (_sx_sasl_data_t)s->plugin_data[p->index]; 00815 char *buf, *out; 00816 int buflen, outlen, ret; 00817 const char *err_buf; 00818 00819 _sx_debug(ZONE, "challenge from client"); 00820 00821 /* decode the response */ 00822 _sx_sasl_decode(in, inlen, &buf, &buflen); 00823 00824 /* process the data */ 00825 ret = sasl_client_step(sd->sasl, buf, buflen, NULL, (const char **) &out, &outlen); 00826 if(buf != NULL) free(buf); 00827 00828 /* in progress */ 00829 if(ret == SASL_OK || ret == SASL_CONTINUE) { 00830 _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out); 00831 00832 /* encode the response */ 00833 _sx_sasl_encode(out, outlen, &buf, &buflen); 00834 00835 _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0); 00836 00837 if(buf != NULL) free(buf); 00838 00839 return; 00840 } 00841 00842 /* its over */ 00843 err_buf = sasl_errdetail(sd->sasl); 00844 if (err_buf == NULL) 00845 err_buf = "[no error message available]"; 00846 00847 _sx_debug(ZONE, "sasl handshake aborted: %s", err_buf); 00848 00849 _sx_nad_write(s, _sx_sasl_abort(s), 0); 00850 } 00851 00853 static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) { 00854 _sx_sasl_data_t sd = (_sx_sasl_data_t)s->plugin_data[p->index]; 00855 int attr; 00856 char mech[128]; 00857 sx_error_t sxe; 00858 int flags; 00859 char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; 00860 00861 /* only want sasl packets */ 00862 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) 00863 return 1; 00864 00865 /* quietly drop it if sasl is disabled, or if not ready */ 00866 if(s->state != state_STREAM || sd == NULL) { 00867 _sx_debug(ZONE, "not correct state for sasl, ignoring"); 00868 nad_free(nad); 00869 return 0; 00870 } 00871 00872 /* packets from the client */ 00873 if(s->type == type_SERVER) { 00874 if(!(s->flags & SX_SASL_OFFER)) { 00875 _sx_debug(ZONE, "they tried to do sasl, but we never offered it, ignoring"); 00876 nad_free(nad); 00877 return 0; 00878 } 00879 00880 #ifdef HAVE_SSL 00881 if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { 00882 _sx_debug(ZONE, "they tried to do sasl, but they have to do starttls first, ignoring"); 00883 nad_free(nad); 00884 return 0; 00885 } 00886 #endif 00887 00888 /* auth */ 00889 if(NAD_ENAME_L(nad, 0) == 4 && strncmp("auth", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00890 /* require mechanism */ 00891 if((attr = nad_find_attr(nad, 0, -1, "mechanism", NULL)) < 0) { 00892 _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); 00893 nad_free(nad); 00894 return 0; 00895 } 00896 00897 /* extract */ 00898 snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); 00899 00900 /* go */ 00901 _sx_sasl_client_process(s, p, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); 00902 00903 nad_free(nad); 00904 return 0; 00905 } 00906 00907 /* response */ 00908 else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00909 /* process it */ 00910 _sx_sasl_client_process(s, p, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); 00911 00912 nad_free(nad); 00913 return 0; 00914 } 00915 00916 /* abort */ 00917 else if(NAD_ENAME_L(nad, 0) == 5 && strncmp("abort", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00918 _sx_debug(ZONE, "sasl handshake aborted"); 00919 00920 _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_ABORTED), 0); 00921 00922 nad_free(nad); 00923 return 0; 00924 } 00925 } 00926 00927 /* packets from the server */ 00928 else if(s->type == type_CLIENT) { 00929 if(sd == NULL) { 00930 _sx_debug(ZONE, "got sasl client packets, but they never started sasl, ignoring"); 00931 nad_free(nad); 00932 return 0; 00933 } 00934 00935 /* challenge */ 00936 if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00937 /* process it */ 00938 _sx_sasl_server_process(s, p, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); 00939 00940 nad_free(nad); 00941 return 0; 00942 } 00943 00944 /* success */ 00945 else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("success", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00946 _sx_debug(ZONE, "sasl handshake completed, resetting"); 00947 nad_free(nad); 00948 00949 /* save interesting bits */ 00950 flags = s->flags; 00951 00952 if(s->ns != NULL) ns = strdup(s->ns); 00953 00954 if(s->req_to != NULL) to = strdup(s->req_to); 00955 if(s->req_from != NULL) from = strdup(s->req_from); 00956 if(s->req_version != NULL) version = strdup(s->req_version); 00957 00958 /* setup the encoder */ 00959 _sx_chain_io_plugin(s, p); 00960 00961 /* reset state */ 00962 _sx_reset(s); 00963 00964 _sx_debug(ZONE, "restarting stream with sasl layer established"); 00965 00966 /* second time round */ 00967 sx_client_init(s, flags, ns, to, from, version); 00968 00969 /* free bits */ 00970 if(ns != NULL) free(ns); 00971 if(to != NULL) free(to); 00972 if(from != NULL) free(from); 00973 if(version != NULL) free(version); 00974 00975 return 0; 00976 } 00977 00978 /* failure */ 00979 else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("failure", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { 00980 /* fire the error */ 00981 _sx_gen_error(sxe, SX_ERR_AUTH, "Authentication failed", NULL); 00982 _sx_event(s, event_ERROR, (void *) &sxe); 00983 00984 /* cleanup */ 00985 _sx_sasl_free(s,p); 00986 00987 nad_free(nad); 00988 return 0; 00989 } 00990 } 00991 00992 /* invalid sasl command, quietly drop it */ 00993 _sx_debug(ZONE, "unknown sasl command '%.*s', ignoring", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); 00994 00995 nad_free(nad); 00996 return 0; 00997 } 00998 01000 static void _sx_sasl_free(sx_t s, sx_plugin_t p) { 01001 _sx_sasl_data_t sd = (_sx_sasl_data_t) s->plugin_data[p->index]; 01002 01003 if(sd == NULL) 01004 return; 01005 01006 _sx_debug(ZONE, "cleaning up conn state"); 01007 01008 if(sd->sasl != NULL) sasl_dispose(&sd->sasl); 01009 if(sd->user != NULL) free(sd->user); 01010 if(sd->psecret != NULL) free(sd->psecret); 01011 if(sd->callbacks != NULL) free(sd->callbacks); 01012 01013 free(sd); 01014 01015 s->plugin_data[p->index] = NULL; 01016 } 01017 01018 static void _sx_sasl_unload(sx_plugin_t p) { 01019 _sx_sasl_t ctx; 01020 01021 ctx = (_sx_sasl_t) p->private; 01022 01023 if (ctx->appname != NULL) free(ctx->appname); 01024 if (ctx->saslcallbacks != NULL) free(ctx->saslcallbacks); 01025 01026 if (p->private != NULL) free(p->private); 01027 } 01028 01030 int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) { 01031 char *appname; 01032 sx_sasl_callback_t cb; 01033 void *cbarg; 01034 int ret; 01035 _sx_sasl_t ctx; 01036 01037 _sx_debug(ZONE, "initialising sasl plugin"); 01038 01039 appname = va_arg(args, char *); 01040 if(appname == NULL) { 01041 _sx_debug(ZONE, "appname was NULL, failing"); 01042 return 1; 01043 } 01044 01045 cb = va_arg(args, sx_sasl_callback_t); 01046 cbarg = va_arg(args, void *); 01047 01048 /* Set up the auxiliary property plugin, which we use to gave SASL 01049 * mechanism plugins access to our passwords 01050 */ 01051 sasl_auxprop_add_plugin("jabbersx", sx_auxprop_init); 01052 01053 ctx = (_sx_sasl_t) calloc(1, sizeof(struct _sx_sasl_st)); 01054 01055 ctx->sec_props.min_ssf = 0; 01056 ctx->sec_props.max_ssf = -1; /* sasl_ssf_t is typedef'd to unsigned, so -1 gets us the max possible ssf */ 01057 ctx->sec_props.maxbufsize = 1024; 01058 ctx->sec_props.security_flags = 0; 01059 01060 ctx->appname = strdup(appname); 01061 ctx->cb = cb; 01062 ctx->cbarg = cbarg; 01063 01064 /* Push the location of our callbacks into the auxprop structure */ 01065 01066 _sx_auxprop_plugin.glob_context = (void *) ctx; 01067 01068 #ifdef _WIN32 01069 ctx->saslcallbacks = calloc(sizeof(sasl_callback_t), 3); 01070 #else 01071 ctx->saslcallbacks = calloc(sizeof(sasl_callback_t), 2); 01072 #endif 01073 ctx->saslcallbacks[0].id = SASL_CB_GETOPT; 01074 ctx->saslcallbacks[0].proc = &_sx_sasl_getopt; 01075 ctx->saslcallbacks[0].context = NULL; 01076 #ifdef _WIN32 01077 ctx->saslcallbacks[1].id = SASL_CB_GETPATH; 01078 ctx->saslcallbacks[1].proc = &_sx_sasl_getpath; 01079 ctx->saslcallbacks[1].context = NULL; 01080 01081 ctx->saslcallbacks[2].id = SASL_CB_LIST_END; 01082 #else 01083 ctx->saslcallbacks[1].id = SASL_CB_LIST_END; 01084 #endif 01085 01086 ret = sasl_server_init(ctx->saslcallbacks, appname); 01087 if(ret != SASL_OK) { 01088 _sx_debug(ZONE, "sasl_server_init() failed (%s), disabling", sasl_errstring(ret, NULL, NULL)); 01089 free(ctx->saslcallbacks); 01090 free(ctx); 01091 return 1; 01092 } 01093 01094 _sx_debug(ZONE, "sasl context initialised; appname=%s", appname); 01095 01096 p->private = (void *) ctx; 01097 01098 p->unload = _sx_sasl_unload; 01099 p->wio = _sx_sasl_wio; 01100 p->rio = _sx_sasl_rio; 01101 01102 p->stream = _sx_sasl_stream; 01103 p->features = _sx_sasl_features; 01104 p->process = _sx_sasl_process; 01105 01106 p->free = _sx_sasl_free; 01107 01108 return 0; 01109 } 01110 01111 /* callback functions for client auth */ 01112 static int _sx_sasl_cb_get_simple(void *ctx, int id, const char **result, unsigned *len) 01113 { 01114 _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; 01115 01116 _sx_debug(ZONE, "in _sx_sasl_cb_get_simple (id 0x%x)", id); 01117 01118 *result = sd->user; 01119 if(len != NULL) 01120 *len = strlen(*result); 01121 01122 return SASL_OK; 01123 } 01124 01125 static int _sx_sasl_cb_get_secret(sasl_conn_t *conn, void *ctx, int id, sasl_secret_t **psecret) 01126 { 01127 _sx_sasl_data_t sd = (_sx_sasl_data_t) ctx; 01128 01129 _sx_debug(ZONE, "in _sx_sasl_cb_get_secret (id 0x%x)", id); 01130 01131 /* sanity check */ 01132 if(conn == NULL || psecret == NULL || id != SASL_CB_PASS) 01133 return SASL_BADPARAM; 01134 01135 *psecret = sd->psecret; 01136 01137 return SASL_OK; 01138 } 01139 01141 int sx_sasl_auth(sx_plugin_t p, sx_t s, char *appname, char *mech, char *user, char *pass) { 01142 _sx_sasl_t ctx = (_sx_sasl_t) p->private; 01143 _sx_sasl_data_t sd; 01144 char *buf, *out, *ext_id; 01145 int i, ret, buflen, outlen, ns; 01146 sasl_security_properties_t sec_props; 01147 nad_t nad; 01148 #ifdef _WIN32 01149 static sasl_callback_t win32_callbacks[2] = { 01150 {SASL_CB_GETPATH, &_sx_sasl_getpath, NULL}, 01151 {SASL_CB_LIST_END, NULL, NULL}}; 01152 #endif 01153 01154 assert((int) (p != NULL)); 01155 assert((int) (s != NULL)); 01156 assert((int) (appname != NULL)); 01157 assert((int) (mech != NULL)); 01158 01159 if(s->type != type_CLIENT || s->state != state_STREAM) { 01160 _sx_debug(ZONE, "need client in stream state for sasl auth"); 01161 return 1; 01162 } 01163 01164 /* startup */ 01165 #ifdef _WIN32 01166 ret = sasl_client_init(win32_callbacks); 01167 #else 01168 ret = sasl_client_init(NULL); 01169 #endif 01170 if(ret != SASL_OK) { 01171 _sx_debug(ZONE, "sasl_client_init() failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); 01172 return 1; 01173 } 01174 01175 sd = (_sx_sasl_data_t) calloc(1, sizeof(struct _sx_sasl_data_st)); 01176 01177 if(user != NULL) 01178 sd->user = strdup(user); 01179 01180 if(pass != NULL) { 01181 sd->psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + strlen(pass) + 1); 01182 strcpy(sd->psecret->data, pass); 01183 sd->psecret->len = strlen(pass); 01184 } 01185 01186 sd->callbacks=calloc(sizeof(sasl_callback_t),4); 01187 01188 /* authentication name callback */ 01189 sd->callbacks[0].id = SASL_CB_AUTHNAME; 01190 sd->callbacks[0].proc = &_sx_sasl_cb_get_simple; 01191 sd->callbacks[0].context = (void *) sd; 01192 01193 /* password callback */ 01194 sd->callbacks[1].id = SASL_CB_PASS; 01195 sd->callbacks[1].proc = &_sx_sasl_cb_get_secret; 01196 sd->callbacks[1].context = (void *) sd; 01197 01198 /* user identity callback */ 01199 sd->callbacks[2].id = SASL_CB_USER; 01200 sd->callbacks[2].proc = &_sx_sasl_cb_get_simple; 01201 sd->callbacks[2].context = (void *) sd; 01202 01203 /* end of callbacks */ 01204 sd->callbacks[3].id = SASL_CB_LIST_END; 01205 sd->callbacks[3].proc = NULL; 01206 sd->callbacks[3].context = NULL; 01207 01208 /* handshake start */ 01209 ret = sasl_client_new(appname, (s->req_to != NULL) ? s->req_to : "", NULL, NULL, sd->callbacks, 0, &sd->sasl); 01210 if(ret != SASL_OK) { 01211 _sx_debug(ZONE, "sasl_client_new failed, (%s), not authing", sasl_errstring(ret, NULL, NULL)); 01212 01213 if (sd->user != NULL) free(sd->user); 01214 if (sd->psecret != NULL) free(sd->psecret); 01215 free(sd->callbacks); 01216 free(sd); 01217 01218 return 1; 01219 } 01220 01221 /* get external data from the ssl plugin */ 01222 ext_id = NULL; 01223 #ifdef HAVE_SSL 01224 for(i = 0; i < s->env->nplugins; i++) 01225 if(s->env->plugins[i]->magic == SX_SSL_MAGIC && s->plugin_data[s->env->plugins[i]->index] != NULL) 01226 ext_id = ((_sx_ssl_conn_t) s->plugin_data[s->env->plugins[i]->index])->external_id; 01227 01228 /* !!! XXX certs */ 01229 /* 01230 if(ext != NULL) { 01231 ext->external_id = strdup("foo"); 01232 ext->external_ssf = 20; 01233 } 01234 */ 01235 01236 /* if we've got some, setup for external auth */ 01237 if(ext_id != NULL) { 01238 ret = sasl_setprop(sd->sasl, SASL_AUTH_EXTERNAL, ext_id); 01239 if(ret == SASL_OK) ret = sasl_setprop(sd->sasl, SASL_SSF_EXTERNAL, &s->ssf); 01240 } 01241 #endif /* HAVE_SSL */ 01242 01243 /* setup security properties */ 01244 sec_props = ctx->sec_props; 01245 if(s->ssf > 0) 01246 /* if we're already encrypted, then no security layers */ 01247 sec_props.max_ssf = 0; 01248 01249 ret = sasl_setprop(sd->sasl, SASL_SEC_PROPS, &sec_props); 01250 if(ret != SASL_OK) { 01251 _sx_debug(ZONE, "sasl_setprop failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); 01252 01253 sasl_dispose(&sd->sasl); 01254 01255 if (sd->user != NULL) free(sd->user); 01256 if (sd->psecret != NULL) free(sd->psecret); 01257 free(sd->callbacks); 01258 free(sd); 01259 01260 return 1; 01261 } 01262 01263 /* handshake start */ 01264 ret = sasl_client_start(sd->sasl, mech, NULL, (const char **) &out, &outlen, NULL); 01265 if(ret != SASL_OK && ret != SASL_CONTINUE) { 01266 _sx_debug(ZONE, "sasl_client_start failed (%s), not authing", sasl_errstring(ret, NULL, NULL)); 01267 01268 sasl_dispose(&sd->sasl); 01269 01270 if (sd->user != NULL) free(sd->user); 01271 if (sd->psecret != NULL) free(sd->psecret); 01272 free(sd->callbacks); 01273 free(sd); 01274 01275 return 1; 01276 } 01277 01278 /* save userdata */ 01279 s->plugin_data[p->index] = (void *) sd; 01280 01281 /* in progress */ 01282 _sx_debug(ZONE, "sending auth request to server, mech '%s': %.*s", mech, outlen, out); 01283 01284 /* encode the challenge */ 01285 _sx_sasl_encode(out, outlen, &buf, &buflen); 01286 01287 /* build the nad */ 01288 nad = nad_new(); 01289 ns = nad_add_namespace(nad, uri_SASL, NULL); 01290 01291 nad_append_elem(nad, ns, "auth", 0); 01292 nad_append_attr(nad, -1, "mechanism", mech); 01293 if(buf != NULL) { 01294 nad_append_cdata(nad, buf, buflen, 1); 01295 free(buf); 01296 } 01297 01298 /* its away */ 01299 sx_nad_write(s, nad); 01300 01301 return 0; 01302 }