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