/** make a new action route */ static nad_t _sm_build_route(sess_t sess, bres_t res, const char *action, const char *target, const char *id) { nad_t nad; int ns, ans; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "route", 0); nad_append_attr(nad, -1, "to", sess->smcomp?sess->smcomp:((char *) res->jid->domain)); nad_append_attr(nad, -1, "from", sess->c2s->id); ans = nad_add_namespace(nad, uri_SESSION, "sc"); nad_append_elem(nad, ans, "session", 1); if(res->c2s_id[0] != '\0') nad_append_attr(nad, ans, "c2s", res->c2s_id); if(res->sm_id[0] != '\0') nad_append_attr(nad, ans, "sm", res->sm_id); nad_append_attr(nad, -1, "action", action); if(target != NULL) { nad_set_attr(nad, 0, -1, "target", target, NULL); nad_append_attr(nad, -1, "target", target); } if(id != NULL) nad_append_attr(nad, -1, "id", id); log_debug(ZONE, "built new route nad for %s action %s target %s id %s", jid_full(res->jid), action, target, id); return nad; }
/** send a new action route */ void sm_c2s_action(sess_t dest, const char *action, const char *target) { nad_t nad; int rns, sns; nad = nad_new(); rns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, rns, "route", 0); nad_append_attr(nad, -1, "to", dest->c2s); nad_append_attr(nad, -1, "from", dest->user->sm->id); sns = nad_add_namespace(nad, uri_SESSION, "sc"); nad_append_elem(nad, sns, "session", 1); if (dest->c2s_id[0] != '\0') nad_append_attr(nad, sns, "c2s", dest->c2s_id); if (dest->sm_id[0] != '\0') nad_append_attr(nad, sns, "sm", dest->sm_id); nad_append_attr(nad, -1, "action", action); if (target != NULL) nad_append_attr(nad, -1, "target", target); log_debug(ZONE, "routing nad to %s from %s c2s %s s2s %s action %s target %s", dest->c2s, dest->user->sm->id, dest->c2s_id, dest->sm_id, action, target); sx_nad_write(dest->user->sm->router, nad); }
/** utility: generate a failure nad */ static nad_t _sx_sasl_failure(sx_t s, const char *err) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "failure", 0); if(err != NULL) nad_append_elem(nad, ns, err, 1); return nad; }
static void _sx_compress_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; /* if the session is already compressed, or the app told us not to, * or STARTTLS is required and stream is not encrypted yet, then we don't offer anything */ if(s->compressed || !(s->flags & SX_COMPRESS_OFFER) || ((s->flags & SX_SSL_STARTTLS_REQUIRE) && s->ssf == 0)) return; _sx_debug(ZONE, "offering compression"); ns = nad_add_namespace(nad, uri_COMPRESS_FEATURE, NULL); nad_append_elem(nad, ns, "compression", 1); nad_append_elem(nad, ns, "method", 2); nad_append_cdata(nad, "zlib", 4, 3); }
/** tell a component about all the others */ static void _router_advertise_reverse(const char *key, int keylen, void *val, void *arg) { component_t dest = (component_t) arg; routes_t routes = (routes_t) val; int el, ns, i; nad_t nad; assert((int) (routes->name != NULL)); assert((int) (routes->comp != NULL)); assert(routes->ncomp); /* don't tell me about myself */ for(i = 0; i < routes->ncomp; i++) if(routes->comp[i] == dest) return; log_debug(ZONE, "informing component about %.*s", keylen, key); /* create a new packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); el = nad_append_elem(nad, ns, "presence", 0); nad_set_attr(nad, el, -1, "from", key, keylen); sx_nad_write(dest->s, nad); }
/** utility: generate an abort nad */ static nad_t _sx_sasl_abort(sx_t s) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "abort", 0); return nad; }
/** sx features callback */ static void _address_features(sx_t s, sx_plugin_t p, nad_t nad) { int ns; /* offer feature only when not authenticated yet */ if(s->state >= state_OPEN) return; _sx_debug(ZONE, "adding address feature"); ns = nad_add_namespace(nad, uri_ADDRESS_FEATURE, NULL); nad_append_elem(nad, ns, "address", 1); nad_append_cdata(nad, s->ip, strlen(s->ip), 2); }
/** utility: generate a response nad */ static nad_t _sx_sasl_response(sx_t s, char *data, int dlen) { nad_t nad; int ns; nad = nad_new(); ns = nad_add_namespace(nad, uri_SASL, NULL); nad_append_elem(nad, ns, "response", 0); if(data != NULL) nad_append_cdata(nad, data, dlen, 1); return nad; }
static void _config_startElement(void *arg, const char *name, const char **atts) { struct build_data *bd = (struct build_data *) arg; int i = 0; nad_append_elem(bd->nad, -1, (char *) name, bd->depth); while(atts[i] != NULL) { nad_append_attr(bd->nad, -1, (char *) atts[i], (char *) atts[i + 1]); i += 2; } bd->depth++; }
pkt_t amp_build_response_pkt(pkt_t pkt, amp_rule_t rule) { if (!pkt || !rule) return NULL; if (rule->result == AMP_TRIGGERED) { int ns; pkt_t res = pkt_create(pkt->sm, "message", NULL, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, res); ns = nad_add_namespace(res->nad, uri_AMP, NULL); nad_append_elem(res->nad, ns, "amp", 2); nad_append_attr(res->nad, -1, "status", rule->action); nad_append_attr(res->nad, -1, "from", jid_full(pkt->from)); nad_append_attr(res->nad, -1, "to", jid_full(pkt->to)); nad_append_elem(res->nad, ns, "rule", 3); nad_append_attr(res->nad, -1, "condition", rule->condition); nad_append_attr(res->nad, -1, "value", rule->value); nad_append_attr(res->nad, -1, "action", rule->action); return res; } return NULL; }
/** register get handler */ static void _authreg_register_get(c2s_t c2s, sess_t sess, nad_t nad) { int attr, ns; char id[128]; /* registrations can happen if reg is enabled and we can create users and set passwords */ if(sess->active || !(sess->host->ar->set_password != NULL && sess->host->ar->create_user != NULL && (sess->host->ar_register_enable || sess->host->ar_register_oob))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_free(nad); /* build a result packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "iq", 0); nad_append_attr(nad, -1, "type", "result"); if(attr >= 0) nad_append_attr(nad, -1, "id", id); ns = nad_add_namespace(nad, uri_REGISTER, NULL); nad_append_elem(nad, ns, "query", 1); nad_append_elem(nad, ns, "instructions", 2); nad_append_cdata(nad, sess->host->ar_register_instructions, strlen(sess->host->ar_register_instructions), 3); if(sess->host->ar_register_enable) { nad_append_elem(nad, ns, "username", 2); nad_append_elem(nad, ns, "password", 2); } if(sess->host->ar_register_oob) { int ns = nad_add_namespace(nad, uri_OOB, NULL); nad_append_elem(nad, ns, "x", 2); nad_append_elem(nad, ns, "url", 3); nad_append_cdata(nad, sess->host->ar_register_oob, strlen(sess->host->ar_register_oob), 4); } /* give it back to the client */ sx_nad_write(sess->s, nad); }
/** domain advertisement */ static void _router_advertise(router_t r, const char *domain, component_t src, int unavail) { struct broadcast_st bc; int ns; log_debug(ZONE, "advertising %s to all routes (unavail=%d)", domain, unavail); bc.r = r; bc.src = src; /* create a new packet */ bc.nad = nad_new(); ns = nad_add_namespace(bc.nad, uri_COMPONENT, NULL); nad_append_elem(bc.nad, ns, "presence", 0); nad_append_attr(bc.nad, -1, "from", domain); if(unavail) nad_append_attr(bc.nad, -1, "type", "unavailable"); xhash_walk(r->routes, _router_broadcast, (void *) &bc); nad_free(bc.nad); }
static mod_ret_t _pep_out_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* add pep identity to disco results from bare JID */ if(!(pkt->type & pkt_IQ) || pkt->ns != ns_DISCO_INFO || (pkt->from != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->from)))) return mod_PASS; /* add PEP identity */ nad_append_elem(pkt->nad, -1, "identity", 3); nad_append_attr(pkt->nad, -1, "category", "pubsub"); nad_append_attr(pkt->nad, -1, "type", "pep"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#access-presence"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#auto-create"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#auto-subscribe"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#filtered-notifications"); nad_append_elem(pkt->nad, -1, "feature", 3); nad_append_attr(pkt->nad, -1, "var", uri_PUBSUB "#publish"); return mod_PASS; }
/** our master callback */ int sm_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { sm_t sm = (sm_t) arg; sx_buf_t buf = (sx_buf_t) data; sx_error_t *sxe; nad_t nad; pkt_t pkt; int len, ns, elem, attr; char *domain; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(sm->mio, sm->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(sm->mio, sm->fd); break; case event_READ: log_debug(ZONE, "reading from %d", sm->fd->fd); /* do the read */ len = recv(sm->fd->fd, buf->data, buf->len, 0); if (len < 0) { if (MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(sm->log, LOG_NOTICE, "[%d] [router] read error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if (len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", sm->fd->fd); len = send(sm->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_write(sm->log, LOG_NOTICE, "[%d] [router] write error: %s (%d)", sm->fd->fd, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(sm->log, LOG_NOTICE, "error from router: %s (%s)", sxe->generic, sxe->specific); if(sxe->code == SX_ERR_AUTH) sx_close(s); break; case event_STREAM: break; case event_OPEN: log_write(sm->log, LOG_NOTICE, "connection to router established"); /* set connection attempts counter */ sm->retry_left = sm->retry_lost; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); nad_append_elem(nad, ns, "bind", 0); nad_append_attr(nad, -1, "name", sm->id); log_debug(ZONE, "requesting component bind for '%s'", sm->id); sx_nad_write(sm->router, nad); if(xhash_iter_first(sm->hosts)) do { xhash_iter_get(sm->hosts, (void *) &domain, &len, NULL); /* skip already requested SM id */ if (strlen(sm->id) == len && strncmp(sm->id, domain, len) == 0) continue; nad = nad_new(); ns = nad_add_namespace(nad, uri_COMPONENT, NULL); elem = nad_append_elem(nad, ns, "bind", 0); nad_set_attr(nad, elem, -1, "name", domain, len); nad_append_attr(nad, -1, "multi", "to"); log_debug(ZONE, "requesting domain bind for '%.*s'", len, domain); sx_nad_write(sm->router, nad); } while(xhash_iter_next(sm->hosts)); sm_update_host = 1; break; case event_PACKET: nad = (nad_t) data; /* drop unqualified packets */ if (NAD_ENS(nad, 0) < 0) { nad_free(nad); return 0; } /* watch for the features packet */ if (s->state == state_STREAM) { if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_STREAMS) || strncmp(uri_STREAMS, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_STREAMS)) != 0 || NAD_ENAME_L(nad, 0) != 8 || strncmp("features", NAD_ENAME(nad, 0), 8) != 0) { log_debug(ZONE, "got a non-features packet on an unauth'd stream, dropping"); nad_free(nad); return 0; } #ifdef HAVE_SSL /* starttls if we can */ if (sm->sx_ssl != NULL && s->ssf == 0) { ns = nad_find_scoped_namespace(nad, uri_TLS, NULL); if (ns >= 0) { elem = nad_find_elem(nad, 0, ns, "starttls", 1); if (elem >= 0) { if (sx_ssl_client_starttls(sm->sx_ssl, s, NULL, NULL) == 0) { nad_free(nad); return 0; } log_write(sm->log, LOG_NOTICE, "unable to establish encrypted session with router"); } } } #endif /* !!! pull the list of mechanisms, and choose the best one. * if there isn't an appropriate one, error and bail */ /* authenticate */ sx_sasl_auth(sm->sx_sasl, s, "jabberd-router", "DIGEST-MD5", sm->router_user, sm->router_pass); nad_free(nad); return 0; } /* watch for the bind response */ if (s->state == state_OPEN && !sm->online) { if (NAD_NURI_L(nad, NAD_ENS(nad, 0)) != strlen(uri_COMPONENT) || strncmp(uri_COMPONENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_COMPONENT)) != 0 || NAD_ENAME_L(nad, 0) != 4 || strncmp("bind", NAD_ENAME(nad, 0), 4)) { log_debug(ZONE, "got a packet from router, but we're not online, dropping"); nad_free(nad); return 0; } /* catch errors */ attr = nad_find_attr(nad, 0, -1, "error", NULL); if(attr >= 0) { log_write(sm->log, LOG_NOTICE, "router refused bind request (%.*s)", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); exit(1); } log_debug(ZONE, "coming online"); /* we're online */ sm->online = sm->started = 1; log_write(sm->log, LOG_NOTICE, "%s ready for sessions", sm->id); nad_free(nad); return 0; } log_debug(ZONE, "got a packet"); pkt = pkt_new(sm, nad); if (pkt == NULL) { log_debug(ZONE, "invalid packet, dropping"); return 0; } /* go */ dispatch(sm, pkt); return 0; case event_CLOSED: mio_close(sm->mio, sm->fd); sm->fd = NULL; return -1; } return 0; }
static nad_t _pbx_presence_nad(int available, char *cmd) { nad_t nad; int ns; char *show = NULL; nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "presence", 0); if(!available) { nad_append_attr(nad, -1, "type", "unavailable"); } else { char *cont; long int priority; char prioritystr[5]; // -128 to +127 + \0 priority = strtol(cmd, &cont, 10); log_debug(ZONE, "Read %ld priority", priority); if(cmd == cont) priority = -1; // use -1 priority if not given if(priority < -128) priority = -128; if(priority > 127) priority = 127; nad_append_elem(nad, -1, "priority", 1); snprintf(prioritystr, 5, "%ld", priority); nad_append_cdata(nad, prioritystr, strlen(prioritystr), 2); if(cmd != cont) { cmd = cont; while(*cmd == ' ') { cmd++; } } if(!strncmp("CHAT", cmd, 4)) { cmd += 4; show = "chat"; } if(!strncmp("ONLINE", cmd, 6)) { cmd += 6; } if(!strncmp("DND", cmd, 3)) { cmd += 3; show = "dnd"; } if(!strncmp("AWAY", cmd, 4)) { cmd += 4; show = "away"; } if(!strncmp("XA", cmd, 2)) { cmd += 2; show = "xa"; } if(show) { nad_append_elem(nad, -1, "show", 1); nad_append_cdata(nad, show, strlen(show), 2); } } while(*cmd == ' ') { cmd++; } if(*cmd != '\0' && *cmd != '\n') { int len = strlen(cmd); nad_append_elem(nad, -1, "status", 1); nad_append_cdata(nad, cmd, len - (cmd[len-1] == '\n' ? 1 : 0), 2); } return nad; }
/** 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); }
/** auth get handler */ static void _authreg_auth_get(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, attr; char username[1024], id[128]; int ar_mechs; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* sort out the username */ ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL); elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth get with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth get username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } ar_mechs = c2s->ar_mechanisms; if (sess->s->ssf>0) ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms; /* no point going on if we have no mechanisms */ if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) snprintf(id, 128, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); nad_free(nad); /* build a result packet */ nad = nad_new(); ns = nad_add_namespace(nad, uri_CLIENT, NULL); nad_append_elem(nad, ns, "iq", 0); nad_append_attr(nad, -1, "type", "result"); if(attr >= 0) nad_append_attr(nad, -1, "id", id); ns = nad_add_namespace(nad, uri_AUTH, NULL); nad_append_elem(nad, ns, "query", 1); nad_append_elem(nad, ns, "username", 2); nad_append_cdata(nad, username, strlen(username), 3); nad_append_elem(nad, ns, "resource", 2); /* fill out the packet with available auth mechanisms */ if(ar_mechs & AR_MECH_TRAD_PLAIN && (c2s->ar->get_password != NULL || c2s->ar->check_password != NULL)) nad_append_elem(nad, ns, "password", 2); if(ar_mechs & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL) nad_append_elem(nad, ns, "digest", 2); /* give it back to the client */ sx_nad_write(sess->s, nad); return; }
/** Send archiving preferences */ void send_arch_prefs(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int prefs; int archive=default_mode; int section; int check; char buff[2060]; // 2048 is jid_user maximum length char* ret_str=buff; os_t os = NULL; os_object_t o = NULL; pkt_t reply; // Create a new packet log_debug(ZONE, "Construction of reply with current settings"); reply = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); // Defaults log_debug(ZONE, "Getting defaults"); prefs = nad_append_elem(reply->nad, nad_add_namespace(reply->nad, archive_uri, NULL), "prefs", 2); // Load defaults snprintf(buff, 2060, "(jid=%s)", jid_user(sess->jid)); if((storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), buff, &os) == st_SUCCESS) && (os_iter_first(os)) && ((o=os_iter_object(os))!=NULL)) os_object_get_int(os, o, "setting", &archive); // Set defaults switch(archive) { case A_ALWAYS: nad_set_attr(reply->nad, prefs, -1,"default", "always", 6); break; case A_ROSTER: nad_set_attr(reply->nad, prefs, -1,"default", "roster", 6); break; default: nad_set_attr(reply->nad, prefs, -1,"default", "never", 5); break; } // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Always archiving log_debug(ZONE, "Getting what to archive always"); section = nad_append_elem(reply->nad, -1, "always", 3); if(storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), "(setting=1)", &os) == st_SUCCESS) if(os_iter_first(os)) do { o = os_iter_object(os); if((o != NULL) && (os_object_get_str(os, o, "jid", &ret_str)) && (ret_str != NULL)) { nad_append_elem(reply->nad, -1, "jid", 4); nad_append_cdata(reply->nad, ret_str, strlen(ret_str), 5); } } while(os_iter_next(os)); // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Never archiving log_debug(ZONE, "Getting what to never archive"); section = nad_append_elem(reply->nad, -1, "never", 3); if(storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), "(setting=0)", &os) == st_SUCCESS) if(os_iter_first(os)) do { o = os_iter_object(os); if((o != NULL) && (os_object_get_str(os, o, "jid", &ret_str)) && (ret_str != NULL)) { nad_append_elem(reply->nad, -1, "jid", 4); nad_append_cdata(reply->nad, ret_str, strlen(ret_str), 5); } } while(os_iter_next(os)); // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Send packet pkt_id(pkt, reply); pkt_sess(reply, sess); pkt_free(pkt); }
/** auth set handler */ static void _authreg_auth_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns, elem, attr, authd = 0; char username[1024], resource[1024], str[1024], hash[280]; int ar_mechs; /* can't auth if they're active */ if(sess->active) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL); /* sort out the username */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "auth set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "auth set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } /* make sure we have the resource */ elem = nad_find_elem(nad, 1, ns, "resource", 1); if(elem < 0) { log_debug(ZONE, "auth set with no resource, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(resource, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_resourceprep(resource, 1024) != 0) { log_debug(ZONE, "auth set resource failed resourceprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } ar_mechs = c2s->ar_mechanisms; if (sess->s->ssf > 0) ar_mechs = ar_mechs | c2s->ar_ssl_mechanisms; /* no point going on if we have no mechanisms */ if(!(ar_mechs & (AR_MECH_TRAD_PLAIN | AR_MECH_TRAD_DIGEST))) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_FORBIDDEN), 0)); return; } /* do we have the user? */ if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm) == 0) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } /* digest auth */ if(!authd && ar_mechs & AR_MECH_TRAD_DIGEST && c2s->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "digest", 1); if(elem >= 0) { if((c2s->ar->get_password)(c2s->ar, username, sess->host->realm, str) == 0) { snprintf(hash, 280, "%s%s", sess->s->id, str); shahash_r(hash, hash); if(strlen(hash) == NAD_CDATA_L(nad, elem) && strncmp(hash, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "digest auth succeeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.digest", username, resource, TRUE); } } } } /* plaintext auth (compare) */ if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && c2s->ar->get_password != NULL) { elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem >= 0) { if((c2s->ar->get_password)(c2s->ar, username, sess->host->realm, str) == 0 && strlen(str) == NAD_CDATA_L(nad, elem) && strncmp(str, NAD_CDATA(nad, elem), NAD_CDATA_L(nad, elem)) == 0) { log_debug(ZONE, "plaintext auth (compare) succeeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.plain(compare)", username, resource, TRUE); } } } /* plaintext auth (check) */ if(!authd && ar_mechs & AR_MECH_TRAD_PLAIN && c2s->ar->check_password != NULL) { elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem >= 0) { snprintf(str, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if((c2s->ar->check_password)(c2s->ar, username, sess->host->realm, str) == 0) { log_debug(ZONE, "plaintext auth (check) succeded"); authd = 1; _authreg_auth_log(c2s, sess, "traditional.plain", username, resource, TRUE); } } } /* now, are they authenticated? */ if(authd) { /* create new bound jid holder */ if(sess->resources == NULL) { sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); } /* our local id */ sprintf(sess->resources->c2s_id, "%d", sess->s->tag); /* the full user jid for this session */ sess->resources->jid = jid_new(sess->s->req_to, -1); jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, resource); log_write(sess->c2s->log, LOG_NOTICE, "[%d] requesting session: jid=%s", sess->s->tag, jid_full(sess->resources->jid)); /* build a result packet, we'll send this back to the client after we have a session for them */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* start a session with the sm */ sm_start(sess, sess->resources); /* finished with the nad */ nad_free(nad); return; } _authreg_auth_log(c2s, sess, "traditional", username, resource, FALSE); /* auth failed, so error */ sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; }
/** sx features callback */ static void _sx_ack_features(sx_t s, sx_plugin_t p, nad_t nad) { /* offer feature only when authenticated and not enabled yet */ if(s->state == state_OPEN && s->plugin_data[p->index] == NULL) nad_append_elem(nad, -1, "ack:ack", 1); }
static void _nad_parse_element_start(void *arg, const char *name, const char **atts) { struct build_data *bd = (struct build_data *) arg; char buf[1024]; char *uri, *elem, *prefix; const char **attr; int el, ns; /* make a copy */ strncpy(buf, name, 1024); buf[1023] = '\0'; /* expat gives us: prefixed namespaced elem: uri|elem|prefix default namespaced elem: uri|elem un-namespaced elem: elem */ /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_add_namespace(bd->nad, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ el = nad_append_elem(bd->nad, ns, elem, bd->depth); /* now the attributes, one at a time */ attr = atts; while(attr[0] != NULL) { /* make a copy */ strncpy(buf, attr[0], 1024); buf[1023] = '\0'; /* extract all the bits */ uri = buf; elem = strchr(uri, '|'); if(elem != NULL) { *elem = '\0'; elem++; prefix = strchr(elem, '|'); if(prefix != NULL) { *prefix = '\0'; prefix++; } ns = nad_append_namespace(bd->nad, el, uri, prefix); } else { /* un-namespaced, just take it as-is */ uri = NULL; elem = buf; prefix = NULL; ns = -1; } /* add it */ nad_append_attr(bd->nad, ns, elem, (char *) attr[1]); attr += 2; } bd->depth++; }
/** register set handler */ static void _authreg_register_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns = 0, elem, attr; char username[1024], password[1024]; /* if we're not configured for registration (or pw changes), or we can't set passwords, fail outright */ if(!(sess->host->ar_register_enable || sess->host->ar_register_password) || c2s->ar->set_password == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL); /* removals */ if(sess->active && nad_find_elem(nad, 1, ns, "remove", 1) >= 0) { /* only if full reg is enabled */ if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } log_debug(ZONE, "user remove requested"); /* make sure we can delete them */ if(c2s->ar->delete_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, delete them */ if((c2s->ar->delete_user)(c2s->ar, sess->resources->jid->node, sess->host->realm) != 0) { log_debug(ZONE, "user delete failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_write(c2s->log, LOG_NOTICE, "[%d] deleted user: user=%s; realm=%s", sess->s->tag, sess->resources->jid->node, sess->host->realm); log_write(c2s->log, LOG_NOTICE, "[%d] registration remove succeeded, requesting user deletion: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); nad_free(nad); sx_nad_write(sess->s, sess->result); sess->result = NULL; /* get the sm to delete them (it will force their sessions to end) */ sm_delete(sess, sess->resources); return; } /* username is required */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "register set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "register set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem < 0) { log_debug(ZONE, "register set with no password, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } /* if they're already auth'd, its a password change */ if(sess->active) { /* confirm that the username matches their auth id */ if(strcmp(username, sess->resources->jid->node) != 0) { log_debug(ZONE, "%s is trying to change password for %s, bouncing it", jid_full(sess->resources->jid), username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } } /* can't go on if we're not doing full reg */ else if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* if they exist, bounce */ else if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm)) { log_debug(ZONE, "attempt to register %s, but they already exist", username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_CONFLICT), 0)); return; } /* make sure we can create them */ else if(c2s->ar->create_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, create them */ else if((c2s->ar->create_user)(c2s->ar, username, sess->host->realm) != 0) { log_debug(ZONE, "user create failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } else log_write(c2s->log, LOG_NOTICE, "[%d] created user: user=%s; realm=%s", sess->s->tag, username, sess->host->realm); /* extract the password */ snprintf(password, 257, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); /* change it */ if((c2s->ar->set_password)(c2s->ar, username, sess->host->realm, password) != 0) { log_debug(ZONE, "password store failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_debug(ZONE, "updated auth creds for %s", username); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* if they're active, then this was just a password change, and we're done */ if(sess->active) { log_write(c2s->log, LOG_NOTICE, "[%d] password changed: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); sx_nad_write(sess->s, sess->result); sess->result = NULL; return; } /* create new bound jid holder */ if(sess->resources == NULL) { sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); } /* our local id */ sprintf(sess->resources->c2s_id, "%d", sess->s->tag); /* the user jid for this transaction */ sess->resources->jid = jid_new(sess->s->req_to, -1); jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, sess->resources->jid->resource); log_write(c2s->log, LOG_NOTICE, "[%d] registration succeeded, requesting user creation: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* get the sm to create them */ sm_create(sess, sess->resources); nad_free(nad); return; }