📄 sasl.c
字号:
/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA *//* SASL authentication handler */#include "sx.h"#include "ssl.h"#include "sasl.h"#define _sasl_err_ABORTED "aborted"#define _sasl_err_BAD_PROTOCOL "bad-protocol"#define _sasl_err_INCORRECT_ENCODING "incorrect-encoding"#define _sasl_err_INVALID_AUTHZID "invalid-authzid"#define _sasl_err_INVALID_MECHANISM "invalid-mechanism"#define _sasl_err_MECH_TOO_WEAK "mechanism-too-weak"#define _sasl_err_NOT_AUTHORIZED "not-authorized"#define _sasl_err_TEMPORARY_FAILURE "temporary-authentication-failure"/** move the stream to the auth state */void _sx_sasl_open(sx_t s, scod_t sd) { char *method; /* get the method */ method = (char *) malloc(sizeof(char) * (strlen(sd->mech->name) + 6)); sprintf(method, "SASL/%s", sd->mech->name); /* schwing! */ sx_auth(s, method, sd->authzid); free(method);}/** make the stream suthenticated second time round */static void _sx_sasl_stream(sx_t s, sx_plugin_t p) { scod_t sd = (scod_t) s->plugin_data[p->index]; /* do nothing the first time */ if(sd == NULL) return; /* are we auth'd? */ if(!sd->authd) { _sx_debug(ZONE, "not auth'd, not advancing to auth'd state yet"); return; } /* otherwise, its auth time */ _sx_sasl_open(s, sd);}static void _sx_sasl_features(sx_t s, sx_plugin_t p, nad_t nad) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; scod_t sd = (scod_t) s->plugin_data[p->index]; int i, ns; if(s->type != type_SERVER) return; if(sd != NULL && sd->authd) { _sx_debug(ZONE, "already auth'd, not offering sasl mechanisms"); return; } if(!(s->flags & SX_SASL_OFFER)) { _sx_debug(ZONE, "application didn't ask us to offer sasl, so we won't"); return; } if(!(s->flags & SX_SASL_MECH_ANONYMOUS || s->flags & SX_SASL_MECH_PLAIN || s->flags & SX_SASL_MECH_DIGESTMD5)) { _sx_debug(ZONE, "application didn't provide any mechanisms we can offer"); return; }#ifdef HAVE_SSL if((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0) { _sx_debug(ZONE, "ssl not established yet but the app requires it, not offering mechanisms"); return; }#endif _sx_debug(ZONE, "offering sasl mechanisms"); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "mechanisms", 1); for(i = 0; i < ctx->scod_ctx->nmechs; i++) if(ctx->scod_ctx->mechs[i]->flags == 0 || ctx->flags & ctx->scod_ctx->mechs[i]->flags) { if((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", ctx->scod_ctx->names[i]) == 0) || (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", ctx->scod_ctx->names[i]) == 0) || (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", ctx->scod_ctx->names[i]) == 0)) { _sx_debug(ZONE, "offering mechanism: %s", ctx->scod_ctx->names[i]); nad_append_elem(nad, ns, "mechanism", 2); nad_append_cdata(nad, ctx->scod_ctx->names[i], strlen(ctx->scod_ctx->names[i]), 3); } }}/** utility: generate a success nad */static nad_t _sx_sasl_success(sx_t s) { nad_t nad; int ns; nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "success", 0); return nad;}/** utility: generate a failure nad */static nad_t _sx_sasl_failure(sx_t s, const char *err) { nad_t nad; int ns; nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "failure", 0); if(err != NULL) nad_append_elem(nad, ns, err, 1); return nad;}/** utility: generate a challenge nad */static nad_t _sx_sasl_challenge(sx_t s, char *data, int dlen) { nad_t nad; int ns; nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "challenge", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad;}/** utility: generate a response nad */static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) { nad_t nad; int ns; nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "response", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad;}/** utility: generate an abort nad */static nad_t _sx_sasl_abort(sx_t s) { nad_t nad; int ns; nad = nad_new(s->nad_cache); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "abort", 0); return nad;}/** utility: decode incoming handshake data */static void _sx_sasl_decode(char *in, int inlen, char **out, int *outlen) { *outlen = ap_base64decode_len(in, inlen); *out = (char *) malloc(sizeof(char) * (*outlen + 1)); ap_base64decode(*out, in, inlen);}/** utility: encode outgoing handshake data */static void _sx_sasl_encode(char *in, int inlen, char **out, int *outlen) { *outlen = ap_base64encode_len(inlen); *out = (char *) malloc(sizeof(char) * *outlen); ap_base64encode(*out, in, inlen); (*outlen)--;}/** auth done, restart the stream */static void _sx_sasl_notify_success(sx_t s, void *arg) { _sx_debug(ZONE, "auth completed, resetting"); _sx_reset(s); sx_server_init(s, s->flags);}/** process handshake packets from the client */static void _sx_sasl_client_process(sx_t s, sx_plugin_t p, scod_t sd, char *mech, char *in, int inlen) { _sx_sasl_t ctx = (_sx_sasl_t) p->private; char realm[256]; char *buf, *out; int buflen, outlen, ret; if(mech != NULL) { _sx_debug(ZONE, "auth request from client (mechanism=%s)", mech); if(!((s->flags & SX_SASL_MECH_ANONYMOUS && strcmp("ANONYMOUS", mech) == 0) || (s->flags & SX_SASL_MECH_PLAIN && strcmp("PLAIN", mech) == 0) || (s->flags & SX_SASL_MECH_DIGESTMD5 && strcmp("DIGEST-MD5", mech) == 0))) { _sx_debug(ZONE, "client requested mechanism that we didn't offer"); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_INVALID_MECHANISM), 0); return; } /* startup */ sd = scod_new(ctx->scod_ctx, sd_type_SERVER); if(sd == NULL) { _sx_debug(ZONE, "scod_new failed, no sasl for this conn"); _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0); return; } _sx_debug(ZONE, "sasl context initialised for %d", s->tag); s->plugin_data[p->index] = (void *) sd; sd->app_private = (void *) s; /* get the realm */ realm[0] = '\0'; assert((int) ctx->cb); (ctx->cb)(sx_sasl_cb_GET_REALM, (void *) s, (void **) realm, sd, ctx->cbarg); /* decode and process */ _sx_sasl_decode(in, inlen, &buf, &buflen); ret = scod_server_start(sd, mech, realm, buf, buflen, &out, &outlen); } else { _sx_debug(ZONE, "response from client"); /* decode and process */ _sx_sasl_decode(in, inlen, &buf, &buflen); ret = scod_server_step(sd, buf, buflen, &out, &outlen); } if(buf != NULL) free(buf); /* auth completed */ if(ret == sd_SUCCESS) { _sx_debug(ZONE, "sasl handshake completed"); if(out != NULL) free(out); /* send success */ _sx_nad_write(s, _sx_sasl_success(s), 0); /* set a notify on the success nad buffer */ ((sx_buf_t) s->wbufq->front->data)->notify = _sx_sasl_notify_success; ((sx_buf_t) s->wbufq->front->data)->notify_arg = (void *) p; return; } /* in progress */ if(ret == sd_CONTINUE) { _sx_debug(ZONE, "sasl handshake in progress (challenge: %.*s)", outlen, out); /* encode the challenge */ _sx_sasl_encode(out, outlen, &buf, &buflen); if(out != NULL) free(out); _sx_nad_write(s, _sx_sasl_challenge(s, buf, buflen), 0); free(buf); return; } if(out != NULL) free(out); /* its over */ _sx_debug(ZONE, "sasl handshake failed: (%d)", ret); /* !!! check ret and flag error appropriately */ _sx_nad_write(s, _sx_sasl_failure(s, _sasl_err_TEMPORARY_FAILURE), 0);}/** process handshake packets from the server */static void _sx_sasl_server_process(sx_t s, sx_plugin_t p, scod_t sd, char *in, int inlen) { char *buf, *out; int buflen, outlen, ret; _sx_debug(ZONE, "challenge from client"); /* decode the response */ _sx_sasl_decode(in, inlen, &buf, &buflen); /* process the data */ ret = scod_client_step(sd, buf, buflen, &out, &outlen); if(buf != NULL) free(buf); /* in progress */ if(ret == sd_SUCCESS || ret == sd_CONTINUE) { _sx_debug(ZONE, "sasl handshake in progress (response: %.*s)", outlen, out); /* encode the response */ _sx_sasl_encode(out, outlen, &buf, &buflen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -