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