#include <jansson.h>
#include <talloc.h>
+#include <sys/time.h>
#include <tr_rp.h>
#include <tr_idp.h>
comm->refcount--;
}
+void tr_comm_set_apcs(TR_COMM *comm, TR_APC *apc)
+{
+ if (comm->apcs!=NULL)
+ tr_apc_free(comm->apcs);
+ comm->apcs=apc;
+ talloc_steal(comm, apc);
+}
+
TR_APC *tr_comm_get_apcs(TR_COMM *comm)
{
return comm->apcs;
return comms;
}
-/* guarantees comm is not in the list, not an error if it was't there */
+/* Guarantees comm is not in the list, not an error if it was't there.
+ * Does not free the removed element, nor change its talloc context. */
#define tr_comm_remove(comms, c) ((comms)=tr_comm_remove_func((comms), (c)))
static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove)
{
- TR_COMM *this=comms;
+ TALLOC_CTX *list_ctx=talloc_parent(comms); /* in case we need to remove the head */
+ TR_COMM *this=NULL;
- if ((this==NULL) || (this==remove))
+ if (comms==NULL)
return NULL;
-
- for (; this->next!=NULL; this=this->next) {
- if (this->next==remove)
- this->next=remove->next;
+
+ if (comms==remove) {
+ /* if we're removing the head, put the next element (if present) into the context
+ * the list head was in. */
+ comms=comms->next;
+ if (comms!=NULL) {
+ talloc_steal(list_ctx, comms->next);
+ /* now put all the other elements in the context of the list head */
+ for (this=comms->next; this!=NULL; this=this->next)
+ talloc_steal(comms, this);
+ }
+ } else {
+ /* not removing the head; no need to play with contexts */
+ for (this=comms; this->next!=NULL; this=this->next) {
+ if (this->next==remove)
+ this->next=remove->next;
+ }
}
return comms;
}
memb->origin=NULL;
memb->provenance=NULL;
memb->interval=0;
- memb->expiry=NULL;
+ memb->expiry=talloc(memb, struct timespec);
+ if (memb->expiry==NULL) {
+ talloc_free(memb);
+ return NULL;
+ }
+ *(memb->expiry)=(struct timespec){0,0};
talloc_set_destructor(memb, tr_comm_memb_destructor);
}
return memb;
void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time)
{
- memb->expiry=time;
+ memb->expiry->tv_sec=time->tv_sec;
+ memb->expiry->tv_nsec=time->tv_nsec;
}
struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb)
if (ctab!=NULL) {
ctab->comms=NULL;
ctab->memberships=NULL;
+ ctab->idp_realms=NULL;
+ ctab->rp_realms=NULL;
}
return ctab;
}
{
TR_COMM_MEMB *cur=NULL;
+ /* TODO: validate the member (must have valid comm and realm) */
+
/* handle the empty list case */
if (ctab->memberships==NULL) {
ctab->memberships=new;
void tr_print_config (TR_CFG *cfg) {
tr_notice("tr_print_config: Logging running trust router configuration.");
- tr_print_comms(cfg->comms);
+ tr_print_comms(cfg->ctable);
}
void tr_print_comms (TR_COMM_TABLE *ctab)
TR_CFG *cfg=talloc(mem_ctx, TR_CFG);
if (cfg!=NULL) {
cfg->internal=NULL;
- cfg->idp_realms=NULL;
- cfg->rp_realms=NULL;
cfg->rp_clients=NULL;
cfg->peers=NULL;
cfg->default_servers=NULL;
- cfg->comms=tr_comm_table_new(cfg);
- if (cfg->comms==NULL) {
+ cfg->ctable=tr_comm_table_new(cfg);
+ if (cfg->ctable==NULL) {
talloc_free(cfg);
cfg=NULL;
}
/* if we succeeded, link things to the configuration and move out of tmp context */
if (retval==TR_CFG_SUCCESS) {
if (new_idp_realms!=NULL) {
- tr_idp_realm_add(trc->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
- talloc_steal(trc, trc->idp_realms); /* make sure the head is in the right context */
+ tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
+ talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */
}
if (new_rp_clients!=NULL) {
*rc=TR_CFG_ERROR;
return;
}
- tr_comm_add_idp_realm(trc->comms, comm, found_idp, NULL, NULL); /* no provenance, never expires */
+ tr_comm_add_idp_realm(trc->ctable, comm, found_idp, NULL, NULL); /* no provenance, never expires */
}
*rc=TR_CFG_SUCCESS;
}
/* see if we already have this RP in this community */
- found_rp=tr_comm_find_rp(trc->comms, comm, rp_name);
+ found_rp=tr_comm_find_rp(trc->ctable, comm, rp_name);
if (found_rp!=NULL) {
tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.",
s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
}
/* Add the RP to the community, first see if we have the RP in any community */
- found_rp=tr_rp_realm_lookup(trc->rp_realms, rp_name);
+ found_rp=tr_rp_realm_lookup(trc->ctable->rp_realms, rp_name);
if (found_rp!=NULL) {
tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s);
new_rp=found_rp; /* use it rather than creating a new realm record */
tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf);
tr_rp_realm_set_id(new_rp, rp_name);
rp_name=NULL; /* rp_name no longer belongs to us */
- tr_rp_realm_add(trc->rp_realms, new_rp);
+ tr_rp_realm_add(trc->ctable->rp_realms, new_rp);
}
- tr_comm_add_rp_realm(trc->comms, comm, new_rp, NULL, NULL);
+ tr_comm_add_rp_realm(trc->ctable, comm, new_rp, NULL, NULL);
}
}
tr_debug("tr_cfg_parse_comms: Community configured: %s.",
tr_comm_get_id(comm)->buf);
- tr_comm_table_add_comm(trc->comms, comm);
+ tr_comm_table_add_comm(trc->ctable, comm);
}
}
tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
rc = TR_CFG_ERROR;
}
- if (0==tr_comm_table_size(trc->comms)) {
+ if (0==tr_comm_table_size(trc->ctable)) {
tr_debug("tr_cfg_validate: Error: No Communities configured");
rc = TR_CFG_ERROR;
}
- if ((NULL == trc->default_servers) && (NULL == trc->idp_realms)) {
+ if ((NULL == trc->default_servers) && (NULL == trc->ctable->idp_realms)) {
tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured.");
rc = TR_CFG_ERROR;
}
return NULL;
}
- for (cfg_idp = tr_cfg->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
+ for (cfg_idp = tr_cfg->ctable->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
return cfg_idp;
#include <trust_router/tr_name.h>
#include <tr_idp.h>
#include <tr_config.h>
+#include <tr_debug.h>
static int tr_aaa_server_destructor(void *obj)
{
idp->aaa_servers=NULL;
idp->apcs=NULL;
idp->origin=TR_REALM_LOCAL;
- idp->peer=NULL;
- idp->expiry=talloc(idp, struct timespec);
- if (idp->expiry==NULL) {
- talloc_free(idp);
- return NULL;
- }
talloc_set_destructor((void *)idp, tr_idp_realm_destructor);
}
return idp;
idp->realm_id=id;
}
+void tr_idp_realm_set_apcs(TR_IDP_REALM *idp, TR_APC *apc)
+{
+ if (idp->apcs!=NULL)
+ tr_apc_free(idp->apcs);
+ idp->apcs=apc;
+ talloc_steal(idp, apc);
+}
+
+TR_APC *tr_idp_realm_get_apcs(TR_IDP_REALM *idp)
+{
+ return idp->apcs;
+}
+
+TR_IDP_REALM *tr_idp_realm_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_name)
+{
+ TR_IDP_REALM *idp = NULL;
+
+ if (!idp_name) {
+ tr_debug("tr_idp_realm_lookup: Bad parameters.");
+ return NULL;
+ }
+
+ for (idp=idp_realms; NULL!=idp; idp=idp->next) {
+ if (0==tr_name_cmp(tr_idp_realm_get_id(idp), idp_name))
+ return idp;
+ }
+ return NULL;
+}
+
+
static TR_IDP_REALM *tr_idp_realm_tail(TR_IDP_REALM *idp)
{
if (idp==NULL)
/* table of communities/memberships */
struct tr_comm_table {
TR_COMM *comms; /* all communities */
+ TR_IDP_REALM *idp_realms; /* all idp realms */
+ TR_RP_REALM *rp_realms; /* all rp realms */
TR_COMM_MEMB *memberships; /* head of the linked list of membership records */
};
TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx);
void tr_comm_free(TR_COMM *comm);
void tr_comm_set_id(TR_COMM *comm, TR_NAME *id);
-TR_APC *tr_comm_get_apcs(TR_COMM *comm);
TR_NAME *tr_comm_get_id(TR_COMM *comm);
TR_NAME *tr_comm_dup_id(TR_COMM *comm);
+void tr_comm_set_apcs(TR_COMM *comm, TR_APC *apc);
+TR_APC *tr_comm_get_apcs(TR_COMM *comm);
void tr_comm_set_type(TR_COMM *comm, TR_COMM_TYPE type);
TR_COMM_TYPE tr_comm_get_type(TR_COMM *comm);
void tr_comm_set_owner_realm(TR_COMM *comm, TR_NAME *realm);
typedef struct tr_cfg {
TR_CFG_INTERNAL *internal; /* internal trust router config */
- TR_IDP_REALM *idp_realms; /* locally associated IDP Realms */
- TR_RP_REALM *rp_realms;
TR_RP_CLIENT *rp_clients; /* locally associated RP Clients */
TRP_PTABLE *peers; /* TRP peer table */
- TR_COMM_TABLE *comms; /* communities */
+ TR_COMM_TABLE *ctable; /* communities/realms */
TR_AAA_SERVER *default_servers; /* default server list */
/* TBD -- Global Filters */
} TR_CFG;
TR_AAA_SERVER *aaa_servers;
TR_APC *apcs;
TR_REALM_ORIGIN origin; /* how did we learn about this realm? */
- TR_NAME *peer; /* for remote/discovered, who told us about this realm? */
- struct timespec *expiry; /* when does this realm entry expire? */
unsigned int refcount; /* how many TR_COMM_MEMBs refer to this realm */
} TR_IDP_REALM;
TR_NAME *tr_idp_realm_get_id(TR_IDP_REALM *idp);
TR_NAME *tr_idp_realm_dup_id(TR_IDP_REALM *idp);
void tr_idp_realm_set_id(TR_IDP_REALM *idp, TR_NAME *id);
+void tr_idp_realm_set_apcs(TR_IDP_REALM *idp, TR_APC *apc);
+TR_APC *tr_idp_realm_get_apcs(TR_IDP_REALM *idp);
+TR_IDP_REALM *tr_idp_realm_lookup(TR_IDP_REALM *idp_realms, TR_NAME *idp_name);
TR_IDP_REALM *tr_idp_realm_add_func(TR_IDP_REALM *head, TR_IDP_REALM *new);
#define tr_idp_realm_add(head,new) ((head)=tr_idp_realm_add_func((head),(new)))
char *tr_idp_realm_to_str(TALLOC_CTX *mem_ctx, TR_IDP_REALM *idp);
TR_APC *apcs;
TR_NAME *owner_realm;
TR_NAME *owner_contact;
+ time_t expiration_interval; /* Minutes to key expiration; only valid for an APC */
json_t *provenance;
unsigned int interval;
} TRP_INFOREC_COMM;
void trps_set_ctable(TRPS_INSTANCE *trps, TR_COMM_TABLE *comm);
void trps_set_ptable(TRPS_INSTANCE *trps, TRP_PTABLE *ptable);
void trps_set_peer_status_callback(TRPS_INSTANCE *trps, void (*cb)(TRP_PEER *, void *), void *cookie);
+TR_NAME *trps_dup_label(TRPS_INSTANCE *trps);
TRP_RC trps_init_rtable(TRPS_INSTANCE *trps);
void trps_clear_rtable(TRPS_INSTANCE *trps);
void trps_set_connect_interval(TRPS_INSTANCE *trps, unsigned int interval);
TRP_RC trp_inforec_set_provenance(TRP_INFOREC *rec, json_t *prov);
TRP_INFOREC_TYPE trp_inforec_type_from_string(const char *s);
const char *trp_inforec_type_to_string(TRP_INFOREC_TYPE msgtype);
+time_t trp_inforec_get_exp_interval(TRP_INFOREC *rec);
+TRP_RC trp_inforec_set_exp_interval(TRP_INFOREC *rec, time_t expint);
TR_COMM_TYPE trp_inforec_get_comm_type(TRP_INFOREC *rec);
TRP_RC trp_inforec_set_comm_type(TRP_INFOREC *rec, TR_COMM_TYPE type);
TR_REALM_ROLE trp_inforec_get_role(TRP_INFOREC *rec);
TRP_RC trp_inforec_set_role(TRP_INFOREC *rec, TR_REALM_ROLE role);
TR_APC *trp_inforec_get_apcs(TRP_INFOREC *rec);
TRP_RC trp_inforec_set_apcs(TRP_INFOREC *rec, TR_APC *apcs);
+TR_NAME *trp_inforec_dup_origin(TRP_INFOREC *rec);
+
#endif /* TRP_INTERNAL_H */
goto cleanup;
}
- if (NULL == (cfg_comm = tr_comm_table_find_comm(cfg_mgr->active->comms, orig_req->comm))) {
+ if (NULL == (cfg_comm = tr_comm_table_find_comm(cfg_mgr->active->ctable, orig_req->comm))) {
tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", orig_req->comm->buf);
tids_send_err_response(tids, orig_req, "Unknown community");
retval=-1;
goto cleanup;
}
/* Check that the rp_realm is a member of the community in the request */
- if (NULL == (tr_comm_find_rp(cfg_mgr->active->comms, cfg_comm, orig_req->rp_realm))) {
+ if (NULL == (tr_comm_find_rp(cfg_mgr->active->ctable, cfg_comm, orig_req->rp_realm))) {
tr_notice("tr_tids_req_handler: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
tids_send_err_response(tids, orig_req, "RP COI membership error");
retval=-1;
apc = tr_dup_name(cfg_comm->apcs->id);
/* Check that the APC is configured */
- if (NULL == (cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->comms, apc))) {
+ if (NULL == (cfg_apc = tr_comm_table_find_comm(cfg_mgr->active->ctable, apc))) {
tr_notice("tr_tids_req_hander: Request for unknown comm: %s.", apc->buf);
tids_send_err_response(tids, orig_req, "Unknown APC");
retval=-1;
fwd_req->orig_coi = orig_req->comm;
/* Check that rp_realm is a member of this APC */
- if (NULL == (tr_comm_find_rp(cfg_mgr->active->comms, cfg_apc, orig_req->rp_realm))) {
+ if (NULL == (tr_comm_find_rp(cfg_mgr->active->ctable, cfg_apc, orig_req->rp_realm))) {
tr_notice("tr_tids_req_hander: RP Realm (%s) not member of community (%s).", orig_req->rp_realm->buf, orig_req->comm->buf);
tids_send_err_response(tids, orig_req, "RP APC membership error");
retval=-1;
tr_debug("tr_tids_req_handler: found route.");
if (trp_route_is_local(route)) {
tr_debug("tr_tids_req_handler: route is local.");
- aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->idp_realms,
+ aaa_servers = tr_idp_aaa_server_lookup(cfg_mgr->active->ctable->idp_realms,
orig_req->realm,
orig_req->comm);
} else {
}
} else {
/* if we aren't defaulting, check idp coi and apc membership */
- if (NULL == (tr_comm_find_idp(cfg_mgr->active->comms, cfg_comm, fwd_req->realm))) {
+ if (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_comm, fwd_req->realm))) {
tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of community (%s).", orig_req->realm->buf, orig_req->comm->buf);
tids_send_err_response(tids, orig_req, "IDP community membership error");
retval=-1;
goto cleanup;
}
- if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->comms, cfg_apc, fwd_req->realm)))) {
+ if ( cfg_apc && (NULL == (tr_comm_find_idp(cfg_mgr->active->ctable, cfg_apc, fwd_req->realm)))) {
tr_notice("tr_tids_req_handler: IDP Realm (%s) not member of APC (%s).", orig_req->realm->buf, orig_req->comm->buf);
tids_send_err_response(tids, orig_req, "IDP APC membership error");
retval=-1;
if (trust_router_name==NULL)
return TRP_NOMEM;
- for (cur=cfg->idp_realms; cur!=NULL; cur=cur->next) {
+ for (cur=cfg->ctable->idp_realms; cur!=NULL; cur=cur->next) {
local_routes=tr_make_local_routes(tmp_ctx, cur, trust_router_name, &n_routes);
for (ii=0; ii<n_routes; ii++)
trps_add_route(trps, local_routes[ii]);
trps_set_connect_interval(trps, new_cfg->internal->trp_connect_interval);
trps_set_update_interval(trps, new_cfg->internal->trp_update_interval);
trps_set_sweep_interval(trps, new_cfg->internal->trp_sweep_interval);
- trps_set_ctable(trps, new_cfg->comms);
+ trps_set_ctable(trps, new_cfg->ctable);
trps_set_ptable(trps, new_cfg->peers);
trps_set_peer_status_callback(trps, tr_peer_status_change, (void *)trps);
trps_clear_rtable(trps); /* should we do this every time??? */
new_rec->apcs=NULL;
new_rec->owner_realm=NULL;
new_rec->owner_contact=NULL;
+ new_rec->expiration_interval=0;
new_rec->provenance=NULL;
new_rec->interval=0;
talloc_set_destructor((void *)new_rec, trp_inforec_comm_destructor);
return TRP_ERROR;
}
+time_t trp_inforec_get_exp_interval(TRP_INFOREC *rec)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL)
+ return rec->data->comm->expiration_interval;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+TRP_RC trp_inforec_set_exp_interval(TRP_INFOREC *rec, time_t expint)
+{
+ switch (rec->type) {
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (rec->data->comm!=NULL) {
+ rec->data->comm->expiration_interval=expint;
+ return TRP_SUCCESS;
+ }
+ break;
+ default:
+ break;
+ }
+ return TRP_ERROR;
+}
+
TR_COMM_TYPE trp_inforec_get_comm_type(TRP_INFOREC *rec)
{
switch (rec->type) {
return TRP_SUCCESS;
}
+TR_NAME *trp_inforec_dup_origin(TRP_INFOREC *rec)
+{
+ TR_NAME *origin=NULL;
+ json_t *prov=trp_inforec_get_provenance(rec);
+ const char *s=NULL;
+
+ if (prov==NULL)
+ return NULL;
+
+ s=json_string_value(json_array_get(prov, 0));
+ if (s==NULL) {
+ tr_debug("trp_inforec_dup_origin: empty origin in provenance list.");
+ return NULL;
+ }
+ origin=tr_new_name(s);
+ return origin;
+}
+
/* generic record type */
TRP_INFOREC *trp_inforec_new(TALLOC_CTX *mem_ctx, TRP_INFOREC_TYPE type)
{
trp_ptable_iter_free(iter);
}
+/* Get the label peers will know us by - needs to match trp_peer_get_label() output.
+ * There is no get, only dup, because we don't store the label except when requested. */
+TR_NAME *trps_dup_label(TRPS_INSTANCE *trps)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME *label=NULL;
+ char *s=talloc_asprintf(tmp_ctx, "%s:%u", trps->hostname, trps->port);
+ if (s==NULL)
+ goto cleanup;
+ label=tr_new_name(s);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return label;
+}
+
TRPC_INSTANCE *trps_find_trpc(TRPS_INSTANCE *trps, TRP_PEER *peer)
{
TRPC_INSTANCE *cur=NULL;
break;
case TRP_INFOREC_TYPE_COMMUNITY:
- /* TODO: handle community updates -jlr*/
+ /* TODO: validate community updates */
+ break;
default:
tr_notice("trps_validate_inforec: unsupported record type.");
return TRP_SUCCESS;
}
-static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+
+static TRP_RC trps_handle_inforec_route(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec)
{
+ TRP_ROUTE *route=NULL;
unsigned int feas=0;
+
+ /* determine feasibility */
+ feas=trps_check_feasibility(trps, trp_upd_get_realm(upd), trp_upd_get_comm(upd), rec);
+ tr_debug("trps_handle_update: record feasibility=%d", feas);
+
+ /* do we have an existing route? */
+ route=trps_get_route(trps,
+ trp_upd_get_comm(upd),
+ trp_upd_get_realm(upd),
+ trp_upd_get_peer(upd));
+ if (route!=NULL) {
+ /* there was a route table entry already */
+ tr_debug("trps_handle_updates: route entry already exists.");
+ if (feas) {
+ /* Update is feasible. Accept it. */
+ trps_accept_update(trps, upd, rec);
+ } else {
+ /* Update is infeasible. Ignore it unless the trust router has changed. */
+ if (0!=tr_name_cmp(trp_route_get_trust_router(route),
+ trp_inforec_get_trust_router(rec))) {
+ /* the trust router associated with the route has changed, treat update as a retraction */
+ trps_retract_route(trps, route);
+ }
+ }
+ } else {
+ /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */
+ tr_debug("trps_handle_update: no route entry exists yet.");
+ if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec)))
+ trps_accept_update(trps, upd, rec);
+ }
+
+ return TRP_SUCCESS;
+}
+
+static int trps_name_in_provenance(TR_NAME *name, json_t *prov)
+{
+ size_t ii=0;
+ TR_NAME *this_name=NULL;
+ const char *s=NULL;
+
+ if (prov==NULL)
+ return 0; /* no provenance list, so it has no names in it */
+
+ /* now check to see if name is in the provenance */
+ for (ii=0; ii<json_array_size(prov); ii++) {
+ s=json_string_value(json_array_get(prov, ii));
+ if (s==NULL) {
+ tr_debug("trps_name_in_provenance: empty entry in provenance list.");
+ continue;
+ }
+
+ this_name=tr_new_name(s);
+ if (this_name==NULL) {
+ tr_debug("trps_name_in_provenance: unable to allocate name.");
+ return -1;
+ }
+ if (0==tr_name_cmp(name, this_name)) {
+ tr_free_name(this_name);
+ return 1;
+ }
+ tr_free_name(this_name);
+ }
+ return 0;
+}
+
+static TR_COMM *trps_create_new_comm(TALLOC_CTX *mem_ctx, TR_NAME *comm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_COMM *comm=tr_comm_new(tmp_ctx);
+
+ if (comm==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate new community.");
+ goto cleanup;
+ }
+ /* fill in the community with info */
+ tr_comm_set_id(comm, tr_dup_name(comm_id));
+ if (tr_comm_get_id(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate community name.");
+ comm=NULL;
+ goto cleanup;
+ }
+ tr_comm_set_type(comm, trp_inforec_get_comm_type(rec));
+ if (trp_inforec_get_apcs(rec)!=NULL) {
+ tr_comm_set_apcs(comm, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec)));
+ if (tr_comm_get_apcs(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate APC list.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ if (trp_inforec_get_owner_realm(rec)!=NULL) {
+ tr_comm_set_owner_realm(comm, tr_dup_name(trp_inforec_get_owner_realm(rec)));
+ if (tr_comm_get_owner_realm(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate owner realm name.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ if (trp_inforec_get_owner_contact(rec)!=NULL) {
+ tr_comm_set_owner_contact(comm, tr_dup_name(trp_inforec_get_owner_contact(rec)));
+ if (tr_comm_get_owner_contact(comm)==NULL) {
+ tr_debug("trps_create_new_comm: unable to allocate owner contact.");
+ comm=NULL;
+ goto cleanup;
+ }
+ }
+ comm->expiration_interval=trp_inforec_get_exp_interval(rec);
+ talloc_steal(mem_ctx, comm);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return comm;
+}
+
+static TR_RP_REALM *trps_create_new_rp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_RP_REALM *rp=tr_rp_realm_new(tmp_ctx);
+
+ if (rp==NULL) {
+ tr_debug("trps_create_new_rp_realm: unable to allocate new realm.");
+ goto cleanup;
+ }
+ /* fill in the realm */
+ tr_rp_realm_set_id(rp, tr_dup_name(realm_id));
+ if (tr_rp_realm_get_id(rp)==NULL) {
+ tr_debug("trps_create_new_rp_realm: unable to allocate realm name.");
+ rp=NULL;
+ goto cleanup;
+ }
+ talloc_steal(mem_ctx, rp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return rp;
+}
+
+static TR_IDP_REALM *trps_create_new_idp_realm(TALLOC_CTX *mem_ctx, TR_NAME *realm_id, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_IDP_REALM *idp=tr_idp_realm_new(tmp_ctx);
+
+ if (idp==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate new realm.");
+ goto cleanup;
+ }
+ /* fill in the realm */
+ tr_idp_realm_set_id(idp, tr_dup_name(realm_id));
+ if (tr_idp_realm_get_id(idp)==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate realm name.");
+ idp=NULL;
+ goto cleanup;
+ }
+ if (trp_inforec_get_apcs(rec)!=NULL) {
+ tr_idp_realm_set_apcs(idp, tr_apc_dup(tmp_ctx, trp_inforec_get_apcs(rec)));
+ if (tr_idp_realm_get_apcs(idp)==NULL) {
+ tr_debug("trps_create_new_idp_realm: unable to allocate APC list.");
+ idp=NULL;
+ goto cleanup;
+ }
+ }
+ idp->origin=TR_REALM_DISCOVERED;
+
+ talloc_steal(mem_ctx, idp);
+
+cleanup:
+ talloc_free(tmp_ctx);
+ return idp;
+}
+
+static TRP_RC trps_handle_inforec_comm(TRPS_INSTANCE *trps, TRP_UPD *upd, TRP_INFOREC *rec)
+{
+ TALLOC_CTX *tmp_ctx=talloc_new(NULL);
+ TR_NAME *comm_id=trp_upd_get_comm(upd);
+ TR_NAME *realm_id=trp_upd_get_realm(upd);
+ TR_NAME *origin_id=NULL;
+ TR_NAME *our_peer_label=NULL;
+ TR_COMM *comm=NULL;
+ TR_RP_REALM *rp_realm=NULL;
+ TR_IDP_REALM *idp_realm=NULL;
+ struct timespec expiry={0,0};
+ TRP_RC rc=TRP_ERROR;
+
+ if ((comm_id==NULL) || (realm_id==NULL))
+ goto cleanup;
+
+ origin_id=trp_inforec_dup_origin(rec);
+ if (origin_id==NULL)
+ goto cleanup;
+
+ /* see whether we want to add this */
+ our_peer_label=trps_dup_label(trps);
+ if (our_peer_label==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to allocate peer label.");
+ goto cleanup;
+ }
+
+ if (trps_name_in_provenance(our_peer_label, trp_inforec_get_provenance(rec)))
+ tr_debug("trps_handle_inforec_comm: rejecting community inforec to avoid loop.");
+ else {
+ /* no loop occurring, accept the update */
+ comm=tr_comm_table_find_comm(trps->ctable, comm_id);
+ if (comm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown community %.*s in inforec, creating it.",
+ comm_id->len, comm_id->buf);
+ comm=trps_create_new_comm(tmp_ctx, comm_id, rec);
+ if (comm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new community.");
+ goto cleanup;
+ }
+ tr_comm_table_add_comm(trps->ctable, comm);
+ }
+ /* TODO: see if other comm data match the new inforec and update or complain */
+
+ trps_compute_expiry(trps, trp_inforec_get_interval(rec), &expiry);
+ if ((expiry.tv_sec==0)&&(expiry.tv_nsec==0))
+ goto cleanup;
+
+ switch (trp_inforec_get_role(rec)) {
+ case TR_ROLE_RP:
+ rp_realm=tr_rp_realm_lookup(trps->ctable->rp_realms, realm_id);
+ if (rp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown RP realm %.*s in inforec, creating it.",
+ realm_id->len, realm_id->buf);
+ rp_realm=trps_create_new_rp_realm(tmp_ctx, realm_id, rec);
+ if (rp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new RP realm.");
+ /* we may leave an unused community in the table, but it will only last until
+ * the next table sweep if it does not get any realms before that happens */
+ goto cleanup;
+ }
+ tr_rp_realm_add(trps->ctable->rp_realms, rp_realm);
+ }
+ /* TODO: if realm existed, see if data match the new inforec and update or complain */
+ tr_comm_add_rp_realm(trps->ctable, comm, rp_realm, trp_inforec_get_provenance(rec), &expiry);
+ tr_debug("trps_handle_inforec_comm: added RP realm %.*s to comm %.*s (origin %.*s).",
+ realm_id->len, realm_id->buf,
+ comm_id->len, comm_id->buf,
+ origin_id->len, origin_id->buf);
+ break;
+ case TR_ROLE_IDP:
+ idp_realm=tr_idp_realm_lookup(trps->ctable->idp_realms, realm_id);
+ if (idp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unknown IDP realm %.*s in inforec, creating it.",
+ realm_id->len, realm_id->buf);
+ idp_realm=trps_create_new_idp_realm(tmp_ctx, realm_id, rec);
+ if (idp_realm==NULL) {
+ tr_debug("trps_handle_inforec_comm: unable to create new IDP realm.");
+ /* we may leave an unused community in the table, but it will only last until
+ * the next table sweep if it does not get any realms before that happens */
+ goto cleanup;
+ }
+ tr_idp_realm_add(trps->ctable->idp_realms, idp_realm);
+ }
+ /* TODO: if realm existed, see if data match the new inforec and update or complain */
+ tr_comm_add_idp_realm(trps->ctable, comm, idp_realm, trp_inforec_get_provenance(rec), &expiry);
+ tr_debug("trps_handle_inforec_comm: added IDP realm %.*s to comm %.*s (origin %.*s).",
+ realm_id->len, realm_id->buf,
+ comm_id->len, comm_id->buf,
+ origin_id->len, origin_id->buf);
+ break;
+ default:
+ tr_debug("trps_handle_inforec_comm: unable to add realm.");
+ goto cleanup;
+ }
+ }
+
+ rc=TRP_SUCCESS;
+
+cleanup:
+ if (our_peer_label!=NULL)
+ tr_free_name(our_peer_label);
+ if (origin_id!=NULL)
+ tr_free_name(origin_id);
+ talloc_free(tmp_ctx);
+ return rc;
+}
+
+static TRP_RC trps_handle_update(TRPS_INSTANCE *trps, TRP_UPD *upd)
+{
TRP_INFOREC *rec=NULL;
- TRP_ROUTE *route=NULL;
if (trps_validate_update(trps, upd) != TRP_SUCCESS) {
tr_notice("trps_handle_update: received invalid TRP update.");
for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
/* validate/sanity check the record update */
if (trps_validate_inforec(trps, rec) != TRP_SUCCESS) {
- tr_notice("trps_handle_update: invalid record in TRP update, discarding entire update.");
+ tr_notice("trps_handle_update: invalid inforec in TRP update, discarding entire update.");
return TRP_ERROR;
}
}
for (rec=trp_upd_get_inforec(upd); rec!=NULL; rec=trp_inforec_get_next(rec)) {
- /* determine feasibility */
- feas=trps_check_feasibility(trps, trp_upd_get_realm(upd), trp_upd_get_comm(upd), rec);
- tr_debug("trps_handle_update: record feasibility=%d", feas);
-
- /* do we have an existing route? */
- route=trps_get_route(trps,
- trp_upd_get_comm(upd),
- trp_upd_get_realm(upd),
- trp_upd_get_peer(upd));
- if (route!=NULL) {
- /* there was a route table entry already */
- tr_debug("trps_handle_updates: route entry already exists.");
- if (feas) {
- /* Update is feasible. Accept it. */
- trps_accept_update(trps, upd, rec);
- } else {
- /* Update is infeasible. Ignore it unless the trust router has changed. */
- if (0!=tr_name_cmp(trp_route_get_trust_router(route),
- trp_inforec_get_trust_router(rec))) {
- /* the trust router associated with the route has changed, treat update as a retraction */
- trps_retract_route(trps, route);
- }
- }
- } else {
- /* No existing route table entry. Ignore it unless it is feasible and not a retraction. */
- tr_debug("trps_handle_update: no route entry exists yet.");
- if (feas && trp_metric_is_finite(trp_inforec_get_metric(rec)))
- trps_accept_update(trps, upd, rec);
+ switch (trp_inforec_get_type(rec)) {
+ case TRP_INFOREC_TYPE_ROUTE:
+ if (TRP_SUCCESS!=trps_handle_inforec_route(trps, upd, rec))
+ tr_notice("trps_handle_update: error handling route inforec.");
+ break;
+ case TRP_INFOREC_TYPE_COMMUNITY:
+ if (TRP_SUCCESS!=trps_handle_inforec_comm(trps, upd, rec))
+ tr_notice("trps_handle_update: error handling community inforec.");
+ break;
+ default:
+ tr_notice("trps_handle_update: unsupported inforec in TRP update.");
+ break;
}
}
return TRP_SUCCESS;