mreturn mod_roster_auto_in_s10n(mapi m, void *arg) { xmlnode reply, x; log_debug("AUTO ROSTER"); //in not s10n if (m->packet->type != JPACKET_S10N) return M_IGNORE; //if no to if (m->packet->to == NULL) return M_PASS; //if from me if (jid_cmpx(m->s->uid, m->packet->from, JID_USER | JID_SERVER) == 0) return M_PASS; log_debug("handling incoming s10n"); switch (jpacket_subtype(m->packet)) { case JPACKET__SUBSCRIBE: log_debug("SUBSCRIBE"); reply = jutil_presnew(JPACKET__SUBSCRIBED, jid_full(m->packet->from), NULL); js_session_from(m->s, jpacket_new(reply)); reply = jutil_presnew(JPACKET__SUBSCRIBE, jid_full(m->packet->from), NULL); js_session_from(m->s, jpacket_new(reply)); break; case JPACKET__SUBSCRIBED: break; case JPACKET__UNSUBSCRIBE: log_debug("UNSUBSCRIBE"); //reply = jutil_presnew(JPACKET__UNSUBSCRIBED, jid_full(m->packet->from),NULL); //js_session_from(m->s, jpacket_new(reply)); //remove account. reply = jutil_iqnew(JPACKET__SET, NS_ROSTER); x = xmlnode_get_tag(reply, "query"); x = xmlnode_insert_tag(x, "item"); xmlnode_put_attrib(x, "jid", jid_full(jid_user(m->packet->from))); xmlnode_put_attrib(x, "subscription", "remove"); js_session_from(m->s, jpacket_new(reply)); // reply = jutil_iqnewpresnew(JPACKET__UNSUBSCRIBE, jid_full(m->packet->from),NULL); // js_session_from(m->s, jpacket_new(reply)); break; case JPACKET__UNSUBSCRIBED: break; } xmlnode_free(m->packet->x); return M_HANDLED; }
/* session thread */ mreturn mod_presence_in(mapi m, void *arg) { modpres mp = (modpres) arg; xmlnode pres; if (m->packet->type != JPACKET_PRESENCE) return M_IGNORE; log_debug("incoming filter for %s", jid_full(m->s->id)); if (jpacket_subtype(m->packet) == JPACKET__PROBE) { /* reply with our presence */ if (m->s->presence == NULL) { log_debug("probe from %s and no presence to return", jid_full(m->packet->from)); } else if (!mp->invisible && js_trust(m->user, m->packet->from) && !_mod_presence_search(m->packet->from, mp->I)) { /* compliment of I in T */ log_debug("got a probe, responding to %s", jid_full(m->packet->from)); pres = xmlnode_dup(m->s->presence); xmlnode_put_attrib(pres, "to", jid_full(m->packet->from)); js_session_from(m->s, jpacket_new(pres)); } else if (mp->invisible && js_trust(m->user, m->packet->from) && _mod_presence_search(m->packet->from, mp->A)) { /* when invisible, intersection of A and T */ log_debug("got a probe when invisible, responding to %s", jid_full(m->packet->from)); pres = jutil_presnew(JPACKET__AVAILABLE, jid_full(m->packet->from), NULL); js_session_from(m->s, jpacket_new(pres)); } else { log_debug("%s attempted to probe by someone not qualified", jid_full(m->packet->from)); } xmlnode_free(m->packet->x); return M_HANDLED; } if (jid_cmp(m->packet->from, m->s->id) == 0) { /* this is our presence, don't send to ourselves */ xmlnode_free(m->packet->x); return M_HANDLED; } /* if a presence packet bounced, remove from the A list */ if (jpacket_subtype(m->packet) == JPACKET__ERROR) mp->A = _mod_presence_whack(m->packet->from, mp->A); /* doh! this is a user, they should see invisibles as unavailables */ if (jpacket_subtype(m->packet) == JPACKET__INVISIBLE) xmlnode_put_attrib(m->packet->x, "type", "unavailable"); return M_PASS; }
/* handle a packet from jabberd */ result at_phandler(instance i,dpacket p,void *arg) { int ret; ati ti; at_mtq_data amd; if(i == NULL || p == NULL) return r_ERR; ti = (ati)arg; switch(p->type) { case p_NONE: case p_NORM: log_debug(ZONE, "[AT] we got a packet from jabberd: %s", xmlnode2str(p->x)); amd = pmalloco(p->p, sizeof(_at_mtq_data)); amd->jp = jpacket_new(p->x); amd->p = p->p; amd->ti = ti; mtq_send(NULL, p->p, at_parse_packet, (void *)amd); return r_DONE; default: log_debug(ZONE, "[AT] ignoring packet from jabberd: %s", xmlnode2str(p->x)); return r_PASS; } }
/* thread safe with sem */ mreturn mod_presence_deliver(mapi m, void *arg) { session cur; if (m->packet->type != JPACKET_PRESENCE) return M_IGNORE; log_debug("deliver phase"); /* only if we HAVE a user, and it was sent to ONLY the user@server, and there is at least one session available */ if (m->user != NULL && m->packet->to->resource == NULL && js_session_primary_all_sem(m->user) != NULL) { log_debug("broadcasting to %s", m->user->user); /* broadcast */ for (cur = m->user->sessions; cur != NULL; cur = cur->next) { if (cur->priority < -128) continue; js_session_to(cur, jpacket_new(xmlnode_dup(m->packet->x))); } SEM_UNLOCK(m->user->sem); if (jpacket_subtype(m->packet) != JPACKET__PROBE) { /* probes get handled by the offline thread as well? */ xmlnode_free(m->packet->x); return M_HANDLED; } } return M_PASS; }
void _mod_presence_broadcast_trusted(session s, jid notify, xmlnode x) { jid cur; xmlnode pres; for (cur = notify; cur != NULL; cur = cur->next) { if (!js_istrusted(s->u, cur)) continue; /* perform insersection search, must be in both */ s->c_out++; pres = xmlnode_dup(x); xmlnode_put_attrib(pres, "to", jid_full(cur)); /* send it to POSTOUT for filter purposes */ js_post_out_main(s, jpacket_new(pres)); } }
result mt_receive(instance i, dpacket d, void *arg) { jpacket jp; mti ti; session s; switch(d->type) { case p_NONE: case p_NORM: jp = jpacket_new(d->x); if (jp->from && jp->from->user && jp->type != JPACKET_UNKNOWN && jpacket_subtype(jp) != JPACKET__ERROR) { mti ti = (mti) arg; session s = mt_session_find(ti,jp->from); lowercase(jp->from->server); lowercase(jp->from->user); if (s != NULL) mt_session_process(s,jp); else mt_unknown_process(ti,jp); } else { log_warn(NULL,"Invalid packet"); xmlnode_free(d->x); } break; default: return r_ERR; } return r_DONE; }
/* any thread */ result js_packet(instance i, dpacket p, void *arg) { jsmi si = (jsmi) arg; jpacket jp = NULL; session s = NULL; packet_thread_p pt; udata u; char *type, *authto; log_debug("incoming packet %s", xmlnode2str(p->x)); /* if this is a routed packet */ if (p->type == p_ROUTE) { type = xmlnode_get_attrib(p->x, "type"); /* new session requests */ if (j_strcmp(type, "session") == 0) { js_session_new_mtq(si, p); return r_DONE; } /* get the internal jpacket */ if (xmlnode_get_firstchild(p->x) != NULL) /* XXX old libjabber jpacket_new() wasn't null safe, this is just safety */ jp = jpacket_new(xmlnode_get_firstchild(p->x)); /* auth/reg requests */ if (jp != NULL && j_strcmp(type, "auth") == 0) { /* check and see if we're configured to forward auth packets for processing elsewhere */ if ((authto = xmlnode_get_data(js_config(si, "auth"))) != NULL) { xmlnode_put_attrib(p->x, "oto", xmlnode_get_attrib(p->x, "to")); /* preserve original to */ xmlnode_put_attrib(p->x, "to", authto); deliver(dpacket_new(p->x), i); return r_DONE; } /* internally, hide the route to/from addresses on the authreg request */ xmlnode_put_attrib(jp->x, "to", xmlnode_get_attrib(p->x, "to")); xmlnode_put_attrib(jp->x, "from", xmlnode_get_attrib(p->x, "from")); xmlnode_put_attrib(jp->x, "route", xmlnode_get_attrib(p->x, "type")); jpacket_reset(jp); jp->aux1 = (void *) si; pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_authreg, pt); return r_DONE; } /* if it's an error */ if (j_strcmp(type, "error") == 0) { /* look for users online */ u = js_user(si, p->id, 1); if (u == NULL) { /* if this was a message, it should have been delievered to that session, store offline */ if (jp != NULL && jp->type == JPACKET_MESSAGE) { pt = pmalloco(jp->p, sizeof (packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } xmlnode_free(p->x); return r_DONE; /* log_notice(p->host, "Bouncing packet intended for nonexistant user: %s", xmlnode2str(p->x)); deliver_fail(dpacket_new(p->x), "Invalid User"); return r_DONE; */ } if (p->id->resource != NULL) { SEM_LOCK(u->sem); for (s = u->sessions; s != NULL; s = s->next) if (j_strcmp (p->id->resource, s->route->resource) == 0) break; SEM_UNLOCK(u->sem); if (s != NULL) { s->sid = NULL; /* they generated the error, no use in sending there anymore! */ js_session_end(s, "Disconnected"); } } else { session temp; /* a way to boot an entire user off */ SEM_LOCK(u->sem); for (s = u->sessions; s != NULL;) { temp = s; s = s->next; js_session_end_nosem(temp, "Removed"); } u->pass = NULL; /* so they can't log back in */ SEM_UNLOCK(u->sem); xmlnode_free(p->x); THREAD_DEC(u->ref); return r_DONE; } THREAD_DEC(u->ref); /* if this was a message, it should have been delievered to that session, store offline */ if (jp != NULL && jp->type == JPACKET_MESSAGE) { pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } /* drop and return */ if (xmlnode_get_firstchild(p->x) != NULL) log_notice(p->host, "Dropping a bounced session packet to %s", jid_full(p->id)); xmlnode_free(p->x); return r_DONE; } /* uhh, empty packet, *shrug* */ if (jp == NULL) { log_notice(p->host, "Dropping an invalid or empty route packet: %s", xmlnode2str(p->x), jid_full(p->id)); xmlnode_free(p->x); return r_DONE; } /* ============================================================== */ /* attempt to locate the session by matching the special resource */ u = js_user(si, p->id, 1); if (u == NULL) { /* only when route packet to users not online */ pt = pmalloco(p->p, sizeof(packet_thread_t)); pt->p = p; pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; } /* user is online :) */ SEM_LOCK(u->sem); for (s = u->sessions; s != NULL; s = s->next) if (j_strcmp(p->id->resource, s->route->resource) == 0) break; SEM_UNLOCK(u->sem); THREAD_DEC(u->ref); if (s != NULL) { /* just pass to the session normally */ js_session_from(s, jp); return r_DONE; } log_notice(p->host, "Bouncing %s packet intended for session %s", xmlnode_get_name(jp->x), jid_full(p->id)); deliver_fail(dpacket_new(p->x), "Invalid Session"); return r_DONE; } /* normal server-server packet, should we make sure it's not spoofing us? if so, if ghash_get(p->to->server) then bounce w/ security error */ jp = jpacket_new(p->x); if (jp == NULL) { log_warn(p->host, "Dropping invalid incoming packet: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } pt = pmalloco(jp->p, sizeof(packet_thread_t)); pt->jp = jp; fast_mtq_send(si->mtq_deliver, pt); return r_DONE; }
/** Callback processing incoming Jabber packets. */ result it_receive(instance i, dpacket d, void *arg) { iti ti = (iti) arg; jpacket jp; session s; session_ref alt_s; unsigned char *user; log_debug(ti->i->id,"Packet received: %s\n",xmlnode2str(d->x)); switch(d->type) { case p_ROUTE: { /* ignore */ return r_PASS; } case p_NONE: case p_NORM: jp = jpacket_new(d->x); break; default: return r_ERR; } if (!jp->from ||/* !jp->from->user ||*/ jp->type == JPACKET_UNKNOWN /* || jpacket_subtype(jp) == JPACKET__ERROR */) { /* ignore invalid packets */ xmlnode_free(jp->x); return r_DONE; } /* JID user part should be case insensitive */ /* convert user part of from JID to lower case */ if(jp->from->user != NULL) for(user = jp->from->user; *user != '\0'; user++) if(*user < 128) *user = tolower(*user); /* Mangle "from" JID, save original attribute for XDB conversion */ xmlnode_put_attrib(jp->x, "origfrom", xmlnode_get_attrib(jp->x, "from")); xmlnode_put_attrib(jp->x, "from", jid_full(jp->from)); SEM_LOCK(ti->sessions_sem); s = (session) wpxhash_get(ti->sessions,jid_full(jid_user(jp->from))); alt_s = (session_ref) wpxhash_get(ti->sessions_alt,jp->to->user); if (s != NULL) { if (s->exit_flag) { SEM_UNLOCK(ti->sessions_sem); log_alert("exit flag","message to exiting session"); if (jp->type != JPACKET_PRESENCE){ jutil_error(jp->x,TERROR_NOTFOUND); it_deliver(ti,jp->x); } else xmlnode_free(jp->x); } else if ((alt_s != NULL) && ( (jp->type == JPACKET_MESSAGE) // all messages || ((jp->type == JPACKET_IQ) && (j_strcmp(xmlnode_get_attrib(jp->iq,"xmlns"),NS_VCARD) == -1)) // all IQs except of vCard || (jp->type == JPACKET_PRESENCE) )) { // all presences _targeted_to_specific_user_ // rewriting "to" and "from" and putting packet back on the wire xmlnode_put_attrib(jp->x, "from", jid_full(it_uin2jid(jp->p,s->uin,jp->to->server))); xmlnode_put_attrib(jp->x, "to", jid_full(alt_s->s->orgid)); SEM_UNLOCK(ti->sessions_sem); it_deliver(ti,jp->x); } else { jp->aux1 = (void *) s; mtq_send(s->q,jp->p,it_session_jpacket,(void *) jp); SEM_UNLOCK(ti->sessions_sem); } } else { SEM_UNLOCK(ti->sessions_sem); if(jpacket_subtype(jp)!=JPACKET__ERROR) it_unknown(ti,jp); else xmlnode_free(jp->x); } return r_DONE; }
/* session thread */ mreturn mod_presence_out(mapi m, void *arg) { xmlnode pnew, delay, pold; modpres mp = (modpres) arg; session cur = NULL; int oldpri, newpri; char *priority; if (m->packet->type != JPACKET_PRESENCE) return M_IGNORE; if (m->packet->to != NULL || jpacket_subtype(m->packet) == JPACKET__PROBE || jpacket_subtype(m->packet) == JPACKET__ERROR) return M_PASS; log_debug("new presence from %s of %s", jid_full(m->s->id), xmlnode2str(m->packet->x)); /* pre-existing conditions (no, we are not an insurance company) */ oldpri = m->s->priority; /* check that the priority is in the valid range */ priority = xmlnode_get_tag_data(m->packet->x, "priority"); if (priority == NULL) { newpri = 0; } else { newpri = j_atoi(priority, 0); if (newpri < -128 || newpri > 127) { log_notice("mod_presence", "got presence with invalid priority value from %s", jid_full(m->s->id)); xmlnode_free(m->packet->x); return M_HANDLED; } } /* invisible mode is special, don't you wish you were special too? */ if (jpacket_subtype(m->packet) == JPACKET__INVISIBLE) { log_debug("handling invisible mode request"); /* if we get this and we're available, it means go unavail first then reprocess this packet, nifty trick :) */ if (oldpri >= -128) { js_session_from(m->s, jpacket_new(jutil_presnew (JPACKET__UNAVAILABLE, NULL, xmlnode_get_tag_data(m->packet->x,"status") ))); js_session_from(m->s, m->packet); return M_HANDLED; } /* now, pretend we come online :) */ /* (this is the handling of the reinjected invisible presence * or an initial invisible presence) */ mp->invisible = 1; mod_presence_roster(m, NULL); /* send out probes to users we are subscribed to */ m->s->priority = newpri; /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); xmlnode_free(m->packet->x); /* we do not broadcast invisible presences without a to attribute */ return M_HANDLED; } /* our new presence */ pnew = xmlnode_dup(m->packet->x); /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); /* stamp the sessions presence */ delay = xmlnode_insert_tag(pnew, "x"); xmlnode_put_attrib(delay, "xmlns", NS_DELAY); xmlnode_put_attrib(delay, "from", jid_full(m->s->id)); xmlnode_put_attrib(delay, "stamp", jutil_timestamp()); /* our old presence */ pold = m->s->presence; m->s->presence = pnew; m->s->priority = jutil_priority(pnew); log_debug("presence oldp %d newp %d", oldpri, m->s->priority); /* if we're going offline now, let everyone know */ if (m->s->priority < -128) { /* jutil_priority returns -129 in case the "type" attribute is missing */ if (!mp->invisible) /* bcc's don't get told if we were invisible */ _mod_presence_broadcast(m->s, mp->conf->bcc, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->A, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->I, m->packet->x, NULL); /* reset vars */ mp->invisible = 0; mp->A->next = NULL; mp->I = NULL; xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; } /* available presence updates, intersection of A and T */ if (oldpri >= -128 && !mp->invisible) { _mod_presence_broadcast_trusted(m->s, mp->A, m->packet->x); xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; } /* at this point we're coming out of the closet */ mp->invisible = 0; /* make sure we get notified for any presence about ourselves */ /* XXX: the following is the original code: it caused existing presences * to be stamped several times and the presence to be sent out twice. pnew = jutil_presnew(JPACKET__PROBE,jid_full(m->s->uid),NULL); xmlnode_put_attrib(pnew,"from",jid_full(m->s->uid)); js_session_from(m->s, jpacket_new(pnew)); */ /* XXX: I think this should be okay as well: */ /* send us all presences of our other resources */ for (cur = m->user->sessions; cur != NULL; cur = cur->next) { pool pool_for_existing_presence = NULL; xmlnode duplicated_presence = NULL; jpacket packet = NULL; /* skip our own session (and sanity check) */ if (cur == m->s || cur->presence == NULL) { continue; } /* send the presence to us: we need a new pool as js_session_to() will free the packet's pool */ pool_for_existing_presence = pool_new(); duplicated_presence = xmlnode_dup_pool(pool_for_existing_presence, cur->presence); xmlnode_put_attrib(duplicated_presence, "to", jid_full(m->user->id)); packet = jpacket_new(duplicated_presence); js_session_to(m->s, packet); } /* probe s10ns and populate A */ mod_presence_roster(m, mp->A); /* we broadcast this baby! */ _mod_presence_broadcast(m->s, mp->conf->bcc, m->packet->x, NULL); _mod_presence_broadcast(m->s, mp->A, m->packet->x, NULL); xmlnode_free(m->packet->x); xmlnode_free(pold); return M_HANDLED; }