jabberd2  2.2.16
router/router.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "router.h"
00022 
00023 #define MAX_JID 3072    // node(1023) + '@'(1) + domain(1023) + '/'(1) + resource(1023) + '\0'(1)
00024 #define MAX_MESSAGE 65535
00025 #define SECS_PER_DAY 86400
00026 #define BYTES_PER_MEG 1048576
00027 
00029 typedef struct broadcast_st {
00030     router_t      r;
00031     component_t   src;
00032     nad_t         nad;
00033 } *broadcast_t;
00034 
00036 static void _router_broadcast(const char *key, int keylen, void *val, void *arg) {
00037     int i;
00038     broadcast_t bc = (broadcast_t) arg;
00039     routes_t routes = (routes_t) val;
00040 
00041     for(i = 0; i < routes->ncomp; i++) {
00042         /* I don't care about myself or the elderly (!?) */
00043         if(routes->comp[i] == bc->src || routes->comp[i]->legacy)
00044             continue;
00045 
00046         sx_nad_write(routes->comp[i]->s, nad_copy(bc->nad));
00047     }
00048 }
00049 
00051 static void _router_advertise(router_t r, char *domain, component_t src, int unavail) {
00052     struct broadcast_st bc;
00053     int ns;
00054 
00055     log_debug(ZONE, "advertising %s to all routes (unavail=%d)", domain, unavail);
00056 
00057     bc.r = r;
00058     bc.src = src;
00059 
00060     /* create a new packet */
00061     bc.nad = nad_new();
00062     ns = nad_add_namespace(bc.nad, uri_COMPONENT, NULL);
00063     nad_append_elem(bc.nad, ns, "presence", 0);
00064     nad_append_attr(bc.nad, -1, "from", domain);
00065     if(unavail)
00066         nad_append_attr(bc.nad, -1, "type", "unavailable");
00067 
00068     xhash_walk(r->routes, _router_broadcast, (void *) &bc);
00069 
00070     nad_free(bc.nad);
00071 }
00072 
00074 static void _router_advertise_reverse(const char *key, int keylen, void *val, void *arg) {
00075     component_t dest = (component_t) arg;
00076     routes_t routes = (routes_t) val;
00077     int el, ns, i;
00078     nad_t nad;
00079 
00080     assert((int) (routes->name != NULL));
00081     assert((int) (routes->comp != NULL));
00082     assert(routes->ncomp);
00083 
00084     /* don't tell me about myself */
00085     for(i = 0; i < routes->ncomp; i++)
00086         if(routes->comp[i] == dest)
00087             return;
00088 
00089     log_debug(ZONE, "informing component about %.*s", keylen, key);
00090 
00091     /* create a new packet */
00092     nad = nad_new();
00093     ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
00094     el = nad_append_elem(nad, ns, "presence", 0);
00095     nad_set_attr(nad, el, -1, "from", key, keylen);
00096 
00097     sx_nad_write(dest->s, nad);
00098 }
00099 
00100 static void _router_process_handshake(component_t comp, nad_t nad) {
00101     char *hash;
00102     int hashlen;
00103 
00104     /* must have a hash as cdata */
00105     if(NAD_CDATA_L(nad, 0) != 40) {
00106         log_debug(ZONE, "handshake isn't long enough to be a sha1 hash");
00107         sx_error(comp->s, stream_err_NOT_AUTHORIZED, "handshake isn't long enough to be a sha1 hash");
00108         sx_close(comp->s);
00109 
00110         nad_free(nad);
00111         return;
00112     }
00113 
00114     /* make room for shahash_r to work .. needs at least 41 chars */
00115     hashlen = strlen(comp->s->id) + strlen(comp->r->local_secret) + 1;
00116     if(hashlen < 41)
00117         hashlen = 41;
00118 
00119     /* build the creds and hash them */
00120     hash = (char *) malloc(sizeof(char) * hashlen);
00121     sprintf(hash, "%s%s", comp->s->id, comp->r->local_secret);
00122     shahash_r(hash, hash);
00123 
00124     /* check */
00125     log_debug(ZONE, "checking their hash %.*s against our hash %s", 40, NAD_CDATA(nad, 0), hash);
00126 
00127     if(strncmp(hash, NAD_CDATA(nad, 0), 40) == 0) {
00128         log_debug(ZONE, "handshake succeeded");
00129 
00130         free(hash);
00131 
00132         /* respond */
00133         nad->elems[0].icdata = nad->elems[0].itail = -1;
00134         nad->elems[0].lcdata = nad->elems[0].ltail = 0;
00135         sx_nad_write(comp->s, nad);
00136 
00137         sx_auth(comp->s, "handshake", comp->s->req_to);
00138         
00139         return;
00140     }
00141     
00142     log_debug(ZONE, "auth failed");
00143 
00144     free(hash);
00145 
00146     /* failed, let them know */
00147     sx_error(comp->s, stream_err_NOT_AUTHORIZED, "hash didn't match, auth failed");
00148     sx_close(comp->s);
00149 
00150     nad_free(nad);
00151 }
00152 
00153 void routes_free(routes_t routes) {
00154     if(routes->name) free(routes->name);
00155     if(routes->comp) free(routes->comp);
00156     free(routes);
00157 }
00158 
00159 static int _route_add(xht hroutes, const char *name, component_t comp, route_type_t rtype) {
00160     routes_t routes;
00161 
00162     routes = xhash_get(hroutes, name);
00163     if(routes == NULL) {
00164         routes = (routes_t) calloc(1, sizeof(struct routes_st));
00165         routes->name = strdup(name);
00166         routes->rtype = rtype;
00167     }
00168     routes->comp = (component_t *) realloc(routes->comp, sizeof(component_t *) * (routes->ncomp + 1));
00169     routes->comp[routes->ncomp] = comp;
00170     routes->ncomp++;
00171     xhash_put(hroutes, routes->name, (void *) routes);
00172 
00173     if(routes->rtype != rtype)
00174         log_write(comp->r->log, LOG_ERR, "Mixed route types for '%s' bind request", name);
00175 
00176     return routes->ncomp;
00177 }
00178 
00179 static void _route_remove(xht hroutes, const char *name, component_t comp) {
00180     routes_t routes;
00181     int i;
00182 
00183     routes = xhash_get(hroutes, name);
00184     if(routes == NULL) return;
00185 
00186     if(routes->ncomp > 1) {
00187         for(i = 0; i < routes->ncomp; i++) {
00188             if(routes->comp[i] == comp) {
00189                 if(i != routes->ncomp - 1) {
00190                     routes->comp[i] = routes->comp[routes->ncomp - 1];
00191                 }
00192                 routes->ncomp--;
00193             }
00194         }
00195     }
00196     else {
00197         jqueue_push(comp->r->deadroutes, (void *) routes, 0);
00198         xhash_zap(hroutes, name);
00199     }
00200 }
00201 
00202 static void _router_process_bind(component_t comp, nad_t nad) {
00203     int attr, multi, n;
00204     jid_t name;
00205     alias_t alias;
00206     char *user, *c;
00207 
00208     attr = nad_find_attr(nad, 0, -1, "name", NULL);
00209     if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
00210         log_debug(ZONE, "no or invalid 'name' on bind packet, bouncing");
00211         nad_set_attr(nad, 0, -1, "error", "400", 3);
00212         sx_nad_write(comp->s, nad);
00213         return;
00214     }
00215 
00216     user = strdup(comp->s->auth_id);
00217     c = strchr(user, '@');
00218     if(c != NULL) *c = '\0';
00219 
00220     if(strcmp(user, name->domain) != 0 && !aci_check(comp->r->aci, "bind", user)) {
00221         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but their username (%s) is not permitted to bind other names", comp->ip, comp->port, name->domain, user);
00222         nad_set_attr(nad, 0, -1, "name", NULL, 0);
00223         nad_set_attr(nad, 0, -1, "error", "403", 3);
00224         sx_nad_write(comp->s, nad);
00225         jid_free(name);
00226         free(user);
00227         return;
00228     }
00229 
00230     multi = nad_find_attr(nad, 0, -1, "multi", NULL);
00231     if(xhash_get(comp->r->routes, name->domain) != NULL && multi < 0) {
00232         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but it's already bound", comp->ip, comp->port, name->domain);
00233         nad_set_attr(nad, 0, -1, "name", NULL, 0);
00234         nad_set_attr(nad, 0, -1, "error", "409", 3);
00235         sx_nad_write(comp->s, nad);
00236         jid_free(name);
00237         free(user);
00238         return;
00239     }
00240 
00241     for(alias = comp->r->aliases; alias != NULL; alias = alias->next)
00242         if(strcmp(alias->name, name->domain) == 0) {
00243             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but that name is aliased", comp->ip, comp->port);
00244             nad_set_attr(nad, 0, -1, "name", NULL, 0);
00245             nad_set_attr(nad, 0, -1, "error", "409", 3);
00246             sx_nad_write(comp->s, nad);
00247             jid_free(name);
00248             free(user);
00249             return;
00250         }
00251 
00252     /* default route */
00253     if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "default", 1) >= 0) {
00254         if(!aci_check(comp->r->aci, "default-route", user)) {
00255             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but their username (%s) is not permitted to set a default route", comp->ip, comp->port, name->domain, user);
00256             nad_set_attr(nad, 0, -1, "name", NULL, 0);
00257             nad_set_attr(nad, 0, -1, "error", "403", 3);
00258             sx_nad_write(comp->s, nad);
00259             jid_free(name);
00260             free(user);
00261             return;
00262         }
00263 
00264         if(comp->r->default_route != NULL) {
00265             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as the default route, but one already exists", comp->ip, comp->port, name->domain);
00266             nad_set_attr(nad, 0, -1, "name", NULL, 0);
00267             nad_set_attr(nad, 0, -1, "error", "409", 3);
00268             sx_nad_write(comp->s, nad);
00269             jid_free(name);
00270             return;
00271         }
00272 
00273         log_write(comp->r->log, LOG_NOTICE, "[%s] set as default route", name->domain);
00274 
00275         comp->r->default_route = strdup(name->domain);
00276     }
00277 
00278     /* log sinks */
00279     if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "log", 1) >= 0) {
00280         if(!aci_check(comp->r->aci, "log", user)) {
00281             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s' as a log sink, but their username (%s) is not permitted to do this", comp->ip, comp->port, name->domain, user);
00282             nad_set_attr(nad, 0, -1, "name", NULL, 0);
00283             nad_set_attr(nad, 0, -1, "error", "403", 3);
00284             sx_nad_write(comp->s, nad);
00285             jid_free(name);
00286             free(user);
00287             return;
00288         }
00289 
00290         log_write(comp->r->log, LOG_NOTICE, "[%s] set as log sink", name->domain);
00291 
00292         xhash_put(comp->r->log_sinks, pstrdup(xhash_pool(comp->r->log_sinks), name->domain), (void *) comp);
00293     }
00294 
00295     free(user);
00296 
00297     n = _route_add(comp->r->routes, name->domain, comp, multi<0?route_SINGLE:route_MULTI_TO);
00298     xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), name->domain), (void *) comp);
00299 
00300     if(n>1)
00301         log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", name->domain, n, comp->ip, comp->port);
00302     else
00303         log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", name->domain, comp->ip, comp->port);
00304 
00305     nad_set_attr(nad, 0, -1, "name", NULL, 0);
00306     sx_nad_write(comp->s, nad);
00307 
00308     /* advertise name */
00309     _router_advertise(comp->r, name->domain, comp, 0);
00310 
00311     /* tell the new component about everyone else */
00312     xhash_walk(comp->r->routes, _router_advertise_reverse, (void *) comp);
00313 
00314     /* bind aliases */
00315     for(alias = comp->r->aliases; alias != NULL; alias = alias->next) {
00316         if(strcmp(alias->target, name->domain) == 0) {
00317             _route_add(comp->r->routes, name->domain, comp, route_MULTI_TO);
00318             xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp);
00319             
00320             log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, name->domain, comp->ip, comp->port);
00321 
00322             /* advertise name */
00323             _router_advertise(comp->r, alias->name, comp, 0);
00324         }
00325     }
00326 
00327     /* done with this */
00328     jid_free(name);
00329 }
00330 
00331 static void _router_process_unbind(component_t comp, nad_t nad) {
00332     int attr;
00333     jid_t name;
00334 
00335     attr = nad_find_attr(nad, 0, -1, "name", NULL);
00336     if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
00337         log_debug(ZONE, "no or invalid 'name' on unbind packet, bouncing");
00338         nad_set_attr(nad, 0, -1, "error", "400", 3);
00339         sx_nad_write(comp->s, nad);
00340         return;
00341     }
00342 
00343     if(xhash_get(comp->routes, name->domain) == NULL) {
00344         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to unbind '%s', but it's not bound to this component", comp->ip, comp->port, name->domain);
00345         nad_set_attr(nad, 0, -1, "name", NULL, 0);
00346         nad_set_attr(nad, 0, -1, "error", "404", 3);
00347         sx_nad_write(comp->s, nad);
00348         jid_free(name);
00349         return;
00350     }
00351 
00352     xhash_zap(comp->r->log_sinks, name->domain);
00353     _route_remove(comp->r->routes, name->domain, comp);
00354     xhash_zap(comp->routes, name->domain);
00355 
00356     if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) {
00357         log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain);
00358         free(comp->r->default_route);
00359         comp->r->default_route = NULL;
00360     }
00361 
00362     log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain);
00363 
00364     nad_set_attr(nad, 0, -1, "name", NULL, 0);
00365     sx_nad_write(comp->s, nad);
00366 
00367     /* deadvertise name */
00368     if(xhash_get(comp->r->routes, name->domain) == NULL)
00369         _router_advertise(comp->r, name->domain, comp, 1);
00370 
00371     jid_free(name);
00372 }
00373 
00374 static void _router_comp_write(component_t comp, nad_t nad) {
00375     int attr;
00376 
00377     if(comp->tq != NULL) {
00378         log_debug(ZONE, "%s port %d is throttled, jqueueing packet", comp->ip, comp->port);
00379         jqueue_push(comp->tq, nad, 0);
00380         return;
00381     }
00382 
00383     /* packets go raw to normal components */
00384     if(!comp->legacy) {
00385         sx_nad_write(comp->s, nad);
00386         return;
00387     }
00388 
00389     log_debug(ZONE, "packet for legacy component, munging");
00390 
00391     attr = nad_find_attr(nad, 0, -1, "error", NULL);
00392     if(attr >= 0) {
00393         if(NAD_AVAL_L(nad, attr) == 3 && strncmp("400", NAD_AVAL(nad, attr), 3) == 0)
00394             stanza_error(nad, 1, stanza_err_BAD_REQUEST);
00395         else
00396             stanza_error(nad, 1, stanza_err_SERVICE_UNAVAILABLE);
00397     }
00398 
00399     sx_nad_write_elem(comp->s, nad, 1);
00400 }
00401 
00402 static void _router_route_log_sink(const char *key, int keylen, void *val, void *arg) {
00403     component_t comp = (component_t) val;
00404     nad_t nad = (nad_t) arg;
00405 
00406     log_debug(ZONE, "copying route to '%.*s' (%s, port %d)", keylen, key, comp->ip, comp->port);
00407 
00408     nad = nad_copy(nad);
00409     nad_set_attr(nad, 0, -1, "type", "log", 3);
00410     _router_comp_write(comp, nad);
00411 }
00412 
00413 static void _router_process_route(component_t comp, nad_t nad) {
00414     int atype, ato, afrom;
00415     unsigned int dest;
00416     struct jid_st sto, sfrom;
00417     jid_static_buf sto_buf, sfrom_buf;
00418     jid_t to = NULL, from = NULL;
00419     routes_t targets;
00420     component_t target;
00421     union xhashv xhv;
00422 
00423     /* init static jid */
00424     jid_static(&sto,&sto_buf);
00425     jid_static(&sfrom,&sfrom_buf);
00426 
00427     if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) {
00428         log_debug(ZONE, "dropping error packet, trying to avoid loops");
00429         nad_free(nad);
00430         return;
00431     }
00432 
00433     atype = nad_find_attr(nad, 0, -1, "type", NULL);
00434     ato = nad_find_attr(nad, 0, -1, "to", NULL);
00435     afrom = nad_find_attr(nad, 0, -1, "from", NULL);
00436 
00437     if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato));
00438     if(afrom >= 0) from = jid_reset(&sfrom, NAD_AVAL(nad, afrom), NAD_AVAL_L(nad, afrom));
00439 
00440     /* unicast */
00441     if(atype < 0) {
00442         if(to == NULL || from == NULL) {
00443             log_debug(ZONE, "unicast route with missing or invalid to or from, bouncing");
00444             nad_set_attr(nad, 0, -1, "error", "400", 3);
00445             _router_comp_write(comp, nad);
00446             return;
00447         }
00448         
00449         log_debug(ZONE, "unicast route from %s to %s", from->domain, to->domain);
00450 
00451         /* check the from */
00452         if(xhash_get(comp->routes, from->domain) == NULL) {
00453             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain);
00454             nad_set_attr(nad, 0, -1, "error", "401", 3);
00455             _router_comp_write(comp, nad);
00456             return;
00457         }
00458 
00459         /* filter it */
00460         if(comp->r->filter != NULL) {
00461             int ret = filter_packet(comp->r, nad);
00462             if(ret == stanza_err_REDIRECT) {
00463                 ato = nad_find_attr(nad, 0, -1, "to", NULL);
00464                 if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato));
00465             }
00466             else if(ret > 0) {
00467                 log_debug(ZONE, "packet filtered out: %s (%s)", _stanza_errors[ret - stanza_err_BAD_REQUEST].name, _stanza_errors[ret - stanza_err_BAD_REQUEST].code);
00468                 nad_set_attr(nad, 0, -1, "error", _stanza_errors[ret - stanza_err_BAD_REQUEST].code, 3);
00469                 _router_comp_write(comp, nad);
00470                 return;
00471             }
00472         }
00473 
00474         /* find a target */
00475         targets = xhash_get(comp->r->routes, to->domain);
00476         if(targets == NULL) {
00477             if(comp->r->default_route != NULL && strcmp(from->domain, comp->r->default_route) == 0) {
00478                 log_debug(ZONE, "%s is unbound, bouncing", from->domain);
00479                 nad_set_attr(nad, 0, -1, "error", "404", 3);
00480                 _router_comp_write(comp, nad);
00481                 return;
00482             }
00483             targets = xhash_get(comp->r->routes, comp->r->default_route);
00484         }
00485 
00486         if(targets == NULL) {
00487             log_debug(ZONE, "%s is unbound, and no default route, bouncing", to->domain);
00488             nad_set_attr(nad, 0, -1, "error", "404", 3);
00489             _router_comp_write(comp, nad);
00490             return;
00491         }
00492 
00493         /* copy to any log sinks */
00494         if(xhash_count(comp->r->log_sinks) > 0)
00495             xhash_walk(comp->r->log_sinks, _router_route_log_sink, (void *) nad);
00496 
00497         /* get route candidate */
00498         if(targets->ncomp == 1) {
00499             dest = 0;
00500         }
00501         else {
00502             switch(targets->rtype) {
00503                 case route_MULTI_TO:
00504                     ato = nad_find_attr(nad, 1, -1, "to", NULL);
00505                     if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato));
00506                     else {
00507                         ato = nad_find_attr(nad, 1, -1, "target", NULL);
00508                         if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato));
00509                         else {
00510                             char *out; int len;
00511                             nad_print(nad, 0, &out, &len);
00512                             log_write(comp->r->log, LOG_ERR, "Cannot get destination for multiple route: %.*s", len, out);
00513                         }
00514                     }
00515                     break;
00516                 case route_MULTI_FROM:
00517                     ato = nad_find_attr(nad, 1, -1, "from", NULL);
00518                     if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato));
00519                     else {
00520                         char *out; int len;
00521                         nad_print(nad, 0, &out, &len);
00522                         log_write(comp->r->log, LOG_ERR, "Cannot get source for multiple route: %.*s", len, out);
00523                     }
00524                     break;
00525                 default:
00526                     log_write(comp->r->log, LOG_ERR, "Multiple components bound to single component route '%s'", targets->name);
00527                     /* simulate no 'to' info in this case */
00528             }
00529             if(to->node == NULL || strlen(to->node) == 0) {
00530                 /* no node in destination JID - going random */
00531                 dest = rand();
00532                 log_debug(ZONE, "randomized to %u %% %d = %d", dest, targets->ncomp, dest % targets->ncomp);
00533             }
00534             else {
00535                 /* use JID hash */
00536                 unsigned char hashval[20];
00537                 unsigned int *val;
00538                 int i;
00539                 
00540                 shahash_raw(jid_user(to), hashval);
00541                 
00542                 val = (unsigned int *) hashval;
00543                 dest = *val;
00544                 for(i=1; i < 20 / (sizeof(unsigned int)/sizeof(unsigned char)); i++, val++) {
00545                     dest ^= *val;
00546                 }
00547                 dest >>= 2;
00548 
00549                 log_debug(ZONE, "JID %s hashed to %u %% %d = %d", jid_user(to), dest, targets->ncomp, dest % targets->ncomp);
00550 
00551                 /* jid_user() calls jid_expand() which may allocate some memory in _user and _full */
00552                 if (to->_user != NULL )
00553                     free(to->_user);
00554                 if (to->_full != NULL )
00555                     free(to->_full);
00556             }
00557             dest = dest % targets->ncomp;
00558         }
00559 
00560         target = targets->comp[dest];
00561 
00562         /* push it out */
00563         log_debug(ZONE, "writing route for '%s'*%u to %s, port %d", to->domain, dest+1, target->ip, target->port);
00564 
00565         /* if logging enabled, log messages that match our criteria */
00566         if (comp->r->message_logging_enabled && comp->r->message_logging_file != NULL) {
00567             int attr_msg_to;
00568             int attr_msg_from;
00569             int attr_route_to;
00570             int attr_route_from;
00571             jid_t jid_msg_from = NULL;
00572             jid_t jid_msg_to = NULL;
00573             jid_t jid_route_from = NULL;
00574             jid_t jid_route_to = NULL;
00575 
00576             if ((NAD_ENAME_L(nad, 1) == 7 && strncmp("message", NAD_ENAME(nad, 1), 7) == 0) &&      // has a "message" element 
00577                 ((attr_route_from = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) &&
00578                 ((attr_route_to = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) &&
00579                 ((strncmp(NAD_AVAL(nad, attr_route_to), "c2s", 3)) != 0) &&                         // ignore messages to "c2s" or we'd have dups
00580                 ((jid_route_from = jid_new(NAD_AVAL(nad, attr_route_from), NAD_AVAL_L(nad, attr_route_from))) != NULL) &&   // has valid JID source in route
00581                 ((jid_route_to = jid_new(NAD_AVAL(nad, attr_route_to), NAD_AVAL_L(nad, attr_route_to))) != NULL) &&     // has valid JID destination in route
00582                 ((attr_msg_from = nad_find_attr(nad, 1, -1, "from", NULL)) >= 0) &&
00583                 ((attr_msg_to = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0) &&
00584                 ((jid_msg_from = jid_new(NAD_AVAL(nad, attr_msg_from), NAD_AVAL_L(nad, attr_msg_from))) != NULL) && // has valid JID source in message 
00585                 ((jid_msg_to = jid_new(NAD_AVAL(nad, attr_msg_to), NAD_AVAL_L(nad, attr_msg_to))) != NULL))         // has valid JID dest in message
00586             {
00587                 message_log(nad, comp->r, jid_full(jid_msg_from), jid_full(jid_msg_to));
00588             }
00589             if (jid_msg_from != NULL)
00590                 jid_free(jid_msg_from);
00591             if (jid_msg_to != NULL)
00592                 jid_free(jid_msg_to);
00593             if (jid_route_from != NULL)
00594                 jid_free(jid_route_from);
00595             if (jid_route_to != NULL)
00596                 jid_free(jid_route_to);
00597         }
00598 
00599         _router_comp_write(target, nad);
00600 
00601         return;
00602     }
00603 
00604     /* broadcast */
00605     if(NAD_AVAL_L(nad, atype) == 9 && strncmp("broadcast", NAD_AVAL(nad, atype), 9) == 0) {
00606         if(from == NULL) {
00607             log_debug(ZONE, "broadcast route with missing or invalid from, bouncing");
00608             nad_set_attr(nad, 0, -1, "error", "400", 3);
00609             _router_comp_write(comp, nad);
00610             return;
00611         }
00612         
00613         log_debug(ZONE, "broadcast route from %s", from->domain);
00614 
00615         /* check the from */
00616         if(xhash_get(comp->routes, from->domain) == NULL) {
00617             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain);
00618             nad_set_attr(nad, 0, -1, "error", "401", 3);
00619             _router_comp_write(comp, nad);
00620             return;
00621         }
00622 
00623         /* loop the components and distribute */
00624         if(xhash_iter_first(comp->r->components))
00625             do {
00626                 xhv.comp_val = &target;
00627                 xhash_iter_get(comp->r->components, NULL, NULL, xhv.val);
00628 
00629                 if(target != comp) {
00630                     log_debug(ZONE, "writing broadcast to %s, port %d", target->ip, target->port);
00631 
00632                     _router_comp_write(target, nad_copy(nad));
00633                 }
00634             } while(xhash_iter_next(comp->r->components));
00635 
00636         nad_free(nad);
00637 
00638         return;
00639     }
00640 
00641     log_debug(ZONE, "unknown route type '%.*s', dropping", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype));
00642 
00643     nad_free(nad);
00644 }
00645 
00646 static void _router_process_throttle(component_t comp, nad_t nad) {
00647     jqueue_t tq;
00648     nad_t pkt;
00649 
00650     if(comp->tq == NULL) {
00651         _router_comp_write(comp, nad);
00652 
00653         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] throttling packets on request", comp->ip, comp->port);
00654         comp->tq = jqueue_new();
00655     }
00656 
00657     else {
00658         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] unthrottling packets on request", comp->ip, comp->port);
00659         tq = comp->tq;
00660         comp->tq = NULL;
00661 
00662         _router_comp_write(comp, nad);
00663 
00664         while((pkt = jqueue_pull(tq)) != NULL)
00665             _router_comp_write(comp, pkt);
00666 
00667         jqueue_free(tq);
00668     }
00669 }
00670 
00671 static int _router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
00672     component_t comp = (component_t) arg;
00673     sx_buf_t buf = (sx_buf_t) data;
00674     int rlen, len, attr, ns, sns, n;
00675     sx_error_t *sxe;
00676     nad_t nad;
00677     struct jid_st sto, sfrom;
00678     jid_static_buf sto_buf, sfrom_buf;
00679     jid_t to, from;
00680     alias_t alias;
00681 
00682     /* init static jid */
00683     jid_static(&sto,&sto_buf);
00684     jid_static(&sfrom,&sfrom_buf);
00685 
00686     switch(e) {
00687         case event_WANT_READ:
00688             log_debug(ZONE, "want read");
00689             mio_read(comp->r->mio, comp->fd);
00690             break;
00691 
00692         case event_WANT_WRITE:
00693             log_debug(ZONE, "want write");
00694             mio_write(comp->r->mio, comp->fd);
00695             break;
00696 
00697         case event_READ:
00698             log_debug(ZONE, "reading from %d", comp->fd->fd);
00699 
00700             /* check rate limits */
00701             if(comp->rate != NULL) {
00702                 if(rate_check(comp->rate) == 0) {
00703 
00704                     /* inform the app if we haven't already */
00705                     if(!comp->rate_log) {
00706                         log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] is being byte rate limited", comp->ip, comp->port);
00707 
00708                         comp->rate_log = 1;
00709                     }
00710 
00711                     log_debug(ZONE, "%d is throttled, delaying read", comp->fd->fd);
00712 
00713                     buf->len = 0;
00714                     return 0;
00715                 }
00716 
00717                 /* find out how much we can have */
00718                 rlen = rate_left(comp->rate);
00719                 if(rlen > buf->len)
00720                     rlen = buf->len;
00721             }
00722 
00723             /* no limit, just read as much as we can */
00724             else
00725                 rlen = buf->len;
00726             
00727             /* do the read */
00728             len = recv(comp->fd->fd, buf->data, rlen, 0);
00729 
00730             /* update rate limits */
00731             if(comp->rate != NULL && len > 0) {
00732                 comp->rate_log = 0;
00733                 rate_add(comp->rate, len);
00734             }
00735 
00736             if(len < 0) {
00737                 if(MIO_WOULDBLOCK) {
00738                     buf->len = 0;
00739                     return 0;
00740                 }
00741 
00742                 log_debug(ZONE, "read failed: %s", strerror(errno));
00743 
00744                 sx_kill(comp->s);
00745                 
00746                 return -1;
00747             }
00748 
00749             else if(len == 0) {
00750                 /* they went away */
00751                 sx_kill(comp->s);
00752 
00753                 return -1;
00754             }
00755 
00756             log_debug(ZONE, "read %d bytes", len);
00757 
00758             buf->len = len;
00759 
00760             return len;
00761 
00762         case event_WRITE:
00763             log_debug(ZONE, "writing to %d", comp->fd->fd);
00764 
00765             len = send(comp->fd->fd, buf->data, buf->len, 0);
00766             if(len >= 0) {
00767                 log_debug(ZONE, "%d bytes written", len);
00768                 return len;
00769             }
00770 
00771             if(MIO_WOULDBLOCK)
00772                 return 0;
00773 
00774             log_debug(ZONE, "write failed: %s", strerror(errno));
00775         
00776             sx_kill(comp->s);
00777         
00778             return -1;
00779 
00780         case event_ERROR:
00781             sxe = (sx_error_t *) data;
00782             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] error: %s (%s)", comp->ip, comp->port, sxe->generic, sxe->specific);
00783 
00784             break;
00785 
00786         case event_STREAM:
00787             
00788             /* legacy check */
00789             if(s->ns == NULL || strcmp("jabber:component:accept", s->ns) != 0)
00790                 return 0;
00791 
00792             /* component, old skool */
00793             comp->legacy = 1;
00794 
00795             /* enabled? */
00796             if(comp->r->local_secret == NULL) {
00797                 sx_error(s, stream_err_INVALID_NAMESPACE, "support for legacy components not available");      /* !!! correct error? */
00798                 sx_close(s);
00799                 return 0;
00800             }
00801             
00802             /* sanity */
00803             if(s->req_to == NULL) {
00804                 sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header");
00805                 sx_close(s);
00806                 return 0;
00807             }
00808 
00809             break;
00810 
00811         case event_OPEN:
00812             
00813             log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] authenticated as %s", comp->ip, comp->port, comp->s->auth_id);
00814 
00815             /* make a route for legacy components */
00816             if(comp->legacy) {
00817                 for(alias = comp->r->aliases; alias != NULL; alias = alias->next)
00818                     if(strcmp(alias->name, s->req_to) == 0) {
00819                         sx_error(s, stream_err_HOST_UNKNOWN, "requested name is aliased");   /* !!! correct error? */
00820                         sx_close(s);
00821                         return 0;
00822                     }
00823 
00824 
00825                 n = _route_add(comp->r->routes, s->req_to, comp, route_MULTI_FROM);
00826                 xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), s->req_to), (void *) comp);
00827 
00828                 if(n>1)
00829                     log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", s->req_to, n, comp->ip, comp->port);
00830                 else
00831                     log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", s->req_to, comp->ip, comp->port);
00832 
00833                 /* advertise the name */
00834                 _router_advertise(comp->r, s->req_to, comp, 0);
00835 
00836                 /* this is a legacy component, so we don't tell it about other routes */
00837 
00838                 /* bind aliases */
00839                 for(alias = comp->r->aliases; alias != NULL; alias = alias->next) {
00840                     if(strcmp(alias->target, s->req_to) == 0) {
00841                         _route_add(comp->r->routes, alias->name, comp, route_MULTI_FROM);
00842                         xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp);
00843             
00844                         log_write(comp->r->log, LOG_NOTICE, "[%s] online (alias of '%s', bound to %s, port %d)", alias->name, s->req_to, comp->ip, comp->port);
00845 
00846                         /* advertise name */
00847                         _router_advertise(comp->r, alias->name, comp, 0);
00848                     }
00849                 }
00850             }
00851 
00852             break;
00853 
00854         case event_PACKET:
00855             nad = (nad_t) data;
00856 
00857             /* preauth */
00858             if(comp->s->state == state_STREAM) {
00859                 /* non-legacy components can't do anything before auth */
00860                 if(!comp->legacy) {
00861                     log_debug(ZONE, "stream is preauth, dropping packet");
00862                     nad_free(nad);
00863                     return 0;
00864                 }
00865 
00866                 /* watch for handshake requests */
00867                 if(NAD_ENAME_L(nad, 0) != 9 || strncmp("handshake", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) != 0) { 
00868                     log_debug(ZONE, "unknown preauth packet %.*s, dropping", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0));
00869 
00870                     nad_free(nad);
00871                     return 0;
00872                 }
00873 
00874                 /* process incoming handshakes */
00875                 _router_process_handshake(comp, nad);
00876 
00877                 return 0;
00878             }
00879 
00880             /* legacy processing */
00881             if(comp->legacy) {
00882                 log_debug(ZONE, "packet from legacy component, munging it");
00883 
00884                 attr = nad_find_attr(nad, 0, -1, "to", NULL);
00885                 if(attr < 0 || (to = jid_reset(&sto, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
00886                     log_debug(ZONE, "invalid or missing 'to' address on legacy packet, dropping it");
00887                     nad_free(nad);
00888                     return 0;
00889                 }
00890 
00891                 attr = nad_find_attr(nad, 0, -1, "from", NULL);
00892                 if(attr < 0 || (from = jid_reset(&sfrom, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) {
00893                     log_debug(ZONE, "invalid or missing 'from' address on legacy packet, dropping it");
00894                     nad_free(nad);
00895                     return 0;
00896                 }
00897 
00898                 /* rewrite component packets into client packets */
00899                 ns = nad_find_namespace(nad, 0, "jabber:component:accept", NULL);
00900                 if(ns >= 0) {
00901                     if(nad->elems[0].ns == ns)
00902                         nad->elems[0].ns = nad->nss[nad->elems[0].ns].next;
00903                     else {
00904                         for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next);
00905                         nad->nss[sns].next = nad->nss[nad->nss[sns].next].next;
00906                     }
00907                 }
00908 
00909                 ns = nad_find_namespace(nad, 0, uri_CLIENT, NULL);
00910                 if(ns < 0) {
00911                     ns = nad_add_namespace(nad, uri_CLIENT, NULL);
00912                     nad->scope = -1;
00913                     nad->nss[ns].next = nad->elems[0].ns;
00914                     nad->elems[0].ns = ns;
00915                 }
00916                 nad->elems[0].my_ns = ns;
00917 
00918                 /* wrap up the packet */
00919                 ns = nad_add_namespace(nad, uri_COMPONENT, NULL);
00920 
00921                 nad_wrap_elem(nad, 0, ns, "route");
00922 
00923                 nad_set_attr(nad, 0, -1, "to", to->domain, 0);
00924                 nad_set_attr(nad, 0, -1, "from", from->domain, 0);
00925             }
00926 
00927             /* top element must be router scoped */
00928             if(NAD_ENS(nad, 0) < 0 || 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) {
00929                 log_debug(ZONE, "invalid packet namespace, dropping");
00930                 nad_free(nad);
00931                 return 0;
00932             }
00933 
00934             /* bind a name to this component */
00935             if(NAD_ENAME_L(nad, 0) == 4 && strncmp("bind", NAD_ENAME(nad, 0), 4) == 0) {
00936                 _router_process_bind(comp, nad);
00937                 return 0;
00938             }
00939 
00940             /* unbind a name from this component */
00941             if(NAD_ENAME_L(nad, 0) == 6 && strncmp("unbind", NAD_ENAME(nad, 0), 6) == 0) {
00942                 _router_process_unbind(comp, nad);
00943                 return 0;
00944             }
00945 
00946             /* route packets */
00947             if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) {
00948                 _router_process_route(comp, nad);
00949                 return 0;
00950             }
00951 
00952             /* throttle packets */
00953             if(NAD_ENAME_L(nad, 0) == 8 && strncmp("throttle", NAD_ENAME(nad, 0), 8) == 0) {
00954                 _router_process_throttle(comp, nad);
00955                 return 0;
00956             }
00957 
00958             log_debug(ZONE, "unknown packet, dropping");
00959 
00960             nad_free(nad);
00961             return 0;
00962 
00963         case event_CLOSED:
00964         {
00965             /* close comp->fd by putting it in closefd ... unless it is already there */
00966             _jqueue_node_t n;
00967             for (n = comp->r->closefd->front; n != NULL; n = n->prev)
00968                 if (n->data == comp->fd) break;
00969             if (!n) jqueue_push(comp->r->closefd, (void *) comp->fd, 0 /*priority*/);
00970             return 0;
00971         }
00972     }
00973 
00974     return 0;
00975 }
00976 
00977 static int _router_accept_check(router_t r, mio_fd_t fd, char *ip) {
00978     rate_t rt;
00979 
00980     if(access_check(r->access, ip) == 0) {
00981         log_write(r->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd->fd, ip);
00982         return 1;
00983     }
00984 
00985     if(r->conn_rate_total != 0) {
00986         rt = (rate_t) xhash_get(r->conn_rates, ip);
00987         if(rt == NULL) {
00988             rt = rate_new(r->conn_rate_total, r->conn_rate_seconds, r->conn_rate_wait);
00989             xhash_put(r->conn_rates, pstrdup(xhash_pool(r->conn_rates), ip), (void *) rt);
00990         }
00991 
00992         if(rate_check(rt) == 0) {
00993             log_write(r->log, LOG_NOTICE, "[%d] [%s] is being rate limited", fd->fd, ip);
00994             return 1;
00995         }
00996 
00997         rate_add(rt, 1);
00998     }
00999 
01000     return 0;
01001 }
01002 
01003 static void _router_route_unbind_walker(const char *key, int keylen, void *val, void *arg) {
01004     component_t comp = (component_t) arg;
01005 
01006     char * local_key;
01007     xhash_zapx(comp->r->log_sinks, key, keylen);
01008     local_key = (char *) malloc(keylen + 1);
01009     memcpy(local_key, key, keylen);
01010     local_key[keylen] = 0;
01011     _route_remove(comp->r->routes, local_key, comp);
01012     xhash_zapx(comp->routes, key, keylen);
01013 
01014     if(comp->r->default_route != NULL && strlen(comp->r->default_route) == keylen && strncmp(key, comp->r->default_route, keylen) == 0) {
01015         log_write(comp->r->log, LOG_NOTICE, "[%.*s] default route offline", keylen, key);
01016         free(comp->r->default_route);
01017         comp->r->default_route = NULL;
01018     }
01019 
01020     log_write(comp->r->log, LOG_NOTICE, "[%.*s] offline", keylen, key);
01021 
01022     /* deadvertise name */
01023     if(xhash_getx(comp->r->routes, key, keylen) == NULL)
01024         _router_advertise(comp->r, local_key, comp, 1);
01025     free(local_key);
01026 }
01027 
01028 int router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
01029     component_t comp = (component_t) arg;
01030     router_t r = (router_t) arg;
01031     struct sockaddr_storage sa;
01032     int namelen = sizeof(sa), port, nbytes;
01033 
01034     switch(a) {
01035         case action_READ:
01036             log_debug(ZONE, "read action on fd %d", fd->fd);
01037 
01038             /* they did something */
01039             comp->last_activity = time(NULL);
01040 
01041             ioctl(fd->fd, FIONREAD, &nbytes);
01042             if(nbytes == 0) {
01043                 sx_kill(comp->s);
01044                 return 0;
01045             }
01046 
01047             return sx_can_read(comp->s);
01048 
01049         case action_WRITE:
01050             log_debug(ZONE, "write action on fd %d", fd->fd);
01051 
01052            /* update activity timestamp */
01053             comp->last_activity = time(NULL);
01054 
01055             return sx_can_write(comp->s);
01056 
01057         case action_CLOSE:
01058             log_debug(ZONE, "close action on fd %d", fd->fd);
01059 
01060             r = comp->r;
01061 
01062             log_write(r->log, LOG_NOTICE, "[%s, port=%d] disconnect", comp->ip, comp->port);
01063 
01064             /* unbind names */
01065             xhash_walk(comp->routes, _router_route_unbind_walker, (void *) comp);
01066 
01067             /* deregister component */
01068             xhash_zap(r->components, comp->ipport);
01069 
01070             xhash_free(comp->routes);
01071 
01072             if(comp->tq != NULL)
01073                 /* !!! bounce packets */
01074                 jqueue_free(comp->tq);
01075 
01076             rate_free(comp->rate);
01077 
01078             jqueue_push(comp->r->dead, (void *) comp->s, 0);
01079 
01080             free(comp);
01081 
01082             break;
01083 
01084         case action_ACCEPT:
01085             log_debug(ZONE, "accept action on fd %d", fd->fd);
01086 
01087             getpeername(fd->fd, (struct sockaddr *) &sa, &namelen);
01088             port = j_inet_getport(&sa);
01089 
01090             log_write(r->log, LOG_NOTICE, "[%s, port=%d] connect", (char *) data, port);
01091 
01092             if(_router_accept_check(r, fd, (char *) data) != 0)
01093                 return 1;
01094 
01095             comp = (component_t) calloc(1, sizeof(struct component_st));
01096 
01097             comp->r = r;
01098 
01099             comp->fd = fd;
01100 
01101             snprintf(comp->ip, INET6_ADDRSTRLEN, "%s", (char *) data);
01102             comp->port = port;
01103 
01104             snprintf(comp->ipport, INET6_ADDRSTRLEN, "%s:%d", comp->ip, comp->port);
01105 
01106             comp->s = sx_new(r->sx_env, fd->fd, _router_sx_callback, (void *) comp);
01107             mio_app(m, fd, router_mio_callback, (void *) comp);
01108 
01109             if(r->byte_rate_total != 0)
01110                 comp->rate = rate_new(r->byte_rate_total, r->byte_rate_seconds, r->byte_rate_wait);
01111 
01112             comp->routes = xhash_new(51);
01113 
01114             /* register component */
01115             log_debug(ZONE, "new component (%p) \"%s\"", comp, comp->ipport);
01116             xhash_put(r->components, comp->ipport, (void *) comp);
01117 
01118 #ifdef HAVE_SSL
01119             sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER);
01120 #else
01121             sx_server_init(comp->s, SX_SASL_OFFER);
01122 #endif
01123 
01124             break;
01125     }
01126 
01127     return 0;
01128 }
01129 
01130 
01131 int message_log(nad_t nad, router_t r, const unsigned char *msg_from, const unsigned char *msg_to)
01132 {
01133     time_t t;
01134     char *time_pos;
01135     int time_sz;
01136     struct stat filestat;
01137     FILE *message_file;
01138     short int new_msg_file = 0;
01139     int i;
01140     int nad_body_len = 0;
01141     long int nad_body_start = 0;
01142     int body_count;
01143     char *nad_body = NULL;
01144     char body[MAX_MESSAGE*2];
01145 
01146     assert((int) (nad != NULL));
01147 
01148     /* timestamp */
01149     t = time(NULL);
01150     time_pos = ctime(&t);
01151     time_sz = strlen(time_pos);
01152     /* chop off the \n */
01153     time_pos[time_sz-1]=' ';
01154 
01155     // Find the message body
01156     for (i = 0; NAD_ENAME_L(nad, i) > 0; i++)
01157     {
01158         if((NAD_ENAME_L(nad, i) == 4) && (strncmp("body", NAD_ENAME(nad, i), 4) == 0))
01159         {
01160             nad_body_len = NAD_CDATA_L(nad, i);
01161             if (nad_body_len > 0) {
01162                 nad_body = NAD_CDATA(nad, i);
01163             } else {
01164                 log_write(r->log, LOG_NOTICE, "message_log received a message with empty body");
01165                 return 0;
01166             }
01167             break;
01168         }
01169     }
01170 
01171     // Don't log anything if we found no NAD body
01172     if (nad_body == NULL) {
01173         return 0;
01174     }
01175 
01176     // Store original pointer address so that we know when to stop iterating through nad_body
01177     nad_body_start = nad_body;
01178 
01179     // replace line endings with "\n"
01180     for (body_count = 0; (nad_body < nad_body_start + nad_body_len) && (body_count < (MAX_MESSAGE*2)-3); nad_body++) {
01181         if (*nad_body == '\n') {
01182             body[body_count++] = '\\';
01183             body[body_count++] = 'n';
01184         } else {
01185             body[body_count++] = *nad_body;
01186         }
01187     }
01188     body[body_count] = '\0';
01189 
01190     // Log our message
01191     umask((mode_t) 0077);
01192     if (stat(r->message_logging_file, &filestat)) {
01193         new_msg_file = 1;
01194     }
01195 
01196     if ((message_file = fopen(r->message_logging_file, "a")) == NULL)
01197     {
01198         log_write(r->log, LOG_ERR, "Unable to open message log for writing: %s", strerror(errno));
01199         return 1;
01200     }
01201 
01202     if (new_msg_file) {
01203         if (! fprintf(message_file, "# This message log is created by the jabberd router.\n"))
01204         {
01205             log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
01206             return 1;
01207         }
01208         fprintf(message_file, "# See router.xml for logging options.\n");
01209         fprintf(message_file, "# Format: (Date)<tab>(From JID)<tab>(To JID)<tab>(Message Body)<line end>\n");
01210     }
01211 
01212     if (! fprintf(message_file, "%s\t%s\t%s\t%s\n", time_pos, msg_from, msg_to, body))
01213     {
01214         log_write(r->log, LOG_ERR, "Unable to write to message log: %s", strerror(errno));
01215         return 1;
01216     }
01217 
01218     fclose(message_file);
01219 
01220     return 0;
01221 }