Use hostname:port format for specifying peer addresses
[trust_router.git] / common / tr_config_orgs.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 #include <tr_util.h>
52
53 #if JANSSON_VERSION_HEX < 0x020500
54 #include "jansson_iterators.h"
55 #endif
56
57 /* takes a talloc context, but currently does not use it */
58 static TR_NAME *tr_cfg_parse_org_name(TALLOC_CTX *mem_ctx, json_t *j_org, TR_CFG_RC *rc)
59 {
60   TR_NAME *name=NULL;
61
62   if ((j_org==NULL) || (rc==NULL) || (!json_is_string(j_org))) {
63     tr_debug("tr_cfg_parse_org_name: Bad parameters.");
64     if (rc!=NULL)
65       *rc = TR_CFG_BAD_PARAMS; /* fill in return value if we can */
66     return NULL;
67   }
68
69   name=tr_new_name(json_string_value(j_org));
70   if (name==NULL)
71     *rc=TR_CFG_NOMEM;
72   else
73     *rc=TR_CFG_SUCCESS;
74   return name;
75 }
76
77 static TR_CFG_RC tr_cfg_parse_one_local_org(TR_CFG *trc, json_t *jlorg)
78 {
79   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
80   TR_CFG_RC retval=TR_CFG_ERROR; /* our return code */
81   TR_CFG_RC rc=TR_CFG_ERROR; /* return code from functions we call */
82   TR_NAME *org_name=NULL;
83   json_t *j_org=NULL;
84   json_t *j_realms=NULL;
85   TR_IDP_REALM *new_idp_realms=NULL;
86   TR_RP_CLIENT *new_rp_clients=NULL;
87
88   tr_debug("tr_cfg_parse_one_local_org: parsing local organization");
89
90   /* get organization_name (optional) */
91   if (NULL==(j_org=json_object_get(jlorg, "organization_name"))) {
92     tr_debug("tr_cfg_parse_one_local_org: organization_name unspecified");
93   } else {
94     org_name=tr_cfg_parse_org_name(tmp_ctx, j_org, &rc);
95     if (rc==TR_CFG_SUCCESS) {
96       tr_debug("tr_cfg_parse_one_local_org: organization_name=\"%.*s\"",
97                org_name->len,
98                org_name->buf);
99       /* we don't actually do anything with this, but we could */
100       tr_free_name(org_name);
101       org_name=NULL;
102     }
103   }
104
105   /* Now get realms. Allow this to be missing; even though that is a pointless organization entry,
106    * it's harmless. Report a warning because that might be unintentional. */
107   if (NULL==(j_realms=json_object_get(jlorg, "realms"))) {
108     tr_warning("tr_cfg_parse_one_local_org: warning - no realms in this local organization");
109   } else {
110     /* Allocate in the tmp_ctx so these will be cleaned up if we do not complete successfully. */
111     new_idp_realms=tr_cfg_parse_idp_realms(tmp_ctx, j_realms, &rc);
112     if (rc!=TR_CFG_SUCCESS)
113       goto cleanup;
114
115     new_rp_clients=tr_cfg_parse_rp_clients(tmp_ctx, j_realms, &rc);
116     if (rc!=TR_CFG_SUCCESS)
117       goto cleanup;
118   }
119   retval=TR_CFG_SUCCESS;
120
121 cleanup:
122   /* if we succeeded, link things to the configuration and move out of tmp context */
123   if (retval==TR_CFG_SUCCESS) {
124     if (new_idp_realms!=NULL) {
125       tr_idp_realm_add(trc->ctable->idp_realms, new_idp_realms); /* fixes talloc contexts except for head*/
126       talloc_steal(trc, trc->ctable->idp_realms); /* make sure the head is in the right context */
127     }
128
129     if (new_rp_clients!=NULL) {
130       tr_rp_client_add(trc->rp_clients, new_rp_clients); /* fixes talloc contexts */
131       talloc_steal(trc, trc->rp_clients); /* make sure head is in the right context */
132     }
133   }
134
135   talloc_free(tmp_ctx);
136   return rc;
137 }
138
139 /* Parse local organizations if present. Returns success if there are none. On failure, the configuration is unreliable. */
140 TR_CFG_RC tr_cfg_parse_local_orgs(TR_CFG *trc, json_t *jcfg)
141 {
142   json_t *jlocorgs=NULL;
143   size_t ii=0;
144
145   jlocorgs=json_object_get(jcfg, "local_organizations");
146   if (jlocorgs==NULL)
147     return TR_CFG_SUCCESS;
148
149   if (!json_is_array(jlocorgs)) {
150     tr_err("tr_cfg_parse_local_orgs: local_organizations is not an array.");
151     return TR_CFG_NOPARSE;
152   }
153
154   for (ii=0; ii<json_array_size(jlocorgs); ii++) {
155     if (tr_cfg_parse_one_local_org(trc, json_array_get(jlocorgs, ii))!=TR_CFG_SUCCESS) {
156       tr_err("tr_cfg_parse_local_orgs: error parsing local_organization %d.", ii+1);
157       return TR_CFG_NOPARSE;
158     }
159   }
160
161   return TR_CFG_SUCCESS;
162 }
163
164 static TR_CFG_RC tr_cfg_parse_one_peer_org(TR_CFG *trc, json_t *jporg)
165 {
166   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
167   json_t *jhost=NULL;
168   json_t *jgss=NULL;
169   json_t *jfilt=NULL;
170   TRP_PEER *new_peer=NULL;
171   TR_GSS_NAMES *names=NULL;
172   TR_FILTER_SET *filt_set=NULL;
173   TR_CFG_RC rc=TR_CFG_ERROR;
174   TR_NAME *hostname=NULL;
175   char *s_hostname=NULL;
176   int port;
177
178   jhost=json_object_get(jporg, "hostname");
179   jgss=json_object_get(jporg, "gss_names");
180   jfilt=json_object_get(jporg, "filters");
181
182   if ((jhost==NULL) || (!json_is_string(jhost))) {
183     tr_err("tr_cfg_parse_one_peer_org: hostname not specified or not a string.");
184     rc=TR_CFG_NOPARSE;
185     goto cleanup;
186   }
187
188   if ((jgss==NULL) || (!json_is_array(jgss))) {
189     tr_err("tr_cfg_parse_one_peer_org: gss_names not specified or not an array.");
190     rc=TR_CFG_NOPARSE;
191     goto cleanup;
192   }
193
194   if ((jfilt!=NULL) && (!json_is_object(jfilt))) {
195     tr_err("tr_cfg_parse_one_peer_org: filters is not an object.");
196     rc=TR_CFG_NOPARSE;
197     goto cleanup;
198   }
199
200   new_peer=trp_peer_new(tmp_ctx);
201   if (new_peer==NULL) {
202     tr_err("tr_cfg_parse_one_peer_org: could not allocate new peer.");
203     rc=TR_CFG_NOMEM;
204     goto cleanup;
205   }
206
207   if (0 != tr_parse_hostname_and_port(json_string_value(jhost), &hostname, &port)) {
208     tr_err("tr_cfg_parse_one_peer_org: error parsing hostname (%s)", json_string_value(jhost));
209     rc=TR_CFG_NOPARSE;
210     goto cleanup;
211   }
212
213   if ((port < 0) || (port > 65535)) {
214     tr_err("tr_cfg_parse_one_peer_org: invalid port (%s)", json_string_value(jhost));
215     rc=TR_CFG_NOPARSE;
216     goto cleanup;
217   }
218
219   if (port == 0)
220     port = TRP_PORT;
221   trp_peer_set_port(new_peer, port);
222
223
224   if (hostname->len == 0) {
225     tr_err("tr_cfg_parse_one_peer_org: no hostname specified (%s)", json_string_value(jhost));
226     rc=TR_CFG_NOPARSE;
227     goto cleanup;
228   }
229
230   s_hostname = tr_name_strdup(hostname);
231   if (s_hostname == NULL) {
232     tr_err("tr_cfg_parse_one_peer_org: could not allocate hostname string.");
233     rc = TR_CFG_NOMEM;
234     goto cleanup;
235   }
236
237   trp_peer_set_server(new_peer, s_hostname); /* string is strdup'ed in _set_server() */
238   if (trp_peer_get_server(new_peer) == NULL) {
239     tr_err("tr_cfg_parse_one_peer: could not set server hostname for new peer");
240     rc = TR_CFG_NOMEM;
241     goto cleanup;
242   }
243
244   rc = tr_cfg_parse_gss_names(tmp_ctx, jgss, &names);
245   if (rc!=TR_CFG_SUCCESS) {
246     tr_err("tr_cfg_parse_one_peer_org: unable to parse gss names.");
247     rc=TR_CFG_NOPARSE;
248     goto cleanup;
249   }
250   trp_peer_set_gss_names(new_peer, names);
251
252   if (jfilt) {
253     filt_set=tr_cfg_parse_filters(tmp_ctx, jfilt, &rc);
254     if (rc!=TR_CFG_SUCCESS) {
255       tr_err("tr_cfg_parse_one_peer_org: unable to parse filters.");
256       rc=TR_CFG_NOPARSE;
257       goto cleanup;
258     }
259     trp_peer_set_filters(new_peer, filt_set);
260   }
261
262   /* success! */
263   trp_ptable_add(trc->peers, new_peer);
264   rc=TR_CFG_SUCCESS;
265
266 cleanup:
267   if (hostname)
268     tr_free_name(hostname);
269
270   if (s_hostname)
271     free(s_hostname);
272
273   talloc_free(tmp_ctx);
274   return rc;
275 }
276
277 /* Parse peer organizations, if present. Returns success if there are none. */
278 TR_CFG_RC tr_cfg_parse_peer_orgs(TR_CFG *trc, json_t *jcfg)
279 {
280   json_t *jpeerorgs=NULL;
281   int ii=0;
282
283   jpeerorgs=json_object_get(jcfg, "peer_organizations");
284   if (jpeerorgs==NULL)
285     return TR_CFG_SUCCESS;
286
287   if (!json_is_array(jpeerorgs)) {
288     tr_err("tr_cfg_parse_peer_orgs: peer_organizations is not an array.");
289     return TR_CFG_NOPARSE;
290   }
291
292   for (ii=0; ii<json_array_size(jpeerorgs); ii++) {
293     if (tr_cfg_parse_one_peer_org(trc, json_array_get(jpeerorgs, ii))!=TR_CFG_SUCCESS) {
294       tr_err("tr_cfg_parse_peer_orgs: error parsing peer_organization %d.", ii+1);
295       return TR_CFG_NOPARSE;
296     }
297   }
298
299   return TR_CFG_SUCCESS;
300 }
301