diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-02 22:07:10 +0100 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-01-11 09:03:25 +0100 |
commit | 72278e62d990d81a05756ef2a33e11aec1beb4e5 (patch) | |
tree | cfbfedbca5c3675499d701b7498258266414d74a /src | |
parent | sd-dhcp-client-id/duid: do not trigger assertion when invalid size is passed (diff) | |
download | systemd-72278e62d990d81a05756ef2a33e11aec1beb4e5.tar.xz systemd-72278e62d990d81a05756ef2a33e11aec1beb4e5.zip |
json: introduce json_dispatch_byte_array_iovec() and json_dispatch_in_addr()
Diffstat (limited to 'src')
-rw-r--r-- | src/shared/json.c | 56 | ||||
-rw-r--r-- | src/shared/json.h | 2 |
2 files changed, 58 insertions, 0 deletions
diff --git a/src/shared/json.c b/src/shared/json.c index 073bf31acd..47cd78b396 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -14,7 +14,9 @@ #include "fd-util.h" #include "fileio.h" #include "float.h" +#include "glyph-util.h" #include "hexdecoct.h" +#include "iovec-util.h" #include "json-internal.h" #include "json.h" #include "macro.h" @@ -4993,6 +4995,60 @@ int json_dispatch_unbase64_iovec(const char *name, JsonVariant *variant, JsonDis return 0; } +int json_dispatch_byte_array_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { + _cleanup_free_ uint8_t *buffer = NULL; + struct iovec *iov = ASSERT_PTR(userdata); + size_t sz, k = 0; + + assert(variant); + + if (!json_variant_is_array(variant)) + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name)); + + sz = json_variant_elements(variant); + + buffer = new(uint8_t, sz); + if (!buffer) + return json_log(variant, flags, SYNTHETIC_ERRNO(ENOMEM), "Out of memory."); + + JsonVariant *i; + JSON_VARIANT_ARRAY_FOREACH(i, variant) { + uint64_t b; + + if (!json_variant_is_unsigned(i)) + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an unsigned integer.", k, strna(name)); + + b = json_variant_unsigned(i); + if (b > 0xff) + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), + "Element %zu of JSON field '%s' is out of range 0%s255.", + k, strna(name), special_glyph(SPECIAL_GLYPH_ELLIPSIS)); + + buffer[k++] = (uint8_t) b; + } + assert(k == sz); + + free_and_replace(iov->iov_base, buffer); + iov->iov_len = sz; + return 0; +} + +int json_dispatch_in_addr(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { + struct in_addr *address = ASSERT_PTR(userdata); + _cleanup_(iovec_done) struct iovec iov = {}; + int r; + + r = json_dispatch_byte_array_iovec(name, variant, flags, &iov); + if (r < 0) + return r; + + if (iov.iov_len != sizeof(struct in_addr)) + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name)); + + memcpy(address, iov.iov_base, iov.iov_len); + return 0; +} + static int json_cmp_strings(const void *x, const void *y) { JsonVariant *const *a = x, *const *b = y; diff --git a/src/shared/json.h b/src/shared/json.h index a40e9496c2..3c20f94b58 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -425,6 +425,8 @@ int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDi int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_unbase64_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); +int json_dispatch_byte_array_iovec(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); +int json_dispatch_in_addr(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); assert_cc(sizeof(uint32_t) == sizeof(unsigned)); #define json_dispatch_uint json_dispatch_uint32 |