Merge pull request #62 from painless-security/jennifer/report_incoming_ipaddr
[trust_router.git] / common / tr_config_rp_clients.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 <tr_constraint_internal.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
57 TR_CFG_RC tr_cfg_parse_gss_names(TALLOC_CTX *mem_ctx, json_t *jgss_names, TR_GSS_NAMES **gssn_out)
58 {
59   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
60   TR_GSS_NAMES *gn=NULL;
61   json_t *jname=NULL;
62   size_t ii=0;
63   TR_NAME *name=NULL;
64   TR_CFG_RC rc = TR_CFG_ERROR;
65
66   if (jgss_names==NULL) {
67     tr_err("tr_cfg_parse_gss_names: Bad parameters.");
68     rc=TR_CFG_BAD_PARAMS;
69     goto cleanup;
70   }
71
72   if (!json_is_array(jgss_names)) {
73     tr_err("tr_cfg_parse_gss_names: gss_names not an array.");
74     rc=TR_CFG_NOPARSE;
75     goto cleanup;
76   }
77
78   gn=tr_gss_names_new(tmp_ctx);
79   for (ii=0; ii<json_array_size(jgss_names); ii++) {
80     jname=json_array_get(jgss_names, ii);
81     if (!json_is_string(jname)) {
82       tr_err("tr_cfg_parse_gss_names: Encountered non-string gss name.");
83       rc=TR_CFG_NOPARSE;
84       goto cleanup;
85     }
86
87     name=tr_new_name(json_string_value(jname));
88     if (name==NULL) {
89       tr_err("tr_cfg_parse_gss_names: Out of memory allocating gss name.");
90       rc=TR_CFG_NOMEM;
91       goto cleanup;
92     }
93
94     if (tr_gss_names_add(gn, name)!=0) {
95       tr_free_name(name);
96       tr_err("tr_cfg_parse_gss_names: Unable to add gss name to RP client.");
97       rc=TR_CFG_ERROR;
98       goto cleanup;
99     }
100   }
101
102   *gssn_out = gn;
103   talloc_steal(mem_ctx, *gssn_out);
104   rc=TR_CFG_SUCCESS;
105
106 cleanup:
107   talloc_free(tmp_ctx);
108   return rc;
109 }
110
111 /* default filter accepts realm and *.realm */
112 static TR_FILTER_SET *tr_cfg_default_filters(TALLOC_CTX *mem_ctx, TR_NAME *realm, TR_CFG_RC *rc)
113 {
114   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
115   TR_FILTER *filt=NULL;
116   TR_FLINE *fline = NULL;
117   TR_FSPEC *fspec = NULL;
118   TR_FILTER_SET *filt_set=NULL;
119   TR_CONSTRAINT *cons=NULL;
120   TR_NAME *name=NULL;
121   TR_NAME *n_prefix=tr_new_name("*.");
122   TR_NAME *n_rp_realm_1=tr_new_name("rp_realm");
123   TR_NAME *n_rp_realm_2=tr_new_name("rp_realm");
124   TR_NAME *n_domain=tr_new_name("domain");
125   TR_NAME *n_realm=tr_new_name("realm");
126
127
128   if ((realm==NULL) || (rc==NULL)) {
129     tr_debug("tr_cfg_default_filters: invalid arguments.");
130     if (rc!=NULL)
131       *rc=TR_CFG_BAD_PARAMS;
132     goto cleanup;
133   }
134
135   if ((n_prefix==NULL) ||
136       (n_rp_realm_1==NULL) ||
137       (n_rp_realm_2==NULL) ||
138       (n_domain==NULL) ||
139       (n_realm==NULL)) {
140     tr_debug("tr_cfg_default_filters: unable to allocate names.");
141     *rc=TR_CFG_NOMEM;
142     goto cleanup;
143   }
144
145   filt=tr_filter_new(tmp_ctx);
146   if (filt==NULL) {
147     tr_debug("tr_cfg_default_filters: could not allocate filter.");
148     *rc=TR_CFG_NOMEM;
149     goto cleanup;
150   }
151   tr_filter_set_type(filt, TR_FILTER_TYPE_TID_INBOUND);
152
153   fline = tr_fline_new(tmp_ctx);
154   if (fline==NULL) {
155     tr_debug("tr_cfg_default_filters: could not allocate filter line.");
156     *rc=TR_CFG_NOMEM;
157     goto cleanup;
158   }
159
160   fline->action=TR_FILTER_ACTION_ACCEPT;
161   
162   fspec=tr_fspec_new(tmp_ctx);
163   fspec->field=n_rp_realm_1;
164   n_rp_realm_1=NULL; /* we don't own this name any more */
165
166   name=tr_dup_name(realm);
167   if (name==NULL) {
168     tr_debug("tr_cfg_default_filters: could not allocate realm name.");
169     *rc=TR_CFG_NOMEM;
170     goto cleanup;
171   }
172   tr_fspec_add_match(fspec, name);
173   name=NULL; /* we no longer own the name */
174
175   if (tr_fline_add_spec(fline, fspec) == NULL) {
176     tr_debug("tr_cfg_default_filters: could not add first spec to filter line");
177     *rc = TR_CFG_NOMEM;
178     goto cleanup;
179   }
180
181   /* now do the wildcard name */
182   fspec=tr_fspec_new(tmp_ctx);
183   fspec->field=n_rp_realm_2;
184   n_rp_realm_2=NULL; /* we don't own this name any more */
185
186   if (NULL==(name=tr_name_cat(n_prefix, realm))) {
187     tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name.");
188     *rc=TR_CFG_NOMEM;
189     goto cleanup;
190   }
191
192   tr_fspec_add_match(fspec, name);
193   name=NULL; /* we no longer own the name */
194
195   if (tr_fline_add_spec(fline, fspec) == NULL) {
196     tr_debug("tr_cfg_default_filters: could not add second spec to filter line");
197     *rc = TR_CFG_NOMEM;
198     goto cleanup;
199   }
200
201   /* domain constraint */
202   if (NULL==(cons=tr_constraint_new(fline))) {
203     tr_debug("tr_cfg_default_filters: could not allocate domain constraint.");
204     *rc=TR_CFG_NOMEM;
205     goto cleanup;
206   }
207
208   cons->type=n_domain;
209   n_domain=NULL; /* belongs to the constraint now */
210   name=tr_dup_name(realm);
211   if (name==NULL) {
212     tr_debug("tr_cfg_default_filters: could not allocate realm name for domain constraint.");
213     *rc=TR_CFG_NOMEM;
214     goto cleanup;
215   }
216   if (NULL == tr_constraint_add_match(cons, name)) {
217     tr_debug("tr_cfg_default_filters: could not add realm name for domain constraint.");
218     *rc=TR_CFG_NOMEM;
219     goto cleanup;
220   }
221   name=tr_name_cat(n_prefix, realm);
222   if (name==NULL) {
223     tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for domain constraint.");
224     *rc=TR_CFG_NOMEM;
225     goto cleanup;
226   }
227   if (NULL == tr_constraint_add_match(cons, name)) {
228     tr_debug("tr_cfg_default_filters: could not add wildcard realm name for domain constraint.");
229     *rc=TR_CFG_NOMEM;
230     goto cleanup;
231   }
232   name=NULL;
233   fline->domain_cons=cons;
234
235
236   /* realm constraint */
237   if (NULL==(cons=tr_constraint_new(fline))) {
238     tr_debug("tr_cfg_default_filters: could not allocate realm constraint.");
239     *rc=TR_CFG_NOMEM;
240     goto cleanup;
241   }
242
243   cons->type=n_realm;
244   n_realm=NULL; /* belongs to the constraint now */
245   name=tr_dup_name(realm);
246   if (name==NULL) {
247     tr_debug("tr_cfg_default_filters: could not allocate realm name for realm constraint.");
248     *rc=TR_CFG_NOMEM;
249     goto cleanup;
250   }
251   if (NULL == tr_constraint_add_match(cons, name)) {
252     tr_debug("tr_cfg_default_filters: could not add realm name for realm constraint.");
253     *rc=TR_CFG_NOMEM;
254     goto cleanup;
255   }
256   name=tr_name_cat(n_prefix, realm);
257   if (name==NULL) {
258     tr_debug("tr_cfg_default_filters: could not allocate wildcard realm name for realm constraint.");
259     *rc=TR_CFG_NOMEM;
260     goto cleanup;
261   }
262   if (NULL == tr_constraint_add_match(cons, name)) {
263     tr_debug("tr_cfg_default_filters: could not add wildcard realm name for realm constraint.");
264     *rc=TR_CFG_NOMEM;
265     goto cleanup;
266   }
267   name=NULL;
268   fline->realm_cons=cons;
269
270   /* put the fline in the filter */
271   if (NULL == tr_filter_add_line(filt, fline)) {
272     tr_debug("tr_cfg_default_filters: could not add line to filter.");
273     *rc = TR_CFG_NOMEM;
274     goto cleanup;
275   }
276
277   /* put the filter in a set */
278   filt_set=tr_filter_set_new(tmp_ctx);
279   if ((filt_set==NULL)||(0!=tr_filter_set_add(filt_set, filt))) {
280     tr_debug("tr_cfg_default_filters: could not allocate filter set.");
281     *rc=TR_CFG_NOMEM;
282     goto cleanup;
283   }
284   talloc_steal(mem_ctx, filt_set);
285
286 cleanup:
287   talloc_free(tmp_ctx);
288
289   if (*rc!=TR_CFG_SUCCESS)
290     filt=NULL;
291
292   if (n_prefix!=NULL)
293     tr_free_name(n_prefix);
294   if (n_rp_realm_1!=NULL)
295     tr_free_name(n_rp_realm_1);
296   if (n_rp_realm_2!=NULL)
297     tr_free_name(n_rp_realm_2);
298   if (n_realm!=NULL)
299     tr_free_name(n_realm);
300   if (n_domain!=NULL)
301     tr_free_name(n_domain);
302   if (name!=NULL)
303     tr_free_name(name);
304
305   return filt_set;
306 }
307
308 /* parses rp client */
309 static TR_RP_CLIENT *tr_cfg_parse_one_rp_client(TALLOC_CTX *mem_ctx, json_t *jrealm, TR_CFG_RC *rc)
310 {
311   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
312   TR_RP_CLIENT *client=NULL;
313   TR_CFG_RC call_rc=TR_CFG_ERROR;
314   TR_FILTER_SET *new_filts=NULL;
315   TR_NAME *realm=NULL;
316   json_t *jfilt=NULL;
317   json_t *jrealm_id=NULL;
318
319   *rc=TR_CFG_ERROR; /* default to error if not set */
320
321   if ((!jrealm) || (!rc)) {
322     tr_err("tr_cfg_parse_one_rp_client: Bad parameters.");
323     if (rc)
324       *rc=TR_CFG_BAD_PARAMS;
325     goto cleanup;
326   }
327
328   if ((NULL==(jrealm_id=json_object_get(jrealm, "realm"))) || (!json_is_string(jrealm_id))) {
329     tr_debug("tr_cfg_parse_one_rp_client: no realm ID found.");
330     *rc=TR_CFG_BAD_PARAMS;
331     goto cleanup;
332   }
333
334   tr_debug("tr_cfg_parse_one_rp_client: realm_id=\"%s\"", json_string_value(jrealm_id));
335   realm=tr_new_name(json_string_value(jrealm_id));
336   if (realm==NULL) {
337     tr_err("tr_cfg_parse_one_rp_client: could not allocate realm ID.");
338     *rc=TR_CFG_NOMEM;
339     goto cleanup;
340   }
341
342   if (NULL==(client=tr_rp_client_new(tmp_ctx))) {
343     tr_err("tr_cfg_parse_one_rp_client: could not allocate rp client.");
344     *rc=TR_CFG_NOMEM;
345     goto cleanup;
346   }
347
348   call_rc = tr_cfg_parse_gss_names(client, json_object_get(jrealm, "gss_names"), &(client->gss_names));
349
350   if (call_rc!=TR_CFG_SUCCESS) {
351     tr_err("tr_cfg_parse_one_rp_client: could not parse gss_names.");
352     *rc=TR_CFG_NOPARSE;
353     goto cleanup;
354   }
355
356   /* parse filters */
357   jfilt=json_object_get(jrealm, "filters");
358   if (jfilt!=NULL) {
359     new_filts=tr_cfg_parse_filters(tmp_ctx, jfilt, &call_rc);
360     if (call_rc!=TR_CFG_SUCCESS) {
361       tr_err("tr_cfg_parse_one_rp_client: could not parse filters.");
362       *rc=TR_CFG_NOPARSE;
363       goto cleanup;
364     }
365   } else {
366     tr_debug("tr_cfg_parse_one_rp_client: no filters specified, using default filters.");
367     new_filts= tr_cfg_default_filters(tmp_ctx, realm, &call_rc);
368     if (call_rc!=TR_CFG_SUCCESS) {
369       tr_err("tr_cfg_parse_one_rp_client: could not set default filters.");
370       *rc=TR_CFG_NOPARSE;
371       goto cleanup;
372     }
373   }
374
375   tr_rp_client_set_filters(client, new_filts);
376   *rc=TR_CFG_SUCCESS;
377
378 cleanup:
379   if (realm!=NULL)
380     tr_free_name(realm);
381
382   if (*rc==TR_CFG_SUCCESS)
383     talloc_steal(mem_ctx, client);
384   else {
385     talloc_free(client);
386     client=NULL;
387   }
388
389   talloc_free(tmp_ctx);
390   return client;
391 }
392
393 /* Determine whether the realm is an RP realm */
394 static int tr_cfg_is_rp_realm(json_t *jrealm)
395 {
396   /* Check that we have a gss name. */
397   if (NULL != json_object_get(jrealm, "gss_names"))
398     return 1;
399   else
400     return 0;
401 }
402
403 /* Parse any rp clients in the j_realms object. Ignores other realms. */
404 TR_RP_CLIENT *tr_cfg_parse_rp_clients(TALLOC_CTX *mem_ctx, json_t *jrealms, TR_CFG_RC *rc)
405 {
406   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
407   TR_RP_CLIENT *clients=NULL;
408   TR_RP_CLIENT *new_client=NULL;
409   json_t *this_jrealm=NULL;
410   int ii=0;
411
412   *rc=TR_CFG_ERROR;
413   if ((jrealms==NULL) || (!json_is_array(jrealms))) {
414     tr_err("tr_cfg_parse_rp_clients: realms not an array");
415     *rc=TR_CFG_BAD_PARAMS;
416     goto cleanup;
417   }
418
419   for (ii=0; ii<json_array_size(jrealms); ii++) {
420     this_jrealm=json_array_get(jrealms, ii);
421     if (tr_cfg_is_rp_realm(this_jrealm)) {
422       new_client=tr_cfg_parse_one_rp_client(tmp_ctx, this_jrealm, rc);
423       if ((*rc)!=TR_CFG_SUCCESS) {
424         tr_err("tr_cfg_parse_rp_clients: error decoding realm entry %d", ii+1);
425         *rc=TR_CFG_NOPARSE;
426         goto cleanup;
427       }
428       tr_rp_client_add(clients, new_client);
429     }
430   }
431
432   *rc=TR_CFG_SUCCESS;
433   talloc_steal(mem_ctx, clients);
434
435 cleanup:
436   talloc_free(tmp_ctx);
437   return clients;
438 }