static void _sm_hosts_expand(sm_t sm) { config_elem_t elem; char id[1024]; int i; elem = config_get(sm->config, "local.id"); if(!elem) { /* use SM id */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), sm->id), sm); log_write(sm->log, LOG_NOTICE, "id: %s", sm->id); return; } for(i = 0; i < elem->nvalues; i++) { /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } /* insert into vHosts xhash */ xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), id), sm); log_write(sm->log, LOG_NOTICE, "[%s] configured", id); } }
static void _s2s_hosts_expand(s2s_t s2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(s2s->config, "local.id"); if (elem) for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(s2s->hosts), sizeof(struct host_st)); if(!host) { log_write(s2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(s2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(s2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); #ifdef HAVE_SSL if(host->host_pemfile != NULL) { if(s2s->sx_ssl == NULL) { s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode); if(s2s->sx_ssl == NULL) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } else { if(sx_ssl_server_addcert(s2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) { log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif /* insert into vHosts xhash */ xhash_put(s2s->hosts, pstrdup(xhash_pool(s2s->hosts), id), host); log_write(s2s->log, LOG_NOTICE, "[%s] configured; realm=%s", id, host->realm); } }
xht aci_load(router_t r) { xht aci; int aelem, uelem, attr; char type[33]; aci_user_t list_head, list_tail, user; log_debug(ZONE, "loading aci"); aci = xhash_new(51); if((aelem = nad_find_elem(r->config->nad, 0, -1, "aci", 1)) < 0) return aci; aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 1); while(aelem >= 0) { if((attr = nad_find_attr(r->config->nad, aelem, -1, "type", NULL)) < 0) { aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0); continue; } list_head = NULL; list_tail = NULL; snprintf(type, 33, "%.*s", NAD_AVAL_L(r->config->nad, attr), NAD_AVAL(r->config->nad, attr)); log_debug(ZONE, "building list for '%s'", type); uelem = nad_find_elem(r->config->nad, aelem, -1, "user", 1); while(uelem >= 0) { if(NAD_CDATA_L(r->config->nad, uelem) > 0) { user = (aci_user_t) calloc(1, sizeof(struct aci_user_st)); user->name = (char *) malloc(sizeof(char) * (NAD_CDATA_L(r->config->nad, uelem) + 1)); sprintf(user->name, "%.*s", NAD_CDATA_L(r->config->nad, uelem), NAD_CDATA(r->config->nad, uelem)); if(list_tail != NULL) { list_tail->next = user; list_tail = user; } /* record the head of the list */ if(list_head == NULL) { list_head = user; list_tail = user; } log_debug(ZONE, "added '%s'", user->name); } uelem = nad_find_elem(r->config->nad, uelem, -1, "user", 0); } if(list_head != NULL) xhash_put(aci, pstrdup(xhash_pool(aci), type), (void *) list_head); aelem = nad_find_elem(r->config->nad, aelem, -1, "acl", 0); } return aci; }
static int _router_accept_check(router_t r, mio_fd_t fd, const char *ip) { rate_t rt; if(access_check(r->access, ip) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] access denied by configuration", fd->fd, ip); return 1; } if(r->conn_rate_total != 0) { rt = (rate_t) xhash_get(r->conn_rates, ip); if(rt == NULL) { rt = rate_new(r->conn_rate_total, r->conn_rate_seconds, r->conn_rate_wait); xhash_put(r->conn_rates, pstrdup(xhash_pool(r->conn_rates), ip), (void *) rt); } if(rate_check(rt) == 0) { log_write(r->log, LOG_NOTICE, "[%d] [%s] is being rate limited", fd->fd, ip); return 1; } rate_add(rt, 1); } return 0; }
xht aci_load(sm_t sm) { xht acls; int aelem, jelem, attr; char type[33]; jid_t list, jid; log_debug(ZONE, "loading aci"); acls = xhash_new(51); if((aelem = nad_find_elem(sm->config->nad, 0, -1, "aci", 1)) < 0) return acls; aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 1); while(aelem >= 0) { list = NULL; if((attr = nad_find_attr(sm->config->nad, aelem, -1, "type", NULL)) < 0) { aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); continue; } snprintf(type, 33, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr)); log_debug(ZONE, "building list for '%s'", type); jelem = nad_find_elem(sm->config->nad, aelem, -1, "jid", 1); while(jelem >= 0) { if(NAD_CDATA_L(sm->config->nad, jelem) > 0) { jid = jid_new(NAD_CDATA(sm->config->nad, jelem), NAD_CDATA_L(sm->config->nad, jelem)); list = jid_append(list, jid); log_debug(ZONE, "added '%s'", jid_user(jid)); jid_free(jid); } jelem = nad_find_elem(sm->config->nad, jelem, -1, "jid", 0); } if(list != NULL) { xhash_put(acls, pstrdup(xhash_pool(acls), type), (void *) list); } aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); } return acls; }
/** register a new global ns */ int sm_register_ns(sm_t sm, const char *uri) { int ns_idx; ns_idx = (int) (long) xhash_get(sm->xmlns, uri); if (ns_idx == 0) { ns_idx = xhash_count(sm->xmlns) + 2; xhash_put(sm->xmlns, pstrdup(xhash_pool(sm->xmlns), uri), (void *) (long) ns_idx); } xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) + 1)); return ns_idx; }
// Rate limit check: Prevent denial-of-service due to excessive database queries // Make sure owner is responsible for the query! int sm_storage_rate_limit(sm_t sm, const char *owner) { rate_t rt; user_t user; sess_t sess; item_t item; if (sm->query_rate_total == 0 || owner == NULL) return FALSE; user = xhash_get(sm->users, owner); if (user != NULL) { rt = (rate_t) xhash_get(sm->query_rates, owner); if (rt == NULL) { rt = rate_new(sm->query_rate_total, sm->query_rate_seconds, sm->query_rate_wait); xhash_put(sm->query_rates, pstrdup(xhash_pool(sm->query_rates), owner), (void *) rt); pool_cleanup(xhash_pool(sm->query_rates), (void (*)(void *)) rate_free, rt); } if(rate_check(rt) == 0) { log_write(sm->log, LOG_WARNING, "[%s] is being disconnected, too many database queries within %d seconds", owner, sm->query_rate_seconds); user = xhash_get(sm->users, owner); for (sess = user->sessions; sess != NULL; sess = sess->next) { sm_c2s_action(sess, "ended", NULL); } if(xhash_iter_first(user->roster)) do { xhash_iter_get(user->roster, NULL, NULL, (void *) &item); if(item->to) { pkt_router(pkt_create(user->sm, "presence", "unavailable", jid_full(item->jid), jid_full(user->jid))); } } while(xhash_iter_next(user->roster)); return TRUE; } else { rate_add(rt, 1); } } else { log_debug(ZONE, "Error: could not get user data for %s", owner); } return FALSE; }
nad_t nad_new(void) { nad_t nad; nad = calloc(1, sizeof(struct nad_st)); nad->scope = -1; #ifdef NAD_DEBUG { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1); } _nad_ptr_check(__func__, nad); #endif return nad; }
void nad_free(nad_t nad) { if(nad == NULL) return; #ifdef NAD_DEBUG _nad_ptr_check(__func__, nad); { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_zap(_nad_alloc_tracked, loc); xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad); } #endif /* Free nad */ free(nad->elems); free(nad->attrs); free(nad->cdata); free(nad->nss); free(nad->depths); #ifndef NAD_DEBUG free(nad); #endif }
int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { conn_t in = (conn_t) arg; s2s_t s2s = (s2s_t) arg; struct sockaddr_storage sa; int namelen = sizeof(sa), port, nbytes; char ipport[INET6_ADDRSTRLEN + 17]; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(in->s); return 0; } return sx_can_read(in->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(in->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); /* !!! logging */ log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, in->ip, in->port, in->packet_count); jqueue_push(in->s2s->dead, (void *) in->s, 0); /* remove from open streams hash if online, or open connections if not */ if (in->online) xhash_zap(in->s2s->in, in->key); else { snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_zap(in->s2s->in_accept, ipport); } jqueue_push(in->s2s->dead_conn, (void *) in, 0); break; case action_ACCEPT: s2s = (s2s_t) arg; log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming connection", fd->fd, (char *) data, port); /* new conn */ in = (conn_t) calloc(1, sizeof(struct conn_st)); in->s2s = s2s; strncpy(in->ip, (char *) data, INET6_ADDRSTRLEN); in->port = port; in->states = xhash_new(101); in->states_time = xhash_new(101); in->fd = fd; in->init_time = time(NULL); in->s = sx_new(s2s->sx_env, in->fd->fd, _in_sx_callback, (void *) in); mio_app(m, in->fd, in_mio_callback, (void *) in); if(s2s->stanza_size_limit != 0) in->s->rbytesmax = s2s->stanza_size_limit; /* add to incoming connections hash */ snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_put(s2s->in_accept, pstrdup(xhash_pool(s2s->in_accept),ipport), (void *) in); #ifdef HAVE_SSL sx_server_init(in->s, S2S_DB_HEADER | ((s2s->sx_ssl != NULL) ? SX_SSL_STARTTLS_OFFER : 0) ); #else sx_server_init(in->s, S2S_DB_HEADER); #endif break; } return 0; }
/** register a feature */ void feature_register(sm_t sm, const char *feature) { log_debug(ZONE, "registering feature %s", feature); xhash_put(sm->features, pstrdup(xhash_pool(sm->features), feature), (void *) ((long) xhash_get(sm->features, feature) + 1)); }
/** auth requests */ static void _in_result(conn_t in, nad_t nad) { int attr, ns; jid_t from, to; char *rkey; nad_t verify; pkt_t pkt; time_t now; attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid from on db result packet"); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "missing or invalid to on db result packet"); jid_free(from); nad_free(nad); return; } rkey = s2s_route_key(NULL, to->domain, from->domain); log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] received dialback auth request for route '%s'", in->fd->fd, in->ip, in->port, rkey); /* get current state */ if((conn_state_t) xhash_get(in->states, rkey) == conn_VALID) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] route '%s' is already valid: sending valid", in->fd->fd, in->ip, in->port, rkey); /* its already valid, just reply right now */ stanza_tofrom(nad, 0); nad_set_attr(nad, 0, -1, "type", "valid", 5); nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(in->s, nad); free(rkey); jid_free(from); jid_free(to); return; } /* not valid, so we need to verify */ /* need the key */ if(NAD_CDATA_L(nad, 0) <= 0) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback key given with db result packet", in->fd->fd, in->ip, in->port, rkey); free(rkey); nad_free(nad); jid_free(from); jid_free(to); return; } log_debug(ZONE, "requesting verification for route %s", rkey); /* set the route status to INPROGRESS and set timestamp */ xhash_put(in->states, pstrdup(xhash_pool(in->states), rkey), (void *) conn_INPROGRESS); /* record the time that we set conn_INPROGRESS state */ now = time(NULL); xhash_put(in->states_time, pstrdup(xhash_pool(in->states_time), rkey), (void *) now); free(rkey); /* new packet */ verify = nad_new(); ns = nad_add_namespace(verify, uri_DIALBACK, "db"); nad_append_elem(verify, ns, "verify", 0); nad_append_attr(verify, -1, "to", from->domain); nad_append_attr(verify, -1, "from", to->domain); nad_append_attr(verify, -1, "id", in->s->id); nad_append_cdata(verify, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0), 1); /* new packet */ pkt = (pkt_t) calloc(1, sizeof(struct pkt_st)); pkt->nad = verify; pkt->to = from; pkt->from = to; pkt->db = 1; /* its away */ out_packet(in->s2s, pkt); nad_free(nad); }
static char *_config_expandx(config_t c, const char *value, int l) { const char *var_value; #ifdef CONFIGEXPAND_GUARDED static char guard[] = "deadbeaf"; #endif // fprintf(stderr, "config_expand: Expanding '%s'\n", value); char *s = strndup(value, l); char *var_start, *var_end; while ((var_start = strstr(s, "${")) != 0) { // fprintf(stderr, "config_expand: processing '%s'\n", s); var_end = strstr(var_start + 2, "}"); if (var_end) { char *tail = var_end + 1; char *var = var_start + 2; *var_end = 0; // fprintf(stderr, "config_expand: Var '%s', tail is '%s'\n", var, tail); var_value = config_get_one(c, var, 0); if (var_value) { int len = (var_start - s) + strlen(tail) + strlen(var_value) + 1; #ifdef CONFIGEXPAND_GUARDED len += sizeof(guard); #endif char *expanded_str = (char *)calloc(len, 1); #ifdef CONFIGEXPAND_GUARDED char *p_guard = expanded_str + len - sizeof(guard); strncpy(p_guard, guard, sizeof(guard)); #endif char *p = expanded_str; strncpy(expanded_str, s, var_start - s); p += var_start - s; strcpy(p, var_value); p += strlen(var_value); strcpy(p, tail); free(s); s = expanded_str; } else { fprintf(stderr, "config_expand: Have no '%s' defined\n", var); free(s); s = 0; break; } } else { fprintf(stderr, "config_expand: } missmatch\n"); free(s); s = 0; break; } } if (s) { char *retval = pstrdup(xhash_pool(c->hash), s); free(s); return retval; } else { return 0; } }
/** turn an xml file into a config hash */ int config_load_with_id(config_t c, const char *file, const char *id) { struct build_data bd; FILE *f; XML_Parser p; int done, len, end, i, j, attr; char buf[1024], *next; struct nad_elem_st **path; config_elem_t elem; int rv = 0; /* open the file */ f = fopen(file, "r"); if(f == NULL) { fprintf(stderr, "config_load: couldn't open %s for reading: %s\n", file, strerror(errno)); return 1; } /* new parser */ p = XML_ParserCreate(NULL); if(p == NULL) { fprintf(stderr, "config_load: couldn't allocate XML parser\n"); fclose(f); return 1; } /* nice new nad to parse it into */ bd.nad = nad_new(); bd.depth = 0; /* setup the parser */ XML_SetUserData(p, (void *) &bd); XML_SetElementHandler(p, _config_startElement, _config_endElement); XML_SetCharacterDataHandler(p, _config_charData); for(;;) { /* read that file */ len = fread(buf, 1, 1024, f); if(ferror(f)) { fprintf(stderr, "config_load: read error: %s\n", strerror(errno)); XML_ParserFree(p); fclose(f); nad_free(bd.nad); return 1; } done = feof(f); /* parse it */ if(!XML_Parse(p, buf, len, done)) { fprintf(stderr, "config_load: parse error at line %llu: %s\n", (unsigned long long) XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p))); XML_ParserFree(p); fclose(f); nad_free(bd.nad); return 1; } if(done) break; } /* done reading */ XML_ParserFree(p); fclose(f); // Put id if specified if (id) { elem = (config_elem_t)pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); xhash_put(c->hash, pstrdup(xhash_pool(c->hash), "id"), elem); elem->values = calloc(1, sizeof(char *)); elem->values[0] = pstrdup(xhash_pool(c->hash), id); elem->nvalues = 1; } /* now, turn the nad into a config hash */ path = NULL; len = 0, end = 0; /* start at 1, so we skip the root element */ for(i = 1; i < bd.nad->ecur && rv == 0; i++) { /* make sure we have enough room to add this element to our path */ if(end <= bd.nad->elems[i].depth) { end = bd.nad->elems[i].depth + 1; path = (struct nad_elem_st **) realloc((void *) path, sizeof(struct nad_elem_st *) * end); } /* save this path element */ path[bd.nad->elems[i].depth] = &bd.nad->elems[i]; len = bd.nad->elems[i].depth + 1; /* construct the key from the current path */ next = buf; for(j = 1; j < len; j++) { strncpy(next, bd.nad->cdata + path[j]->iname, path[j]->lname); next = next + path[j]->lname; *next = '.'; next++; } next--; *next = '\0'; /* find the config element for this key */ elem = (config_elem_t)xhash_get(c->hash, buf); if(elem == NULL) { /* haven't seen it before, so create it */ elem = (config_elem_t)pmalloco(xhash_pool(c->hash), sizeof(struct config_elem_st)); xhash_put(c->hash, pstrdup(xhash_pool(c->hash), buf), elem); } /* make room for this value .. can't easily realloc off a pool, so * we do it this way and let _config_reaper clean up */ elem->values = realloc((void *) elem->values, sizeof(char *) * (elem->nvalues + 1)); /* and copy it in */ if(NAD_CDATA_L(bd.nad, i) > 0) { // Expand values const char *val = _config_expandx(c, NAD_CDATA(bd.nad, i), NAD_CDATA_L(bd.nad, i)); if (!val) { rv = 1; break; } // Make a copy elem->values[elem->nvalues] = val; } else { elem->values[elem->nvalues] = "1"; } /* make room for the attribute lists */ elem->attrs = realloc((void *) elem->attrs, sizeof(char **) * (elem->nvalues + 1)); elem->attrs[elem->nvalues] = NULL; /* count the attributes */ for(attr = bd.nad->elems[i].attr, j = 0; attr >= 0; attr = bd.nad->attrs[attr].next, j++); /* make space */ elem->attrs[elem->nvalues] = pmalloc(xhash_pool(c->hash), sizeof(char *) * (j * 2 + 2)); /* if we have some */ if(j > 0) { /* copy them in */ j = 0; attr = bd.nad->elems[i].attr; while(attr >= 0) { elem->attrs[elem->nvalues][j] = pstrdupx(xhash_pool(c->hash), NAD_ANAME(bd.nad, attr), NAD_ANAME_L(bd.nad, attr)); elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); /* * pstrdupx(blob, 0) returns NULL - which means that later * there's no way of telling whether an attribute is defined * as empty, or just not defined. This fixes that by creating * an empty string for attributes which are defined empty */ if (NAD_AVAL_L(bd.nad, attr)==0) { elem->attrs[elem->nvalues][j + 1] = pstrdup(xhash_pool(c->hash), ""); } else { elem->attrs[elem->nvalues][j + 1] = pstrdupx(xhash_pool(c->hash), NAD_AVAL(bd.nad, attr), NAD_AVAL_L(bd.nad, attr)); } j += 2; attr = bd.nad->attrs[attr].next; } } /* do this and we can use j_attr */ elem->attrs[elem->nvalues][j] = NULL; elem->attrs[elem->nvalues][j + 1] = NULL; elem->nvalues++; } if(path != NULL) free(path); if(c->nad != NULL) nad_free(c->nad); c->nad = bd.nad; return rv; }
st_ret_t storage_add_type(storage_t st, const char *driver, const char *type) { st_driver_t drv; st_driver_init_fn init_fn = NULL; char mod_fullpath[PATH_MAX]; const char *modules_path; st_ret_t ret; void *handle; /* startup, see if we've already registered this type */ if(type == NULL) { log_debug(ZONE, "adding arbitrary types to driver '%s'", driver); /* see if we already have one */ if(st->default_drv != NULL) { log_debug(ZONE, "we already have a default handler, ignoring this one"); return st_FAILED; } } else { log_debug(ZONE, "adding type '%s' to driver '%s'", type, driver); /* see if we already have one */ if(xhash_get(st->types, type) != NULL) { log_debug(ZONE, "we already have a handler for type '%s', ignoring this one", type); return st_FAILED; } } /* set modules path */ modules_path = config_get_one(st->config, "storage.path", 0); /* get the driver */ drv = xhash_get(st->drivers, driver); if(drv == NULL) { log_debug(ZONE, "driver not loaded, trying to init"); log_write(st->log, LOG_INFO, "loading '%s' storage module", driver); #ifndef _WIN32 if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", modules_path, driver); else snprintf(mod_fullpath, PATH_MAX, "%s/storage_%s.so", LIBRARY_DIR, driver); handle = dlopen(mod_fullpath, RTLD_LAZY); if (handle != NULL) init_fn = dlsym(handle, "st_init"); #else if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s\\storage_%s.dll", modules_path, driver); else snprintf(mod_fullpath, PATH_MAX, "storage_%s.dll", driver); handle = (void*) LoadLibrary(mod_fullpath); if (handle != NULL) init_fn = (st_driver_init_fn)GetProcAddress((HMODULE) handle, "st_init"); #endif if (handle != NULL && init_fn != NULL) { log_debug(ZONE, "preloaded module '%s' (not initialized yet)", driver); } else { #ifndef _WIN32 log_write(st->log, LOG_ERR, "failed loading storage module '%s' (%s)", driver, dlerror()); if (handle != NULL) dlclose(handle); #else log_write(st->log, LOG_ERR, "failed loading storage module '%s' (errcode: %x)", driver, GetLastError()); if (handle != NULL) FreeLibrary((HMODULE) handle); #endif return st_FAILED; } /* make a new driver structure */ drv = (st_driver_t) calloc(1, sizeof(struct st_driver_st)); drv->handle = handle; drv->st = st; log_debug(ZONE, "calling driver initializer"); /* init */ if((init_fn)(drv) == st_FAILED) { log_write(st->log, LOG_NOTICE, "initialisation of storage driver '%s' failed", driver); free(drv); return st_FAILED; } /* add it to the drivers hash so we can find it later */ drv->name = pstrdup(xhash_pool(st->drivers), driver); xhash_put(st->drivers, drv->name, (void *) drv); log_write(st->log, LOG_NOTICE, "initialised storage driver '%s'", driver); } /* if its a default, set it up as such */ if(type == NULL) { st->default_drv = drv; return st_SUCCESS; } /* its a real type, so let the driver know */ if(type != NULL && (ret = (drv->add_type)(drv, type)) != st_SUCCESS) { log_debug(ZONE, "driver '%s' can't handle '%s' data", driver, type); return ret; } /* register the type */ xhash_put(st->types, pstrdup(xhash_pool(st->types), type), (void *) drv); return st_SUCCESS; }
/** get a handle for the named module */ authreg_t authreg_init(c2s_t c2s, const char *name) { char mod_fullpath[PATH_MAX]; const char *modules_path; ar_module_init_fn init_fn = NULL; authreg_t ar; void *handle; /* return if already loaded */ ar = xhash_get(c2s->ar_modules, name); if (ar) { return ar->initialized ? ar : NULL; } /* load authreg module */ modules_path = config_get_one(c2s->config, "authreg.path", 0); if (modules_path != NULL) log_write(c2s->log, LOG_NOTICE, "modules search path: %s", modules_path); else log_write(c2s->log, LOG_NOTICE, "modules search path undefined, using default: "LIBRARY_DIR); log_write(c2s->log, LOG_INFO, "loading '%s' authreg module", name); #ifndef _WIN32 if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s/authreg_%s.so", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "%s/authreg_%s.so", LIBRARY_DIR, name); handle = dlopen(mod_fullpath, RTLD_LAZY); if (handle != NULL) init_fn = dlsym(handle, "ar_init"); #else if (modules_path != NULL) snprintf(mod_fullpath, PATH_MAX, "%s\\authreg_%s.dll", modules_path, name); else snprintf(mod_fullpath, PATH_MAX, "authreg_%s.dll", name); handle = (void*) LoadLibrary(mod_fullpath); if (handle != NULL) init_fn = (ar_module_init_fn)GetProcAddress((HMODULE) handle, "ar_init"); #endif if (handle != NULL && init_fn != NULL) { log_debug(ZONE, "preloaded module '%s' (not initialized yet)", name); } else { #ifndef _WIN32 log_write(c2s->log, LOG_ERR, "failed loading authreg module '%s' (%s)", name, dlerror()); if (handle != NULL) dlclose(handle); #else log_write(c2s->log, LOG_ERR, "failed loading authreg module '%s' (errcode: %x)", name, GetLastError()); if (handle != NULL) FreeLibrary((HMODULE) handle); #endif return NULL; } /* make a new one */ ar = (authreg_t) pmalloco(xhash_pool(c2s->ar_modules), sizeof(struct authreg_st)); if(!ar) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new authreg, aborting"); exit(1); } ar->c2s = c2s; xhash_put(c2s->ar_modules, name, ar); /* call the initialiser */ if((init_fn)(ar) != 0) { log_write(c2s->log, LOG_ERR, "failed to initialize auth module '%s'", name); authreg_free(ar); return NULL; } /* we need user_exists(), at the very least */ if(ar->user_exists == NULL) { log_write(c2s->log, LOG_ERR, "auth module '%s' has no check for user existence", name); authreg_free(ar); return NULL; } /* its good */ ar->initialized = TRUE; log_write(c2s->log, LOG_NOTICE, "initialized auth module '%s'", name); return ar; }
static int _router_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { component_t comp = (component_t) arg; sx_buf_t buf = (sx_buf_t) data; int rlen, len, attr, ns, sns, n; sx_error_t *sxe; nad_t nad; struct jid_st sto, sfrom; jid_static_buf sto_buf, sfrom_buf; jid_t to, from; alias_t alias; /* init static jid */ jid_static(&sto,&sto_buf); jid_static(&sfrom,&sfrom_buf); switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(comp->r->mio, comp->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(comp->r->mio, comp->fd); break; case event_READ: log_debug(ZONE, "reading from %d", comp->fd->fd); /* check rate limits */ if(comp->rate != NULL) { if(rate_check(comp->rate) == 0) { /* inform the app if we haven't already */ if(!comp->rate_log) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] is being byte rate limited", comp->ip, comp->port); comp->rate_log = 1; } log_debug(ZONE, "%d is throttled, delaying read", comp->fd->fd); buf->len = 0; return 0; } /* find out how much we can have */ rlen = rate_left(comp->rate); if(rlen > buf->len) rlen = buf->len; } /* no limit, just read as much as we can */ else rlen = buf->len; /* do the read */ len = recv(comp->fd->fd, buf->data, rlen, 0); /* update rate limits */ if(comp->rate != NULL && len > 0) { comp->rate_log = 0; rate_add(comp->rate, len); } if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_debug(ZONE, "read failed: %s", strerror(errno)); sx_kill(comp->s); return -1; } else if(len == 0) { /* they went away */ sx_kill(comp->s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", comp->fd->fd); len = send(comp->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_debug(ZONE, "write failed: %s", strerror(errno)); sx_kill(comp->s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] error: %s (%s)", comp->ip, comp->port, sxe->generic, sxe->specific); break; case event_STREAM: /* legacy check */ if(s->ns == NULL || strcmp("jabber:component:accept", s->ns) != 0) return 0; /* component, old skool */ comp->legacy = 1; /* enabled? */ if(comp->r->local_secret == NULL) { sx_error(s, stream_err_INVALID_NAMESPACE, "support for legacy components not available"); /* !!! correct error? */ sx_close(s); return 0; } /* sanity */ if(s->req_to == NULL) { sx_error(s, stream_err_HOST_UNKNOWN, "no 'to' attribute on stream header"); sx_close(s); return 0; } break; case event_OPEN: log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] authenticated as %s", comp->ip, comp->port, comp->s->auth_id); /* make a route for legacy components */ if(comp->legacy) { for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, s->req_to) == 0) { sx_error(s, stream_err_HOST_UNKNOWN, "requested name is aliased"); /* !!! correct error? */ sx_close(s); return 0; } n = _route_add(comp->r->routes, s->req_to, comp, route_MULTI_FROM); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), s->req_to), (void *) comp); if(n>1) log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", s->req_to, n, comp->ip, comp->port); else log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", s->req_to, comp->ip, comp->port); /* advertise the name */ _router_advertise(comp->r, s->req_to, comp, 0); /* this is a legacy component, so we don't tell it about other routes */ /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, s->req_to) == 0) { _route_add(comp->r->routes, alias->name, comp, route_MULTI_FROM); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp); 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); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } } break; case event_PACKET: nad = (nad_t) data; /* preauth */ if(comp->s->state == state_STREAM) { /* non-legacy components can't do anything before auth */ if(!comp->legacy) { log_debug(ZONE, "stream is preauth, dropping packet"); nad_free(nad); return 0; } /* watch for handshake requests */ if(NAD_ENAME_L(nad, 0) != 9 || strncmp("handshake", NAD_ENAME(nad, 0), NAD_ENAME_L(nad, 0)) != 0) { log_debug(ZONE, "unknown preauth packet %.*s, dropping", NAD_ENAME_L(nad, 0), NAD_ENAME(nad, 0)); nad_free(nad); return 0; } /* process incoming handshakes */ _router_process_handshake(comp, nad); return 0; } /* legacy processing */ if(comp->legacy) { log_debug(ZONE, "packet from legacy component, munging it"); attr = nad_find_attr(nad, 0, -1, "to", NULL); if(attr < 0 || (to = jid_reset(&sto, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'to' address on legacy packet, dropping it"); nad_free(nad); return 0; } attr = nad_find_attr(nad, 0, -1, "from", NULL); if(attr < 0 || (from = jid_reset(&sfrom, NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "invalid or missing 'from' address on legacy packet, dropping it"); nad_free(nad); return 0; } /* rewrite component packets into client packets */ ns = nad_find_namespace(nad, 0, "jabber:component:accept", NULL); if(ns >= 0) { if(nad->elems[0].ns == ns) nad->elems[0].ns = nad->nss[nad->elems[0].ns].next; else { for(sns = nad->elems[0].ns; sns >= 0 && nad->nss[sns].next != ns; sns = nad->nss[sns].next); nad->nss[sns].next = nad->nss[nad->nss[sns].next].next; } } ns = nad_find_namespace(nad, 0, uri_CLIENT, NULL); if(ns < 0) { ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad->scope = -1; nad->nss[ns].next = nad->elems[0].ns; nad->elems[0].ns = ns; } nad->elems[0].my_ns = ns; /* wrap up the packet */ ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_wrap_elem(nad, 0, ns, "route"); nad_set_attr(nad, 0, -1, "to", to->domain, 0); nad_set_attr(nad, 0, -1, "from", from->domain, 0); } /* top element must be router scoped */ 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) { log_debug(ZONE, "invalid packet namespace, dropping"); nad_free(nad); return 0; } /* bind a name to this component */ if(NAD_ENAME_L(nad, 0) == 4 && strncmp("bind", NAD_ENAME(nad, 0), 4) == 0) { _router_process_bind(comp, nad); return 0; } /* unbind a name from this component */ if(NAD_ENAME_L(nad, 0) == 6 && strncmp("unbind", NAD_ENAME(nad, 0), 6) == 0) { _router_process_unbind(comp, nad); return 0; } /* route packets */ if(NAD_ENAME_L(nad, 0) == 5 && strncmp("route", NAD_ENAME(nad, 0), 5) == 0) { _router_process_route(comp, nad); return 0; } /* throttle packets */ if(NAD_ENAME_L(nad, 0) == 8 && strncmp("throttle", NAD_ENAME(nad, 0), 8) == 0) { _router_process_throttle(comp, nad); return 0; } log_debug(ZONE, "unknown packet, dropping"); nad_free(nad); return 0; case event_CLOSED: { /* close comp->fd by putting it in closefd ... unless it is already there */ _jqueue_node_t n; for (n = comp->r->closefd->front; n != NULL; n = n->prev) if (n->data == comp->fd) break; if (!n) jqueue_push(comp->r->closefd, (void *) comp->fd, 0 /*priority*/); return 0; } } return 0; }
static void _router_process_bind(component_t comp, nad_t nad) { int attr, multi, n; jid_t name; alias_t alias; char *user, *c; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on bind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } user = strdup(comp->s->auth_id); c = strchr(user, '@'); if(c != NULL) *c = '\0'; if(strcmp(user, name->domain) != 0 && !aci_check(comp->r->aci, "bind", user)) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } multi = nad_find_attr(nad, 0, -1, "multi", NULL); if(xhash_get(comp->r->routes, name->domain) != NULL && multi < 0) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } for(alias = comp->r->aliases; alias != NULL; alias = alias->next) if(strcmp(alias->name, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to bind '%s', but that name is aliased", comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } /* default route */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "default", 1) >= 0) { if(!aci_check(comp->r->aci, "default-route", user)) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } if(comp->r->default_route != NULL) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "409", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as default route", name->domain); comp->r->default_route = strdup(name->domain); } /* log sinks */ if(nad_find_elem(nad, 0, NAD_ENS(nad, 0), "log", 1) >= 0) { if(!aci_check(comp->r->aci, "log", user)) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "403", 3); sx_nad_write(comp->s, nad); jid_free(name); free(user); return; } log_write(comp->r->log, LOG_NOTICE, "[%s] set as log sink", name->domain); xhash_put(comp->r->log_sinks, pstrdup(xhash_pool(comp->r->log_sinks), name->domain), (void *) comp); } free(user); n = _route_add(comp->r->routes, name->domain, comp, multi<0?route_SINGLE:route_MULTI_TO); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), name->domain), (void *) comp); if(n>1) log_write(comp->r->log, LOG_NOTICE, "[%s]:%d online (bound to %s, port %d)", name->domain, n, comp->ip, comp->port); else log_write(comp->r->log, LOG_NOTICE, "[%s] online (bound to %s, port %d)", name->domain, comp->ip, comp->port); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* advertise name */ _router_advertise(comp->r, name->domain, comp, 0); /* tell the new component about everyone else */ xhash_walk(comp->r->routes, _router_advertise_reverse, (void *) comp); /* bind aliases */ for(alias = comp->r->aliases; alias != NULL; alias = alias->next) { if(strcmp(alias->target, name->domain) == 0) { _route_add(comp->r->routes, name->domain, comp, route_MULTI_TO); xhash_put(comp->routes, pstrdup(xhash_pool(comp->routes), alias->name), (void *) comp); 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); /* advertise name */ _router_advertise(comp->r, alias->name, comp, 0); } } /* done with this */ jid_free(name); }
static void _c2s_hosts_expand(c2s_t c2s) { char *realm; config_elem_t elem; char id[1024]; int i; elem = config_get(c2s->config, "local.id"); if(!elem) { log_write(c2s->log, LOG_NOTICE, "no local.id configured - skipping local domains configuration"); return; } for(i = 0; i < elem->nvalues; i++) { host_t host = (host_t) pmalloco(xhash_pool(c2s->hosts), sizeof(struct host_st)); if(!host) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new host, aborting"); exit(1); } realm = j_attr((const char **) elem->attrs[i], "realm"); /* stringprep ids (domain names) so that they are in canonical form */ strncpy(id, elem->values[i], 1024); id[1023] = '\0'; if (stringprep_nameprep(id, 1024) != 0) { log_write(c2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id); exit(1); } host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(c2s->hosts), id); host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile"); host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain"); host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0); host->host_private_key_password = j_attr((const char **) elem->attrs[i], "private-key-password"); #ifdef HAVE_SSL if(host->host_pemfile != NULL) { if(c2s->sx_ssl == NULL) { c2s->sx_ssl = sx_env_plugin(c2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password); if(c2s->sx_ssl == NULL) { log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } else { if(sx_ssl_server_addcert(c2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode, host->host_private_key_password) != 0) { log_write(c2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm); host->host_pemfile = NULL; } } } #endif host->host_require_starttls = (j_attr((const char **) elem->attrs[i], "require-starttls") != NULL); host->ar_register_enable = (j_attr((const char **) elem->attrs[i], "register-enable") != NULL); host->ar_register_oob = j_attr((const char **) elem->attrs[i], "register-oob"); if(host->ar_register_enable || host->ar_register_oob) { host->ar_register_instructions = j_attr((const char **) elem->attrs[i], "instructions"); if(host->ar_register_instructions == NULL) { if(host->ar_register_oob) host->ar_register_instructions = "Only web based registration is possible with this server."; else host->ar_register_instructions = "Enter a username and password to register with this server."; } } else host->ar_register_password = (j_attr((const char **) elem->attrs[i], "password-change") != NULL); /* check for empty <id/> CDATA - XXX this "1" is VERY config.c dependant !!! */ if(! strcmp(id, "1")) { /* remove the realm even if set */ host->realm = NULL; /* skip if vHost already configured */ if(! c2s->vhost) c2s->vhost = host; /* add meaningful log "id" */ strcpy(id, "default vHost"); } else { /* insert into vHosts xhash */ xhash_put(c2s->hosts, pstrdup(xhash_pool(c2s->hosts), id), host); } log_write(c2s->log, LOG_NOTICE, "[%s] configured; realm=%s, registration %s, using PEM:%s", id, (host->realm != NULL ? host->realm : "no realm set"), (host->ar_register_enable ? "enabled" : "disabled"), (host->host_pemfile ? host->host_pemfile : "Default")); } }
/** pull values out of the config file */ static void _c2s_config_expand(c2s_t c2s) { const char *str, *ip, *mask; char *req_domain, *to_address, *to_port; config_elem_t elem; int i; stream_redirect_t sr; set_debug_log_from_config(c2s->config); c2s->id = config_get_one(c2s->config, "id", 0); if(c2s->id == NULL) c2s->id = "c2s"; c2s->router_ip = config_get_one(c2s->config, "router.ip", 0); if(c2s->router_ip == NULL) c2s->router_ip = "127.0.0.1"; c2s->router_port = j_atoi(config_get_one(c2s->config, "router.port", 0), 5347); c2s->router_user = config_get_one(c2s->config, "router.user", 0); if(c2s->router_user == NULL) c2s->router_user = "******"; c2s->router_pass = config_get_one(c2s->config, "router.pass", 0); if(c2s->router_pass == NULL) c2s->router_pass = "******"; c2s->router_pemfile = config_get_one(c2s->config, "router.pemfile", 0); c2s->router_cachain = config_get_one(c2s->config, "router.cachain", 0); c2s->router_private_key_password = config_get_one(c2s->config, "router.private_key_password", 0); c2s->retry_init = j_atoi(config_get_one(c2s->config, "router.retry.init", 0), 3); c2s->retry_lost = j_atoi(config_get_one(c2s->config, "router.retry.lost", 0), 3); if((c2s->retry_sleep = j_atoi(config_get_one(c2s->config, "router.retry.sleep", 0), 2)) < 1) c2s->retry_sleep = 1; c2s->log_type = log_STDOUT; if(config_get(c2s->config, "log") != NULL) { if((str = config_get_attr(c2s->config, "log", 0, "type")) != NULL) { if(strcmp(str, "file") == 0) c2s->log_type = log_FILE; else if(strcmp(str, "syslog") == 0) c2s->log_type = log_SYSLOG; } } if(c2s->log_type == log_SYSLOG) { c2s->log_facility = config_get_one(c2s->config, "log.facility", 0); c2s->log_ident = config_get_one(c2s->config, "log.ident", 0); if(c2s->log_ident == NULL) c2s->log_ident = "jabberd/c2s"; } else if(c2s->log_type == log_FILE) c2s->log_ident = config_get_one(c2s->config, "log.file", 0); c2s->packet_stats = config_get_one(c2s->config, "stats.packet", 0); c2s->local_ip = config_get_one(c2s->config, "local.ip", 0); if(c2s->local_ip == NULL) c2s->local_ip = "0.0.0.0"; c2s->local_port = j_atoi(config_get_one(c2s->config, "local.port", 0), 0); c2s->local_pemfile = config_get_one(c2s->config, "local.pemfile", 0); c2s->local_cachain = config_get_one(c2s->config, "local.cachain", 0); c2s->local_private_key_password = config_get_one(c2s->config, "local.private_key_password", 0); c2s->local_verify_mode = j_atoi(config_get_one(c2s->config, "local.verify-mode", 0), 0); c2s->local_ssl_port = j_atoi(config_get_one(c2s->config, "local.ssl-port", 0), 0); c2s->http_forward = config_get_one(c2s->config, "local.httpforward", 0); c2s->io_max_fds = j_atoi(config_get_one(c2s->config, "io.max_fds", 0), 1024); c2s->compression = (config_get(c2s->config, "io.compression") != NULL); c2s->io_check_interval = j_atoi(config_get_one(c2s->config, "io.check.interval", 0), 0); c2s->io_check_idle = j_atoi(config_get_one(c2s->config, "io.check.idle", 0), 0); c2s->io_check_keepalive = j_atoi(config_get_one(c2s->config, "io.check.keepalive", 0), 0); c2s->pbx_pipe = config_get_one(c2s->config, "pbx.pipe", 0); elem = config_get(c2s->config, "stream_redirect.redirect"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { sr = (stream_redirect_t) pmalloco(xhash_pool(c2s->stream_redirects), sizeof(struct stream_redirect_st)); if(!sr) { log_write(c2s->log, LOG_ERR, "cannot allocate memory for new stream redirection record, aborting"); exit(1); } req_domain = j_attr((const char **) elem->attrs[i], "requested_domain"); to_address = j_attr((const char **) elem->attrs[i], "to_address"); to_port = j_attr((const char **) elem->attrs[i], "to_port"); if(req_domain == NULL || to_address == NULL || to_port == NULL) { log_write(c2s->log, LOG_ERR, "Error reading a stream_redirect.redirect element from file, skipping"); continue; } // Note that to_address should be RFC 3986 compliant sr->to_address = to_address; sr->to_port = to_port; xhash_put(c2s->stream_redirects, pstrdup(xhash_pool(c2s->stream_redirects), req_domain), sr); } } c2s->ar_module_name = config_get_one(c2s->config, "authreg.module", 0); if(config_get(c2s->config, "authreg.mechanisms.traditional.plain") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_PLAIN; if(config_get(c2s->config, "authreg.mechanisms.traditional.digest") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_DIGEST; if(config_get(c2s->config, "authreg.mechanisms.traditional.cram-md5") != NULL) c2s->ar_mechanisms |= AR_MECH_TRAD_CRAMMD5; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.plain") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_PLAIN; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.digest") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_DIGEST; if(config_get(c2s->config, "authreg.ssl-mechanisms.traditional.cram-md5") != NULL) c2s->ar_ssl_mechanisms |= AR_MECH_TRAD_CRAMMD5; elem = config_get(c2s->config, "io.limits.bytes"); if(elem != NULL) { c2s->byte_rate_total = j_atoi(elem->values[0], 0); if(c2s->byte_rate_total != 0) { c2s->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1); c2s->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } elem = config_get(c2s->config, "io.limits.stanzas"); if(elem != NULL) { c2s->stanza_rate_total = j_atoi(elem->values[0], 0); if(c2s->stanza_rate_total != 0) { c2s->stanza_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 1); c2s->stanza_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } elem = config_get(c2s->config, "io.limits.connects"); if(elem != NULL) { c2s->conn_rate_total = j_atoi(elem->values[0], 0); if(c2s->conn_rate_total != 0) { c2s->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5); c2s->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5); } } c2s->stanza_size_limit = j_atoi(config_get_one(c2s->config, "io.limits.stanzasize", 0), 0); /* tweak timed checks with rate times */ if(c2s->io_check_interval == 0) { if(c2s->byte_rate_total != 0) c2s->io_check_interval = c2s->byte_rate_wait; if(c2s->stanza_rate_total != 0 && c2s->io_check_interval > c2s->stanza_rate_wait) c2s->io_check_interval = c2s->stanza_rate_wait; } str = config_get_one(c2s->config, "io.access.order", 0); if(str == NULL || strcmp(str, "deny,allow") != 0) c2s->access = access_new(0); else c2s->access = access_new(1); elem = config_get(c2s->config, "io.access.allow"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_allow(c2s->access, ip, mask); } } elem = config_get(c2s->config, "io.access.deny"); if(elem != NULL) { for(i = 0; i < elem->nvalues; i++) { ip = j_attr((const char **) elem->attrs[i], "ip"); mask = j_attr((const char **) elem->attrs[i], "mask"); if(ip == NULL) continue; if(mask == NULL) mask = "255.255.255.255"; access_deny(c2s->access, ip, mask); } } }
int user_table_load(router_t r) { const char *userfile; FILE *f; long size; char *buf; nad_t nad; int nusers, user, name, secret; log_debug(ZONE, "loading user table"); if(r->users != NULL) xhash_free(r->users); r->users = xhash_new(51); userfile = config_get_one(r->config, "local.users", 0); if(userfile == NULL) userfile = CONFIG_DIR "/router-users.xml"; f = fopen(userfile, "rb"); if(f == NULL) { log_write(r->log, LOG_ERR, "couldn't open user table file %s: %s", userfile, strerror(errno)); return 1; } fseek(f, 0, SEEK_END); size = ftell(f); if(size < 0) { log_write(r->log, LOG_ERR, "couldn't seek user table file %s: %s", userfile, strerror(errno)); fclose(f); return 1; } if(size == 0) { log_write(r->log, LOG_ERR, "empty user table file %s", userfile); fclose(f); return 1; } fseek(f, 0, SEEK_SET); buf = (char *) malloc(sizeof(char) * size); if (fread(buf, 1, size, f) != size || ferror(f)) { log_write(r->log, LOG_ERR, "couldn't read from user table file: %s", strerror(errno)); free(buf); fclose(f); return 1; } fclose(f); nad = nad_parse(buf, size); if(nad == NULL) { log_write(r->log, LOG_ERR, "couldn't parse user table"); free(buf); return 1; } free(buf); nusers = 0; user = nad_find_elem(nad, 0, -1, "user", 1); while(user >= 0) { name = nad_find_elem(nad, user, -1, "name", 1); secret = nad_find_elem(nad, user, -1, "secret", 1); if(name < 0 || secret < 0 || NAD_CDATA_L(nad, name) <= 0 || NAD_CDATA_L(nad, secret) <= 0) { log_write(r->log, LOG_ERR, "malformed user entry in user table file, skipping"); continue; } log_debug(ZONE, "remembering user '%.*s'", NAD_CDATA_L(nad, name), NAD_CDATA(nad, name)); xhash_put(r->users, pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, name), NAD_CDATA_L(nad, name)), pstrdupx(xhash_pool(r->users), NAD_CDATA(nad, secret), NAD_CDATA_L(nad, secret))); nusers++; user = nad_find_elem(nad, user, -1, "user", 0); } nad_free(nad); log_write(r->log, LOG_NOTICE, "loaded user table (%d users)", nusers); r->users_load = time(NULL); return 0; }