/** do stringprep on the pieces */ static int jid_prep_pieces(char *node, char *domain, char *resource) { if(node[0] != '\0') if(stringprep_xmpp_nodeprep(node, 1024) != 0) return 1; if(stringprep_nameprep(domain, 1024) != 0) return 1; if(resource[0] != '\0') if(stringprep_xmpp_resourceprep(resource, 1024) != 0) return 1; return 0; }
char * jid_normalized(const char *jid,int full){ int i,at,slash,ret; char node[1024],domain[1024],resource[1024]; char *domainbuf; if (!jid) return NULL; slash=-1; at=-1; /* split into parts */ for(i=0;jid[i];i++){ if (jid[i]=='@' && at<0) at=i; if (jid[i]=='/' && slash<0) slash=i; } if (slash>=0 && slash<at){ g_warning(N_("slash<at (%i<%i) in %s"),slash,at,jid); return NULL; } if (slash==at+1){ g_warning(N_("empty domain in %s"),jid); return NULL; } /* node */ if (at>0){ if (at>1023){ g_warning(N_("node too long in %s"),jid); return NULL; } memcpy(node,jid,at); node[at]='\000'; } else node[0]='\000'; /* domain */ if (slash>0){ if (slash-at>1024){ g_warning(N_("domain too long in %s"),jid); return NULL; } memcpy(domain,jid+at+1,slash-at-1); domain[slash-at-1]='\000'; } else{ if (strlen(jid+at+1)>1023){ g_warning(N_("domain too long in %s"),jid); return NULL; } strcpy(domain,jid+at+1); } /* resource */ if (slash>0){ if (strlen(jid+slash+1)>1023){ g_warning(N_("resource too long in %s"),jid); return NULL; } strcpy(resource,jid+slash+1); } else resource[0]='\000'; if (node[0]){ ret=stringprep_xmpp_nodeprep(node,1024); if (ret!=0){ g_warning(N_("bad node: %s"),node); return NULL; } } if (resource[0]){ ret=stringprep_xmpp_resourceprep(resource,1024); if (ret!=0){ g_warning(N_("bad node: %s"),resource); return NULL; } } ret=idna_to_unicode_8z8z(domain,&domainbuf,IDNA_ALLOW_UNASSIGNED); if (ret!=IDNA_SUCCESS){ g_warning(N_("bad domain: %s"),domain); return NULL; } strcpy(domain,domainbuf); g_free(domainbuf); if (!full || !resource[0]){ if (node[0]) return g_strconcat(node,"@",domain,NULL); else return g_strdup(domain); } else{ if (node[0]) return g_strconcat(node,"@",domain,"/",resource,NULL); else return g_strconcat(domain,"/",resource,NULL); } }
/** 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; }
static gboolean jabber_resourceprep(char *str, size_t buflen) { return stringprep_xmpp_resourceprep(str, buflen) == STRINGPREP_OK; }