📄 sasl.c
字号:
if(out != NULL) free(out); _sx_nad_write(s, _sx_sasl_response(s, buf, buflen), 0); if(buf != NULL) free(buf); return; } if(out != NULL) free(out); /* its over */ _sx_debug(ZONE, "sasl handshake aborted: (%d)", ret); _sx_nad_write(s, _sx_sasl_abort(s), 0);}/** main nad processor */static int _sx_sasl_process(sx_t s, sx_plugin_t p, nad_t nad) { scod_t sd = (scod_t) s->plugin_data[p->index]; int attr; char mech[128]; sx_error_t sxe; int flags; char *ns = NULL, *to = NULL, *from = NULL, *version = NULL; /* only want sasl packets */ 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) return 1; /* quietly drop it if sasl is disabled, or if not ready */ if(s->state != state_STREAM) { _sx_debug(ZONE, "not correct state for sasl, ignoring"); nad_free(nad); return 0; } /* packets from the client */ if(s->type == type_SERVER) { if(!(s->flags & SX_SASL_OFFER)) { _sx_debug(ZONE, "they tried to do sasl, but we never offered it, ignoring"); nad_free(nad); return 0; }#ifdef HAVE_SSL if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { _sx_debug(ZONE, "they tried to do sasl, but they have to do starttls first, ignoring"); nad_free(nad); return 0; }#endif /* auth */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp("auth", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* require mechanism */ if((attr = nad_find_attr(nad, 0, -1, "mechanism", NULL)) < 0) { _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); nad_free(nad); return 0; } /* extract */ snprintf(mech, 127, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); /* go */ _sx_sasl_client_process(s, p, sd, mech, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* response */ else if(NAD_ENAME_L(nad, 0) == 8 && strncmp("response", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ _sx_sasl_client_process(s, p, sd, NULL, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* abort */ else if(NAD_ENAME_L(nad, 0) == 5 && strncmp("abort", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { _sx_debug(ZONE, "sasl handshake aborted"); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_ABORTED), 0); nad_free(nad); return 0; } } /* packets from the server */ else if(s->type == type_CLIENT) { if(sd == NULL) { _sx_debug(ZONE, "got sasl client packets, but they never started sasl, ignoring"); nad_free(nad); return 0; } /* challenge */ if(NAD_ENAME_L(nad, 0) == 9 && strncmp("challenge", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* process it */ _sx_sasl_server_process(s, p, sd, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)); nad_free(nad); return 0; } /* success */ else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("success", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { _sx_debug(ZONE, "sasl handshake completed, resetting"); nad_free(nad); /* save interesting bits */ flags = s->flags; if(s->ns != NULL) ns = strdup(s->ns); if(s->req_to != NULL) to = strdup(s->req_to); if(s->req_from != NULL) from = strdup(s->req_from); if(s->req_version != NULL) version = strdup(s->req_version); /* reset state */ _sx_reset(s); _sx_debug(ZONE, "restarting stream with sasl layer established"); /* second time round */ sx_client_init(s, flags, ns, to, from, version); /* free bits */ if(ns != NULL) free(ns); if(to != NULL) free(to); if(from != NULL) free(from); if(version != NULL) free(version); return 0; } /* failure */ else if(NAD_ENAME_L(nad, 0) == 7 && strncmp("failure", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) == 0) { /* fire the error */ _sx_gen_error(sxe, SX_ERR_AUTH, "Authentication failed", NULL); _sx_event(s, event_ERROR, (void *) &sxe); /* cleanup */ scod_free(sd); s->plugin_data[p->index] = NULL; nad_free(nad); return 0; } } /* invalid sasl command, quietly drop it */ _sx_debug(ZONE, "unknown sasl command '%.*s', ignoring", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0;}/** cleanup */static void _sx_sasl_free(sx_t s, sx_plugin_t p) { scod_t sd = (scod_t) s->plugin_data[p->index]; if(sd == NULL) return; _sx_debug(ZONE, "cleaning up conn state"); scod_free(sd); s->plugin_data[p->index] = NULL;}static int _sx_sasl_scod_callback(scod_t sd, int cb, void *arg, void **res, void *cbarg) { _sx_sasl_t ctx = (_sx_sasl_t) cbarg; xht realms; switch(cb) { case sd_cb_DIGEST_MD5_CHOOSE_REALM: realms = (xht) arg; if(xhash_iter_first(realms)) xhash_iter_get(realms, (const char **) res, NULL); else *res = NULL; break; case sd_cb_GET_PASS: assert((int) ctx->cb); return (ctx->cb)(sx_sasl_cb_GET_PASS, arg, res, sd, ctx->cbarg); case sd_cb_CHECK_PASS: assert((int) ctx->cb); return (ctx->cb)(sx_sasl_cb_CHECK_PASS, arg, res, sd, ctx->cbarg); case sd_cb_CHECK_AUTHZID: assert((int) ctx->cb); return (ctx->cb)(sx_sasl_cb_CHECK_AUTHZID, arg, res, sd, ctx->cbarg); case sd_cb_ANONYMOUS_GEN_AUTHZID: assert((int) ctx->cb); return (ctx->cb)(sx_sasl_cb_GEN_AUTHZID, arg, res, sd, ctx->cbarg); default: break; } return 0;}static void _sx_sasl_unload(sx_plugin_t p) { free(p->private);}/** args: realm callback, cb arg, scod flags */int sx_sasl_init(sx_env_t env, sx_plugin_t p, va_list args) { sx_sasl_callback_t cb; void *cbarg; int flags; _sx_sasl_t ctx; _sx_debug(ZONE, "initialising sasl plugin"); cb = va_arg(args, sx_sasl_callback_t); cbarg = va_arg(args, void *); flags = va_arg(args, int); ctx = (_sx_sasl_t) malloc(sizeof(struct _sx_sasl_st)); memset(ctx, 0, sizeof(struct _sx_sasl_st)); ctx->cb = cb; ctx->cbarg = cbarg; ctx->flags = flags; ctx->scod_ctx = scod_ctx_new(_sx_sasl_scod_callback, ctx); if(ctx->scod_ctx == NULL) { _sx_debug(ZONE, "couldn't create scod context, disabling"); free(ctx); return 1; } _sx_debug(ZONE, "sasl context initialised"); p->private = (void *) ctx; p->unload = _sx_sasl_unload; p->stream = _sx_sasl_stream; p->features = _sx_sasl_features; p->process = _sx_sasl_process; p->free = _sx_sasl_free; return 0;}/** kick off the auth handshake */int sx_sasl_auth(sx_plugin_t p, sx_t s, char *mech, char *user, char *pass, char *authzid) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; scod_t sd; char *buf, *out; int ret, buflen, outlen, ns; nad_t nad; assert((int) p); assert((int) s); assert((int) mech); assert((int) user); assert((int) pass); if(s->type != type_CLIENT || s->state != state_STREAM) { _sx_debug(ZONE, "need client in stream state for sasl auth"); return 1; } /* startup */ sd = scod_new(ctx->scod_ctx, sd_type_CLIENT); if(sd == NULL) { _sx_debug(ZONE, "couldn't create scod instance, not authing"); return 1; } /* handshake start */ ret = scod_client_start(sd, mech, authzid, user, pass, &out, &outlen); if(ret != sd_SUCCESS && ret != sd_CONTINUE) { _sx_debug(ZONE, "scod_client_start failed (%d), not authing", ret); if(out != NULL) free(out); scod_free(sd); return 1; } /* save userdata */ s->plugin_data[p->index] = (void *) sd; /* in progress */ _sx_debug(ZONE, "sending auth request to server, mech '%s': %.*s", mech, outlen, out); /* encode the challenge */ _sx_sasl_encode(out, outlen, &buf, &buflen); free(out); /* build the nad */ nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "auth", 0); nad_append_attr(nad, -1, "mechanism", mech); if(buf != NULL) { nad_append_cdata(nad, buf, buflen, 1); free(buf); } /* its away */ sx_nad_write(s, nad); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -