Coverage Report

Created: 2025-11-24 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/proftpd/src/json.c
Line
Count
Source
1
/*
2
 * ProFTPD - FTP server daemon
3
 * Copyright (c) 2017-2025 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
44
0
static pr_json_array_t *alloc_array(pool *p) {
45
0
  pool *sub_pool;
46
0
  pr_json_array_t *json;
47
48
0
  sub_pool = make_sub_pool(p);
49
0
  pr_pool_tag(sub_pool, "JSON Array Pool");
50
51
0
  json = pcalloc(sub_pool, sizeof(pr_json_array_t));
52
0
  json->pool = sub_pool;
53
54
0
  return json;
55
0
}
56
57
3.60k
static pr_json_object_t *alloc_object(pool *p) {
58
3.60k
  pool *sub_pool;
59
3.60k
  pr_json_object_t *json;
60
61
3.60k
  sub_pool = make_sub_pool(p);
62
3.60k
  pr_pool_tag(sub_pool, "JSON Object Pool");
63
64
3.60k
  json = pcalloc(sub_pool, sizeof(pr_json_object_t));
65
3.60k
  json->pool = sub_pool;
66
67
3.60k
  return json;
68
3.60k
}
69
70
3.60k
static unsigned int get_count(JsonNode *json) {
71
3.60k
  unsigned int count;
72
3.60k
  JsonNode *node;
73
74
3.60k
  for (count = 0, node = json_first_child(json);
75
14.4k
       node != NULL;
76
10.8k
       node = node->next) {
77
10.8k
    count++;
78
10.8k
  }
79
80
3.60k
  return count;
81
3.60k
}
82
83
0
static char *get_text(pool *p, JsonNode *json, const char *indent) {
84
0
  char *str, *text = NULL;
85
86
0
  if (p == NULL ||
87
0
      indent == NULL) {
88
0
    errno = EINVAL;
89
0
    return NULL;
90
0
  }
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
0
  if (*indent == '\0') {
97
0
    indent = NULL;
98
0
  }
99
100
0
  str = json_stringify(json, indent);
101
0
  if (str != NULL) {
102
0
    text = pstrdup(p, str);
103
0
    free(str);
104
0
  }
105
106
0
  return text;
107
0
}
108
109
0
static int get_type(JsonNode *node) {
110
0
  int type;
111
112
0
  switch (node->tag) {
113
0
    case JSON_NULL:
114
0
      type = PR_JSON_TYPE_NULL;
115
0
      break;
116
117
0
    case JSON_BOOL:
118
0
      type = PR_JSON_TYPE_BOOL;
119
0
      break;
120
121
0
    case JSON_STRING:
122
0
      type = PR_JSON_TYPE_STRING;
123
0
      break;
124
125
0
    case JSON_NUMBER:
126
0
      type = PR_JSON_TYPE_NUMBER;
127
0
      break;
128
129
0
    case JSON_ARRAY:
130
0
      type = PR_JSON_TYPE_ARRAY;
131
0
      break;
132
133
0
    case JSON_OBJECT:
134
0
      type = PR_JSON_TYPE_OBJECT;
135
0
      break;
136
137
0
    default:
138
0
      errno = EINVAL;
139
0
      return -1;
140
0
  }
141
142
0
  return type;
143
0
}
144
145
/* JSON Objects */
146
147
0
pr_json_object_t *pr_json_object_alloc(pool *p) {
148
0
  pr_json_object_t *json;
149
150
0
  if (p == NULL) {
151
0
    errno = EINVAL;
152
0
    return NULL;
153
0
  }
154
155
0
  json = alloc_object(p);
156
0
  json->object = json_mkobject();
157
158
0
  return json;
159
0
}
160
161
8.68k
int pr_json_object_free(pr_json_object_t *json) {
162
8.68k
  if (json == NULL) {
163
5.08k
    errno = EINVAL;
164
5.08k
    return -1;
165
5.08k
  }
166
167
3.60k
  json_delete(json->object);
168
3.60k
  json->object = NULL;
169
170
3.60k
  destroy_pool(json->pool);
171
3.60k
  return 0;
172
8.68k
}
173
174
8.68k
pr_json_object_t *pr_json_object_from_text(pool *p, const char *text) {
175
8.68k
  JsonNode *node;
176
8.68k
  pr_json_object_t *json;
177
178
8.68k
  if (p == NULL ||
179
8.68k
      text == NULL) {
180
0
    errno = EINVAL;
181
0
    return NULL;
182
0
  }
183
184
8.68k
  if (json_validate(text) == FALSE) {
185
4.54k
    pr_trace_msg(trace_channel, 9, "unable to parse invalid JSON text '%s'",
186
4.54k
      text);
187
4.54k
    errno = EPERM;
188
4.54k
    return NULL;
189
4.54k
  }
190
191
4.13k
  node = json_decode(text);
192
4.13k
  if (node->tag != JSON_OBJECT) {
193
536
    json_delete(node);
194
195
536
    pr_trace_msg(trace_channel, 9, "JSON text '%s' is not a JSON object", text);
196
536
    errno = EEXIST;
197
536
    return NULL;
198
536
  }
199
200
3.60k
  json = alloc_object(p);
201
3.60k
  json->object = node;
202
3.60k
  json->member_count = get_count(node);
203
204
3.60k
  return json;
205
4.13k
}
206
207
char *pr_json_object_to_text(pool *p, const pr_json_object_t *json,
208
0
    const char *indent) {
209
0
  if (json == NULL) {
210
0
    errno = EINVAL;
211
0
    return NULL;
212
0
  }
213
214
0
  return get_text(p, json->object, indent);
215
0
}
216
217
0
int pr_json_object_count(const pr_json_object_t *json) {
218
0
  if (json == NULL) {
219
0
    errno = EINVAL;
220
0
    return -1;
221
0
  }
222
223
0
  return json->member_count;
224
0
}
225
226
0
int pr_json_object_remove(pr_json_object_t *json, const char *key) {
227
0
  JsonNode *node;
228
229
0
  if (json == NULL ||
230
0
      key == NULL) {
231
0
    errno = EINVAL;
232
0
    return -1;
233
0
  }
234
235
0
  node = json_find_member(json->object, key);
236
0
  if (node != NULL) {
237
    /* This CCAN JSON code automatically removes the node from its parent. */
238
0
    json_delete(node);
239
240
0
    if (json->member_count > 0) {
241
0
      json->member_count--;
242
0
    }
243
0
  }
244
245
0
  return 0;
246
0
}
247
248
0
int pr_json_object_exists(const pr_json_object_t *json, const char *key) {
249
0
  JsonNode *node;
250
251
0
  if (json == NULL ||
252
0
      key == NULL) {
253
0
    errno = EINVAL;
254
0
    return -1;
255
0
  }
256
257
0
  node = json_find_member(json->object, key);
258
0
  if (node == NULL) {
259
0
    return FALSE;
260
0
  }
261
262
0
  return TRUE;
263
0
}
264
265
static int can_get_member(pool *p, const pr_json_object_t *json,
266
0
    const char *key, JsonTag tag, void *val) {
267
268
0
  if (p == NULL ||
269
0
      json == NULL ||
270
0
      key == NULL) {
271
0
    errno = EINVAL;
272
0
    return -1;
273
0
  }
274
275
0
  if (tag != JSON_NULL &&
276
0
      val == NULL) {
277
0
    errno = EINVAL;
278
0
    return -1;
279
0
  }
280
281
0
  return 0;
282
0
}
283
284
static int can_set_member(pool *p, const pr_json_object_t *json,
285
0
    const char *key) {
286
287
0
  if (p == NULL ||
288
0
      json == NULL ||
289
0
      key == NULL) {
290
0
    errno = EINVAL;
291
0
    return -1;
292
0
  }
293
294
0
  return 0;
295
0
}
296
297
0
static int get_val_from_node(pool *p, JsonNode *node, JsonTag tag, void *val) {
298
299
  /* For any tag except JSON_NULL, we expect val to not be a NULL. */
300
0
  if (tag != JSON_NULL &&
301
0
      val == NULL) {
302
0
    errno = EINVAL;
303
0
    return -1;
304
0
  }
305
306
0
  switch (tag) {
307
0
    case JSON_NULL:
308
0
      break;
309
310
0
    case JSON_BOOL:
311
0
      *((int *) val) = node->bool_;
312
0
      break;
313
314
0
    case JSON_STRING:
315
      /* Fortunately, valid JSON does not allow an empty element, or
316
       * a member without a value.  Thus checking for NULL string_ here
317
       * would be superfluous.  The only way for that to happen is if the
318
       * caller were using the CCAN JSON API directly, in which case, they
319
       * get what they paid for.
320
       */
321
0
      *((char **) val) = pstrdup(p, node->string_);
322
0
      break;
323
324
0
    case JSON_NUMBER:
325
0
      *((double *) val) = node->number_;
326
0
      break;
327
328
0
    case JSON_ARRAY: {
329
0
      pr_json_array_t *array;
330
331
0
      array = alloc_array(p);
332
333
      /* Make a duplicate of the child array, rather than just copying
334
       * its pointer.  Otherwise, freeing this array and then freeing
335
       * the parent node would cause a double free.
336
       *
337
       * A convenient way to get a deep copy is to encode the node
338
       * as a string, then decode it again.
339
       */
340
0
      if (node->children.head != NULL) {
341
0
        char *encoded_str = NULL;
342
343
0
        encoded_str = json_encode(node);
344
0
        array->array = json_decode(encoded_str);
345
0
        free(encoded_str);
346
347
0
      } else {
348
0
        array->array = json_mkarray();
349
0
      }
350
0
      array->item_count = get_count(array->array);
351
352
0
      *((pr_json_array_t **) val) = array;
353
0
      break;
354
0
    }
355
356
0
    case JSON_OBJECT: {
357
0
      pr_json_object_t *object;
358
359
0
      object = alloc_object(p);
360
361
      /* Make a duplicate of the child object, rather than just copying
362
       * its pointer.  Otherwise, freeing this object and then freeing
363
       * the parent node would cause a double free.
364
       *
365
       * A convenient way to get a deep copy is to encode the node
366
       * as a string, then decode it again.
367
       */
368
0
      if (node->children.head != NULL) {
369
0
        char *encoded_str = NULL;
370
371
0
        encoded_str = json_encode(node);
372
0
        object->object = json_decode(encoded_str);
373
0
        free(encoded_str);
374
375
0
      } else {
376
0
        object->object = json_mkobject();
377
0
      }
378
0
      object->member_count = get_count(object->object);
379
380
0
      *((pr_json_object_t **) val) = object;
381
0
      break;
382
0
    }
383
384
0
    default:
385
0
      break;
386
0
  }
387
388
0
  return 0;
389
0
}
390
391
static int get_member(pool *p, const pr_json_object_t *json, const char *key,
392
0
    JsonTag tag, void *val) {
393
0
  JsonNode *node;
394
395
0
  node = json_find_member(json->object, key);
396
0
  if (node == NULL) {
397
0
    errno = ENOENT;
398
0
    return -1;
399
0
  }
400
401
0
  if (node->tag != tag) {
402
0
    errno = EEXIST;
403
0
    return -1;
404
0
  }
405
406
0
  return get_val_from_node(p, node, tag, val);
407
0
}
408
409
0
static JsonNode *get_node_from_val(JsonTag tag, const void *val) {
410
0
  JsonNode *node = NULL;
411
412
0
  switch (tag) {
413
0
    case JSON_NULL:
414
0
      node = json_mknull();
415
0
      break;
416
417
0
    case JSON_BOOL:
418
0
      node = json_mkbool(*((int *) val));
419
0
      break;
420
421
0
    case JSON_NUMBER:
422
0
      node = json_mknumber(*((double *) val));
423
0
      break;
424
425
0
    case JSON_STRING:
426
0
      node = json_mkstring(val);
427
0
      break;
428
429
0
    case JSON_ARRAY: {
430
0
      const pr_json_array_t *array;
431
432
0
      array = val;
433
0
      node = array->array;
434
0
      break;
435
0
    }
436
437
0
    case JSON_OBJECT: {
438
0
      const pr_json_object_t *object;
439
440
0
      object = val;
441
0
      node = object->object;
442
0
      break;
443
0
    }
444
445
0
    default:
446
0
      break;
447
0
  }
448
449
0
  return node;
450
0
}
451
452
static int set_member(pool *p, pr_json_object_t *json, const char *key,
453
0
    JsonTag tag, const void *val) {
454
0
  JsonNode *node = NULL;
455
456
0
  node = get_node_from_val(tag, val);
457
0
  json_append_member(json->object, key, node);
458
0
  json->member_count++;
459
460
0
  return 0;
461
0
}
462
463
int pr_json_object_foreach(pool *p, const pr_json_object_t *json,
464
    int (*cb)(const char *key, int val_type, const void *val, size_t valsz,
465
0
    void *cb_data), void *user_data) {
466
0
  JsonNode *iter;
467
468
0
  if (p == NULL ||
469
0
      json == NULL ||
470
0
      cb == NULL) {
471
0
    errno = EINVAL;
472
0
    return -1;
473
0
  }
474
475
0
  for (iter = json_first_child(json->object); iter != NULL; iter = iter->next) {
476
0
    int res, val_type, xerrno;
477
0
    const void *val = NULL;
478
0
    size_t valsz = 0;
479
480
0
    pr_signals_handle();
481
482
0
    val_type = get_type(iter);
483
0
    if (val_type < 0) {
484
0
      xerrno = errno;
485
486
0
      pr_trace_msg(trace_channel, 9, "unknown value type %d in object",
487
0
        (int) iter->tag);
488
489
0
      errno = xerrno;
490
0
      return -1;
491
0
    }
492
493
0
    switch (val_type) {
494
0
      case PR_JSON_TYPE_BOOL:
495
0
        val = &(iter->bool_);
496
0
        valsz = sizeof(iter->bool_);
497
0
        break;
498
499
0
      case PR_JSON_TYPE_NUMBER:
500
0
        val = &(iter->number_);
501
0
        valsz = sizeof(iter->number_);
502
0
        break;
503
504
0
      case PR_JSON_TYPE_NULL:
505
0
        val = NULL;
506
0
        valsz = 0;
507
0
        break;
508
509
0
      case PR_JSON_TYPE_STRING:
510
0
        val = iter->string_;
511
0
        valsz = strlen(iter->string_);
512
0
        break;
513
514
0
      case PR_JSON_TYPE_ARRAY: {
515
0
        pr_json_array_t *array;
516
517
0
        (void) get_val_from_node(p, iter, JSON_ARRAY, &array);
518
0
        if (array != NULL) {
519
0
          val = array;
520
0
        }
521
522
0
        valsz = 0;
523
0
        break;
524
0
      }
525
526
0
      case PR_JSON_TYPE_OBJECT: {
527
0
        pr_json_object_t *object = NULL;
528
529
0
        (void) get_val_from_node(p, iter, JSON_OBJECT, &object);
530
0
        if (object != NULL) {
531
0
          val = object;
532
0
        }
533
534
0
        valsz = 0;
535
0
        break;
536
0
      }
537
538
0
      default:
539
        /* Unknown types are already detected/rejected above. */
540
0
        break;
541
0
    }
542
543
0
    res = (cb)(iter->key, val_type, val, valsz, user_data);
544
0
    xerrno = errno;
545
546
0
    switch (val_type) {
547
0
      case PR_JSON_TYPE_ARRAY:
548
0
        pr_json_array_free((pr_json_array_t *) val);
549
0
        break;
550
551
0
      case PR_JSON_TYPE_OBJECT:
552
0
        pr_json_object_free((pr_json_object_t *) val);
553
0
        break;
554
555
0
      default:
556
0
        break;
557
0
    }
558
559
0
    if (res < 0) {
560
0
      errno = xerrno;
561
0
      return -1;
562
0
    }
563
0
  }
564
565
0
  return 0;
566
0
}
567
568
int pr_json_object_get_bool(pool *p, const pr_json_object_t *json,
569
0
    const char *key, int *val) {
570
0
  if (can_get_member(p, json, key, JSON_BOOL, val) < 0) {
571
0
    return -1;
572
0
  }
573
574
0
  return get_member(p, json, key, JSON_BOOL, val);
575
0
}
576
577
int pr_json_object_set_bool(pool *p, pr_json_object_t *json, const char *key,
578
0
    int val) {
579
0
  if (can_set_member(p, json, key) < 0) {
580
0
    return -1;
581
0
  }
582
583
0
  return set_member(p, json, key, JSON_BOOL, &val);
584
0
}
585
586
int pr_json_object_get_null(pool *p, const pr_json_object_t *json,
587
0
    const char *key) {
588
0
  if (can_get_member(p, json, key, JSON_NULL, NULL) < 0) {
589
0
    return -1;
590
0
  }
591
592
0
  return get_member(p, json, key, JSON_NULL, NULL);
593
0
}
594
595
0
int pr_json_object_set_null(pool *p, pr_json_object_t *json, const char *key) {
596
0
  if (can_set_member(p, json, key) < 0) {
597
0
    return -1;
598
0
  }
599
600
0
  return set_member(p, json, key, JSON_NULL, NULL);
601
0
}
602
603
int pr_json_object_get_number(pool *p, const pr_json_object_t *json,
604
0
    const char *key, double *val) {
605
0
  if (can_get_member(p, json, key, JSON_NUMBER, val) < 0) {
606
0
    return -1;
607
0
  }
608
609
0
  return get_member(p, json, key, JSON_NUMBER, val);
610
0
}
611
612
int pr_json_object_set_number(pool *p, pr_json_object_t *json, const char *key,
613
0
    double val) {
614
0
  if (can_set_member(p, json, key) < 0) {
615
0
    return -1;
616
0
  }
617
618
0
  return set_member(p, json, key, JSON_NUMBER, &val);
619
0
}
620
621
int pr_json_object_get_string(pool *p, const pr_json_object_t *json,
622
0
    const char *key, char **val) {
623
0
  if (can_get_member(p, json, key, JSON_STRING, val) < 0) {
624
0
    return -1;
625
0
  }
626
627
0
  return get_member(p, json, key, JSON_STRING, val);
628
0
}
629
630
int pr_json_object_set_string(pool *p, pr_json_object_t *json, const char *key,
631
0
    const char *val) {
632
0
  if (can_set_member(p, json, key) < 0) {
633
0
    return -1;
634
0
  }
635
636
0
  if (val == NULL) {
637
0
    errno = EINVAL;
638
0
    return -1;
639
0
  }
640
641
0
  return set_member(p, json, key, JSON_STRING, val);
642
0
}
643
644
int pr_json_object_get_array(pool *p, const pr_json_object_t *json,
645
0
    const char *key, pr_json_array_t **val) {
646
0
  if (can_get_member(p, json, key, JSON_ARRAY, val) < 0) {
647
0
    return -1;
648
0
  }
649
650
0
  return get_member(p, json, key, JSON_ARRAY, val);
651
0
}
652
653
int pr_json_object_set_array(pool *p, pr_json_object_t *json, const char *key,
654
0
    const pr_json_array_t *val) {
655
0
  if (can_set_member(p, json, key) < 0) {
656
0
    return -1;
657
0
  }
658
659
0
  if (val == NULL) {
660
0
    errno = EINVAL;
661
0
    return -1;
662
0
  }
663
664
0
  return set_member(p, json, key, JSON_ARRAY, val);
665
0
}
666
667
int pr_json_object_get_object(pool *p, const pr_json_object_t *json,
668
0
    const char *key, pr_json_object_t **val) {
669
0
  if (can_get_member(p, json, key, JSON_OBJECT, val) < 0) {
670
0
    return -1;
671
0
  }
672
673
0
  return get_member(p, json, key, JSON_OBJECT, val);
674
0
}
675
676
int pr_json_object_set_object(pool *p, pr_json_object_t *json, const char *key,
677
0
    const pr_json_object_t *val) {
678
0
  if (can_set_member(p, json, key) < 0) {
679
0
    return -1;
680
0
  }
681
682
0
  if (val == NULL) {
683
0
    errno = EINVAL;
684
0
    return -1;
685
0
  }
686
687
0
  return set_member(p, json, key, JSON_OBJECT, val);
688
0
}
689
690
/* JSON Arrays */
691
692
0
pr_json_array_t *pr_json_array_alloc(pool *p) {
693
0
  pr_json_array_t *json;
694
695
0
  if (p == NULL) {
696
0
    errno = EINVAL;
697
0
    return NULL;
698
0
  }
699
700
0
  json = alloc_array(p);
701
0
  json->array = json_mkarray();
702
703
0
  return json;
704
0
}
705
706
0
int pr_json_array_free(pr_json_array_t *json) {
707
0
  if (json == NULL) {
708
0
    errno = EINVAL;
709
0
    return -1;
710
0
  }
711
712
0
  json_delete(json->array);
713
0
  json->array = NULL;
714
715
0
  destroy_pool(json->pool);
716
0
  return 0;
717
0
}
718
719
int pr_json_array_foreach(pool *p, const pr_json_array_t *json,
720
    int (*cb)(int val_type, const void *val, size_t valsz, void *cb_data),
721
0
    void *user_data) {
722
0
  JsonNode *iter;
723
724
0
  if (p == NULL ||
725
0
      json == NULL ||
726
0
      cb == NULL) {
727
0
    errno = EINVAL;
728
0
    return -1;
729
0
  }
730
731
0
  for (iter = json_first_child(json->array); iter != NULL; iter = iter->next) {
732
0
    int res, val_type, xerrno;
733
0
    const void *val = NULL;
734
0
    size_t valsz = 0;
735
736
0
    pr_signals_handle();
737
738
0
    val_type = get_type(iter);
739
0
    if (val_type < 0) {
740
0
      xerrno = errno;
741
742
0
      pr_trace_msg(trace_channel, 9, "unknown value type %d in array",
743
0
        (int) iter->tag);
744
745
0
      errno = xerrno;
746
0
      return -1;
747
0
    }
748
749
0
    switch (val_type) {
750
0
      case PR_JSON_TYPE_BOOL:
751
0
        val = &(iter->bool_);
752
0
        valsz = sizeof(iter->bool_);
753
0
        break;
754
755
0
      case PR_JSON_TYPE_NUMBER:
756
0
        val = &(iter->number_);
757
0
        valsz = sizeof(iter->number_);
758
0
        break;
759
760
0
      case PR_JSON_TYPE_NULL:
761
0
        val = NULL;
762
0
        valsz = 0;
763
0
        break;
764
765
0
      case PR_JSON_TYPE_STRING:
766
0
        val = iter->string_;
767
0
        valsz = strlen(iter->string_);
768
0
        break;
769
770
0
      case PR_JSON_TYPE_ARRAY: {
771
0
        pr_json_array_t *array;
772
773
0
        (void) get_val_from_node(p, iter, JSON_ARRAY, &array);
774
0
        if (array != NULL) {
775
0
          val = array;
776
0
        }
777
778
0
        valsz = 0;
779
0
        break;
780
0
      }
781
782
0
      case PR_JSON_TYPE_OBJECT: {
783
0
        pr_json_object_t *object = NULL;
784
785
0
        (void) get_val_from_node(p, iter, JSON_OBJECT, &object);
786
0
        if (object != NULL) {
787
0
          val = object;
788
0
        }
789
790
0
        valsz = 0;
791
0
        break;
792
0
      }
793
794
0
      default:
795
        /* Unknown types are already detected/rejected above. */
796
0
        break;
797
0
    }
798
799
0
    res = (cb)(val_type, val, valsz, user_data);
800
0
    xerrno = errno;
801
802
0
    switch (val_type) {
803
0
      case PR_JSON_TYPE_ARRAY:
804
0
        pr_json_array_free((pr_json_array_t *) val);
805
0
        break;
806
807
0
      case PR_JSON_TYPE_OBJECT:
808
0
        pr_json_object_free((pr_json_object_t *) val);
809
0
        break;
810
811
0
      default:
812
0
        break;
813
0
    }
814
815
0
    if (res < 0) {
816
0
      errno = xerrno;
817
0
      return -1;
818
0
    }
819
0
  }
820
821
0
  return 0;
822
0
}
823
824
0
pr_json_array_t *pr_json_array_from_text(pool *p, const char *text) {
825
0
  JsonNode *node;
826
0
  pr_json_array_t *json;
827
828
0
  if (p == NULL ||
829
0
      text == NULL) {
830
0
    errno = EINVAL;
831
0
    return NULL;
832
0
  }
833
834
0
  if (json_validate(text) == FALSE) {
835
0
    pr_trace_msg(trace_channel, 9, "unable to parse invalid JSON text '%s'",
836
0
      text);
837
0
    errno = EPERM;
838
0
    return NULL;
839
0
  }
840
841
0
  node = json_decode(text);
842
0
  if (node->tag != JSON_ARRAY) {
843
0
    json_delete(node);
844
845
0
    pr_trace_msg(trace_channel, 9, "JSON text '%s' is not a JSON array", text);
846
0
    errno = EEXIST;
847
0
    return NULL;
848
0
  }
849
850
0
  json = alloc_array(p);
851
0
  json->array = node;
852
0
  json->item_count = get_count(node);
853
854
0
  return json;
855
0
}
856
857
char *pr_json_array_to_text(pool *p, const pr_json_array_t *json,
858
0
    const char *indent) {
859
0
  if (json == NULL) {
860
0
    errno = EINVAL;
861
0
    return NULL;
862
0
  }
863
864
0
  return get_text(p, json->array, indent);
865
0
}
866
867
0
int pr_json_array_count(const pr_json_array_t *json) {
868
0
  if (json == NULL) {
869
0
    errno = EINVAL;
870
0
    return -1;
871
0
  }
872
873
0
  return json->item_count;
874
0
}
875
876
0
int pr_json_array_remove(pr_json_array_t *json, unsigned int idx) {
877
0
  JsonNode *node;
878
879
0
  if (json == NULL) {
880
0
    errno = EINVAL;
881
0
    return -1;
882
0
  }
883
884
0
  node = json_find_element(json->array, idx);
885
0
  if (node != NULL) {
886
    /* This CCAN JSON code automatically removes the node from its parent. */
887
0
    json_delete(node);
888
889
0
    if (json->item_count > 0) {
890
0
      json->item_count--;
891
0
    }
892
0
  }
893
894
0
  return 0;
895
0
}
896
897
0
int pr_json_array_exists(const pr_json_array_t *json, unsigned int idx) {
898
0
  JsonNode *node;
899
900
0
  if (json == NULL) {
901
0
    errno = EINVAL;
902
0
    return -1;
903
0
  }
904
905
0
  node = json_find_element(json->array, idx);
906
0
  if (node == NULL) {
907
0
    return FALSE;
908
0
  }
909
910
0
  return TRUE;
911
0
}
912
913
static int can_get_item(pool *p, const pr_json_array_t *json, JsonTag tag,
914
0
    void *val) {
915
916
0
  if (p == NULL ||
917
0
      json == NULL) {
918
0
    errno = EINVAL;
919
0
    return -1;
920
0
  }
921
922
0
  if (tag != JSON_NULL &&
923
0
      val == NULL) {
924
0
    errno = EINVAL;
925
0
    return -1;
926
0
  }
927
928
0
  return 0;
929
0
}
930
931
0
static int can_add_item(pool *p, const pr_json_array_t *json) {
932
933
0
  if (p == NULL ||
934
0
      json == NULL) {
935
0
    errno = EINVAL;
936
0
    return -1;
937
0
  }
938
939
0
  return 0;
940
0
}
941
942
static int get_item(pool *p, const pr_json_array_t *json, unsigned int idx,
943
0
    JsonTag tag, void *val) {
944
0
  JsonNode *node;
945
946
0
  node = json_find_element(json->array, idx);
947
0
  if (node == NULL) {
948
0
    errno = ENOENT;
949
0
    return -1;
950
0
  }
951
952
0
  if (node->tag != tag) {
953
0
    errno = EEXIST;
954
0
    return -1;
955
0
  }
956
957
0
  return get_val_from_node(p, node, tag, val);
958
0
}
959
960
static int append_item(pool *p, pr_json_array_t *json, JsonTag tag,
961
0
    const void *val) {
962
0
  JsonNode *node = NULL;
963
964
0
  node = get_node_from_val(tag, val);
965
0
  json_append_element(json->array, node);
966
0
  json->item_count++;
967
968
0
  return 0;
969
0
}
970
971
0
int pr_json_array_append_bool(pool *p, pr_json_array_t *json, int val) {
972
0
  if (can_add_item(p, json) < 0) {
973
0
    return -1;
974
0
  }
975
976
0
  return append_item(p, json, JSON_BOOL, &val);
977
0
}
978
979
int pr_json_array_get_bool(pool *p, const pr_json_array_t *json,
980
0
    unsigned int idx, int *val) {
981
0
  if (can_get_item(p, json, JSON_BOOL, val) < 0) {
982
0
    return -1;
983
0
  }
984
985
0
  return get_item(p, json, idx, JSON_BOOL, val);
986
0
}
987
988
0
int pr_json_array_append_null(pool *p, pr_json_array_t *json) {
989
0
  if (can_add_item(p, json) < 0) {
990
0
    return -1;
991
0
  }
992
993
0
  return append_item(p, json, JSON_NULL, NULL);
994
0
}
995
996
int pr_json_array_get_null(pool *p, const pr_json_array_t *json,
997
0
    unsigned int idx) {
998
0
  if (can_get_item(p, json, JSON_NULL, NULL) < 0) {
999
0
    return -1;
1000
0
  }
1001
1002
0
  return get_item(p, json, idx, JSON_NULL, NULL);
1003
0
}
1004
1005
0
int pr_json_array_append_number(pool *p, pr_json_array_t *json, double val) {
1006
0
  if (can_add_item(p, json) < 0) {
1007
0
    return -1;
1008
0
  }
1009
1010
0
  return append_item(p, json, JSON_NUMBER, &val);
1011
0
}
1012
1013
int pr_json_array_get_number(pool *p, const pr_json_array_t *json,
1014
0
    unsigned int idx, double *val) {
1015
0
  if (can_get_item(p, json, JSON_NUMBER, val) < 0) {
1016
0
    return -1;
1017
0
  }
1018
1019
0
  return get_item(p, json, idx, JSON_NUMBER, val);
1020
0
}
1021
1022
int pr_json_array_append_string(pool *p, pr_json_array_t *json,
1023
0
    const char *val) {
1024
0
  if (can_add_item(p, json) < 0) {
1025
0
    return -1;
1026
0
  }
1027
1028
0
  if (val == NULL) {
1029
0
    errno = EINVAL;
1030
0
    return -1;
1031
0
  }
1032
1033
0
  return append_item(p, json, JSON_STRING, val);
1034
0
}
1035
1036
int pr_json_array_get_string(pool *p, const pr_json_array_t *json,
1037
0
    unsigned int idx, char **val) {
1038
0
  if (can_get_item(p, json, JSON_STRING, val) < 0) {
1039
0
    return -1;
1040
0
  }
1041
1042
0
  return get_item(p, json, idx, JSON_STRING, val);
1043
0
}
1044
1045
int pr_json_array_append_array(pool *p, pr_json_array_t *json,
1046
0
    const pr_json_array_t *val) {
1047
0
  if (can_add_item(p, json) < 0) {
1048
0
    return -1;
1049
0
  }
1050
1051
0
  if (val == NULL) {
1052
0
    errno = EINVAL;
1053
0
    return -1;
1054
0
  }
1055
1056
0
  return append_item(p, json, JSON_ARRAY, val);
1057
0
}
1058
1059
int pr_json_array_get_array(pool *p, const pr_json_array_t *json,
1060
0
    unsigned int idx, pr_json_array_t **val) {
1061
0
  if (can_get_item(p, json, JSON_ARRAY, val) < 0) {
1062
0
    return -1;
1063
0
  }
1064
1065
0
  return get_item(p, json, idx, JSON_ARRAY, val);
1066
0
}
1067
1068
int pr_json_array_append_object(pool *p, pr_json_array_t *json,
1069
0
    const pr_json_object_t *val) {
1070
0
  if (can_add_item(p, json) < 0) {
1071
0
    return -1;
1072
0
  }
1073
1074
0
  if (val == NULL) {
1075
0
    errno = EINVAL;
1076
0
    return -1;
1077
0
  }
1078
1079
0
  return append_item(p, json, JSON_OBJECT, val);
1080
0
}
1081
1082
int pr_json_array_get_object(pool *p, const pr_json_array_t *json,
1083
0
    unsigned int idx, pr_json_object_t **val) {
1084
0
  if (can_get_item(p, json, JSON_OBJECT, val) < 0) {
1085
0
    return -1;
1086
0
  }
1087
1088
0
  return get_item(p, json, idx, JSON_OBJECT, val);
1089
0
}
1090
1091
0
int pr_json_text_validate(pool *p, const char *text) {
1092
0
  if (p == NULL ||
1093
0
      text == NULL) {
1094
0
    errno = EINVAL;
1095
0
    return -1;
1096
0
  }
1097
1098
0
  return json_validate(text);
1099
0
}
1100
1101
0
const char *pr_json_type_name(unsigned int json_type) {
1102
0
  const char *name;
1103
1104
0
  switch (json_type) {
1105
0
    case PR_JSON_TYPE_BOOL:
1106
0
      name = "boolean";
1107
0
      break;
1108
1109
0
    case PR_JSON_TYPE_NUMBER:
1110
0
      name = "number";
1111
0
      break;
1112
1113
0
    case PR_JSON_TYPE_NULL:
1114
0
      name = "null";
1115
0
      break;
1116
1117
0
    case PR_JSON_TYPE_STRING:
1118
0
      name = "string";
1119
0
      break;
1120
1121
0
    case PR_JSON_TYPE_ARRAY:
1122
0
      name = "array";
1123
0
      break;
1124
1125
0
    case PR_JSON_TYPE_OBJECT:
1126
0
      name = "object";
1127
0
      break;
1128
1129
0
    default:
1130
0
      errno = EINVAL;
1131
0
      name = NULL;
1132
0
  }
1133
1134
0
  return name;
1135
0
}
1136
1137
0
static void json_oom(void) {
1138
0
  pr_log_pri(PR_LOG_ALERT, "%s", "Out of memory!");
1139
0
  exit(1);
1140
0
}
1141
1142
1143
1.73k
int init_json(void) {
1144
1.73k
  json_set_oom(json_oom);
1145
1.73k
  return 0;
1146
1.73k
}
1147
1148
1.73k
int finish_json(void) {
1149
  json_set_oom(NULL);
1150
1.73k
  return 0;
1151
1.73k
}
1152