/** 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); }
/** validate their key */ static void _in_verify(conn_t in, nad_t nad) { int attr; jid_t from, to; char *id, *dbkey, *type; 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 verify 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 verify packet"); jid_free(from); nad_free(nad); return; } attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr < 0) { log_debug(ZONE, "missing id on db verify packet"); jid_free(from); jid_free(to); nad_free(nad); return; } if(NAD_CDATA_L(nad, 0) <= 0) { log_debug(ZONE, "no cdata on db verify packet"); jid_free(from); jid_free(to); nad_free(nad); return; } /* extract the id */ id = (char *) malloc(sizeof(char) * (NAD_AVAL_L(nad, attr) + 1)); snprintf(id, NAD_AVAL_L(nad, attr) + 1, "%.*s", NAD_AVAL_L(nad, attr), NAD_AVAL(nad, attr)); /* generate a dialback key */ dbkey = s2s_db_key(NULL, in->s2s->local_secret, from->domain, id); /* valid */ if(NAD_CDATA_L(nad, 0) == strlen(dbkey) && strncmp(dbkey, NAD_CDATA(nad, 0), NAD_CDATA_L(nad, 0)) == 0) { log_debug(ZONE, "valid dialback key %s, verify succeeded", dbkey); type = "valid"; } else { log_debug(ZONE, "invalid dialback key %s, verify failed", dbkey); type = "invalid"; } log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] checking dialback verification from %s: sending %s", in->fd->fd, in->ip, in->port, from->domain, type); log_debug(ZONE, "letting them know"); /* now munge the packet and send it back to them */ stanza_tofrom(nad, 0); nad_set_attr(nad, 0, -1, "type", type, 0); 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(dbkey); free(id); jid_free(from); jid_free(to); return; }
/** 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 mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) { sm_t sm = mi->mod->mm->sm; int ns, iq, elem, attr; jid_t jid; sess_t sess = (sess_t) NULL; mod_ret_t ret; /* if we've got this namespace, its from a c2s */ if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0) return mod_PASS; /* don't bother if its a failure */ if(pkt->type & pkt_SESS_FAILED) { /* !!! check failed=1, handle */ pkt_free(pkt); return mod_HANDLED; } /* session commands */ if(pkt->type & pkt_SESS) { ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL); /* only end can get away without a target */ attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL); if(attr < 0 && pkt->type != pkt_SESS_END) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* session start */ if(pkt->type == pkt_SESS) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid != NULL) sess = sess_start(sm, jid); if(jid == NULL || sess == NULL) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); if(jid != NULL) jid_free(jid); return mod_HANDLED; } /* c2s component that is handling this session */ strcpy(sess->c2s, pkt->rfrom->domain); /* remember what c2s calls us */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); /* mark PBX session as fake */ if(!strncmp("PBX", sess->c2s_id, 3)) { sess->fake = 1; } /* add our id */ nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0); /* mark that it started OK */ nad_set_attr(pkt->nad, 1, -1, "action", "started", 7); /* set this SM name */ nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0); /* inform c2s */ sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* user create */ if(pkt->type == pkt_SESS_CREATE) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL || user_create(sm, jid) != 0) { nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); if(jid != NULL) jid_free(jid); return mod_HANDLED; } /* inform c2s */ nad_set_attr(pkt->nad, 1, -1, "action", "created", 7); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* user delete */ if(pkt->type == pkt_SESS_DELETE) { jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); if(jid == NULL) { pkt_free(pkt); return mod_HANDLED; } user_delete(sm, jid); /* inform c2s */ nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); jid_free(jid); return mod_HANDLED; } /* get the session id */ attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); if(attr < 0) { log_debug(ZONE, "no session id, bouncing"); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* find the corresponding session */ sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); /* active check */ if(sess == NULL) { log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* make sure its from them */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id); pkt_free(pkt); return mod_HANDLED; } /* session end */ if(pkt->type == pkt_SESS_END) { sm_c2s_action(sess, "ended", NULL); sess_end(sess); pkt_free(pkt); return mod_HANDLED; } log_debug(ZONE, "unknown session packet, dropping"); pkt_free(pkt); return mod_HANDLED; } /* otherwise, its a normal packet for the session */ /* #ifdef ENABLE_SUPERSEDED // FIXME XXX TODO clients are not yet ready for this */ /* check for RFC3920 session request * * with RFC3920bis it is unneeded * * session is activated by bind, so we just return back result */ if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 && (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 && (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) { log_debug(ZONE, "session create request"); /* build a result packet */ nad_drop_elem(pkt->nad, elem); nad_set_attr(pkt->nad, iq, -1, "type", "result", 6); /* return the result */ sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* #endif */ /* get the session id */ attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL); if(attr < 0) { log_debug(ZONE, "no session id, bouncing"); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* find the corresponding session */ sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)); /* active check */ if(sess == NULL) { log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1); sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0)); pkt->nad = NULL; pkt_free(pkt); return mod_HANDLED; } /* make sure its from them */ attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL); if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) { log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id); pkt_free(pkt); return mod_HANDLED; } /* where it came from */ pkt->source = sess; /* hand it to the modules */ ret = mm_in_sess(pkt->sm->mm, sess, pkt); switch(ret) { case mod_HANDLED: break; case mod_PASS: /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */ if(pkt->type == pkt_IQ_RESULT) break; else ret = -stanza_err_FEATURE_NOT_IMPLEMENTED; default: pkt_sess(pkt_error(pkt, -ret), sess); break; } return mod_HANDLED; }
/** * processor for iq:auth and iq:register packets * return 0 if handled, 1 if not handled */ int authreg_process(c2s_t c2s, sess_t sess, nad_t nad) { int ns, query, type, authreg = -1, getset = -1; /* need iq */ if(NAD_ENAME_L(nad, 0) != 2 || strncmp("iq", NAD_ENAME(nad, 0), 2) != 0) return 1; /* only want auth or register packets */ if((ns = nad_find_scoped_namespace(nad, uri_AUTH, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0) authreg = 0; else if((ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL)) >= 0 && (query = nad_find_elem(nad, 0, ns, "query", 1)) >= 0) authreg = 1; else return 1; /* if its to someone else, pass it */ if(nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "to", sess->s->req_to) < 0) return 1; /* need a type */ if((type = nad_find_attr(nad, 0, -1, "type", NULL)) < 0 || NAD_AVAL_L(nad, type) != 3) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return 0; } /* get or set? */ if(strncmp("get", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0) getset = 0; else if(strncmp("set", NAD_AVAL(nad, type), NAD_AVAL_L(nad, type)) == 0) getset = 1; else { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return 0; } /* hand to the correct handler */ if(authreg == 0) { /* can't do iq:auth after sasl auth */ if(sess->sasl_authd) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return 0; } if(getset == 0) { log_debug(ZONE, "auth get"); _authreg_auth_get(c2s, sess, nad); } else if(getset == 1) { log_debug(ZONE, "auth set"); _authreg_auth_set(c2s, sess, nad); } } if(authreg == 1) { if(getset == 0) { log_debug(ZONE, "register get"); _authreg_register_get(c2s, sess, nad); } else if(getset == 1) { log_debug(ZONE, "register set"); _authreg_register_set(c2s, sess, nad); } } /* handled */ return 0; }
/** 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; }
/** 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; }
/** 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; }