677a5b8686c835997b8cf13e917f15e27ade9e50
[trust_router.git] / common / tr_comm.c
1 /*
2  * Copyright (c) 2012, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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.
32  *
33  */
34
35 #include <jansson.h>
36 #include <talloc.h>
37
38 #include <tr_rp.h>
39 #include <tr_idp.h>
40 #include <trust_router/tr_name.h>
41 #include <tr_comm.h>
42 #include <tr_debug.h>
43
44
45 /* static prototypes */
46 static TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb);
47
48
49 static int tr_comm_destructor(void *obj)
50 {
51   TR_COMM *comm=talloc_get_type_abort(obj, TR_COMM);
52   if (comm->id!=NULL)
53     tr_free_name(comm->id);
54   if (comm->owner_realm!=NULL)
55     tr_free_name(comm->owner_realm);
56   if (comm->owner_contact!=NULL)
57     tr_free_name(comm->owner_contact);
58   return 0;
59 }
60
61 TR_COMM *tr_comm_new(TALLOC_CTX *mem_ctx)
62 {
63   TR_COMM *comm=talloc(mem_ctx, TR_COMM);
64   if (comm!=NULL) {
65     comm->next=NULL;
66     comm->id=NULL;
67     comm->type=TR_COMM_UNKNOWN;
68     comm->apcs=NULL;
69     comm->owner_realm=NULL;
70     comm->owner_contact=NULL;
71     comm->expiration_interval=0;
72     comm->refcount=0;
73     talloc_set_destructor((void *)comm, tr_comm_destructor);
74   }
75   return comm;
76 }
77
78 void tr_comm_free(TR_COMM *comm)
79 {
80   talloc_free(comm);
81 }
82
83 void tr_comm_set_id(TR_COMM *comm, TR_NAME *id)
84 {
85   if (comm->id != NULL)
86     tr_free_name(comm->id);
87   comm->id=id;
88 }
89
90 void tr_comm_incref(TR_COMM *comm)
91 {
92   comm->refcount++;
93 }
94
95 void tr_comm_decref(TR_COMM *comm)
96 {
97   if (comm->refcount>0)
98     comm->refcount--;
99 }
100
101 TR_APC *tr_comm_get_apcs(TR_COMM *comm)
102 {
103   return comm->apcs;
104 }
105
106 TR_NAME *tr_comm_get_id(TR_COMM *comm)
107 {
108   return comm->id;
109 }
110
111 TR_NAME *tr_comm_dup_id(TR_COMM *comm)
112 {
113   return tr_dup_name(comm->id);
114 }
115
116 void tr_comm_set_type(TR_COMM *comm, TR_COMM_TYPE type)
117 {
118   comm->type=type;
119 }
120
121 TR_COMM_TYPE tr_comm_get_type(TR_COMM *comm)
122 {
123   return comm->type;
124 }
125
126 void tr_comm_set_owner_realm(TR_COMM *comm, TR_NAME *realm)
127 {
128   if (comm->owner_realm!=NULL)
129     tr_free_name(comm->owner_realm);
130   comm->owner_realm=realm;
131 }
132
133 TR_NAME *tr_comm_get_owner_realm(TR_COMM *comm)
134 {
135   return comm->owner_realm;
136 }
137
138 TR_NAME *tr_comm_dup_owner_realm(TR_COMM *comm)
139 {
140   return tr_dup_name(comm->owner_realm);
141 }
142
143 void tr_comm_set_owner_contact(TR_COMM *comm, TR_NAME *contact)
144 {
145   if (comm->owner_contact != NULL)
146     tr_free_name(comm->owner_contact);
147   comm->owner_contact=contact;
148 }
149
150 TR_NAME *tr_comm_get_owner_contact(TR_COMM *comm)
151 {
152   return comm->owner_contact;
153 }
154
155 TR_NAME *tr_comm_dup_owner_contact(TR_COMM *comm)
156 {
157   return tr_dup_name(comm->owner_contact);
158 }
159
160 unsigned int tr_comm_get_refcount(TR_COMM *comm)
161 {
162   return comm->refcount;
163 }
164
165 /* add to the table if it's a new membership or has a shorter
166  * provenance list than our existing membership */
167 static void tr_comm_add_if_shorter(TR_COMM_TABLE *ctab, TR_COMM_MEMB *existing, TR_COMM_MEMB *newmemb)
168 {
169   if (existing==NULL) {
170     /* not in the table */
171     tr_comm_table_add_memb(ctab, newmemb);
172   } else {
173     /* Had an entry. Replace if we have shorter provenance. */
174     if (tr_comm_memb_provenance_len(newmemb) < tr_comm_memb_provenance_len(existing)) {
175       tr_comm_table_remove_memb(ctab, existing);
176       tr_comm_memb_free(existing);
177       tr_comm_table_add_memb(ctab, newmemb);
178     } 
179   }
180 }
181
182 /* does not take responsibility for freeing IDP realm */
183 void tr_comm_add_idp_realm(TR_COMM_TABLE *ctab,
184                            TR_COMM *comm,
185                            TR_IDP_REALM *realm,
186                            json_t *provenance,
187                            struct timespec *expiry)
188 {
189   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
190   TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
191   TR_COMM_MEMB *existing=NULL;
192
193   if (newmemb==NULL) {
194     tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
195     talloc_free(tmp_ctx);
196     return;
197   }
198
199   tr_comm_memb_set_idp_realm(newmemb, realm);
200   tr_comm_memb_set_comm(newmemb, comm);
201   tr_comm_memb_set_provenance(newmemb, provenance);
202   tr_comm_memb_set_expiry(newmemb, expiry);
203
204   existing=tr_comm_table_find_idp_memb(ctab,
205                                        tr_idp_realm_get_id(realm),
206                                        tr_comm_get_id(comm),
207                                        tr_comm_memb_get_origin(newmemb));
208   tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
209   talloc_free(tmp_ctx);
210 }
211
212 /* does not take responsibility for freeing RP realm */
213 void tr_comm_add_rp_realm(TR_COMM_TABLE *ctab,
214                           TR_COMM *comm,
215                           TR_RP_REALM *realm,
216                           json_t *provenance,
217                           struct timespec *expiry)
218 {
219   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
220   TR_COMM_MEMB *newmemb=tr_comm_memb_new(tmp_ctx);
221   TR_COMM_MEMB *existing=NULL;
222
223   if (newmemb==NULL) {
224     tr_err("tr_comm_add_idp_realm: unable to allocate new membership record.");
225     talloc_free(tmp_ctx);
226     return;
227   }
228
229   tr_comm_memb_set_rp_realm(newmemb, realm);
230   tr_comm_memb_set_comm(newmemb, comm);
231   tr_comm_memb_set_provenance(newmemb, provenance);
232   tr_comm_memb_set_expiry(newmemb, expiry);
233
234   existing=tr_comm_table_find_rp_memb(ctab,
235                                       tr_rp_realm_get_id(realm),
236                                       tr_comm_get_id(comm),
237                                       tr_comm_memb_get_origin(newmemb));
238   tr_comm_add_if_shorter(ctab, existing, newmemb); /* takes newmemb out of tmp_ctx if needed */
239   talloc_free(tmp_ctx);
240 }
241
242 static TR_COMM *tr_comm_tail(TR_COMM *comm)
243 {
244   if (comm==NULL)
245     return comm;
246
247   while (comm->next!=NULL)
248     comm=comm->next;
249   return comm;
250 }
251
252 /* All list members are in the talloc context of the head.
253  * This will require careful thought if entries are ever removed
254  * Call like comms=tr_comm_add_func(comms, new_comm);
255  * or just use the tr_comm_add(comms, new) macro. */
256 #define tr_comm_add(comms, new) ((comms)=tr_comm_add_func((comms), (new)))
257 static TR_COMM *tr_comm_add_func(TR_COMM *comms, TR_COMM *new)
258 {
259   if (comms==NULL)
260     comms=new;
261   else {
262     tr_comm_tail(comms)->next=new;
263     while(new!=NULL) {
264       talloc_steal(comms, new);
265       new=new->next;
266     }
267   }
268   return comms;
269 }
270
271 /* guarantees comm is not in the list, not an error if it was't there */
272 #define tr_comm_remove(comms, c) ((comms)=tr_comm_remove_func((comms), (c)))
273 static TR_COMM *tr_comm_remove_func(TR_COMM *comms, TR_COMM *remove)
274 {
275   TR_COMM *this=comms;
276
277   if ((this==NULL) || (this==remove))
278     return NULL;
279   
280   for (; this->next!=NULL; this=this->next) {
281     if (this->next==remove)
282       this->next=remove->next;
283   }
284   return comms;
285 }
286
287 TR_IDP_REALM *tr_comm_find_idp(TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *idp_realm)
288 {
289   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
290   TR_COMM_ITER *iter=NULL;
291   TR_IDP_REALM *this_idp=NULL;
292
293   if ((NULL==ctab) || (NULL==comm) || (NULL==idp_realm)) {
294     talloc_free(tmp_ctx);
295     return NULL;
296   }
297
298   iter=tr_comm_iter_new(tmp_ctx);
299   for (this_idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
300        this_idp!=NULL;
301        this_idp=tr_idp_realm_iter_next(iter)) {
302     if (0==tr_name_cmp(idp_realm, tr_idp_realm_get_id(this_idp))) {
303       tr_debug("tr_comm_find_idp: Found IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
304       talloc_free(tmp_ctx);
305       return this_idp;
306     }
307   }
308   tr_debug("tr_comm_find_idp: Unable to find IdP %s in community %s.", idp_realm->buf, tr_comm_get_id(comm)->buf);
309   talloc_free(tmp_ctx);
310   return NULL;
311 }
312
313 TR_RP_REALM *tr_comm_find_rp (TR_COMM_TABLE *ctab, TR_COMM *comm, TR_NAME *rp_realm)
314 {
315   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
316   TR_COMM_ITER *iter=NULL;
317   TR_RP_REALM *this_rp=NULL;
318
319   if ((NULL==ctab) || (NULL==comm) || (NULL==rp_realm)) {
320     talloc_free(tmp_ctx);
321     return NULL;
322   }
323
324   iter=tr_comm_iter_new(tmp_ctx);
325   for (this_rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
326        this_rp!=NULL;
327        this_rp=tr_rp_realm_iter_next(iter)) {
328     if (0==tr_name_cmp(rp_realm, tr_rp_realm_get_id(this_rp))) {
329       tr_debug("tr_comm_find_rp: Found RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
330       talloc_free(tmp_ctx);
331       return this_rp;
332     }
333   }
334   tr_debug("tr_comm_find_rp: Unable to find RP %s in community %s.", rp_realm->buf, tr_comm_get_id(comm)->buf);
335   talloc_free(tmp_ctx);
336   return NULL;
337 }
338
339 static TR_COMM *tr_comm_lookup(TR_COMM *comms, TR_NAME *comm_name) 
340 {
341   TR_COMM *cfg_comm = NULL;
342
343   for (cfg_comm = comms; NULL != cfg_comm; cfg_comm = cfg_comm->next) {
344     if (0==tr_name_cmp(cfg_comm->id, comm_name))
345       return cfg_comm;
346   }
347   return NULL;
348 }
349
350 TR_COMM_ITER *tr_comm_iter_new(TALLOC_CTX *mem_ctx)
351 {
352   TR_COMM_ITER *iter=talloc(mem_ctx, TR_COMM_ITER);
353   if (iter!=NULL) {
354     iter->cur_memb=NULL;
355     iter->match=NULL;
356   }
357   return iter;
358 }
359
360 void tr_comm_iter_free(TR_COMM_ITER *iter)
361 {
362   talloc_free(iter);
363 }
364
365
366 TR_COMM *tr_comm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
367 {
368   iter->match=realm;
369
370   /* find memberships for this realm */
371   for (iter->cur_memb=ctab->memberships;
372        iter->cur_memb!=NULL;
373        iter->cur_memb=iter->cur_memb->next) {
374     if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
375       return tr_comm_memb_get_comm(iter->cur_memb);
376   }
377   return NULL;
378 }
379
380 TR_COMM *tr_comm_iter_next(TR_COMM_ITER *iter)
381 {
382   for (iter->cur_memb=iter->cur_memb->next;
383        iter->cur_memb!=NULL;
384        iter->cur_memb=iter->cur_memb->next) {
385     if (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb)))
386       return tr_comm_memb_get_comm(iter->cur_memb);
387   }
388   return NULL;
389 }
390
391 /* iterate only over RPs */
392 TR_COMM *tr_comm_iter_first_rp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
393 {
394   iter->match=realm;
395
396   /* find memberships for this realm */
397   for (iter->cur_memb=ctab->memberships;
398        iter->cur_memb!=NULL;
399        iter->cur_memb=iter->cur_memb->next) {
400     if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
401         (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
402       return tr_comm_memb_get_comm(iter->cur_memb);
403   }
404   return NULL;
405 }
406
407 TR_COMM *tr_comm_iter_next_rp(TR_COMM_ITER *iter)
408 {
409   for (iter->cur_memb=iter->cur_memb->next;
410        iter->cur_memb!=NULL;
411        iter->cur_memb=iter->cur_memb->next) {
412     if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
413         (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
414       return tr_comm_memb_get_comm(iter->cur_memb);
415   }
416   return NULL;
417 }
418
419 /* iterate only over IDPs */
420 TR_COMM *tr_comm_iter_first_idp(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *realm)
421 {
422   iter->match=realm;
423
424   /* find memberships for this realm */
425   for (iter->cur_memb=ctab->memberships;
426        iter->cur_memb!=NULL;
427        iter->cur_memb=iter->cur_memb->next) {
428     if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
429         (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
430       return tr_comm_memb_get_comm(iter->cur_memb);
431   }
432   return NULL;
433 }
434
435 TR_COMM *tr_comm_iter_next_idp(TR_COMM_ITER *iter)
436 {
437   for (iter->cur_memb=iter->cur_memb->next;
438        iter->cur_memb!=NULL;
439        iter->cur_memb=iter->cur_memb->next) {
440     if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
441         (0==tr_name_cmp(iter->match, tr_comm_memb_get_realm_id(iter->cur_memb))))
442       return tr_comm_memb_get_comm(iter->cur_memb);
443   }
444   return NULL;
445 }
446
447 TR_RP_REALM *tr_rp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
448 {
449   iter->match=comm;
450
451   /* find memberships for this comm */
452   for (iter->cur_memb=ctab->memberships;
453        iter->cur_memb!=NULL;
454        iter->cur_memb=iter->cur_memb->next) {
455     if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
456         (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
457       return tr_comm_memb_get_rp_realm(iter->cur_memb);
458   }
459   return NULL;
460 }
461
462 TR_RP_REALM *tr_rp_realm_iter_next(TR_COMM_ITER *iter)
463 {
464   for (iter->cur_memb=iter->cur_memb->next;
465        iter->cur_memb!=NULL;
466        iter->cur_memb=iter->cur_memb->next) {
467     if ((tr_comm_memb_get_rp_realm(iter->cur_memb)!=NULL) &&
468         (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
469       return tr_comm_memb_get_rp_realm(iter->cur_memb);
470   }
471   return NULL;
472 }
473
474 TR_IDP_REALM *tr_idp_realm_iter_first(TR_COMM_ITER *iter, TR_COMM_TABLE *ctab, TR_NAME *comm)
475 {
476   iter->match=comm;
477
478   /* find memberships for this comm */
479   for (iter->cur_memb=ctab->memberships;
480        iter->cur_memb!=NULL;
481        iter->cur_memb=iter->cur_memb->next) {
482     if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
483         (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
484       return tr_comm_memb_get_idp_realm(iter->cur_memb);
485   }
486   return NULL;
487 }
488
489 TR_IDP_REALM *tr_idp_realm_iter_next(TR_COMM_ITER *iter)
490 {
491   for (iter->cur_memb=iter->cur_memb->next;
492        iter->cur_memb!=NULL;
493        iter->cur_memb=iter->cur_memb->next) {
494     if ((tr_comm_memb_get_idp_realm(iter->cur_memb)!=NULL) &&
495         (0==tr_name_cmp(iter->match, tr_comm_get_id(tr_comm_memb_get_comm(iter->cur_memb)))))
496       return tr_comm_memb_get_idp_realm(iter->cur_memb);
497   }
498   return NULL;
499 }
500
501 const char *tr_comm_type_to_str(TR_COMM_TYPE type)
502 {
503   const char *s=NULL;
504   switch(type) {
505   case TR_COMM_UNKNOWN:
506     s="unknown";
507     break;
508   case TR_COMM_APC:
509     s="apc";
510     break;
511   case TR_COMM_COI:
512     s="coi";
513     break;
514   default:
515     s="invalid";
516   }
517   return s;
518 }
519
520 TR_COMM_TYPE tr_comm_type_from_str(const char *s)
521 {
522   if (strcmp(s, "apc")==0)
523     return TR_COMM_APC;
524   if (strcmp(s,"coi")==0)
525     return TR_COMM_COI;
526   return TR_COMM_UNKNOWN;
527 }
528
529
530 static int tr_comm_memb_destructor(void *obj)
531 {
532   TR_COMM_MEMB *memb=talloc_get_type_abort(obj, TR_COMM_MEMB);
533   if (memb->origin!=NULL)
534     tr_free_name(memb->origin);
535
536   if (memb->rp!=NULL)
537     tr_rp_realm_decref(memb->rp);
538   if (memb->idp!=NULL)
539     tr_idp_realm_decref(memb->idp);
540   if (memb->comm!=NULL)
541     tr_comm_decref(memb->comm);
542   if (memb->provenance!=NULL)
543     json_decref(memb->provenance);
544   return 0;
545 }
546
547 TR_COMM_MEMB *tr_comm_memb_new(TALLOC_CTX *mem_ctx)
548 {
549   TR_COMM_MEMB *memb=talloc(mem_ctx, TR_COMM_MEMB);
550   if (memb!=NULL) {
551     memb->next=NULL;
552     memb->idp=NULL;
553     memb->rp=NULL;
554     memb->comm=NULL;
555     memb->origin=NULL;
556     memb->provenance=NULL;
557     memb->expiry=NULL;
558     talloc_set_destructor(memb, tr_comm_memb_destructor);
559   }
560   return memb;
561 }
562
563 void tr_comm_memb_free(TR_COMM_MEMB *memb)
564 {
565   talloc_free(memb);
566 }
567
568 void tr_comm_memb_set_rp_realm(TR_COMM_MEMB *memb, TR_RP_REALM *realm)
569 {
570   if (memb->idp!=NULL) {
571     tr_idp_realm_decref(memb->idp);
572     memb->idp=NULL;
573   }
574   if (memb->rp!=NULL)
575     tr_rp_realm_decref(memb->rp);
576
577
578   memb->rp=realm;
579   tr_rp_realm_incref(realm);
580 }
581
582 TR_RP_REALM *tr_comm_memb_get_rp_realm(TR_COMM_MEMB *memb)
583 {
584   return memb->rp;
585 }
586
587 void tr_comm_memb_set_idp_realm(TR_COMM_MEMB *memb, TR_IDP_REALM *realm)
588 {
589   if (memb->rp!=NULL) {
590     tr_rp_realm_decref(memb->rp);
591     memb->rp=NULL;
592   }
593   if (memb->idp!=NULL)
594     tr_idp_realm_decref(memb->idp);
595
596   memb->idp=realm;
597   tr_idp_realm_incref(realm);
598 }
599
600 TR_IDP_REALM *tr_comm_memb_get_idp_realm(TR_COMM_MEMB *memb)
601 {
602   return memb->idp;
603 }
604
605 void tr_comm_memb_set_comm(TR_COMM_MEMB *memb, TR_COMM *comm)
606 {
607   if (memb->comm!=NULL)
608     tr_comm_decref(memb->comm);
609   memb->comm=comm;
610   tr_comm_incref(comm);
611 }
612
613 TR_COMM *tr_comm_memb_get_comm(TR_COMM_MEMB *memb)
614 {
615   return memb->comm;
616 }
617
618 static void tr_comm_memb_set_origin(TR_COMM_MEMB *memb, TR_NAME *origin)
619 {
620   if (memb->origin!=NULL)
621     tr_free_name(memb->origin);
622   memb->origin=origin;
623 }
624
625 TR_NAME *tr_comm_memb_get_origin(TR_COMM_MEMB *memb)
626 {
627   return memb->origin;
628 }
629
630 TR_NAME *tr_comm_memb_dup_origin(TR_COMM_MEMB *memb)
631 {
632   if (memb->origin!=NULL)
633     return tr_dup_name(memb->origin);
634   return NULL;
635 }
636
637 void tr_comm_memb_set_provenance(TR_COMM_MEMB *memb, json_t *prov)
638 {
639   if (memb->provenance)
640     json_decref(memb->provenance);
641
642   memb->provenance=prov;
643   if (prov!=NULL) {
644     json_incref(prov);
645
646     /* next line sets origin to NULL if provenance is empty because jansson
647      * routines return NULL on error */
648     memb->origin=tr_new_name(json_string_value(json_array_get(prov, 0)));
649   } else {
650     tr_comm_memb_set_origin(memb, NULL);
651   }
652 }
653
654 void tr_comm_memb_add_to_provenance(TR_COMM_MEMB *memb, TR_NAME *hop)
655 {
656   if (memb->provenance==NULL) {
657     memb->provenance=json_array();
658     if (memb->provenance==NULL) {
659       tr_err("tr_comm_memb_add_to_provenance: unable to allocate provenance list.");
660       return;
661     }
662     /* this is the first entry in the provenance, so it is the origin */
663     tr_comm_memb_set_origin(memb,tr_dup_name(hop));
664     if (memb->origin==NULL) {
665       tr_err("tr_comm_memb_add_to_provenance: unable to allocate origin.");
666       json_decref(memb->provenance);
667       memb->provenance=NULL;
668       return;
669     }
670   }
671   if (0!=json_array_append_new(memb->provenance, tr_name_to_json_string(hop)))
672     tr_err("tr_comm_memb_add_to_provenance: unable to extend provenance list.");
673 }
674
675 size_t tr_comm_memb_provenance_len(TR_COMM_MEMB *memb)
676 {
677   if (memb->provenance==NULL)
678     return 0;
679   return json_array_size(memb->provenance);
680 }
681
682 void tr_comm_memb_set_expiry(TR_COMM_MEMB *memb, struct timespec *time)
683 {
684   memb->expiry=time;
685 }
686
687 struct timespec *tr_comm_memb_get_expiry(TR_COMM_MEMB *memb)
688 {
689   return memb->expiry;
690 }
691
692 int tr_comm_memb_is_expired(TR_COMM_MEMB *memb, struct timespec *curtime)
693 {
694   return ((curtime->tv_sec > memb->expiry->tv_sec)
695          || ((curtime->tv_sec == memb->expiry->tv_sec)
696             &&(curtime->tv_nsec >= memb->expiry->tv_nsec)));
697 }
698
699 TR_COMM_TABLE *tr_comm_table_new(TALLOC_CTX *mem_ctx)
700 {
701   TR_COMM_TABLE *ctab=talloc(mem_ctx, TR_COMM_TABLE);
702   if (ctab!=NULL) {
703     ctab->comms=NULL;
704     ctab->memberships=NULL;
705   }
706   return ctab;
707 }
708
709 void tr_comm_table_free(TR_COMM_TABLE *ctab)
710 {
711   talloc_free(ctab);
712 }
713
714 void tr_comm_table_add_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *new)
715 {
716   TR_COMM_MEMB *cur=NULL;
717
718   if (ctab->memberships==NULL) {
719     ctab->memberships=new;
720     talloc_steal(ctab, new);
721   } else {
722     for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) { }
723     cur->next=new;
724   }
725   talloc_steal(ctab, new);
726 }
727
728 /* Remove memb from ctab. Do not free anything. Do nothing if memb not in ctab. */
729 void tr_comm_table_remove_memb(TR_COMM_TABLE *ctab, TR_COMM_MEMB *memb)
730 {
731   TR_COMM_MEMB *cur=NULL;
732
733   if ((memb==NULL) || (ctab->memberships==NULL)) {
734     return;
735   } else if (ctab->memberships==memb) {
736     ctab->memberships=memb->next;
737     return;
738   } else {
739     for (cur=ctab->memberships; cur->next!=NULL; cur=cur->next) {
740       if (cur->next==memb) {
741         cur->next=memb->next;
742         return;
743       }
744     }
745   }
746 }
747
748 static TR_NAME *tr_comm_memb_get_realm_id(TR_COMM_MEMB *memb)
749 {
750   if (memb->rp!=NULL)
751     return tr_rp_realm_get_id(memb->rp);
752   else
753     return tr_idp_realm_get_id(memb->idp);
754 }
755
756 TR_COMM_MEMB *tr_comm_table_find_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
757 {
758   TR_COMM_MEMB *cur=NULL;
759   TR_NAME *cur_realm_name=NULL;
760
761   for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
762     cur_realm_name=tr_comm_memb_get_realm_id(cur);
763     if (cur_realm_name==NULL) {
764       tr_warning("tr_comm_table_find: encountered realm with no name.");
765       continue;
766     }
767     if ((0==tr_name_cmp(realm, cur_realm_name)) &&
768         (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) &&
769         (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur)))) {
770       return cur;
771     }
772   }
773   return NULL;
774 }
775
776 TR_COMM_MEMB *tr_comm_table_find_idp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
777 {
778   TR_COMM_MEMB *cur=NULL;
779   TR_IDP_REALM *idp_realm=NULL;
780
781   for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
782     idp_realm=tr_comm_memb_get_idp_realm(cur);
783     if (idp_realm==NULL)
784       continue; /* was not an idp */
785
786     if ((0==tr_name_cmp(realm, idp_realm->realm_id)) &&
787         (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) &&
788         (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur)))) {
789       return cur;
790     }
791   }
792   return NULL;
793 }
794
795 TR_COMM_MEMB *tr_comm_table_find_rp_memb(TR_COMM_TABLE *ctab, TR_NAME *realm, TR_NAME *comm, TR_NAME *origin)
796 {
797   TR_COMM_MEMB *cur=NULL;
798   TR_RP_REALM *rp_realm=NULL;
799
800   for (cur=ctab->memberships; cur!=NULL; cur=cur->next) {
801     rp_realm=tr_comm_memb_get_rp_realm(cur);
802     if (rp_realm==NULL)
803       continue; /* was not an rp */
804
805     if ((0==tr_name_cmp(realm, tr_rp_realm_get_id(rp_realm))) &&
806         (0==tr_name_cmp(comm, tr_comm_get_id(tr_comm_memb_get_comm(cur)))) &&
807         (0==tr_name_cmp(origin, tr_comm_memb_get_origin(cur)))) {
808       return cur;
809     }
810   }
811   return NULL;
812 }
813
814 TR_COMM *tr_comm_table_find_comm(TR_COMM_TABLE *ctab, TR_NAME *comm_id)
815 {
816   return tr_comm_lookup(ctab->comms, comm_id);
817 }
818
819 void tr_comm_table_add_comm(TR_COMM_TABLE *ctab, TR_COMM *new)
820 {
821   tr_comm_add(ctab->comms, new);
822 }
823
824 void tr_comm_table_remove_comm(TR_COMM_TABLE *ctab, TR_COMM *comm)
825 {
826   tr_comm_remove(ctab->comms, comm);
827 }
828
829 /* how many communities in the table? */
830 size_t tr_comm_table_size(TR_COMM_TABLE *ctab)
831 {
832   size_t count=0;
833   TR_COMM *this=ctab->comms;
834   while(this!=NULL) {
835     this=this->next;
836     count++;
837   }
838   return count;
839 }
840
841
842 const char *tr_realm_role_to_str(TR_REALM_ROLE role)
843 {
844   switch(role) {
845   case TR_ROLE_IDP:
846     return "idp";
847   case TR_ROLE_RP:
848     return "rp";
849   default:
850     return NULL;
851   }
852 }
853
854 TR_REALM_ROLE tr_realm_role_from_str(const char *s)
855 {
856   if (strcmp(s, "idp")==0)
857     return TR_ROLE_IDP;
858   if (strcmp(s, "rp")==0)
859     return TR_ROLE_RP;
860   return TR_ROLE_UNKNOWN;
861 }
862