Add accidentally omitted 'port' parameter to error messages
[trust_router.git] / common / tr_config_realms.c
1 /*
2  * Copyright (c) 2012-2018, 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_names.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 #if JANSSON_VERSION_HEX < 0x020500
53 #include "jansson_iterators.h"
54 #endif
55
56 TR_AAA_SERVER *tr_cfg_parse_one_aaa_server(TALLOC_CTX *mem_ctx, json_t *jaddr, TR_CFG_RC *rc)
57 {
58   TR_AAA_SERVER *aaa = NULL;
59   TR_NAME *name=NULL;
60
61   if ((!jaddr) || (!json_is_string(jaddr))) {
62     tr_debug("tr_cfg_parse_one_aaa_server: Bad parameters.");
63     *rc = TR_CFG_BAD_PARAMS;
64     return NULL;
65   }
66
67   name=tr_new_name(json_string_value(jaddr));
68   if (name==NULL) {
69     tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating hostname.");
70     *rc = TR_CFG_NOMEM;
71     return NULL;
72   }
73
74   aaa=tr_aaa_server_new(mem_ctx, name);
75   if (aaa==NULL) {
76     tr_free_name(name);
77     tr_debug("tr_cfg_parse_one_aaa_server: Out of memory allocating AAA server.");
78     *rc = TR_CFG_NOMEM;
79     return NULL;
80   }
81
82   return aaa;
83 }
84
85 static TR_AAA_SERVER *tr_cfg_parse_aaa_servers(TALLOC_CTX *mem_ctx, json_t *jaaas, TR_CFG_RC *rc)
86 {
87   TALLOC_CTX *tmp_ctx=NULL;
88   TR_AAA_SERVER *aaa = NULL;
89   TR_AAA_SERVER *temp_aaa = NULL;
90   int i = 0;
91
92   for (i = 0; i < json_array_size(jaaas); i++) {
93     /* rc gets set in here */
94     if (NULL == (temp_aaa = tr_cfg_parse_one_aaa_server(tmp_ctx, json_array_get(jaaas, i), rc))) {
95       talloc_free(tmp_ctx);
96       return NULL;
97     }
98     /* TBD -- IPv6 addresses */
99     //    tr_debug("tr_cfg_parse_aaa_servers: Configuring AAA Server: ip_addr = %s.", inet_ntoa(temp_aaa->aaa_server_addr));
100     temp_aaa->next = aaa;
101     aaa = temp_aaa;
102   }
103   tr_debug("tr_cfg_parse_aaa_servers: Finished (rc=%d)", *rc);
104
105   for (temp_aaa=aaa; temp_aaa!=NULL; temp_aaa=temp_aaa->next)
106     talloc_steal(mem_ctx, temp_aaa);
107   talloc_free(tmp_ctx);
108   return aaa;
109 }
110
111 static TR_APC *tr_cfg_parse_one_apc(TALLOC_CTX *mem_ctx, json_t *japc, TR_CFG_RC *rc)
112 {
113   TR_APC *apc=NULL;
114   TR_NAME *name=NULL;
115
116   *rc = TR_CFG_SUCCESS;         /* presume success */
117
118   if ((!japc) || (!rc) || (!json_is_string(japc))) {
119     tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
120     if (rc)
121       *rc = TR_CFG_BAD_PARAMS;
122     return NULL;
123   }
124
125   apc=tr_apc_new(mem_ctx);
126   if (apc==NULL) {
127     tr_debug("tr_cfg_parse_one_apc: Out of memory.");
128     *rc = TR_CFG_NOMEM;
129     return NULL;
130   }
131
132   name=tr_new_name(json_string_value(japc));
133   if (name==NULL) {
134     tr_debug("tr_cfg_parse_one_apc: No memory for APC name.");
135     tr_apc_free(apc);
136     *rc = TR_CFG_NOMEM;
137     return NULL;
138   }
139   tr_apc_set_id(apc, name); /* apc is now responsible for freeing the name */
140
141   return apc;
142 }
143
144 TR_APC *tr_cfg_parse_apcs(TALLOC_CTX *mem_ctx, json_t *japcs, TR_CFG_RC *rc)
145 {
146   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
147   TR_APC *apcs=NULL;
148   TR_APC *new_apc=NULL;
149   int ii=0;
150   TR_CFG_RC call_rc=TR_CFG_ERROR;
151
152   *rc = TR_CFG_SUCCESS;         /* presume success */
153
154   if ((!japcs) || (!rc) || (!json_is_array(japcs))) {
155     tr_debug("tr_cfg_parse_one_apc: Bad parameters.");
156     if (rc)
157       *rc = TR_CFG_BAD_PARAMS;
158     return NULL;
159   }
160
161   for (ii=0; ii<json_array_size(japcs); ii++) {
162     new_apc=tr_cfg_parse_one_apc(tmp_ctx, json_array_get(japcs, ii), &call_rc);
163     if ((call_rc!=TR_CFG_SUCCESS) || (new_apc==NULL)) {
164       tr_debug("tr_cfg_parse_apcs: Error parsing APC %d.", ii+1);
165       *rc=TR_CFG_NOPARSE;
166       goto cleanup;
167     }
168     tr_apc_add(apcs, new_apc);
169   }
170
171   talloc_steal(mem_ctx, apcs);
172   *rc=TR_CFG_SUCCESS;
173
174 cleanup:
175   talloc_free(tmp_ctx);
176   return apcs;
177 }
178
179 static TR_NAME *tr_cfg_parse_name(TALLOC_CTX *mem_ctx, json_t *jname, TR_CFG_RC *rc)
180 {
181   TR_NAME *name=NULL;
182   *rc=TR_CFG_ERROR;
183
184   if ((jname==NULL) || (!json_is_string(jname))) {
185     tr_err("tr_cfg_parse_name: name missing or not a string");
186     *rc=TR_CFG_BAD_PARAMS;
187     name=NULL;
188   } else {
189     name=tr_new_name(json_string_value(jname));
190     if (name==NULL) {
191       tr_err("tr_cfg_parse_name: could not allocate name");
192       *rc=TR_CFG_NOMEM;
193     } else {
194       *rc=TR_CFG_SUCCESS;
195     }
196   }
197   return name;
198 }
199
200 static int tr_cfg_parse_shared_config(json_t *jsc, TR_CFG_RC *rc)
201 {
202   const char *shared=NULL;
203   *rc=TR_CFG_SUCCESS;
204
205   if ((jsc==NULL) ||
206       (!json_is_string(jsc)) ||
207       (NULL==(shared=json_string_value(jsc)))) {
208     *rc=TR_CFG_BAD_PARAMS;
209     return -1;
210   }
211
212   if (0==strcmp(shared, "no"))
213     return 0;
214   else if (0==strcmp(shared, "yes"))
215     return 1;
216
217   /* any other value is an error */
218   tr_debug("tr_cfg_parse_shared_config: invalid shared_config value \"%s\" (should be \"yes\" or \"no\")",
219            shared);
220   *rc=TR_CFG_NOPARSE;
221   return -1;
222 }
223
224 static TR_REALM_ORIGIN tr_cfg_realm_origin(json_t *jrealm)
225 {
226   json_t *jremote=json_object_get(jrealm, "remote");
227   const char *s=NULL;
228
229   if (jremote==NULL)
230     return TR_REALM_LOCAL;
231   if (!json_is_string(jremote)) {
232     tr_warning("tr_cfg_realm_origin: \"remote\" is not a string, assuming this is a local realm.");
233     return TR_REALM_LOCAL;
234   }
235   s=json_string_value(jremote);
236   if (strcasecmp(s, "yes")==0)
237     return TR_REALM_REMOTE_INCOMPLETE;
238   else if (strcasecmp(s, "no")!=0)
239     tr_warning("tr_cfg_realm_origin: \"remote\" is neither 'yes' nor 'no', assuming this is a local realm.");
240
241   return TR_REALM_LOCAL;
242 }
243
244 /* Parse the identity provider object from a realm and fill in the given TR_IDP_REALM. */
245 static TR_CFG_RC tr_cfg_parse_idp(TR_IDP_REALM *idp, json_t *jidp)
246 {
247   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
248   TR_APC *apcs=NULL;
249   TR_AAA_SERVER *aaa=NULL;
250   TR_CFG_RC rc=TR_CFG_ERROR;
251
252   if (jidp==NULL)
253     goto cleanup;
254
255   idp->shared_config=tr_cfg_parse_shared_config(json_object_get(jidp, "shared_config"), &rc);
256   if (rc!=TR_CFG_SUCCESS) {
257     tr_err("tr_cfg_parse_idp: missing or malformed shared_config specification");
258     rc=TR_CFG_NOPARSE;
259     goto cleanup;
260   }
261
262   apcs=tr_cfg_parse_apcs(tmp_ctx, json_object_get(jidp, "apcs"), &rc);
263   if ((rc!=TR_CFG_SUCCESS) || (apcs==NULL)) {
264     tr_err("tr_cfg_parse_idp: unable to parse APC");
265     rc=TR_CFG_NOPARSE;
266     goto cleanup;
267   }
268
269   aaa=tr_cfg_parse_aaa_servers(idp, json_object_get(jidp, "aaa_servers"), &rc);
270   if (rc!=TR_CFG_SUCCESS) {
271     tr_err("tr_cfg_parse_idp: unable to parse AAA servers");
272     rc=TR_CFG_NOPARSE;
273     goto cleanup;
274   }
275
276   tr_debug("tr_cfg_parse_idp: APC=\"%.*s\"",
277            apcs->id->len,
278            apcs->id->buf);
279
280   /* done, fill in the idp structures */
281   idp->apcs=apcs;
282   talloc_steal(idp, apcs);
283   idp->aaa_servers=aaa;
284   rc=TR_CFG_SUCCESS;
285
286 cleanup:
287   if (rc!=TR_CFG_SUCCESS) {
288     if (apcs!=NULL)
289       tr_apc_free(apcs);
290     if (aaa!=NULL)
291       tr_aaa_server_free(aaa);
292   }
293
294   talloc_free(tmp_ctx);
295   return rc;
296 }
297
298 /* parses idp realm */
299 static TR_IDP_REALM *tr_cfg_parse_one_idp_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
300 {
301   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
302   TR_IDP_REALM *realm=NULL;
303   TR_CFG_RC call_rc=TR_CFG_ERROR;
304
305   *rc=TR_CFG_ERROR; /* default to error if not set */
306
307   if ((!jrealm) || (!rc)) {
308     tr_err("tr_cfg_parse_one_idp_realm: Bad parameters.");
309     if (rc)
310       *rc=TR_CFG_BAD_PARAMS;
311     goto cleanup;
312   }
313
314   if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
315     tr_err("tr_cfg_parse_one_idp_realm: could not allocate idp realm.");
316     *rc=TR_CFG_NOMEM;
317     goto cleanup;
318   }
319
320   realm->origin=tr_cfg_realm_origin(jrealm);
321   if (realm->origin!=TR_REALM_LOCAL) {
322     tr_debug("tr_cfg_parse_one_idp_realm: realm is remote, should not have full IdP info.");
323     *rc=TR_CFG_NOPARSE;
324     goto cleanup;
325   }
326
327   /* must have a name */
328   realm->realm_id=tr_cfg_parse_name(realm,
329                                     json_object_get(jrealm, "realm"),
330                                     &call_rc);
331   if ((call_rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
332     tr_err("tr_cfg_parse_one_idp_realm: could not parse realm name");
333     *rc=TR_CFG_NOPARSE;
334     goto cleanup;
335   }
336   tr_debug("tr_cfg_parse_one_idp_realm: realm_id=\"%.*s\"",
337            realm->realm_id->len,
338            realm->realm_id->buf);
339
340   call_rc=tr_cfg_parse_idp(realm, json_object_get(jrealm, "identity_provider"));
341   if (call_rc!=TR_CFG_SUCCESS) {
342     tr_err("tr_cfg_parse_one_idp_realm: could not parse identity_provider.");
343     *rc=TR_CFG_NOPARSE;
344     goto cleanup;
345   }
346
347   *rc=TR_CFG_SUCCESS;
348
349 cleanup:
350   if (*rc==TR_CFG_SUCCESS)
351     talloc_steal(mem_ctx, realm);
352   else {
353     talloc_free(realm);
354     realm=NULL;
355   }
356
357   talloc_free(tmp_ctx);
358   return realm;
359 }
360
361 /* Determine whether the realm is an IDP realm */
362 static int tr_cfg_is_idp_realm(json_t *jrealm)
363 {
364   /* If a realm spec contains an identity_provider, it's an IDP realm. */
365   if (NULL != json_object_get(jrealm, "identity_provider"))
366     return 1;
367   else
368     return 0;
369 }
370
371 static TR_IDP_REALM *tr_cfg_parse_one_remote_realm(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
372 {
373   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
374   TR_IDP_REALM *realm=talloc(mem_ctx, TR_IDP_REALM);
375
376   *rc=TR_CFG_ERROR; /* default to error if not set */
377
378   if ((!jrealm) || (!rc)) {
379     tr_err("tr_cfg_parse_one_remote_realm: Bad parameters.");
380     if (rc)
381       *rc=TR_CFG_BAD_PARAMS;
382     goto cleanup;
383   }
384
385   if (NULL==(realm=tr_idp_realm_new(tmp_ctx))) {
386     tr_err("tr_cfg_parse_one_remote_realm: could not allocate idp realm.");
387     *rc=TR_CFG_NOMEM;
388     goto cleanup;
389   }
390
391   /* must have a name */
392   realm->realm_id=tr_cfg_parse_name(realm,
393                                     json_object_get(jrealm, "realm"),
394                                     rc);
395   if ((*rc!=TR_CFG_SUCCESS) || (realm->realm_id==NULL)) {
396     tr_err("tr_cfg_parse_one_remote_realm: could not parse realm name");
397     *rc=TR_CFG_NOPARSE;
398     goto cleanup;
399   }
400   tr_debug("tr_cfg_parse_one_remote_realm: realm_id=\"%.*s\"",
401            realm->realm_id->len,
402            realm->realm_id->buf);
403
404   realm->origin=tr_cfg_realm_origin(jrealm);
405   *rc=TR_CFG_SUCCESS;
406
407 cleanup:
408   if (*rc==TR_CFG_SUCCESS)
409     talloc_steal(mem_ctx, realm);
410   else {
411     talloc_free(realm);
412     realm=NULL;
413   }
414
415   talloc_free(tmp_ctx);
416   return realm;
417 }
418
419 static int tr_cfg_is_remote_realm(json_t *jrealm)
420 {
421   return (tr_cfg_realm_origin(jrealm)!=TR_REALM_LOCAL);
422 }
423
424 /* Parse any idp realms in the j_realms object. Ignores other realm types. */
425 TR_IDP_REALM *tr_cfg_parse_idp_realms(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
426 {
427   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
428   TR_IDP_REALM *realms=NULL;
429   TR_IDP_REALM *new_realm=NULL;
430   json_t *this_jrealm=NULL;
431   int ii=0;
432
433   *rc=TR_CFG_ERROR;
434   if ((jrealms==NULL) || (!json_is_array(jrealms))) {
435     tr_err("tr_cfg_parse_idp_realms: realms not an array");
436     *rc=TR_CFG_BAD_PARAMS;
437     goto cleanup;
438   }
439
440   for (ii=0; ii<json_array_size(jrealms); ii++) {
441     this_jrealm=json_array_get(jrealms, ii);
442     if (tr_cfg_is_idp_realm(this_jrealm)) {
443       new_realm=tr_cfg_parse_one_idp_realm(tmp_ctx, this_jrealm, rc);
444       if ((*rc)!=TR_CFG_SUCCESS) {
445         tr_err("tr_cfg_parse_idp_realms: error decoding realm entry %d", ii+1);
446         *rc=TR_CFG_NOPARSE;
447         goto cleanup;
448       }
449       tr_idp_realm_add(realms, new_realm);
450     } else if (tr_cfg_is_remote_realm(this_jrealm)) {
451       new_realm=tr_cfg_parse_one_remote_realm(tmp_ctx, this_jrealm, rc);
452       if ((*rc)!=TR_CFG_SUCCESS) {
453         tr_err("tr_cfg_parse_idp_realms: error decoding remote realm entry %d", ii+1);
454         *rc=TR_CFG_NOPARSE;
455         goto cleanup;
456       }
457       tr_idp_realm_add(realms, new_realm);
458     }
459   }
460
461   *rc=TR_CFG_SUCCESS;
462   talloc_steal(mem_ctx, realms);
463
464 cleanup:
465   talloc_free(tmp_ctx);
466   return realms;
467 }