/** 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; }
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; }
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; }