diff --git a/shared/systemd/nm-sd-utils-shared.c b/shared/systemd/nm-sd-utils-shared.c index 6c71702502..0e89fbb7d1 100644 --- a/shared/systemd/nm-sd-utils-shared.c +++ b/shared/systemd/nm-sd-utils-shared.c @@ -23,6 +23,7 @@ #include "nm-sd-adapt-shared.h" #include "path-util.h" +#include "hexdecoct.h" /*****************************************************************************/ @@ -43,3 +44,39 @@ nm_sd_utils_path_startswith (const char *path, const char *prefix) { return path_startswith (path, prefix); } + +/*****************************************************************************/ + +gboolean +nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal) +{ + if ( ch == '=' + && accept_padding_equal) + return G_MAXINT; + return unbase64char (ch); +} + +/** + * nm_sd_utils_unbase64mem: + * @p: a valid base64 string. Whitespace is ignored, but invalid encodings + * will cause the function to fail. + * @l: the length of @p. @p is not treated as NUL terminated string but + * merely as a buffer of ascii characters. + * @mem: (transfer full): the decoded buffer on success. + * @len: the length of @mem on success. + * + * glib provides g_base64_decode(), but that does not report any errors + * from invalid encodings. Expose systemd's implementation which does + * reject invalid inputs. + * + * Returns: a non-negative code on success. Invalid encoding let the + * function fail. + */ +int +nm_sd_utils_unbase64mem (const char *p, + size_t l, + guint8 **mem, + size_t *len) +{ + return unbase64mem (p, l, (void **) mem, len); +} diff --git a/shared/systemd/nm-sd-utils-shared.h b/shared/systemd/nm-sd-utils-shared.h index 3103b3c7c4..eddf0c285a 100644 --- a/shared/systemd/nm-sd-utils-shared.h +++ b/shared/systemd/nm-sd-utils-shared.h @@ -29,4 +29,10 @@ const char *nm_sd_utils_path_startswith (const char *path, const char *prefix); /*****************************************************************************/ +int nm_sd_utils_unbase64char (char ch, gboolean accept_padding_equal); + +int nm_sd_utils_unbase64mem (const char *p, size_t l, guint8 **mem, size_t *len); + +/*****************************************************************************/ + #endif /* __NM_SD_UTILS_SHARED_H__ */ diff --git a/shared/systemd/src/basic/hexdecoct.c b/shared/systemd/src/basic/hexdecoct.c index 6a9869bcc4..ffd9a8f60f 100644 --- a/shared/systemd/src/basic/hexdecoct.c +++ b/shared/systemd/src/basic/hexdecoct.c @@ -515,6 +515,7 @@ char base64char(int x) { "0123456789+/"; return table[x & 63]; } +#endif /* NM_IGNORED */ int unbase64char(char c) { unsigned offset; @@ -545,6 +546,7 @@ int unbase64char(char c) { return -EINVAL; } +#if 0 /* NM_IGNORED */ ssize_t base64mem(const void *p, size_t l, char **out) { char *r, *z; const uint8_t *x; @@ -644,6 +646,7 @@ int base64_append( /* leave plen on the left, keep last column free */ return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1); } +#endif /* NM_IGNORED */ static int unbase64_next(const char **p, size_t *l) { int ret; @@ -775,6 +778,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { return 0; } +#if 0 /* NM_IGNORED */ void hexdump(FILE *f, const void *p, size_t s) { const uint8_t *b = p; unsigned n = 0; diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index 2d018517c5..05e2277665 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -225,6 +225,101 @@ test_path_equal (void) /*****************************************************************************/ +static void +_test_unbase64char (char ch, gboolean maybe_invalid) +{ + int r; + + r = nm_sd_utils_unbase64char (ch, FALSE); + + if (ch == '=') { + g_assert (!maybe_invalid); + g_assert_cmpint (r, <, 0); + g_assert_cmpint (nm_sd_utils_unbase64char (ch, TRUE), ==, G_MAXINT); + } else { + g_assert_cmpint (r, ==, nm_sd_utils_unbase64char (ch, TRUE)); + if (r >= 0) + g_assert_cmpint (r, <=, 255); + if (!maybe_invalid) + g_assert_cmpint (r, >=, 0); + } +} + +static void +_test_unbase64mem_mem (const char *base64, const guint8 *expected_arr, gsize expected_len) +{ + gs_free char *expected_base64 = NULL; + int r; + gs_free guint8 *exp2_arr = NULL; + gs_free guint8 *exp3_arr = NULL; + gsize exp2_len; + gsize exp3_len; + gsize i; + + expected_base64 = g_base64_encode (expected_arr, expected_len); + + for (i = 0; expected_base64[i]; i++) + _test_unbase64char (expected_base64[i], FALSE); + + r = nm_sd_utils_unbase64mem (expected_base64, strlen (expected_base64), &exp2_arr, &exp2_len); + g_assert_cmpint (r, ==, 0); + g_assert_cmpmem (expected_arr, expected_len, exp2_arr, exp2_len); + + if (!nm_streq (base64, expected_base64)) { + r = nm_sd_utils_unbase64mem (base64, strlen (base64), &exp3_arr, &exp3_len); + g_assert_cmpint (r, ==, 0); + g_assert_cmpmem (expected_arr, expected_len, exp3_arr, exp3_len); + } +} + +#define _test_unbase64mem(base64, expected_str) _test_unbase64mem_mem (base64, (const guint8 *) ""expected_str"", NM_STRLEN (expected_str)) + +static void +_test_unbase64mem_inval (const char *base64) +{ + gs_free guint8 *exp_arr = NULL; + gsize exp_len = 0; + int r; + + r = nm_sd_utils_unbase64mem (base64, strlen (base64), &exp_arr, &exp_len); + g_assert_cmpint (r, <, 0); + g_assert (!exp_arr); + g_assert (exp_len == 0); +} + +static void +test_nm_sd_utils_unbase64mem (void) +{ + gs_free char *rnd_base64 = NULL; + guint8 rnd_buf[30]; + guint i, rnd_len; + + _test_unbase64mem ("", ""); + _test_unbase64mem (" ", ""); + _test_unbase64mem (" Y Q == ", "a"); + _test_unbase64mem (" Y WJjZGV mZ 2g = ", "abcdefgh"); + _test_unbase64mem_inval (" Y %WJjZGV mZ 2g = "); + _test_unbase64mem_inval (" Y %WJjZGV mZ 2g = a"); + _test_unbase64mem ("YQ==", "a"); + _test_unbase64mem_inval ("YQ==a"); + + rnd_len = nmtst_get_rand_int () % sizeof (rnd_buf); + for (i = 0; i < rnd_len; i++) + rnd_buf[i] = nmtst_get_rand_int () % 256; + rnd_base64 = g_base64_encode (rnd_buf, rnd_len); + _test_unbase64mem_mem (rnd_base64, rnd_buf, rnd_len); + + _test_unbase64char ('=', FALSE); + for (i = 0; i < 10; i++) { + char ch = nmtst_get_rand_int () % 256; + + if (ch != '=') + _test_unbase64char (ch, TRUE); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -236,6 +331,7 @@ main (int argc, char **argv) g_test_add_func ("/systemd/lldp/create", test_lldp_create); g_test_add_func ("/systemd/sd-event", test_sd_event); g_test_add_func ("/systemd/test_path_equal", test_path_equal); + g_test_add_func ("/systemd/test_nm_sd_utils_unbase64mem", test_nm_sd_utils_unbase64mem); return g_test_run (); }