/** generate a new session request id */ static void _sm_generate_id(sess_t sess, bres_t res, const char *type) { char str[3094]; /* JID=3071 chars max + time = 12 chars max + type = 10 chars max + terminator = 3094 */ snprintf(str, 3094, "%s%d%s", type, (int) time(NULL), jid_full(res->jid)); str[3093] = '\0'; shahash_r(str, res->sm_request); }
static void _router_process_handshake(component_t comp, nad_t nad) { char *hash; int hashlen; /* must have a hash as cdata */ if(NAD_CDATA_L(nad, 0) != 40) { log_debug(ZONE, "handshake isn't long enough to be a sha1 hash"); sx_error(comp->s, stream_err_NOT_AUTHORIZED, "handshake isn't long enough to be a sha1 hash"); sx_close(comp->s); nad_free(nad); return; } /* make room for shahash_r to work .. needs at least 41 chars */ hashlen = strlen(comp->s->id) + strlen(comp->r->local_secret) + 1; if(hashlen < 41) hashlen = 41; /* build the creds and hash them */ hash = (char *) malloc(sizeof(char) * hashlen); sprintf(hash, "%s%s", comp->s->id, comp->r->local_secret); shahash_r(hash, hash); /* check */ log_debug(ZONE, "checking their hash %.*s against our hash %s", 40, NAD_CDATA(nad, 0), hash); if(strncmp(hash, NAD_CDATA(nad, 0), 40) == 0) { log_debug(ZONE, "handshake succeeded"); free(hash); /* respond */ nad->elems[0].icdata = nad->elems[0].itail = -1; nad->elems[0].lcdata = nad->elems[0].ltail = 0; sx_nad_write(comp->s, nad); sx_auth(comp->s, "handshake", comp->s->req_to); return; } log_debug(ZONE, "auth failed"); free(hash); /* failed, let them know */ sx_error(comp->s, stream_err_NOT_AUTHORIZED, "hash didn't match, auth failed"); sx_close(comp->s); nad_free(nad); }
void jabber_stream_start(Stream *s,xmlnode x){ char hashbuf[50]; char *str; xmlnode tag; if (jabber_state!=JS_NONE){ g_warning(N_("unexpected <stream:stream/>")); return; } stream_id=xmlnode_get_attrib(x,"id"); str=g_strdup_printf("%s%s",stream_id,secret); shahash_r(str,hashbuf); g_free(str); tag=xmlnode_new_tag("handshake"); xmlnode_insert_cdata(tag,hashbuf,-1); stream_write(s,tag); xmlnode_free(tag); jabber_state=JS_HANDSHAKE; }
/** * 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; }
/** 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; }