/* drop incoming presence if the user isn't around, * so we don't have to load them during broadcasts */ mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt) { user_t user; sess_t sess; /* only check presence to users, pass presence to sm and probes */ if(!(pkt->type & pkt_PRESENCE) || pkt->to->node[0] == '\0' || pkt->type == pkt_PRESENCE_PROBE) return mod_PASS; /* get the user _without_ doing a load */ user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to)); /* no user, or no sessions, bail */ if(user == NULL || user->sessions == NULL) { pkt_free(pkt); return mod_HANDLED; } /* only pass if there's at least one available session */ for(sess = user->sessions; sess != NULL; sess = sess->next) if(sess->available) return mod_PASS; /* no available sessions, drop */ pkt_free(pkt); return mod_HANDLED; }
static void _nad_ptr_check(const char *func, nad_t nad) { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); if(xhash_get(_nad_alloc_tracked, loc) == NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad); abort(); } if(xhash_get(_nad_free_tracked, loc) != NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad); abort(); } fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad); }
void mt_ns_rng(mpacket mp, session s) { sbchat sc; char *user = mt_packet_data(mp,5); char *sid, *chal, *host, *port; sc = xhash_get(s->chats,user); /* is there already is a SB session? */ if (sc != NULL) { if (sc->state == sb_START) { log_debug(ZONE,"SB Session with '%s' already started",user); return; } log_debug(ZONE,"Replacing SB session"); mt_chat_end(sc); } sid = mt_packet_data(mp,1); host = mt_packet_data(mp,2); chal = mt_packet_data(mp,4); port = strchr(host,':'); if (port != NULL) { *port = '\0'; port++; } mt_chat_join(s,user,host,j_atoi(port,1863),chal,sid); }
/* * get group's descriptive name by it's text id * returned value needs to be freed by caller */ static const char *_roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid) { os_t os; os_object_t o; char *str; char *group; #ifndef NO_SM_CACHE _roster_publish_group_cache_t group_cached; #endif if(!groupid) return groupid; #ifndef NO_SM_CACHE /* check for remembered group value in cache */ if( rp->group_cache_ttl ) { if( rp->group_cache ) { group_cached = xhash_get(rp->group_cache, groupid); if( group_cached != NULL ) { if( (time(NULL) - group_cached->time) >= rp->group_cache_ttl ) { log_debug(ZONE,"group cache: expiring cached value for %s",groupid); xhash_zap(rp->group_cache, groupid); free(group_cached); } else { log_debug(ZONE,"group cache: returning cached value for %s",groupid); return strdup(group_cached->groupname); } } } else { log_debug(ZONE,"group cache: creating cache"); rp->group_cache = xhash_new(401); } } #endif if(storage_get(sm->st, "published-roster-groups", groupid, NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); if( os_object_get_str(os, o, "groupname", &str) && str ) { group=strdup(str); } else { group=NULL; } os_free(os); #ifndef NO_SM_CACHE if( rp->group_cache_ttl && group ) { log_debug(ZONE,"group cache: updating cache value for %s",groupid); group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st)); group_cached->time = time(NULL); group_cached->groupid = strdup(groupid); group_cached->groupname = strdup(group); xhash_put(rp->group_cache, group_cached->groupid, group_cached); } #endif return group; } else { return NULL; } }
/** get an attr for this value */ char *config_get_attr(config_t c, const char *key, int num, const char *attr) { config_elem_t elem = (config_elem_t)xhash_get(c->hash, key); if(num >= elem->nvalues || elem->attrs == NULL || elem->attrs[num] == NULL) return NULL; return j_attr((const char **) elem->attrs[num], attr); }
/** how many values for this key? */ int config_count(config_t c, const char *key) { config_elem_t elem = (config_elem_t)xhash_get(c->hash, key); if(elem == NULL) return 0; return elem->nvalues; }
/** see if a username is in an acl */ int aci_check(xht aci, const char *type, const char *name) { aci_user_t list, scan; log_debug(ZONE, "checking for '%s' in acl 'all'", name); list = (aci_user_t) xhash_get(aci, "all"); for(scan = list; scan != NULL; scan = scan->next) if(strcmp(scan->name, name) == 0) return 1; if(type != NULL) { log_debug(ZONE, "checking for '%s' in acl '%s'", name, type); list = (aci_user_t) xhash_get(aci, type); for(scan = list; scan != NULL; scan = scan->next) if(strcmp(scan->name, name) == 0) return 1; } return 0; }
static void _router_process_unbind(component_t comp, nad_t nad) { int attr; jid_t name; 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 unbind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } if(xhash_get(comp->routes, name->domain) == NULL) { 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); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "404", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } xhash_zap(comp->r->log_sinks, name->domain); _route_remove(comp->r->routes, name->domain, comp); xhash_zap(comp->routes, name->domain); if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain); free((void*)(comp->r->default_route)); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* deadvertise name */ if(xhash_get(comp->r->routes, name->domain) == NULL) _router_advertise(comp->r, name->domain, comp, 1); jid_free(name); }
/** see if a jid is in an acl */ int aci_check(xht acls, char *type, jid_t jid) { jid_t list, dup; dup = jid_dup(jid); if (dup->resource[0]) { /* resourceless version */ dup->resource[0] = '\0'; dup->dirty = 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_full(jid)); list = (jid_t) xhash_get(acls, "all"); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_user(dup)); if(jid_search(list, dup)) { jid_free(dup); return 1; } if(type != NULL) { log_debug(ZONE, "checking for '%s' in acl '%s'", jid_full(jid), type); list = (jid_t) xhash_get(acls, type); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl '%s'", jid_user(dup), type); if(jid_search(list, dup)) { jid_free(dup); return 1; } } jid_free(dup); return 0; }
int at_run_iqcb(ati ti, const char *ns, jpacket jp) { iqcb cb; log_debug(ZONE, "Running callback for %s", ns); cb = xhash_get(ti->iq__callbacks, ns); if(cb == NULL) return -1; return cb(ti, jp); }
END_TEST START_TEST(test_find) { xhash_t* ht = g_ht; char buffer[255]; int i; /* test bad match */ fail_unless(xhash_get(ht, "bad") == NULL , "invalid case not null"); fail_unless(xhash_get(ht, "-1") == NULL , "invalid case not null"); fail_unless(xhash_get(ht, "10000") == NULL, "invalid case not null"); /* test all good indexes */ for (i = 0; i < g_hashableslen; ++i) { snprintf(buffer, sizeof(buffer), "%d", i); fail_unless(xhash_get(ht, buffer) == (g_hashables + i), "bad hashable item returned"); } }
/** get config value n for this key */ const char *config_get_one(config_t c, const char* key, int num) { config_elem_t elem = (config_elem_t) xhash_get(c->hash, key); if(elem == NULL) return NULL; if(num >= elem->nvalues) return NULL; return elem->values[num]; }
/** unregister feature */ void feature_unregister(sm_t sm, const char *feature) { int refcount = (int) (long) xhash_get(sm->features, feature); log_debug(ZONE, "unregistering feature %s", feature); if (refcount == 1) { xhash_zap(sm->features, feature); } else if (refcount > 1) { xhash_put(sm->features, feature, (void *) ((long) refcount - 1)); } }
// 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; }
int at_iq_last(ati ti, jpacket jp) { xmlnode last; xmlnode q; char str[10]; /* XXX I can do last if I track logouts in the XDB... not too hard */ if(jpacket_subtype(jp) != JPACKET__GET) { at_bounce(ti, jp, TERROR_BAD); return 1; } if(jp->to->user != NULL) { at_session s; at_buddy buddy; char *res; s = at_session_find_by_jid(ti, jp->from); if(s == NULL) { at_bounce(ti, jp, TERROR_REGISTER); return 1; } buddy = xhash_get(s->buddies, jp->to->user); if(buddy == NULL) { at_bounce(ti, jp, TERROR_BAD); return 1; } jutil_iqresult(jp->x); last = xmlnode_insert_tag(jp->x, "query"); xmlnode_put_attrib(last,"xmlns",NS_LAST); sprintf(str, "%d", buddy->idle_time); xmlnode_put_attrib(last, "seconds", str); at_deliver(ti,jp->x); return 1; } jutil_iqresult(jp->x); last = xmlnode_insert_tag(jp->x, "query"); xmlnode_put_attrib(last,"xmlns",NS_LAST); sprintf(str, "%d", time(NULL) - ti->start_time); xmlnode_put_attrib(last,"seconds", str); at_deliver(ti,jp->x); return 1; }
int at_register_iqns(ati ti, const char *ns, iqcb cb) { iqcb cur; log_debug(ZONE, "Registering callback for %s", ns); cur = xhash_get(ti->iq__callbacks, ns); if(cur) { xhash_zap(ti->iq__callbacks, ns); } xhash_put(ti->iq__callbacks, ns, cb); return; }
/* * _find_alias_node_record - find a record for node with the alias of * the specified name supplied * IN: name - name to be aliased of the desired node * IN: log_missing - if set, then print an error message if the node is not found * OUT: return pointer to node record or NULL if not found */ static struct node_record *_find_alias_node_record(char *name, bool log_missing) { int i; char *alias = NULL; if ((name == NULL) || (name[0] == '\0')) { info("%s: passed NULL name", __func__); return NULL; } /* Get the alias we have just to make sure the user isn't * trying to use the real hostname to run on something that has * been aliased. */ alias = slurm_conf_get_nodename(name); if (!alias) return NULL; /* try to find via hash table, if it exists */ if (node_hash_table) { struct node_record *node_ptr; node_ptr = (struct node_record*) xhash_get(node_hash_table, alias); if (node_ptr) { xassert(node_ptr->magic == NODE_MAGIC); xfree(alias); return node_ptr; } if (log_missing) error("%s: lookup failure for %s", __func__, name); } /* revert to sequential search */ else { for (i = 0; i < node_record_count; i++) { if (!xstrcmp (alias, node_record_table_ptr[i].name)) { xfree(alias); return (&node_record_table_ptr[i]); } } } xfree(alias); return (struct node_record *) NULL; }
result dnsrv_deliver(instance i, dpacket p, void* args) { dns_io di = (dns_io)args; xmlnode c; int timeout = di->cache_timeout; char *ip; jid to; /* if we get a route packet, it has to be to *us* and have the child as the real packet */ if(p->type == p_ROUTE) { if(j_strcmp(p->host,i->id) != 0 || (to = jid_new(p->p,xmlnode_get_attrib(xmlnode_get_firstchild(p->x),"to"))) == NULL) return r_ERR; p->x=xmlnode_get_firstchild(p->x); p->id = to; p->host = to->server; } /* Ensure this packet doesn't already have an IP */ if(xmlnode_get_attrib(p->x, "ip") || xmlnode_get_attrib(p->x, "iperror")) { log_notice(p->host, "dropping looping dns lookup request: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } /* try the cache first */ if((c = xhash_get(di->cache_table, p->host)) != NULL) { /* if there's no IP, cached failed lookup, time those out 10 times faster! (weird, I know, *shrug*) */ if((ip = xmlnode_get_attrib(c,"ip")) == NULL) timeout = timeout / 10; if((time(NULL) - (int)xmlnode_get_vattrib(c,"t")) > timeout) { /* timed out of the cache, lookup again */ xmlnode_free(c); xhash_zap(di->cache_table,p->host); }else{ /* yay, send back right from the cache */ dnsrv_resend(p->x, ip, xmlnode_get_attrib(c,"to")); return r_DONE; } } dnsrv_lookup(di, p); return r_DONE; }
END_TEST /* returns the number of item deleted from the hash table */ static int test_delete_helper() { xhash_t* ht = g_ht; int ret = 0; int i; char buffer[255]; for (i = 0; i < g_hashableslen; ++i) { snprintf(buffer, sizeof(buffer), "%d", i); if (xhash_get(ht, buffer) != (g_hashables + i)) { ++ret; } } return ret; }
static int _route_add(xht hroutes, const char *name, component_t comp, route_type_t rtype) { routes_t routes; routes = xhash_get(hroutes, name); if(routes == NULL) { routes = (routes_t) calloc(1, sizeof(struct routes_st)); routes->name = strdup(name); routes->rtype = rtype; } routes->comp = (component_t *) realloc(routes->comp, sizeof(component_t *) * (routes->ncomp + 1)); routes->comp[routes->ncomp] = comp; routes->ncomp++; xhash_put(hroutes, routes->name, (void *) routes); if(routes->rtype != rtype) log_write(comp->r->log, LOG_ERR, "Mixed route types for '%s' bind request", name); return routes->ncomp; }
/* * _find_node_record - find a record for node with specified name * IN: name - name of the desired node * IN: test_alias - if set, also test NodeHostName value * IN: log_missing - if set, then print an error message if the node is not found * RET: pointer to node record or NULL if not found */ static struct node_record *_find_node_record (char *name, bool test_alias, bool log_missing) { int i; struct node_record *node_ptr; if ((name == NULL) || (name[0] == '\0')) { info("find_node_record passed NULL name"); return NULL; } /* try to find via hash table, if it exists */ if (node_hash_table) { node_ptr = (struct node_record*) xhash_get(node_hash_table, name); if (node_ptr) { xassert(node_ptr->magic == NODE_MAGIC); return node_ptr; } if ((node_record_count == 1) && (xstrcmp(node_record_table_ptr[0].name, "localhost") == 0)) return (&node_record_table_ptr[0]); if (log_missing) error ("find_node_record: lookup failure for %s", name); } /* revert to sequential search */ else { for (i = 0; i < node_record_count; i++) { if (!xstrcmp (name, node_record_table_ptr[i].name)) { return (&node_record_table_ptr[i]); } } } if (test_alias) { /* look for the alias node record if the user put this in * instead of what slurm sees the node name as */ return _find_alias_node_record(name, log_missing); } return NULL; }
/* Hostname lookup requested */ void dnsrv_lookup(dns_io d, dpacket p) { dns_packet_list l, lnew; xmlnode req; char *reqs; /* make sure we have a child! */ if(d->out <= 0) { deliver_fail(p, "DNS Resolver Error"); return; } /* Attempt to lookup this hostname in the packet table */ l = (dns_packet_list)xhash_get(d->packet_table, p->host); /* IF: hashtable has the hostname, a lookup is already pending, so push the packet on the top of the list (most recent at the top) */ if (l != NULL) { log_debug(ZONE, "dnsrv: Adding lookup request for %s to pending queue.", p->host); lnew = pmalloco(p->p, sizeof(_dns_packet_list)); lnew->packet = p; lnew->stamp = time(NULL); lnew->next = l; xhash_put(d->packet_table, p->host, lnew); return; } /* insert the packet into the packet_table using the hostname as the key and send a request to the coprocess */ log_debug(ZONE, "dnsrv: Creating lookup request queue for %s", p->host); l = pmalloco(p->p, sizeof(_dns_packet_list)); l->packet = p; l->stamp = time(NULL); xhash_put(d->packet_table, p->host, l); req = xmlnode_new_tag_pool(p->p,"host"); xmlnode_insert_cdata(req,p->host,-1); reqs = xmlnode2str(req); log_debug(ZONE, "dnsrv: Transmitting lookup request: %s", reqs); pth_write(d->out, reqs, strlen(reqs)); }
static void _route_remove(xht hroutes, const char *name, component_t comp) { routes_t routes; int i; routes = xhash_get(hroutes, name); if(routes == NULL) return; if(routes->ncomp > 1) { for(i = 0; i < routes->ncomp; i++) { if(routes->comp[i] == comp) { if(i != routes->ncomp - 1) { routes->comp[i] = routes->comp[routes->ncomp - 1]; } routes->ncomp--; } } } else { jqueue_push(comp->r->deadroutes, (void *) routes, 0); xhash_zap(hroutes, name); } }
END_TEST START_TEST(test_add) { xhash_t* ht = NULL; hashable_t a[4] = {{"0", 0}, {"1", 1}, {"2", 2}, {"3", 3}}; int i, len = sizeof(a)/sizeof(a[0]); char buffer[255]; ht = xhash_init(hashable_identify, NULL, NULL, 0); fail_unless(xhash_add(NULL, a) == NULL, "invalid cases not null"); fail_unless(xhash_add(ht, NULL) == NULL, "invalid cases not null"); fail_unless(xhash_add(ht, a) != NULL, "xhash_add failed"); fail_unless(xhash_add(ht, a+1) != NULL, "xhash_add failed"); fail_unless(xhash_add(ht, a+2) != NULL, "xhash_add failed"); fail_unless(xhash_add(ht, a+3) != NULL, "xhash_add failed"); for (i = 0; i < len; ++i) { snprintf(buffer, sizeof(buffer), "%d", i); fail_unless(xhash_get(ht, buffer) == (a + i), "bad hashable item returned"); } xhash_free(ht); }
st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count) { st_driver_t drv; st_ret_t ret; log_debug(ZONE, "storage_count: type=%s owner=%s filter=%s", type, owner, filter); /* find the handler for this type */ drv = xhash_get(st->types, type); if(drv == NULL) { /* never seen it before, so it goes to the default driver */ drv = st->default_drv; if(drv == NULL) { log_debug(ZONE, "no driver associated with type, and no default driver"); return st_NOTIMPL; } /* register the type */ ret = storage_add_type(st, drv->name, type); if(ret != st_SUCCESS) return ret; } return ((drv->count != NULL) ? (drv->count)(drv, type, owner, filter, count) : st_NOTIMPL); }
int entity_add_data(entity_t* entity, const char* key, void* value, void (*_free)(void*)) { entity_data_t* result; entity_data_t* new_data_item; if (!key || !*key || !value) return 0; result = (entity_data_t*)xhash_get(entity->data, key); if (result != NULL) { if (_free) _free(result->value); result->value = value; return 1; } new_data_item = (entity_data_t*)xmalloc(sizeof(entity_data_t)); new_data_item->key = key; new_data_item->value = value; result = xhash_add(entity->data, new_data_item); if (result == NULL) { xfree(new_data_item); return 0; } return 1; }
static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, elem, target, targetns; st_ret_t ret; char filter[4096]; os_t os; os_object_t o; nad_t nad; pkt_t result; sess_t sscan; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "query", 1); /* find the first child */ target = elem + 1; while(target < pkt->nad->ecur) { if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth) break; target++; } /* not found, so we're done */ if(target == pkt->nad->ecur) return -stanza_err_BAD_REQUEST; /* find the target namespace */ targetns = NAD_ENS(pkt->nad, target); /* gotta have a namespace */ if(targetns < 0) { log_debug(ZONE, "no namespace specified"); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); /* get */ if(pkt->type == pkt_IQ) { #ifdef ENABLE_EXPERIMENTAL /* remember that this resource requested the namespace */ if(sess->module_data[mod->index] == NULL) { /* create new hash if necesary */ sess->module_data[mod->index] = xhash_new(101); pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]); } xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1); #endif snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os); switch(ret) { case st_SUCCESS: if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { result = pkt_new(sess->user->sm, nad_copy(nad)); if(result != NULL) { nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); os_free(os); return mod_HANDLED; } } } os_free(os); /* drop through */ log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND"); case st_NOTFOUND: log_debug(ZONE, "namespace not found, returning"); /* * !!! really, we should just return a 404. 1.4 just slaps a * result on the packet and sends it back. hurrah for * legacy namespaces. */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } } os = os_new(); o = os_object_new(os); snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); os_object_put(o, "ns", filter, os_type_STRING); os_object_put(o, "xml", pkt->nad, os_type_NAD); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: /* create result packet */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* and flush it to the session */ pkt_sess(result, sess); #ifdef ENABLE_EXPERIMENTAL /* push it to all resources that read this xmlns item */ snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* skip our resource and those that didn't read any private-storage */ if(sscan == sess || sscan->module_data[mod->index] == NULL) continue; /* check whether namespace was read */ if(xhash_get(sscan->module_data[mod->index], filter)) { result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } #endif /* finally free the packet */ pkt_free(pkt); return mod_HANDLED; } /* we never get here */ return 0; }
/** * process commandline * @return: 0 to indicate that output needs to be written */ int _pbx_process_command(c2s_t c2s, char *cmd) { jid_t jid; int action = 0, len; sess_t sess; unsigned char hashbuf[44] = "PBX"; unsigned char *sesshash; sesshash = hashbuf+3; /* get command */ if(!strncasecmp("START ", cmd, 6)) { cmd += 6; action = 1; } if(!strncasecmp("STOP ", cmd, 5)) { cmd += 5; action = 2; } if(action != 0) { len = _pbx_command_part_len(cmd); if(len > 0) { jid = jid_new(cmd, len); if(jid) { cmd += len; if(*cmd != '\0') cmd++; shahash_r(jid_full(jid), sesshash); sess = xhash_get(c2s->sessions, hashbuf); switch(action) { case 1: log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd); if(sess == NULL) { /* create new session */ sess = (sess_t) calloc(1, sizeof(struct sess_st)); sess->c2s = c2s; sess->last_activity = time(NULL); /* put into sessions hash */ snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf); xhash_put(c2s->sessions, sess->skey, (void *) sess); /* generate bound resource */ sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf); sess->resources->jid = jid; /* open SM session */ log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid)); sm_start(sess, sess->resources); /* generate presence packet to get session online */ /* a bit hacky, but we need to emulate _some_ of the client behavior */ sess->result = _pbx_presence_nad(1, cmd); } else { /* just send the presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd)); } break; case 2: log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd); if(sess != NULL) { /* send unavailable presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd)); /* end the session */ sm_end(sess, sess->resources); xhash_zap(c2s->sessions, sess->skey); jqueue_push(c2s->dead_sess, (void *) sess, 0); } break; } /* TODO: respond with "OK", return 0 */ return -1; } } /* TODO: generate "ERR" response, return 0 */ return -1; } if(!strncasecmp("STATUS", cmd, 6)) { log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet"); return -1; } return -1; }
static void _router_process_route(component_t comp, nad_t nad) { int atype, ato, afrom; unsigned int dest; struct jid_st sto, sfrom; jid_static_buf sto_buf, sfrom_buf; jid_t to = NULL, from = NULL; routes_t targets; component_t target; union xhashv xhv; /* init static jid */ jid_static(&sto,&sto_buf); jid_static(&sfrom,&sfrom_buf); if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) { log_debug(ZONE, "dropping error packet, trying to avoid loops"); nad_free(nad); return; } atype = nad_find_attr(nad, 0, -1, "type", NULL); ato = nad_find_attr(nad, 0, -1, "to", NULL); afrom = nad_find_attr(nad, 0, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); if(afrom >= 0) from = jid_reset(&sfrom, NAD_AVAL(nad, afrom), NAD_AVAL_L(nad, afrom)); /* unicast */ if(atype < 0) { if(to == NULL || from == NULL) { log_debug(ZONE, "unicast route with missing or invalid to or from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "unicast route from %s to %s", from->domain, to->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { 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); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* filter it */ if(comp->r->filter != NULL) { int ret = filter_packet(comp->r, nad); if(ret == stanza_err_REDIRECT) { ato = nad_find_attr(nad, 0, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); } else if(ret > 0) { log_debug(ZONE, "packet filtered out: %s (%s)", _stanza_errors[ret - stanza_err_BAD_REQUEST].name, _stanza_errors[ret - stanza_err_BAD_REQUEST].code); nad_set_attr(nad, 0, -1, "error", _stanza_errors[ret - stanza_err_BAD_REQUEST].code, 3); _router_comp_write(comp, nad); return; } } /* find a target */ targets = xhash_get(comp->r->routes, to->domain); if(targets == NULL) { if(comp->r->default_route != NULL && strcmp(from->domain, comp->r->default_route) == 0) { log_debug(ZONE, "%s is unbound, bouncing", from->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } targets = xhash_get(comp->r->routes, comp->r->default_route); } if(targets == NULL) { log_debug(ZONE, "%s is unbound, and no default route, bouncing", to->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } /* copy to any log sinks */ if(xhash_count(comp->r->log_sinks) > 0) xhash_walk(comp->r->log_sinks, _router_route_log_sink, (void *) nad); /* get route candidate */ if(targets->ncomp == 1) { dest = 0; } else { switch(targets->rtype) { case route_MULTI_TO: ato = nad_find_attr(nad, 1, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { ato = nad_find_attr(nad, 1, -1, "target", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get destination for multiple route: %.*s", len, out); } } break; case route_MULTI_FROM: ato = nad_find_attr(nad, 1, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get source for multiple route: %.*s", len, out); } break; default: log_write(comp->r->log, LOG_ERR, "Multiple components bound to single component route '%s'", targets->name); /* simulate no 'to' info in this case */ } if(to->node == NULL || strlen(to->node) == 0) { /* no node in destination JID - going random */ dest = rand(); log_debug(ZONE, "randomized to %u %% %d = %d", dest, targets->ncomp, dest % targets->ncomp); } else { /* use JID hash */ unsigned char hashval[20]; unsigned int *val; int i; shahash_raw(jid_user(to), hashval); val = (unsigned int *) hashval; dest = *val; for(i=1; i < 20 / (sizeof(unsigned int)/sizeof(unsigned char)); i++, val++) { dest ^= *val; } dest >>= 2; log_debug(ZONE, "JID %s hashed to %u %% %d = %d", jid_user(to), dest, targets->ncomp, dest % targets->ncomp); /* jid_user() calls jid_expand() which may allocate some memory in _user and _full */ if (to->_user != NULL ) free(to->_user); if (to->_full != NULL ) free(to->_full); } dest = dest % targets->ncomp; } target = targets->comp[dest]; /* push it out */ log_debug(ZONE, "writing route for '%s'*%u to %s, port %d", to->domain, dest+1, target->ip, target->port); /* if logging enabled, log messages that match our criteria */ if (comp->r->message_logging_enabled && comp->r->message_logging_file != NULL) { int attr_msg_to; int attr_msg_from; int attr_route_to; int attr_route_from; jid_t jid_msg_from = NULL; jid_t jid_msg_to = NULL; jid_t jid_route_from = NULL; jid_t jid_route_to = NULL; if ((NAD_ENAME_L(nad, 1) == 7 && strncmp("message", NAD_ENAME(nad, 1), 7) == 0) && // has a "message" element ((attr_route_from = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) && ((attr_route_to = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) && ((strncmp(NAD_AVAL(nad, attr_route_to), "c2s", 3)) != 0) && // ignore messages to "c2s" or we'd have dups ((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 ((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 ((attr_msg_from = nad_find_attr(nad, 1, -1, "from", NULL)) >= 0) && ((attr_msg_to = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0) && ((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 ((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 { message_log(nad, comp->r, jid_full(jid_msg_from), jid_full(jid_msg_to)); } if (jid_msg_from != NULL) jid_free(jid_msg_from); if (jid_msg_to != NULL) jid_free(jid_msg_to); if (jid_route_from != NULL) jid_free(jid_route_from); if (jid_route_to != NULL) jid_free(jid_route_to); } _router_comp_write(target, nad); return; } /* broadcast */ if(NAD_AVAL_L(nad, atype) == 9 && strncmp("broadcast", NAD_AVAL(nad, atype), 9) == 0) { if(from == NULL) { log_debug(ZONE, "broadcast route with missing or invalid from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "broadcast route from %s", from->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { 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); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* loop the components and distribute */ if(xhash_iter_first(comp->r->components)) do { xhv.comp_val = ⌖ xhash_iter_get(comp->r->components, NULL, NULL, xhv.val); if(target != comp) { log_debug(ZONE, "writing broadcast to %s, port %d", target->ip, target->port); _router_comp_write(target, nad_copy(nad)); } } while(xhash_iter_next(comp->r->components)); nad_free(nad); return; } log_debug(ZONE, "unknown route type '%.*s', dropping", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype)); nad_free(nad); }
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); }