Add a 'request_id' to TID requests and responses
[trust_router.git] / common / tr_msg.c
1 /*
2  * Copyright (c) 2012-2014 , 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 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <string.h>
38 #include <openssl/dh.h>
39 #include <openssl/crypto.h>
40 #include <jansson.h>
41 #include <assert.h>
42 #include <talloc.h>
43
44
45 #include <tr_apc.h>
46 #include <tr_comm.h>
47 #include <tr_msg.h>
48 #include <tr_name_internal.h>
49 #include <trp_internal.h>
50 #include <trust_router/tr_constraint.h>
51 #include <trust_router/tr_dh.h>
52 #include <tr_debug.h>
53
54 /* JSON helpers */
55 /* Read attribute attr from msg as an integer. Returns nonzero on error. */
56 static int tr_msg_get_json_integer(json_t *jmsg, const char *attr, int *dest)
57 {
58   json_t *obj;
59
60   obj=json_object_get(jmsg, attr);
61   if (obj == NULL) {
62     return -1;
63   }
64   /* check type */
65   if (!json_is_integer(obj)) {
66     return -1;
67   }
68
69   (*dest)=json_integer_value(obj);
70   return 0;
71 }
72
73 /* Read attribute attr from msg as a string. Copies string into mem_ctx context so jmsg can
74  * be destroyed safely. Returns nonzero on error. */
75 static TRP_RC tr_msg_get_json_string(json_t *jmsg, const char *attr, char **dest, TALLOC_CTX *mem_ctx)
76 {
77   json_t *obj;
78
79   obj=json_object_get(jmsg, attr);
80   if (obj == NULL)
81     return TRP_ERROR;
82
83   /* check type */
84   if (!json_is_string(obj))
85     return TRP_ERROR;
86
87   *dest=talloc_strdup(mem_ctx, json_string_value(obj));
88   if (*dest==NULL)
89     return TRP_ERROR;
90
91   return TRP_SUCCESS;
92 }
93
94 enum msg_type tr_msg_get_msg_type(TR_MSG *msg) 
95 {
96   return msg->msg_type;
97 }
98
99 void tr_msg_set_msg_type(TR_MSG *msg, enum msg_type type)
100 {
101   msg->msg_type = type;
102 }
103
104 TID_REQ *tr_msg_get_req(TR_MSG *msg)
105 {
106   if (msg->msg_type == TID_REQUEST)
107     return (TID_REQ *)msg->msg_rep;
108   return NULL;
109 }
110
111 void tr_msg_set_req(TR_MSG *msg, TID_REQ *req)
112 {
113   msg->msg_rep = req;
114   msg->msg_type = TID_REQUEST;
115 }
116
117 TID_RESP *tr_msg_get_resp(TR_MSG *msg)
118 {
119   if (msg->msg_type == TID_RESPONSE)
120     return (TID_RESP *)msg->msg_rep;
121   return NULL;
122 }
123
124 void tr_msg_set_resp(TR_MSG *msg, TID_RESP *resp)
125 {
126   msg->msg_rep = resp;
127   msg->msg_type = TID_RESPONSE;
128 }
129
130 TRP_UPD *tr_msg_get_trp_upd(TR_MSG *msg)
131 {
132   if (msg->msg_type == TRP_UPDATE)
133     return (TRP_UPD *)msg->msg_rep;
134   return NULL;
135 }
136
137 void tr_msg_set_trp_upd(TR_MSG *msg, TRP_UPD *update)
138 {
139   msg->msg_rep=update;
140   talloc_steal(NULL, update); /* should attach to msg, but TR_MSG not usually talloc'ed */
141   msg->msg_type=TRP_UPDATE;
142 }
143
144 TRP_REQ *tr_msg_get_trp_req(TR_MSG *msg)
145 {
146   if (msg->msg_type == TRP_REQUEST)
147     return (TRP_REQ *)msg->msg_rep;
148   return NULL;
149 }
150
151 void tr_msg_set_trp_req(TR_MSG *msg, TRP_REQ *req)
152 {
153   msg->msg_rep=req;
154   msg->msg_type=TRP_REQUEST;
155 }
156
157 static json_t *tr_msg_encode_dh(DH *dh)
158 {
159   json_t *jdh = NULL;
160   json_t *jbn = NULL;
161   char *s=NULL;
162
163   if ((!dh) || (!dh->p) || (!dh->g) || (!dh->pub_key))
164     return NULL;
165
166   jdh = json_object();
167
168   jbn = json_string(s=BN_bn2hex(dh->p));
169   OPENSSL_free(s);
170   json_object_set_new(jdh, "dh_p", jbn);
171
172   jbn = json_string(s=BN_bn2hex(dh->g));
173   OPENSSL_free(s);
174   json_object_set_new(jdh, "dh_g", jbn);
175
176   jbn = json_string(s=BN_bn2hex(dh->pub_key));
177   OPENSSL_free(s);
178   json_object_set_new(jdh, "dh_pub_key", jbn);
179
180   return jdh;
181 }
182
183 static DH *tr_msg_decode_dh(json_t *jdh)
184 {
185   DH *dh = NULL;
186   json_t *jp = NULL;
187   json_t *jg = NULL;
188   json_t *jpub_key = NULL;
189
190   if (!(dh=tr_dh_new())) {
191     tr_crit("tr_msg_decode_dh(): Error allocating DH structure.");
192     return NULL;
193   }
194  
195   /* store required fields from dh object */
196   if ((NULL == (jp = json_object_get(jdh, "dh_p"))) ||
197       (NULL == (jg = json_object_get(jdh, "dh_g"))) ||
198       (NULL == (jpub_key = json_object_get(jdh, "dh_pub_key")))) {
199     tr_debug("tr_msg_decode_dh(): Error parsing dh_info.");
200     tr_dh_destroy(dh);
201     return NULL;
202   }
203
204   BN_hex2bn(&(dh->p), json_string_value(jp));
205   BN_hex2bn(&(dh->g), json_string_value(jg));
206   BN_hex2bn(&(dh->pub_key), json_string_value(jpub_key));
207
208   return dh;
209 }
210
211 static json_t * tr_msg_encode_tidreq(TID_REQ *req)
212 {
213   json_t *jreq = NULL;
214   json_t *jstr = NULL;
215
216   if ((!req) || (!req->rp_realm) || (!req->realm) || !(req->comm))
217     return NULL;
218
219   assert(jreq = json_object());
220
221   jstr = tr_name_to_json_string(req->rp_realm);
222   json_object_set_new(jreq, "rp_realm", jstr);
223
224   jstr = tr_name_to_json_string(req->realm);
225   json_object_set_new(jreq, "target_realm", jstr);
226
227   jstr = tr_name_to_json_string(req->comm);
228   json_object_set_new(jreq, "community", jstr);
229
230   if (req->orig_coi) {
231     jstr = tr_name_to_json_string(req->orig_coi);
232     json_object_set_new(jreq, "orig_coi", jstr);
233   }
234
235   if (tid_req_get_request_id(req)) {
236     jstr = tr_name_to_json_string(tid_req_get_request_id(req));
237     json_object_set_new(jreq, "request_id", jstr);
238   }
239
240   json_object_set_new(jreq, "dh_info", tr_msg_encode_dh(req->tidc_dh));
241
242   if (req->cons)
243     json_object_set(jreq, "constraints", (json_t *) req->cons);
244
245   if (req->path)
246     json_object_set(jreq, "path", req->path);
247   if (req->expiration_interval)
248     json_object_set_new(jreq, "expiration_interval",
249                         json_integer(req->expiration_interval));
250   
251   return jreq;
252 }
253
254 static TID_REQ *tr_msg_decode_tidreq(json_t *jreq)
255 {
256   TID_REQ *treq = NULL;
257   json_t *jrp_realm = NULL;
258   json_t *jrealm = NULL;
259   json_t *jcomm = NULL;
260   json_t *jorig_coi = NULL;
261   json_t *jrequest_id = NULL;
262   json_t *jdh = NULL;
263   json_t *jpath = NULL;
264   json_t *jexpire_interval = NULL;
265
266   if (!(treq =tid_req_new())) {
267     tr_crit("tr_msg_decode_tidreq(): Error allocating TID_REQ structure.");
268     return NULL;
269   }
270  
271   /* store required fields from request */
272   if ((NULL == (jrp_realm = json_object_get(jreq, "rp_realm"))) ||
273       (NULL == (jrealm = json_object_get(jreq, "target_realm"))) ||
274       (NULL == (jcomm = json_object_get(jreq, "community")))) {
275     tr_notice("tr_msg_decode(): Error parsing required fields.");
276     tid_req_free(treq);
277     return NULL;
278   }
279
280   jpath = json_object_get(jreq, "path");
281   jexpire_interval = json_object_get(jreq, "expiration_interval");
282
283   treq->rp_realm = tr_new_name(json_string_value(jrp_realm));
284   treq->realm = tr_new_name(json_string_value(jrealm));
285   treq->comm = tr_new_name(json_string_value(jcomm));
286
287   /* Get DH Info from the request */
288   if (NULL == (jdh = json_object_get(jreq, "dh_info"))) {
289     tr_debug("tr_msg_decode(): Error parsing dh_info.");
290     tid_req_free(treq);
291     return NULL;
292   }
293   treq->tidc_dh = tr_msg_decode_dh(jdh);
294
295   /* store optional "orig_coi" field */
296   if (NULL != (jorig_coi = json_object_get(jreq, "orig_coi"))) {
297     treq->orig_coi = tr_new_name(json_string_value(jorig_coi));
298   }
299
300   /* store optional "request_id" field */
301   if (NULL != (jrequest_id = json_object_get(jreq, "request_id"))) {
302     tid_req_set_request_id(treq, tr_new_name(json_string_value(jrequest_id)));
303   }
304
305   treq->cons = (TR_CONSTRAINT_SET *) json_object_get(jreq, "constraints");
306   if (treq->cons) {
307     if (!tr_constraint_set_validate(treq->cons)) {
308       tr_debug("Constraint set validation failed");
309     tid_req_free(treq);
310     return NULL;
311     }
312     json_incref((json_t *) treq->cons);
313     tid_req_cleanup_json(treq, (json_t *) treq->cons);
314   }
315   if (jpath) {
316     json_incref(jpath);
317     treq->path = jpath;
318     tid_req_cleanup_json(treq, jpath);
319   }
320   if (jexpire_interval)
321     treq->expiration_interval = json_integer_value(jexpire_interval);
322   
323   return treq;
324 }
325
326 static json_t *tr_msg_encode_one_server(TID_SRVR_BLK *srvr)
327 {
328   json_t *jsrvr = NULL;
329   json_t *jstr = NULL;
330   gchar *time_str = g_time_val_to_iso8601(&srvr->key_expiration);
331
332   tr_debug("Encoding one server.");
333
334   jsrvr = json_object();
335
336   jstr = json_string(srvr->aaa_server_addr);
337   json_object_set_new(jsrvr, "server_addr", jstr);
338
339   json_object_set_new(jsrvr,
340                       "key_expiration", json_string(time_str));
341   g_free(time_str);
342   /* Server DH Block */
343   jstr = tr_name_to_json_string(srvr->key_name);
344   json_object_set_new(jsrvr, "key_name", jstr);
345   json_object_set_new(jsrvr, "server_dh", tr_msg_encode_dh(srvr->aaa_server_dh));
346   if (srvr->path)
347     /* The path is owned by the srvr, so grab an extra ref*/
348     json_object_set(jsrvr, "path", (json_t *)(srvr->path));
349   return jsrvr;
350 }
351
352 static int tr_msg_decode_one_server(json_t *jsrvr, TID_SRVR_BLK *srvr) 
353 {
354   json_t *jsrvr_addr = NULL;
355   json_t *jsrvr_kn = NULL;
356   json_t *jsrvr_dh = NULL;
357   json_t *jsrvr_expire = NULL;
358
359   if (jsrvr == NULL)
360     return -1;
361
362
363   if ((NULL == (jsrvr_addr = json_object_get(jsrvr, "server_addr"))) ||
364       (NULL == (jsrvr_kn = json_object_get(jsrvr, "key_name"))) ||
365       (NULL == (jsrvr_dh = json_object_get(jsrvr, "server_dh")))) {
366     tr_notice("tr_msg_decode_one_server(): Error parsing required fields.");
367     return -1;
368   }
369
370   srvr->aaa_server_addr=talloc_strdup(srvr, json_string_value(jsrvr_addr));
371   srvr->key_name = tr_new_name((char *)json_string_value(jsrvr_kn));
372   srvr->aaa_server_dh = tr_msg_decode_dh(jsrvr_dh);
373   tid_srvr_blk_set_path(srvr, (TID_PATH *) json_object_get(jsrvr, "path"));
374   jsrvr_expire = json_object_get(jsrvr, "key_expiration");
375   if (jsrvr_expire && json_is_string(jsrvr_expire)) {
376     if (!g_time_val_from_iso8601(json_string_value(jsrvr_expire),
377                                  &srvr->key_expiration))
378       tr_notice("Key expiration %s cannot be parsed", json_string_value(jsrvr_expire));
379   }
380   
381   return 0;
382 }
383
384 static json_t *tr_msg_encode_servers(TID_RESP *resp)
385 {
386   json_t *jservers = NULL;
387   json_t *jsrvr = NULL;
388   TID_SRVR_BLK *srvr = NULL;
389   size_t index;
390
391   jservers = json_array();
392
393   tid_resp_servers_foreach(resp, srvr, index) {
394     if ((NULL == (jsrvr = tr_msg_encode_one_server(srvr))) ||
395         (-1 == json_array_append_new(jservers, jsrvr))) {
396       return NULL;
397     }
398   }
399
400   //  tr_debug("tr_msg_encode_servers(): servers contains:");
401   //  tr_debug("%s", json_dumps(jservers, 0));
402   return jservers;
403 }
404
405 static TID_SRVR_BLK *tr_msg_decode_servers(TALLOC_CTX *mem_ctx, json_t *jservers)
406 {
407   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
408   TID_SRVR_BLK *servers=NULL;
409   TID_SRVR_BLK *new_srvr=NULL;
410   json_t *jsrvr;
411   size_t i, num_servers;
412
413   num_servers = json_array_size(jservers);
414   tr_debug("tr_msg_decode_servers(): Number of servers = %u.", (unsigned) num_servers);
415   
416   if (0 == num_servers) {
417     tr_debug("tr_msg_decode_servers(): Server array is empty."); 
418     goto cleanup;
419   }
420
421   for (i = 0; i < num_servers; i++) {
422     jsrvr = json_array_get(jservers, i);
423
424     new_srvr=tid_srvr_blk_new(tmp_ctx);
425     if (new_srvr==NULL) {
426       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
427       goto cleanup;
428     }
429     
430     if (0 != tr_msg_decode_one_server(jsrvr, new_srvr)) {
431       servers=NULL; /* it's all in tmp_ctx, so we can just let go */
432       goto cleanup;
433     }
434
435     tid_srvr_blk_add(servers, new_srvr);
436   }
437
438   talloc_steal(mem_ctx, servers);
439
440 cleanup:
441   talloc_free(tmp_ctx);
442   return servers;
443 }
444
445 static json_t * tr_msg_encode_tidresp(TID_RESP *resp)
446 {
447   json_t *jresp = NULL;
448   json_t *jstr = NULL;
449   json_t *jservers = NULL;
450
451   if ((!resp) || (!resp->rp_realm) || (!resp->realm) || !(resp->comm))
452     return NULL;
453
454   jresp = json_object();
455
456   if (TID_ERROR == resp->result) {
457     jstr = json_string("error");
458     json_object_set_new(jresp, "result", jstr);
459     if (resp->err_msg) {
460       jstr = tr_name_to_json_string(resp->err_msg);
461       json_object_set_new(jresp, "err_msg", jstr);
462     }
463   }
464   else {
465     jstr = json_string("success");
466     json_object_set_new(jresp, "result", jstr);
467   }
468
469   jstr = tr_name_to_json_string(resp->rp_realm);
470   json_object_set_new(jresp, "rp_realm", jstr);
471
472   jstr = tr_name_to_json_string(resp->realm);
473   json_object_set_new(jresp, "target_realm", jstr);
474
475   jstr = tr_name_to_json_string(resp->comm);
476   json_object_set_new(jresp, "comm", jstr);
477
478   if (resp->orig_coi) {
479     jstr = tr_name_to_json_string(resp->orig_coi);
480     json_object_set_new(jresp, "orig_coi", jstr);
481   }
482
483   if (tid_resp_get_request_id(resp)) {
484     jstr = tr_name_to_json_string(tid_resp_get_request_id(resp));
485     json_object_set_new(jresp, "request_id", jstr);
486   }
487
488   if (NULL == resp->servers) {
489     tr_debug("tr_msg_encode_tidresp(): No servers to encode.");
490   }
491   else {
492     jservers = tr_msg_encode_servers(resp);
493     json_object_set_new(jresp, "servers", jservers);
494   }
495   if (resp->error_path)
496     json_object_set(jresp, "error_path", resp->error_path);
497   
498   
499   return jresp;
500 }
501
502 static TID_RESP *tr_msg_decode_tidresp(json_t *jresp)
503 {
504   TID_RESP *tresp = NULL;
505   json_t *jresult = NULL;
506   json_t *jrp_realm = NULL;
507   json_t *jrealm = NULL;
508   json_t *jcomm = NULL;
509   json_t *jorig_coi = NULL;
510   json_t *jrequest_id = NULL;
511   json_t *jservers = NULL;
512   json_t *jerr_msg = NULL;
513
514   if (!(tresp=tid_resp_new(NULL))) {
515     tr_crit("tr_msg_decode_tidresp(): Error allocating TID_RESP structure.");
516     return NULL;
517   }
518  
519
520   /* store required fields from response */
521   if ((NULL == (jresult = json_object_get(jresp, "result"))) ||
522       (!json_is_string(jresult)) ||
523       (NULL == (jrp_realm = json_object_get(jresp, "rp_realm"))) ||
524       (!json_is_string(jrp_realm)) ||
525       (NULL == (jrealm = json_object_get(jresp, "target_realm"))) ||
526       (!json_is_string(jrealm)) ||
527       (NULL == (jcomm = json_object_get(jresp, "comm"))) ||
528       (!json_is_string(jcomm))) {
529     tr_debug("tr_msg_decode_tidresp(): Error parsing response.");
530     talloc_free(tresp);
531     return NULL;
532   }
533
534   if (0 == (strcmp(json_string_value(jresult), "success"))) {
535     tr_debug("tr_msg_decode_tidresp(): Success! result = %s.", json_string_value(jresult));
536     if ((NULL != (jservers = json_object_get(jresp, "servers"))) ||
537         (!json_is_array(jservers))) {
538       tresp->servers = tr_msg_decode_servers(tresp, jservers); 
539     } 
540     else {
541       talloc_free(tresp);
542       return NULL;
543     }
544     tresp->result = TID_SUCCESS;
545   }
546   else {
547     tresp->result = TID_ERROR;
548     tr_debug("tr_msg_decode_tidresp(): Error! result = %s.", json_string_value(jresult));
549     if ((NULL != (jerr_msg = json_object_get(jresp, "err_msg"))) ||
550         (!json_is_string(jerr_msg))) {
551       tresp->err_msg = tr_new_name(json_string_value(jerr_msg));
552     } else
553       tresp->err_msg = tr_new_name("No error message set.");
554
555     if (NULL !=(tresp->error_path = json_object_get(jresp, "error_path")))
556       json_incref(tresp->error_path);
557   }
558
559   tresp->rp_realm = tr_new_name(json_string_value(jrp_realm));
560   tresp->realm = tr_new_name(json_string_value(jrealm));
561   tresp->comm = tr_new_name(json_string_value(jcomm));
562
563   /* store optional "orig_coi" field */
564   if ((NULL != (jorig_coi = json_object_get(jresp, "orig_coi"))) &&
565       json_is_string(jorig_coi)) {
566     tresp->orig_coi = tr_new_name(json_string_value(jorig_coi));
567   }
568
569   /* store optional "request_id" field */
570   if ((NULL != (jrequest_id = json_object_get(jresp, "request_id"))) &&
571       json_is_string(jrequest_id)) {
572     tid_resp_set_request_id(tresp, tr_new_name(json_string_value(jrequest_id)));
573   }
574
575   return tresp;
576 }
577
578
579 /* Information records for TRP update msg 
580  * requires that jrec already be allocated */
581 static TRP_RC tr_msg_encode_inforec_route(json_t *jrec, TRP_INFOREC *rec)
582 {
583   json_t *jstr=NULL;
584   json_t *jint=NULL;
585   char *s=NULL;
586
587   if (rec==NULL)
588     return TRP_BADTYPE;
589
590   if (trp_inforec_get_trust_router(rec)==NULL)
591     return TRP_ERROR;
592
593   s=tr_name_strdup(trp_inforec_get_trust_router(rec));
594   if (s==NULL)
595     return TRP_NOMEM;
596   jstr=json_string(s);
597   free(s);s=NULL;
598   if(jstr==NULL)
599     return TRP_ERROR;
600   json_object_set_new(jrec, "trust_router", jstr);
601
602   jint=json_integer(trp_inforec_get_metric(rec));
603   if(jint==NULL)
604     return TRP_ERROR;
605   json_object_set_new(jrec, "metric", jint);
606
607   jint=json_integer(trp_inforec_get_interval(rec));
608   if(jint==NULL)
609     return TRP_ERROR;
610   json_object_set_new(jrec, "interval", jint);
611
612   return TRP_SUCCESS;
613 }
614
615 /* returns a json array */
616 static json_t *tr_msg_encode_apcs(TR_APC *apcs)
617 {
618   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
619   TR_APC_ITER *iter=tr_apc_iter_new(tmp_ctx);
620   TR_APC *apc=NULL;
621   json_t *jarray=NULL;
622   json_t *jid=NULL;
623
624   if (iter==NULL)
625     goto cleanup;
626
627   jarray=json_array();
628   if (jarray==NULL)
629     goto cleanup;
630
631   for (apc=tr_apc_iter_first(iter, apcs); apc!=NULL; apc=tr_apc_iter_next(iter)) {
632     jid=tr_name_to_json_string(tr_apc_get_id(apc));
633     if ((jid==NULL) || (json_array_append_new(jarray, jid)!=0)) {
634       json_decref(jarray);
635       jarray=NULL;
636       goto cleanup;
637     }
638   }
639   
640 cleanup:
641   talloc_free(tmp_ctx);
642   return jarray;
643 }
644
645 static TR_APC *tr_msg_decode_apcs(TALLOC_CTX *mem_ctx, json_t *jarray, TRP_RC *rc)
646 {
647   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
648   size_t ii=0;
649   TR_APC *apc_list=NULL;
650   TR_APC *new=NULL;
651   json_t *jstr=NULL;
652
653   *rc=TRP_ERROR;
654
655   for (ii=0; ii<json_array_size(jarray); ii++) {
656     jstr=json_array_get(jarray, ii);
657     new=tr_apc_new(tmp_ctx);
658     if ((jstr==NULL) || (new==NULL) || (!json_is_string(jstr))) {
659       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
660       goto cleanup;
661     }
662
663     tr_apc_set_id(new, tr_new_name(json_string_value(jstr)));
664     if (tr_apc_get_id(new)==NULL) {
665       apc_list=NULL; /* these are all in tmp_ctx, so they'll still get cleaned up */
666       goto cleanup;
667     }
668
669     tr_apc_add(apc_list, new);
670   }
671
672   *rc=TRP_SUCCESS;
673
674   if (apc_list!=NULL)
675     talloc_steal(mem_ctx, apc_list);
676
677 cleanup:
678   talloc_free(tmp_ctx);
679   return apc_list;
680 }
681
682 static TRP_RC tr_msg_encode_inforec_comm(json_t *jrec, TRP_INFOREC *rec)
683 {
684   json_t *jstr=NULL;
685   json_t *jint=NULL;
686   json_t *japcs=NULL;
687   const char *sconst=NULL;
688   TR_COMM_TYPE commtype=TR_COMM_UNKNOWN;
689
690   if (rec==NULL)
691     return TRP_BADTYPE;
692
693   commtype=trp_inforec_get_comm_type(rec);
694   if (commtype==TR_COMM_UNKNOWN) {
695     tr_notice("tr_msg_encode_inforec_comm: unknown community type.");
696     return TRP_ERROR;
697   }
698   sconst=tr_comm_type_to_str(commtype);
699   if (sconst==NULL)
700     return TRP_ERROR;
701   jstr=json_string(sconst);
702   if(jstr==NULL)
703     return TRP_ERROR;
704   json_object_set_new(jrec, "type", jstr);
705
706   sconst=tr_realm_role_to_str(trp_inforec_get_role(rec));
707   if (sconst==NULL) {
708     tr_notice("tr_msg_encode_inforec_comm: unknown realm role.");
709     return TRP_ERROR;
710   }
711   jstr=json_string(sconst);
712   if(jstr==NULL)
713     return TRP_ERROR;
714   json_object_set_new(jrec, "role", jstr);
715
716   japcs=tr_msg_encode_apcs(trp_inforec_get_apcs(rec));
717   if (japcs==NULL) {
718     tr_notice("tr_msg_encode_inforec_comm: error encoding APCs.");
719     return TRP_ERROR;
720   }
721   json_object_set_new(jrec, "apcs", japcs);
722   
723
724   if (trp_inforec_get_owner_realm(rec)!=NULL) {
725     jstr=tr_name_to_json_string(trp_inforec_get_owner_realm(rec));
726     if(jstr==NULL)
727       return TRP_ERROR;
728     json_object_set_new(jrec, "owner_realm", jstr);
729   }  
730
731   if (trp_inforec_get_owner_contact(rec)!=NULL) {
732     jstr=tr_name_to_json_string(trp_inforec_get_owner_contact(rec));
733     if(jstr==NULL)
734       return TRP_ERROR;
735     json_object_set_new(jrec, "owner_contact", jstr);
736   }  
737
738   json_object_set(jrec, "provenance", trp_inforec_get_provenance(rec));
739
740   jint=json_integer(trp_inforec_get_interval(rec));
741   if(jint==NULL)
742     return TRP_ERROR;
743   json_object_set_new(jrec, "interval", jint);
744
745   return TRP_SUCCESS;
746 }
747
748 static json_t *tr_msg_encode_inforec(TRP_INFOREC *rec)
749 {
750   json_t *jrec=NULL;
751   json_t *jstr=NULL;
752
753   if ((rec==NULL) || (trp_inforec_get_type(rec)==TRP_INFOREC_TYPE_UNKNOWN))
754     return NULL;
755
756   jrec=json_object();
757   if (jrec==NULL)
758     return NULL;
759
760   jstr=json_string(trp_inforec_type_to_string(trp_inforec_get_type(rec)));
761   if (jstr==NULL) {
762     json_decref(jrec);
763     return NULL;
764   }
765   json_object_set_new(jrec, "record_type", jstr);
766
767   switch (rec->type) {
768   case TRP_INFOREC_TYPE_ROUTE:
769     if (TRP_SUCCESS!=tr_msg_encode_inforec_route(jrec, rec)) {
770       json_decref(jrec);
771       return NULL;
772     }
773     break;
774   case TRP_INFOREC_TYPE_COMMUNITY:
775     if (TRP_SUCCESS!=tr_msg_encode_inforec_comm(jrec, rec)) {
776       json_decref(jrec);
777       return NULL;
778     }
779     break;
780   default:
781     json_decref(jrec);
782     return NULL;
783   }
784   return jrec;
785 }
786
787 static TRP_RC tr_msg_decode_trp_inforec_route(json_t *jrecord, TRP_INFOREC *rec)
788 {
789   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
790   TRP_RC rc=TRP_ERROR;
791   char *s=NULL;
792   int num=0;
793
794   rc=tr_msg_get_json_string(jrecord, "trust_router", &s, tmp_ctx);
795   if (rc != TRP_SUCCESS)
796     goto cleanup;
797   if (TRP_SUCCESS!=trp_inforec_set_trust_router(rec, tr_new_name(s))) {
798     rc=TRP_ERROR;
799     goto cleanup;
800   }
801   talloc_free(s); s=NULL;
802
803   trp_inforec_set_next_hop(rec, NULL); /* make sure this is null (filled in later) */
804
805   rc=tr_msg_get_json_integer(jrecord, "metric", &num);
806   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_metric(rec,num)))
807     goto cleanup;
808
809   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
810   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
811     goto cleanup;
812
813 cleanup:
814   talloc_free(tmp_ctx);
815   return rc;
816 }
817
818 static TRP_RC tr_msg_decode_trp_inforec_comm(json_t *jrecord, TRP_INFOREC *rec)
819 {
820   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
821   TRP_RC rc=TRP_ERROR;
822   char *s=NULL;
823   int num=0;
824   TR_APC *apcs=NULL;
825
826   rc=tr_msg_get_json_string(jrecord, "type", &s, tmp_ctx);
827   if (rc != TRP_SUCCESS)
828     goto cleanup;
829   if (TRP_SUCCESS!=trp_inforec_set_comm_type(rec, tr_comm_type_from_str(s))) {
830     rc=TRP_ERROR;
831     goto cleanup;
832   }
833   talloc_free(s); s=NULL;
834
835   rc=tr_msg_get_json_string(jrecord, "role", &s, tmp_ctx);
836   if (rc != TRP_SUCCESS)
837     goto cleanup;
838   if (TRP_SUCCESS!=trp_inforec_set_role(rec, tr_realm_role_from_str(s))) {
839     rc=TRP_ERROR;
840     goto cleanup;
841   }
842   talloc_free(s); s=NULL;
843
844   apcs=tr_msg_decode_apcs(rec, json_object_get(jrecord, "apcs"), &rc);
845   if (rc!=TRP_SUCCESS) {
846     rc=TRP_ERROR;
847     goto cleanup;
848   }
849   trp_inforec_set_apcs(rec, apcs);
850
851   rc=tr_msg_get_json_integer(jrecord, "interval", &num);
852   tr_debug("tr_msg_decode_trp_inforec_comm: interval=%u", num);
853   if ((rc != TRP_SUCCESS) || (TRP_SUCCESS!=trp_inforec_set_interval(rec,num)))
854     goto cleanup;
855
856   trp_inforec_set_provenance(rec, json_object_get(jrecord, "provenance"));
857
858   /* optional */
859   rc=tr_msg_get_json_string(jrecord, "owner_realm", &s, tmp_ctx);
860   if (rc == TRP_SUCCESS) {
861     if (TRP_SUCCESS!=trp_inforec_set_owner_realm(rec, tr_new_name(s))) {
862       rc=TRP_ERROR;
863       goto cleanup;
864     }
865     if (s!=NULL) {
866       talloc_free(s);
867       s=NULL;
868     }
869   }
870
871   rc=tr_msg_get_json_string(jrecord, "owner_contact", &s, tmp_ctx);
872   if (rc == TRP_SUCCESS) {
873     if (TRP_SUCCESS!=trp_inforec_set_owner_contact(rec, tr_new_name(s))) {
874       rc=TRP_ERROR;
875       goto cleanup;
876     }
877     if (s!=NULL) {
878       talloc_free(s);
879       s=NULL;
880     }
881   }
882
883 cleanup:
884   talloc_free(tmp_ctx);
885   return rc;
886 }
887
888 /* decode a single record */
889 static TRP_INFOREC *tr_msg_decode_trp_inforec(TALLOC_CTX *mem_ctx, json_t *jrecord)
890 {
891   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
892   TRP_INFOREC_TYPE rectype;
893   TRP_INFOREC *rec=NULL;
894   TRP_RC rc=TRP_ERROR;
895   char *s=NULL;
896   
897   if (TRP_SUCCESS!=tr_msg_get_json_string(jrecord, "record_type", &s, tmp_ctx))
898     goto cleanup;
899
900   rectype=trp_inforec_type_from_string(s);
901   talloc_free(s); s=NULL;
902
903   rec=trp_inforec_new(tmp_ctx, rectype);
904   if (rec==NULL) {
905     rc=TRP_NOMEM;
906     goto cleanup;
907   }
908
909   tr_debug("tr_msg_decode_trp_inforec: '%s' record found.", trp_inforec_type_to_string(rec->type));
910
911   switch(trp_inforec_get_type(rec)) {
912   case TRP_INFOREC_TYPE_ROUTE:
913     rc=tr_msg_decode_trp_inforec_route(jrecord, rec);
914     break;
915   case TRP_INFOREC_TYPE_COMMUNITY:
916     rc=tr_msg_decode_trp_inforec_comm(jrecord, rec);
917     break;
918   default:
919     rc=TRP_UNSUPPORTED;
920     goto cleanup;
921   }
922
923   talloc_steal(mem_ctx, rec);
924   rc=TRP_SUCCESS;
925
926 cleanup:
927   if (rc != TRP_SUCCESS) {
928     trp_inforec_free(rec);
929     rec=NULL;
930   }
931   talloc_free(tmp_ctx);
932   return rec;
933 }
934
935 /* TRP update msg */
936 static json_t *tr_msg_encode_trp_upd(TRP_UPD *update)
937 {
938   json_t *jupdate=NULL;
939   json_t *jrecords=NULL;
940   json_t *jrec=NULL;
941   json_t *jstr=NULL;
942   TRP_INFOREC *rec;
943   char *s=NULL;
944
945   if (update==NULL)
946     return NULL;
947
948   jupdate=json_object();
949   if (jupdate==NULL)
950     return NULL;
951
952   s=tr_name_strdup(trp_upd_get_comm(update));
953   if (s==NULL) {
954     json_decref(jupdate);
955     return NULL;
956   }
957   jstr=json_string(s);
958   free(s);s=NULL;
959   if(jstr==NULL) {
960     json_decref(jupdate);
961     return NULL;
962   }
963   json_object_set_new(jupdate, "community", jstr);
964
965   s=tr_name_strdup(trp_upd_get_realm(update));
966   if (s==NULL) {
967     json_decref(jupdate);
968     return NULL;
969   }
970   jstr=json_string(s);
971   free(s);s=NULL;
972   if(jstr==NULL) {
973     json_decref(jupdate);
974     return NULL;
975   }
976   json_object_set_new(jupdate, "realm", jstr);
977
978   jrecords=json_array();
979   if (jrecords==NULL) {
980     json_decref(jupdate);
981     return NULL;
982   }
983   json_object_set_new(jupdate, "records", jrecords); /* jrecords now a "borrowed" reference */
984   for (rec=trp_upd_get_inforec(update); rec!=NULL; rec=trp_inforec_get_next(rec)) {
985     tr_debug("tr_msg_encode_trp_upd: encoding inforec.");
986     jrec=tr_msg_encode_inforec(rec);
987     if (jrec==NULL) {
988       json_decref(jupdate); /* also decs jrecords and any elements */
989       return NULL;
990     }
991     if (0!=json_array_append_new(jrecords, jrec)) {
992       json_decref(jupdate); /* also decs jrecords and any elements */
993       json_decref(jrec); /* this one did not get added so dec explicitly */
994       return NULL;
995     }
996   }
997
998   return jupdate;
999 }
1000
1001 /* Creates a linked list of records in the msg->body talloc context.
1002  * An error will be returned if any unparseable records are encountered. 
1003  */
1004 static TRP_UPD *tr_msg_decode_trp_upd(TALLOC_CTX *mem_ctx, json_t *jupdate)
1005 {
1006   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1007   json_t *jrecords=NULL;
1008   size_t ii=0;
1009   TRP_UPD *update=NULL;
1010   TRP_INFOREC *new_rec=NULL;
1011   TRP_INFOREC *list_tail=NULL;
1012   char *s=NULL;
1013   TR_NAME *name;
1014   TRP_RC rc=TRP_ERROR;
1015
1016   update=trp_upd_new(tmp_ctx);
1017   if (update==NULL) {
1018     rc=TRP_NOMEM;
1019     goto cleanup;
1020   }
1021
1022   rc=tr_msg_get_json_string(jupdate, "community", &s, tmp_ctx);
1023   if (rc != TRP_SUCCESS) {
1024     tr_debug("tr_msg_decode_trp_upd: no community in TRP update message.");
1025     rc=TRP_NOPARSE;
1026     goto cleanup;
1027   }
1028   name=tr_new_name(s);
1029   if (name==NULL) {
1030     tr_debug("tr_msg_decode_trp_upd: could not allocate community name.");
1031     rc=TRP_NOMEM;
1032     goto cleanup;
1033   }
1034   talloc_free(s); s=NULL;
1035   trp_upd_set_comm(update, name);
1036
1037   rc=tr_msg_get_json_string(jupdate, "realm", &s, tmp_ctx);
1038   if (rc != TRP_SUCCESS) {
1039     tr_debug("tr_msg_decode_trp_upd: no realm in TRP update message.");
1040     rc=TRP_NOPARSE;
1041     goto cleanup;
1042   }
1043   name=tr_new_name(s);
1044   if (name==NULL) {
1045     tr_debug("tr_msg_decode_trp_upd: could not allocate realm name.");
1046     rc=TRP_NOMEM;
1047     goto cleanup;
1048   }
1049   talloc_free(s); s=NULL;
1050   trp_upd_set_realm(update, name);
1051
1052   jrecords=json_object_get(jupdate, "records");
1053   if ((jrecords==NULL) || (!json_is_array(jrecords))) {
1054     rc=TRP_NOPARSE;
1055     goto cleanup;
1056   }
1057
1058   tr_debug("tr_msg_decode_trp_upd: found %d records", json_array_size(jrecords));
1059   /* process the array */
1060   for (ii=0; ii<json_array_size(jrecords); ii++) {
1061     new_rec=tr_msg_decode_trp_inforec(update, json_array_get(jrecords, ii));
1062     if (new_rec==NULL) {
1063       rc=TRP_NOPARSE;
1064       goto cleanup;
1065     }
1066
1067     if (list_tail==NULL)
1068       trp_upd_set_inforec(update, new_rec); /* first is a special case */
1069     else
1070       trp_inforec_set_next(list_tail, new_rec);
1071
1072     list_tail=new_rec;
1073   }
1074
1075   /* Succeeded. Move new allocations into the correct talloc context */
1076   talloc_steal(mem_ctx, update);
1077   rc=TRP_SUCCESS;
1078
1079 cleanup:
1080   talloc_free(tmp_ctx);
1081   if (rc!=TRP_SUCCESS)
1082     return NULL;
1083   return update;
1084 }
1085
1086 static json_t *tr_msg_encode_trp_req(TRP_REQ *req)
1087 {
1088   json_t *jbody=NULL;
1089   json_t *jstr=NULL;
1090   char *s=NULL;
1091
1092   if (req==NULL)
1093     return NULL;
1094
1095   jbody=json_object();
1096   if (jbody==NULL)
1097     return NULL;
1098
1099   if ((NULL==trp_req_get_comm(req))
1100      || (NULL==trp_req_get_realm(req))) {
1101     json_decref(jbody);
1102     return NULL;
1103   }
1104
1105   s=tr_name_strdup(trp_req_get_comm(req)); /* ensures null termination */
1106   if (s==NULL) {
1107     json_decref(jbody);
1108     return NULL;
1109   }
1110   jstr=json_string(s);
1111   free(s); s=NULL;
1112   if (jstr==NULL) {
1113     json_decref(jbody);
1114     return NULL;
1115   }
1116   json_object_set_new(jbody, "community", jstr);
1117     
1118   s=tr_name_strdup(trp_req_get_realm(req)); /* ensures null termination */
1119   if (s==NULL) {
1120     json_decref(jbody);
1121     return NULL;
1122   }
1123   jstr=json_string(s);
1124   free(s); s=NULL;
1125   if (jstr==NULL) {
1126     json_decref(jbody);
1127     return NULL;
1128   }
1129   json_object_set_new(jbody, "realm", jstr);
1130
1131   return jbody;
1132 }
1133
1134 static TRP_REQ *tr_msg_decode_trp_req(TALLOC_CTX *mem_ctx, json_t *jreq)
1135 {
1136   TALLOC_CTX *tmp_ctx=talloc_new(NULL);
1137   TRP_REQ *req=NULL;
1138   char *s=NULL;
1139   TRP_RC rc=TRP_ERROR;
1140
1141   /* check message type and body type for agreement */
1142   req=trp_req_new(tmp_ctx);
1143   if (req==NULL) {
1144     rc=TRP_NOMEM;
1145     goto cleanup;
1146   }
1147
1148   rc=tr_msg_get_json_string(jreq, "community", &s, tmp_ctx);
1149   if (rc!=TRP_SUCCESS)
1150     goto cleanup;
1151   trp_req_set_comm(req, tr_new_name(s));
1152   talloc_free(s); s=NULL;
1153
1154   rc=tr_msg_get_json_string(jreq, "realm", &s, tmp_ctx);
1155   if (rc!=TRP_SUCCESS)
1156     goto cleanup;
1157   trp_req_set_realm(req, tr_new_name(s));
1158   talloc_free(s); s=NULL;
1159
1160   rc=TRP_SUCCESS;
1161   talloc_steal(mem_ctx, req);
1162
1163 cleanup:
1164   talloc_free(tmp_ctx);
1165   if (rc!=TRP_SUCCESS)
1166     return NULL;
1167   return req;
1168 }
1169
1170 char *tr_msg_encode(TR_MSG *msg) 
1171 {
1172   json_t *jmsg=NULL;
1173   json_t *jmsg_type=NULL;
1174   char *encoded=NULL;
1175   TID_RESP *tidresp=NULL;
1176   TID_REQ *tidreq=NULL;
1177   TRP_UPD *trpupd=NULL;
1178   TRP_REQ *trpreq=NULL;
1179
1180   /* TBD -- add error handling */
1181   jmsg = json_object();
1182
1183   switch (msg->msg_type) 
1184     {
1185     case TID_REQUEST:
1186       jmsg_type = json_string("tid_request");
1187       json_object_set_new(jmsg, "msg_type", jmsg_type);
1188       tidreq=tr_msg_get_req(msg);
1189       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidreq(tidreq));
1190       break;
1191
1192     case TID_RESPONSE:
1193       jmsg_type = json_string("tid_response");
1194       json_object_set_new(jmsg, "msg_type", jmsg_type);
1195       tidresp=tr_msg_get_resp(msg);
1196       json_object_set_new(jmsg, "msg_body", tr_msg_encode_tidresp(tidresp));
1197       break;
1198
1199     case TRP_UPDATE:
1200       jmsg_type = json_string("trp_update");
1201       json_object_set_new(jmsg, "msg_type", jmsg_type);
1202       trpupd=tr_msg_get_trp_upd(msg);
1203       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_upd(trpupd));
1204       break;
1205
1206     case TRP_REQUEST:
1207       jmsg_type = json_string("trp_request");
1208       json_object_set_new(jmsg, "msg_type", jmsg_type);
1209       trpreq=tr_msg_get_trp_req(msg);
1210       json_object_set_new(jmsg, "msg_body", tr_msg_encode_trp_req(trpreq));
1211       break;
1212
1213     default:
1214       json_decref(jmsg);
1215       return NULL;
1216     }
1217
1218   encoded=json_dumps(jmsg, 0);
1219   tr_debug("tr_msg_encode: outgoing msg=%s", encoded);
1220   json_decref(jmsg);
1221   return encoded;
1222 }
1223
1224 TR_MSG *tr_msg_decode(const char *jbuf, size_t buflen)
1225 {
1226   TR_MSG *msg=NULL;
1227   json_t *jmsg = NULL;
1228   json_error_t rc;
1229   json_t *jtype=NULL;
1230   json_t *jbody=NULL;
1231   const char *mtype = NULL;
1232
1233   if (NULL == (jmsg = json_loadb(jbuf, buflen, JSON_DISABLE_EOF_CHECK, &rc))) {
1234     tr_debug("tr_msg_decode(): error loading object");
1235     return NULL;
1236   }
1237
1238   if (!(msg = malloc(sizeof(TR_MSG)))) {
1239     tr_debug("tr_msg_decode(): Error allocating TR_MSG structure.");
1240     json_decref(jmsg);
1241     return NULL;
1242   }
1243  
1244   memset(msg, 0, sizeof(TR_MSG));
1245
1246   if ((NULL == (jtype = json_object_get(jmsg, "msg_type"))) ||
1247       (NULL == (jbody = json_object_get(jmsg, "msg_body")))) {
1248     tr_debug("tr_msg_decode(): Error parsing message header.");
1249     json_decref(jmsg);
1250     tr_msg_free_decoded(msg);
1251     return NULL;
1252   }
1253
1254   mtype = json_string_value(jtype);
1255
1256   if (0 == strcmp(mtype, "tid_request")) {
1257     msg->msg_type = TID_REQUEST;
1258     tr_msg_set_req(msg, tr_msg_decode_tidreq(jbody));
1259   }
1260   else if (0 == strcmp(mtype, "tid_response")) {
1261     msg->msg_type = TID_RESPONSE;
1262     tr_msg_set_resp(msg, tr_msg_decode_tidresp(jbody));
1263   }
1264   else if (0 == strcmp(mtype, "trp_update")) {
1265     msg->msg_type = TRP_UPDATE;
1266     tr_msg_set_trp_upd(msg, tr_msg_decode_trp_upd(NULL, jbody)); /* null talloc context for now */
1267   }
1268   else if (0 == strcmp(mtype, "trp_request")) {
1269     msg->msg_type = TRP_UPDATE;
1270     tr_msg_set_trp_req(msg, tr_msg_decode_trp_req(NULL, jbody)); /* null talloc context for now */
1271   }
1272   else {
1273     msg->msg_type = TR_UNKNOWN;
1274     msg->msg_rep = NULL;
1275   }
1276
1277   json_decref(jmsg);
1278
1279   return msg;
1280 }
1281
1282 void tr_msg_free_encoded(char *jmsg)
1283 {
1284   if (jmsg)
1285     free (jmsg);
1286 }
1287
1288 void tr_msg_free_decoded(TR_MSG *msg)
1289 {
1290   if (msg) {
1291     if (msg->msg_rep!=NULL) {
1292       switch (msg->msg_type) {
1293         case TID_REQUEST:
1294           tid_req_free(tr_msg_get_req(msg));
1295           break;
1296         case TID_RESPONSE:
1297           tid_resp_free(tr_msg_get_resp(msg));
1298           break;
1299         case TRP_UPDATE:
1300           trp_upd_free(tr_msg_get_trp_upd(msg));
1301           break;
1302         case TRP_REQUEST:
1303           trp_req_free(tr_msg_get_trp_req(msg));
1304         default:
1305           break;
1306       }
1307     }
1308     free (msg);
1309   }
1310 }