diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/k5-json.h | 36 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/export_cred.c | 151 | ||||
-rw-r--r-- | src/lib/gssapi/krb5/import_cred.c | 21 | ||||
-rw-r--r-- | src/lib/krb5/krb/get_in_tkt.c | 32 | ||||
-rw-r--r-- | src/lib/krb5/krb/init_creds_ctx.h | 4 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth2.c | 19 | ||||
-rw-r--r-- | src/lib/krb5/krb/preauth_otp.c | 128 | ||||
-rw-r--r-- | src/util/support/json.c | 536 | ||||
-rw-r--r-- | src/util/support/t_json.c | 83 |
9 files changed, 546 insertions, 464 deletions
diff --git a/src/include/k5-json.h b/src/include/k5-json.h index 42dcfa3d38..4b9b8fec3b 100644 --- a/src/include/k5-json.h +++ b/src/include/k5-json.h @@ -93,13 +93,12 @@ k5_json_tid k5_json_get_tid(k5_json_value val); * decrement the refcount, possibly freeing the value. k5_json_retain returns * its argument and always succeeds. Both functions gracefully accept NULL. */ -void *k5_json_retain(k5_json_value val); +k5_json_value k5_json_retain(k5_json_value val); void k5_json_release(k5_json_value val); /* - * Unless otherwise specified, the following functions return NULL on error - * (generally only if out of memory) if they return a pointer type, or 0 on - * success and -1 on failure if they return int. + * If a k5_json_* function can fail, it returns 0 on success and an errno value + * on failure. */ /* @@ -108,7 +107,7 @@ void k5_json_release(k5_json_value val); typedef struct k5_json_null_st *k5_json_null; -k5_json_null k5_json_null_create(void); +int k5_json_null_create(k5_json_null *null_out); /* * Boolean @@ -116,7 +115,7 @@ k5_json_null k5_json_null_create(void); typedef struct k5_json_bool_st *k5_json_bool; -k5_json_bool k5_json_bool_create(int truth); +int k5_json_bool_create(int truth, k5_json_bool *val_out); int k5_json_bool_value(k5_json_bool bval); /* @@ -125,7 +124,7 @@ int k5_json_bool_value(k5_json_bool bval); typedef struct k5_json_array_st *k5_json_array; -k5_json_array k5_json_array_create(void); +int k5_json_array_create(k5_json_array *val_out); size_t k5_json_array_length(k5_json_array array); /* Both of these functions increment the reference count on val. */ @@ -144,7 +143,7 @@ typedef struct k5_json_object_st *k5_json_object; typedef void (*k5_json_object_iterator_fn)(void *arg, const char *key, k5_json_value val); -k5_json_object k5_json_object_create(void); +int k5_json_object_create(k5_json_object *val_out); void k5_json_object_iterate(k5_json_object obj, k5_json_object_iterator_fn func, void *arg); @@ -164,16 +163,19 @@ k5_json_value k5_json_object_get(k5_json_object obj, const char *key); typedef struct k5_json_string_st *k5_json_string; -k5_json_string k5_json_string_create(const char *string); -k5_json_string k5_json_string_create_len(const void *data, size_t len); +int k5_json_string_create(const char *cstring, k5_json_string *val_out); +int k5_json_string_create_len(const void *data, size_t len, + k5_json_string *val_out); const char *k5_json_string_utf8(k5_json_string string); + /* Create a base64 string value from binary data. */ -k5_json_string k5_json_string_create_base64(const void *data, size_t len); +int k5_json_string_create_base64(const void *data, size_t len, + k5_json_string *val_out); -/* Decode a base64 string. Returns NULL and *len_out == 0 if out of memory, - * NULL and *len == SIZE_MAX if string's contents aren't valid base64. */ -void *k5_json_string_unbase64(k5_json_string string, size_t *len_out); +/* Decode the base64 contents of string. */ +int k5_json_string_unbase64(k5_json_string string, unsigned char **data_out, + size_t *len_out); /* * Number @@ -181,14 +183,14 @@ void *k5_json_string_unbase64(k5_json_string string, size_t *len_out); typedef struct k5_json_number_st *k5_json_number; -k5_json_number k5_json_number_create(long long number); +int k5_json_number_create(long long number, k5_json_number *val_out); long long k5_json_number_value(k5_json_number number); /* * JSON encoding and decoding */ -char *k5_json_encode(k5_json_value val); -k5_json_value k5_json_decode(const char *str); +int k5_json_encode(k5_json_value val, char **json_out); +int k5_json_decode(const char *str, k5_json_value *val_out); #endif /* K5_JSON_H */ diff --git a/src/lib/gssapi/krb5/export_cred.c b/src/lib/gssapi/krb5/export_cred.c index 162547966b..e5ffaf54aa 100644 --- a/src/lib/gssapi/krb5/export_cred.c +++ b/src/lib/gssapi/krb5/export_cred.c @@ -44,12 +44,51 @@ add(k5_json_array array, k5_json_value v) return 0; } +static inline k5_json_number +number(long long nval) +{ + k5_json_number num; + + return k5_json_number_create(nval, &num) ? NULL : num; +} + +static inline k5_json_string +string(const char *cstring) +{ + k5_json_string str; + + return k5_json_string_create(cstring, &str) ? NULL : str; +} + +static inline k5_json_string +base64string(const void *data, size_t len) +{ + k5_json_string str; + + return k5_json_string_create_base64(data, len, &str) ? NULL : str; +} + +static inline k5_json_null +null(void) +{ + k5_json_null n; + + return k5_json_null_create(&n) ? NULL : n; +} + +static inline k5_json_bool +bool(int truth) +{ + k5_json_bool b; + + return k5_json_bool_create(truth, &b) ? NULL : b; +} + /* Return a JSON null or string value representing str. */ static k5_json_value json_optional_string(const char *str) { - return (str == NULL) ? (k5_json_value)k5_json_null_create() : - (k5_json_value)k5_json_string_create(str); + return (str == NULL) ? (k5_json_value)null() : string(str); } /* Return a JSON null or array value representing princ. */ @@ -60,10 +99,10 @@ json_principal(krb5_context context, krb5_principal princ) k5_json_string str; if (princ == NULL) - return k5_json_null_create(); + return null(); if (krb5_unparse_name(context, princ, &princname)) return NULL; - str = k5_json_string_create(princname); + str = string(princname); krb5_free_unparsed_name(context, princname); return str; } @@ -75,12 +114,11 @@ json_etypes(krb5_enctype *etypes) k5_json_array array; if (etypes == NULL) - return k5_json_null_create(); - array = k5_json_array_create(); - if (array == NULL) + return null(); + if (k5_json_array_create(&array)) return NULL; for (; *etypes != 0; etypes++) { - if (add(array, k5_json_number_create(*etypes))) + if (add(array, number(*etypes))) goto oom; } return array; @@ -96,9 +134,8 @@ json_kgname(krb5_context context, krb5_gss_name_t name) k5_json_array array; if (name == NULL) - return k5_json_null_create(); - array = k5_json_array_create(); - if (array == NULL) + return null(); + if (k5_json_array_create(&array)) return NULL; if (add(array, json_principal(context, name->princ))) goto oom; @@ -119,10 +156,10 @@ json_keytab(krb5_context context, krb5_keytab keytab) char name[1024]; if (keytab == NULL) - return k5_json_null_create(); + return null(); if (krb5_kt_get_name(context, keytab, name, sizeof(name))) return NULL; - return k5_json_string_create(name); + return string(name); } /* Return a JSON null or string value representing rcache. */ @@ -133,11 +170,11 @@ json_rcache(krb5_context context, krb5_rcache rcache) k5_json_string str; if (rcache == NULL) - return k5_json_null_create(); + return null(); if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache), krb5_rc_get_name(context, rcache)) < 0) return NULL; - str = k5_json_string_create(name); + str = string(name); free(name); return str; } @@ -148,13 +185,11 @@ json_keyblock(krb5_keyblock *keyblock) { k5_json_array array; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; - if (add(array, k5_json_number_create(keyblock->enctype))) + if (add(array, number(keyblock->enctype))) goto oom; - if (add(array, k5_json_string_create_base64(keyblock->contents, - keyblock->length))) + if (add(array, base64string(keyblock->contents, keyblock->length))) goto oom; return array; oom: @@ -168,12 +203,11 @@ json_address(krb5_address *addr) { k5_json_array array; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; - if (add(array, k5_json_number_create(addr->addrtype))) + if (add(array, number(addr->addrtype))) goto oom; - if (add(array, k5_json_string_create_base64(addr->contents, addr->length))) + if (add(array, base64string(addr->contents, addr->length))) goto oom; return array; oom: @@ -188,9 +222,8 @@ json_addresses(krb5_address **addrs) k5_json_array array; if (addrs == NULL) - return k5_json_null_create(); - array = k5_json_array_create(); - if (array == NULL) + return null(); + if (k5_json_array_create(&array)) return NULL; for (; *addrs != NULL; addrs++) { if (add(array, json_address(*addrs))) { @@ -207,12 +240,11 @@ json_authdata_element(krb5_authdata *ad) { k5_json_array array; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; - if (add(array, k5_json_number_create(ad->ad_type))) + if (add(array, number(ad->ad_type))) goto oom; - if (add(array, k5_json_string_create_base64(ad->contents, ad->length))) + if (add(array, base64string(ad->contents, ad->length))) goto oom; return array; oom: @@ -227,9 +259,8 @@ json_authdata(krb5_authdata **authdata) k5_json_array array; if (authdata == NULL) - return k5_json_null_create(); - array = k5_json_array_create(); - if (array == NULL) + return null(); + if (k5_json_array_create(&array)) return NULL; for (; *authdata != NULL; authdata++) { if (add(array, json_authdata_element(*authdata))) { @@ -246,8 +277,7 @@ json_creds(krb5_context context, krb5_creds *creds) { k5_json_array array; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; if (add(array, json_principal(context, creds->client))) goto eom; @@ -255,25 +285,24 @@ json_creds(krb5_context context, krb5_creds *creds) goto eom; if (add(array, json_keyblock(&creds->keyblock))) goto eom; - if (add(array, k5_json_number_create(creds->times.authtime))) + if (add(array, number(creds->times.authtime))) goto eom; - if (add(array, k5_json_number_create(creds->times.starttime))) + if (add(array, number(creds->times.starttime))) goto eom; - if (add(array, k5_json_number_create(creds->times.endtime))) + if (add(array, number(creds->times.endtime))) goto eom; - if (add(array, k5_json_number_create(creds->times.renew_till))) + if (add(array, number(creds->times.renew_till))) goto eom; - if (add(array, k5_json_bool_create(creds->is_skey))) + if (add(array, bool(creds->is_skey))) goto eom; - if (add(array, k5_json_number_create(creds->ticket_flags))) + if (add(array, number(creds->ticket_flags))) goto eom; if (add(array, json_addresses(creds->addresses))) goto eom; - if (add(array, k5_json_string_create_base64(creds->ticket.data, - creds->ticket.length))) + if (add(array, base64string(creds->ticket.data, creds->ticket.length))) goto eom; - if (add(array, k5_json_string_create_base64(creds->second_ticket.data, - creds->second_ticket.length))) + if (add(array, base64string(creds->second_ticket.data, + creds->second_ticket.length))) goto eom; if (add(array, json_authdata(creds->authdata))) goto eom; @@ -294,8 +323,7 @@ json_ccache_contents(krb5_context context, krb5_ccache ccache) k5_json_array array; int st; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; /* Put the principal in the first array entry. */ @@ -334,13 +362,13 @@ json_ccache(krb5_context context, krb5_ccache ccache) k5_json_string str; if (ccache == NULL) - return k5_json_null_create(); + return null(); if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) { return json_ccache_contents(context, ccache); } else { if (krb5_cc_get_full_name(context, ccache, &name)) return NULL; - str = k5_json_string_create(name); + str = string(name); free(name); return str; } @@ -352,18 +380,17 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred) { k5_json_array array; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) return NULL; - if (add(array, k5_json_number_create(cred->usage))) + if (add(array, number(cred->usage))) goto oom; if (add(array, json_kgname(context, cred->name))) goto oom; if (add(array, json_principal(context, cred->impersonator))) goto oom; - if (add(array, k5_json_bool_create(cred->default_identity))) + if (add(array, bool(cred->default_identity))) goto oom; - if (add(array, k5_json_bool_create(cred->iakerb_mech))) + if (add(array, bool(cred->iakerb_mech))) goto oom; /* Don't marshal cred->destroy_ccache. */ if (add(array, json_keytab(context, cred->keytab))) @@ -374,11 +401,11 @@ json_kgcred(krb5_context context, krb5_gss_cred_id_t cred) goto oom; if (add(array, json_keytab(context, cred->client_keytab))) goto oom; - if (add(array, k5_json_bool_create(cred->have_tgt))) + if (add(array, bool(cred->have_tgt))) goto oom; - if (add(array, k5_json_number_create(cred->expire))) + if (add(array, number(cred->expire))) goto oom; - if (add(array, k5_json_number_create(cred->refresh_time))) + if (add(array, number(cred->refresh_time))) goto oom; if (add(array, json_etypes(cred->req_enctypes))) goto oom; @@ -414,16 +441,14 @@ krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle, return status; cred = (krb5_gss_cred_id_t)cred_handle; - array = k5_json_array_create(); - if (array == NULL) + if (k5_json_array_create(&array)) goto oom; - if (add(array, k5_json_string_create(CRED_EXPORT_MAGIC))) + if (add(array, string(CRED_EXPORT_MAGIC))) goto oom; if (add(array, json_kgcred(context, cred))) goto oom; - str = k5_json_encode(array); - if (str == NULL) + if (k5_json_encode(array, &str)) goto oom; d = string2data(str); if (data_to_gss(&d, token)) diff --git a/src/lib/gssapi/krb5/import_cred.c b/src/lib/gssapi/krb5/import_cred.c index ad9a1110e9..973b9d0152 100644 --- a/src/lib/gssapi/krb5/import_cred.c +++ b/src/lib/gssapi/krb5/import_cred.c @@ -205,8 +205,7 @@ json_to_keyblock(k5_json_value v, krb5_keyblock *keyblock) s = check_element(array, 1, K5_JSON_TID_STRING); if (s == NULL) return -1; - keyblock->contents = k5_json_string_unbase64(s, &len); - if (keyblock->contents == NULL) + if (k5_json_string_unbase64(s, &keyblock->contents, &len)) return -1; keyblock->length = len; keyblock->magic = KV5M_KEYBLOCK; @@ -241,8 +240,7 @@ json_to_address(k5_json_value v, krb5_address **addr_out) if (addr == NULL) return -1; addr->addrtype = k5_json_number_value(n); - addr->contents = k5_json_string_unbase64(s, &len); - if (addr->contents == NULL) { + if (k5_json_string_unbase64(s, &addr->contents, &len)) { free(addr); return -1; } @@ -311,8 +309,7 @@ json_to_authdata_element(k5_json_value v, krb5_authdata **ad_out) if (ad == NULL) return -1; ad->ad_type = k5_json_number_value(n); - ad->contents = k5_json_string_unbase64(s, &len); - if (ad->contents == NULL) { + if (k5_json_string_unbase64(s, &ad->contents, &len)) { free(ad); return -1; } @@ -361,6 +358,7 @@ json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds) k5_json_number n; k5_json_bool b; k5_json_string s; + unsigned char *data; size_t len; memset(creds, 0, sizeof(*creds)); @@ -418,17 +416,17 @@ json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds) s = check_element(array, 10, K5_JSON_TID_STRING); if (s == NULL) goto invalid; - creds->ticket.data = k5_json_string_unbase64(s, &len); - if (creds->ticket.data == NULL) + if (k5_json_string_unbase64(s, &data, &len)) goto invalid; + creds->ticket.data = (char *)data; creds->ticket.length = len; s = check_element(array, 11, K5_JSON_TID_STRING); if (s == NULL) goto invalid; - creds->second_ticket.data = k5_json_string_unbase64(s, &len); - if (creds->second_ticket.data == NULL) + if (k5_json_string_unbase64(s, &data, &len)) goto invalid; + creds->second_ticket.data = (char *)data; creds->second_ticket.length = len; if (json_to_authdata(context, k5_json_array_get(array, 12), @@ -620,8 +618,7 @@ krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token, *minor_status = ret; goto cleanup; } - v = k5_json_decode(copy); - if (v == NULL) + if (k5_json_decode(copy, &v)) goto invalid; /* Decode the CRED_EXPORT_MAGIC array wrapper. */ diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c index c88b67a6e8..dfec99179b 100644 --- a/src/lib/krb5/krb/get_in_tkt.c +++ b/src/lib/krb5/krb/get_in_tkt.c @@ -1124,24 +1124,21 @@ save_selected_preauth_type(krb5_context context, krb5_ccache ccache, static krb5_error_code clear_cc_config_out_data(krb5_context context, krb5_init_creds_context ctx) { - if (ctx->cc_config_out != NULL) - k5_json_release(ctx->cc_config_out); - ctx->cc_config_out = k5_json_object_create(); - if (ctx->cc_config_out == NULL) - return ENOMEM; - return 0; + k5_json_release(ctx->cc_config_out); + ctx->cc_config_out = NULL; + return k5_json_object_create(&ctx->cc_config_out); } static krb5_error_code read_cc_config_in_data(krb5_context context, krb5_init_creds_context ctx) { + k5_json_value val; krb5_data config; char *encoded; krb5_error_code code; int i; - if (ctx->cc_config_in != NULL) - k5_json_release(ctx->cc_config_in); + k5_json_release(ctx->cc_config_in); ctx->cc_config_in = NULL; if (ctx->opte->opt_private->in_ccache == NULL) @@ -1159,16 +1156,15 @@ read_cc_config_in_data(krb5_context context, krb5_init_creds_context ctx) if (i < 0) return ENOMEM; - ctx->cc_config_in = k5_json_decode(encoded); + code = k5_json_decode(encoded, &val); free(encoded); - if (ctx->cc_config_in == NULL) - return ENOMEM; - if (k5_json_get_tid(ctx->cc_config_in) != K5_JSON_TID_OBJECT) { - k5_json_release(ctx->cc_config_in); - ctx->cc_config_in = NULL; + if (code) + return code; + if (k5_json_get_tid(val) != K5_JSON_TID_OBJECT) { + k5_json_release(val); return EINVAL; } - + ctx->cc_config_in = val; return 0; } @@ -1183,9 +1179,9 @@ save_cc_config_out_data(krb5_context context, krb5_ccache ccache, if (ctx->cc_config_out == NULL || k5_json_object_count(ctx->cc_config_out) == 0) return 0; - encoded = k5_json_encode(ctx->cc_config_out); - if (encoded == NULL) - return ENOMEM; + code = k5_json_encode(ctx->cc_config_out, &encoded); + if (code) + return code; config = string2data(encoded); code = krb5_cc_set_config(context, ccache, ctx->cred.server, KRB5_CC_CONF_PA_CONFIG_DATA, &config); diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h index 5d813914a4..1bc90a528e 100644 --- a/src/lib/krb5/krb/init_creds_ctx.h +++ b/src/lib/krb5/krb/init_creds_ctx.h @@ -50,8 +50,8 @@ struct _krb5_init_creds_context { struct krb5_responder_context_st rctx; krb5_preauthtype selected_preauth_type; krb5_preauthtype allowed_preauth_type; - void *cc_config_in; - void *cc_config_out; + k5_json_object cc_config_in; + k5_json_object cc_config_out; /* Discovered offset of server time during preauth */ krb5_timestamp pa_offset; krb5_int32 pa_offset_usec; diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c index 060f98aa00..74a4f27beb 100644 --- a/src/lib/krb5/krb/preauth2.c +++ b/src/lib/krb5/krb/preauth2.c @@ -469,22 +469,19 @@ set_cc_config(krb5_context context, krb5_clpreauth_rock rock, const char *key, const char *data) { krb5_init_creds_context ctx = (krb5_init_creds_context)rock; - k5_json_value value; - int i; + krb5_error_code ret; + k5_json_string str; if (ctx->cc_config_out == NULL) return ENOENT; - value = k5_json_string_create(data); - if (value == NULL) - return ENOMEM; - - i = k5_json_object_set(ctx->cc_config_out, key, value); - k5_json_release(value); - if (i < 0) - return ENOMEM; + ret = k5_json_string_create(data, &str); + if (ret) + return ret; - return 0; + ret = k5_json_object_set(ctx->cc_config_out, key, str); + k5_json_release(str); + return ret; } static struct krb5_clpreauth_callbacks_st callbacks = { diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c index e610d47a94..d343683c02 100644 --- a/src/lib/krb5/krb/preauth_otp.c +++ b/src/lib/krb5/krb/preauth_otp.c @@ -99,13 +99,13 @@ codec_data_to_value(krb5_data *data, k5_json_object obj, const char *key) if (data->data == NULL) return 0; - str = k5_json_string_create_len(data->data, data->length); - if (str == NULL) - return ENOMEM; + retval = k5_json_string_create_len(data->data, data->length, &str); + if (retval) + return retval; retval = k5_json_object_set(obj, key, str); k5_json_release(str); - return retval == 0 ? 0 : ENOMEM; + return retval; } /* Converts a property of a json object into a krb5_int32. */ @@ -135,25 +135,25 @@ codec_int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key) if (int32 == -1) return 0; - num = k5_json_number_create(int32); - if (num == NULL) - return ENOMEM; + retval = k5_json_number_create(int32, &num); + if (retval) + return retval; retval = k5_json_object_set(obj, key, num); k5_json_release(num); - return retval == 0 ? 0 : ENOMEM; + return retval; } /* Converts a krb5_otp_tokeninfo into a JSON object. */ static krb5_error_code codec_encode_tokeninfo(krb5_otp_tokeninfo *ti, k5_json_object *out) { - krb5_error_code retval = 0; + krb5_error_code retval; k5_json_object obj; krb5_flags flags; - obj = k5_json_object_create(); - if (obj == NULL) + retval = k5_json_object_create(&obj); + if (retval != 0) goto error; flags = KRB5_RESPONDER_OTP_FLAGS_COLLECT_TOKEN; @@ -212,60 +212,51 @@ codec_encode_challenge(krb5_context ctx, krb5_pa_otp_challenge *chl, k5_json_object obj = NULL, tmp = NULL; k5_json_string str = NULL; k5_json_array arr = NULL; - krb5_error_code retval = 0; + krb5_error_code retval; int i; - obj = k5_json_object_create(); - if (obj == NULL) - goto error; + retval = k5_json_object_create(&obj); + if (retval != 0) + goto cleanup; if (chl->service.data) { - str = k5_json_string_create_len(chl->service.data, - chl->service.length); - if (str == NULL) - goto error; + retval = k5_json_string_create_len(chl->service.data, + chl->service.length, &str); + if (retval != 0) + goto cleanup; retval = k5_json_object_set(obj, "service", str); k5_json_release(str); - if (retval != 0) { - retval = ENOMEM; - goto error; - } + if (retval != 0) + goto cleanup; } - arr = k5_json_array_create(); - if (arr == NULL) - goto error; + retval = k5_json_array_create(&arr); + if (retval != 0) + goto cleanup; for (i = 0; chl->tokeninfo[i] != NULL ; i++) { retval = codec_encode_tokeninfo(chl->tokeninfo[i], &tmp); if (retval != 0) - goto error; + goto cleanup; retval = k5_json_array_add(arr, tmp); k5_json_release(tmp); - if (retval != 0) { - retval = ENOMEM; - goto error; - } - } - - if (k5_json_object_set(obj, "tokenInfo", arr) != 0) { - retval = ENOMEM; - goto error; + if (retval != 0) + goto cleanup; } - *json = k5_json_encode(obj); - if (*json == NULL) - goto error; + retval = k5_json_object_set(obj, "tokenInfo", arr); + if (retval != 0) + goto cleanup; - k5_json_release(arr); - k5_json_release(obj); - return 0; + retval = k5_json_encode(obj, json); + if (retval) + goto cleanup; -error: +cleanup: k5_json_release(arr); k5_json_release(obj); - return retval == 0 ? ENOMEM : retval; + return retval; } /* Converts a JSON object into a krb5_responder_otp_tokeninfo. */ @@ -327,8 +318,8 @@ codec_decode_challenge(krb5_context ctx, const char *json) krb5_error_code retval; size_t i; - obj = k5_json_decode(json); - if (obj == NULL) + retval = k5_json_decode(json, &obj); + if (retval != 0) goto error; if (k5_json_get_tid(obj) != K5_JSON_TID_OBJECT) @@ -384,7 +375,7 @@ codec_decode_answer(krb5_context context, const char *answer, krb5_otp_tokeninfo **tis, krb5_otp_tokeninfo **ti, krb5_data *value, krb5_data *pin) { - krb5_error_code retval = EBADMSG; + krb5_error_code retval; k5_json_value val = NULL; krb5_int32 indx, i; krb5_data tmp; @@ -392,8 +383,8 @@ codec_decode_answer(krb5_context context, const char *answer, if (answer == NULL) return EBADMSG; - val = k5_json_decode(answer); - if (val == NULL) + retval = k5_json_decode(answer, &val); + if (retval != 0) goto cleanup; if (k5_json_get_tid(val) != K5_JSON_TID_OBJECT) @@ -1196,48 +1187,49 @@ krb5_responder_otp_set_answer(krb5_context ctx, krb5_responder_context rctx, { krb5_error_code retval; k5_json_object obj = NULL; - k5_json_value val = NULL; + k5_json_number num; + k5_json_string str; char *tmp; - obj = k5_json_object_create(); - if (obj == NULL) + retval = k5_json_object_create(&obj); + if (retval != 0) goto error; - val = k5_json_number_create(ti); - if (val == NULL) + retval = k5_json_number_create(ti, &num); + if (retval != 0) goto error; - retval = k5_json_object_set(obj, "tokeninfo", val); - k5_json_release(val); + retval = k5_json_object_set(obj, "tokeninfo", num); + k5_json_release(num); if (retval != 0) goto error; if (value != NULL) { - val = k5_json_string_create(value); - if (val == NULL) + retval = k5_json_string_create(value, &str); + if (retval != 0) goto error; - retval = k5_json_object_set(obj, "value", val); - k5_json_release(val); + retval = k5_json_object_set(obj, "value", str); + k5_json_release(str); if (retval != 0) goto error; } if (pin != NULL) { - val = k5_json_string_create(pin); - if (val == NULL) + retval = k5_json_string_create(pin, &str); + if (retval != 0) goto error; - retval = k5_json_object_set(obj, "pin", val); - k5_json_release(val); + retval = k5_json_object_set(obj, "pin", str); + k5_json_release(str); if (retval != 0) goto error; } - tmp = k5_json_encode(obj); - k5_json_release(obj); - if (tmp == NULL) + retval = k5_json_encode(obj, &tmp); + if (retval != 0) goto error; + k5_json_release(obj); retval = krb5_responder_set_answer(ctx, rctx, KRB5_RESPONDER_QUESTION_OTP, tmp); @@ -1246,7 +1238,7 @@ krb5_responder_otp_set_answer(krb5_context ctx, krb5_responder_context rctx, error: k5_json_release(obj); - return ENOMEM; + return retval; } void KRB5_CALLCONV diff --git a/src/util/support/json.c b/src/util/support/json.c index f02fe263df..5151b84159 100644 --- a/src/util/support/json.c +++ b/src/util/support/json.c @@ -96,7 +96,7 @@ struct value_base { #define PTR2BASE(ptr) (((struct value_base *)ptr) - 1) #define BASE2PTR(ptr) ((void *)(((struct value_base *)ptr) + 1)) -void * +k5_json_value k5_json_retain(k5_json_value val) { struct value_base *p; @@ -160,24 +160,29 @@ alloc_value(json_type type, size_t size) static struct json_type_st null_type = { K5_JSON_TID_NULL, "null", NULL }; -k5_json_null -k5_json_null_create(void) +int +k5_json_null_create(k5_json_null *val_out) { - return alloc_value(&null_type, 0); + *val_out = alloc_value(&null_type, 0); + return (*val_out == NULL) ? ENOMEM : 0; } /*** Boolean type ***/ static struct json_type_st bool_type = { K5_JSON_TID_BOOL, "bool", NULL }; -k5_json_bool -k5_json_bool_create(int truth) +int +k5_json_bool_create(int truth, k5_json_bool *val_out) { k5_json_bool b; + *val_out = NULL; b = alloc_value(&bool_type, 1); + if (b == NULL) + return ENOMEM; *(unsigned char *)b = !!truth; - return b; + *val_out = b; + return 0; } int @@ -209,10 +214,11 @@ static struct json_type_st array_type = { K5_JSON_TID_ARRAY, "array", array_dealloc }; -k5_json_array -k5_json_array_create(void) +int +k5_json_array_create(k5_json_array *val_out) { - return alloc_value(&array_type, sizeof(struct k5_json_array_st)); + *val_out = alloc_value(&array_type, sizeof(struct k5_json_array_st)); + return (*val_out == NULL) ? ENOMEM : 0; } int @@ -289,10 +295,11 @@ static struct json_type_st object_type = { K5_JSON_TID_OBJECT, "object", object_dealloc }; -k5_json_object -k5_json_object_create(void) +int +k5_json_object_create(k5_json_object *val_out) { - return alloc_value(&object_type, sizeof(struct k5_json_object_st)); + *val_out = alloc_value(&object_type, sizeof(struct k5_json_object_st)); + return (*val_out == NULL) ? ENOMEM : 0; } size_t @@ -373,37 +380,42 @@ static struct json_type_st string_type = { K5_JSON_TID_STRING, "string", NULL }; -k5_json_string -k5_json_string_create(const char *string) +int +k5_json_string_create(const char *cstring, k5_json_string *val_out) { - return k5_json_string_create_len(string, strlen(string)); + return k5_json_string_create_len(cstring, strlen(cstring), val_out); } -k5_json_string -k5_json_string_create_len(const void *data, size_t len) +int +k5_json_string_create_len(const void *data, size_t len, + k5_json_string *val_out) { char *s; + *val_out = NULL; s = alloc_value(&string_type, len + 1); if (s == NULL) - return NULL; + return ENOMEM; memcpy(s, data, len); s[len] = '\0'; - return (k5_json_string)s; + *val_out = (k5_json_string)s; + return 0; } -k5_json_string -k5_json_string_create_base64(const void *data, size_t len) +int +k5_json_string_create_base64(const void *data, size_t len, + k5_json_string *val_out) { char *base64; - k5_json_string s; + int ret; + *val_out = NULL; base64 = k5_base64_encode(data, len); if (base64 == NULL) - return NULL; - s = k5_json_string_create(base64); + return ENOMEM; + ret = k5_json_string_create(base64, val_out); free(base64); - return s; + return ret; } const char * @@ -412,10 +424,21 @@ k5_json_string_utf8(k5_json_string string) return (const char *)string; } -void * -k5_json_string_unbase64(k5_json_string string, size_t *len_out) +int +k5_json_string_unbase64(k5_json_string string, unsigned char **data_out, + size_t *len_out) { - return k5_base64_decode((const char *)string, len_out); + unsigned char *data; + size_t len; + + *data_out = NULL; + *len_out = 0; + data = k5_base64_decode((const char *)string, &len); + if (data == NULL) + return (len == 0) ? ENOMEM : EINVAL; + *data_out = data; + *len_out = len; + return 0; } /*** Number type ***/ @@ -424,15 +447,18 @@ static struct json_type_st number_type = { K5_JSON_TID_NUMBER, "number", NULL }; -k5_json_number -k5_json_number_create(long long number) +int +k5_json_number_create(long long number, k5_json_number *val_out) { k5_json_number n; + *val_out = NULL; n = alloc_value(&number_type, sizeof(long long)); - if (n) - *((long long *)n) = number; - return n; + if (n == NULL) + return ENOMEM; + *((long long *)n) = number; + *val_out = n; + return 0; } long long @@ -448,62 +474,61 @@ static const char quotemap_c[] = "\"\\/\b\f\n\r\t"; static const char needs_quote[] = "\\\"\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17" "\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37"; -struct encode_ctx { - struct k5buf buf; - int ret; - int first; -}; - -static int encode_value(struct encode_ctx *j, k5_json_value val); +static int encode_value(struct k5buf *buf, k5_json_value val); static void -encode_string(struct encode_ctx *j, const char *str) +encode_string(struct k5buf *buf, const char *str) { size_t n; const char *p; - krb5int_buf_add(&j->buf, "\""); + krb5int_buf_add(buf, "\""); while (*str != '\0') { n = strcspn(str, needs_quote); - krb5int_buf_add_len(&j->buf, str, n); + krb5int_buf_add_len(buf, str, n); str += n; if (*str == '\0') break; - krb5int_buf_add(&j->buf, "\\"); + krb5int_buf_add(buf, "\\"); p = strchr(quotemap_c, *str); if (p != NULL) - krb5int_buf_add_len(&j->buf, quotemap_json + (p - quotemap_c), 1); + krb5int_buf_add_len(buf, quotemap_json + (p - quotemap_c), 1); else - krb5int_buf_add_fmt(&j->buf, "u00%02X", (unsigned int)*str); + krb5int_buf_add_fmt(buf, "u00%02X", (unsigned int)*str); str++; } - krb5int_buf_add(&j->buf, "\""); + krb5int_buf_add(buf, "\""); } +struct obj_ctx { + struct k5buf *buf; + int ret; + int first; +}; + static void -encode_dict_entry(void *ctx, const char *key, k5_json_value value) +encode_obj_entry(void *ctx, const char *key, k5_json_value value) { - struct encode_ctx *j = ctx; + struct obj_ctx *j = ctx; if (j->ret) return; if (j->first) j->first = 0; else - krb5int_buf_add(&j->buf, ","); - encode_string(j, key); - krb5int_buf_add(&j->buf, ":"); - j->ret = encode_value(j, value); - if (j->ret) - return; + krb5int_buf_add(j->buf, ","); + encode_string(j->buf, key); + krb5int_buf_add(j->buf, ":"); + j->ret = encode_value(j->buf, value); } static int -encode_value(struct encode_ctx *j, k5_json_value val) +encode_value(struct k5buf *buf, k5_json_value val) { k5_json_tid type; - int first = 0, ret; + int ret; size_t i, len; + struct obj_ctx ctx; if (val == NULL) return EINVAL; @@ -511,62 +536,63 @@ encode_value(struct encode_ctx *j, k5_json_value val) type = k5_json_get_tid(val); switch (type) { case K5_JSON_TID_ARRAY: - krb5int_buf_add(&j->buf, "["); + krb5int_buf_add(buf, "["); len = k5_json_array_length(val); for (i = 0; i < len; i++) { if (i != 0) - krb5int_buf_add(&j->buf, ","); - ret = encode_value(j, k5_json_array_get(val, i)); + krb5int_buf_add(buf, ","); + ret = encode_value(buf, k5_json_array_get(val, i)); if (ret) return ret; } - krb5int_buf_add(&j->buf, "]"); - break; + krb5int_buf_add(buf, "]"); + return 0; case K5_JSON_TID_OBJECT: - krb5int_buf_add(&j->buf, "{"); - first = j->first; - j->first = 1; - k5_json_object_iterate(val, encode_dict_entry, j); - krb5int_buf_add(&j->buf, "}"); - j->first = first; - break; + krb5int_buf_add(buf, "{"); + ctx.buf = buf; + ctx.ret = 0; + ctx.first = 1; + k5_json_object_iterate(val, encode_obj_entry, &ctx); + krb5int_buf_add(buf, "}"); + return ctx.ret; case K5_JSON_TID_STRING: - encode_string(j, k5_json_string_utf8(val)); - break; + encode_string(buf, k5_json_string_utf8(val)); + return 0; case K5_JSON_TID_NUMBER: - krb5int_buf_add_fmt(&j->buf, "%lld", k5_json_number_value(val)); - break; + krb5int_buf_add_fmt(buf, "%lld", k5_json_number_value(val)); + return 0; case K5_JSON_TID_NULL: - krb5int_buf_add(&j->buf, "null"); - break; + krb5int_buf_add(buf, "null"); + return 0; case K5_JSON_TID_BOOL: - krb5int_buf_add(&j->buf, k5_json_bool_value(val) ? "true" : "false"); - break; + krb5int_buf_add(buf, k5_json_bool_value(val) ? "true" : "false"); + return 0; default: - return 1; + return EINVAL; } - return 0; } -char * -k5_json_encode(k5_json_value val) +int +k5_json_encode(k5_json_value val, char **json_out) { - struct encode_ctx j; + struct k5buf buf; + int ret; - j.ret = 0; - j.first = 1; - krb5int_buf_init_dynamic(&j.buf); - if (encode_value(&j, val)) { - krb5int_free_buf(&j.buf); - return NULL; + *json_out = NULL; + krb5int_buf_init_dynamic(&buf); + ret = encode_value(&buf, val); + if (ret) { + krb5int_free_buf(&buf); + return ret; } - return krb5int_buf_data(&j.buf); + *json_out = krb5int_buf_data(&buf); + return (*json_out == NULL) ? ENOMEM : 0; } /*** JSON decoding ***/ @@ -576,8 +602,7 @@ struct decode_ctx { size_t depth; }; -static k5_json_value -parse_value(struct decode_ctx *ctx); +static int parse_value(struct decode_ctx *ctx, k5_json_value *val_out); /* Consume whitespace. Return 0 if there is anything left to parse after the * whitespace, -1 if not. */ @@ -621,66 +646,70 @@ hexval(unsigned char c) /* Parse a JSON number (which must be an integer in the signed 64-bit range; we * do not allow floating-point numbers). */ -static k5_json_number -parse_number(struct decode_ctx *ctx) +static int +parse_number(struct decode_ctx *ctx, k5_json_number *val_out) { const unsigned long long umax = ~0ULL, smax = (1ULL << 63) - 1; unsigned long long number = 0; int neg = 1; + *val_out = NULL; + if (*ctx->p == '-') { neg = -1; ctx->p++; } if (!is_digit(*ctx->p)) - return NULL; + return EINVAL; /* Read the number into an unsigned 64-bit container, ensuring that we * don't overflow it. */ while (is_digit(*ctx->p)) { if (number + 1 > umax / 10) - return NULL; + return EOVERFLOW; number = (number * 10) + (*ctx->p - '0'); ctx->p++; } /* Make sure the unsigned 64-bit value fits in the signed 64-bit range. */ if (number > smax + 1 || (number > smax && neg == 1)) - return NULL; + return EOVERFLOW; - return k5_json_number_create(number * neg); + return k5_json_number_create(number * neg, val_out); } /* Parse a JSON string (which must not quote Unicode code points above 256). */ -static char * -parse_string(struct decode_ctx *ctx) +static int +parse_string(struct decode_ctx *ctx, char **str_out) { const unsigned char *p, *start, *end = NULL; const char *q; char *buf, *pos; unsigned int code; + *str_out = NULL; + /* Find the start and end of the string. */ if (*ctx->p != '"') - return NULL; + return EINVAL; start = ++ctx->p; for (; *ctx->p != '\0'; ctx->p++) { if (*ctx->p == '\\') { ctx->p++; if (*ctx->p == '\0') - return NULL; + return EINVAL; } else if (*ctx->p == '"') { end = ctx->p++; break; } } if (end == NULL) - return NULL; + return EINVAL; pos = buf = malloc(end - start + 1); if (buf == NULL) - return NULL; + return ENOMEM; for (p = start; p < end;) { if (*p == '\\') { p++; @@ -694,7 +723,7 @@ parse_string(struct decode_ctx *ctx) /* Code points above 0xff don't need to be quoted, so we * don't implement translating those into UTF-8. */ free(buf); - return NULL; + return EINVAL; } p += 5; } else { @@ -703,7 +732,7 @@ parse_string(struct decode_ctx *ctx) *pos++ = quotemap_c[q - quotemap_json]; } else { free(buf); - return NULL; + return EINVAL; } p++; } @@ -712,198 +741,245 @@ parse_string(struct decode_ctx *ctx) } } *pos = '\0'; - return buf; + *str_out = buf; + return 0; } -/* - * Parse an object association and the following comma. Return 1 if an - * association was parsed, 0 if the end of the object was reached, and -1 on - * error. - */ +/* Parse an object association and place it into obj. */ static int -parse_pair(k5_json_object obj, struct decode_ctx *ctx) +parse_object_association(k5_json_object obj, struct decode_ctx *ctx) { char *key = NULL; - k5_json_value value; - - if (white_spaces(ctx)) - goto err; - - /* Check for the end of the object. */ - if (*ctx->p == '}') { - ctx->p++; - return 0; - } + k5_json_value val; + int ret; /* Parse the key and value. */ - key = parse_string(ctx); - if (key == NULL) - goto err; + ret = parse_string(ctx, &key); + if (ret) + return ret; if (white_spaces(ctx)) - goto err; + goto invalid; if (*ctx->p != ':') - goto err; + goto invalid; ctx->p++; if (white_spaces(ctx)) - goto err; - value = parse_value(ctx); - if (value == NULL) { + goto invalid; + ret = parse_value(ctx, &val); + if (ret) { free(key); - return -1; + return ret; } - /* Add the key and value to the object. */ - k5_json_object_set(obj, key, value); + /* Add the key and value to obj. */ + ret = k5_json_object_set(obj, key, val); free(key); - key = NULL; - k5_json_release(value); - - /* Consume the following comma if this isn't the last item. */ - if (white_spaces(ctx)) - goto err; - if (*ctx->p == ',') - ctx->p++; - else if (*ctx->p != '}') - goto err; + k5_json_release(val); + return ret; - return 1; - -err: +invalid: free(key); - return -1; + return EINVAL; } /* Parse a JSON object. */ -static k5_json_object -parse_object(struct decode_ctx *ctx) +static int +parse_object(struct decode_ctx *ctx, k5_json_object *val_out) { - k5_json_object obj; + k5_json_object obj = NULL; int ret; - obj = k5_json_object_create(); - if (obj == NULL) - return NULL; + *val_out = NULL; + /* Parse past the opening brace. */ + if (*ctx->p != '{') + return EINVAL; ctx->p++; - while ((ret = parse_pair(obj, ctx)) > 0) - ; - if (ret < 0) { - k5_json_release(obj); - return NULL; - } - return obj; -} - -/* Parse a JSON array item and the following comma. Return 1 if an item was - * parsed, 0 if the end of the array was reached, and -1 on error. */ -static int -parse_item(k5_json_array array, struct decode_ctx *ctx) -{ - k5_json_value value; - if (white_spaces(ctx)) - return -1; + return EINVAL; - if (*ctx->p == ']') { - ctx->p++; - return 0; - } + ret = k5_json_object_create(&obj); + if (ret) + return ret; - value = parse_value(ctx); - if (value == NULL) - return -1; + /* Pairs associations until we reach the terminating brace. */ + if (*ctx->p != '}') { + while (1) { + ret = parse_object_association(obj, ctx); + if (ret) { + k5_json_release(obj); + return ret; + } + if (white_spaces(ctx)) + goto invalid; + if (*ctx->p == '}') + break; + if (*ctx->p != ',') + goto invalid; + ctx->p++; + if (white_spaces(ctx)) + goto invalid; + } + } + ctx->p++; + *val_out = obj; + return 0; - k5_json_array_add(array, value); - k5_json_release(value); +invalid: + k5_json_release(obj); + return EINVAL; +} - if (white_spaces(ctx)) - return -1; +/* Parse an value and place it into array. */ +static int +parse_array_item(k5_json_array array, struct decode_ctx *ctx) +{ + k5_json_value val; + int ret; - if (*ctx->p == ',') - ctx->p++; - else if (*ctx->p != ']') - return -1; - return 1; + ret = parse_value(ctx, &val); + if (ret) + return ret; + ret = k5_json_array_add(array, val); + k5_json_release(val); + return ret; } /* Parse a JSON array. */ -static k5_json_array -parse_array(struct decode_ctx *ctx) +static int +parse_array(struct decode_ctx *ctx, k5_json_array *val_out) { - k5_json_array array = k5_json_array_create(); + k5_json_array array = NULL; int ret; - assert(*ctx->p == '['); - ctx->p += 1; + *val_out = NULL; - while ((ret = parse_item(array, ctx)) > 0) - ; - if (ret < 0) { - k5_json_release(array); - return NULL; + /* Parse past the opening bracket. */ + if (*ctx->p != '[') + return EINVAL; + ctx->p++; + if (white_spaces(ctx)) + return EINVAL; + + ret = k5_json_array_create(&array); + if (ret) + return ret; + + /* Pairs values until we reach the terminating bracket. */ + if (*ctx->p != ']') { + while (1) { + ret = parse_array_item(array, ctx); + if (ret) { + k5_json_release(array); + return ret; + } + if (white_spaces(ctx)) + goto invalid; + if (*ctx->p == ']') + break; + if (*ctx->p != ',') + goto invalid; + ctx->p++; + if (white_spaces(ctx)) + goto invalid; + } } - return array; + ctx->p++; + *val_out = array; + return 0; + +invalid: + k5_json_release(array); + return EINVAL; } /* Parse a JSON value of any type. */ -static k5_json_value -parse_value(struct decode_ctx *ctx) +static int +parse_value(struct decode_ctx *ctx, k5_json_value *val_out) { - k5_json_value v; - char *str; + k5_json_null null; + k5_json_bool bval; + k5_json_number num; + k5_json_string str; + k5_json_object obj; + k5_json_array array; + char *cstring; + int ret; + + *val_out = NULL; if (white_spaces(ctx)) - return NULL; + return EINVAL; if (*ctx->p == '"') { - str = parse_string(ctx); - if (str == NULL) - return NULL; - v = k5_json_string_create(str); - free(str); - return v; + ret = parse_string(ctx, &cstring); + if (ret) + return ret; + ret = k5_json_string_create(cstring, &str); + free(cstring); + if (ret) + return ret; + *val_out = str; } else if (*ctx->p == '{') { if (ctx->depth-- == 1) - return NULL; - v = parse_object(ctx); + return EINVAL; + ret = parse_object(ctx, &obj); + if (ret) + return ret; ctx->depth++; - return v; + *val_out = obj; } else if (*ctx->p == '[') { if (ctx->depth-- == 1) - return NULL; - v = parse_array(ctx); + return EINVAL; + ret = parse_array(ctx, &array); ctx->depth++; - return v; + *val_out = array; } else if (is_digit(*ctx->p) || *ctx->p == '-') { - return parse_number(ctx); - } - - if (strncmp((char *)ctx->p, "null", 4) == 0) { + ret = parse_number(ctx, &num); + if (ret) + return ret; + *val_out = num; + } else if (strncmp((char *)ctx->p, "null", 4) == 0) { ctx->p += 4; - return k5_json_null_create(); + ret = k5_json_null_create(&null); + if (ret) + return ret; + *val_out = null; } else if (strncmp((char *)ctx->p, "true", 4) == 0) { ctx->p += 4; - return k5_json_bool_create(1); + ret = k5_json_bool_create(1, &bval); + if (ret) + return ret; + *val_out = bval; } else if (strncmp((char *)ctx->p, "false", 5) == 0) { ctx->p += 5; - return k5_json_bool_create(0); + ret = k5_json_bool_create(0, &bval); + if (ret) + return ret; + *val_out = bval; + } else { + return EINVAL; } - return NULL; + return 0; } -k5_json_value -k5_json_decode(const char *string) +int +k5_json_decode(const char *string, k5_json_value *val_out) { struct decode_ctx ctx; - k5_json_value v; + k5_json_value val; + int ret; + *val_out = NULL; ctx.p = (unsigned char *)string; ctx.depth = MAX_DECODE_DEPTH; - v = parse_value(&ctx); + ret = parse_value(&ctx, &val); + if (ret) + return ret; if (white_spaces(&ctx) == 0) { - k5_json_release(v); - return NULL; + k5_json_release(val); + return EINVAL; } - return v; + *val_out = val; + return 0; } diff --git a/src/util/support/t_json.c b/src/util/support/t_json.c index 7b30007afd..afb02ee614 100644 --- a/src/util/support/t_json.c +++ b/src/util/support/t_json.c @@ -88,14 +88,18 @@ check(int pred, const char *str) static void test_array() { - k5_json_string v1 = k5_json_string_create("abc"); - k5_json_number v2 = k5_json_number_create(2); - k5_json_null v3 = k5_json_null_create(); - k5_json_array a = k5_json_array_create(); + k5_json_string v1; + k5_json_number v2; + k5_json_null v3; + k5_json_array a; k5_json_value v; + k5_json_array_create(&a); + k5_json_string_create("abc", &v1); k5_json_array_add(a, v1); + k5_json_number_create(2, &v2); k5_json_array_add(a, v2); + k5_json_null_create(&v3); k5_json_array_add(a, v3); check(k5_json_array_length(a) == 3, "array length"); @@ -118,11 +122,13 @@ static void test_object(void) { k5_json_object object; - k5_json_number n, v1 = k5_json_number_create(1); - k5_json_string s, v2 = k5_json_string_create("hejsan"); + k5_json_number n, v1; + k5_json_string s, v2; - object = k5_json_object_create(); + k5_json_object_create(&object); + k5_json_number_create(1, &v1); k5_json_object_set(object, "key1", v1); + k5_json_string_create("hejsan", &v2); k5_json_object_set(object, "key2", v2); n = k5_json_object_get(object, "key1"); @@ -142,20 +148,21 @@ static void test_string(void) { k5_json_string s1, s2, s3; - void *data; + unsigned char *data; size_t len; - s1 = k5_json_string_create("hejsan"); - s2 = k5_json_string_create("hejsan"); - s3 = k5_json_string_create_base64("55555", 5); + k5_json_string_create("hejsan", &s1); + k5_json_string_create("hejsan", &s2); + k5_json_string_create_base64("55555", 5, &s3); if (strcmp(k5_json_string_utf8(s1), k5_json_string_utf8(s2)) != 0) err("Identical strings are not identical"); if (strcmp(k5_json_string_utf8(s3), "NTU1NTU=") != 0) err("base64 string has incorrect value"); - data = k5_json_string_unbase64(s3, &len); - if (data == NULL || len != 5 || memcmp(data, "55555", 5) != 0) + k5_json_string_unbase64(s3, &data, &len); + if (len != 5 || memcmp(data, "55555", 5) != 0) err("base64 string doesn't decode to correct value"); + free(data); k5_json_release(s1); k5_json_release(s2); @@ -181,20 +188,17 @@ test_json(void) int i; k5_json_value v, v2; - v = k5_json_decode("\"string\""); - check(v != NULL, "string1"); + check(k5_json_decode("\"string\"", &v) == 0, "string1"); check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string1 tid"); check(strcmp(k5_json_string_utf8(v), "string") == 0, "string1 utf8"); k5_json_release(v); - v = k5_json_decode("\t \"foo\\\"bar\" "); - check(v != NULL, "string2"); + check(k5_json_decode("\t \"foo\\\"bar\" ", &v) == 0, "string2"); check(k5_json_get_tid(v) == K5_JSON_TID_STRING, "string2 tid"); check(strcmp(k5_json_string_utf8(v), "foo\"bar") == 0, "string2 utf8"); k5_json_release(v); - v = k5_json_decode(" { \"key\" : \"value\" }"); - check(v != NULL, "object1"); + check(k5_json_decode(" { \"key\" : \"value\" }", &v) == 0, "object1"); check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object1 tid"); v2 = k5_json_object_get(v, "key"); check(v2 != NULL, "object[key]"); @@ -202,9 +206,8 @@ test_json(void) check(strcmp(k5_json_string_utf8(v2), "value") == 0, "object1[key] utf8"); k5_json_release(v); - v = k5_json_decode("{ \"k1\" : { \"k2\" : \"s2\", \"k3\" : \"s3\" }, " - "\"k4\" : \"s4\" }"); - check(v != NULL, "object2"); + check(k5_json_decode("{ \"k1\" : { \"k2\" : \"s2\", \"k3\" : \"s3\" }, " + "\"k4\" : \"s4\" }", &v) == 0, "object2"); v2 = k5_json_object_get(v, "k1"); check(v2 != NULL, "object2[k1]"); check(k5_json_get_tid(v2) == K5_JSON_TID_OBJECT, "object2[k1] tid"); @@ -214,28 +217,24 @@ test_json(void) check(strcmp(k5_json_string_utf8(v2), "s3") == 0, "object2[k1][k3] utf8"); k5_json_release(v); - v = k5_json_decode("{ \"k1\" : 1 }"); - check(v != NULL, "object3"); + check(k5_json_decode("{ \"k1\" : 1 }", &v) == 0, "object3"); check(k5_json_get_tid(v) == K5_JSON_TID_OBJECT, "object3 id"); v2 = k5_json_object_get(v, "k1"); check(k5_json_get_tid(v2) == K5_JSON_TID_NUMBER, "object3[k1] tid"); check(k5_json_number_value(v2) == 1, "object3[k1] value"); k5_json_release(v); - v = k5_json_decode("-10"); - check(v != NULL, "number1"); + check(k5_json_decode("-10", &v) == 0, "number1"); check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number1 tid"); check(k5_json_number_value(v) == -10, "number1 value"); k5_json_release(v); - v = k5_json_decode("99"); - check(v != NULL, "number2"); + check(k5_json_decode("99", &v) == 0, "number2"); check(k5_json_get_tid(v) == K5_JSON_TID_NUMBER, "number2 tid"); check(k5_json_number_value(v) == 99, "number2 value"); k5_json_release(v); - v = k5_json_decode(" [ 1 ]"); - check(v != NULL, "array1"); + check(k5_json_decode(" [ 1 ]", &v) == 0, "array1"); check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array1 tid"); check(k5_json_array_length(v) == 1, "array1 len"); v2 = k5_json_array_get(v, 0); @@ -244,8 +243,7 @@ test_json(void) check(k5_json_number_value(v2) == 1, "array1[0] value"); k5_json_release(v); - v = k5_json_decode(" [ -1 ]"); - check(v != NULL, "array2"); + check(k5_json_decode(" [ -1 ]", &v) == 0, "array2"); check(k5_json_get_tid(v) == K5_JSON_TID_ARRAY, "array2 tid"); check(k5_json_array_length(v) == 1, "array2 len"); v2 = k5_json_array_get(v, 0); @@ -254,20 +252,18 @@ test_json(void) check(k5_json_number_value(v2) == -1, "array2[0] value"); k5_json_release(v); - v = k5_json_decode("18446744073709551616"); - check(v == NULL, "unsigned 64-bit overflow"); - v = k5_json_decode("9223372036854775808"); - check(v == NULL, "signed 64-bit positive overflow"); - v = k5_json_decode("-9223372036854775809"); - check(v == NULL, "signed 64-bit negative overflow"); + check(k5_json_decode("18446744073709551616", &v) == EOVERFLOW, + "unsigned 64-bit overflow"); + check(k5_json_decode("9223372036854775808", &v) == EOVERFLOW, + "signed 64-bit positive overflow"); + check(k5_json_decode("-9223372036854775809", &v) == EOVERFLOW, + "signed 64-bit negative overflow"); for (tptr = tests; *tptr != NULL; tptr++) { s = strdup(*tptr); - v = k5_json_decode(s); - if (v == NULL) + if (k5_json_decode(s, &v)) err(s); - enc = k5_json_encode(v); - if (enc == NULL || strcmp(enc, s) != 0) + if (k5_json_encode(v, &enc) || strcmp(enc, s) != 0) err(s); free(enc); k5_json_release(v); @@ -278,7 +274,8 @@ test_json(void) orig = *p; for (i = 0; i <= 255; i++) { *p = i; - k5_json_release(k5_json_decode(s)); + k5_json_decode(s, &v); + k5_json_release(v); } *p = orig; } |