jabberd2  2.2.17
c2s.c
Go to the documentation of this file.
1 /* vim: set et ts=4 sw=4: */
2 /*
3  * jabberd - Jabber Open Source Server
4  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
5  * Ryan Eatmon, Robert Norris
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
20  */
21 
22 #include "c2s.h"
23 #include <stringprep.h>
24 
25 static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
26  sess_t sess = (sess_t) arg;
27  sx_buf_t buf = (sx_buf_t) data;
28  int rlen, len, ns, elem, attr;
29  sx_error_t *sxe;
30  nad_t nad;
31  char root[9];
32  bres_t bres, ires;
33  stream_redirect_t redirect;
34 
35  switch(e) {
36  case event_WANT_READ:
37  log_debug(ZONE, "want read");
38  mio_read(sess->c2s->mio, sess->fd);
39  break;
40 
41  case event_WANT_WRITE:
42  log_debug(ZONE, "want write");
43  mio_write(sess->c2s->mio, sess->fd);
44  break;
45 
46  case event_READ:
47  log_debug(ZONE, "reading from %d", sess->fd->fd);
48 
49  /* check rate limits */
50  if(sess->rate != NULL) {
51  if(rate_check(sess->rate) == 0) {
52 
53  /* inform the app if we haven't already */
54  if(!sess->rate_log) {
55  if(s->state >= state_STREAM && sess->resources != NULL)
56  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] is being byte rate limited", sess->fd->fd, jid_user(sess->resources->jid));
57  else
58  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] is being byte rate limited", sess->fd->fd, sess->ip, sess->port);
59 
60  sess->rate_log = 1;
61  }
62 
63  return -1;
64  }
65 
66  /* find out how much we can have */
67  rlen = rate_left(sess->rate);
68  if(rlen > buf->len)
69  rlen = buf->len;
70  }
71 
72  /* no limit, just read as much as we can */
73  else
74  rlen = buf->len;
75 
76  /* do the read */
77  len = recv(sess->fd->fd, buf->data, rlen, 0);
78 
79  /* update rate limits */
80  if(sess->rate != NULL)
81  rate_add(sess->rate, len);
82 
83  if(len < 0) {
84  if(MIO_WOULDBLOCK) {
85  buf->len = 0;
86  return 0;
87  }
88 
89  if(s->state >= state_STREAM && sess->resources != NULL)
90  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] read error: %s (%d)", sess->fd->fd, jid_user(sess->resources->jid), MIO_STRERROR(MIO_ERROR), MIO_ERROR);
91  else
92  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", sess->fd->fd, sess->ip, sess->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
93 
94  sx_kill(s);
95 
96  return -1;
97  }
98 
99  else if(len == 0) {
100  /* they went away */
101  sx_kill(s);
102 
103  return -1;
104  }
105 
106  log_debug(ZONE, "read %d bytes", len);
107 
108  /* If the first chars are "GET " then it's for HTTP (GET ....)
109  and if we configured http client forwarding to a real http server */
110  if (sess->c2s->http_forward && !sess->active && !sess->sasl_authd
111  && sess->result == NULL && len >= 4 && strncmp("GET ", buf->data, 4) == 0) {
112  char* http =
113  "HTTP/1.0 301 Found\r\n"
114  "Location: %s\r\n"
115  "Server: " PACKAGE_STRING "\r\n"
116  "Expires: Fri, 10 Oct 1997 10:10:10 GMT\r\n"
117  "Pragma: no-cache\r\n"
118  "Cache-control: private\r\n"
119  "Connection: close\r\n\r\n";
120  char *answer;
121 
122  len = strlen(sess->c2s->http_forward) + strlen(http);
123  answer = malloc(len * sizeof(char));
124  sprintf (answer, http, sess->c2s->http_forward);
125 
126  log_write(sess->c2s->log, LOG_NOTICE, "[%d] bouncing HTTP request to %s", sess->fd->fd, sess->c2s->http_forward);
127 
128  /* send HTTP answer */
129  len = send(sess->fd->fd, answer, len-1, 0);
130 
131  free(answer);
132 
133  /* close connection */
134  sx_kill(s);
135 
136  return -1;
137  }
138 
139  buf->len = len;
140 
141  return len;
142 
143  case event_WRITE:
144  log_debug(ZONE, "writing to %d", sess->fd->fd);
145 
146  len = send(sess->fd->fd, buf->data, buf->len, 0);
147  if(len >= 0) {
148  log_debug(ZONE, "%d bytes written", len);
149  return len;
150  }
151 
152  if(MIO_WOULDBLOCK)
153  return 0;
154 
155  if(s->state >= state_OPEN && sess->resources != NULL)
156  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] write error: %s (%d)", sess->fd->fd, jid_user(sess->resources->jid), MIO_STRERROR(MIO_ERROR), MIO_ERROR);
157  else
158  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s. port=%d] write error: %s (%d)", sess->fd->fd, sess->ip, sess->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
159 
160  sx_kill(s);
161 
162  return -1;
163 
164  case event_ERROR:
165  sxe = (sx_error_t *) data;
166  if(sess->resources != NULL)
167  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] error: %s (%s)", sess->fd->fd, jid_user(sess->resources->jid), sxe->generic, sxe->specific);
168  else
169  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", sess->fd->fd, sess->ip, sess->port, sxe->generic, sxe->specific);
170 
171  break;
172 
173  case event_STREAM:
174 
175  if(s->req_to == NULL) {
176  log_debug(ZONE, "no stream to provided, closing");
177  sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header");
178  sx_close(s);
179 
180  return 0;
181  }
182 
183  /* send a see-other-host error if we're configured to do so */
184  redirect = (stream_redirect_t) xhash_get(sess->c2s->stream_redirects, s->req_to);
185  if (redirect != NULL) {
186  log_debug(ZONE, "redirecting client's stream using see-other-host for domain: '%s'", s->req_to);
187  len = strlen(redirect->to_address) + strlen(redirect->to_port) + 1;
188  char *other_host = (char *) malloc(len+1);
189  snprintf(other_host, len+1, "%s:%s", redirect->to_address, redirect->to_port);
191  free(other_host);
192  sx_close(s);
193 
194  return 0;
195  }
196 
197  /* setup the host */
198  sess->host = xhash_get(sess->c2s->hosts, s->req_to);
199 
200  if(sess->host == NULL && sess->c2s->vhost == NULL) {
201  log_debug(ZONE, "no host available for requested domain '%s'", s->req_to);
202  sx_error(s, stream_err_HOST_UNKNOWN, "service requested for unknown domain");
203  sx_close(s);
204 
205  return 0;
206  }
207 
208  if(xhash_get(sess->c2s->sm_avail, s->req_to) == NULL) {
209  log_debug(ZONE, "sm for domain '%s' is not online", s->req_to);
210  sx_error(s, stream_err_HOST_GONE, "session manager for requested domain is not available");
211  sx_close(s);
212 
213  return 0;
214  }
215 
216  if(sess->host == NULL) {
217  /* create host on-fly */
218  sess->host = (host_t) pmalloc(xhash_pool(sess->c2s->hosts), sizeof(struct host_st));
219  memcpy(sess->host, sess->c2s->vhost, sizeof(struct host_st));
220  sess->host->realm = pstrdup(xhash_pool(sess->c2s->hosts), s->req_to);
221  xhash_put(sess->c2s->hosts, pstrdup(xhash_pool(sess->c2s->hosts), s->req_to), sess->host);
222  }
223 
224 #ifdef HAVE_SSL
225  if(sess->host->host_pemfile != NULL)
226  sess->s->flags |= SX_SSL_STARTTLS_OFFER;
227  if(sess->host->host_require_starttls)
228  sess->s->flags |= SX_SSL_STARTTLS_REQUIRE;
229 #endif
230  break;
231 
232  case event_PACKET:
233  /* we're counting packets */
234  sess->packet_count++;
235  sess->c2s->packet_count++;
236 
237  /* check rate limits */
238  if(sess->stanza_rate != NULL) {
239  if(rate_check(sess->stanza_rate) == 0) {
240 
241  /* inform the app if we haven't already */
242  if(!sess->stanza_rate_log) {
243  if(s->state >= state_STREAM && sess->resources != NULL)
244  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s] is being stanza rate limited", sess->fd->fd, jid_user(sess->resources->jid));
245  else
246  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] is being stanza rate limited", sess->fd->fd, sess->ip, sess->port);
247 
248  sess->stanza_rate_log = 1;
249  }
250  }
251 
252  /* update rate limits */
253  rate_add(sess->stanza_rate, 1);
254  }
255 
256  nad = (nad_t) data;
257 
258  /* we only want (message|presence|iq) in jabber:client, everything else gets dropped */
259  snprintf(root, 9, "%.*s", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0));
260  if(NAD_ENS(nad, 0) != nad_find_namespace(nad, 0, uri_CLIENT, NULL) ||
261  (strcmp(root, "message") != 0 && strcmp(root, "presence") != 0 && strcmp(root, "iq") != 0)) {
262  nad_free(nad);
263  return 0;
264  }
265 
266  /* resource bind */
267  if((ns = nad_find_scoped_namespace(nad, uri_BIND, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "bind", 1)) >= 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) {
268  bres_t bres;
269  jid_t jid = jid_new(sess->s->auth_id, -1);
270 
271  /* get the resource */
272  elem = nad_find_elem(nad, elem, ns, "resource", 1);
273 
274  /* user-specified resource */
275  if(elem >= 0) {
276  char resource_buf[1024];
277 
278  if(NAD_CDATA_L(nad, elem) == 0) {
279  log_debug(ZONE, "empty resource specified on bind");
281 
282  return 0;
283  }
284 
285  snprintf(resource_buf, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
286  /* Put resource into JID */
287  if (jid == NULL || jid_reset_components(jid, jid->node, jid->domain, resource_buf) == NULL) {
288  log_debug(ZONE, "invalid jid data");
290 
291  return 0;
292  }
293 
294  /* check if resource already bound */
295  for(bres = sess->resources; bres != NULL; bres = bres->next)
296  if(strcmp(bres->jid->resource, jid->resource) == 0){
297  log_debug(ZONE, "resource /%s already bound - generating", jid->resource);
299  }
300  }
301  else {
302  /* generate random resource */
303  log_debug(ZONE, "no resource given - generating");
305  }
306 
307  /* attach new bound jid holder */
308  bres = (bres_t) calloc(1, sizeof(struct bres_st));
309  bres->jid = jid;
310  if(sess->resources != NULL) {
311  for(ires = sess->resources; ires->next != NULL; ires = ires->next);
312  ires->next = bres;
313  } else
314  sess->resources = bres;
315 
316  sess->bound += 1;
317 
318  log_write(sess->c2s->log, LOG_NOTICE, "[%d] bound: jid=%s", sess->s->tag, jid_full(bres->jid));
319 
320  /* build a result packet, we'll send this back to the client after we have a session for them */
321  sess->result = nad_new();
322 
323  ns = nad_add_namespace(sess->result, uri_CLIENT, NULL);
324 
325  nad_append_elem(sess->result, ns, "iq", 0);
326  nad_set_attr(sess->result, 0, -1, "type", "result", 6);
327 
328  attr = nad_find_attr(nad, 0, -1, "id", NULL);
329  if(attr >= 0)
330  nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
331 
332  ns = nad_add_namespace(sess->result, uri_BIND, NULL);
333 
334  nad_append_elem(sess->result, ns, "bind", 1);
335  nad_append_elem(sess->result, ns, "jid", 2);
336  nad_append_cdata(sess->result, jid_full(bres->jid), strlen(jid_full(bres->jid)), 3);
337 
338  /* our local id */
339  sprintf(bres->c2s_id, "%d", sess->s->tag);
340 
341  /* start a session with the sm */
342  sm_start(sess, bres);
343 
344  /* finished with the nad */
345  nad_free(nad);
346 
347  /* handled */
348  return 0;
349  }
350 
351  /* resource unbind */
352  if((ns = nad_find_scoped_namespace(nad, uri_BIND, NULL)) >= 0 && (elem = nad_find_elem(nad, 0, ns, "unbind", 1)) >= 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) {
353  char resource_buf[1024];
354  bres_t bres;
355 
356  /* get the resource */
357  elem = nad_find_elem(nad, elem, ns, "resource", 1);
358 
359  if(elem < 0 || NAD_CDATA_L(nad, elem) == 0) {
360  log_debug(ZONE, "no/empty resource given to unbind");
362 
363  return 0;
364  }
365 
366  snprintf(resource_buf, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem));
367  if(stringprep_xmpp_resourceprep(resource_buf, 1024) != 0) {
368  log_debug(ZONE, "cannot resourceprep");
370 
371  return 0;
372  }
373 
374  /* check if resource bound */
375  for(bres = sess->resources; bres != NULL; bres = bres->next)
376  if(strcmp(bres->jid->resource, resource_buf) == 0)
377  break;
378 
379  if(bres == NULL) {
380  log_debug(ZONE, "resource /%s not bound", resource_buf);
382 
383  return 0;
384  }
385 
386  /* build a result packet, we'll send this back to the client after we close a session for them */
387  sess->result = nad_new();
388 
389  ns = nad_add_namespace(sess->result, uri_CLIENT, NULL);
390 
391  nad_append_elem(sess->result, ns, "iq", 0);
392  nad_set_attr(sess->result, 0, -1, "type", "result", 6);
393 
394  attr = nad_find_attr(nad, 0, -1, "id", NULL);
395  if(attr >= 0)
396  nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
397 
398  /* end a session with the sm */
399  sm_end(sess, bres);
400 
401  /* finished with the nad */
402  nad_free(nad);
403 
404  /* handled */
405  return 0;
406  }
407 
408  /* pre-session requests */
409  if(!sess->active && sess->sasl_authd && sess->result == NULL && strcmp(root, "iq") == 0 && nad_find_attr(nad, 0, -1, "type", "set") >= 0) {
410  log_debug(ZONE, "unrecognised pre-session packet, bye");
411  log_write(sess->c2s->log, LOG_NOTICE, "[%d] unrecognized pre-session packet, closing stream", sess->s->tag);
412 
413  sx_error(s, stream_err_NOT_AUTHORIZED, "unrecognized pre-session stanza");
414  sx_close(s);
415 
416  nad_free(nad);
417  return 0;
418  }
419 
420 #ifdef HAVE_SSL
421  /* drop packets if they have to starttls and they haven't */
422  if((sess->s->flags & SX_SSL_STARTTLS_REQUIRE) && sess->s->ssf == 0) {
423  log_debug(ZONE, "pre STARTTLS packet, dropping");
424  log_write(sess->c2s->log, LOG_NOTICE, "[%d] got pre STARTTLS packet, dropping", sess->s->tag);
425 
426  sx_error(s, stream_err_POLICY_VIOLATION, "STARTTLS is required for this stream");
427 
428  nad_free(nad);
429  return 0;
430  }
431 #endif
432 
433  /* handle iq:auth packets */
434  if(authreg_process(sess->c2s, sess, nad) == 0)
435  return 0;
436 
437  /* drop it if no session */
438  if(!sess->active) {
439  log_debug(ZONE, "pre-session packet, bye");
440  log_write(sess->c2s->log, LOG_NOTICE, "[%d] packet sent before session start, closing stream", sess->s->tag);
441 
442  sx_error(s, stream_err_NOT_AUTHORIZED, "stanza sent before session start");
443  sx_close(s);
444 
445  nad_free(nad);
446  return 0;
447  }
448 
449  /* validate 'from' */
450  assert(sess->resources != NULL);
451  if(sess->bound > 1) {
452  bres = NULL;
453  if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0)
454  for(bres = sess->resources; bres != NULL; bres = bres->next)
455  if(strncmp(jid_full(bres->jid), NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)) == 0)
456  break;
457 
458  if(bres == NULL) {
459  if(attr >= 0) {
460  log_debug(ZONE, "packet from: %.*s that has not bound the resource", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
461  } else {
462  log_debug(ZONE, "packet without 'from' on multiple resource stream");
463  }
464 
466 
467  return 0;
468  }
469  } else
470  bres = sess->resources;
471 
472  /* pass it on to the session manager */
473  sm_packet(sess, bres, nad);
474 
475  break;
476 
477  case event_OPEN:
478 
479  /* only send a result and bring us online if this wasn't a sasl auth */
480  if(strlen(s->auth_method) < 4 || strncmp("SASL", s->auth_method, 4) != 0) {
481  /* return the auth result to the client */
482  sx_nad_write(s, sess->result);
483  sess->result = NULL;
484 
485  /* we're good to go */
486  sess->active = 1;
487  }
488 
489  /* they sasl auth'd, so we only want the new-style session start */
490  else {
491  log_write(sess->c2s->log, LOG_NOTICE, "[%d] %s authentication succeeded: %s %s:%d%s%s",
492  sess->s->tag, &sess->s->auth_method[5],
493  sess->s->auth_id, sess->s->ip, sess->s->port,
494  sess->s->ssf ? " TLS" : "", sess->s->compressed ? " ZLIB" : ""
495  );
496  sess->sasl_authd = 1;
497  }
498 
499  break;
500 
501  case event_CLOSED:
502  mio_close(sess->c2s->mio, sess->fd);
503  sess->fd = NULL;
504  return -1;
505  }
506 
507  return 0;
508 }
509 
510 static int _c2s_client_accept_check(c2s_t c2s, mio_fd_t fd, char *ip) {
511  rate_t rt;
512 
513  if(access_check(c2s->access, ip) == 0) {
514  log_write(c2s->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd->fd, ip);
515  return 1;
516  }
517 
518  if(c2s->conn_rate_total != 0) {
519  rt = (rate_t) xhash_get(c2s->conn_rates, ip);
520  if(rt == NULL) {
522  xhash_put(c2s->conn_rates, pstrdup(xhash_pool(c2s->conn_rates), ip), (void *) rt);
523  pool_cleanup(xhash_pool(c2s->conn_rates), (void (*)(void *)) rate_free, rt);
524  }
525 
526  if(rate_check(rt) == 0) {
527  log_write(c2s->log, LOG_NOTICE, "[%d] [%s] is being connect rate limited", fd->fd, ip);
528  return 1;
529  }
530 
531  rate_add(rt, 1);
532  }
533 
534  return 0;
535 }
536 
537 static int _c2s_client_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
538  sess_t sess = (sess_t) arg;
539  c2s_t c2s = (c2s_t) arg;
540  bres_t bres;
541  struct sockaddr_storage sa;
542  int namelen = sizeof(sa), port, nbytes, flags = 0;
543 
544  switch(a) {
545  case action_READ:
546  log_debug(ZONE, "read action on fd %d", fd->fd);
547 
548  /* they did something */
549  sess->last_activity = time(NULL);
550 
551  ioctl(fd->fd, FIONREAD, &nbytes);
552  if(nbytes == 0) {
553  sx_kill(sess->s);
554  return 0;
555  }
556 
557  return sx_can_read(sess->s);
558 
559  case action_WRITE:
560  log_debug(ZONE, "write action on fd %d", fd->fd);
561 
562  return sx_can_write(sess->s);
563 
564  case action_CLOSE:
565  log_debug(ZONE, "close action on fd %d", fd->fd);
566 
567  log_write(sess->c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect jid=%s, packets: %i", sess->fd->fd, sess->ip, sess->port, ((sess->resources)?((char*) jid_full(sess->resources->jid)):"unbound"), sess->packet_count);
568 
569  /* tell the sm to close their session */
570  if(sess->active)
571  for(bres = sess->resources; bres != NULL; bres = bres->next)
572  sm_end(sess, bres);
573 
574  jqueue_push(sess->c2s->dead, (void *) sess->s, 0);
575 
576  xhash_zap(sess->c2s->sessions, sess->skey);
577 
578  jqueue_push(sess->c2s->dead_sess, (void *) sess, 0);
579 
580  break;
581 
582  case action_ACCEPT:
583  log_debug(ZONE, "accept action on fd %d", fd->fd);
584 
585  getpeername(fd->fd, (struct sockaddr *) &sa, &namelen);
586  port = j_inet_getport(&sa);
587 
588  log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connect", fd->fd, (char *) data, port);
589 
590  if(_c2s_client_accept_check(c2s, fd, (char *) data) != 0)
591  return 1;
592 
593  sess = (sess_t) calloc(1, sizeof(struct sess_st));
594 
595  sess->c2s = c2s;
596 
597  sess->fd = fd;
598 
599  sess->ip = strdup((char *) data);
600  sess->port = port;
601 
602  /* they did something */
603  sess->last_activity = time(NULL);
604 
605  sess->s = sx_new(c2s->sx_env, fd->fd, _c2s_client_sx_callback, (void *) sess);
606  mio_app(m, fd, _c2s_client_mio_callback, (void *) sess);
607 
608  if(c2s->stanza_size_limit != 0)
609  sess->s->rbytesmax = c2s->stanza_size_limit;
610 
611  if(c2s->byte_rate_total != 0)
613 
614  if(c2s->stanza_rate_total != 0)
616 
617  /* give IP to SX */
618  sess->s->ip = sess->ip;
619  sess->s->port = sess->port;
620 
621  /* find out which port this is */
622  getsockname(fd->fd, (struct sockaddr *) &sa, &namelen);
623  port = j_inet_getport(&sa);
624 
625  /* remember it */
626  sprintf(sess->skey, "%d", fd->fd);
627  xhash_put(c2s->sessions, sess->skey, (void *) sess);
628 
629  flags = SX_SASL_OFFER;
630 #ifdef HAVE_SSL
631  /* go ssl wrappermode if they're on the ssl port */
632  if(port == c2s->local_ssl_port)
633  flags |= SX_SSL_WRAPPER;
634 #endif
635 #ifdef HAVE_LIBZ
636  if(c2s->compression)
637  flags |= SX_COMPRESS_OFFER;
638 #endif
639  sx_server_init(sess->s, flags);
640 
641  break;
642  }
643 
644  return 0;
645 }
646 
647 static void _c2s_component_presence(c2s_t c2s, nad_t nad) {
648  int attr;
649  char from[1024];
650  sess_t sess;
651  union xhashv xhv;
652 
653  if((attr = nad_find_attr(nad, 0, -1, "from", NULL)) < 0) {
654  nad_free(nad);
655  return;
656  }
657 
658  strncpy(from, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr));
659  from[NAD_AVAL_L(nad, attr)] = '\0';
660 
661  if(nad_find_attr(nad, 0, -1, "type", NULL) < 0) {
662  log_debug(ZONE, "component available from '%s'", from);
663 
664  log_debug(ZONE, "sm for serviced domain '%s' online", from);
665 
666  xhash_put(c2s->sm_avail, pstrdup(xhash_pool(c2s->sm_avail), from), (void *) 1);
667 
668  nad_free(nad);
669  return;
670  }
671 
672  if(nad_find_attr(nad, 0, -1, "type", "unavailable") < 0) {
673  nad_free(nad);
674  return;
675  }
676 
677  log_debug(ZONE, "component unavailable from '%s'", from);
678 
679  if(xhash_get(c2s->sm_avail, from) != NULL) {
680  log_debug(ZONE, "sm for serviced domain '%s' offline", from);
681 
682  if(xhash_iter_first(c2s->sessions))
683  do {
684  xhv.sess_val = &sess;
685  xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val);
686 
687  if(sess->resources != NULL && strcmp(sess->resources->jid->domain, from) == 0) {
688  log_debug(ZONE, "killing session %s", jid_user(sess->resources->jid));
689 
690  sess->active = 0;
691  if(sess->s) sx_close(sess->s);
692  }
693  } while(xhash_iter_next(c2s->sessions));
694 
695  xhash_zap(c2s->sm_avail, from);
696  }
697 }
698 
699 int c2s_router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
700  c2s_t c2s = (c2s_t) arg;
701  sx_buf_t buf = (sx_buf_t) data;
702  sx_error_t *sxe;
703  nad_t nad;
704  int len, elem, from, c2sid, smid, action, id, ns, attr, scan, replaced;
705  char skey[44];
706  sess_t sess;
707  bres_t bres, ires;
708 
709  switch(e) {
710  case event_WANT_READ:
711  log_debug(ZONE, "want read");
712  mio_read(c2s->mio, c2s->fd);
713  break;
714 
715  case event_WANT_WRITE:
716  log_debug(ZONE, "want write");
717  mio_write(c2s->mio, c2s->fd);
718  break;
719 
720  case event_READ:
721  log_debug(ZONE, "reading from %d", c2s->fd->fd);
722 
723  /* do the read */
724  len = recv(c2s->fd->fd, buf->data, buf->len, 0);
725 
726  if(len < 0) {
727  if(MIO_WOULDBLOCK) {
728  buf->len = 0;
729  return 0;
730  }
731 
732  log_write(c2s->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", c2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
733 
734  sx_kill(s);
735 
736  return -1;
737  }
738 
739  else if(len == 0) {
740  /* they went away */
741  sx_kill(s);
742 
743  return -1;
744  }
745 
746  log_debug(ZONE, "read %d bytes", len);
747 
748  buf->len = len;
749 
750  return len;
751 
752  case event_WRITE:
753  log_debug(ZONE, "writing to %d", c2s->fd->fd);
754 
755  len = send(c2s->fd->fd, buf->data, buf->len, 0);
756  if(len >= 0) {
757  log_debug(ZONE, "%d bytes written", len);
758  return len;
759  }
760 
761  if(MIO_WOULDBLOCK)
762  return 0;
763 
764  log_write(c2s->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", c2s->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR);
765 
766  sx_kill(s);
767 
768  return -1;
769 
770  case event_ERROR:
771  sxe = (sx_error_t *) data;
772  log_write(c2s->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific);
773 
774  if(sxe->code == SX_ERR_AUTH)
775  sx_close(s);
776 
777  break;
778 
779  case event_STREAM:
780  break;
781 
782  case event_OPEN:
783  log_write(c2s->log, LOG_NOTICE, "connection to router established");
784 
785  /* set connection attempts counter */
786  c2s->retry_left = c2s->retry_lost;
787 
788  nad = nad_new();
789  ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
790  nad_append_elem(nad, ns, "bind", 0);
791  nad_append_attr(nad, -1, "name", c2s->id);
792 
793  log_debug(ZONE, "requesting component bind for '%s'", c2s->id);
794 
795  sx_nad_write(c2s->router, nad);
796 
797  return 0;
798 
799  case event_PACKET:
800  nad = (nad_t) data;
801 
802  /* drop unqualified packets */
803  if(NAD_ENS(nad, 0) < 0) {
804  nad_free(nad);
805  return 0;
806  }
807 
808  /* watch for the features packet */
809  if(s->state == state_STREAM) {
810  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) {
811  log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping");
812  nad_free(nad);
813  return 0;
814  }
815 
816 #ifdef HAVE_SSL
817  /* starttls if we can */
818  if(c2s->sx_ssl != NULL && c2s->router_pemfile != NULL && s->ssf == 0) {
819  ns = nad_find_scoped_namespace(nad, uri_TLS, NULL);
820  if(ns >= 0) {
821  elem = nad_find_elem(nad, 0, ns, "starttls", 1);
822  if(elem >= 0) {
823  if(sx_ssl_client_starttls(c2s->sx_ssl, s, c2s->router_pemfile) == 0) {
824  nad_free(nad);
825  return 0;
826  }
827  log_write(c2s->log, LOG_ERR, "unable to establish encrypted session with router");
828  }
829  }
830  }
831 #endif
832 
833  /* !!! pull the list of mechanisms, and choose the best one.
834  * if there isn't an appropriate one, error and bail */
835 
836  /* authenticate */
837  sx_sasl_auth(c2s->sx_sasl, s, "jabberd-router", "DIGEST-MD5", c2s->router_user, c2s->router_pass);
838 
839  nad_free(nad);
840  return 0;
841  }
842 
843  /* watch for the bind response */
844  if(s->state == state_OPEN && !c2s->online) {
845  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4) != 0) {
846  log_debug(ZONE, "got a packet from router, but we're not online, dropping");
847  nad_free(nad);
848  return 0;
849  }
850 
851  /* catch errors */
852  attr = nad_find_attr(nad, 0, -1, "error", NULL);
853  if(attr >= 0) {
854  log_write(c2s->log, LOG_ERR, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr));
855  exit(1);
856  }
857 
858  log_debug(ZONE, "coming online");
859 
860  /* if we're coming online for the first time, setup listening sockets */
861 #ifdef HAVE_SSL
862  if(c2s->server_fd == 0 && c2s->server_ssl_fd == 0) {
863 #else
864  if(c2s->server_fd == 0) {
865 #endif
866  if(c2s->local_port != 0) {
867  c2s->server_fd = mio_listen(c2s->mio, c2s->local_port, c2s->local_ip, _c2s_client_mio_callback, (void *) c2s);
868  if(c2s->server_fd == NULL)
869  log_write(c2s->log, LOG_ERR, "[%s, port=%d] failed to listen", c2s->local_ip, c2s->local_port);
870  else
871  log_write(c2s->log, LOG_NOTICE, "[%s, port=%d] listening for connections", c2s->local_ip, c2s->local_port);
872  } else
873  c2s->server_fd = NULL;
874 
875 #ifdef HAVE_SSL
876  if(c2s->local_ssl_port != 0 && c2s->local_pemfile != NULL) {
877  c2s->server_ssl_fd = mio_listen(c2s->mio, c2s->local_ssl_port, c2s->local_ip, _c2s_client_mio_callback, (void *) c2s);
878  if(c2s->server_ssl_fd == NULL)
879  log_write(c2s->log, LOG_ERR, "[%s, port=%d] failed to listen", c2s->local_ip, c2s->local_ssl_port);
880  else
881  log_write(c2s->log, LOG_NOTICE, "[%s, port=%d] listening for SSL connections", c2s->local_ip, c2s->local_ssl_port);
882  } else
883  c2s->server_ssl_fd = NULL;
884 #endif
885  }
886 
887 #ifdef HAVE_SSL
888  if(c2s->server_fd == NULL && c2s->server_ssl_fd == NULL && c2s->pbx_pipe == NULL) {
889  log_write(c2s->log, LOG_ERR, "both normal and SSL ports are disabled, nothing to do!");
890 #else
891  if(c2s->server_fd == NULL && c2s->pbx_pipe == NULL) {
892  log_write(c2s->log, LOG_ERR, "server port is disabled, nothing to do!");
893 #endif
894  exit(1);
895  }
896 
897  /* open PBX integration FIFO */
898  if(c2s->pbx_pipe != NULL)
899  c2s_pbx_init(c2s);
900 
901  /* we're online */
902  c2s->online = c2s->started = 1;
903  log_write(c2s->log, LOG_NOTICE, "ready for connections", c2s->id);
904 
905  nad_free(nad);
906  return 0;
907  }
908 
909  /* need component packets */
910  if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0) {
911  log_debug(ZONE, "wanted component packet, dropping");
912  nad_free(nad);
913  return 0;
914  }
915 
916  /* component presence */
917  if(NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) {
918  _c2s_component_presence(c2s, nad);
919  return 0;
920  }
921 
922  /* we want route */
923  if(NAD_ENAME_L(nad, 0) != 5 || strncmp("route", NAD_ENAME(nad, 0), 5) != 0) {
924  log_debug(ZONE, "wanted {component}route, dropping");
925  nad_free(nad);
926  return 0;
927  }
928 
929  /* only handle unicasts */
930  if(nad_find_attr(nad, 0, -1, "type", NULL) >= 0) {
931  log_debug(ZONE, "non-unicast packet, dropping");
932  nad_free(nad);
933  return 0;
934  }
935 
936  /* need some payload */
937  if(nad->ecur == 1) {
938  log_debug(ZONE, "no route payload, dropping");
939  nad_free(nad);
940  return 0;
941  }
942 
943  ns = nad_find_namespace(nad, 1, uri_SESSION, NULL);
944  if(ns < 0) {
945  log_debug(ZONE, "not a c2s packet, dropping");
946  nad_free(nad);
947  return 0;
948  }
949 
950  /* figure out the session */
951  c2sid = nad_find_attr(nad, 1, ns, "c2s", NULL);
952  if(c2sid < 0) {
953  log_debug(ZONE, "no c2s id on payload, dropping");
954  nad_free(nad);
955  return 0;
956  }
957  snprintf(skey, sizeof(skey), "%.*s", NAD_AVAL_L(nad, c2sid), NAD_AVAL(nad, c2sid));
958 
959  /* find the session, quietly drop if we don't have it */
960  sess = xhash_get(c2s->sessions, skey);
961  if(sess == NULL) {
962  /* if we get this, the SM probably thinks the session is still active
963  * so we need to tell SM to free it up */
964  log_debug(ZONE, "no session for %s", skey);
965 
966  /* check if it's a started action; otherwise we could end up in an infinite loop
967  * trying to tell SM to close in response to errors */
968  action = nad_find_attr(nad, 1, -1, "action", NULL);
969  if(action >= 0 && NAD_AVAL_L(nad, action) == 7 && strncmp("started", NAD_AVAL(nad, action), 7) == 0) {
970  int target;
971  bres_t tres;
972  sess_t tsess;
973 
974  log_write(c2s->log, LOG_NOTICE, "session %s does not exist; telling sm to close", skey);
975 
976  /* we don't have a session and we don't have a resource; we need to forge them both
977  * to get SM to close stuff */
978  target = nad_find_attr(nad, 1, -1, "target", NULL);
979  smid = nad_find_attr(nad, 1, ns, "sm", NULL);
980  if(target < 0 || smid < 0) {
981  char *buf;
982  int len;
983  nad_print(nad, 0, &buf, &len);
984  log_write(c2s->log, LOG_NOTICE, "sm sent an invalid start packet: %.*s", len, buf );
985  nad_free(nad);
986  return 0;
987  }
988 
989  /* build temporary resource to close session for */
990  tres = NULL;
991  tres = (bres_t) calloc(1, sizeof(struct bres_st));
992  tres->jid = jid_new(NAD_AVAL(nad, target), NAD_AVAL_L(nad, target));
993 
994  strncpy(tres->c2s_id, skey, sizeof(tres->c2s_id));
995  snprintf(tres->sm_id, sizeof(tres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid));
996 
997  /* make a temporary session */
998  tsess = (sess_t) calloc(1, sizeof(struct sess_st));
999  tsess->c2s = c2s;
1000  tsess->result = nad_new();
1001  strncpy(tsess->skey, skey, sizeof(tsess->skey));
1002 
1003  /* end a session with the sm */
1004  sm_end(tsess, tres);
1005 
1006  /* free our temporary messes */
1007  nad_free(tsess->result);
1008  jid_free(tres->jid); //TODO will this crash?
1009  free(tsess);
1010  free(tres);
1011  }
1012 
1013  nad_free(nad);
1014  return 0;
1015  }
1016 
1017  /* if they're pre-stream, then this is leftovers from a previous session */
1018  if(sess->s && sess->s->state < state_STREAM) {
1019  log_debug(ZONE, "session %s is pre-stream", skey);
1020 
1021  nad_free(nad);
1022  return 0;
1023  }
1024 
1025  /* check the sm session id if they gave us one */
1026  smid = nad_find_attr(nad, 1, ns, "sm", NULL);
1027 
1028  /* get the action attribute */
1029  action = nad_find_attr(nad, 1, -1, "action", NULL);
1030 
1031  /* first user created packets - these are out of session */
1032  if(action >= 0 && NAD_AVAL_L(nad, action) == 7 && strncmp("created", NAD_AVAL(nad, action), 7) == 0) {
1033 
1034  nad_free(nad);
1035 
1036  if(sess->result) {
1037  /* return the result to the client */
1038  sx_nad_write(sess->s, sess->result);
1039  sess->result = NULL;
1040  } else {
1041  log_write(sess->c2s->log, LOG_WARNING, "user created for session %s which is already gone", skey);
1042  }
1043 
1044  return 0;
1045  }
1046 
1047  /* route errors */
1048  if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) {
1049  log_debug(ZONE, "routing error");
1050 
1051  if(sess->s) {
1052  sx_error(sess->s, stream_err_INTERNAL_SERVER_ERROR, "internal server error");
1053  sx_close(sess->s);
1054  }
1055 
1056  nad_free(nad);
1057  return 0;
1058  }
1059 
1060  /* all other packets need to contain an sm ID */
1061  if (smid < 0) {
1062  log_debug(ZONE, "received packet from sm without an sm ID, dropping");
1063  nad_free(nad);
1064  return 0;
1065  }
1066 
1067  /* find resource that we got packet for */
1068  bres = NULL;
1069  if(smid >= 0)
1070  for(bres = sess->resources; bres != NULL; bres = bres->next){
1071  if(bres->sm_id[0] == '\0' || (strlen(bres->sm_id) == NAD_AVAL_L(nad, smid) && strncmp(bres->sm_id, NAD_AVAL(nad, smid), NAD_AVAL_L(nad, smid)) == 0))
1072  break;
1073  }
1074  if(bres == NULL) {
1075  jid_t jid = NULL;
1076  bres_t tres = NULL;
1077 
1078  /* if it's a failure, just drop it */
1079  if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) {
1080  nad_free(nad);
1081  return 0;
1082  }
1083 
1084  /* build temporary resource to close session for */
1085  tres = (bres_t) calloc(1, sizeof(struct bres_st));
1086  if(sess->s) {
1087  jid = jid_new(sess->s->auth_id, -1);
1088  sprintf(tres->c2s_id, "%d", sess->s->tag);
1089  }
1090  else {
1091  /* does not have SX - extract values from route packet */
1092  int c2sid, target;
1093  c2sid = nad_find_attr(nad, 1, ns, "c2s", NULL);
1094  target = nad_find_attr(nad, 1, -1, "target", NULL);
1095  if(c2sid < 0 || target < 0) {
1096  log_debug(ZONE, "needed ids not found - c2sid:%d target:%d", c2sid, target);
1097  nad_free(nad);
1098  free(tres);
1099  return 0;
1100  }
1101  jid = jid_new(NAD_AVAL(nad, target), NAD_AVAL_L(nad, target));
1102  snprintf(tres->c2s_id, sizeof(tres->c2s_id), "%.*s", NAD_AVAL_L(nad, c2sid), NAD_AVAL(nad, c2sid));
1103  }
1104  tres->jid = jid;
1105  snprintf(tres->sm_id, sizeof(tres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid));
1106 
1107  if(sess->resources) {
1108  log_debug(ZONE, "expected packet from sm session %s, but got one from %.*s, ending sm session", sess->resources->sm_id, NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid));
1109  } else {
1110  log_debug(ZONE, "no resource bound yet, but got packet from sm session %.*s, ending sm session", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid));
1111  }
1112 
1113  /* end a session with the sm */
1114  sm_end(sess, tres);
1115 
1116  /* finished with the nad */
1117  nad_free(nad);
1118 
1119  /* free temp objects */
1120  jid_free(jid);
1121  free(tres);
1122 
1123  return 0;
1124  }
1125 
1126  /* session control packets */
1127  if(NAD_ENS(nad, 1) == ns && action >= 0) {
1128  /* end responses */
1129 
1130  /* !!! this "replaced" stuff is a hack - its really a subaction of "ended".
1131  * hurrah, another control protocol rewrite is needed :(
1132  */
1133 
1134  replaced = 0;
1135  if(NAD_AVAL_L(nad, action) == 8 && strncmp("replaced", NAD_AVAL(nad, action), NAD_AVAL_L(nad, action)) == 0)
1136  replaced = 1;
1137  if(sess->active &&
1138  (replaced || (NAD_AVAL_L(nad, action) == 5 && strncmp("ended", NAD_AVAL(nad, action), NAD_AVAL_L(nad, action)) == 0))) {
1139 
1140  sess->bound -= 1;
1141  /* no more resources bound? */
1142  if(sess->bound < 1){
1143  sess->active = 0;
1144 
1145  if(sess->s) {
1146  /* return the unbind result to the client */
1147  if(sess->result != NULL) {
1148  sx_nad_write(sess->s, sess->result);
1149  sess->result = NULL;
1150  }
1151 
1152  if(replaced)
1153  sx_error(sess->s, stream_err_CONFLICT, NULL);
1154 
1155  sx_close(sess->s);
1156 
1157  } else {
1158  // handle fake PBX sessions
1159  if(sess->result != NULL) {
1160  nad_free(sess->result);
1161  sess->result = NULL;
1162  }
1163  }
1164 
1165  nad_free(nad);
1166  return 0;
1167  }
1168 
1169  /* else remove the bound resource */
1170  if(bres == sess->resources) {
1171  sess->resources = bres->next;
1172  } else {
1173  for(ires = sess->resources; ires != NULL; ires = ires->next)
1174  if(ires->next == bres)
1175  break;
1176  assert(ires != NULL);
1177  ires->next = bres->next;
1178  }
1179 
1180  log_write(sess->c2s->log, LOG_NOTICE, "[%d] unbound: jid=%s", sess->s->tag, jid_full(bres->jid));
1181 
1182  jid_free(bres->jid);
1183  free(bres);
1184 
1185  /* and return the unbind result to the client */
1186  if(sess->result != NULL) {
1187  sx_nad_write(sess->s, sess->result);
1188  sess->result = NULL;
1189  }
1190 
1191  return 0;
1192  }
1193 
1194  id = nad_find_attr(nad, 1, -1, "id", NULL);
1195 
1196  /* make sure the id matches */
1197  if(id < 0 || bres->sm_request[0] == '\0' || strlen(bres->sm_request) != NAD_AVAL_L(nad, id) || strncmp(bres->sm_request, NAD_AVAL(nad, id), NAD_AVAL_L(nad, id)) != 0) {
1198  if(id >= 0) {
1199  log_debug(ZONE, "got a response with id %.*s, but we were expecting %s", NAD_AVAL_L(nad, id), NAD_AVAL(nad, id), bres->sm_request);
1200  } else {
1201  log_debug(ZONE, "got a response with no id, but we were expecting %s", bres->sm_request);
1202  }
1203 
1204  nad_free(nad);
1205  return 0;
1206  }
1207 
1208  /* failed requests */
1209  if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) {
1210  /* handled request */
1211  bres->sm_request[0] = '\0';
1212 
1213  /* we only care about failed start and create */
1214  if((NAD_AVAL_L(nad, action) == 5 && strncmp("start", NAD_AVAL(nad, action), 5) == 0) ||
1215  (NAD_AVAL_L(nad, action) == 6 && strncmp("create", NAD_AVAL(nad, action), 6) == 0)) {
1216 
1217  /* create failed, so we need to remove them from authreg */
1218  if(NAD_AVAL_L(nad, action) == 6 && c2s->ar->delete_user != NULL) {
1219  if((c2s->ar->delete_user)(c2s->ar, bres->jid->node, sess->host->realm) != 0)
1220  log_write(c2s->log, LOG_NOTICE, "[%d] user creation failed, and unable to delete user credentials: user=%s, realm=%s", sess->s->tag, bres->jid->node, sess->host->realm);
1221  else
1222  log_write(c2s->log, LOG_NOTICE, "[%d] user creation failed, so deleted user credentials: user=%s, realm=%s", sess->s->tag, bres->jid->node, sess->host->realm);
1223  }
1224 
1225  /* error the result and return it to the client */
1227  sess->result = NULL;
1228 
1229  /* remove the bound resource */
1230  if(bres == sess->resources) {
1231  sess->resources = bres->next;
1232  } else {
1233  for(ires = sess->resources; ires != NULL; ires = ires->next)
1234  if(ires->next == bres)
1235  break;
1236  assert(ires != NULL);
1237  ires->next = bres->next;
1238  }
1239 
1240  jid_free(bres->jid);
1241  free(bres);
1242 
1243  nad_free(nad);
1244  return 0;
1245  }
1246 
1247  log_debug(ZONE, "weird, got a failed session response, with a matching id, but the action is bogus *shrug*");
1248 
1249  nad_free(nad);
1250  return 0;
1251  }
1252 
1253  /* session started */
1254  if(NAD_AVAL_L(nad, action) == 7 && strncmp("started", NAD_AVAL(nad, action), 7) == 0) {
1255  /* handled request */
1256  bres->sm_request[0] = '\0';
1257 
1258  /* copy the sm id */
1259  if(smid >= 0)
1260  snprintf(bres->sm_id, sizeof(bres->sm_id), "%.*s", NAD_AVAL_L(nad, smid), NAD_AVAL(nad, smid));
1261 
1262  /* and remember the SM that services us */
1263  from = nad_find_attr(nad, 0, -1, "from", NULL);
1264  sess->smcomp = malloc(NAD_AVAL_L(nad, from) + 1);
1265  snprintf(sess->smcomp, NAD_AVAL_L(nad, from) + 1, "%.*s", NAD_AVAL_L(nad, from), NAD_AVAL(nad, from));
1266 
1267  nad_free(nad);
1268 
1269  /* bring them online, old-skool */
1270  if(!sess->sasl_authd && sess->s) {
1271  sx_auth(sess->s, "traditional", jid_full(bres->jid));
1272  return 0;
1273  }
1274 
1275  if(sess->result) {
1276  /* return the auth result to the client */
1277  if(sess->s) sx_nad_write(sess->s, sess->result);
1278  /* or follow-up the session creation with cached presence packet */
1279  else sm_packet(sess, bres, sess->result);
1280  }
1281  sess->result = NULL;
1282 
1283  /* we're good to go */
1284  sess->active = 1;
1285 
1286  return 0;
1287  }
1288 
1289  /* handled request */
1290  bres->sm_request[0] = '\0';
1291 
1292  log_debug(ZONE, "unknown action %.*s", NAD_AVAL_L(nad, id), NAD_AVAL(nad, id));
1293 
1294  nad_free(nad);
1295 
1296  return 0;
1297  }
1298 
1299  /* client packets */
1300  if(NAD_NURI_L(nad, NAD_ENS(nad, 1)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 1)), strlen(uri_CLIENT)) == 0) {
1301  if(!sess->active || !sess->s) {
1302  /* its a strange world .. */
1303  log_debug(ZONE, "Got packet for %s - dropping", !sess->s ? "session without stream (PBX pipe session?)" : "inactive session");
1304  nad_free(nad);
1305  return 0;
1306  }
1307 
1308  /* sm is bouncing something */
1309  if(nad_find_attr(nad, 1, ns, "failed", NULL) >= 0) {
1310  if(s) {
1311  /* there's really no graceful way to handle this */
1312  sx_error(s, stream_err_INTERNAL_SERVER_ERROR, "session manager failed control action");
1313  sx_close(s);
1314  }
1315 
1316  nad_free(nad);
1317  return 0;
1318  }
1319 
1320  /* we're counting packets */
1321  sess->packet_count++;
1322  sess->c2s->packet_count++;
1323 
1324  /* remove sm specifics */
1325  nad_set_attr(nad, 1, ns, "c2s", NULL, 0);
1326  nad_set_attr(nad, 1, ns, "sm", NULL, 0);
1327 
1328  /* forget about the internal namespace too */
1329  if(nad->elems[1].ns == ns)
1330  nad->elems[1].ns = nad->nss[ns].next;
1331 
1332  else {
1333  for(scan = nad->elems[1].ns; nad->nss[scan].next != -1 && nad->nss[scan].next != ns; scan = nad->nss[scan].next);
1334 
1335  /* got it */
1336  if(nad->nss[scan].next != -1)
1337  nad->nss[scan].next = nad->nss[ns].next;
1338  }
1339 
1340  sx_nad_write_elem(sess->s, nad, 1);
1341 
1342  return 0;
1343  }
1344 
1345  /* its something else */
1346  log_debug(ZONE, "unknown packet, dropping");
1347 
1348  nad_free(nad);
1349  return 0;
1350 
1351  case event_CLOSED:
1352  mio_close(c2s->mio, c2s->fd);
1353  c2s->fd = NULL;
1354  return -1;
1355  }
1356 
1357  return 0;
1358 }
1359 
1360 int c2s_router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
1361  c2s_t c2s = (c2s_t) arg;
1362  int nbytes;
1363 
1364  switch(a) {
1365  case action_READ:
1366  log_debug(ZONE, "read action on fd %d", fd->fd);
1367 
1368  ioctl(fd->fd, FIONREAD, &nbytes);
1369  if(nbytes == 0) {
1370  sx_kill(c2s->router);
1371  return 0;
1372  }
1373 
1374  return sx_can_read(c2s->router);
1375 
1376  case action_WRITE:
1377  log_debug(ZONE, "write action on fd %d", fd->fd);
1378  return sx_can_write(c2s->router);
1379 
1380  case action_CLOSE:
1381  log_debug(ZONE, "close action on fd %d", fd->fd);
1382  log_write(c2s->log, LOG_NOTICE, "connection to router closed");
1383 
1384  c2s_lost_router = 1;
1385 
1386  /* we're offline */
1387  c2s->online = 0;
1388 
1389  break;
1390 
1391  case action_ACCEPT:
1392  break;
1393  }
1394 
1395  return 0;
1396 }