⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl.c

📁 这是一个完全开放的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 *//** * this plugin implements the traditional SSL "wrappermode" streams and * STARTTLS extension documented in xmpp-core */#include "sx.h"#ifdef HAVE_SSL#include "ssl.h"static void _sx_ssl_starttls_notify_proceed(sx_t s, void *arg) {    _sx_debug(ZONE, "preparing for starttls");    _sx_reset(s);    /* start listening */    sx_server_init(s, s->flags | SX_SSL_WRAPPER);}static int _sx_ssl_process(sx_t s, sx_plugin_t p, nad_t nad) {    int flags;    char *ns = NULL, *to = NULL, *from = NULL, *version = NULL;    sx_error_t sxe;    /* not interested if we're a server and we never offered it */    if(s->type == type_SERVER && !(s->flags & SX_SSL_STARTTLS_OFFER))        return 1;    /* only want tls packets */    if(NAD_ENS(nad, 0) < 0 || NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_TLS) || strncmp(NAD_NURI(nad, NAD_ENS(nad, 0)), uri_TLS, strlen(uri_TLS)) != 0)        return 1;    /* starttls from client */    if(s->type == type_SERVER) {        if(NAD_ENAME_L(nad, 0) == 8 || strncmp(NAD_ENAME(nad, 0), "starttls", 8) == 0) {            nad_free(nad);                /* can't go on if we've been here before */            if(s->ssf > 0) {                _sx_debug(ZONE, "starttls requested on already encrypted channel, dropping packet");                return 0;            }            _sx_debug(ZONE, "starttls requested, setting up");            /* go ahead */            jqueue_push(s->wbufq, _sx_buffer_new("<proceed xmlns='" uri_TLS "'/>", strlen(uri_TLS) + 19, _sx_ssl_starttls_notify_proceed, NULL), 0);            s->want_write = 1;            /* handled the packet */            return 0;        }    }    else if(s->type == type_CLIENT) {        /* kick off the handshake */        if(NAD_ENAME_L(nad, 0) == 7 || strncmp(NAD_ENAME(nad, 0), "proceed", 7) == 0) {            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, "server ready for ssl, starting");            /* second time round */            sx_client_init(s, flags | SX_SSL_WRAPPER, 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;        }        /* busted server */        if(NAD_ENAME_L(nad, 0) == 7 || strncmp(NAD_ENAME(nad, 0), "failure", 7) == 0) {            nad_free(nad);            /* free the pemfile arg */            if(s->plugin_data[p->index] != NULL)                free(s->plugin_data[p->index]);            _sx_debug(ZONE, "server can't handle ssl, business as usual");            _sx_gen_error(sxe, SX_ERR_STARTTLS_FAILURE, "STARTTLS failure", "Server was unable to prepare for the TLS handshake");            _sx_event(s, event_ERROR, (void *) &sxe);            return 0;        }    }    _sx_debug(ZONE, "unknown starttls namespace element '%.*s', dropping packet", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0));    nad_free(nad);    return 0;}static void _sx_ssl_features(sx_t s, sx_plugin_t p, nad_t nad) {    int ns;    /* if the session is already encrypted, or the app told us not to, then we don't offer anything */    if(s->state > state_STREAM || s->ssf > 0 || !(s->flags & SX_SSL_STARTTLS_OFFER))        return;    _sx_debug(ZONE, "offering starttls");    ns = nad_add_namespace(nad, uri_TLS, NULL);    nad_append_elem(nad, ns, "starttls", 1);    if(s->flags & SX_SSL_STARTTLS_REQUIRE)        nad_append_elem(nad, ns, "required", 2);}static int _sx_ssl_handshake(sx_t s, _sx_ssl_conn_t sc) {    int ret, err;    char *errstring;    sx_error_t sxe;    /* work on establishing the channel */    while(!SSL_is_init_finished(sc->ssl)) {        _sx_debug(ZONE, "secure channel not established, handshake in progress");        /* we can't handshake if they want to read, but there's nothing to read */        if(sc->last_state == SX_SSL_STATE_WANT_READ && BIO_pending(sc->rbio) == 0)            return 0;        /* more handshake */        if(s->type == type_CLIENT)            ret = SSL_connect(sc->ssl);        else            ret = SSL_accept(sc->ssl);        /* check if we're done */        if(ret == 1) {            _sx_debug(ZONE, "secure channel established");            sc->last_state = SX_SSL_STATE_NONE;            s->ssf = SSL_get_cipher_bits(sc->ssl, NULL);            _sx_debug(ZONE, "using cipher %s (%d bits)", SSL_get_cipher_name(sc->ssl), s->ssf);            return 1;        }        /* error checking */        else if(ret <= 0) {            err = SSL_get_error(sc->ssl, ret);            if(err == SSL_ERROR_WANT_READ)                sc->last_state = SX_SSL_STATE_WANT_READ;            else if(err == SSL_ERROR_WANT_WRITE)                sc->last_state = SX_SSL_STATE_WANT_WRITE;            else {                /* fatal error */                sc->last_state = SX_SSL_STATE_ERROR;                errstring = ERR_error_string(ERR_get_error(), NULL);                _sx_debug(ZONE, "openssl error: %s", errstring);                /* throw an error */                _sx_gen_error(sxe, SX_ERR_SSL, "SSL handshake error", errstring);                _sx_event(s, event_ERROR, (void *) &sxe);                _sx_error(s, stream_err_INTERNAL_SERVER_ERROR, errstring);                _sx_close(s);                /* !!! drop queue */                return -1;            }        }    }    return 1;}static int _sx_ssl_wio(sx_t s, sx_plugin_t p, sx_buf_t buf) {    _sx_ssl_conn_t sc = (_sx_ssl_conn_t) s->plugin_data[p->index];    int est, ret, err;    sx_buf_t wbuf;    char *errstring;    sx_error_t sxe;    /* sanity */    if(sc->last_state == SX_SSL_STATE_ERROR)        return -2;    _sx_debug(ZONE, "in _sx_ssl_wio");    /* queue the buffer */    if(buf->len > 0) {        _sx_debug(ZONE, "queueing buffer for write");        jqueue_push(sc->wq, _sx_buffer_new(buf->data, buf->len, buf->notify, buf->notify_arg), 0);        _sx_buffer_clear(buf);        buf->notify = NULL;        buf->notify_arg = NULL;    }    /* handshake */    est = _sx_ssl_handshake(s, sc);    if(est < 0)        return -2;  /* fatal error */    /* channel established, do some real writing */    wbuf = NULL;    if(est > 0 && jqueue_size(sc->wq) > 0) {        _sx_debug(ZONE, "preparing queued buffer for write");        wbuf = jqueue_pull(sc->wq);        ret = SSL_write(sc->ssl, wbuf->data, wbuf->len);        if(ret <= 0) {            /* something's wrong */            _sx_debug(ZONE, "write failed, requeuing buffer");            /* requeue the buffer */            jqueue_push(sc->wq, wbuf, (sc->wq->front != NULL) ? sc->wq->front->priority + 1 : 0);            /* error checking */            err = SSL_get_error(sc->ssl, ret);            if(err == SSL_ERROR_ZERO_RETURN) {                /* ssl channel closed, we're done */                _sx_close(s);            }            if(err == SSL_ERROR_WANT_READ) {                /* we'll be renegotiating next time */                _sx_debug(ZONE, "renegotiation started");                sc->last_state = SX_SSL_STATE_WANT_READ;            }            else {                sc->last_state = SX_SSL_STATE_ERROR;                /* something very bad */                errstring = ERR_error_string(ERR_get_error(), NULL);                _sx_debug(ZONE, "openssl error: %s", errstring);                /* throw an error */                _sx_gen_error(sxe, SX_ERR_SSL, "SSL handshake error", errstring);                _sx_event(s, event_ERROR, (void *) &sxe);                _sx_error(s, stream_err_INTERNAL_SERVER_ERROR, errstring);                _sx_close(s);                /* !!! drop queue */                return -2;  /* fatal */            }        }    }    /* prepare the buffer with stuff to write */    if(BIO_pending(sc->wbio) > 0) {        int bytes_pending = BIO_pending(sc->wbio);        assert(buf->len == 0);        _sx_buffer_alloc_margin(buf, 0, bytes_pending);        BIO_read(sc->wbio, buf->data, bytes_pending);        buf->len += bytes_pending;        /* restore notify and clean up */        if(wbuf != NULL) {            buf->notify = wbuf->notify;            buf->notify_arg = wbuf->notify_arg;            _sx_buffer_free(wbuf);        }        _sx_debug(ZONE, "prepared %d ssl bytes for write", buf->len);    }    /* flag if we want to read */    if(sc->last_state == SX_SSL_STATE_WANT_READ || sc->last_state == SX_SSL_STATE_NONE)        s->want_read = 1;    return 1;}static int _sx_ssl_rio(sx_t s, sx_plugin_t p, sx_buf_t buf) {    _sx_ssl_conn_t sc = (_sx_ssl_conn_t) s->plugin_data[p->index];    int est, ret, err, pending;    char *errstring;    sx_error_t sxe;    /* sanity */    if(sc->last_state == SX_SSL_STATE_ERROR)        return -1;    _sx_debug(ZONE, "in _sx_ssl_rio");    /* move the data into the ssl read buffer */    if(buf->len > 0) {        _sx_debug(ZONE, "loading %d bytes into ssl read buffer", buf->len);        BIO_write(sc->rbio, buf->data, buf->len);        _sx_buffer_clear(buf);    }    /* handshake */    est = _sx_ssl_handshake(s, sc);    if(est < 0)        return -1;  /* fatal error */    /* channel is up, slurp up the read buffer */    if(est > 0) {        pending = SSL_pending(sc->ssl);        if(pending == 0)            pending = BIO_pending(sc->rbio);        /* get it all */        while((pending = SSL_pending(sc->ssl)) > 0 || (pending = BIO_pending(sc->rbio)) > 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -