📄 c2s.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 */#include "c2s.h"static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { sess_t sess = (sess_t) arg; sx_buf_t buf = (sx_buf_t) data; int rlen, len, ns, elem, attr, i, r; sx_error_t *sxe; nad_t nad; char root[9]; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(sess->c2s->mio, sess->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(sess->c2s->mio, sess->fd); break; case event_READ: log_debug(ZONE, "reading from %d", sess->fd); /* check rate limits */ if(sess->rate != NULL) { if(rate_check(sess->rate) == 0) { /* inform the app if we haven't already */ if(!sess->rate_log) { if(s->state >= state_STREAM && sess->jid != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] is being byte rate limited", sess->fd, sess->jid); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] is being byte rate limited", sess->fd, sess->ip, sess->port); sess->rate_log = 1; } log_debug(ZONE, "%d is throttled, delaying read", sess->fd); buf->len = 0; return 0; } /* find out how much we can have */ rlen = rate_left(sess->rate); if(rlen > buf->len) rlen = buf->len; } /* do the read */ len = recv(sess->fd, buf->data, buf->len, 0); if(len < 0) { if(errno == EWOULDBLOCK || errno == EINTR || errno == EAGAIN) { buf->len = 0; return 0; } if(s->state >= state_STREAM && sess->jid != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] read error: %s (%d)", sess->fd, jid_full(sess->jid), strerror(errno), errno); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", sess->fd, sess->ip, sess->port, strerror(errno), errno); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", sess->fd); len = send(sess->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(errno == EWOULDBLOCK || errno == EINTR || errno == EAGAIN) return 0; if(s->state >= state_OPEN && sess->jid != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] write error: %s (%d)", sess->fd, jid_full(sess->jid), strerror(errno), errno); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s. port=%d] write error: %s (%d)", sess->fd, sess->ip, sess->port, strerror(errno), errno); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; if(sess->jid != NULL) log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] error: %s (%s)", sess->fd, jid_full(sess->jid), sxe->generic, sxe->specific); else log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", sess->fd, sess->ip, sess->port, sxe->generic, sxe->specific); break; case event_STREAM: if(s->req_to == NULL) { log_debug(ZONE, "no stream to provided, closing"); sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header"); sx_close(s); return 0; } /* setup the realm */ sess->realm = xhash_get(sess->c2s->realms, s->req_to); if(sess->realm == NULL) { log_debug(ZONE, "no service available for requested domain '%s'", s->req_to); sx_error(s, stream_err_HOST_UNKNOWN, "service requested for unknown domain"); sx_close(s); return 0; } if(xhash_get(sess->c2s->sm_avail, s->req_to) == NULL) { log_debug(ZONE, "sm for domain '%s' is not online", s->req_to); sx_error(s, stream_err_HOST_GONE, "session manager for requested domain is not available"); sx_close(s); return 0; } break; case event_PACKET: nad = (nad_t) data; /* we only want (message|presence|iq) in jabber:client, everything else gets dropped */ snprintf(root, 9, "%.*s", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); if(NAD_ENS(nad, 0) != nad_find_namespace(nad, 0, uri_CLIENT, NULL) || (strcmp(root, "message") != 0 && strcmp(root, "presence") != 0 && strcmp(root, "iq") != 0)) { nad_free(nad); return 0; } /* pre-session requests */ if(!sess->active && sess->sasl_authd && sess->result == NULL && strcmp(root, "iq") == 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) { /* resource bind */ if(!sess->bound && (ns = nad_find_scoped_namespace(nad, uri_BIND, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "bind", 1)) >= 0) { sess->jid = jid_new(sess->c2s->pc, sess->s->auth_id, 0); /* get the resource */ elem = nad_find_elem(nad, elem, ns, "resource", 1); /* user-specified resource */ if(elem >= 0) { if(NAD_CDATA_L(nad, elem) == 0) { log_debug(ZONE, "no resource specified on bind"); sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } snprintf(sess->jid->resource, sizeof(sess->jid->resource), "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); /* prep the resource */ if(jid_prep(sess->jid) != 0) { jid_free(sess->jid); sess->jid = NULL; sx_nad_write(sess->s, stanza_error(nad, 0, stanza_err_BAD_REQUEST)); return 0; } /* !!! xmpp-core-19 requires that the resource be unused, and that an * error be returned if its not. this is hard for us todo, and * might not be the right thing anyway (it basically gets rid * of the session replacement functionality, though that is not * as important now that resources can be generated). clarification * sought from the xmppwg */ } /* generated resource */ else { for(i = 0; i < 256; i++) { r = (int) (36.0 * rand() / RAND_MAX); sess->jid->resource[i] = (r >= 0 && r <= 0) ? (r + 48) : (r + 87); } shahash_r(sess->jid->resource, sess->jid->resource); jid_prep(sess->jid); } log_write(sess->c2s->log, LOG_NOTICE, "[%d] bound: jid=%s", sess->s->tag, jid_full(sess->jid)); sess->bound = 1; sess->result = nad_new(sess->s->nad_cache); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); ns = nad_add_namespace(sess->result, uri_BIND, NULL); nad_append_elem(sess->result, ns, "bind", 1); nad_append_elem(sess->result, ns, "jid", 2); nad_append_cdata(sess->result, jid_full(sess->jid), strlen(jid_full(sess->jid)), 3); sx_nad_write(sess->s, stanza_tofrom(sess->result, 0)); sess->result = NULL; nad_free(nad); return 0; } /* new-style session request */ else if(sess->bound && (ns = nad_find_scoped_namespace(nad, uri_XSESSION, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "session", 1)) >= 0) { /* our local id */ sprintf(sess->c2s_id, "%d", sess->s->tag); log_write(sess->c2s->log, LOG_NOTICE, "[%d] requesting session: jid=%s", sess->s->tag, jid_full(sess->jid)); /* build a result packet, we'll send this back to the client after we have a session for them */ sess->result = nad_new(sess->s->nad_cache); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* start a session with the sm */ sm_start(sess); /* finished with the nad */ nad_free(nad); /* handled */ return 0; } log_debug(ZONE, "unrecognised pre-session packet, bye"); sx_error(s, stream_err_NOT_AUTHORIZED, NULL); sx_close(s); nad_free(nad); return 0; }#ifdef HAVE_SSL /* drop packets if they have to starttls and they haven't */ if((sess->s->flags & SX_SSL_STARTTLS_REQUIRE) && sess->s->ssf == 0) { nad_free(nad); return 0; }#endif /* handle iq:auth packets */ if(authreg_process(sess->c2s, sess, nad) == 0) return 0; /* drop it if no session */ if(!sess->active) { log_debug(ZONE, "pre-session packet, bye"); sx_error(s, stream_err_NOT_AUTHORIZED, NULL); sx_close(s); nad_free(nad); return 0; } /* pass it on to the session manager */ sm_packet(sess, nad); break; case event_OPEN: /* only send a result and bring us online if this wasn't a sasl auth */ if(strlen(s->auth_method) < 4 || strncmp("SASL", s->auth_method, 4) != 0) { /* return the auth result to the client */ sx_nad_write(s, sess->result); sess->result = NULL; /* we're good to go */ sess->active = 1; } /* they sasl auth'd, so we only want the new-style session start */ else { log_write(sess->c2s->log, LOG_NOTICE, "[%d] SASL authentication succeeded: mechanism=%s; authzid=%s", sess->s->tag, &sess->s->auth_method[5], sess->s->auth_id); sess->sasl_authd = 1; } break; case event_CLOSED: mio_close(sess->c2s->mio, sess->fd); break; } return 0;}static int _c2s_client_accept_check(c2s_t c2s, int fd, char *ip) { rate_t rt; if(access_check(c2s->access, ip) == 0) { log_write(c2s->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd, ip); return 1; } if(c2s->conn_rate_total != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -