1 /*
2  * ProFTPD - FTP server daemon
3  * Copyright (c) 2017-2020 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* JSON implementation (pool-based wrapper around CCAN JSON) */
26 
27 #include "json.h"
28 #include "ccan-json.h"
29 
30 struct json_list_st {
31   pool *pool;
32   JsonNode *array;
33   unsigned int item_count;
34 };
35 
36 struct json_obj_st {
37   pool *pool;
38   JsonNode *object;
39   unsigned int member_count;
40 };
41 
42 static const char *trace_channel = "json";
43 
alloc_array(pool * p)44 static pr_json_array_t *alloc_array(pool *p) {
45   pool *sub_pool;
46   pr_json_array_t *json;
47 
48   sub_pool = make_sub_pool(p);
49   pr_pool_tag(sub_pool, "JSON Array Pool");
50 
51   json = pcalloc(sub_pool, sizeof(pr_json_array_t));
52   json->pool = sub_pool;
53 
54   return json;
55 }
56 
alloc_object(pool * p)57 static pr_json_object_t *alloc_object(pool *p) {
58   pool *sub_pool;
59   pr_json_object_t *json;
60 
61   sub_pool = make_sub_pool(p);
62   pr_pool_tag(sub_pool, "JSON Object Pool");
63 
64   json = pcalloc(sub_pool, sizeof(pr_json_object_t));
65   json->pool = sub_pool;
66 
67   return json;
68 }
69 
get_count(JsonNode * json)70 static unsigned int get_count(JsonNode *json) {
71   unsigned int count;
72   JsonNode *node;
73 
74   for (count = 0, node = json_first_child(json);
75        node != NULL;
76        node = node->next) {
77     count++;
78   }
79 
80   return count;
81 }
82 
get_text(pool * p,JsonNode * json,const char * indent)83 static char *get_text(pool *p, JsonNode *json, const char *indent) {
84   char *str, *text = NULL;
85 
86   if (p == NULL ||
87       indent == NULL) {
88     errno = EINVAL;
89     return NULL;
90   }
91 
92   /* An interesting gotcha: if you use "" as the indent, then json_stringify()
93    * WILL include newlines in its text.  But if you use NULL, then it will
94    * not include newlines.  This is not the behavior we expect.
95    */
96   if (*indent == '\0') {
97     indent = NULL;
98   }
99 
100   str = json_stringify(json, indent);
101   if (str != NULL) {
102     text = pstrdup(p, str);
103     free(str);
104   }
105 
106   return text;
107 }
108 
109 /* JSON Objects */
110 
pr_json_object_alloc(pool * p)111 pr_json_object_t *pr_json_object_alloc(pool *p) {
112   pr_json_object_t *json;
113 
114   if (p == NULL) {
115     errno = EINVAL;
116     return NULL;
117   }
118 
119   json = alloc_object(p);
120   json->object = json_mkobject();
121 
122   return json;
123 }
124 
pr_json_object_free(pr_json_object_t * json)125 int pr_json_object_free(pr_json_object_t *json) {
126   if (json == NULL) {
127     errno = EINVAL;
128     return -1;
129   }
130 
131   json_delete(json->object);
132   json->object = NULL;
133 
134   destroy_pool(json->pool);
135   json->pool = NULL;
136 
137   return 0;
138 }
139 
pr_json_object_from_text(pool * p,const char * text)140 pr_json_object_t *pr_json_object_from_text(pool *p, const char *text) {
141   JsonNode *node;
142   pr_json_object_t *json;
143 
144   if (p == NULL ||
145       text == NULL) {
146     errno = EINVAL;
147     return NULL;
148   }
149 
150   if (json_validate(text) == FALSE) {
151     pr_trace_msg(trace_channel, 9, "unable to parse invalid JSON text '%s'",
152       text);
153     errno = EPERM;
154     return NULL;
155   }
156 
157   node = json_decode(text);
158   if (node->tag != JSON_OBJECT) {
159     json_delete(node);
160 
161     pr_trace_msg(trace_channel, 9, "JSON text '%s' is not a JSON object", text);
162     errno = EEXIST;
163     return NULL;
164   }
165 
166   json = alloc_object(p);
167   json->object = node;
168   json->member_count = get_count(node);
169 
170   return json;
171 }
172 
pr_json_object_to_text(pool * p,const pr_json_object_t * json,const char * indent)173 char *pr_json_object_to_text(pool *p, const pr_json_object_t *json,
174     const char *indent) {
175   if (json == NULL) {
176     errno = EINVAL;
177     return NULL;
178   }
179 
180   return get_text(p, json->object, indent);
181 }
182 
pr_json_object_count(const pr_json_object_t * json)183 int pr_json_object_count(const pr_json_object_t *json) {
184   if (json == NULL) {
185     errno = EINVAL;
186     return -1;
187   }
188 
189   return json->member_count;
190 }
191 
pr_json_object_remove(pr_json_object_t * json,const char * key)192 int pr_json_object_remove(pr_json_object_t *json, const char *key) {
193   JsonNode *node;
194 
195   if (json == NULL ||
196       key == NULL) {
197     errno = EINVAL;
198     return -1;
199   }
200 
201   node = json_find_member(json->object, key);
202   if (node != NULL) {
203     /* This CCAN JSON code automatically removes the node from its parent. */
204     json_delete(node);
205 
206     if (json->member_count > 0) {
207       json->member_count--;
208     }
209   }
210 
211   return 0;
212 }
213 
pr_json_object_exists(const pr_json_object_t * json,const char * key)214 int pr_json_object_exists(const pr_json_object_t *json, const char *key) {
215   JsonNode *node;
216 
217   if (json == NULL ||
218       key == NULL) {
219     errno = EINVAL;
220     return -1;
221   }
222 
223   node = json_find_member(json->object, key);
224   if (node == NULL) {
225     return FALSE;
226   }
227 
228   return TRUE;
229 }
230 
can_get_member(pool * p,const pr_json_object_t * json,const char * key,JsonTag tag,void * val)231 static int can_get_member(pool *p, const pr_json_object_t *json,
232     const char *key, JsonTag tag, void *val) {
233 
234   if (p == NULL ||
235       json == NULL ||
236       key == NULL) {
237     errno = EINVAL;
238     return -1;
239   }
240 
241   if (tag != JSON_NULL &&
242       val == NULL) {
243     errno = EINVAL;
244     return -1;
245   }
246 
247   return 0;
248 }
249 
can_set_member(pool * p,const pr_json_object_t * json,const char * key)250 static int can_set_member(pool *p, const pr_json_object_t *json,
251     const char *key) {
252 
253   if (p == NULL ||
254       json == NULL ||
255       key == NULL) {
256     errno = EINVAL;
257     return -1;
258   }
259 
260   return 0;
261 }
262 
get_val_from_node(pool * p,JsonNode * node,JsonTag tag,void * val)263 static int get_val_from_node(pool *p, JsonNode *node, JsonTag tag, void *val) {
264 
265   /* For any tag except JSON_NULL, we expect val to not be a NULL. */
266   if (tag != JSON_NULL &&
267       val == NULL) {
268     errno = EINVAL;
269     return -1;
270   }
271 
272   switch (tag) {
273     case JSON_NULL:
274       break;
275 
276     case JSON_BOOL:
277       *((int *) val) = node->bool_;
278       break;
279 
280     case JSON_STRING:
281       /* Fortunately, valid JSON does not allow an empty element, or
282        * a member without a value.  Thus checking for NULL string_ here
283        * would be superfluous.  The only way for that to happen is if the
284        * caller were using the CCAN JSON API directly, in which case, they
285        * get what they paid for.
286        */
287       *((char **) val) = pstrdup(p, node->string_);
288       break;
289 
290     case JSON_NUMBER:
291       *((double *) val) = node->number_;
292       break;
293 
294     case JSON_ARRAY: {
295       pr_json_array_t *array;
296 
297       array = alloc_array(p);
298 
299       /* Make a duplicate of the child array, rather than just copying
300        * its pointer.  Otherwise, freeing this array and then freeing
301        * the parent node would cause a double free.
302        *
303        * A convenient way to get a deep copy is to encode the node
304        * as a string, then decode it again.
305        */
306       if (node->children.head != NULL) {
307         char *encoded_str = NULL;
308 
309         encoded_str = json_encode(node);
310         array->array = json_decode(encoded_str);
311         free(encoded_str);
312 
313       } else {
314         array->array = json_mkarray();
315       }
316       array->item_count = get_count(array->array);
317 
318       *((pr_json_array_t **) val) = array;
319       break;
320     }
321 
322     case JSON_OBJECT: {
323       pr_json_object_t *object;
324 
325       object = alloc_object(p);
326 
327       /* Make a duplicate of the child object, rather than just copying
328        * its pointer.  Otherwise, freeing this object and then freeing
329        * the parent node would cause a double free.
330        *
331        * A convenient way to get a deep copy is to encode the node
332        * as a string, then decode it again.
333        */
334       if (node->children.head != NULL) {
335         char *encoded_str = NULL;
336 
337         encoded_str = json_encode(node);
338         object->object = json_decode(encoded_str);
339         free(encoded_str);
340 
341       } else {
342         object->object = json_mkobject();
343       }
344       object->member_count = get_count(object->object);
345 
346       *((pr_json_object_t **) val) = object;
347       break;
348     }
349   }
350 
351   return 0;
352 }
353 
get_member(pool * p,const pr_json_object_t * json,const char * key,JsonTag tag,void * val)354 static int get_member(pool *p, const pr_json_object_t *json, const char *key,
355     JsonTag tag, void *val) {
356   JsonNode *node;
357 
358   node = json_find_member(json->object, key);
359   if (node == NULL) {
360     errno = ENOENT;
361     return -1;
362   }
363 
364   if (node->tag != tag) {
365     errno = EEXIST;
366     return -1;
367   }
368 
369   return get_val_from_node(p, node, tag, val);
370 }
371 
get_node_from_val(JsonTag tag,const void * val)372 static JsonNode *get_node_from_val(JsonTag tag, const void *val) {
373   JsonNode *node = NULL;
374 
375   switch (tag) {
376     case JSON_NULL:
377       node = json_mknull();
378       break;
379 
380     case JSON_BOOL:
381       node = json_mkbool(*((int *) val));
382       break;
383 
384     case JSON_NUMBER:
385       node = json_mknumber(*((double *) val));
386       break;
387 
388     case JSON_STRING:
389       node = json_mkstring(val);
390       break;
391 
392     case JSON_ARRAY: {
393       const pr_json_array_t *array;
394 
395       array = val;
396       node = array->array;
397       break;
398     }
399 
400     case JSON_OBJECT: {
401       const pr_json_object_t *object;
402 
403       object = val;
404       node = object->object;
405       break;
406     }
407   }
408 
409   return node;
410 }
411 
set_member(pool * p,pr_json_object_t * json,const char * key,JsonTag tag,const void * val)412 static int set_member(pool *p, pr_json_object_t *json, const char *key,
413     JsonTag tag, const void *val) {
414   JsonNode *node = NULL;
415 
416   node = get_node_from_val(tag, val);
417   json_append_member(json->object, key, node);
418   json->member_count++;
419 
420   return 0;
421 }
422 
pr_json_object_get_bool(pool * p,const pr_json_object_t * json,const char * key,int * val)423 int pr_json_object_get_bool(pool *p, const pr_json_object_t *json,
424     const char *key, int *val) {
425   if (can_get_member(p, json, key, JSON_BOOL, val) < 0) {
426     return -1;
427   }
428 
429   return get_member(p, json, key, JSON_BOOL, val);
430 }
431 
pr_json_object_set_bool(pool * p,pr_json_object_t * json,const char * key,int val)432 int pr_json_object_set_bool(pool *p, pr_json_object_t *json, const char *key,
433     int val) {
434   if (can_set_member(p, json, key) < 0) {
435     return -1;
436   }
437 
438   return set_member(p, json, key, JSON_BOOL, &val);
439 }
440 
pr_json_object_get_null(pool * p,const pr_json_object_t * json,const char * key)441 int pr_json_object_get_null(pool *p, const pr_json_object_t *json,
442     const char *key) {
443   if (can_get_member(p, json, key, JSON_NULL, NULL) < 0) {
444     return -1;
445   }
446 
447   return get_member(p, json, key, JSON_NULL, NULL);
448 }
449 
pr_json_object_set_null(pool * p,pr_json_object_t * json,const char * key)450 int pr_json_object_set_null(pool *p, pr_json_object_t *json, const char *key) {
451   if (can_set_member(p, json, key) < 0) {
452     return -1;
453   }
454 
455   return set_member(p, json, key, JSON_NULL, NULL);
456 }
457 
pr_json_object_get_number(pool * p,const pr_json_object_t * json,const char * key,double * val)458 int pr_json_object_get_number(pool *p, const pr_json_object_t *json,
459     const char *key, double *val) {
460   if (can_get_member(p, json, key, JSON_NUMBER, val) < 0) {
461     return -1;
462   }
463 
464   return get_member(p, json, key, JSON_NUMBER, val);
465 }
466 
pr_json_object_set_number(pool * p,pr_json_object_t * json,const char * key,double val)467 int pr_json_object_set_number(pool *p, pr_json_object_t *json, const char *key,
468     double val) {
469   if (can_set_member(p, json, key) < 0) {
470     return -1;
471   }
472 
473   return set_member(p, json, key, JSON_NUMBER, &val);
474 }
475 
pr_json_object_get_string(pool * p,const pr_json_object_t * json,const char * key,char ** val)476 int pr_json_object_get_string(pool *p, const pr_json_object_t *json,
477     const char *key, char **val) {
478   if (can_get_member(p, json, key, JSON_STRING, val) < 0) {
479     return -1;
480   }
481 
482   return get_member(p, json, key, JSON_STRING, val);
483 }
484 
pr_json_object_set_string(pool * p,pr_json_object_t * json,const char * key,const char * val)485 int pr_json_object_set_string(pool *p, pr_json_object_t *json, const char *key,
486     const char *val) {
487   if (can_set_member(p, json, key) < 0) {
488     return -1;
489   }
490 
491   if (val == NULL) {
492     errno = EINVAL;
493     return -1;
494   }
495 
496   return set_member(p, json, key, JSON_STRING, val);
497 }
498 
pr_json_object_get_array(pool * p,const pr_json_object_t * json,const char * key,pr_json_array_t ** val)499 int pr_json_object_get_array(pool *p, const pr_json_object_t *json,
500     const char *key, pr_json_array_t **val) {
501   if (can_get_member(p, json, key, JSON_ARRAY, val) < 0) {
502     return -1;
503   }
504 
505   return get_member(p, json, key, JSON_ARRAY, val);
506 }
507 
pr_json_object_set_array(pool * p,pr_json_object_t * json,const char * key,const pr_json_array_t * val)508 int pr_json_object_set_array(pool *p, pr_json_object_t *json, const char *key,
509     const pr_json_array_t *val) {
510   if (can_set_member(p, json, key) < 0) {
511     return -1;
512   }
513 
514   if (val == NULL) {
515     errno = EINVAL;
516     return -1;
517   }
518 
519   return set_member(p, json, key, JSON_ARRAY, val);
520 }
521 
pr_json_object_get_object(pool * p,const pr_json_object_t * json,const char * key,pr_json_object_t ** val)522 int pr_json_object_get_object(pool *p, const pr_json_object_t *json,
523     const char *key, pr_json_object_t **val) {
524   if (can_get_member(p, json, key, JSON_OBJECT, val) < 0) {
525     return -1;
526   }
527 
528   return get_member(p, json, key, JSON_OBJECT, val);
529 }
530 
pr_json_object_set_object(pool * p,pr_json_object_t * json,const char * key,const pr_json_object_t * val)531 int pr_json_object_set_object(pool *p, pr_json_object_t *json, const char *key,
532     const pr_json_object_t *val) {
533   if (can_set_member(p, json, key) < 0) {
534     return -1;
535   }
536 
537   if (val == NULL) {
538     errno = EINVAL;
539     return -1;
540   }
541 
542   return set_member(p, json, key, JSON_OBJECT, val);
543 }
544 
545 /* JSON Arrays */
546 
pr_json_array_alloc(pool * p)547 pr_json_array_t *pr_json_array_alloc(pool *p) {
548   pr_json_array_t *json;
549 
550   if (p == NULL) {
551     errno = EINVAL;
552     return NULL;
553   }
554 
555   json = alloc_array(p);
556   json->array = json_mkarray();
557 
558   return json;
559 }
560 
pr_json_array_free(pr_json_array_t * json)561 int pr_json_array_free(pr_json_array_t *json) {
562   if (json == NULL) {
563     errno = EINVAL;
564     return -1;
565   }
566 
567   json_delete(json->array);
568   json->array = NULL;
569 
570   destroy_pool(json->pool);
571   json->pool = NULL;
572 
573   return 0;
574 }
575 
pr_json_array_from_text(pool * p,const char * text)576 pr_json_array_t *pr_json_array_from_text(pool *p, const char *text) {
577   JsonNode *node;
578   pr_json_array_t *json;
579 
580   if (p == NULL ||
581       text == NULL) {
582     errno = EINVAL;
583     return NULL;
584   }
585 
586   if (json_validate(text) == FALSE) {
587     pr_trace_msg(trace_channel, 9, "unable to parse invalid JSON text '%s'",
588       text);
589     errno = EPERM;
590     return NULL;
591   }
592 
593   node = json_decode(text);
594   if (node->tag != JSON_ARRAY) {
595     json_delete(node);
596 
597     pr_trace_msg(trace_channel, 9, "JSON text '%s' is not a JSON array", text);
598     errno = EEXIST;
599     return NULL;
600   }
601 
602   json = alloc_array(p);
603   json->array = node;
604   json->item_count = get_count(node);
605 
606   return json;
607 }
608 
pr_json_array_to_text(pool * p,const pr_json_array_t * json,const char * indent)609 char *pr_json_array_to_text(pool *p, const pr_json_array_t *json,
610     const char *indent) {
611   if (json == NULL) {
612     errno = EINVAL;
613     return NULL;
614   }
615 
616   return get_text(p, json->array, indent);
617 }
618 
pr_json_array_count(const pr_json_array_t * json)619 int pr_json_array_count(const pr_json_array_t *json) {
620   if (json == NULL) {
621     errno = EINVAL;
622     return -1;
623   }
624 
625   return json->item_count;
626 }
627 
pr_json_array_remove(pr_json_array_t * json,unsigned int idx)628 int pr_json_array_remove(pr_json_array_t *json, unsigned int idx) {
629   JsonNode *node;
630 
631   if (json == NULL) {
632     errno = EINVAL;
633     return -1;
634   }
635 
636   node = json_find_element(json->array, idx);
637   if (node != NULL) {
638     /* This CCAN JSON code automatically removes the node from its parent. */
639     json_delete(node);
640 
641     if (json->item_count > 0) {
642       json->item_count--;
643     }
644   }
645 
646   return 0;
647 }
648 
pr_json_array_exists(const pr_json_array_t * json,unsigned int idx)649 int pr_json_array_exists(const pr_json_array_t *json, unsigned int idx) {
650   JsonNode *node;
651 
652   if (json == NULL) {
653     errno = EINVAL;
654     return -1;
655   }
656 
657   node = json_find_element(json->array, idx);
658   if (node == NULL) {
659     return FALSE;
660   }
661 
662   return TRUE;
663 }
664 
can_get_item(pool * p,const pr_json_array_t * json,JsonTag tag,void * val)665 static int can_get_item(pool *p, const pr_json_array_t *json, JsonTag tag,
666     void *val) {
667 
668   if (p == NULL ||
669       json == NULL) {
670     errno = EINVAL;
671     return -1;
672   }
673 
674   if (tag != JSON_NULL &&
675       val == NULL) {
676     errno = EINVAL;
677     return -1;
678   }
679 
680   return 0;
681 }
682 
can_add_item(pool * p,const pr_json_array_t * json)683 static int can_add_item(pool *p, const pr_json_array_t *json) {
684 
685   if (p == NULL ||
686       json == NULL) {
687     errno = EINVAL;
688     return -1;
689   }
690 
691   return 0;
692 }
693 
get_item(pool * p,const pr_json_array_t * json,unsigned int idx,JsonTag tag,void * val)694 static int get_item(pool *p, const pr_json_array_t *json, unsigned int idx,
695     JsonTag tag, void *val) {
696   JsonNode *node;
697 
698   node = json_find_element(json->array, idx);
699   if (node == NULL) {
700     errno = ENOENT;
701     return -1;
702   }
703 
704   if (node->tag != tag) {
705     errno = EEXIST;
706     return -1;
707   }
708 
709   return get_val_from_node(p, node, tag, val);
710 }
711 
append_item(pool * p,pr_json_array_t * json,JsonTag tag,const void * val)712 static int append_item(pool *p, pr_json_array_t *json, JsonTag tag,
713     const void *val) {
714   JsonNode *node = NULL;
715 
716   node = get_node_from_val(tag, val);
717   json_append_element(json->array, node);
718   json->item_count++;
719 
720   return 0;
721 }
722 
pr_json_array_append_bool(pool * p,pr_json_array_t * json,int val)723 int pr_json_array_append_bool(pool *p, pr_json_array_t *json, int val) {
724   if (can_add_item(p, json) < 0) {
725     return -1;
726   }
727 
728   return append_item(p, json, JSON_BOOL, &val);
729 }
730 
pr_json_array_get_bool(pool * p,const pr_json_array_t * json,unsigned int idx,int * val)731 int pr_json_array_get_bool(pool *p, const pr_json_array_t *json,
732     unsigned int idx, int *val) {
733   if (can_get_item(p, json, JSON_BOOL, val) < 0) {
734     return -1;
735   }
736 
737   return get_item(p, json, idx, JSON_BOOL, val);
738 }
739 
pr_json_array_append_null(pool * p,pr_json_array_t * json)740 int pr_json_array_append_null(pool *p, pr_json_array_t *json) {
741   if (can_add_item(p, json) < 0) {
742     return -1;
743   }
744 
745   return append_item(p, json, JSON_NULL, NULL);
746 }
747 
pr_json_array_get_null(pool * p,const pr_json_array_t * json,unsigned int idx)748 int pr_json_array_get_null(pool *p, const pr_json_array_t *json,
749     unsigned int idx) {
750   if (can_get_item(p, json, JSON_NULL, NULL) < 0) {
751     return -1;
752   }
753 
754   return get_item(p, json, idx, JSON_NULL, NULL);
755 }
756 
pr_json_array_append_number(pool * p,pr_json_array_t * json,double val)757 int pr_json_array_append_number(pool *p, pr_json_array_t *json, double val) {
758   if (can_add_item(p, json) < 0) {
759     return -1;
760   }
761 
762   return append_item(p, json, JSON_NUMBER, &val);
763 }
764 
pr_json_array_get_number(pool * p,const pr_json_array_t * json,unsigned int idx,double * val)765 int pr_json_array_get_number(pool *p, const pr_json_array_t *json,
766     unsigned int idx, double *val) {
767   if (can_get_item(p, json, JSON_NUMBER, val) < 0) {
768     return -1;
769   }
770 
771   return get_item(p, json, idx, JSON_NUMBER, val);
772 }
773 
pr_json_array_append_string(pool * p,pr_json_array_t * json,const char * val)774 int pr_json_array_append_string(pool *p, pr_json_array_t *json,
775     const char *val) {
776   if (can_add_item(p, json) < 0) {
777     return -1;
778   }
779 
780   if (val == NULL) {
781     errno = EINVAL;
782     return -1;
783   }
784 
785   return append_item(p, json, JSON_STRING, val);
786 }
787 
pr_json_array_get_string(pool * p,const pr_json_array_t * json,unsigned int idx,char ** val)788 int pr_json_array_get_string(pool *p, const pr_json_array_t *json,
789     unsigned int idx, char **val) {
790   if (can_get_item(p, json, JSON_STRING, val) < 0) {
791     return -1;
792   }
793 
794   return get_item(p, json, idx, JSON_STRING, val);
795 }
796 
pr_json_array_append_array(pool * p,pr_json_array_t * json,const pr_json_array_t * val)797 int pr_json_array_append_array(pool *p, pr_json_array_t *json,
798     const pr_json_array_t *val) {
799   if (can_add_item(p, json) < 0) {
800     return -1;
801   }
802 
803   if (val == NULL) {
804     errno = EINVAL;
805     return -1;
806   }
807 
808   return append_item(p, json, JSON_ARRAY, val);
809 }
810 
pr_json_array_get_array(pool * p,const pr_json_array_t * json,unsigned int idx,pr_json_array_t ** val)811 int pr_json_array_get_array(pool *p, const pr_json_array_t *json,
812     unsigned int idx, pr_json_array_t **val) {
813   if (can_get_item(p, json, JSON_ARRAY, val) < 0) {
814     return -1;
815   }
816 
817   return get_item(p, json, idx, JSON_ARRAY, val);
818 }
819 
pr_json_array_append_object(pool * p,pr_json_array_t * json,const pr_json_object_t * val)820 int pr_json_array_append_object(pool *p, pr_json_array_t *json,
821     const pr_json_object_t *val) {
822   if (can_add_item(p, json) < 0) {
823     return -1;
824   }
825 
826   if (val == NULL) {
827     errno = EINVAL;
828     return -1;
829   }
830 
831   return append_item(p, json, JSON_OBJECT, val);
832 }
833 
pr_json_array_get_object(pool * p,const pr_json_array_t * json,unsigned int idx,pr_json_object_t ** val)834 int pr_json_array_get_object(pool *p, const pr_json_array_t *json,
835     unsigned int idx, pr_json_object_t **val) {
836   if (can_get_item(p, json, JSON_OBJECT, val) < 0) {
837     return -1;
838   }
839 
840   return get_item(p, json, idx, JSON_OBJECT, val);
841 }
842 
pr_json_text_validate(pool * p,const char * text)843 int pr_json_text_validate(pool *p, const char *text) {
844   if (p == NULL ||
845       text == NULL) {
846     errno = EINVAL;
847     return -1;
848   }
849 
850   return json_validate(text);
851 }
852 
pr_json_type_name(unsigned int json_type)853 const char *pr_json_type_name(unsigned int json_type) {
854   const char *name;
855 
856   switch (json_type) {
857     case PR_JSON_TYPE_BOOL:
858       name = "boolean";
859       break;
860 
861     case PR_JSON_TYPE_NUMBER:
862       name = "number";
863       break;
864 
865     case PR_JSON_TYPE_NULL:
866       name = "null";
867       break;
868 
869     case PR_JSON_TYPE_STRING:
870       name = "string";
871       break;
872 
873     case PR_JSON_TYPE_ARRAY:
874       name = "array";
875       break;
876 
877     case PR_JSON_TYPE_OBJECT:
878       name = "object";
879       break;
880 
881     default:
882       errno = EINVAL;
883       name = NULL;
884   }
885 
886   return name;
887 }
888 
json_oom(void)889 static void json_oom(void) {
890   pr_log_pri(PR_LOG_ALERT, "%s", "Out of memory!");
891   exit(1);
892 }
893 
894 
init_json(void)895 int init_json(void) {
896   json_set_oom(json_oom);
897   return 0;
898 }
899 
finish_json(void)900 int finish_json(void) {
901   json_set_oom(NULL);
902   return 0;
903 }
904 
905