2 * Copyright (c) 2012, JANET(UK)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of JANET(UK) nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include <tr_name_internal.h>
47 static int tr_comm_destructor(void *obj)
49 TR_COMM *comm=talloc_get_type_abort(obj, TR_COMM);
51 tr_free_name(comm->id);
52 if (comm->owner_realm!=NULL)
53 tr_free_name(comm->owner_realm);
54 if (comm->owner_contact!=NULL)
55 tr_free_name(comm->owner_contact);
59 TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx)
61 TR_COMM *comm=talloc(mem_ctx, TR_COMM);
65 comm->type=TR_COMM_UNKNOWN;
67 comm->owner_realm=NULL;
68 comm->owner_contact=NULL;
69 comm->expiration_interval=0;
71 talloc_set_destructor((void *)comm, tr_comm_destructor);
76 void tr_comm_free(TR_COMM *comm)
81 void tr_comm_set_id(TR_COMM *comm, TR_NAME *id)
84 tr_free_name(comm->id);
88 void tr_comm_incref(TR_COMM *comm)
93 void tr_comm_decref(TR_COMM *comm)
99 void tr_comm_set_apcs(TR_COMM *comm, TR_APC *apc)
101 if (comm->apcs!=NULL)
102 tr_apc_free(comm->apcs);
104 talloc_steal(comm, apc);
107 TR_APC *tr_comm_get_apcs(TR_COMM *comm)
112 TR_NAME *tr_comm_get_id(TR_COMM *comm)
117 TR_NAME *tr_comm_dup_id(TR_COMM *comm)
119 return tr_dup_name(comm->id);
122 void tr_comm_set_type(TR_COMM *comm, TR_COMM_TYPE type)
127 TR_COMM_TYPE tr_comm_get_type(TR_COMM *comm)
132 void tr_comm_set_owner_realm(TR_COMM *comm, TR_NAME *realm)
134 if (comm->owner_realm!=NULL)
135 tr_free_name(comm->owner_realm);
136 comm->owner_realm=realm;
139 TR_NAME *tr_comm_get_owner_realm(TR_COMM *comm)
141 return comm->owner_realm;
144 TR_NAME *tr_comm_dup_owner_realm(TR_COMM *comm)
146 return tr_dup_name(comm->owner_realm);
149 void tr_comm_set_owner_contact(TR_COMM *comm, TR_NAME *contact)
151 if (comm->owner_contact != NULL)
152 tr_free_name(comm->owner_contact);
153 comm->owner_contact=contact;
156 TR_NAME *tr_comm_get_owner_contact(TR_COMM *comm)
158 return comm->owner_contact;
161 TR_NAME *tr_comm_dup_owner_contact(TR_COMM *comm)
163 return tr_dup_name(comm->owner_contact);
166 unsigned int tr_comm_get_refcount(TR_COMM *comm)
168 return comm->refcount;
171 /* 0 if equivalent, nonzero if different, only considers
172 * nhops last hops (nhops==0 means consider all, nhops==1
173 * only considers last hop) */
174 static int tr_comm_memb_provenance_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2, int nhops)
178 if ((m1->provenance==NULL) || (m2->provenance==NULL))
179 return m1->provenance!=m2->provenance; /* return 0 if both null, 1 if only one null */
181 if (json_array_size(m1->provenance)!=json_array_size(m2->provenance))
185 nhops=json_array_size(m1->provenance); /* same as size(m2->provenance) */
187 for (ii=0; ii<json_array_size(m1->provenance); ii++) {
188 if (0==strcmp(json_string_value(json_array_get(m1->provenance, ii)),
189 json_string_value(json_array_get(m2->provenance, ii)))) {
196 /* Accepts an update that either came from the same peer as the previous
197 * origin, has a shorter provenance list, or can replace an expired
198 * membership. Otherwise keeps the existing one.
199 * On replacement, frees the old member and moves new member to ctab's
200 * context. Caller should not free newmemb except by freeing its original
202 static void tr_comm_add_if_shorter(TR_COMM_TABLE *ctab, TR_COMM_MEMB *existing, TR_COMM_MEMB *newmemb)
206 if (existing==NULL) {
207 /* not in the table */
208 tr_comm_table_add_memb(ctab, newmemb);
210 if (0==tr_comm_memb_provenance_cmp(existing, newmemb, 1))
211 accept=1; /* always accept a replacement from the same peer */
212 else if (tr_comm_memb_provenance_len(newmemb) < tr_comm_memb_provenance_len(existing))
213 accept=1; /* accept a shorter provenance */
214 else if (existing->times_expired>0)
220 tr_comm_table_remove_memb(ctab, existing);
221 tr_comm_memb_free(existing);
222 tr_comm_table_add_memb(ctab, newmemb);
227 /* does not take responsibility for freeing IDP realm */
228 void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab,
231 unsigned int interval,
233 struct timespec *expiry)
235 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
236 TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
237 TR_COMM_MEMB *existing=NULL;
240 tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
241 talloc_free(tmp_ctx);
245 tr_comm_memb_set_idp_realm(newmemb, realm);
246 tr_comm_memb_set_comm(newmemb, comm);
247 tr_comm_memb_set_interval(newmemb, interval);
248 tr_comm_memb_set_provenance(newmemb, provenance);
249 tr_comm_memb_set_expiry(newmemb, expiry);
251 existing=tr_comm_table_find_idp_memb_origin(ctab,
252 tr_idp_realm_get_id(realm),
253 tr_comm_get_id(comm),
254 tr_comm_memb_get_origin(newmemb));
255 tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
257 talloc_free(tmp_ctx);
260 /* does not take responsibility for freeing RP realm */
261 void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab,
264 unsigned int interval,
266 struct timespec *expiry)
268 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
269 TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
270 TR_COMM_MEMB *existing=NULL;
273 tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
274 talloc_free(tmp_ctx);
278 tr_comm_memb_set_rp_realm(newmemb, realm);
279 tr_comm_memb_set_comm(newmemb, comm);
280 tr_comm_memb_set_interval(newmemb, interval);
281 tr_comm_memb_set_provenance(newmemb, provenance);
282 tr_comm_memb_set_expiry(newmemb, expiry);
284 existing=tr_comm_table_find_rp_memb_origin(ctab,
285 tr_rp_realm_get_id(realm),
286 tr_comm_get_id(comm),
287 tr_comm_memb_get_origin(newmemb));
288 tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
289 talloc_free(tmp_ctx);
292 static TR_COMM *tr_comm_tail(TR_COMM *comm)
297 while (comm->next!=NULL)
302 /* All list members are in the talloc context of the head.
303 * This will require careful thought if entries are ever removed
304 * Call like comms=tr_comm_add_func(comms, new_comm);
305 * or just use the tr_comm_add(comms, new) macro. */
306 #define tr_comm_add(comms, new) ((comms)=tr_comm_add_func((comms), (new)))
307 static TR_COMM *tr_comm_add_func(TR_COMM *comms, TR_COMM *new)
312 tr_comm_tail(comms)->next=new;
314 talloc_steal(comms, new);
321 /* Guarantees comm is not in the list, not an error if it was't there.
322 * Does not free the removed element, nor change its talloc context. */
323 #define tr_comm_remove(comms, c) ((comms)=tr_comm_remove_func((comms), (c)))
324 static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove)
326 TALLOC_CTX *list_ctx=talloc_parent(comms); /* in case we need to remove the head */
333 /* if we're removing the head, put the next element (if present) into the context
334 * the list head was in. */
337 talloc_steal(list_ctx, comms);
338 /* now put all the other elements in the context of the list head */
339 for (this=comms->next; this!=NULL; this=this->next)
340 talloc_steal(comms, this);
343 /* not removing the head; no need to play with contexts */
344 for (this=comms; this->next!=NULL; this=this->next) {
345 if (this->next==remove) {
346 this->next=remove->next;
354 /* remove any with zero refcount
356 #define tr_comm_sweep(head) ((head)=tr_comm_sweep_func((head)))
357 static TR_COMM *tr_comm_sweep_func(TR_COMM *head)
360 TR_COMM *old_next=NULL;
365 while ((head!=NULL) && (head->refcount==0)) {
366 comm=head; /* keep a pointer so we can remove it */
367 tr_comm_remove(head, comm); /* use this to get talloc contexts right */
374 /* will not remove the head here, that has already been done */
375 for (comm=head; comm->next!=NULL; comm=comm->next) {
376 if (comm->next->refcount==0) {
378 tr_comm_remove(head, comm->next); /* changes comm->next */
379 tr_comm_free(old_next);
386 TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm)
388 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
389 TR_COMM_ITER *iter=NULL;
390 TR_IDP_REALM *this_idp=NULL;
392 if ((NULL==ctab) || (NULL==comm) || (NULL==idp_realm)) {
393 talloc_free(tmp_ctx);
397 iter=tr_comm_iter_new(tmp_ctx);
398 for (this_idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
400 this_idp=tr_idp_realm_iter_next(iter)) {
401 if (0==tr_name_cmp(idp_realm, tr_idp_realm_get_id(this_idp))) {
402 tr_debug("tr_comm_find_idp: Found IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
403 talloc_free(tmp_ctx);
407 tr_debug("tr_comm_find_idp: Unable to find IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
408 talloc_free(tmp_ctx);
412 TR_RP_REALM *tr_comm_find_rp (TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *rp_realm)
414 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
415 TR_COMM_ITER *iter=NULL;
416 TR_RP_REALM *this_rp=NULL;
418 if ((NULL==ctab) || (NULL==comm) || (NULL==rp_realm)) {
419 talloc_free(tmp_ctx);
423 iter=tr_comm_iter_new(tmp_ctx);
424 for (this_rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
426 this_rp=tr_rp_realm_iter_next(iter)) {
427 if (0==tr_name_cmp(rp_realm, tr_rp_realm_get_id(this_rp))) {
428 tr_debug("tr_comm_find_rp: Found RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
429 talloc_free(tmp_ctx);
433 tr_debug("tr_comm_find_rp: Unable to find RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
434 talloc_free(tmp_ctx);
438 static TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name)
440 TR_COMM *cfg_comm = NULL;
442 for (cfg_comm = comms; NULL != cfg_comm; cfg_comm = cfg_comm->next) {
443 if (0==tr_name_cmp(cfg_comm->id, comm_name))
449 TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx)
451 TR_COMM_ITER *iter=talloc(mem_ctx, TR_COMM_ITER);
455 iter->cur_orig_head=NULL;
462 void tr_comm_iter_free(TR_COMM_ITER *iter)
468 TR_COMM *tr_comm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
472 /* find memberships for this realm */
473 for (iter->cur_memb=ctab->memberships;
474 iter->cur_memb!=NULL;
475 iter->cur_memb=iter->cur_memb->next) {
476 if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
477 return tr_comm_memb_get_comm(iter->cur_memb);
482 TR_COMM *tr_comm_iter_next(TR_COMM_ITER *iter)
484 for (iter->cur_memb=iter->cur_memb->next;
485 iter->cur_memb!=NULL;
486 iter->cur_memb=iter->cur_memb->next) {
487 if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
488 return tr_comm_memb_get_comm(iter->cur_memb);
493 /* iterate only over RPs */
494 TR_COMM *tr_comm_iter_first_rp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
498 /* find memberships for this realm */
499 for (iter->cur_memb=ctab->memberships;
500 iter->cur_memb!=NULL;
501 iter->cur_memb=iter->cur_memb->next) {
502 if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
503 (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
504 return tr_comm_memb_get_comm(iter->cur_memb);
509 TR_COMM *tr_comm_iter_next_rp(TR_COMM_ITER *iter)
511 for (iter->cur_memb=iter->cur_memb->next;
512 iter->cur_memb!=NULL;
513 iter->cur_memb=iter->cur_memb->next) {
514 if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
515 (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
516 return tr_comm_memb_get_comm(iter->cur_memb);
521 /* iterate only over IDPs */
522 TR_COMM *tr_comm_iter_first_idp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
526 /* find memberships for this realm */
527 for (iter->cur_memb=ctab->memberships;
528 iter->cur_memb!=NULL;
529 iter->cur_memb=iter->cur_memb->next) {
530 if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
531 (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
532 return tr_comm_memb_get_comm(iter->cur_memb);
537 TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter)
539 for (iter->cur_memb=iter->cur_memb->next;
540 iter->cur_memb!=NULL;
541 iter->cur_memb=iter->cur_memb->next) {
542 if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
543 (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
544 return tr_comm_memb_get_comm(iter->cur_memb);
549 static TR_REALM *tr_realm_new(TALLOC_CTX *mem_ctx)
551 TR_REALM *realm=talloc(mem_ctx, TR_REALM);
553 realm->role=TR_ROLE_UNKNOWN;
560 static void tr_realm_free(TR_REALM *realm)
565 static void tr_realm_set_rp(TR_REALM *realm, TR_RP_REALM *rp)
567 if (realm->idp!=NULL)
569 realm->role=TR_ROLE_RP;
573 static void tr_realm_set_idp(TR_REALM *realm, TR_IDP_REALM *idp)
577 realm->role=TR_ROLE_IDP;
581 TR_NAME *tr_realm_get_id(TR_REALM *realm)
583 switch (realm->role) {
585 return tr_rp_realm_get_id(realm->rp);
587 return tr_idp_realm_get_id(realm->idp);
594 TR_NAME *tr_realm_dup_id(TR_REALM *realm)
596 return tr_dup_name(tr_realm_get_id(realm));
599 /* Iterate over either sort of realm. Do not free the TR_REALM returned. It becomes
600 * undefined/invalid after the next operation affecting the iterator. */
601 TR_REALM *tr_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
604 if (iter->realm==NULL)
605 iter->realm=tr_realm_new(iter);
606 if (iter->realm==NULL)
609 /* find memberships for this comm */
610 for (iter->cur_memb=ctab->memberships;
611 iter->cur_memb!=NULL;
612 iter->cur_memb=iter->cur_memb->next) {
613 if (0==tr_name_cmp(iter->match,
614 tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) {
615 /* found a match, determine whether it's an rp realm or an idp realm */
616 if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL)
617 tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb));
618 else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL)
619 tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb));
621 if (iter->realm!=NULL)
622 tr_realm_free(iter->realm);
628 if (iter->realm!=NULL)
629 tr_realm_free(iter->realm);
634 TR_REALM *tr_realm_iter_next(TR_COMM_ITER *iter)
636 if (iter->realm==NULL)
639 /* find memberships for this comm */
640 for (iter->cur_memb=iter->cur_memb->next;
641 iter->cur_memb!=NULL;
642 iter->cur_memb=iter->cur_memb->next) {
643 if (0==tr_name_cmp(iter->match,
644 tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))) {
645 /* found a match, determine whether it's an rp realm or an idp realm */
646 if (tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL)
647 tr_realm_set_rp(iter->realm, tr_comm_memb_get_rp_realm(iter->cur_memb));
648 else if (tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL)
649 tr_realm_set_idp(iter->realm, tr_comm_memb_get_idp_realm(iter->cur_memb));
651 if (iter->realm!=NULL)
652 tr_realm_free(iter->realm);
658 if (iter->realm!=NULL)
659 tr_realm_free(iter->realm);
664 TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
668 /* find memberships for this comm */
669 for (iter->cur_memb=ctab->memberships;
670 iter->cur_memb!=NULL;
671 iter->cur_memb=iter->cur_memb->next) {
672 if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
673 (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
674 return tr_comm_memb_get_rp_realm(iter->cur_memb);
679 TR_RP_REALM *tr_rp_realm_iter_next(TR_COMM_ITER *iter)
681 for (iter->cur_memb=iter->cur_memb->next;
682 iter->cur_memb!=NULL;
683 iter->cur_memb=iter->cur_memb->next) {
684 if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
685 (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
686 return tr_comm_memb_get_rp_realm(iter->cur_memb);
691 TR_IDP_REALM *tr_idp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
695 /* find memberships for this comm */
696 for (iter->cur_memb=ctab->memberships;
697 iter->cur_memb!=NULL;
698 iter->cur_memb=iter->cur_memb->next) {
699 if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
700 (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
701 return tr_comm_memb_get_idp_realm(iter->cur_memb);
706 TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter)
708 for (iter->cur_memb=iter->cur_memb->next;
709 iter->cur_memb!=NULL;
710 iter->cur_memb=iter->cur_memb->next) {
711 if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
712 (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
713 return tr_comm_memb_get_idp_realm(iter->cur_memb);
718 /* iterators for all communities in a table */
719 TR_COMM *tr_comm_table_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
721 iter->cur_comm=ctab->comms;
722 return iter->cur_comm;
725 TR_COMM *tr_comm_table_iter_next(TR_COMM_ITER *iter)
727 return iter->cur_comm=iter->cur_comm->next;
730 const char *tr_comm_type_to_str(TR_COMM_TYPE type)
734 case TR_COMM_UNKNOWN:
749 /* iterate along the origin list for this member */
750 TR_COMM_MEMB *tr_comm_memb_iter_first(TR_COMM_ITER *iter, TR_COMM_MEMB *memb)
753 return iter->cur_memb;
756 TR_COMM_MEMB *tr_comm_memb_iter_next(TR_COMM_ITER *iter)
758 if (iter->cur_memb!=NULL)
759 iter->cur_memb=iter->cur_memb->origin_next;
760 return iter->cur_memb;
764 /* iterate over all memberships in the table */
765 TR_COMM_MEMB *tr_comm_memb_iter_all_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab)
767 iter->cur_memb=ctab->memberships;
768 iter->cur_orig_head=ctab->memberships;
769 return iter->cur_memb;
772 TR_COMM_MEMB *tr_comm_memb_iter_all_next(TR_COMM_ITER *iter)
774 if (iter->cur_memb->next==NULL) {
775 if (iter->cur_orig_head->next==NULL) {
779 iter->cur_memb=iter->cur_orig_head->next;
780 iter->cur_orig_head=iter->cur_orig_head->next;
783 iter->cur_memb=iter->cur_memb->origin_next;
785 return iter->cur_memb;
789 TR_COMM_TYPE tr_comm_type_from_str(const char *s)
791 if (strcmp(s, "apc")==0)
793 if (strcmp(s,"coi")==0)
795 return TR_COMM_UNKNOWN;
799 static int tr_comm_memb_destructor(void *obj)
801 TR_COMM_MEMB *memb=talloc_get_type_abort(obj, TR_COMM_MEMB);
802 if (memb->origin!=NULL)
803 tr_free_name(memb->origin);
806 tr_rp_realm_decref(memb->rp);
808 tr_idp_realm_decref(memb->idp);
809 if (memb->comm!=NULL)
810 tr_comm_decref(memb->comm);
811 if (memb->provenance!=NULL)
812 json_decref(memb->provenance);
816 TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx)
818 TR_COMM_MEMB *memb=talloc(mem_ctx, TR_COMM_MEMB);
821 memb->origin_next=NULL;
826 memb->provenance=NULL;
829 memb->times_expired=0;
830 memb->expiry=talloc(memb, struct timespec);
831 if (memb->expiry==NULL) {
835 *(memb->expiry)=(struct timespec){0,0};
836 talloc_set_destructor((void *)memb, tr_comm_memb_destructor);
841 void tr_comm_memb_free(TR_COMM_MEMB *memb)
846 /* Returns 0 if they are the same, nonzero if they differ.
847 * Ignores expiry, triggered, and times_expired, next pointers */
848 int tr_comm_memb_cmp(TR_COMM_MEMB *m1, TR_COMM_MEMB *m2)
850 if ((m1->idp==m2->idp) &&
852 (m1->comm==m2->comm) &&
853 (tr_comm_memb_provenance_cmp(m1, m2, 0)==0) &&
854 (m1->interval==m2->interval))
859 TR_REALM_ROLE tr_comm_memb_get_role(TR_COMM_MEMB *memb)
865 return TR_ROLE_UNKNOWN;
868 void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm)
870 if (memb->idp!=NULL) {
871 tr_idp_realm_decref(memb->idp);
875 tr_rp_realm_decref(memb->rp);
879 tr_rp_realm_incref(realm);
882 TR_RP_REALM *tr_comm_memb_get_rp_realm(TR_COMM_MEMB *memb)
887 void tr_comm_memb_set_idp_realm(TR_COMM_MEMB *memb, TR_IDP_REALM *realm)
889 if (memb->rp!=NULL) {
890 tr_rp_realm_decref(memb->rp);
894 tr_idp_realm_decref(memb->idp);
897 tr_idp_realm_incref(realm);
900 TR_IDP_REALM *tr_comm_memb_get_idp_realm(TR_COMM_MEMB *memb)
905 void tr_comm_memb_set_comm(TR_COMM_MEMB *memb, TR_COMM *comm)
907 if (memb->comm!=NULL)
908 tr_comm_decref(memb->comm);
910 tr_comm_incref(comm);
913 TR_COMM *tr_comm_memb_get_comm(TR_COMM_MEMB *memb)
918 static void tr_comm_memb_set_origin(TR_COMM_MEMB *memb, TR_NAME *origin)
920 if (memb->origin!=NULL)
921 tr_free_name(memb->origin);
925 TR_NAME *tr_comm_memb_get_origin(TR_COMM_MEMB *memb)
930 TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb)
932 if (memb->origin!=NULL)
933 return tr_dup_name(memb->origin);
937 json_t *tr_comm_memb_get_provenance(TR_COMM_MEMB *memb)
940 return memb->provenance;
944 void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov)
948 if (memb->provenance)
949 json_decref(memb->provenance);
951 memb->provenance=prov;
955 /* next line sets origin to NULL if provenance is empty because jansson
956 * routines return NULL on error */
957 s=json_string_value(json_array_get(prov, 0));
959 tr_comm_memb_set_origin(memb, NULL);
961 memb->origin=tr_new_name(s);
963 tr_comm_memb_set_origin(memb, NULL);
967 void tr_comm_memb_add_to_provenance(TR_COMM_MEMB *memb, TR_NAME *hop)
969 if (memb->provenance==NULL) {
970 memb->provenance=json_array();
971 if (memb->provenance==NULL) {
972 tr_err("tr_comm_memb_add_to_provenance: unable to allocate provenance list.");
975 /* this is the first entry in the provenance, so it is the origin */
976 tr_comm_memb_set_origin(memb,tr_dup_name(hop));
977 if (memb->origin==NULL) {
978 tr_err("tr_comm_memb_add_to_provenance: unable to allocate origin.");
979 json_decref(memb->provenance);
980 memb->provenance=NULL;
984 if (0!=json_array_append_new(memb->provenance, tr_name_to_json_string(hop)))
985 tr_err("tr_comm_memb_add_to_provenance: unable to extend provenance list.");
988 size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb)
990 if (memb->provenance==NULL)
992 return json_array_size(memb->provenance);
995 void tr_comm_memb_set_interval(TR_COMM_MEMB *memb, unsigned int interval)
997 memb->interval=interval;
1000 unsigned int tr_comm_memb_get_interval(TR_COMM_MEMB *memb)
1002 return memb->interval;
1005 void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time)
1008 *(memb->expiry)=(struct timespec){0,0};
1010 memb->expiry->tv_sec=time->tv_sec;
1011 memb->expiry->tv_nsec=time->tv_nsec;
1015 struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb)
1017 return memb->expiry;
1020 int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime)
1022 tr_debug("tr_comm_memb_is_expired: (cur->tv_sec>memb->expiry->tv_sec)=(%u > %u)=%s",
1024 memb->expiry->tv_sec,
1025 (curtime->tv_sec > memb->expiry->tv_sec)?"true":"false");
1027 return ((curtime->tv_sec > memb->expiry->tv_sec)
1028 || ((curtime->tv_sec == memb->expiry->tv_sec)
1029 &&(curtime->tv_nsec >= memb->expiry->tv_nsec)));
1032 void tr_comm_memb_set_triggered(TR_COMM_MEMB *memb, int trig)
1034 memb->triggered=trig;
1037 int tr_comm_memb_is_triggered(TR_COMM_MEMB *memb)
1039 return memb->triggered;
1042 void tr_comm_memb_reset_times_expired(TR_COMM_MEMB *memb)
1044 memb->times_expired=0;
1047 /* bumps the expiration count */
1048 void tr_comm_memb_expire(TR_COMM_MEMB *memb)
1050 /* avoid overflow */
1051 if (memb->times_expired+1>memb->times_expired)
1052 memb->times_expired++;
1055 unsigned int tr_comm_memb_get_times_expired(TR_COMM_MEMB *memb)
1057 return memb->times_expired;
1060 TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx)
1062 TR_COMM_TABLE *ctab=talloc(mem_ctx, TR_COMM_TABLE);
1065 ctab->memberships=NULL;
1066 ctab->idp_realms=NULL;
1067 ctab->rp_realms=NULL;
1072 void tr_comm_table_free(TR_COMM_TABLE *ctab)
1077 static TR_REALM_ROLE tr_comm_memb_role(TR_COMM_MEMB *memb)
1081 if (memb->idp!=NULL)
1084 return TR_ROLE_UNKNOWN;
1087 void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new)
1089 TR_COMM_MEMB *cur=NULL;
1091 /* TODO: further validate the member (must have valid comm and realm) */
1092 if ((new->next!=NULL) || (new->origin_next!=NULL)) {
1093 tr_debug("tr_comm_table_add_memb: attempting to add member already in a list.");
1096 /* handle the empty list case */
1097 if (ctab->memberships==NULL) {
1098 ctab->memberships=new;
1099 talloc_steal(ctab, new);
1103 /* The list was not empty. See if we already have a membership for this realm/comm/role */
1104 switch (tr_comm_memb_role(new)) {
1106 cur=tr_comm_table_find_rp_memb(ctab,
1107 tr_rp_realm_get_id(tr_comm_memb_get_rp_realm(new)),
1108 tr_comm_get_id(tr_comm_memb_get_comm(new)));
1111 cur=tr_comm_table_find_idp_memb(ctab,
1112 tr_idp_realm_get_id(tr_comm_memb_get_idp_realm(new)),
1113 tr_comm_get_id(tr_comm_memb_get_comm(new)));
1115 case TR_ROLE_UNKNOWN:
1117 tr_err("tr_comm_table_add_memb: realm with unknown role added.");
1122 /* no entry for this realm/comm/role, tack it on the end */
1123 for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) { }
1126 /* Found an entry. Add to the end of its same-origin list. */
1127 while (cur->origin_next!=NULL) {
1128 cur=cur->origin_next;
1130 cur->origin_next=new;
1133 talloc_steal(ctab, new);
1136 /* Remove memb from ctab. Do not free anything. Do nothing if memb not in ctab. */
1137 void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb)
1139 TR_COMM_MEMB *cur=NULL; /* for walking the main list */
1140 TR_COMM_MEMB *orig_cur=NULL; /* for walking the origin list */
1142 if ((memb==NULL) || (ctab->memberships==NULL))
1145 /* see if it's the first member */
1146 if (ctab->memberships==memb) {
1147 if (memb->origin_next!=NULL) {
1148 memb->origin_next->next=memb->next;
1149 ctab->memberships=memb->origin_next;
1151 ctab->memberships=memb->next;
1156 /* see if it's in first member's origin list */
1157 for (orig_cur=ctab->memberships;
1158 orig_cur->origin_next!=NULL;
1159 orig_cur=orig_cur->origin_next) {
1160 if (orig_cur->origin_next==memb) {
1161 orig_cur->origin_next=memb->origin_next;
1166 /* now we have to walk the rest of the tree */
1167 for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) {
1168 if (cur->next==memb) {
1169 /* it matched an entry on the main list */
1170 if (memb->origin_next==NULL)
1171 cur->next=memb->next; /* no origin list, just drop memb */
1173 /* replace the entry in the main list with the next element on the origin list */
1174 memb->origin_next->next=memb->next;
1175 cur->next=memb->origin_next;
1179 /* it was not on the main list, walk the origin list */
1180 for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
1181 if (orig_cur->origin_next==memb) {
1182 orig_cur->origin_next=memb->origin_next;
1183 return; /* just drop the element from the origin list */
1188 /* if we got here, cur->next was null. Still have to check the origin_next list */
1189 for (orig_cur=cur; orig_cur->origin_next!=NULL; orig_cur=orig_cur->origin_next) {
1190 if (orig_cur->origin_next==memb) {
1191 orig_cur->origin_next=memb->origin_next;
1192 return; /* just drop the element from the origin list */
1197 TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb)
1200 return tr_rp_realm_get_id(memb->rp);
1202 return tr_idp_realm_get_id(memb->idp);
1205 /* find a membership from any origin */
1206 TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
1208 TR_COMM_MEMB *cur=NULL;
1209 TR_NAME *cur_realm_name=NULL;
1211 for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
1212 cur_realm_name=tr_comm_memb_get_realm_id(cur);
1213 if (cur_realm_name==NULL) {
1214 tr_warning("tr_comm_table_find: encountered realm with no name.");
1217 if ((0==tr_name_cmp(realm, cur_realm_name)) &&
1218 (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
1225 /* find a membership from a particular origin */
1226 TR_COMM_MEMB *tr_comm_table_find_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
1228 TR_NAME *cur_orig=NULL;
1229 TR_COMM_MEMB *cur=tr_comm_table_find_memb(ctab, realm, comm);
1231 return NULL; /* no match */
1233 /* had a match for comm/realm; find origin match */
1235 if (((origin==NULL) && (cur_orig==NULL)) ||
1236 ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
1237 return cur; /* found a match */
1238 cur=cur->origin_next;
1240 return NULL; /* no match */
1244 /* find an idp membership regardless of its origin */
1245 TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
1247 TR_COMM_MEMB *cur=NULL;
1248 TR_IDP_REALM *idp_realm=NULL;
1250 for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
1251 idp_realm=tr_comm_memb_get_idp_realm(cur);
1252 if (idp_realm==NULL)
1253 continue; /* was not an idp */
1255 if ((0==tr_name_cmp(realm, idp_realm->realm_id)) &&
1256 (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
1263 /* find an idp membership from a particular origin */
1264 TR_COMM_MEMB *tr_comm_table_find_idp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
1266 TR_NAME *cur_orig=NULL;
1267 TR_COMM_MEMB *cur=tr_comm_table_find_idp_memb(ctab, realm, comm);
1269 return NULL; /* no match */
1271 /* had a match for comm/realm; find origin match */
1273 cur_orig=tr_comm_memb_get_origin(cur);
1274 if (((origin==NULL) && (cur_orig==NULL)) ||
1275 ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
1276 return cur; /* found a match */
1277 cur=cur->origin_next;
1279 return NULL; /* no match */
1282 /* find an rp membership from any origin */
1283 TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm)
1285 TR_COMM_MEMB *cur=NULL;
1286 TR_RP_REALM *rp_realm=NULL;
1288 for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
1289 rp_realm=tr_comm_memb_get_rp_realm(cur);
1291 continue; /* was not an rp */
1293 if ((0==tr_name_cmp(realm, tr_rp_realm_get_id(rp_realm))) &&
1294 (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur))))) {
1301 /* find an rp membership from a particular origin */
1302 TR_COMM_MEMB *tr_comm_table_find_rp_memb_origin(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
1304 TR_NAME *cur_orig=NULL;
1305 TR_COMM_MEMB *cur=tr_comm_table_find_rp_memb(ctab, realm, comm);
1307 return NULL; /* no match */
1309 /* had a match for comm/realm; find origin match */
1311 cur_orig=tr_comm_memb_get_origin(cur);
1312 if (((origin==NULL) && (cur_orig==NULL)) ||
1313 ((origin!=NULL) && (cur_orig!=NULL) && (0==tr_name_cmp(origin, cur_orig))))
1314 return cur; /* found a match */
1315 cur=cur->origin_next;
1317 return NULL; /* no match */
1320 TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id)
1322 return tr_comm_lookup(ctab->comms, comm_id);
1325 void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
1327 tr_comm_add(ctab->comms, new);
1328 if (ctab->comms!=NULL)
1329 talloc_steal(ctab, ctab->comms); /* make sure it's in the right context */
1332 void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm)
1334 tr_comm_remove(ctab->comms, comm);
1337 TR_RP_REALM *tr_comm_table_find_rp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
1339 return tr_rp_realm_lookup(ctab->rp_realms, realm_id);
1342 void tr_comm_table_add_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *new)
1344 tr_rp_realm_add(ctab->rp_realms, new);
1345 if (ctab->rp_realms!=NULL)
1346 talloc_steal(ctab, ctab->rp_realms); /* make sure it's in the right context */
1349 void tr_comm_table_remove_rp_realm(TR_COMM_TABLE *ctab, TR_RP_REALM *realm)
1351 tr_rp_realm_remove(ctab->rp_realms, realm);
1354 TR_IDP_REALM *tr_comm_table_find_idp_realm(TR_COMM_TABLE *ctab, TR_NAME *realm_id)
1356 return tr_idp_realm_lookup(ctab->idp_realms, realm_id);
1359 void tr_comm_table_add_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *new)
1361 tr_idp_realm_add(ctab->idp_realms, new);
1362 if (ctab->idp_realms!=NULL)
1363 talloc_steal(ctab, ctab->idp_realms); /* make sure it's in the right context */
1366 void tr_comm_table_remove_idp_realm(TR_COMM_TABLE *ctab, TR_IDP_REALM *realm)
1368 tr_idp_realm_remove(ctab->idp_realms, realm);
1372 /* how many communities in the table? */
1373 size_t tr_comm_table_size(TR_COMM_TABLE *ctab)
1376 TR_COMM *this=ctab->comms;
1384 /* clean up unreferenced realms, etc */
1385 void tr_comm_table_sweep(TR_COMM_TABLE *ctab)
1387 tr_rp_realm_sweep(ctab->rp_realms);
1388 tr_idp_realm_sweep(ctab->idp_realms);
1389 tr_comm_sweep(ctab->comms);
1393 const char *tr_realm_role_to_str(TR_REALM_ROLE role)
1405 TR_REALM_ROLE tr_realm_role_from_str(const char *s)
1407 if (strcmp(s, "idp")==0)
1409 if (strcmp(s, "rp")==0)
1411 return TR_ROLE_UNKNOWN;
1414 static char *tr_comm_table_append_provenance(char *ctable_s, json_t *prov)
1420 for (ii=0; ii<json_array_size(prov); ii++) {
1421 s=json_string_value(json_array_get(prov, ii));
1423 tmp=talloc_asprintf_append(ctable_s, "%s%s", s, ((ii + 1) == json_array_size(prov)) ? "" : ", ");
1432 char *tr_comm_table_to_str(TALLOC_CTX *mem_ctx, TR_COMM_TABLE *ctab)
1434 TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1435 char *ctable_s=NULL;
1437 #define append_on_success_helper(tab,tmp,expr) if(NULL==((tmp)=(expr))){(tab)=NULL;goto cleanup;}(tab)=(tmp)
1439 TR_COMM_MEMB *p1=NULL; /* for walking the main list */
1440 TR_COMM_MEMB *p2=NULL; /* for walking the same-origin lists */
1442 ctable_s=talloc_asprintf(tmp_ctx, ">> Membership table start <<\n");
1446 for (p1=ctab->memberships; p1!=NULL; p1=p1->next) {
1447 append_on_success_helper(
1449 talloc_asprintf_append(ctable_s, "* %s %s/%s\n %s (%p) - prov: ",
1450 tr_realm_role_to_str(tr_comm_memb_get_role(p1)),
1451 tr_comm_memb_get_realm_id(p1)->buf,
1452 tr_comm_get_id(tr_comm_memb_get_comm(p1))->buf,
1453 (tr_comm_memb_get_origin(p1)==NULL)?"null origin":(tr_comm_memb_get_origin(p1)->buf),
1456 append_on_success_helper(ctable_s, tmp, tr_comm_table_append_provenance(ctable_s, p1->provenance));
1458 append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
1460 for (p2=p1->origin_next; p2!=NULL; p2=p2->origin_next) {
1461 append_on_success_helper(
1463 talloc_asprintf_append(ctable_s, " %s (%p) - prov: ",
1464 (tr_comm_memb_get_origin(p2)==NULL)?"null origin":(tr_comm_memb_get_origin(p2)->buf),
1466 append_on_success_helper(ctable_s, tmp, tr_comm_table_append_provenance(ctable_s, p2->provenance));
1467 append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
1469 append_on_success_helper(ctable_s, tmp, talloc_strdup_append_buffer(ctable_s, "\n"));
1474 talloc_steal(mem_ctx, ctable_s);
1476 talloc_free(tmp_ctx);
1480 void tr_comm_table_print(FILE *f, TR_COMM_TABLE *ctab)
1482 char *s=tr_comm_table_to_str(NULL, ctab);