Fix misleading indentation
[trust_router.git] / common / tr_config.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 <stdlib.h>
36 #include <string.h>
37 #include <jansson.h>
38 #include <dirent.h>
39 #include <talloc.h>
40
41 #include <tr_cfgwatch.h>
42 #include <tr_comm.h>
43 #include <tr_config.h>
44 #include <tr_gss.h>
45 #include <tr_debug.h>
46 #include <tr_filter.h>
47 #include <trust_router/tr_constraint.h>
48 #include <tr_idp.h>
49 #include <tr.h>
50 #include <trust_router/trp.h>
51
52 void tr_print_config (TR_CFG *cfg) {
53   tr_notice("tr_print_config: Logging running trust router configuration.");
54   tr_print_comms(cfg->ctable);
55 }
56
57 void tr_print_comms (TR_COMM_TABLE *ctab)
58 {
59   TR_COMM *comm = NULL;
60
61   for (comm = ctab->comms; NULL != comm; comm = comm->next) {
62     tr_notice("tr_print_config: Community %s:", comm->id->buf);
63
64     tr_notice("tr_print_config:  - Member IdPs:");
65     tr_print_comm_idps(ctab, comm);
66
67     tr_notice("tr_print_config:  - Member RPs:");
68     tr_print_comm_rps(ctab, comm);
69   }
70 }
71
72 void tr_print_comm_idps(TR_COMM_TABLE *ctab, TR_COMM *comm)
73 {
74   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
75   TR_COMM_ITER *iter=NULL;
76   TR_IDP_REALM *idp = NULL;
77   char *s=NULL;
78
79   iter=tr_comm_iter_new(tmp_ctx);
80   if (iter==NULL) {
81     tr_notice("tr_print_config: unable to allocate IdP iterator.");
82     talloc_free(tmp_ctx);
83     return;
84   }
85   
86   for (idp=tr_idp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
87        NULL!=idp;
88        idp=tr_idp_realm_iter_next(iter)) {
89     s=tr_idp_realm_to_str(tmp_ctx, idp);
90     if (s!=NULL)
91       tr_notice("tr_print_config:    - @%s", s);
92     else
93       tr_notice("tr_print_config: unable to allocate IdP output string.");
94   }
95   talloc_free(tmp_ctx);
96 }
97
98 void tr_print_comm_rps(TR_COMM_TABLE *ctab, TR_COMM *comm)
99 {
100   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
101   TR_COMM_ITER *iter=NULL;
102   TR_RP_REALM *rp = NULL;
103   char *s=NULL;
104
105   iter=tr_comm_iter_new(tmp_ctx);
106   if (iter==NULL) {
107     tr_notice("tr_print_config: unable to allocate RP iterator.");
108     talloc_free(tmp_ctx);
109     return;
110   }
111   
112   for (rp=tr_rp_realm_iter_first(iter, ctab, tr_comm_get_id(comm));
113        NULL!=rp;
114        rp=tr_rp_realm_iter_next(iter)) {
115     s=tr_rp_realm_to_str(tmp_ctx, rp);
116     if (s!=NULL)
117       tr_notice("tr_print_config:    - @%s", s);
118     else
119       tr_notice("tr_print_config: unable to allocate RP output string.");
120   }
121   talloc_free(tmp_ctx);
122 }
123
124 TR_CFG *tr_cfg_new(TALLOC_CTX *mem_ctx)
125 {
126   TR_CFG *cfg=talloc(mem_ctx, TR_CFG);
127   if (cfg!=NULL) {
128     cfg->internal=NULL;
129     cfg->rp_clients=NULL;
130     cfg->peers=NULL;
131     cfg->default_servers=NULL;
132     cfg->ctable=tr_comm_table_new(cfg);
133     if (cfg->ctable==NULL) {
134       talloc_free(cfg);
135       cfg=NULL;
136     }
137   }
138   return cfg;
139 }
140
141 void tr_cfg_free (TR_CFG *cfg)
142 {
143   talloc_free(cfg);
144 }
145
146 TR_CFG_MGR *tr_cfg_mgr_new(TALLOC_CTX *mem_ctx)
147 {
148   return talloc_zero(mem_ctx, TR_CFG_MGR);
149 }
150
151 void tr_cfg_mgr_free (TR_CFG_MGR *cfg_mgr) {
152   talloc_free(cfg_mgr);
153 }
154
155 TR_CFG_RC tr_apply_new_config (TR_CFG_MGR *cfg_mgr)
156 {
157   /* cfg_mgr->active is allowed to be null, but new cannot be */
158   if ((cfg_mgr==NULL) || (cfg_mgr->new==NULL))
159     return TR_CFG_BAD_PARAMS;
160
161   if (cfg_mgr->active != NULL)
162     tr_cfg_free(cfg_mgr->active);
163
164   cfg_mgr->active = cfg_mgr->new;
165   cfg_mgr->new=NULL; /* only keep a single handle on the new configuration */
166
167   tr_log_threshold(cfg_mgr->active->internal->log_threshold);
168   tr_console_threshold(cfg_mgr->active->internal->console_threshold);
169
170   return TR_CFG_SUCCESS;
171 }
172
173 static TR_CFG_RC tr_cfg_parse_internal(TR_CFG *trc, json_t *jcfg)
174 {
175   json_t *jint = NULL;
176   json_t *jmtd = NULL;
177   json_t *jtidsp = NULL;
178   json_t *jtrpsp = NULL;
179   json_t *jhname = NULL;
180   json_t *jlog = NULL;
181   json_t *jconthres = NULL;
182   json_t *jlogthres = NULL;
183   json_t *jcfgpoll = NULL;
184   json_t *jcfgsettle = NULL;
185   json_t *jroutesweep = NULL;
186   json_t *jrouteupdate = NULL;
187   json_t *jtidreq_timeout = NULL;
188   json_t *jtidresp_numer = NULL;
189   json_t *jtidresp_denom = NULL;
190   json_t *jrouteconnect = NULL;
191
192   if ((!trc) || (!jcfg))
193     return TR_CFG_BAD_PARAMS;
194
195   if (NULL == trc->internal) {
196     if (NULL == (trc->internal = talloc_zero(trc, TR_CFG_INTERNAL)))
197       return TR_CFG_NOMEM;
198   }
199
200   if (NULL != (jint = json_object_get(jcfg, "tr_internal"))) {
201     if (NULL != (jmtd = json_object_get(jint, "max_tree_depth"))) {
202       if (json_is_number(jmtd)) {
203         trc->internal->max_tree_depth = json_integer_value(jmtd);
204       } else {
205         tr_debug("tr_cfg_parse_internal: Parsing error, max_tree_depth is not a number.");
206         return TR_CFG_NOPARSE;
207       }
208     } else {
209       /* If not configured, use the default */
210       trc->internal->max_tree_depth = TR_DEFAULT_MAX_TREE_DEPTH;
211     }
212     if (NULL != (jtidsp = json_object_get(jint, "tids_port"))) {
213       if (json_is_number(jtidsp)) {
214         trc->internal->tids_port = json_integer_value(jtidsp);
215       } else {
216         tr_debug("tr_cfg_parse_internal: Parsing error, tids_port is not a number.");
217         return TR_CFG_NOPARSE;
218       }
219     } else {
220       /* If not configured, use the default */
221       trc->internal->tids_port = TR_DEFAULT_TIDS_PORT;
222     }
223     if (NULL != (jtrpsp = json_object_get(jint, "trps_port"))) {
224       if (json_is_number(jtrpsp)) {
225         trc->internal->trps_port = json_integer_value(jtrpsp);
226       } else {
227         tr_debug("tr_cfg_parse_internal: Parsing error, trps_port is not a number.");
228         return TR_CFG_NOPARSE;
229       }
230     } else {
231       /* If not configured, use the default */
232       trc->internal->trps_port = TR_DEFAULT_TRPS_PORT;
233     }
234     if (NULL != (jhname = json_object_get(jint, "hostname"))) {
235       if (json_is_string(jhname)) {
236         trc->internal->hostname = json_string_value(jhname);
237       } else {
238         tr_debug("tr_cfg_parse_internal: Parsing error, hostname is not a string.");
239         return TR_CFG_NOPARSE;
240       }
241     }
242     if (NULL != (jcfgpoll = json_object_get(jint, "cfg_poll_interval"))) {
243       if (json_is_number(jcfgpoll)) {
244         trc->internal->cfg_poll_interval = json_integer_value(jcfgpoll);
245       } else {
246         tr_debug("tr_cfg_parse_internal: Parsing error, cfg_poll_interval is not a number.");
247         return TR_CFG_NOPARSE;
248       }
249     } else {
250       trc->internal->cfg_poll_interval = TR_CFGWATCH_DEFAULT_POLL;
251     }
252
253     if (NULL != (jcfgsettle = json_object_get(jint, "cfg_settling_time"))) {
254       if (json_is_number(jcfgsettle)) {
255         trc->internal->cfg_settling_time = json_integer_value(jcfgsettle);
256       } else {
257         tr_debug("tr_cfg_parse_internal: Parsing error, cfg_settling_time is not a number.");
258         return TR_CFG_NOPARSE;
259       }
260     } else {
261       trc->internal->cfg_settling_time = TR_CFGWATCH_DEFAULT_SETTLE;
262     }
263
264     if (NULL != (jrouteconnect = json_object_get(jint, "trp_connect_interval"))) {
265       if (json_is_number(jrouteconnect)) {
266         trc->internal->trp_connect_interval = json_integer_value(jrouteconnect);
267       } else {
268         tr_debug("tr_cfg_parse_internal: Parsing error, trp_connect_interval is not a number.");
269         return TR_CFG_NOPARSE;
270       }
271     } else {
272       /* if not configured, use the default */
273       trc->internal->trp_connect_interval=TR_DEFAULT_TRP_CONNECT_INTERVAL;
274     }
275
276     if (NULL != (jroutesweep = json_object_get(jint, "trp_sweep_interval"))) {
277       if (json_is_number(jroutesweep)) {
278         trc->internal->trp_sweep_interval = json_integer_value(jroutesweep);
279       } else {
280         tr_debug("tr_cfg_parse_internal: Parsing error, trp_sweep_interval is not a number.");
281         return TR_CFG_NOPARSE;
282       }
283     } else {
284       /* if not configured, use the default */
285       trc->internal->trp_sweep_interval=TR_DEFAULT_TRP_SWEEP_INTERVAL;
286     }
287
288     if (NULL != (jrouteupdate = json_object_get(jint, "trp_update_interval"))) {
289       if (json_is_number(jrouteupdate)) {
290         trc->internal->trp_update_interval = json_integer_value(jrouteupdate);
291       } else {
292         tr_debug("tr_cfg_parse_internal: Parsing error, trp_update_interval is not a number.");
293         return TR_CFG_NOPARSE;
294       }
295     } else {
296       /* if not configured, use the default */
297       trc->internal->trp_update_interval=TR_DEFAULT_TRP_UPDATE_INTERVAL;
298     }
299
300     if (NULL != (jtidreq_timeout = json_object_get(jint, "tid_request_timeout"))) {
301       if (json_is_number(jtidreq_timeout)) {
302         trc->internal->tid_req_timeout = json_integer_value(jtidreq_timeout);
303       } else {
304         tr_debug("tr_cfg_parse_internal: Parsing error, tid_request_timeout is not a number.");
305         return TR_CFG_NOPARSE;
306       }
307     } else {
308       /* if not configured, use the default */
309       trc->internal->tid_req_timeout=TR_DEFAULT_TID_REQ_TIMEOUT;
310     }
311
312     if (NULL != (jtidresp_numer = json_object_get(jint, "tid_response_numerator"))) {
313       if (json_is_number(jtidresp_numer)) {
314         trc->internal->tid_resp_numer = json_integer_value(jtidresp_numer);
315       } else {
316         tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_numerator is not a number.");
317         return TR_CFG_NOPARSE;
318       }
319     } else {
320       /* if not configured, use the default */
321       trc->internal->tid_resp_numer=TR_DEFAULT_TID_RESP_NUMER;
322     }
323
324     if (NULL != (jtidresp_denom = json_object_get(jint, "tid_response_denominator"))) {
325       if (json_is_number(jtidresp_denom)) {
326         trc->internal->tid_resp_denom = json_integer_value(jtidresp_denom);
327       } else {
328         tr_debug("tr_cfg_parse_internal: Parsing error, tid_response_denominator is not a number.");
329         return TR_CFG_NOPARSE;
330       }
331     } else {
332       /* if not configured, use the default */
333       trc->internal->tid_resp_denom=TR_DEFAULT_TID_RESP_DENOM;
334     }
335
336     if (NULL != (jlog = json_object_get(jint, "logging"))) {
337       if (NULL != (jlogthres = json_object_get(jlog, "log_threshold"))) {
338         if (json_is_string(jlogthres)) {
339           trc->internal->log_threshold = str2sev(json_string_value(jlogthres));
340         } else {
341           tr_debug("tr_cfg_parse_internal: Parsing error, log_threshold is not a string.");
342           return TR_CFG_NOPARSE;
343         }
344       } else {
345         /* If not configured, use the default */
346         trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
347       }
348
349       if (NULL != (jconthres = json_object_get(jlog, "console_threshold"))) {
350         if (json_is_string(jconthres)) {
351             trc->internal->console_threshold = str2sev(json_string_value(jconthres));
352         } else {
353           tr_debug("tr_cfg_parse_internal: Parsing error, console_threshold is not a string.");
354           return TR_CFG_NOPARSE;
355         }
356       } else {
357         /* If not configured, use the default */
358         trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
359       }
360     } else {
361         /* If not configured, use the default */
362         trc->internal->console_threshold = TR_DEFAULT_CONSOLE_THRESHOLD;
363         trc->internal->log_threshold = TR_DEFAULT_LOG_THRESHOLD;
364     }
365
366     tr_debug("tr_cfg_parse_internal: Internal config parsed.");
367     return TR_CFG_SUCCESS;
368   }
369   return TR_CFG_SUCCESS;
370 }
371
372 static TR_CONSTRAINT *tr_cfg_parse_one_constraint(TALLOC_CTX *mem_ctx, char *ctype, json_t *jc, TR_CFG_RC *rc)
373 {
374   TR_CONSTRAINT *cons=NULL;
375   int i=0;
376
377   if ((!ctype) || (!jc) || (!rc) ||
378       (!json_is_array(jc)) ||
379       (0 >= json_array_size(jc)) ||
380       (TR_MAX_CONST_MATCHES < json_array_size(jc)) ||
381       (!json_is_string(json_array_get(jc, 0)))) {
382     tr_err("tr_cfg_parse_one_constraint: config error.");
383     *rc=TR_CFG_NOPARSE;
384     return NULL;
385   }
386
387   if (NULL==(cons=tr_constraint_new(mem_ctx))) {
388     tr_debug("tr_cfg_parse_one_constraint: Out of memory (cons).");
389     *rc=TR_CFG_NOMEM;
390     return NULL;
391   }
392
393   if (NULL==(cons->type=tr_new_name(ctype))) {
394     tr_err("tr_cfg_parse_one_constraint: Out of memory (type).");
395     *rc=TR_CFG_NOMEM;
396     tr_constraint_free(cons);
397     return NULL;
398   }
399
400   for (i=0; i < json_array_size(jc); i++) {
401     cons->matches[i]=tr_new_name(json_string_value(json_array_get(jc, i)));
402     if (cons->matches[i]==NULL) {
403       tr_err("tr_cfg_parse_one_constraint: Out of memory (match %d).", i+1);
404       *rc=TR_CFG_NOMEM;
405       tr_constraint_free(cons);
406       return NULL;
407     }
408   }
409
410   return cons;
411 }
412
413 static TR_FILTER *tr_cfg_parse_one_filter(TALLOC_CTX *mem_ctx, json_t *jfilt, TR_FILTER_TYPE ftype, TR_CFG_RC *rc)
414 {
415   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
416   TR_FILTER *filt=NULL;
417   json_t *jfaction=NULL;
418   json_t *jfspecs=NULL;
419   json_t *jffield=NULL;
420   json_t *jfmatch=NULL;
421   json_t *jrc=NULL;
422   json_t *jdc=NULL;
423   TR_NAME *name=NULL;
424   int i=0, j=0;
425
426   *rc=TR_CFG_ERROR;
427
428   if ((jfilt==NULL) || (rc==NULL)) {
429     tr_err("tr_cfg_parse_one_filter: null argument");
430     *rc=TR_CFG_BAD_PARAMS;
431     goto cleanup;
432   }
433     
434   if (NULL==(filt=tr_filter_new(tmp_ctx))) {
435     tr_err("tr_cfg_parse_one_filter: Out of memory.");
436     *rc=TR_CFG_NOMEM;
437     goto cleanup;
438   }
439   tr_filter_set_type(filt, ftype);
440
441   /* make sure we have space to represent the filter */
442   if (json_array_size(jfilt) > TR_MAX_FILTER_LINES) {
443     tr_err("tr_cfg_parse_one_filter: Filter has too many lines, maximum of %d.", TR_MAX_FILTER_LINES);
444     *rc=TR_CFG_NOPARSE;
445     goto cleanup;
446   }
447
448   /* For each entry in the filter... */
449   for (i=0; i < json_array_size(jfilt); i++) {
450     if ((NULL==(jfaction=json_object_get(json_array_get(jfilt, i), "action"))) ||
451         (!json_is_string(jfaction))) {
452       tr_debug("tr_cfg_parse_one_filter: Error parsing filter action.");
453       *rc=TR_CFG_NOPARSE;
454       goto cleanup;
455     }
456  
457     if ((NULL==(jfspecs=json_object_get(json_array_get(jfilt, i), "specs"))) ||
458         (!json_is_array(jfspecs)) ||
459         (0==json_array_size(jfspecs))) {
460       tr_debug("tr_cfg_parse_one_filter: Error parsing filter specs.");
461       *rc=TR_CFG_NOPARSE;
462       goto cleanup;
463     }
464   
465     if (TR_MAX_FILTER_SPECS < json_array_size(jfspecs)) {
466       tr_debug("tr_cfg_parse_one_filter: Filter has too many specs, maximimum of %d.", TR_MAX_FILTER_SPECS);
467       *rc=TR_CFG_NOPARSE;
468       goto cleanup;
469     }
470
471     if (NULL==(filt->lines[i]=tr_fline_new(filt))) {
472       tr_debug("tr_cfg_parse_one_filter: Out of memory allocating filter line %d.", i+1);
473       *rc=TR_CFG_NOMEM;
474       goto cleanup;
475     }
476
477     if (!strcmp(json_string_value(jfaction), "accept")) {
478       filt->lines[i]->action=TR_FILTER_ACTION_ACCEPT;
479     }
480     else if (!strcmp(json_string_value(jfaction), "reject")) {
481       filt->lines[i]->action=TR_FILTER_ACTION_REJECT;
482     }
483     else {
484       tr_debug("tr_cfg_parse_one_filter: Error parsing filter action, unknown action' %s'.", json_string_value(jfaction));
485       *rc=TR_CFG_NOPARSE;
486       goto cleanup;
487     }
488
489     if (NULL!=(jrc=json_object_get(json_array_get(jfilt, i), "realm_constraints"))) {
490       if (!json_is_array(jrc)) {
491         tr_err("tr_cfg_parse_one_filter: cannot parse realm_constraints, not an array.");
492         *rc=TR_CFG_NOPARSE;
493         goto cleanup;
494       } else if (json_array_size(jrc)>TR_MAX_CONST_MATCHES) {
495         tr_err("tr_cfg_parse_one_filter: realm_constraints has too many entries, maximum of %d.",
496                TR_MAX_CONST_MATCHES);
497         *rc=TR_CFG_NOPARSE;
498         goto cleanup;
499       } else if (json_array_size(jrc)>0) {
500         /* ok we actually have entries to process */
501         if (NULL==(filt->lines[i]->realm_cons=tr_cfg_parse_one_constraint(filt->lines[i], "realm", jrc, rc))) {
502           tr_debug("tr_cfg_parse_one_filter: Error parsing realm constraint");
503           *rc=TR_CFG_NOPARSE;
504           goto cleanup;
505         }
506       }
507     }
508
509     if (NULL!=(jdc=json_object_get(json_array_get(jfilt, i), "domain_constraints"))) {
510       if (!json_is_array(jdc)) {
511         tr_err("tr_cfg_parse_one_filter: cannot parse domain_constraints, not an array.");
512         *rc=TR_CFG_NOPARSE;
513         goto cleanup;
514       } else if (json_array_size(jdc)>TR_MAX_CONST_MATCHES) {
515         tr_err("tr_cfg_parse_one_filter: domain_constraints has too many entries, maximum of %d.",
516                TR_MAX_CONST_MATCHES);
517         *rc=TR_CFG_NOPARSE;
518         goto cleanup;
519       } else if (json_array_size(jdc)>0) {
520         if (NULL==(filt->lines[i]->domain_cons=tr_cfg_parse_one_constraint(filt->lines[i], "domain", jdc, rc))) {
521           tr_debug("tr_cfg_parse_one_filter: Error parsing domain constraint");
522           *rc=TR_CFG_NOPARSE;
523           goto cleanup;
524         }
525       }
526     }
527
528     /*For each filter spec within the filter line... */
529     for (j=0; j <json_array_size(jfspecs); j++) {
530       if ((NULL==(jffield=json_object_get(json_array_get(jfspecs, j), "field"))) ||
531           (!json_is_string(jffield))) {
532         tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing field for filer spec %d, filter line %d.", i, j);
533         *rc=TR_CFG_NOPARSE;
534         goto cleanup;
535       }
536
537       /* check that we have a match attribute */
538       if (NULL==(jfmatch=json_object_get(json_array_get(jfspecs, j), "match"))) {
539         tr_debug("tr_cfg_parse_one_filter: Error parsing filter: missing match for filer spec %d, filter line %d.", i, j);
540         *rc=TR_CFG_NOPARSE;
541         goto cleanup;
542       }
543
544       /* check that match is a string */
545       if (!json_is_string(jfmatch)) {
546         tr_debug("tr_cfg_parse_one_filter: Error parsing filter: match not a string for filter spec %d, filter line %d.", i, j);
547         *rc=TR_CFG_NOPARSE;
548         goto cleanup;
549       }
550
551       /* allocate the filter spec */
552       if (NULL==(filt->lines[i]->specs[j]=tr_fspec_new(filt->lines[i]))) {
553         tr_debug("tr_cfg_parse_one_filter: Out of memory.");
554         *rc=TR_CFG_NOMEM;
555         goto cleanup;
556       }
557
558       /* fill in the field */
559       if (NULL==(filt->lines[i]->specs[j]->field=tr_new_name(json_string_value(jffield)))) {
560         tr_debug("tr_cfg_parse_one_filter: Out of memory.");
561         *rc=TR_CFG_NOMEM;
562         goto cleanup;
563       }
564
565       /* fill in the matches */
566       if (NULL==(name=tr_new_name(json_string_value(jfmatch)))) {
567         tr_debug("tr_cfg_parse_one_filter: Out of memory.");
568         *rc=TR_CFG_NOMEM;
569         goto cleanup;
570       }
571       tr_fspec_set_match(filt->lines[i]->specs[j], name);
572     }
573   }
574   *rc=TR_CFG_SUCCESS;
575   talloc_steal(mem_ctx, filt);
576   
577  cleanup:
578   talloc_free(tmp_ctx);
579   if (*rc!=TR_CFG_SUCCESS)
580     filt=NULL;
581   return filt;
582 }
583
584 static TR_FILTER *tr_cfg_parse_filters(TALLOC_CTX *mem_ctx, json_t *jfilts, TR_CFG_RC *rc)
585 {
586   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
587   json_t *jfilt;
588   TR_FILTER *filt=NULL;
589
590   *rc=TR_CFG_ERROR;
591
592   /* no filters */
593   if (jfilts==NULL) {
594     *rc=TR_CFG_SUCCESS;
595     goto cleanup;
596   }
597
598   jfilt=json_object_get(jfilts, "tid_inbound");
599   if (jfilt!=NULL) {
600     filt=tr_cfg_parse_one_filter(tmp_ctx, jfilt, TR_FILTER_TYPE_TID_INCOMING, rc);
601     if (*rc!=TR_CFG_SUCCESS) {
602       tr_debug("tr_cfg_parse_filters: Error parsing tid_inbound filter.");
603       *rc=TR_CFG_NOPARSE;
604       goto cleanup;
605     }
606   } else {
607     tr_debug("tr_cfg_parse_filters: Unknown filter types in filter block.");
608     *rc=TR_CFG_NOPARSE;
609     goto cleanup;
610   }
611   
612   *rc=TR_CFG_SUCCESS;
613
614  cleanup:
615   if (*rc==TR_CFG_SUCCESS)
616     talloc_steal(mem_ctx, filt);
617   else if (filt!=NULL) {
618     talloc_free(filt);
619     filt=NULL;
620   }
621
622   talloc_free(tmp_ctx);
623   return filt;
624 }
625
626 static TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
627 {
628   TR_AAA_SERVER *aaa = NULL;
629   TR_NAME *name=NULL;
630
631   if ((!jaddr) || (!json_is_string(jaddr))) {
632     tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
633     *rc = TR_CFG_BAD_PARAMS;
634     return NULL;
635   }
636
637   name=tr_new_name(json_string_value(jaddr));
638   if (name==NULL) {
639     tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
640     *rc = TR_CFG_NOMEM;
641     return NULL;
642   }
643
644   aaa=tr_aaa_server_new(mem_ctx, name);
645   if (aaa==NULL) {
646     tr_free_name(name);
647     tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
648     *rc = TR_CFG_NOMEM;
649     return NULL;
650   }
651
652   return aaa;
653 }
654
655 static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc) 
656 {
657   TALLOC_CTX *tmp_ctx=NULL;
658   TR_AAA_SERVER *aaa = NULL;
659   TR_AAA_SERVER *temp_aaa = NULL;
660   int i = 0;
661
662   for (i = 0; i < json_array_size(jaaas); i++) {
663     /* rc gets set in here */
664     if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
665       talloc_free(tmp_ctx);
666       return NULL;
667     }
668     /* TBD -- IPv6 addresses */
669     //    tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
670     temp_aaa->next = aaa;
671     aaa = temp_aaa;
672   }
673   tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
674
675   for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
676     talloc_steal(mem_ctx, temp_aaa);
677   talloc_free(tmp_ctx);
678   return aaa;
679 }
680
681 static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
682 {
683   TR_APC *apc=NULL;
684   TR_NAME *name=NULL;
685   
686   *rc = TR_CFG_SUCCESS;         /* presume success */
687
688   if ((!japc) || (!rc) || (!json_is_string(japc))) {
689     tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
690     if (rc) 
691       *rc = TR_CFG_BAD_PARAMS;
692     return NULL;
693   }
694
695   apc=tr_apc_new(mem_ctx);
696   if (apc==NULL) {
697     tr_debug("tr_cfg_parse_one_apc: Out of memory.");
698     *rc = TR_CFG_NOMEM;
699     return NULL;
700   }
701
702   name=tr_new_name(json_string_value(japc));
703   if (name==NULL) {
704     tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
705     tr_apc_free(apc);
706     *rc = TR_CFG_NOMEM;
707     return NULL;
708   }
709   tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
710
711   return apc;
712 }
713
714 static TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
715 {
716   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
717   TR_APC *apcs=NULL;
718   TR_APC *new_apc=NULL;
719   int ii=0;
720   TR_CFG_RC call_rc=TR_CFG_ERROR;
721   
722   *rc = TR_CFG_SUCCESS;         /* presume success */
723
724   if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
725     tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
726     if (rc) 
727       *rc = TR_CFG_BAD_PARAMS;
728     return NULL;
729   }
730
731   for (ii=0; ii<json_array_size(japcs); ii++) {
732     new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
733     if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
734       tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
735       *rc=TR_CFG_NOPARSE;
736       goto cleanup;
737     }
738     tr_apc_add(apcs, new_apc);
739   }
740
741   talloc_steal(mem_ctx, apcs);
742   *rc=TR_CFG_SUCCESS;
743
744  cleanup:
745   talloc_free(tmp_ctx);
746   return apcs;
747 }
748
749 static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
750 {
751   TR_NAME *name=NULL;
752   *rc=TR_CFG_ERROR;
753
754   if ((jname==NULL) || (!json_is_string(jname))) {
755     tr_err("tr_cfg_parse_name: name missing or not a string");
756     *rc=TR_CFG_BAD_PARAMS;
757     name=NULL;
758   } else {
759     name=tr_new_name(json_string_value(jname));
760     if (name==NULL) {
761       tr_err("tr_cfg_parse_name: could not allocate name");
762       *rc=TR_CFG_NOMEM;
763     } else {
764       *rc=TR_CFG_SUCCESS;
765     }
766   }
767   return name;  
768 }
769
770 static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
771 {
772   const char *shared=NULL;
773   *rc=TR_CFG_SUCCESS;
774   
775   if ((jsc==NULL) ||
776       (!json_is_string(jsc)) ||
777       (NULL==(shared=json_string_value(jsc)))) {
778     *rc=TR_CFG_BAD_PARAMS;
779     return -1;
780   }
781
782   if (0==strcmp(shared, "no"))
783     return 0;
784   else if (0==strcmp(shared, "yes"))
785     return 1;
786
787   /* any other value is an error */
788   tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
789            shared);
790   *rc=TR_CFG_NOPARSE;
791   return -1;
792 }
793
794 static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
795 {
796   json_t *jremote=json_object_get(jrealm, "remote");
797   const char *s=NULL;
798
799   if (jremote==NULL)
800     return TR_REALM_LOCAL;
801   if (!json_is_string(jremote)) {
802     tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
803     return TR_REALM_LOCAL;
804   }
805   s=json_string_value(jremote);
806   if (strcasecmp(s, "yes")==0)
807     return TR_REALM_REMOTE_INCOMPLETE;
808   else if (strcasecmp(s, "no")!=0)
809     tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
810
811   return TR_REALM_LOCAL;
812 }
813
814 /* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
815 static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
816 {
817   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
818   TR_APC *apcs=NULL;
819   TR_AAA_SERVER *aaa=NULL;
820   TR_CFG_RC rc=TR_CFG_ERROR;
821   
822   if (jidp==NULL)
823     goto cleanup;
824
825   idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
826   if (rc!=TR_CFG_SUCCESS) {
827     tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
828     rc=TR_CFG_NOPARSE;
829     goto cleanup;
830   }
831
832   apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
833   if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
834     tr_err("tr_cfg_parse_idp: unable to parse APC");
835     rc=TR_CFG_NOPARSE;
836     goto cleanup;
837   }
838   
839   aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
840   if (rc!=TR_CFG_SUCCESS) {
841     tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
842     rc=TR_CFG_NOPARSE;
843     goto cleanup;
844   }
845   
846   tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
847            apcs->id->len,
848            apcs->id->buf);
849   
850   /* done, fill in the idp structures */
851   idp->apcs=apcs;
852   talloc_steal(idp, apcs);
853   idp->aaa_servers=aaa;
854   rc=TR_CFG_SUCCESS;
855   
856 cleanup:
857   if (rc!=TR_CFG_SUCCESS) {
858     if (apcs!=NULL)
859       tr_apc_free(apcs);
860     if (aaa!=NULL)
861       tr_aaa_server_free(aaa);
862   }
863   
864   talloc_free(tmp_ctx);
865   return rc;
866 }
867
868 /* parses idp realm */
869 static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
870 {
871   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
872   TR_IDP_REALM *realm=NULL;
873   TR_CFG_RC call_rc=TR_CFG_ERROR;
874
875   *rc=TR_CFG_ERROR; /* default to error if not set */
876
877   if ((!jrealm) || (!rc)) {
878     tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
879     if (rc)
880       *rc=TR_CFG_BAD_PARAMS;
881     goto cleanup;
882   }
883
884   if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
885     tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
886     *rc=TR_CFG_NOMEM;
887     goto cleanup;
888   }
889
890   realm->origin=tr_cfg_realm_origin(jrealm);
891   if (realm->origin!=TR_REALM_LOCAL) {
892     tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
893     *rc=TR_CFG_NOPARSE;
894     goto cleanup;
895   }
896
897   /* must have a name */
898   realm->realm_id=tr_cfg_parse_name(realm,
899                                     json_object_get(jrealm, "realm"),
900                                    &call_rc);
901   if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
902     tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
903     *rc=TR_CFG_NOPARSE;
904     goto cleanup;
905   }
906   tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
907            realm->realm_id->len,
908            realm->realm_id->buf);
909         
910   call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
911   if (call_rc!=TR_CFG_SUCCESS) {
912     tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
913     *rc=TR_CFG_NOPARSE;
914     goto cleanup;
915   }
916   
917   *rc=TR_CFG_SUCCESS;
918
919 cleanup:
920   if (*rc==TR_CFG_SUCCESS)
921     talloc_steal(mem_ctx, realm);
922   else {
923     talloc_free(realm);
924     realm=NULL;
925   }
926   
927   talloc_free(tmp_ctx);
928   return realm;
929 }
930
931   /* Determine whether the realm is an IDP realm */
932 static int tr_cfg_is_idp_realm(json_t *jrealm)
933 {
934   /* If a realm spec contains an identity_provider, it's an IDP realm. */
935   if (NULL != json_object_get(jrealm, "identity_provider"))
936     return 1;
937   else
938     return 0;
939 }
940
941 static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
942 {
943   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
944   TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
945   
946   *rc=TR_CFG_ERROR; /* default to error if not set */
947
948   if ((!jrealm) || (!rc)) {
949     tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
950     if (rc)
951       *rc=TR_CFG_BAD_PARAMS;
952     goto cleanup;
953   }
954
955   if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
956     tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
957     *rc=TR_CFG_NOMEM;
958     goto cleanup;
959   }
960
961   /* must have a name */
962   realm->realm_id=tr_cfg_parse_name(realm,
963                                     json_object_get(jrealm, "realm"),
964                                     rc);
965   if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
966     tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
967     *rc=TR_CFG_NOPARSE;
968     goto cleanup;
969   }
970   tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
971            realm->realm_id->len,
972            realm->realm_id->buf);
973
974   realm->origin=tr_cfg_realm_origin(jrealm);
975   *rc=TR_CFG_SUCCESS;
976
977 cleanup:
978   if (*rc==TR_CFG_SUCCESS)
979     talloc_steal(mem_ctx, realm);
980   else {
981     talloc_free(realm);
982     realm=NULL;
983   }
984   
985   talloc_free(tmp_ctx);
986   return realm;
987 }
988
989 static int tr_cfg_is_remote_realm(json_t *jrealm)
990 {
991   return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
992 }
993
994 /* Parse any idp realms in the j_realms object. Ignores other realm types. */
995 static TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
996 {
997   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
998   TR_IDP_REALM *realms=NULL;
999   TR_IDP_REALM *new_realm=NULL;
1000   json_t *this_jrealm=NULL;
1001   int ii=0;
1002
1003   *rc=TR_CFG_ERROR;
1004   if ((jrealms==NULL) || (!json_is_array(jrealms))) {
1005     tr_err("tr_cfg_parse_idp_realms: realms not an array");
1006     *rc=TR_CFG_BAD_PARAMS;
1007     goto cleanup;
1008   }
1009
1010   for (ii=0; ii<json_array_size(jrealms); ii++) {
1011     this_jrealm=json_array_get(jrealms, ii);
1012     if (tr_cfg_is_idp_realm(this_jrealm)) {
1013       new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
1014       if ((*rc)!=TR_CFG_SUCCESS) {
1015         tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
1016         *rc=TR_CFG_NOPARSE;
1017         goto cleanup;
1018       }
1019       tr_idp_realm_add(realms, new_realm);
1020     } else if (tr_cfg_is_remote_realm(this_jrealm)) {
1021       new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
1022       if ((*rc)!=TR_CFG_SUCCESS) {
1023         tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
1024         *rc=TR_CFG_NOPARSE;
1025         goto cleanup;
1026       }
1027       tr_idp_realm_add(realms, new_realm);
1028     }
1029   }
1030   
1031   *rc=TR_CFG_SUCCESS;
1032   talloc_steal(mem_ctx, realms);
1033
1034 cleanup:
1035   talloc_free(tmp_ctx);
1036   return realms;
1037 }
1038
1039 static TR_GSS_NAMES *tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_CFG_RC *rc)
1040 {
1041   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1042   TR_GSS_NAMES *gn=NULL;
1043   json_t *jname=NULL;
1044   int ii=0;
1045   TR_NAME *name=NULL;
1046
1047   if ((rc==NULL) || (jgss_names==NULL)) {
1048     tr_err("tr_cfg_parse_gss_names: Bad parameters.");
1049     *rc=TR_CFG_BAD_PARAMS;
1050
1051   }
1052
1053   if (!json_is_array(jgss_names)) {
1054     tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
1055     *rc=TR_CFG_NOPARSE;
1056     goto cleanup;
1057   }
1058
1059   gn=tr_gss_names_new(tmp_ctx);
1060   for (ii=0; ii<json_array_size(jgss_names); ii++) {
1061     jname=json_array_get(jgss_names, ii);
1062     if (!json_is_string(jname)) {
1063       tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
1064       *rc=TR_CFG_NOPARSE;
1065       goto cleanup;
1066     }
1067
1068     name=tr_new_name(json_string_value(jname));
1069     if (name==NULL) {
1070       tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
1071       *rc=TR_CFG_NOMEM;
1072       goto cleanup;
1073     }
1074
1075     if (tr_gss_names_add(gn, name)!=0) {
1076       tr_free_name(name);
1077       tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
1078       *rc=TR_CFG_ERROR;
1079       goto cleanup;
1080     }
1081   }
1082
1083   talloc_steal(mem_ctx, gn);
1084   *rc=TR_CFG_SUCCESS;
1085
1086  cleanup:
1087   talloc_free(tmp_ctx);
1088   if ((*rc!=TR_CFG_SUCCESS) && (gn!=NULL))
1089     gn=NULL;
1090   return gn;
1091 }
1092
1093 /* default filter accepts realm and *.realm */
1094 static TR_FILTER *tr_cfg_default_filter(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
1095 {
1096   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1097   TR_FILTER *filt=NULL;
1098   TR_CONSTRAINT *cons=NULL;
1099   TR_NAME *name=NULL;
1100   TR_NAME *n_prefix=tr_new_name("*.");
1101   TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
1102   TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
1103   TR_NAME *n_domain=tr_new_name("domain");
1104   TR_NAME *n_realm=tr_new_name("realm");
1105   
1106
1107   if ((realm==NULL) || (rc==NULL)) {
1108     tr_debug("tr_cfg_default_filter: invalid arguments.");
1109     if (rc!=NULL)
1110       *rc=TR_CFG_BAD_PARAMS;
1111     goto cleanup;
1112   }
1113
1114   if ((n_prefix==NULL) ||
1115       (n_rp_realm_1==NULL) ||
1116       (n_rp_realm_2==NULL) ||
1117       (n_domain==NULL) ||
1118       (n_realm==NULL)) {
1119     tr_debug("tr_cfg_default_filter: unable to allocate names.");
1120     *rc=TR_CFG_NOMEM;
1121     goto cleanup;
1122   }
1123
1124   filt=tr_filter_new(tmp_ctx);
1125   if (filt==NULL) {
1126     tr_debug("tr_cfg_default_filter: could not allocate filter.");
1127     *rc=TR_CFG_NOMEM;
1128     goto cleanup;
1129   }
1130   tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INCOMING);
1131   filt->lines[0]=tr_fline_new(filt);
1132   if (filt->lines[0]==NULL) {
1133     tr_debug("tr_cfg_default_filter: could not allocate filter line.");
1134     *rc=TR_CFG_NOMEM;
1135     goto cleanup;
1136   }
1137
1138   filt->lines[0]->action=TR_FILTER_ACTION_ACCEPT;
1139   filt->lines[0]->specs[0]=tr_fspec_new(filt->lines[0]);
1140   filt->lines[0]->specs[0]->field=n_rp_realm_1;
1141   n_rp_realm_1=NULL; /* we don't own this name any more */
1142
1143   name=tr_dup_name(realm);
1144   if (name==NULL) {
1145     tr_debug("tr_cfg_default_filter: could not allocate realm name.");
1146     *rc=TR_CFG_NOMEM;
1147     goto cleanup;
1148   }
1149   tr_fspec_set_match(filt->lines[0]->specs[0], name);
1150   name=NULL; /* we no longer own the name */
1151
1152   /* now do the wildcard name */
1153   filt->lines[0]->specs[1]=tr_fspec_new(filt->lines[0]);
1154   filt->lines[0]->specs[1]->field=n_rp_realm_2;
1155   n_rp_realm_2=NULL; /* we don't own this name any more */
1156
1157   if (NULL==(name=tr_name_cat(n_prefix, realm))) {
1158     tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name.");
1159     *rc=TR_CFG_NOMEM;
1160     goto cleanup;
1161   }
1162
1163   tr_fspec_set_match(filt->lines[0]->specs[1], name);
1164   name=NULL; /* we no longer own the name */
1165
1166   /* domain constraint */
1167   if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
1168     tr_debug("tr_cfg_default_filter: could not allocate domain constraint.");
1169     *rc=TR_CFG_NOMEM;
1170     goto cleanup;
1171   }
1172
1173   cons->type=n_domain;
1174   n_domain=NULL; /* belongs to the constraint now */
1175   name=tr_dup_name(realm);
1176   if (name==NULL) {
1177     tr_debug("tr_cfg_default_filter: could not allocate realm name for domain constraint.");
1178     *rc=TR_CFG_NOMEM;
1179     goto cleanup;
1180   }
1181   cons->matches[0]=name;
1182   name=tr_name_cat(n_prefix, realm);
1183   if (name==NULL) {
1184     tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for domain constraint.");
1185     *rc=TR_CFG_NOMEM;
1186     goto cleanup;
1187   }
1188   cons->matches[1]=name;
1189   name=NULL;
1190   filt->lines[0]->domain_cons=cons;
1191
1192
1193   /* realm constraint */
1194   if (NULL==(cons=tr_constraint_new(filt->lines[0]))) {
1195     tr_debug("tr_cfg_default_filter: could not allocate realm constraint.");
1196     *rc=TR_CFG_NOMEM;
1197     goto cleanup;
1198   }
1199
1200   cons->type=n_realm;
1201   n_realm=NULL; /* belongs to the constraint now */
1202   name=tr_dup_name(realm);
1203   if (name==NULL) {
1204     tr_debug("tr_cfg_default_filter: could not allocate realm name for realm constraint.");
1205     *rc=TR_CFG_NOMEM;
1206     goto cleanup;
1207   }
1208   cons->matches[0]=name;
1209   name=tr_name_cat(n_prefix, realm);
1210   if (name==NULL) {
1211     tr_debug("tr_cfg_default_filter: could not allocate wildcard realm name for realm constraint.");
1212     *rc=TR_CFG_NOMEM;
1213     goto cleanup;
1214   }
1215   cons->matches[1]=name;
1216   name=NULL;
1217   filt->lines[0]->realm_cons=cons;
1218
1219   talloc_steal(mem_ctx, filt);
1220 cleanup:
1221   talloc_free(tmp_ctx);
1222
1223   if (*rc!=TR_CFG_SUCCESS)
1224     filt=NULL;
1225
1226   if (n_prefix!=NULL)
1227     tr_free_name(n_prefix);
1228   if (n_rp_realm_1!=NULL)
1229     tr_free_name(n_rp_realm_1);
1230   if (n_rp_realm_2!=NULL)
1231     tr_free_name(n_rp_realm_2);
1232   if (n_realm!=NULL)
1233     tr_free_name(n_realm);
1234   if (n_domain!=NULL)
1235     tr_free_name(n_domain);
1236   if (name!=NULL)
1237     tr_free_name(name);
1238
1239   return filt;
1240 }
1241
1242 /* parses rp client */
1243 static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
1244 {
1245   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1246   TR_RP_CLIENT *client=NULL;
1247   TR_CFG_RC call_rc=TR_CFG_ERROR;
1248   TR_FILTER *new_filt=NULL;
1249   TR_NAME *realm=NULL;
1250   json_t *jfilt=NULL;
1251   json_t *jrealm_id=NULL;
1252
1253   *rc=TR_CFG_ERROR; /* default to error if not set */
1254
1255   if ((!jrealm) || (!rc)) {
1256     tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
1257     if (rc)
1258       *rc=TR_CFG_BAD_PARAMS;
1259     goto cleanup;
1260   }
1261
1262   if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
1263     tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
1264     *rc=TR_CFG_BAD_PARAMS;
1265     goto cleanup;
1266   } 
1267
1268   tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
1269   realm=tr_new_name(json_string_value(jrealm_id));
1270   if (realm==NULL) {
1271     tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
1272     *rc=TR_CFG_NOMEM;
1273     goto cleanup;
1274   }
1275
1276   if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
1277     tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
1278     *rc=TR_CFG_NOMEM;
1279     goto cleanup;
1280   }
1281
1282   client->gss_names=tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &call_rc);
1283
1284   if (call_rc!=TR_CFG_SUCCESS) {
1285     tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
1286     *rc=TR_CFG_NOPARSE;
1287     goto cleanup;
1288   }
1289
1290   /* parse filters */
1291   jfilt=json_object_get(jrealm, "filters");
1292   if (jfilt!=NULL) {
1293     new_filt=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
1294     if (call_rc!=TR_CFG_SUCCESS) {
1295       tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
1296       *rc=TR_CFG_NOPARSE;
1297       goto cleanup;
1298     }
1299   } else {
1300     tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
1301     new_filt=tr_cfg_default_filter(tmp_ctx, realm, &call_rc);
1302     if (call_rc!=TR_CFG_SUCCESS) {
1303       tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
1304       *rc=TR_CFG_NOPARSE;
1305       goto cleanup;
1306     }
1307   }
1308
1309   tr_rp_client_set_filter(client, new_filt);
1310   *rc=TR_CFG_SUCCESS;
1311
1312   cleanup:
1313   if (realm!=NULL)
1314     tr_free_name(realm);
1315
1316   if (*rc==TR_CFG_SUCCESS)
1317     talloc_steal(mem_ctx, client);
1318   else {
1319     talloc_free(client);
1320     client=NULL;
1321   }
1322
1323   talloc_free(tmp_ctx);
1324   return client;
1325 }
1326
1327   /* Determine whether the realm is an RP realm */
1328 static int tr_cfg_is_rp_realm(json_t *jrealm)
1329 {
1330   /* Check that we have a gss name. */
1331   if (NULL != json_object_get(jrealm, "gss_names"))
1332     return 1;
1333   else
1334     return 0;
1335 }
1336
1337 /* Parse any rp clients in the j_realms object. Ignores other realms. */
1338 static TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
1339 {
1340   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1341   TR_RP_CLIENT *clients=NULL;
1342   TR_RP_CLIENT *new_client=NULL;
1343   json_t *this_jrealm=NULL;
1344   int ii=0;
1345
1346   *rc=TR_CFG_ERROR;
1347   if ((jrealms==NULL) || (!json_is_array(jrealms))) {
1348     tr_err("tr_cfg_parse_rp_clients: realms not an array");
1349     *rc=TR_CFG_BAD_PARAMS;
1350     goto cleanup;
1351   }
1352
1353   for (ii=0; ii<json_array_size(jrealms); ii++) {
1354     this_jrealm=json_array_get(jrealms, ii);
1355     if (tr_cfg_is_rp_realm(this_jrealm)) {
1356       new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
1357       if ((*rc)!=TR_CFG_SUCCESS) {
1358         tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
1359         *rc=TR_CFG_NOPARSE;
1360         goto cleanup;
1361       }
1362       tr_rp_client_add(clients, new_client);
1363     }
1364   }
1365   
1366   *rc=TR_CFG_SUCCESS;
1367   talloc_steal(mem_ctx, clients);
1368
1369 cleanup:
1370   talloc_free(tmp_ctx);
1371   return clients;
1372 }
1373
1374 /* takes a talloc context, but currently does not use it */
1375 static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
1376 {
1377   TR_NAME *name=NULL;
1378
1379   if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
1380     tr_debug("tr_cfg_parse_org_name: Bad parameters.");
1381     if (rc!=NULL)
1382       *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
1383     return NULL;
1384   }
1385
1386   name=tr_new_name(json_string_value(j_org));
1387   if (name==NULL)
1388     *rc=TR_CFG_NOMEM;
1389   else
1390     *rc=TR_CFG_SUCCESS;
1391   return name;
1392 }
1393
1394 #if 0
1395 /* TODO: are we using this? JLR */
1396 /* Update the community information with data from a new batch of IDP realms.
1397  * May partially add realms if there is a failure, no guarantees.
1398  * Call like comms=tr_comm_idp_update(comms, new_realms, &rc) */
1399 static TR_COMM *tr_cfg_comm_idp_update(TALLOC_CTX *mem_ctx,
1400                                        TR_COMM_TABLE *ctab,
1401                                        TR_IDP_REALM *new_realms,
1402                                        TR_CFG_RC *rc)
1403 {
1404   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1405   TR_COMM *comm=NULL; /* community looked up in comms table */
1406   TR_COMM *new_comms=NULL; /* new communities as we create them */
1407   TR_IDP_REALM *realm=NULL;
1408   TR_APC *apc=NULL; /* apc of one realm */
1409
1410   if (rc==NULL) {
1411     *rc=TR_CFG_BAD_PARAMS;
1412     goto cleanup;
1413   }
1414
1415   /* start with an empty list communities, then fill that in */
1416   for (realm=new_realms; realm!=NULL; realm=realm->next) {
1417     for (apc=realm->apcs; apc!=NULL; apc=apc->next) {
1418       comm=tr_comm_lookup(comms, apc->id);
1419       if (comm==NULL) {
1420         comm=tr_comm_new(tmp_ctx);
1421         if (comm==NULL) {
1422           tr_debug("tr_cfg_comm_idp_update: unable to allocate new community.");
1423           *rc=TR_CFG_NOMEM;
1424           goto cleanup;
1425         }
1426         /* fill in the community with info */
1427         comm->type=TR_COMM_APC; /* realms added this way are in APCs */
1428         comm->expiration_interval=TR_DEFAULT_APC_EXPIRATION_INTERVAL;
1429         tr_comm_set_id(comm, tr_dup_name(apc->id));
1430         tr_comm_add_idp_realm(comm, realm);
1431         tr_comm_add(new_comms, comm);
1432       } else {
1433         /* add this realm to the comm */
1434         tr_comm_add_idp_realm(comm, realm);
1435       }
1436     }
1437   }
1438
1439   /* we successfully built a list, add it to the other list */
1440   tr_comm_add(comms, new_comms);
1441   talloc_steal(mem_ctx, comms);
1442  cleanup:
1443   talloc_free(tmp_ctx);
1444   return comms;
1445 }
1446 #endif
1447
1448 static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
1449 {
1450   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1451   TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
1452   TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
1453   TR_NAME *org_name=NULL;
1454   json_t *j_org=NULL;
1455   json_t *j_realms=NULL;
1456   TR_IDP_REALM *new_idp_realms=NULL;
1457   TR_RP_CLIENT *new_rp_clients=NULL;
1458
1459   tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
1460
1461   /* get organization_name (optional) */
1462   if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
1463     tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
1464   } else {
1465     org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
1466     if (rc==TR_CFG_SUCCESS) {
1467       tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
1468                org_name->len,
1469                org_name->buf);
1470       /* we don't actually do anything with this, but we could */
1471       tr_free_name(org_name);
1472       org_name=NULL; 
1473     }
1474   }
1475
1476   /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
1477    * it's harmless. Report a warning because that might be unintentional. */
1478   if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
1479     tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
1480   } else {
1481     /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
1482     new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
1483     if (rc!=TR_CFG_SUCCESS)
1484       goto cleanup;
1485
1486     new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
1487     if (rc!=TR_CFG_SUCCESS)
1488       goto cleanup;
1489   }
1490   retval=TR_CFG_SUCCESS;
1491   
1492 cleanup:
1493   /* if we succeeded, link things to the configuration and move out of tmp context */
1494   if (retval==TR_CFG_SUCCESS) {
1495     if (new_idp_realms!=NULL) {
1496       tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
1497       talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */
1498     }
1499
1500     if (new_rp_clients!=NULL) {
1501       tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
1502       talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
1503     }
1504   }
1505
1506   talloc_free(tmp_ctx);
1507   return rc;
1508 }
1509
1510 /* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
1511 static TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
1512 {
1513   json_t *jlocorgs=NULL;
1514   int ii=0;
1515
1516   jlocorgs=json_object_get(jcfg, "local_organizations");
1517   if (jlocorgs==NULL)
1518     return TR_CFG_SUCCESS;
1519
1520   if (!json_is_array(jlocorgs)) {
1521     tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
1522     return TR_CFG_NOPARSE;
1523   }
1524
1525   for (ii=0; ii<json_array_size(jlocorgs); ii++) {
1526     if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
1527       tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
1528       return TR_CFG_NOPARSE;
1529     }
1530   }
1531
1532   return TR_CFG_SUCCESS;
1533 }
1534
1535 static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
1536 {
1537   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1538   json_t *jhost=NULL;
1539   json_t *jport=NULL;
1540   json_t *jgss=NULL;
1541   TRP_PEER *new_peer=NULL;
1542   TR_GSS_NAMES *names=NULL;
1543   TR_CFG_RC rc=TR_CFG_ERROR;
1544
1545   jhost=json_object_get(jporg, "hostname");
1546   jport=json_object_get(jporg, "port");
1547   jgss=json_object_get(jporg, "gss_names");
1548
1549   if ((jhost==NULL) || (!json_is_string(jhost))) {
1550     tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
1551     rc=TR_CFG_NOPARSE;
1552     goto cleanup;
1553   }
1554
1555   if ((jport!=NULL) && (!json_is_number(jport))) {
1556     /* note that not specifying the port is allowed, but if set it must be a number */
1557     tr_err("tr_cfg_parse_one_peer_org: port is not a number.");
1558     rc=TR_CFG_NOPARSE;
1559     goto cleanup;
1560   }
1561   
1562   if ((jgss==NULL) || (!json_is_array(jgss))) {
1563     tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
1564     rc=TR_CFG_NOPARSE;
1565     goto cleanup;
1566   }
1567
1568   new_peer=trp_peer_new(tmp_ctx);
1569   if (new_peer==NULL) {
1570     tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
1571     rc=TR_CFG_NOMEM;
1572     goto cleanup;
1573   }
1574
1575   trp_peer_set_server(new_peer, json_string_value(jhost));
1576   if (jport==NULL)
1577     trp_peer_set_port(new_peer, TRP_PORT);
1578   else
1579     trp_peer_set_port(new_peer, json_integer_value(jport));
1580
1581   names=tr_cfg_parse_gss_names(tmp_ctx, jgss, &rc);
1582   if (rc!=TR_CFG_SUCCESS) {
1583     tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
1584     rc=TR_CFG_NOPARSE;
1585     goto cleanup;
1586   }
1587   trp_peer_set_gss_names(new_peer, names);
1588
1589   /* success! */
1590   trp_ptable_add(trc->peers, new_peer);
1591   rc=TR_CFG_SUCCESS;
1592
1593  cleanup:
1594   talloc_free(tmp_ctx);
1595   return rc;
1596 }
1597
1598 /* Parse peer organizations, if present. Returns success if there are none. */
1599 static TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
1600 {
1601   json_t *jpeerorgs=NULL;
1602   int ii=0;
1603
1604   jpeerorgs=json_object_get(jcfg, "peer_organizations");
1605   if (jpeerorgs==NULL)
1606     return TR_CFG_SUCCESS;
1607
1608   if (!json_is_array(jpeerorgs)) {
1609     tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
1610     return TR_CFG_NOPARSE;
1611   }
1612
1613   for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
1614     if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
1615       tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
1616       return TR_CFG_NOPARSE;
1617     }
1618   }
1619
1620   return TR_CFG_SUCCESS;
1621 }
1622              
1623 static TR_CFG_RC tr_cfg_parse_default_servers (TR_CFG *trc, json_t *jcfg) 
1624 {
1625   json_t *jdss = NULL;
1626   TR_CFG_RC rc = TR_CFG_SUCCESS;
1627   TR_AAA_SERVER *ds = NULL;
1628   int i = 0;
1629
1630   if ((!trc) || (!jcfg))
1631     return TR_CFG_BAD_PARAMS;
1632
1633   /* If there are default servers, store them */
1634   if ((NULL != (jdss = json_object_get(jcfg, "default_servers"))) &&
1635       (json_is_array(jdss)) &&
1636       (0 < json_array_size(jdss))) {
1637
1638     for (i = 0; i < json_array_size(jdss); i++) {
1639       if (NULL == (ds = tr_cfg_parse_one_aaa_server(trc,
1640                                                     json_array_get(jdss, i), 
1641                                                    &rc))) {
1642         return rc;
1643       }
1644       tr_debug("tr_cfg_parse_default_servers: Default server configured: %s", ds->hostname->buf);
1645       ds->next = trc->default_servers;
1646       trc->default_servers = ds;
1647     }
1648   } 
1649
1650   tr_debug("tr_cfg_parse_default_servers: Finished (rc=%d)", rc);
1651   return rc;
1652 }
1653
1654 static void tr_cfg_parse_comm_idps(TR_CFG *trc, json_t *jidps, TR_COMM *comm, TR_CFG_RC *rc)
1655 {
1656   TR_IDP_REALM *found_idp=NULL;
1657   int i = 0;
1658
1659   if ((!trc) ||
1660       (!jidps) ||
1661       (!json_is_array(jidps))) {
1662     if (rc)
1663       *rc = TR_CFG_BAD_PARAMS;
1664     return;
1665   }
1666
1667   for (i=0; i < json_array_size(jidps); i++) {
1668     found_idp=tr_cfg_find_idp(trc, 
1669                               tr_new_name((char *)json_string_value(json_array_get(jidps, i))), 
1670                               rc);
1671     if ((found_idp==NULL) || (*rc!=TR_CFG_SUCCESS)) {
1672       tr_debug("tr_cfg_parse_comm_idps: Unknown IDP %s.", 
1673                (char *)json_string_value(json_array_get(jidps, i)));
1674       *rc=TR_CFG_ERROR;
1675       return;
1676     }
1677     tr_comm_add_idp_realm(trc->ctable, comm, found_idp, 0, NULL, NULL); /* no provenance, never expires */
1678   }
1679
1680   *rc=TR_CFG_SUCCESS;
1681   return;
1682 }
1683
1684 static void tr_cfg_parse_comm_rps(TR_CFG *trc, json_t *jrps, TR_COMM *comm, TR_CFG_RC *rc)
1685 {
1686   TR_RP_REALM *found_rp=NULL;
1687   TR_RP_REALM *new_rp=NULL;
1688   TR_NAME *rp_name=NULL;
1689   const char *s=NULL;
1690   int ii=0;
1691
1692   if ((!trc) ||
1693       (!jrps) ||
1694       (!json_is_array(jrps))) {
1695     if (rc)
1696       *rc = TR_CFG_BAD_PARAMS;
1697     return;
1698   }
1699
1700   for (ii=0; ii<json_array_size(jrps); ii++) {
1701     /* get the RP name as a string */
1702     s=json_string_value(json_array_get(jrps, ii));
1703     if (s==NULL) {
1704       tr_notice("tr_cfg_parse_comm_rps: null RP found in community %.*s, ignoring.",
1705                 tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1706       continue;
1707     }
1708
1709     /* convert string to TR_NAME */
1710     rp_name=tr_new_name(s);
1711     if (rp_name==NULL) {
1712       tr_err("tr_cfg_parse_comm_rps: unable to allocate RP name for %s in community %.*s.",
1713              s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1714     }
1715
1716     /* see if we already have this RP in this community */
1717     found_rp=tr_comm_find_rp(trc->ctable, comm, rp_name);
1718     if (found_rp!=NULL) {
1719       tr_notice("tr_cfg_parse_comm_rps: RP %s repeated in community %.*s.",
1720                 s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1721       tr_free_name(rp_name);
1722       continue;
1723     }
1724
1725     /* Add the RP to the community, first see if we have the RP in any community */
1726     found_rp=tr_rp_realm_lookup(trc->ctable->rp_realms, rp_name);
1727     if (found_rp!=NULL) {
1728       tr_debug("tr_cfg_parse_comm_rps: RP realm %s already exists.", s);
1729       new_rp=found_rp; /* use it rather than creating a new realm record */
1730     } else {
1731       new_rp=tr_rp_realm_new(NULL);
1732       if (new_rp==NULL) {
1733         tr_err("tr_cfg_parse_comm_rps: unable to allocate RP record for %s in community %.*s.",
1734                s, tr_comm_get_id(comm)->len, tr_comm_get_id(comm)->buf);
1735       }
1736       tr_debug("tr_cfg_parse_comm_rps: setting name to %s", rp_name->buf);
1737       tr_rp_realm_set_id(new_rp, rp_name);
1738       rp_name=NULL; /* rp_name no longer belongs to us */
1739       tr_rp_realm_add(trc->ctable->rp_realms, new_rp);
1740       talloc_steal(trc->ctable, trc->ctable->rp_realms); /* make sure head is in the right context */
1741     }
1742     tr_comm_add_rp_realm(trc->ctable, comm, new_rp, 0, NULL, NULL);
1743   }
1744 }
1745
1746 static TR_COMM *tr_cfg_parse_one_comm (TALLOC_CTX *mem_ctx, TR_CFG *trc, json_t *jcomm, TR_CFG_RC *rc)
1747 {
1748   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1749   TR_COMM *comm = NULL;
1750   json_t *jid = NULL;
1751   json_t *jtype = NULL;
1752   json_t *japcs = NULL;
1753   json_t *jidps = NULL;
1754   json_t *jrps = NULL;
1755
1756   if ((!trc) || (!jcomm) || (!rc)) {
1757     tr_debug("tr_cfg_parse_one_comm: Bad parameters.");
1758     if (rc)
1759       *rc = TR_CFG_BAD_PARAMS;
1760     goto cleanup;
1761   }
1762
1763   comm=tr_comm_new(tmp_ctx);
1764   if (comm==NULL) {
1765     tr_crit("tr_cfg_parse_one_comm: Out of memory.");
1766     *rc = TR_CFG_NOMEM;
1767     goto cleanup;
1768   }
1769
1770
1771   if ((NULL == (jid = json_object_get(jcomm, "community_id"))) ||
1772       (!json_is_string(jid)) ||
1773       (NULL == (jtype = json_object_get(jcomm, "type"))) ||
1774       (!json_is_string(jtype)) ||
1775       (NULL == (japcs = json_object_get(jcomm, "apcs"))) ||
1776       (!json_is_array(japcs)) ||
1777       (NULL == (jidps = json_object_get(jcomm, "idp_realms"))) ||
1778       (!json_is_array(jidps)) ||
1779       (NULL == (jrps = json_object_get(jcomm, "rp_realms"))) ||
1780       (!json_is_array(jrps))) {
1781     tr_debug("tr_cfg_parse_one_comm: Error parsing Communities configuration.");
1782     *rc = TR_CFG_NOPARSE;
1783     comm=NULL;
1784     goto cleanup;
1785   }
1786
1787   tr_comm_set_id(comm, tr_new_name(json_string_value(jid)));
1788   if (NULL == tr_comm_get_id(comm)) {
1789     tr_debug("tr_cfg_parse_one_comm: No memory for community id.");
1790     *rc = TR_CFG_NOMEM;
1791     comm=NULL;
1792     goto cleanup;
1793   }
1794
1795   if (0 == strcmp(json_string_value(jtype), "apc")) {
1796     comm->type = TR_COMM_APC;
1797   } else if (0 == strcmp(json_string_value(jtype), "coi")) {
1798     comm->type = TR_COMM_COI;
1799     if (NULL == (comm->apcs = tr_cfg_parse_apcs(trc, japcs, rc))) {
1800       tr_debug("tr_cfg_parse_one_comm: Can't parse APCs for COI %s.",
1801                tr_comm_get_id(comm)->buf);
1802       comm=NULL;
1803       goto cleanup;
1804     }
1805   } else {
1806     tr_debug("tr_cfg_parse_one_comm: Invalid community type, comm = %s, type = %s",
1807              tr_comm_get_id(comm)->buf, json_string_value(jtype));
1808     *rc = TR_CFG_NOPARSE;
1809     comm=NULL;
1810     goto cleanup;
1811   }
1812
1813   tr_cfg_parse_comm_idps(trc, jidps, comm, rc);
1814   if (TR_CFG_SUCCESS != *rc) {
1815     tr_debug("tr_cfg_parse_one_comm: Can't parse IDP realms for comm %s.",
1816              tr_comm_get_id(comm)->buf);
1817     comm=NULL;
1818     goto cleanup;
1819   }
1820
1821   tr_cfg_parse_comm_rps(trc, jrps, comm, rc);
1822   if (TR_CFG_SUCCESS != *rc) {
1823     tr_debug("tr_cfg_parse_one_comm: Can't parse RP realms for comm %s .",
1824              tr_comm_get_id(comm)->buf);
1825     comm=NULL;
1826     goto cleanup;
1827   }
1828
1829   if (TR_COMM_APC == comm->type) {
1830     json_t *jexpire  = json_object_get(jcomm, "expiration_interval");
1831     comm->expiration_interval = 43200; /*30 days*/
1832     if (jexpire) {
1833         if (!json_is_integer(jexpire)) {
1834           fprintf(stderr, "tr_parse_one_comm: expiration_interval is not an integer\n");
1835     comm=NULL;
1836     goto cleanup;
1837         }
1838         comm->expiration_interval = json_integer_value(jexpire);
1839         if (comm->expiration_interval <= 10)
1840           comm->expiration_interval = 11; /* Freeradius waits 10 minutes between successful TR queries*/
1841         if (comm->expiration_interval > 129600) /* 90 days*/
1842         comm->expiration_interval = 129600;
1843     }
1844   }
1845
1846 cleanup:
1847   if (comm!=NULL)
1848     talloc_steal(mem_ctx, comm);
1849   talloc_free(tmp_ctx);
1850   return comm;
1851 }
1852
1853 static TR_CFG_RC tr_cfg_parse_comms (TR_CFG *trc, json_t *jcfg) 
1854 {
1855   json_t *jcomms = NULL;
1856   TR_CFG_RC rc = TR_CFG_SUCCESS;
1857   TR_COMM *comm = NULL;
1858   int i = 0;
1859
1860   if ((!trc) || (!jcfg)) {
1861     tr_debug("tr_cfg_parse_comms: Bad Parameters.");
1862     return TR_CFG_BAD_PARAMS;
1863   }
1864
1865   if (NULL != (jcomms = json_object_get(jcfg, "communities"))) {
1866     if (!json_is_array(jcomms)) {
1867       return TR_CFG_NOPARSE;
1868     }
1869
1870     for (i = 0; i < json_array_size(jcomms); i++) {
1871       if (NULL == (comm = tr_cfg_parse_one_comm(NULL, /* TODO: use a talloc context */
1872                                                 trc, 
1873                                                 json_array_get(jcomms, i), 
1874                                                &rc))) {
1875         return rc;
1876       }
1877       tr_debug("tr_cfg_parse_comms: Community configured: %s.",
1878                tr_comm_get_id(comm)->buf);
1879
1880       tr_comm_table_add_comm(trc->ctable, comm);
1881     }
1882   }
1883   tr_debug("tr_cfg_parse_comms: Finished (rc=%d)", rc);
1884   return rc;
1885 }
1886
1887 TR_CFG_RC tr_cfg_validate(TR_CFG *trc)
1888 {
1889   TR_CFG_RC rc = TR_CFG_SUCCESS;
1890
1891   if (!trc)
1892     return TR_CFG_BAD_PARAMS;
1893
1894   if ((NULL == trc->internal)||
1895       (NULL == trc->internal->hostname)) {
1896     tr_debug("tr_cfg_validate: Error: No internal configuration, or no hostname.");
1897     rc = TR_CFG_ERROR;
1898   }
1899
1900   if (NULL == trc->rp_clients) {
1901     tr_debug("tr_cfg_validate: Error: No RP Clients configured");
1902     rc = TR_CFG_ERROR;
1903   }
1904
1905   if (0==tr_comm_table_size(trc->ctable)) {
1906     tr_debug("tr_cfg_validate: Error: No Communities configured");
1907     rc = TR_CFG_ERROR;
1908   }
1909
1910   if ((NULL == trc->default_servers) && (NULL == trc->ctable->idp_realms)) {
1911     tr_debug("tr_cfg_validate: Error: No default servers or IDPs configured.");
1912     rc = TR_CFG_ERROR;
1913   }
1914   
1915   return rc;
1916 }
1917
1918 /* Join two paths and return a pointer to the result. This should be freed
1919  * via talloc_free. Returns NULL on failure. */
1920 static char *join_paths(TALLOC_CTX *mem_ctx, const char *p1, const char *p2)
1921 {
1922   return talloc_asprintf(mem_ctx, "%s/%s", p1, p2); /* returns NULL on a failure */
1923 }
1924
1925 static void tr_cfg_log_json_error(const char *label, json_error_t *rc)
1926 {
1927   tr_debug("%s: JSON parse error on line %d: %s",
1928            label,
1929            rc->line,
1930            rc->text);
1931 }
1932
1933 TR_CFG_RC tr_cfg_parse_one_config_file(TR_CFG *cfg, const char *file_with_path)
1934 {
1935   json_t *jcfg=NULL;
1936   json_t *jser=NULL;
1937   json_error_t rc;
1938
1939   if (NULL==(jcfg=json_load_file(file_with_path, 
1940                                  JSON_DISABLE_EOF_CHECK, &rc))) {
1941     tr_debug("tr_cfg_parse_one_config_file: Error parsing config file %s.", 
1942              file_with_path);
1943     tr_cfg_log_json_error("tr_cfg_parse_one_config_file", &rc);
1944     return TR_CFG_NOPARSE;
1945   }
1946
1947   // Look for serial number and log it if it exists
1948   if (NULL!=(jser=json_object_get(jcfg, "serial_number"))) {
1949     if (json_is_number(jser)) {
1950       tr_notice("tr_parse_one_config_file: Attempting to load revision %" JSON_INTEGER_FORMAT " of '%s'.",
1951                 json_integer_value(jser),
1952                 file_with_path);
1953     }
1954   }
1955
1956   if ((TR_CFG_SUCCESS != tr_cfg_parse_internal(cfg, jcfg)) ||
1957       (TR_CFG_SUCCESS != tr_cfg_parse_local_orgs(cfg, jcfg)) ||
1958       (TR_CFG_SUCCESS != tr_cfg_parse_peer_orgs(cfg, jcfg)) ||
1959       (TR_CFG_SUCCESS != tr_cfg_parse_default_servers(cfg, jcfg)) ||
1960       (TR_CFG_SUCCESS != tr_cfg_parse_comms(cfg, jcfg)))
1961     return TR_CFG_ERROR;
1962
1963   return TR_CFG_SUCCESS;
1964 }
1965
1966 /* Reads configuration files in config_dir ("" or "./" will use the current directory). */
1967 TR_CFG_RC tr_parse_config(TR_CFG_MGR *cfg_mgr, const char *config_dir, int n, struct dirent **cfg_files)
1968 {
1969   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1970   char *file_with_path;
1971   int ii;
1972   TR_CFG_RC cfg_rc=TR_CFG_ERROR;
1973
1974   if ((!cfg_mgr) || (!cfg_files) || (n<=0)) {
1975     cfg_rc=TR_CFG_BAD_PARAMS;
1976     goto cleanup;
1977   }
1978
1979   if (cfg_mgr->new != NULL)
1980     tr_cfg_free(cfg_mgr->new);
1981   cfg_mgr->new=tr_cfg_new(tmp_ctx); /* belongs to the temporary context for now */
1982   if (cfg_mgr->new == NULL) {
1983     cfg_rc=TR_CFG_NOMEM;
1984     goto cleanup;
1985   }
1986
1987   cfg_mgr->new->peers=trp_ptable_new(cfg_mgr);
1988
1989   /* Parse configuration information from each config file */
1990   for (ii=0; ii<n; ii++) {
1991     file_with_path=join_paths(tmp_ctx, config_dir, cfg_files[ii]->d_name); /* must free result with talloc_free */
1992     if(file_with_path == NULL) {
1993       tr_crit("tr_parse_config: error joining path.");
1994       cfg_rc=TR_CFG_NOMEM;
1995       goto cleanup;
1996     }
1997     tr_debug("tr_parse_config: Parsing %s.", cfg_files[ii]->d_name); /* print the filename without the path */
1998     cfg_rc=tr_cfg_parse_one_config_file(cfg_mgr->new, file_with_path);
1999     if (cfg_rc!=TR_CFG_SUCCESS) {
2000       tr_crit("tr_parse_config: Error parsing %s", file_with_path);
2001       goto cleanup;
2002     }
2003     talloc_free(file_with_path); /* done with filename */
2004   }
2005
2006   /* make sure we got a complete, consistent configuration */
2007   if (TR_CFG_SUCCESS != tr_cfg_validate(cfg_mgr->new)) {
2008     tr_err("tr_parse_config: Error: INVALID CONFIGURATION");
2009     cfg_rc=TR_CFG_ERROR;
2010     goto cleanup;
2011   }
2012
2013   /* success! */
2014   talloc_steal(cfg_mgr, cfg_mgr->new); /* hand this over to the cfg_mgr context */
2015   cfg_rc=TR_CFG_SUCCESS;
2016
2017 cleanup:
2018   talloc_free(tmp_ctx);
2019   return cfg_rc;
2020 }
2021
2022 TR_IDP_REALM *tr_cfg_find_idp (TR_CFG *tr_cfg, TR_NAME *idp_id, TR_CFG_RC *rc)
2023 {
2024
2025   TR_IDP_REALM *cfg_idp;
2026
2027   if ((!tr_cfg) || (!idp_id)) {
2028     if (rc)
2029       *rc = TR_CFG_BAD_PARAMS;
2030     return NULL;
2031   }
2032
2033   for (cfg_idp = tr_cfg->ctable->idp_realms; NULL != cfg_idp; cfg_idp = cfg_idp->next) {
2034     if (!tr_name_cmp (idp_id, cfg_idp->realm_id)) {
2035       tr_debug("tr_cfg_find_idp: Found %s.", idp_id->buf);
2036       return cfg_idp;
2037     }
2038   }
2039   /* if we didn't find one, return NULL */ 
2040   return NULL;
2041 }
2042
2043 TR_RP_CLIENT *tr_cfg_find_rp (TR_CFG *tr_cfg, TR_NAME *rp_gss, TR_CFG_RC *rc)
2044 {
2045   TR_RP_CLIENT *cfg_rp;
2046
2047   if ((!tr_cfg) || (!rp_gss)) {
2048     if (rc)
2049       *rc = TR_CFG_BAD_PARAMS;
2050     return NULL;
2051   }
2052
2053   for (cfg_rp = tr_cfg->rp_clients; NULL != cfg_rp; cfg_rp = cfg_rp->next) {
2054     if (tr_gss_names_matches(cfg_rp->gss_names, rp_gss)) {
2055       tr_debug("tr_cfg_find_rp: Found %s.", rp_gss->buf);
2056       return cfg_rp;
2057     }
2058   }
2059   /* if we didn't find one, return NULL */ 
2060   return NULL;
2061 }
2062
2063 static int is_cfg_file(const struct dirent *dent) {
2064   int n;
2065
2066   /* Only accept filenames ending in ".cfg" and starting with a character
2067    * other than an ASCII '.' */
2068
2069   /* filename must be at least 4 characters long to be acceptable */
2070   n=strlen(dent->d_name);
2071   if (n < 4) {
2072     return 0;
2073   }
2074
2075   /* filename must not start with '.' */
2076   if ('.' == dent->d_name[0]) {
2077     return 0;
2078   }
2079
2080   /* If the above passed and the last four characters of the filename are .cfg, accept.
2081    * (n.b., assumes an earlier test checked that the name is >= 4 chars long.) */
2082   if (0 == strcmp(&(dent->d_name[n-4]), ".cfg")) {
2083     return 1;
2084   }
2085
2086   /* otherwise, return false. */
2087   return 0;
2088 }
2089
2090 /* Find configuration files in a particular directory. Returns the
2091  * number of entries found, 0 if none are found, or <0 for some
2092  * errors. If n>=0, the cfg_files parameter will contain a newly
2093  * allocated array of pointers to struct dirent entries, as returned
2094  * by scandir(). These can be freed with tr_free_config_file_list().
2095  */
2096 int tr_find_config_files (const char *config_dir, struct dirent ***cfg_files) {
2097   int n = 0;
2098   
2099   n = scandir(config_dir, cfg_files, is_cfg_file, alphasort);
2100
2101   if (n < 0) {
2102     perror("scandir");
2103     tr_debug("tr_find_config: scandir error trying to scan %s.", config_dir);
2104   } 
2105
2106   return n;
2107 }
2108
2109 /* Free memory allocated for configuration file list returned from tr_find_config_files().
2110  * This can be called regardless of the return value of tr_find_config_values(). */
2111 void tr_free_config_file_list(int n, struct dirent ***cfg_files) {
2112   int ii;
2113
2114   /* if n < 0, then scandir did not allocate anything because it failed */
2115   if((n>=0) && (*cfg_files != NULL)) {
2116     for(ii=0; ii<n; ii++) {
2117       free((*cfg_files)[ii]);
2118     }
2119     free(*cfg_files); /* safe even if n==0 */
2120     *cfg_files=NULL; /* this will help prevent accidentally freeing twice */
2121   }
2122 }