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