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