diff --git a/src/libsystemd-network/dhcp-client-id-internal.h b/src/libsystemd-network/dhcp-client-id-internal.h index 72f13de24e8..655f17b2e95 100644 --- a/src/libsystemd-network/dhcp-client-id-internal.h +++ b/src/libsystemd-network/dhcp-client-id-internal.h @@ -4,6 +4,7 @@ #include "sd-dhcp-client-id.h" #include "dhcp-duid-internal.h" +#include "json.h" #include "macro.h" #include "siphash24.h" #include "sparse-endian.h" @@ -55,3 +56,5 @@ static inline bool client_id_data_size_is_valid(size_t size) { void client_id_hash_func(const sd_dhcp_client_id *client_id, struct siphash *state); int client_id_compare_func(const sd_dhcp_client_id *a, const sd_dhcp_client_id *b); + +int json_dispatch_client_id(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); diff --git a/src/libsystemd-network/sd-dhcp-client-id.c b/src/libsystemd-network/sd-dhcp-client-id.c index da5fcaa450b..cab04f05e5f 100644 --- a/src/libsystemd-network/sd-dhcp-client-id.c +++ b/src/libsystemd-network/sd-dhcp-client-id.c @@ -2,6 +2,7 @@ #include "alloc-util.h" #include "dhcp-client-id-internal.h" +#include "iovec-util.h" #include "unaligned.h" #include "utf8.h" @@ -51,7 +52,9 @@ int sd_dhcp_client_id_set( assert_return(client_id, -EINVAL); assert_return(data, -EINVAL); - assert_return(client_id_data_size_is_valid(data_size), -EINVAL); + + if (!client_id_data_size_is_valid(data_size)) + return -EINVAL; client_id->id.type = type; memcpy(client_id->id.data, data, data_size); @@ -67,10 +70,12 @@ int sd_dhcp_client_id_set_raw( assert_return(client_id, -EINVAL); assert_return(data, -EINVAL); - assert_return(client_id_size_is_valid(data_size), -EINVAL); /* Unlike sd_dhcp_client_id_set(), this takes whole client ID including its type. */ + if (!client_id_size_is_valid(data_size)) + return -EINVAL; + memcpy(client_id->raw, data, data_size); client_id->size = data_size; @@ -150,7 +155,6 @@ int sd_dhcp_client_id_to_string_from_raw(const void *data, size_t data_size, cha int r; assert_return(data, -EINVAL); - assert_return(client_id_size_is_valid(data_size), -EINVAL); assert_return(ret, -EINVAL); r = sd_dhcp_client_id_set_raw(&client_id, data, data_size); @@ -174,3 +178,19 @@ int client_id_compare_func(const sd_dhcp_client_id *a, const sd_dhcp_client_id * return memcmp_nn(a->raw, a->size, b->raw, b->size); } + +int json_dispatch_client_id(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { + sd_dhcp_client_id *client_id = 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; + + r = sd_dhcp_client_id_set_raw(client_id, iov.iov_base, iov.iov_len); + if (r < 0) + return json_log(variant, flags, r, "Failed to set DHCP client ID from JSON field '%s': %m", strna(name)); + + return 0; +} diff --git a/src/libsystemd-network/sd-dhcp-duid.c b/src/libsystemd-network/sd-dhcp-duid.c index 297deb8a5d6..4782ec62d7a 100644 --- a/src/libsystemd-network/sd-dhcp-duid.c +++ b/src/libsystemd-network/sd-dhcp-duid.c @@ -71,7 +71,9 @@ int sd_dhcp_duid_set( assert_return(duid, -EINVAL); assert_return(data, -EINVAL); - assert_return(duid_data_size_is_valid(data_size), -EINVAL); + + if (!duid_data_size_is_valid(data_size)) + return -EINVAL; unaligned_write_be16(&duid->duid.type, duid_type); memcpy(duid->duid.data, data, data_size); @@ -87,10 +89,12 @@ int sd_dhcp_duid_set_raw( assert_return(duid, -EINVAL); assert_return(data, -EINVAL); - assert_return(duid_size_is_valid(data_size), -EINVAL); /* Unlike sd_dhcp_duid_set(), this takes whole DUID including its type. */ + if (!duid_size_is_valid(data_size)) + return -EINVAL; + memcpy(duid->raw, data, data_size); duid->size = data_size; @@ -209,9 +213,11 @@ int dhcp_duid_to_string_internal(uint16_t type, const void *data, size_t data_si const char *t; assert(data); - assert(duid_data_size_is_valid(data_size)); assert(ret); + if (!duid_data_size_is_valid(data_size)) + return -EINVAL; + x = hexmem(data, data_size); if (!x) return -ENOMEM; diff --git a/src/shared/json.c b/src/shared/json.c index 073bf31acde..47cd78b3965 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 a40e9496c2d..3c20f94b587 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