10a73ee0aSchristos /* 20a73ee0aSchristos * JavaScript Object Notation (JSON) parser (RFC7159) 30a73ee0aSchristos * Copyright (c) 2017, Qualcomm Atheros, Inc. 40a73ee0aSchristos * 50a73ee0aSchristos * This software may be distributed under the terms of the BSD license. 60a73ee0aSchristos * See README for more details. 70a73ee0aSchristos */ 80a73ee0aSchristos 90a73ee0aSchristos #include "includes.h" 100a73ee0aSchristos 110a73ee0aSchristos #include "common.h" 120a73ee0aSchristos #include "base64.h" 130a73ee0aSchristos #include "json.h" 140a73ee0aSchristos 150a73ee0aSchristos #define JSON_MAX_DEPTH 10 160a73ee0aSchristos #define JSON_MAX_TOKENS 500 170a73ee0aSchristos 180a73ee0aSchristos 190a73ee0aSchristos void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len) 200a73ee0aSchristos { 210a73ee0aSchristos char *end = txt + maxlen; 220a73ee0aSchristos size_t i; 230a73ee0aSchristos 240a73ee0aSchristos for (i = 0; i < len; i++) { 250a73ee0aSchristos if (txt + 4 >= end) 260a73ee0aSchristos break; 270a73ee0aSchristos 280a73ee0aSchristos switch (data[i]) { 290a73ee0aSchristos case '\"': 300a73ee0aSchristos *txt++ = '\\'; 310a73ee0aSchristos *txt++ = '\"'; 320a73ee0aSchristos break; 330a73ee0aSchristos case '\\': 340a73ee0aSchristos *txt++ = '\\'; 350a73ee0aSchristos *txt++ = '\\'; 360a73ee0aSchristos break; 370a73ee0aSchristos case '\n': 380a73ee0aSchristos *txt++ = '\\'; 390a73ee0aSchristos *txt++ = 'n'; 400a73ee0aSchristos break; 410a73ee0aSchristos case '\r': 420a73ee0aSchristos *txt++ = '\\'; 430a73ee0aSchristos *txt++ = 'r'; 440a73ee0aSchristos break; 450a73ee0aSchristos case '\t': 460a73ee0aSchristos *txt++ = '\\'; 470a73ee0aSchristos *txt++ = 't'; 480a73ee0aSchristos break; 490a73ee0aSchristos default: 500a73ee0aSchristos if (data[i] >= 32 && data[i] <= 126) { 510a73ee0aSchristos *txt++ = data[i]; 520a73ee0aSchristos } else { 530a73ee0aSchristos txt += os_snprintf(txt, end - txt, "\\u%04x", 54*bb618362Schristos (unsigned char) data[i]); 550a73ee0aSchristos } 560a73ee0aSchristos break; 570a73ee0aSchristos } 580a73ee0aSchristos } 590a73ee0aSchristos 600a73ee0aSchristos *txt = '\0'; 610a73ee0aSchristos } 620a73ee0aSchristos 630a73ee0aSchristos 640a73ee0aSchristos static char * json_parse_string(const char **json_pos, const char *end) 650a73ee0aSchristos { 660a73ee0aSchristos const char *pos = *json_pos; 670a73ee0aSchristos char *str, *spos, *s_end; 680a73ee0aSchristos size_t max_len, buf_len; 690a73ee0aSchristos u8 bin[2]; 700a73ee0aSchristos 710a73ee0aSchristos pos++; /* skip starting quote */ 720a73ee0aSchristos 730a73ee0aSchristos max_len = end - pos + 1; 740a73ee0aSchristos buf_len = max_len > 10 ? 10 : max_len; 750a73ee0aSchristos str = os_malloc(buf_len); 760a73ee0aSchristos if (!str) 770a73ee0aSchristos return NULL; 780a73ee0aSchristos spos = str; 790a73ee0aSchristos s_end = str + buf_len; 800a73ee0aSchristos 810a73ee0aSchristos for (; pos < end; pos++) { 820a73ee0aSchristos if (buf_len < max_len && s_end - spos < 3) { 830a73ee0aSchristos char *tmp; 840a73ee0aSchristos int idx; 850a73ee0aSchristos 860a73ee0aSchristos idx = spos - str; 870a73ee0aSchristos buf_len *= 2; 880a73ee0aSchristos if (buf_len > max_len) 890a73ee0aSchristos buf_len = max_len; 900a73ee0aSchristos tmp = os_realloc(str, buf_len); 910a73ee0aSchristos if (!tmp) 920a73ee0aSchristos goto fail; 930a73ee0aSchristos str = tmp; 940a73ee0aSchristos spos = str + idx; 950a73ee0aSchristos s_end = str + buf_len; 960a73ee0aSchristos } 970a73ee0aSchristos 980a73ee0aSchristos switch (*pos) { 990a73ee0aSchristos case '\"': /* end string */ 1000a73ee0aSchristos *spos = '\0'; 1010a73ee0aSchristos /* caller will move to the next position */ 1020a73ee0aSchristos *json_pos = pos; 1030a73ee0aSchristos return str; 1040a73ee0aSchristos case '\\': 1050a73ee0aSchristos pos++; 1063d6c0713Schristos if (pos >= end) { 1073d6c0713Schristos wpa_printf(MSG_DEBUG, 1083d6c0713Schristos "JSON: Truncated \\ escape"); 1093d6c0713Schristos goto fail; 1103d6c0713Schristos } 1110a73ee0aSchristos switch (*pos) { 1120a73ee0aSchristos case '"': 1130a73ee0aSchristos case '\\': 1140a73ee0aSchristos case '/': 1150a73ee0aSchristos *spos++ = *pos; 1160a73ee0aSchristos break; 1170a73ee0aSchristos case 'n': 1180a73ee0aSchristos *spos++ = '\n'; 1190a73ee0aSchristos break; 1200a73ee0aSchristos case 'r': 1210a73ee0aSchristos *spos++ = '\r'; 1220a73ee0aSchristos break; 1230a73ee0aSchristos case 't': 1240a73ee0aSchristos *spos++ = '\t'; 1250a73ee0aSchristos break; 1260a73ee0aSchristos case 'u': 1270a73ee0aSchristos if (end - pos < 5 || 1280a73ee0aSchristos hexstr2bin(pos + 1, bin, 2) < 0 || 1290a73ee0aSchristos bin[1] == 0x00) { 1300a73ee0aSchristos wpa_printf(MSG_DEBUG, 1310a73ee0aSchristos "JSON: Invalid \\u escape"); 1320a73ee0aSchristos goto fail; 1330a73ee0aSchristos } 1340a73ee0aSchristos if (bin[0] == 0x00) { 1350a73ee0aSchristos *spos++ = bin[1]; 1360a73ee0aSchristos } else { 1370a73ee0aSchristos *spos++ = bin[0]; 1380a73ee0aSchristos *spos++ = bin[1]; 1390a73ee0aSchristos } 1400a73ee0aSchristos pos += 4; 1410a73ee0aSchristos break; 1420a73ee0aSchristos default: 1430a73ee0aSchristos wpa_printf(MSG_DEBUG, 1440a73ee0aSchristos "JSON: Unknown escape '%c'", *pos); 1450a73ee0aSchristos goto fail; 1460a73ee0aSchristos } 1470a73ee0aSchristos break; 1480a73ee0aSchristos default: 1490a73ee0aSchristos *spos++ = *pos; 1500a73ee0aSchristos break; 1510a73ee0aSchristos } 1520a73ee0aSchristos } 1530a73ee0aSchristos 1540a73ee0aSchristos fail: 1550a73ee0aSchristos os_free(str); 1560a73ee0aSchristos return NULL; 1570a73ee0aSchristos } 1580a73ee0aSchristos 1590a73ee0aSchristos 1600a73ee0aSchristos static int json_parse_number(const char **json_pos, const char *end, 1610a73ee0aSchristos int *ret_val) 1620a73ee0aSchristos { 1630a73ee0aSchristos const char *pos = *json_pos; 1640a73ee0aSchristos size_t len; 1650a73ee0aSchristos char *str; 1660a73ee0aSchristos 1670a73ee0aSchristos for (; pos < end; pos++) { 1680a73ee0aSchristos if (*pos != '-' && (*pos < '0' || *pos > '9')) { 1690a73ee0aSchristos pos--; 1700a73ee0aSchristos break; 1710a73ee0aSchristos } 1720a73ee0aSchristos } 1733d6c0713Schristos if (pos == end) 1743d6c0713Schristos pos--; 1750a73ee0aSchristos if (pos < *json_pos) 1760a73ee0aSchristos return -1; 1770a73ee0aSchristos len = pos - *json_pos + 1; 1780a73ee0aSchristos str = os_malloc(len + 1); 1790a73ee0aSchristos if (!str) 1800a73ee0aSchristos return -1; 1810a73ee0aSchristos os_memcpy(str, *json_pos, len); 1820a73ee0aSchristos str[len] = '\0'; 1830a73ee0aSchristos 1840a73ee0aSchristos *ret_val = atoi(str); 1850a73ee0aSchristos os_free(str); 1860a73ee0aSchristos *json_pos = pos; 1870a73ee0aSchristos return 0; 1880a73ee0aSchristos } 1890a73ee0aSchristos 1900a73ee0aSchristos 1910a73ee0aSchristos static int json_check_tree_state(struct json_token *token) 1920a73ee0aSchristos { 1930a73ee0aSchristos if (!token) 1940a73ee0aSchristos return 0; 1950a73ee0aSchristos if (json_check_tree_state(token->child) < 0 || 1960a73ee0aSchristos json_check_tree_state(token->sibling) < 0) 1970a73ee0aSchristos return -1; 1980a73ee0aSchristos if (token->state != JSON_COMPLETED) { 1990a73ee0aSchristos wpa_printf(MSG_DEBUG, 2000a73ee0aSchristos "JSON: Unexpected token state %d (name=%s type=%d)", 2010a73ee0aSchristos token->state, token->name ? token->name : "N/A", 2020a73ee0aSchristos token->type); 2030a73ee0aSchristos return -1; 2040a73ee0aSchristos } 2050a73ee0aSchristos return 0; 2060a73ee0aSchristos } 2070a73ee0aSchristos 2080a73ee0aSchristos 2090a73ee0aSchristos static struct json_token * json_alloc_token(unsigned int *tokens) 2100a73ee0aSchristos { 2110a73ee0aSchristos (*tokens)++; 2120a73ee0aSchristos if (*tokens > JSON_MAX_TOKENS) { 2130a73ee0aSchristos wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded"); 2140a73ee0aSchristos return NULL; 2150a73ee0aSchristos } 2160a73ee0aSchristos return os_zalloc(sizeof(struct json_token)); 2170a73ee0aSchristos } 2180a73ee0aSchristos 2190a73ee0aSchristos 2200a73ee0aSchristos struct json_token * json_parse(const char *data, size_t data_len) 2210a73ee0aSchristos { 2220a73ee0aSchristos struct json_token *root = NULL, *curr_token = NULL, *token = NULL; 2230a73ee0aSchristos const char *pos, *end; 2240a73ee0aSchristos char *str; 2250a73ee0aSchristos int num; 2260a73ee0aSchristos unsigned int depth = 0; 2270a73ee0aSchristos unsigned int tokens = 0; 2280a73ee0aSchristos 2290a73ee0aSchristos pos = data; 2300a73ee0aSchristos end = data + data_len; 2310a73ee0aSchristos 2320a73ee0aSchristos for (; pos < end; pos++) { 2330a73ee0aSchristos switch (*pos) { 2340a73ee0aSchristos case '[': /* start array */ 2350a73ee0aSchristos case '{': /* start object */ 2360a73ee0aSchristos if (!curr_token) { 2370a73ee0aSchristos token = json_alloc_token(&tokens); 2380a73ee0aSchristos if (!token) 2390a73ee0aSchristos goto fail; 2400a73ee0aSchristos if (!root) 2410a73ee0aSchristos root = token; 2420a73ee0aSchristos } else if (curr_token->state == JSON_WAITING_VALUE) { 2430a73ee0aSchristos token = curr_token; 2440a73ee0aSchristos } else if (curr_token->parent && 2450a73ee0aSchristos curr_token->parent->type == JSON_ARRAY && 2460a73ee0aSchristos curr_token->parent->state == JSON_STARTED && 2470a73ee0aSchristos curr_token->state == JSON_EMPTY) { 2480a73ee0aSchristos token = curr_token; 2490a73ee0aSchristos } else { 2500a73ee0aSchristos wpa_printf(MSG_DEBUG, 2510a73ee0aSchristos "JSON: Invalid state for start array/object"); 2520a73ee0aSchristos goto fail; 2530a73ee0aSchristos } 2540a73ee0aSchristos depth++; 2550a73ee0aSchristos if (depth > JSON_MAX_DEPTH) { 2560a73ee0aSchristos wpa_printf(MSG_DEBUG, 2570a73ee0aSchristos "JSON: Max depth exceeded"); 2580a73ee0aSchristos goto fail; 2590a73ee0aSchristos } 2600a73ee0aSchristos token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT; 2610a73ee0aSchristos token->state = JSON_STARTED; 2620a73ee0aSchristos token->child = json_alloc_token(&tokens); 2630a73ee0aSchristos if (!token->child) 2640a73ee0aSchristos goto fail; 2650a73ee0aSchristos curr_token = token->child; 2660a73ee0aSchristos curr_token->parent = token; 2670a73ee0aSchristos curr_token->state = JSON_EMPTY; 2680a73ee0aSchristos break; 2690a73ee0aSchristos case ']': /* end array */ 2700a73ee0aSchristos case '}': /* end object */ 2710a73ee0aSchristos if (!curr_token || !curr_token->parent || 2720a73ee0aSchristos curr_token->parent->state != JSON_STARTED) { 2730a73ee0aSchristos wpa_printf(MSG_DEBUG, 2740a73ee0aSchristos "JSON: Invalid state for end array/object"); 2750a73ee0aSchristos goto fail; 2760a73ee0aSchristos } 2770a73ee0aSchristos depth--; 2780a73ee0aSchristos curr_token = curr_token->parent; 2790a73ee0aSchristos if ((*pos == ']' && 2800a73ee0aSchristos curr_token->type != JSON_ARRAY) || 2810a73ee0aSchristos (*pos == '}' && 2820a73ee0aSchristos curr_token->type != JSON_OBJECT)) { 2830a73ee0aSchristos wpa_printf(MSG_DEBUG, 2840a73ee0aSchristos "JSON: Array/Object mismatch"); 2850a73ee0aSchristos goto fail; 2860a73ee0aSchristos } 2870a73ee0aSchristos if (curr_token->child->state == JSON_EMPTY && 2880a73ee0aSchristos !curr_token->child->child && 2890a73ee0aSchristos !curr_token->child->sibling) { 2900a73ee0aSchristos /* Remove pending child token since the 2910a73ee0aSchristos * array/object was empty. */ 2920a73ee0aSchristos json_free(curr_token->child); 2930a73ee0aSchristos curr_token->child = NULL; 2940a73ee0aSchristos } 2950a73ee0aSchristos curr_token->state = JSON_COMPLETED; 2960a73ee0aSchristos break; 2970a73ee0aSchristos case '\"': /* string */ 2980a73ee0aSchristos str = json_parse_string(&pos, end); 2990a73ee0aSchristos if (!str) 3000a73ee0aSchristos goto fail; 3010a73ee0aSchristos if (!curr_token) { 3020a73ee0aSchristos token = json_alloc_token(&tokens); 303*bb618362Schristos if (!token) { 304*bb618362Schristos os_free(str); 3050a73ee0aSchristos goto fail; 306*bb618362Schristos } 3070a73ee0aSchristos token->type = JSON_STRING; 3080a73ee0aSchristos token->string = str; 3090a73ee0aSchristos token->state = JSON_COMPLETED; 3100a73ee0aSchristos } else if (curr_token->parent && 3110a73ee0aSchristos curr_token->parent->type == JSON_ARRAY && 3120a73ee0aSchristos curr_token->parent->state == JSON_STARTED && 3130a73ee0aSchristos curr_token->state == JSON_EMPTY) { 3140a73ee0aSchristos curr_token->string = str; 3150a73ee0aSchristos curr_token->state = JSON_COMPLETED; 3160a73ee0aSchristos curr_token->type = JSON_STRING; 3170a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 3180a73ee0aSchristos "JSON: String value: '%s'", 3190a73ee0aSchristos curr_token->string); 3200a73ee0aSchristos } else if (curr_token->state == JSON_EMPTY) { 3210a73ee0aSchristos curr_token->type = JSON_VALUE; 3220a73ee0aSchristos curr_token->name = str; 3230a73ee0aSchristos curr_token->state = JSON_STARTED; 3240a73ee0aSchristos } else if (curr_token->state == JSON_WAITING_VALUE) { 3250a73ee0aSchristos curr_token->string = str; 3260a73ee0aSchristos curr_token->state = JSON_COMPLETED; 3270a73ee0aSchristos curr_token->type = JSON_STRING; 3280a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 3290a73ee0aSchristos "JSON: String value: '%s' = '%s'", 3300a73ee0aSchristos curr_token->name, 3310a73ee0aSchristos curr_token->string); 3320a73ee0aSchristos } else { 3330a73ee0aSchristos wpa_printf(MSG_DEBUG, 3340a73ee0aSchristos "JSON: Invalid state for a string"); 3350a73ee0aSchristos os_free(str); 3360a73ee0aSchristos goto fail; 3370a73ee0aSchristos } 3380a73ee0aSchristos break; 3390a73ee0aSchristos case ' ': 3400a73ee0aSchristos case '\t': 3410a73ee0aSchristos case '\r': 3420a73ee0aSchristos case '\n': 3430a73ee0aSchristos /* ignore whitespace */ 3440a73ee0aSchristos break; 3450a73ee0aSchristos case ':': /* name/value separator */ 3460a73ee0aSchristos if (!curr_token || curr_token->state != JSON_STARTED) 3470a73ee0aSchristos goto fail; 3480a73ee0aSchristos curr_token->state = JSON_WAITING_VALUE; 3490a73ee0aSchristos break; 3500a73ee0aSchristos case ',': /* member separator */ 3510a73ee0aSchristos if (!curr_token) 3520a73ee0aSchristos goto fail; 3530a73ee0aSchristos curr_token->sibling = json_alloc_token(&tokens); 3540a73ee0aSchristos if (!curr_token->sibling) 3550a73ee0aSchristos goto fail; 3560a73ee0aSchristos curr_token->sibling->parent = curr_token->parent; 3570a73ee0aSchristos curr_token = curr_token->sibling; 3580a73ee0aSchristos curr_token->state = JSON_EMPTY; 3590a73ee0aSchristos break; 3600a73ee0aSchristos case 't': /* true */ 3610a73ee0aSchristos case 'f': /* false */ 3620a73ee0aSchristos case 'n': /* null */ 3630a73ee0aSchristos if (!((end - pos >= 4 && 3640a73ee0aSchristos os_strncmp(pos, "true", 4) == 0) || 3650a73ee0aSchristos (end - pos >= 5 && 3660a73ee0aSchristos os_strncmp(pos, "false", 5) == 0) || 3670a73ee0aSchristos (end - pos >= 4 && 3680a73ee0aSchristos os_strncmp(pos, "null", 4) == 0))) { 3690a73ee0aSchristos wpa_printf(MSG_DEBUG, 3700a73ee0aSchristos "JSON: Invalid literal name"); 3710a73ee0aSchristos goto fail; 3720a73ee0aSchristos } 3730a73ee0aSchristos if (!curr_token) { 3740a73ee0aSchristos token = json_alloc_token(&tokens); 3750a73ee0aSchristos if (!token) 3760a73ee0aSchristos goto fail; 3770a73ee0aSchristos curr_token = token; 3780a73ee0aSchristos } else if (curr_token->state == JSON_WAITING_VALUE) { 3790a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 3800a73ee0aSchristos "JSON: Literal name: '%s' = %c", 3810a73ee0aSchristos curr_token->name, *pos); 3820a73ee0aSchristos } else if (curr_token->parent && 3830a73ee0aSchristos curr_token->parent->type == JSON_ARRAY && 3840a73ee0aSchristos curr_token->parent->state == JSON_STARTED && 3850a73ee0aSchristos curr_token->state == JSON_EMPTY) { 3860a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 3870a73ee0aSchristos "JSON: Literal name: %c", *pos); 3880a73ee0aSchristos } else { 3890a73ee0aSchristos wpa_printf(MSG_DEBUG, 3900a73ee0aSchristos "JSON: Invalid state for a literal name"); 3910a73ee0aSchristos goto fail; 3920a73ee0aSchristos } 3930a73ee0aSchristos switch (*pos) { 3940a73ee0aSchristos case 't': 3950a73ee0aSchristos curr_token->type = JSON_BOOLEAN; 3960a73ee0aSchristos curr_token->number = 1; 3970a73ee0aSchristos pos += 3; 3980a73ee0aSchristos break; 3990a73ee0aSchristos case 'f': 4000a73ee0aSchristos curr_token->type = JSON_BOOLEAN; 4010a73ee0aSchristos curr_token->number = 0; 4020a73ee0aSchristos pos += 4; 4030a73ee0aSchristos break; 4040a73ee0aSchristos case 'n': 4050a73ee0aSchristos curr_token->type = JSON_NULL; 4060a73ee0aSchristos pos += 3; 4070a73ee0aSchristos break; 4080a73ee0aSchristos } 4090a73ee0aSchristos curr_token->state = JSON_COMPLETED; 4100a73ee0aSchristos break; 4110a73ee0aSchristos case '-': 4120a73ee0aSchristos case '0': 4130a73ee0aSchristos case '1': 4140a73ee0aSchristos case '2': 4150a73ee0aSchristos case '3': 4160a73ee0aSchristos case '4': 4170a73ee0aSchristos case '5': 4180a73ee0aSchristos case '6': 4190a73ee0aSchristos case '7': 4200a73ee0aSchristos case '8': 4210a73ee0aSchristos case '9': 4220a73ee0aSchristos /* number */ 4230a73ee0aSchristos if (json_parse_number(&pos, end, &num) < 0) 4240a73ee0aSchristos goto fail; 4250a73ee0aSchristos if (!curr_token) { 4260a73ee0aSchristos token = json_alloc_token(&tokens); 4270a73ee0aSchristos if (!token) 4280a73ee0aSchristos goto fail; 4290a73ee0aSchristos token->type = JSON_NUMBER; 4300a73ee0aSchristos token->number = num; 4310a73ee0aSchristos token->state = JSON_COMPLETED; 4320a73ee0aSchristos } else if (curr_token->state == JSON_WAITING_VALUE) { 4330a73ee0aSchristos curr_token->number = num; 4340a73ee0aSchristos curr_token->state = JSON_COMPLETED; 4350a73ee0aSchristos curr_token->type = JSON_NUMBER; 4360a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 4370a73ee0aSchristos "JSON: Number value: '%s' = '%d'", 4380a73ee0aSchristos curr_token->name, 4390a73ee0aSchristos curr_token->number); 4400a73ee0aSchristos } else if (curr_token->parent && 4410a73ee0aSchristos curr_token->parent->type == JSON_ARRAY && 4420a73ee0aSchristos curr_token->parent->state == JSON_STARTED && 4430a73ee0aSchristos curr_token->state == JSON_EMPTY) { 4440a73ee0aSchristos curr_token->number = num; 4450a73ee0aSchristos curr_token->state = JSON_COMPLETED; 4460a73ee0aSchristos curr_token->type = JSON_NUMBER; 4470a73ee0aSchristos wpa_printf(MSG_MSGDUMP, 4480a73ee0aSchristos "JSON: Number value: %d", 4490a73ee0aSchristos curr_token->number); 4500a73ee0aSchristos } else { 4510a73ee0aSchristos wpa_printf(MSG_DEBUG, 4520a73ee0aSchristos "JSON: Invalid state for a number"); 4530a73ee0aSchristos goto fail; 4540a73ee0aSchristos } 4550a73ee0aSchristos break; 4560a73ee0aSchristos default: 4570a73ee0aSchristos wpa_printf(MSG_DEBUG, 4580a73ee0aSchristos "JSON: Unexpected JSON character: %c", *pos); 4590a73ee0aSchristos goto fail; 4600a73ee0aSchristos } 4610a73ee0aSchristos 4620a73ee0aSchristos if (!root) 4630a73ee0aSchristos root = token; 4640a73ee0aSchristos if (!curr_token) 4650a73ee0aSchristos curr_token = token; 4660a73ee0aSchristos } 4670a73ee0aSchristos 4680a73ee0aSchristos if (json_check_tree_state(root) < 0) { 4690a73ee0aSchristos wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree"); 4700a73ee0aSchristos goto fail; 4710a73ee0aSchristos } 4720a73ee0aSchristos 4730a73ee0aSchristos return root; 4740a73ee0aSchristos fail: 4750a73ee0aSchristos wpa_printf(MSG_DEBUG, "JSON: Parsing failed"); 4760a73ee0aSchristos json_free(root); 4770a73ee0aSchristos return NULL; 4780a73ee0aSchristos } 4790a73ee0aSchristos 4800a73ee0aSchristos 4810a73ee0aSchristos void json_free(struct json_token *json) 4820a73ee0aSchristos { 4830a73ee0aSchristos if (!json) 4840a73ee0aSchristos return; 4850a73ee0aSchristos json_free(json->child); 4860a73ee0aSchristos json_free(json->sibling); 4870a73ee0aSchristos os_free(json->name); 4880a73ee0aSchristos os_free(json->string); 4890a73ee0aSchristos os_free(json); 4900a73ee0aSchristos } 4910a73ee0aSchristos 4920a73ee0aSchristos 4930a73ee0aSchristos struct json_token * json_get_member(struct json_token *json, const char *name) 4940a73ee0aSchristos { 4950a73ee0aSchristos struct json_token *token, *ret = NULL; 4960a73ee0aSchristos 4970a73ee0aSchristos if (!json || json->type != JSON_OBJECT) 4980a73ee0aSchristos return NULL; 4990a73ee0aSchristos /* Return last matching entry */ 5000a73ee0aSchristos for (token = json->child; token; token = token->sibling) { 5010a73ee0aSchristos if (token->name && os_strcmp(token->name, name) == 0) 5020a73ee0aSchristos ret = token; 5030a73ee0aSchristos } 5040a73ee0aSchristos return ret; 5050a73ee0aSchristos } 5060a73ee0aSchristos 5070a73ee0aSchristos 5080a73ee0aSchristos struct wpabuf * json_get_member_base64url(struct json_token *json, 5090a73ee0aSchristos const char *name) 5100a73ee0aSchristos { 5110a73ee0aSchristos struct json_token *token; 5120a73ee0aSchristos unsigned char *buf; 5130a73ee0aSchristos size_t buflen; 5140a73ee0aSchristos struct wpabuf *ret; 5150a73ee0aSchristos 5160a73ee0aSchristos token = json_get_member(json, name); 5170a73ee0aSchristos if (!token || token->type != JSON_STRING) 5180a73ee0aSchristos return NULL; 519*bb618362Schristos buf = base64_url_decode(token->string, os_strlen(token->string), 520*bb618362Schristos &buflen); 521*bb618362Schristos if (!buf) 522*bb618362Schristos return NULL; 523*bb618362Schristos ret = wpabuf_alloc_ext_data(buf, buflen); 524*bb618362Schristos if (!ret) 525*bb618362Schristos os_free(buf); 526*bb618362Schristos 527*bb618362Schristos return ret; 528*bb618362Schristos } 529*bb618362Schristos 530*bb618362Schristos 531*bb618362Schristos struct wpabuf * json_get_member_base64(struct json_token *json, 532*bb618362Schristos const char *name) 533*bb618362Schristos { 534*bb618362Schristos struct json_token *token; 535*bb618362Schristos unsigned char *buf; 536*bb618362Schristos size_t buflen; 537*bb618362Schristos struct wpabuf *ret; 538*bb618362Schristos 539*bb618362Schristos token = json_get_member(json, name); 540*bb618362Schristos if (!token || token->type != JSON_STRING) 541*bb618362Schristos return NULL; 542*bb618362Schristos buf = base64_decode(token->string, os_strlen(token->string), &buflen); 5430a73ee0aSchristos if (!buf) 5440a73ee0aSchristos return NULL; 5450a73ee0aSchristos ret = wpabuf_alloc_ext_data(buf, buflen); 5460a73ee0aSchristos if (!ret) 5470a73ee0aSchristos os_free(buf); 5480a73ee0aSchristos 5490a73ee0aSchristos return ret; 5500a73ee0aSchristos } 5510a73ee0aSchristos 5520a73ee0aSchristos 5530a73ee0aSchristos static const char * json_type_str(enum json_type type) 5540a73ee0aSchristos { 5550a73ee0aSchristos switch (type) { 5560a73ee0aSchristos case JSON_VALUE: 5570a73ee0aSchristos return "VALUE"; 5580a73ee0aSchristos case JSON_OBJECT: 5590a73ee0aSchristos return "OBJECT"; 5600a73ee0aSchristos case JSON_ARRAY: 5610a73ee0aSchristos return "ARRAY"; 5620a73ee0aSchristos case JSON_STRING: 5630a73ee0aSchristos return "STRING"; 5640a73ee0aSchristos case JSON_NUMBER: 5650a73ee0aSchristos return "NUMBER"; 5660a73ee0aSchristos case JSON_BOOLEAN: 5670a73ee0aSchristos return "BOOLEAN"; 5680a73ee0aSchristos case JSON_NULL: 5690a73ee0aSchristos return "NULL"; 5700a73ee0aSchristos } 5710a73ee0aSchristos return "??"; 5720a73ee0aSchristos } 5730a73ee0aSchristos 5740a73ee0aSchristos 5750a73ee0aSchristos static void json_print_token(struct json_token *token, int depth, 5760a73ee0aSchristos char *buf, size_t buflen) 5770a73ee0aSchristos { 5780a73ee0aSchristos size_t len; 5790a73ee0aSchristos int ret; 5800a73ee0aSchristos 5810a73ee0aSchristos if (!token) 5820a73ee0aSchristos return; 5830a73ee0aSchristos len = os_strlen(buf); 5840a73ee0aSchristos ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]", 5850a73ee0aSchristos depth, json_type_str(token->type), 5860a73ee0aSchristos token->name ? token->name : ""); 5870a73ee0aSchristos if (os_snprintf_error(buflen - len, ret)) { 5880a73ee0aSchristos buf[len] = '\0'; 5890a73ee0aSchristos return; 5900a73ee0aSchristos } 5910a73ee0aSchristos json_print_token(token->child, depth + 1, buf, buflen); 5920a73ee0aSchristos json_print_token(token->sibling, depth, buf, buflen); 5930a73ee0aSchristos } 5940a73ee0aSchristos 5950a73ee0aSchristos 5960a73ee0aSchristos void json_print_tree(struct json_token *root, char *buf, size_t buflen) 5970a73ee0aSchristos { 5980a73ee0aSchristos buf[0] = '\0'; 5990a73ee0aSchristos json_print_token(root, 1, buf, buflen); 6000a73ee0aSchristos } 601*bb618362Schristos 602*bb618362Schristos 603*bb618362Schristos void json_add_int(struct wpabuf *json, const char *name, int val) 604*bb618362Schristos { 605*bb618362Schristos wpabuf_printf(json, "\"%s\":%d", name, val); 606*bb618362Schristos } 607*bb618362Schristos 608*bb618362Schristos 609*bb618362Schristos void json_add_string(struct wpabuf *json, const char *name, const char *val) 610*bb618362Schristos { 611*bb618362Schristos wpabuf_printf(json, "\"%s\":\"%s\"", name, val); 612*bb618362Schristos } 613*bb618362Schristos 614*bb618362Schristos 615*bb618362Schristos int json_add_string_escape(struct wpabuf *json, const char *name, 616*bb618362Schristos const void *val, size_t len) 617*bb618362Schristos { 618*bb618362Schristos char *tmp; 619*bb618362Schristos size_t tmp_len = 6 * len + 1; 620*bb618362Schristos 621*bb618362Schristos tmp = os_malloc(tmp_len); 622*bb618362Schristos if (!tmp) 623*bb618362Schristos return -1; 624*bb618362Schristos json_escape_string(tmp, tmp_len, val, len); 625*bb618362Schristos json_add_string(json, name, tmp); 626*bb618362Schristos bin_clear_free(tmp, tmp_len); 627*bb618362Schristos return 0; 628*bb618362Schristos } 629*bb618362Schristos 630*bb618362Schristos 631*bb618362Schristos int json_add_base64url(struct wpabuf *json, const char *name, const void *val, 632*bb618362Schristos size_t len) 633*bb618362Schristos { 634*bb618362Schristos char *b64; 635*bb618362Schristos 636*bb618362Schristos b64 = base64_url_encode(val, len, NULL); 637*bb618362Schristos if (!b64) 638*bb618362Schristos return -1; 639*bb618362Schristos json_add_string(json, name, b64); 640*bb618362Schristos os_free(b64); 641*bb618362Schristos return 0; 642*bb618362Schristos } 643*bb618362Schristos 644*bb618362Schristos 645*bb618362Schristos int json_add_base64(struct wpabuf *json, const char *name, const void *val, 646*bb618362Schristos size_t len) 647*bb618362Schristos { 648*bb618362Schristos char *b64; 649*bb618362Schristos 650*bb618362Schristos b64 = base64_encode_no_lf(val, len, NULL); 651*bb618362Schristos if (!b64) 652*bb618362Schristos return -1; 653*bb618362Schristos json_add_string(json, name, b64); 654*bb618362Schristos os_free(b64); 655*bb618362Schristos return 0; 656*bb618362Schristos } 657*bb618362Schristos 658*bb618362Schristos 659*bb618362Schristos void json_start_object(struct wpabuf *json, const char *name) 660*bb618362Schristos { 661*bb618362Schristos if (name) 662*bb618362Schristos wpabuf_printf(json, "\"%s\":", name); 663*bb618362Schristos wpabuf_put_u8(json, '{'); 664*bb618362Schristos } 665*bb618362Schristos 666*bb618362Schristos 667*bb618362Schristos void json_end_object(struct wpabuf *json) 668*bb618362Schristos { 669*bb618362Schristos wpabuf_put_u8(json, '}'); 670*bb618362Schristos } 671*bb618362Schristos 672*bb618362Schristos 673*bb618362Schristos void json_start_array(struct wpabuf *json, const char *name) 674*bb618362Schristos { 675*bb618362Schristos if (name) 676*bb618362Schristos wpabuf_printf(json, "\"%s\":", name); 677*bb618362Schristos wpabuf_put_u8(json, '['); 678*bb618362Schristos } 679*bb618362Schristos 680*bb618362Schristos 681*bb618362Schristos void json_end_array(struct wpabuf *json) 682*bb618362Schristos { 683*bb618362Schristos wpabuf_put_u8(json, ']'); 684*bb618362Schristos } 685*bb618362Schristos 686*bb618362Schristos 687*bb618362Schristos void json_value_sep(struct wpabuf *json) 688*bb618362Schristos { 689*bb618362Schristos wpabuf_put_u8(json, ','); 690*bb618362Schristos } 691