#include "dialback.h"
typedef struct dbic_struct
{
mio m;
char *id;
xmlnode results;
db d;
} *dbic, _dbic;
void dialback_in_dbic_cleanup(void *arg)
{
dbic c = (dbic)arg;
if(ghash_get(c->d->in_id,c->id) == c)
ghash_remove(c->d->in_id,c->id);
}
dbic dialback_in_dbic_new(db d, mio m)
{
dbic c;
c = pmalloco(m->p, sizeof(_dbic));
c->m = m;
c->id = pstrdup(m->p,dialback_randstr());
c->results = xmlnode_new_tag_pool(m->p,"r");
c->d = d;
pool_cleanup(m->p,dialback_in_dbic_cleanup, (void *)c);
ghash_put(d->in_id, c->id, (void *)c);
log_debug(ZONE,"created incoming connection %s from %s",c->id,m->ip);
return c;
}
void dialback_in_read_db(mio m, int flags, void *arg, xmlnode x)
{
dbic c = (dbic)arg;
miod md;
jid key, from;
xmlnode x2;
if(flags != MIO_XML_NODE) return;
log_debug(ZONE,"dbin read dialback: fd %d packet %s",m->fd, xmlnode2str(x));
if(j_strcmp(xmlnode_get_name(x),"db:verify") == 0)
{
if(j_strcmp( xmlnode_get_data(x), dialback_merlin(xmlnode_pool(x), c->d->secret, xmlnode_get_attrib(x,"from"), xmlnode_get_attrib(x,"id"))) == 0)
xmlnode_put_attrib(x,"type","valid");
else
xmlnode_put_attrib(x,"type","invalid");
jutil_tofrom(x);
while((x2 = xmlnode_get_firstchild(x)) != NULL)
xmlnode_hide(x2);
mio_write(m, x, NULL, 0);
return;
}
if((from = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"from"))) == NULL || (key = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"to"))) == NULL)
{
mio_write(m, NULL, "<stream:error>Invalid Packets Recieved!</stream:error>", -1);
mio_close(m);
xmlnode_free(x);
return;
}
jid_set(key,from->server,JID_RESOURCE);
jid_set(key,c->id,JID_USER);
if(j_strcmp(xmlnode_get_name(x),"db:result") == 0)
{
xmlnode_put_attrib(xmlnode_insert_tag_node(c->results, x),"key",jid_full(key));
x2 = xmlnode_new_tag_pool(xmlnode_pool(x),"db:verify");
xmlnode_put_attrib(x2,"to",xmlnode_get_attrib(x,"from"));
xmlnode_put_attrib(x2,"ofrom",xmlnode_get_attrib(x,"to"));
xmlnode_put_attrib(x2,"from",c->d->i->id);
xmlnode_put_attrib(x2,"id",c->id);
xmlnode_insert_node(x2,xmlnode_get_firstchild(x));
deliver(dpacket_new(x2),c->d->i);
return;
}
md = ghash_get(c->d->in_ok_db, jid_full(key));
if(md == NULL || md->m != m)
{
mio_write(m, NULL, "<stream:error>Invalid Packets Recieved!</stream:error>", -1);
mio_close(m);
xmlnode_free(x);
return;
}
dialback_miod_read(md, x);
}
void dialback_in_read_legacy(mio s, int flags, void *arg, xmlnode x)
{
miod md = (miod)arg;
if(flags != MIO_XML_NODE) return;
dialback_miod_read(md, x);
}
void dialback_in_read(mio m, int flags, void *arg, xmlnode x)
{
db d = (db)arg;
xmlnode x2;
miod md;
jid key;
char strid[10];
dbic c;
log_debug(ZONE,"dbin read: fd %d flag %d",m->fd, flags);
if(flags != MIO_XML_ROOT)
return;
if(j_strcmp(xmlnode_get_attrib(x,"xmlns"),"jabber:server") != 0)
{
mio_write(m, NULL, "<stream:stream><stream:error>Invalid Stream Header!</stream:error>", -1);
mio_close(m);
xmlnode_free(x);
return;
}
snprintf(strid, 9, "%X", m);
if(xmlnode_get_attrib(x,"xmlns:db") == NULL)
{
key = jid_new(xmlnode_pool(x), xmlnode_get_attrib(x, "to"));
mio_write(m,NULL, xstream_header_char(xstream_header("jabber:server", NULL, jid_full(key))), -1);
if(d->legacy && key != NULL)
{
log_notice(d->i->id,"legacy server incoming connection to %s established from %s",key->server, m->ip);
md = dialback_miod_new(d, m);
jid_set(key,strid,JID_USER);
dialback_miod_hash(md, d->in_ok_legacy, jid_user(key));
mio_reset(m, dialback_in_read_legacy, (void *)md);
xmlnode_free(x);
return;
}
mio_write(m, NULL, "<stream:error>Legacy Access Denied!</stream:error>", -1);
mio_close(m);
xmlnode_free(x);
return;
}
c = dialback_in_dbic_new(d, m);
x2 = xstream_header("jabber:server", NULL, xmlnode_get_attrib(x,"to"));
xmlnode_put_attrib(x2,"xmlns:db","jabber:server:dialback");
xmlnode_put_attrib(x2,"id",c->id);
mio_write(m,NULL, xstream_header_char(x2), -1);
xmlnode_free(x2);
xmlnode_free(x);
mio_reset(m, dialback_in_read_db, (void *)c);
}
void dialback_in_verify(db d, xmlnode x)
{
dbic c;
xmlnode x2;
jid key;
log_debug(ZONE,"dbin validate: %s",xmlnode2str(x));
if((c = ghash_get(d->in_id, xmlnode_get_attrib(x,"id"))) == NULL)
{
log_warn(d->i->id, "dropping broken dialback validating request: %s", xmlnode2str(x));
xmlnode_free(x);
return;
}
key = jid_new(xmlnode_pool(x),xmlnode_get_attrib(x,"to"));
jid_set(key,xmlnode_get_attrib(x,"from"),JID_RESOURCE);
jid_set(key,c->id,JID_USER);
if((x2 = xmlnode_get_tag(c->results, spools(xmlnode_pool(x),"?key=",jid_full(key),xmlnode_pool(x)))) == NULL)
{
log_warn(d->i->id, "dropping broken dialback validating request: %s", xmlnode2str(x));
xmlnode_free(x);
return;
}
xmlnode_hide(x2);
if(j_strcmp(xmlnode_get_attrib(x,"type"),"valid") == 0)
dialback_miod_hash(dialback_miod_new(c->d, c->m), c->d->in_ok_db, key);
x2 = xmlnode_new_tag_pool(xmlnode_pool(x),"db:result");
xmlnode_put_attrib(x2,"to",xmlnode_get_attrib(x,"from"));
xmlnode_put_attrib(x2,"from",xmlnode_get_attrib(x,"to"));
xmlnode_put_attrib(x2,"type",xmlnode_get_attrib(x,"type"));
mio_write(c->m, x2, NULL, -1);
}