jabberd2  2.7.0
sm.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
30 sig_atomic_t sm_lost_router = 0;
31 
33 int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
34  sm_t sm = (sm_t) arg;
35  sx_buf_t buf = (sx_buf_t) data;
36  sx_error_t *sxe;
37  nad_t nad;
38  pkt_t pkt;
39  int len, ns, elem, attr;
40  char *domain;
41 
42  switch(e) {
43  case event_WANT_READ:
44  log_debug(ZONE, "want read");
45  mio_read(sm->mio, sm->fd);
46  break;
47 
48  case event_WANT_WRITE:
49  log_debug(ZONE, "want write");
50  mio_write(sm->mio, sm->fd);
51  break;
52 
53  case event_READ:
54  log_debug(ZONE, "reading from %d", sm->fd->fd);
55 
56  /* do the read */
57  len = recv(sm->fd->fd, buf->data, buf->len, 0);
58 
59  if (len < 0) {
60  if (MIO_WOULDBLOCK) {
61  buf->len = 0;
62  return 0;
63  }
64 
65  log_write(sm->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
66 
67  sx_kill(s);
68 
69  return -1;
70  }
71 
72  else if (len == 0) {
73  /* they went away */
74  sx_kill(s);
75 
76  return -1;
77  }
78 
79  log_debug(ZONE, "read %d bytes", len);
80 
81  buf->len = len;
82 
83  return len;
84 
85  case event_WRITE:
86  log_debug(ZONE, "writing to %d", sm->fd->fd);
87 
88  len = send(sm->fd->fd, buf->data, buf->len, 0);
89  if (len >= 0) {
90  log_debug(ZONE, "%d bytes written", len);
91  return len;
92  }
93 
94  if (MIO_WOULDBLOCK)
95  return 0;
96 
97  log_write(sm->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
98 
99  sx_kill(s);
100 
101  return -1;
102 
103  case event_ERROR:
104  sxe = (sx_error_t *) data;
105  log_write(sm->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific);
106 
107  if(sxe->code == SX_ERR_AUTH)
108  sx_close(s);
109 
110  break;
111 
112  case event_STREAM:
113  break;
114 
115  case event_OPEN:
116  log_write(sm->log, LOG_NOTICE, "connection to router established");
117 
118  /* set connection attempts counter */
120 
121  nad = nad_new();
122  ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
123  nad_append_elem(nad, ns, "bind", 0);
124  nad_append_attr(nad, -1, "name", sm->id);
125  log_debug(ZONE, "requesting component bind for '%s'", sm->id);
126  sx_nad_write(sm->router, nad);
127 
129  do {
130  xhash_iter_get(sm->hosts, (void *) &domain, &len, NULL);
131 
132  /* skip already requested SM id */
133  if (strlen(sm->id) == len && strncmp(sm->id, domain, len) == 0)
134  continue;
135 
136  nad = nad_new();
137  ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
138  elem = nad_append_elem(nad, ns, "bind", 0);
139  nad_set_attr(nad, elem, -1, "name", domain, len);
140  nad_append_attr(nad, -1, "multi", "to");
141  log_debug(ZONE, "requesting domain bind for '%.*s'", len, domain);
142  sx_nad_write(sm->router, nad);
143 
144  } while(xhash_iter_next(sm->hosts));
145  break;
146 
147  case event_PACKET:
148  nad = (nad_t) data;
149 
150  /* drop unqualified packets */
151  if (NAD_ENS(nad, 0) < 0) {
152  nad_free(nad);
153  return 0;
154  }
155  /* watch for the features packet */
156  if (s->state == state_STREAM) {
157  if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS)
158  || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0
159  || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) {
160  log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping");
161  nad_free(nad);
162  return 0;
163  }
164 
165 #ifdef HAVE_SSL
166  /* starttls if we can */
167  if (sm->sx_ssl != NULL && s->ssf == 0) {
168  ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
169  if (ns >= 0) {
170  elem = nad_find_elem(nad, 0, ns, "starttls", 1);
171  if (elem >= 0) {
172  if (sx_ssl_client_starttls(sm->sx_ssl, s, NULL, NULL) == 0) {
173  nad_free(nad);
174  return 0;
175  }
176  log_write(sm->log, LOG_NOTICE, "unable to establish encrypted session with router");
177  }
178  }
179  }
180 #endif
181 
182  /* !!! pull the list of mechanisms, and choose the best one.
183  * if there isn't an appropriate one, error and bail */
184 
185  /* authenticate */
186  sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass);
187 
188  nad_free(nad);
189  return 0;
190  }
191 
192  /* watch for the bind response */
193  if (s->state == state_OPEN && !sm->online) {
194  if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT)
195  || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0
196  || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) {
197  log_debug(ZONE, "got a packet from router, but we're not online, dropping");
198  nad_free(nad);
199  return 0;
200  }
201 
202  /* catch errors */
203  attr = nad_find_attr(nad, 0, -1, "error", NULL);
204  if(attr >= 0) {
205  log_write(sm->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
206  exit(1);
207  }
208 
209  log_debug(ZONE, "coming online");
210 
211  /* we're online */
212  sm->online = sm->started = 1;
213  log_write(sm->log, LOG_NOTICE, "%s ready for sessions", sm->id);
214 
215  nad_free(nad);
216  return 0;
217  }
218 
219  log_debug(ZONE, "got a packet");
220 
221  pkt = pkt_new(sm, nad);
222  if (pkt == NULL) {
223  log_debug(ZONE, "invalid packet, dropping");
224  return 0;
225  }
226 
227  /* go */
228  dispatch(sm, pkt);
229 
230  return 0;
231 
232  case event_CLOSED:
233  mio_close(sm->mio, sm->fd);
234  sm->fd = NULL;
235  return -1;
236  }
237 
238  return 0;
239 }
240 
241 int sm_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
242  sm_t sm = (sm_t) arg;
243  int nbytes;
244 
245  switch (a) {
246  case action_READ:
247  log_debug(ZONE, "read action on fd %d", fd->fd);
248 
249  ioctl(fd->fd, FIONREAD, &nbytes);
250  if(nbytes == 0) {
251  sx_kill(sm->router);
252  return 0;
253  }
254 
255  return sx_can_read(sm->router);
256 
257  case action_WRITE:
258  log_debug(ZONE, "write action on fd %d", fd->fd);
259  return sx_can_write(sm->router);
260 
261  case action_CLOSE:
262  log_debug(ZONE, "close action on fd %d", fd->fd);
263  log_write(sm->log, LOG_NOTICE, "connection to router closed");
264 
265  sm_lost_router = 1;
266 
267  /* we're offline */
268  sm->online = 0;
269 
270  break;
271 
272  case action_ACCEPT:
273  break;
274  }
275 
276  return 0;
277 }
278 
280 void sm_c2s_action(sess_t dest, const char *action, const char *target) {
281  nad_t nad;
282  int rns, sns;
283 
284  nad = nad_new();
285 
286  rns = nad_add_namespace(nad, uri_COMPONENT, NULL);
287  nad_append_elem(nad, rns, "route", 0);
288 
289  nad_append_attr(nad, -1, "to", dest->c2s);
290  nad_append_attr(nad, -1, "from", dest->user->sm->id);
291 
292  sns = nad_add_namespace(nad, uri_SESSION, "sc");
293  nad_append_elem(nad, sns, "session", 1);
294 
295  if (dest->c2s_id[0] != '\0')
296  nad_append_attr(nad, sns, "c2s", dest->c2s_id);
297  if (dest->sm_id[0] != '\0')
298  nad_append_attr(nad, sns, "sm", dest->sm_id);
299 
300  nad_append_attr(nad, -1, "action", action);
301  if (target != NULL)
302  nad_append_attr(nad, -1, "target", target);
303 
304  log_debug(ZONE,
305  "routing nad to %s from %s c2s %s s2s %s action %s target %s",
306  dest->c2s, dest->user->sm->id, dest->c2s_id, dest->sm_id,
307  action, target);
308 
309  sx_nad_write(dest->user->sm->router, nad);
310 }
311 
313 void sm_signature(sm_t sm, const char *str) {
314  if (sm->siglen == 0) {
315  snprintf(&sm->signature[sm->siglen], 2048 - sm->siglen, "%s", str);
316  sm->siglen += strlen(str);
317  } else {
318  snprintf(&sm->signature[sm->siglen], 2048 - sm->siglen, " %s", str);
319  sm->siglen += strlen(str) + 1;
320  }
321 }
322 
324 int sm_register_ns(sm_t sm, const char *uri) {
325  int ns_idx;
326 
327  ns_idx = (int) (long) xhash_get(sm->xmlns, uri);
328  if (ns_idx == 0) {
329  ns_idx = xhash_count(sm->xmlns) + 2;
330  xhash_put(sm->xmlns, pstrdup(xhash_pool(sm->xmlns), uri), (void *) (long) ns_idx);
331  }
332  xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) + 1));
333 
334  return ns_idx;
335 }
336 
338 void sm_unregister_ns(sm_t sm, const char *uri) {
339  int refcount = (int) (long) xhash_get(sm->xmlns_refcount, uri);
340  if (refcount == 1) {
341  xhash_zap(sm->xmlns, uri);
342  xhash_zap(sm->xmlns_refcount, uri);
343  } else if (refcount > 1) {
344  xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) - 1));
345  }
346 }
347 
349 int sm_get_ns(sm_t sm, const char *uri) {
350  return (int) (long) xhash_get(sm->xmlns, uri);
351 }
352 
353 // Rate limit check: Prevent denial-of-service due to excessive database queries
354 // Make sure owner is responsible for the query!
355 int sm_storage_rate_limit(sm_t sm, const char *owner) {
356  rate_t rt;
357  user_t user;
358  sess_t sess;
359  item_t item;
360 
361  if (sm->query_rate_total == 0 || owner == NULL)
362  return FALSE;
363 
364  user = xhash_get(sm->users, owner);
365  if (user != NULL) {
366  rt = (rate_t) xhash_get(sm->query_rates, owner);
367  if (rt == NULL) {
369  xhash_put(sm->query_rates, pstrdup(xhash_pool(sm->query_rates), owner), (void *) rt);
370  pool_cleanup(xhash_pool(sm->query_rates), (void (*)(void *)) rate_free, rt);
371  }
372 
373  if(rate_check(rt) == 0) {
374  log_write(sm->log, LOG_WARNING, "[%s] is being disconnected, too many database queries within %d seconds", owner, sm->query_rate_seconds);
375  user = xhash_get(sm->users, owner);
376  for (sess = user->sessions; sess != NULL; sess = sess->next) {
377  sm_c2s_action(sess, "ended", NULL);
378  }
379  if(xhash_iter_first(user->roster))
380  do {
381  xhash_iter_get(user->roster, NULL, NULL, (void *) &item);
382  if(item->to) {
383  pkt_router(pkt_create(user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(user->jid)));
384  }
385  } while(xhash_iter_next(user->roster));
386  return TRUE;
387  } else {
388  rate_add(rt, 1);
389  }
390  } else {
391  log_debug(ZONE, "Error: could not get user data for %s", owner);
392  }
393  return FALSE;
394 }
user_t user
user this session belongs to
Definition: sm.h:256
xht roster
roster for this user (key is full jid of item, value is item_t)
Definition: sm.h:241
int sm_register_ns(sm_t sm, const char *uri)
register a new global ns
Definition: sm.c:324
static sm_t sm
Definition: main.c:33
Definition: nad.h:93
xht query_rates
Definition: sm.h:230
nad_t nad_new(void)
create a new nad
Definition: nad.c:125
Definition: sx.h:113
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
attach new attr to the last elem
Definition: nad.c:745
data structures and prototypes for the session manager
_sx_state_t state
Definition: sx.h:319
int query_rate_seconds
Definition: sm.h:228
const char * id
component id
Definition: sm.h:168
#define sx_nad_write(s, nad)
Definition: sx.h:167
void sm_unregister_ns(sm_t sm, const char *uri)
unregister a global ns
Definition: sm.c:338
Definition: sx.h:59
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
int nad_find_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
Definition: nad.c:237
log_t log
log context
Definition: sm.h:200
void rate_add(rate_t rt, int count)
Add a number of events to the counter.
Definition: rate.c:48
void nad_set_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:407
Definition: sx.h:65
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
xht hosts
vHosts map
Definition: sm.h:224
rate_t rate_new(int total, int seconds, int wait)
Definition: rate.c:25
error info for event_ERROR
Definition: sx.h:99
void sm_c2s_action(sess_t dest, const char *action, const char *target)
send a new action route
Definition: sm.c:280
#define MIO_STRERROR(e)
Definition: mio.h:170
int sx_can_write(sx_t s)
Definition: io.c:347
#define uri_TLS
Definition: uri.h:40
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:778
sm_t sm
sm context
Definition: sm.h:237
#define NAD_ENAME(N, E)
Definition: nad.h:183
mio_action_t
these are the actions and a handler type assigned by the applicaiton using mio
Definition: mio.h:106
Definition: mio.h:109
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:711
void nad_free(nad_t nad)
free that nad
Definition: nad.c:180
int xhash_iter_next(xht h)
Definition: xhash.c:320
char c2s_id[44]
remote id (for session control)
Definition: sm.h:263
sx_plugin_t sx_ssl
SX SSL plugin.
Definition: sm.h:184
xht users
pointers to currently loaded users (key is user@domain)
Definition: sm.h:189
Definition: sx.h:60
void rate_free(rate_t rt)
Definition: rate.c:36
#define mio_read(m, fd)
process read events for this fd
Definition: mio.h:161
int siglen
length of signature
Definition: sm.h:218
sess_t next
next session (in a list of sessions)
Definition: sm.h:276
#define MIO_ERROR
all MIO related routines should use those for error reporting
Definition: mio.h:168
pkt_t pkt_new(sm_t sm, nad_t nad)
Definition: pkt.c:113
#define MIO_WOULDBLOCK
Definition: mio.h:171
void pool_cleanup(pool_t p, pool_cleanup_t f, void *arg)
public cleanup utils, insert in a way that they are run FIFO, before mem frees
Definition: pool.c:251
int sx_can_read(sx_t s)
we can read
Definition: io.c:196
struct rate_st * rate_t
int retry_left
number of tries left before failure
Definition: sm.h:209
#define SX_ERR_AUTH
Definition: sx.h:95
holds the state for a single stream
Definition: sx.h:253
sess_t sessions
list of action sessions
Definition: sm.h:243
char * data
Definition: sx.h:114
sx_t router
SX of router connection.
Definition: sm.h:186
packet summary data wrapper
Definition: sm.h:129
xht xmlns_refcount
ref-counting for modules namespaces
Definition: sm.h:194
int sm_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg)
Definition: sm.c:241
#define NAD_ENAME_L(N, E)
Definition: nad.h:184
#define NAD_NURI_L(N, NS)
Definition: nad.h:192
session manager global context
Definition: sm.h:167
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)
our master callback
Definition: sm.c:33
char sm_id[41]
local id (for session control)
Definition: sm.h:262
const char * generic
Definition: sx.h:101
int code
Definition: sx.h:100
int xhash_iter_get(xht h, const char **key, int *keylen, void **val)
Definition: xhash.c:374
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
void sm_signature(sm_t sm, const char *str)
this is gratuitous, but apache gets one, so why not?
Definition: sm.c:313
struct sm_st * sm_t
Definition: sm.h:59
void sx_close(sx_t s)
Definition: io.c:512
void pkt_router(pkt_t pkt)
Definition: pkt.c:379
void xhash_zap(xht h, const char *key)
Definition: xhash.c:235
#define log_debug(...)
Definition: log.h:65
const char * router_user
username to authenticate to the router as
Definition: sm.h:172
roster items
Definition: sm.h:150
const char * router_pass
password to authenticate to the router with
Definition: sm.h:173
int rate_check(rate_t rt)
Definition: rate.c:78
#define uri_STREAMS
Definition: uri.h:34
#define NAD_AVAL(N, A)
Definition: nad.h:189
struct _sx_buf_st * sx_buf_t
utility: buffer
Definition: sx.h:112
int retry_lost
number of times to try reconnecting to the router if the connection drops
Definition: sm.h:207
JABBERD2_API int sx_sasl_auth(sx_plugin_t p, sx_t s, const char *appname, const char *mech, const char *user, const char *pass)
trigger for client auth
Definition: sasl.c:934
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
char signature[2048]
server signature
Definition: sm.h:217
int sm_get_ns(sm_t sm, const char *uri)
get a globally registered ns
Definition: sm.c:349
int ssf
Definition: sx.h:343
int nad_find_elem(nad_t nad, unsigned int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:206
int xhash_count(xht h)
return the total number of entries in this xht
Definition: xhash.c:297
const char * specific
Definition: sx.h:102
int xhash_iter_first(xht h)
iteration
Definition: xhash.c:311
mio_fd_t fd
file descriptor of router connection
Definition: sm.h:187
int fd
Definition: mio.h:102
unsigned int len
Definition: sx.h:115
mio_t mio
TLS ciphers.
Definition: sm.h:180
sig_atomic_t sm_lost_router
Definition: sm.c:30
int query_rate_wait
Definition: sm.h:229
int started
true if we&#39;ve connected to the router at least once
Definition: sm.h:220
pool_t xhash_pool(xht h)
get our pool
Definition: xhash.c:305
int online
true if we&#39;re currently bound in the router
Definition: sm.h:222
char * pstrdup(pool_t p, const char *src)
XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is wit...
Definition: pool.c:191
Definition: mio.h:100
void sx_kill(sx_t s)
Definition: io.c:527
Definition: util.h:258
jid_t jid
user jid (user@host)
Definition: sm.h:239
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define uri_COMPONENT
Definition: uri.h:52
#define mio_close(m, fd)
request that mio close this fd
Definition: mio.h:155
#define mio_write(m, fd)
mio should try the write action on this fd now
Definition: mio.h:158
#define ZONE
Definition: mio_impl.h:76
#define NAD_NURI(N, NS)
Definition: nad.h:191
sx_event_t
things that can happen
Definition: sx.h:56
xht xmlns
index of namespaces (for iq sub-namespace in pkt_t)
Definition: sm.h:193
int query_rate_total
Database query rate limits.
Definition: sm.h:227
c2s_t c2s
Definition: c2s.h:75
Definition: sx.h:74
#define uri_SESSION
Definition: uri.h:53
pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from)
Definition: pkt.c:328
void dispatch(sm_t sm, pkt_t pkt)
main packet dispatcher
Definition: dispatch.c:31
Definition: sx.h:62
struct nad_st * nad_t
int sx_ssl_client_starttls(sx_plugin_t p, sx_t s, const char *pemfile, const char *private_key_password)
Definition: ssl.c:1148
int sm_storage_rate_limit(sm_t sm, const char *owner)
Definition: sm.c:355
sx_plugin_t sx_sasl
SX SASL plugin.
Definition: sm.h:183
#define NAD_ENS(N, E)
Definition: nad.h:196
data for a single user
Definition: sm.h:234
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
find a namespace in scope
Definition: nad.c:292