all/systemd: merge branch 'th/replace-systemd-utils-1'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1191
This commit is contained in:
Thomas Haller 2022-04-20 12:15:34 +02:00
commit 4930cdd3c8
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
19 changed files with 1196 additions and 303 deletions

View file

@ -2329,8 +2329,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_libadd = \
src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/nm-default-systemd-core.h \
src/libnm-systemd-core/nm-sd-utils-core.c \
src/libnm-systemd-core/nm-sd-utils-core.h \
src/libnm-systemd-core/nm-sd.c \
src/libnm-systemd-core/nm-sd.h \
src/libnm-systemd-core/sd-adapt-core/condition.h \

View file

@ -30,7 +30,6 @@
#include "libnm-platform/nm-linux-platform.h"
#include "libnm-platform/nm-platform-utils.h"
#include "nm-auth-utils.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
/*****************************************************************************/
@ -1155,7 +1154,7 @@ nm_utils_file_is_in_path(const char *abs_filename, const char *abs_path)
g_return_val_if_fail(abs_filename && abs_filename[0] == '/', NULL);
g_return_val_if_fail(abs_path && abs_path[0] == '/', NULL);
path = nm_sd_utils_path_startswith(abs_filename, abs_path);
path = nm_path_startswith(abs_filename, abs_path);
if (!path)
return NULL;

View file

@ -1080,7 +1080,7 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src)
if (!config->send_hostname) {
nm_clear_g_free((gpointer *) &config->hostname);
} else if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname))
|| (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) {
|| (!config->use_fqdn && !nm_hostname_is_valid(config->hostname, FALSE))) {
nm_log_warn(LOGD_DHCP,
"dhcp%c: %s '%s' is invalid, will be ignored",
nm_utils_addr_family_to_char(config->addr_family),

View file

@ -26,7 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device.h"
@ -2104,7 +2103,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s
domain = hostname;
}
if (!nm_sd_hostname_is_valid(domain, FALSE))
if (!nm_hostname_is_valid(domain, FALSE))
domain = NULL;
}
}

View file

@ -30,7 +30,6 @@
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "nm-utils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-setting-connection.h"
@ -5239,7 +5238,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
nm_assert(hostname);
nm_assert(shortened);
if (nm_sd_hostname_is_valid(hostname, FALSE)) {
if (nm_hostname_is_valid(hostname, FALSE)) {
*shortened = NULL;
return TRUE;
}
@ -5253,7 +5252,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
s = g_strndup(hostname, l);
if (!nm_sd_hostname_is_valid(s, FALSE)) {
if (!nm_hostname_is_valid(s, FALSE)) {
*shortened = NULL;
return FALSE;
}

View file

@ -26,8 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-core-intern/nm-keyfile-internal.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "settings/nm-settings-plugin.h"
#include "settings/nm-settings-storage.h"
#include "settings/nm-settings-utils.h"
@ -1247,9 +1245,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
/* dirname_libs are a set of read-only directories with lower priority than /etc or /run.
* There is nothing complicated about having multiple of such directories, so dirname_libs
* is a list (which currently only has at most one directory). */
priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
priv->dirname_libs[0] = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
priv->dirname_libs[1] = NULL;
priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
priv->dirname_run = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
priv->dirname_etc = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG,
NM_CONFIG_KEYFILE_GROUP_KEYFILE,
NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH,
@ -1262,9 +1260,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
} else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') {
/* either invalid path or unspecified. Use the default. */
g_free(priv->dirname_etc);
priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
priv->dirname_etc = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
} else
nm_sd_utils_path_simplify(priv->dirname_etc);
nm_path_simplify(priv->dirname_etc);
/* no duplicates */
if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run))

View file

@ -15,7 +15,6 @@
#include "NetworkManagerUtils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-core-utils.h"
#include "libnm-systemd-core/nm-sd-utils-core.h"
#include "dns/nm-dns-manager.h"
#include "nm-connectivity.h"
@ -2314,7 +2313,6 @@ test_dns_create_resolv_conf(void)
static void
test_machine_id_read(void)
{
NMUuid machine_id_sd;
const NMUuid *machine_id;
char machine_id_str[33];
gpointer logstate;
@ -2346,27 +2344,6 @@ test_machine_id_read(void)
== machine_id_str);
g_assert(strlen(machine_id_str) == 32);
g_assert_cmpstr(machine_id_str, ==, nm_utils_machine_id_str());
/* double check with systemd's implementation... */
if (!nm_sd_utils_id128_get_machine(&machine_id_sd)) {
/* if systemd failed to read /etc/machine-id, the file likely
* is invalid. Our machine-id is fake, and we have nothing to
* compare against. */
if (g_file_test(LOCALSTATEDIR "/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) {
/* Hm. So systemd failed to read /etc/machine-id, but we may have the one from D-Bus.
* With LOCALSTATEDIR"/lib/dbus/machine-id", we don't really know whether we
* parsed that file. Assume we don't know and skip the test on this system. */
g_assert(!nm_utils_machine_id_is_fake());
return;
}
/* OK, in this case, our function should have generated a random machine ID. */
g_assert(nm_utils_machine_id_is_fake());
} else {
g_assert(!nm_utils_machine_id_is_fake());
g_assert_cmpmem(&machine_id_sd, sizeof(NMUuid), machine_id, 16);
}
}
/*****************************************************************************/

View file

@ -98,141 +98,6 @@ test_sd_event(void)
/*****************************************************************************/
static void
test_path_equal(void)
{
#define _path_equal_check(path, expected) \
G_STMT_START \
{ \
const char *_path0 = (path); \
const char *_expected = (expected); \
gs_free char *_path = g_strdup(_path0); \
const char *_path_result; \
\
_path_result = nm_sd_utils_path_simplify(_path); \
g_assert(_path_result == _path); \
g_assert_cmpstr(_path, ==, _expected); \
} \
G_STMT_END
_path_equal_check("", "");
_path_equal_check(".", ".");
_path_equal_check("..", "..");
_path_equal_check("/..", "/..");
_path_equal_check("//..", "/..");
_path_equal_check("/.", "/");
_path_equal_check("./", ".");
_path_equal_check("./.", ".");
_path_equal_check(".///.", ".");
_path_equal_check(".///./", ".");
_path_equal_check(".////", ".");
_path_equal_check("//..//foo/", "/../foo");
_path_equal_check("///foo//./bar/.", "/foo/bar");
_path_equal_check(".//./foo//./bar/.", "foo/bar");
}
/*****************************************************************************/
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;
nm_auto_free guint8 *exp2_arr = NULL;
nm_auto_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),
TRUE,
&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), TRUE, &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), TRUE, &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_uint32() % sizeof(rnd_buf);
for (i = 0; i < rnd_len; i++)
rnd_buf[i] = nmtst_get_rand_uint32() % 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_uint32() % 256;
if (ch != '=')
_test_unbase64char(ch, TRUE);
}
}
/*****************************************************************************/
NMTST_DEFINE();
int
@ -242,8 +107,6 @@ 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();
}

View file

@ -21,7 +21,6 @@
#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
#include "libnm-core-intern/nm-core-internal.h"
@ -4062,7 +4061,7 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info)
public_key = nm_wireguard_peer_get_public_key(peer);
if (!public_key || !public_key[0]
|| !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) {
|| !NM_STRCHAR_ALL(public_key, ch, nm_unbase64char(ch) != -EINVAL)) {
/* invalid peer. Skip it */
continue;
}

View file

@ -23,7 +23,6 @@
#include "libnm-glib-aux/nm-enum-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "nm-utils-private.h"
#include "nm-setting-private.h"
@ -5356,7 +5355,7 @@ nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, gui
base64_key_len = strlen(base64_key);
r = nm_sd_utils_unbase64mem(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
r = nm_unbase64mem_full(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
if (r < 0)
return FALSE;
if (bin_len != required_key_len) {

View file

@ -6714,3 +6714,540 @@ nm_g_main_context_can_acquire(GMainContext *context)
g_main_context_release(context);
return TRUE;
}
/*****************************************************************************/
int
nm_unbase64char(char c)
{
/* copied from systemd's unbase64char():
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L539 */
switch (c) {
case 'A' ... 'Z':
return c - 'A';
case 'a' ... 'z':
return (c - 'a') + ('Z' - 'A' + 1);
case '0' ... '9':
return (c - '0') + (('Z' - 'A' + 1) + ('z' - 'a' + 1));
case '+':
return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1);
case '/':
return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 1;
case '=':
/* The padding is a different kind of base64 character. Return
* a special error code for it. */
return -ERANGE;
default:
return -EINVAL;
}
}
static int
unbase64_next(const char **p, size_t *l)
{
int ret;
nm_assert(p);
nm_assert(l);
/* copied from systemd's unbase64_next():
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L709 */
/* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
* greedily skip all preceding and all following whitespace. */
for (;;) {
if (*l == 0)
return -EPIPE;
if (!nm_ascii_is_whitespace(**p))
break;
/* Skip leading whitespace */
(*p)++;
(*l)--;
}
ret = nm_unbase64char(**p);
if (ret < 0) {
nm_assert(NM_IN_SET(ret, -EINVAL, -ERANGE));
if (ret != -ERANGE)
return ret;
}
for (;;) {
(*p)++;
(*l)--;
if (*l == 0)
break;
if (!nm_ascii_is_whitespace(**p))
break;
/* Skip following whitespace */
}
nm_assert(ret == -ERANGE || ret >= 0);
return ret;
}
/**
* nm_unbase64mem_full:
* @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.
* @secure: whether the temporary memory will be cleared to avoid leaving
* secrets in memory (see also nm_explicit_bzero()).
* @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. Our own implementation (based on systemd code)
* rejects invalid inputs.
*
* Returns: a non-negative code on success. Invalid encoding let the
* function fail.
*/
int
nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size)
{
gs_free uint8_t *buf = NULL;
const char *x;
guint8 *z;
gsize len;
int r;
/* copied from systemd's unbase64mem_full():
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L751 */
nm_assert(p || l == 0);
if (l == G_MAXSIZE)
l = strlen(p);
/* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
* bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
buf = g_malloc(len + 1);
for (x = p, z = buf;;) {
int a; /* a == 00XXXXXX */
int b; /* b == 00YYYYYY */
int c; /* c == 00ZZZZZZ */
int d; /* d == 00WWWWWW */
a = unbase64_next(&x, &l);
if (a < 0) {
if (a == -EPIPE) /* End of string */
break;
if (a == -ERANGE) { /* Padding is not allowed at the beginning of a 4ch block */
r = -EINVAL;
goto on_failure;
}
r = a;
goto on_failure;
}
b = unbase64_next(&x, &l);
if (b < 0) {
if (b == -ERANGE) {
/* Padding is not allowed at the second character of a 4ch block either */
r = -EINVAL;
goto on_failure;
}
r = b;
goto on_failure;
}
c = unbase64_next(&x, &l);
if (c < 0) {
if (c != -ERANGE) {
r = c;
goto on_failure;
}
}
d = unbase64_next(&x, &l);
if (d < 0) {
if (d != -ERANGE) {
r = d;
goto on_failure;
}
}
if (c == -ERANGE) { /* Padding at the third character */
if (d != -ERANGE) { /* If the third character is padding, the fourth must be too */
r = -EINVAL;
goto on_failure;
}
/* b == 00YY0000 */
if (b & 15) {
r = -EINVAL;
goto on_failure;
}
if (l > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto on_failure;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
}
if (d == -ERANGE) {
/* c == 00ZZZZ00 */
if (c & 3) {
r = -EINVAL;
goto on_failure;
}
if (l > 0) { /* Trailing rubbish? */
r = -ENAMETOOLONG;
goto on_failure;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
break;
}
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
*(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
}
*z = '\0';
NM_SET_OUT(ret_size, (gsize) (z - buf));
NM_SET_OUT(ret, g_steal_pointer(&buf));
return 0;
on_failure:
if (secure)
nm_explicit_bzero(buf, len);
return r;
}
/*****************************************************************************/
static const char *
skip_slash_or_dot(const char *p)
{
for (; !nm_str_is_empty(p);) {
if (p[0] == '/') {
p += 1;
continue;
}
if (p[0] == '.' && p[1] == '/') {
p += 2;
continue;
}
break;
}
return p;
}
int
nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret)
{
const char *q, *first, *end_first, *next;
size_t len;
/* Copied from systemd's path_compare()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L809 */
nm_assert(p);
/* When a path is input, then returns the pointer to the first component and its length, and
* move the input pointer to the next component or nul. This skips both over any '/'
* immediately *before* and *after* the first component before returning.
*
* Examples
* Input: p: "//.//aaa///bbbbb/cc"
* Output: p: "bbbbb///cc"
* ret: "aaa///bbbbb/cc"
* return value: 3 (== strlen("aaa"))
*
* Input: p: "aaa//"
* Output: p: (pointer to NUL)
* ret: "aaa//"
* return value: 3 (== strlen("aaa"))
*
* Input: p: "/", ".", ""
* Output: p: (pointer to NUL)
* ret: NULL
* return value: 0
*
* Input: p: NULL
* Output: p: NULL
* ret: NULL
* return value: 0
*
* Input: p: "(too long component)"
* Output: return value: -EINVAL
*
* (when accept_dot_dot is false)
* Input: p: "//..//aaa///bbbbb/cc"
* Output: return value: -EINVAL
*/
q = *p;
first = skip_slash_or_dot(q);
if (nm_str_is_empty(first)) {
*p = first;
if (ret)
*ret = NULL;
return 0;
}
if (nm_streq(first, ".")) {
*p = first + 1;
if (ret)
*ret = NULL;
return 0;
}
end_first = strchrnul(first, '/');
len = end_first - first;
if (len > NAME_MAX)
return -EINVAL;
if (!accept_dot_dot && len == 2 && first[0] == '.' && first[1] == '.')
return -EINVAL;
next = skip_slash_or_dot(end_first);
*p = next + (nm_streq(next, ".") ? 1 : 0);
if (ret)
*ret = first;
return len;
}
int
nm_path_compare(const char *a, const char *b)
{
/* Copied from systemd's path_compare()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L415 */
/* Order NULL before non-NULL */
NM_CMP_SELF(a, b);
/* A relative path and an absolute path must not compare as equal.
* Which one is sorted before the other does not really matter.
* Here a relative path is ordered before an absolute path. */
NM_CMP_DIRECT(nm_path_is_absolute(a), nm_path_is_absolute(b));
for (;;) {
const char *aa, *bb;
int j, k;
j = nm_path_find_first_component(&a, TRUE, &aa);
k = nm_path_find_first_component(&b, TRUE, &bb);
if (j < 0 || k < 0) {
/* When one of paths is invalid, order invalid path after valid one. */
NM_CMP_DIRECT(j < 0, k < 0);
/* fallback to use strcmp() if both paths are invalid. */
NM_CMP_DIRECT_STRCMP(a, b);
return 0;
}
/* Order prefixes first: "/foo" before "/foo/bar" */
if (j == 0) {
if (k == 0)
return 0;
return -1;
}
if (k == 0)
return 1;
/* Alphabetical sort: "/foo/aaa" before "/foo/b" */
NM_CMP_DIRECT_MEMCMP(aa, bb, NM_MIN(j, k));
/* Sort "/foo/a" before "/foo/aaa" */
NM_CMP_DIRECT(j, k);
}
}
char *
nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot)
{
/* Copied from systemd's path_startswith_full()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L375 */
nm_assert(path);
nm_assert(prefix);
/* Returns a pointer to the start of the first component after the parts matched by
* the prefix, iff
* - both paths are absolute or both paths are relative,
* and
* - each component in prefix in turn matches a component in path at the same position.
* An empty string will be returned when the prefix and path are equivalent.
*
* Returns NULL otherwise.
*/
if ((path[0] == '/') != (prefix[0] == '/'))
return NULL;
for (;;) {
const char *p, *q;
int r, k;
r = nm_path_find_first_component(&path, accept_dot_dot, &p);
if (r < 0)
return NULL;
k = nm_path_find_first_component(&prefix, accept_dot_dot, &q);
if (k < 0)
return NULL;
if (k == 0)
return (char *) (p ?: path);
if (r != k)
return NULL;
if (strncmp(p, q, r) != 0)
return NULL;
}
}
char *
nm_path_simplify(char *path)
{
bool add_slash = false;
char *f = path;
int r;
/* Copied from systemd's path_simplify()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L325 */
nm_assert(path);
/* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
* Modifies the passed string in-place.
*
* ///foo//./bar/. becomes /foo/bar
* .//./foo//./bar/. becomes foo/bar
*/
if (path[0] == '\0')
return path;
if (nm_path_is_absolute(path))
f++;
for (const char *p = f;;) {
const char *e;
r = nm_path_find_first_component(&p, TRUE, &e);
if (r == 0)
break;
if (add_slash)
*f++ = '/';
if (r < 0) {
/* if path is invalid, then refuse to simplify remaining part. */
memmove(f, p, strlen(p) + 1);
return path;
}
memmove(f, e, r);
f += r;
add_slash = TRUE;
}
/* Special rule, if we stripped everything, we need a "." for the current directory. */
if (f == path)
*f++ = '.';
*f = '\0';
return path;
}
/*****************************************************************************/
static gboolean
valid_ldh_char(char c)
{
/* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-';
}
/**
* nm_hostname_is_valid:
* @s: the hostname to check.
* @trailing_dot: Accept trailing dot on multi-label names.
*
* Return: %TRUE if valid.
*/
gboolean
nm_hostname_is_valid(const char *s, gboolean trailing_dot)
{
unsigned n_dots = 0;
const char *p;
gboolean dot;
gboolean hyphen;
/* Copied from systemd's hostname_is_valid()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/hostname-util.c#L85 */
/* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
* checks if the name is composed of allowed characters and the length is not above the maximum
* allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
* VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
* that due to the restricted charset and length this call is substantially more conservative than
* dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
* with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
if (nm_str_is_empty(s))
return FALSE;
for (p = s, dot = hyphen = TRUE; *p; p++)
if (*p == '.') {
if (dot || hyphen)
return FALSE;
dot = TRUE;
hyphen = FALSE;
n_dots++;
} else if (*p == '-') {
if (dot)
return FALSE;
dot = FALSE;
hyphen = TRUE;
} else {
if (!valid_ldh_char(*p))
return FALSE;
dot = FALSE;
hyphen = FALSE;
}
if (dot && (n_dots < 2 || !trailing_dot))
return FALSE;
if (hyphen)
return FALSE;
/* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
* 255 characters */
if (p - s > HOST_NAME_MAX)
return FALSE;
return TRUE;
}

View file

@ -3308,4 +3308,46 @@ gboolean nm_utils_validate_hostname(const char *hostname);
void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify);
/*****************************************************************************/
int nm_unbase64char(char c);
int nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size);
/*****************************************************************************/
static inline gboolean
nm_path_is_absolute(const char *p)
{
/* Copied from systemd's path_is_absolute()
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.h#L50 */
nm_assert(p);
return p[0] == '/';
}
int nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret);
int nm_path_compare(const char *a, const char *b);
static inline gboolean
nm_path_equal(const char *a, const char *b)
{
return nm_path_compare(a, b) == 0;
}
char *nm_path_simplify(char *path);
char *
nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot) _nm_pure;
static inline char *
nm_path_startswith(const char *path, const char *prefix)
{
return nm_path_startswith_full(path, prefix, TRUE);
}
/*****************************************************************************/
gboolean nm_hostname_is_valid(const char *s, gboolean trailing_dot);
#endif /* __NM_SHARED_UTILS_H__ */

View file

@ -1556,6 +1556,600 @@ test_parse_env_file(void)
/*****************************************************************************/
static void
test_unbase64char(void)
{
static const int expected[128] = {
[0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1, [5] = -1, [6] = -1,
[7] = -1, [8] = -1, [9] = -1, [10] = -1, [11] = -1, [12] = -1, [13] = -1,
[14] = -1, [15] = -1, [16] = -1, [17] = -1, [18] = -1, [19] = -1, [20] = -1,
[21] = -1, [22] = -1, [23] = -1, [24] = -1, [25] = -1, [26] = -1, [27] = -1,
[28] = -1, [29] = -1, [30] = -1, [31] = -1, [32] = -1, [33] = -1, [34] = -1,
[35] = -1, [36] = -1, [37] = -1, [38] = -1, [39] = -1, [40] = -1, [41] = -1,
[42] = -1, ['+'] = 62, [44] = -1, [45] = -1, [46] = -1, ['/'] = 63, ['0'] = 52,
['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
['8'] = 60, ['9'] = 61, [58] = -1, [59] = -1, [60] = -1, [61] = -1, [62] = -1,
[63] = -1, [64] = -1, ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11,
['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18,
['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
[91] = -1, [92] = -1, [93] = -1, [94] = -1, [95] = -1, [96] = -1, ['a'] = 26,
['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40,
['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, [123] = -1, [124] = -1, [125] = -1,
[126] = -1, [127] = -1,
};
int i;
/* Copied from systemd's TEST(unbase64char)
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L44 */
g_assert_cmpint(nm_unbase64char('A'), ==, 0);
g_assert_cmpint(nm_unbase64char('Z'), ==, 25);
g_assert_cmpint(nm_unbase64char('a'), ==, 26);
g_assert_cmpint(nm_unbase64char('z'), ==, 51);
g_assert_cmpint(nm_unbase64char('0'), ==, 52);
g_assert_cmpint(nm_unbase64char('9'), ==, 61);
g_assert_cmpint(nm_unbase64char('+'), ==, 62);
g_assert_cmpint(nm_unbase64char('/'), ==, 63);
g_assert_cmpint(nm_unbase64char('='), ==, -ERANGE);
g_assert_cmpint(nm_unbase64char('\0'), ==, -EINVAL);
g_assert_cmpint(nm_unbase64char('\1'), ==, -EINVAL);
g_assert_cmpint(nm_unbase64char('\x7F'), ==, -EINVAL);
g_assert_cmpint(nm_unbase64char('\x80'), ==, -EINVAL);
g_assert_cmpint(nm_unbase64char('\xFF'), ==, -EINVAL);
for (i = 0; i < 256; i++) {
int base64;
base64 = nm_unbase64char((char) i);
if (base64 < 0) {
if (((char) i) == '=')
g_assert_cmpint(base64, ==, -ERANGE);
else
g_assert_cmpint(base64, ==, -EINVAL);
base64 = -1;
}
if (i >= G_N_ELEMENTS(expected)) {
g_assert_cmpint(base64, ==, -1);
continue;
}
g_assert_cmpint(base64, ==, expected[i]);
}
}
/*****************************************************************************/
static void
test_unbase64mem1(void)
{
nm_auto_str_buf NMStrBuf encoded_wrapped = NM_STR_BUF_INIT(400, FALSE);
uint8_t data[4096];
int i_run;
/* Copied from systemd's TEST(base64mem_linebreak)
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L280 */
for (i_run = 0; i_run < 20; i_run++) {
gs_free char *encoded = NULL;
gs_free guint8 *decoded = NULL;
gsize decoded_size;
guint64 n;
guint64 m;
guint64 i;
guint64 j;
gssize l;
int r;
/* Try a bunch of differently sized blobs */
n = nmtst_get_rand_uint64() % sizeof(data);
nmtst_rand_buf(NULL, data, n);
/* Break at various different columns */
m = 1 + (nmtst_get_rand_uint64() % (n + 5));
encoded = g_base64_encode(data, n);
g_assert(encoded);
l = strlen(encoded);
nm_str_buf_reset(&encoded_wrapped);
for (i = 0, j = 0; i < l; i++, j++) {
if (j == m) {
nm_str_buf_append_c(&encoded_wrapped, '\n');
j = 0;
}
nm_str_buf_append_c(&encoded_wrapped, encoded[i]);
}
g_assert_cmpint(strlen(nm_str_buf_get_str(&encoded_wrapped)), ==, encoded_wrapped.len);
r = nm_unbase64mem_full(nm_str_buf_get_str(&encoded_wrapped),
nmtst_get_rand_bool() ? SIZE_MAX : encoded_wrapped.len,
nmtst_get_rand_bool(),
&decoded,
&decoded_size);
g_assert_cmpint(r, >=, 0);
g_assert_cmpmem(data, n, decoded, decoded_size);
for (j = 0; j < encoded_wrapped.len; j++)
g_assert((nm_str_buf_get_str(&encoded_wrapped)[j] == '\n') == (j % (m + 1) == m));
}
}
/*****************************************************************************/
static void
_assert_unbase64mem(const char *input, const char *output, int ret)
{
gs_free guint8 *buffer = NULL;
gsize size = 0;
int r;
r = nm_unbase64mem_full(input, SIZE_MAX, nmtst_get_rand_bool(), &buffer, &size);
g_assert_cmpint(r, ==, ret);
if (ret >= 0) {
g_assert_cmpmem(buffer, size, output, strlen(output));
g_assert_cmpint(((const char *) buffer)[size], ==, '\0');
} else {
g_assert(!buffer);
g_assert_cmpint(size, ==, 0);
}
}
static void
test_unbase64mem2(void)
{
/* Copied from systemd's TEST(unbase64mem)
* https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L324 */
_assert_unbase64mem("", "", 0);
_assert_unbase64mem("Zg==", "f", 0);
_assert_unbase64mem("Zm8=", "fo", 0);
_assert_unbase64mem("Zm9v", "foo", 0);
_assert_unbase64mem("Zm9vYg==", "foob", 0);
_assert_unbase64mem("Zm9vYmE=", "fooba", 0);
_assert_unbase64mem("Zm9vYmFy", "foobar", 0);
_assert_unbase64mem(" ", "", 0);
_assert_unbase64mem(" \n\r ", "", 0);
_assert_unbase64mem(" Zg\n== ", "f", 0);
_assert_unbase64mem(" Zm 8=\r", "fo", 0);
_assert_unbase64mem(" Zm9\n\r\r\nv ", "foo", 0);
_assert_unbase64mem(" Z m9vYg==\n\r", "foob", 0);
_assert_unbase64mem(" Zm 9vYmE= ", "fooba", 0);
_assert_unbase64mem(" Z m9v YmFy ", "foobar", 0);
_assert_unbase64mem("A", NULL, -EPIPE);
_assert_unbase64mem("A====", NULL, -EINVAL);
_assert_unbase64mem("AAB==", NULL, -EINVAL);
_assert_unbase64mem(" A A A B = ", NULL, -EINVAL);
_assert_unbase64mem(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG);
}
/*****************************************************************************/
static void
_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len)
{
gs_free char *expected_base64 = NULL;
int r;
nm_auto_free guint8 *exp2_arr = NULL;
nm_auto_free guint8 *exp3_arr = NULL;
gsize exp2_len;
gsize exp3_len;
expected_base64 = g_base64_encode(expected_arr, expected_len);
r = nm_unbase64mem_full(expected_base64, strlen(expected_base64), TRUE, &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_unbase64mem_full(base64, strlen(base64), TRUE, &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_unbase64mem_full(base64, strlen(base64), TRUE, &exp_arr, &exp_len);
g_assert_cmpint(r, <, 0);
g_assert(!exp_arr);
g_assert(exp_len == 0);
}
static void
test_unbase64mem3(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_uint32() % sizeof(rnd_buf);
for (i = 0; i < rnd_len; i++)
rnd_buf[i] = nmtst_get_rand_uint32() % 256;
rnd_base64 = g_base64_encode(rnd_buf, rnd_len);
_test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len);
}
/*****************************************************************************/
static void
assert_path_compare(const char *a, const char *b, int expected)
{
int r;
g_assert(NM_IN_SET(expected, -1, 0, 1));
g_assert_cmpint(nm_path_compare(a, a), ==, 0);
g_assert_cmpint(nm_path_compare(b, b), ==, 0);
r = nm_path_compare(a, b);
g_assert_cmpint(r, ==, expected);
r = nm_path_compare(b, a);
g_assert_cmpint(r, ==, -expected);
g_assert(nm_path_equal(a, a) == 1);
g_assert(nm_path_equal(b, b) == 1);
g_assert(nm_path_equal(a, b) == (expected == 0));
g_assert(nm_path_equal(b, a) == (expected == 0));
}
static void
test_path_compare(void)
{
/* Copied from systemd.
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L126 */
assert_path_compare("/goo", "/goo", 0);
assert_path_compare("/goo", "/goo", 0);
assert_path_compare("//goo", "/goo", 0);
assert_path_compare("//goo/////", "/goo", 0);
assert_path_compare("goo/////", "goo", 0);
assert_path_compare("/goo/boo", "/goo//boo", 0);
assert_path_compare("//goo/boo", "/goo/boo//", 0);
assert_path_compare("//goo/././//./boo//././//", "/goo/boo//.", 0);
assert_path_compare("/.", "//.///", 0);
assert_path_compare("/x", "x/", 1);
assert_path_compare("x/", "/", -1);
assert_path_compare("/x/./y", "x/y", 1);
assert_path_compare("/x/./y", "/x/y", 0);
assert_path_compare("/x/./././y", "/x/y/././.", 0);
assert_path_compare("./x/./././y", "./x/y/././.", 0);
assert_path_compare(".", "./.", 0);
assert_path_compare(".", "././.", 0);
assert_path_compare("./..", ".", 1);
assert_path_compare("x/.y", "x/y", -1);
assert_path_compare("foo", "/foo", -1);
assert_path_compare("/foo", "/foo/bar", -1);
assert_path_compare("/foo/aaa", "/foo/b", -1);
assert_path_compare("/foo/aaa", "/foo/b/a", -1);
assert_path_compare("/foo/a", "/foo/aaa", -1);
assert_path_compare("/foo/a/b", "/foo/aaa", -1);
}
/*****************************************************************************/
static void
test_path_equal(void)
{
#define _path_equal_check(path, expected) \
G_STMT_START \
{ \
const char *_path0 = (path); \
const char *_expected = (expected); \
gs_free char *_path = g_strdup(_path0); \
const char *_path_result; \
\
_path_result = nm_path_simplify(_path); \
g_assert(_path_result == _path); \
g_assert_cmpstr(_path, ==, _expected); \
} \
G_STMT_END
_path_equal_check("", "");
_path_equal_check(".", ".");
_path_equal_check("..", "..");
_path_equal_check("/..", "/..");
_path_equal_check("//..", "/..");
_path_equal_check("/.", "/");
_path_equal_check("./", ".");
_path_equal_check("./.", ".");
_path_equal_check(".///.", ".");
_path_equal_check(".///./", ".");
_path_equal_check(".////", ".");
_path_equal_check("//..//foo/", "/../foo");
_path_equal_check("///foo//./bar/.", "/foo/bar");
_path_equal_check(".//./foo//./bar/.", "foo/bar");
}
/*****************************************************************************/
static void
assert_path_find_first_component(const char *path,
gboolean accept_dot_dot,
const char *const *expected,
int ret)
{
const char *p;
for (p = path;;) {
const char *e;
int r;
r = nm_path_find_first_component(&p, accept_dot_dot, &e);
if (r <= 0) {
if (r == 0) {
if (path)
g_assert(p == path + strlen(path));
else
g_assert(!p);
g_assert(!e);
}
g_assert(r == ret);
g_assert(!expected || !*expected);
return;
}
g_assert(e);
g_assert(strcspn(e, "/") == (size_t) r);
g_assert(strlen(*expected) == (size_t) r);
g_assert(strncmp(e, *expected++, r) == 0);
}
}
static void
test_path_find_first_component(void)
{
gs_free char *hoge = NULL;
char foo[NAME_MAX * 2];
/* Copied from systemd.
* https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L631 */
assert_path_find_first_component(NULL, false, NULL, 0);
assert_path_find_first_component("", false, NULL, 0);
assert_path_find_first_component("/", false, NULL, 0);
assert_path_find_first_component(".", false, NULL, 0);
assert_path_find_first_component("./", false, NULL, 0);
assert_path_find_first_component("./.", false, NULL, 0);
assert_path_find_first_component("..", false, NULL, -EINVAL);
assert_path_find_first_component("/..", false, NULL, -EINVAL);
assert_path_find_first_component("./..", false, NULL, -EINVAL);
assert_path_find_first_component("////./././//.", false, NULL, 0);
assert_path_find_first_component("a/b/c", false, NM_MAKE_STRV("a", "b", "c"), 0);
assert_path_find_first_component("././//.///aa/bbb//./ccc",
false,
NM_MAKE_STRV("aa", "bbb", "ccc"),
0);
assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.",
false,
NM_MAKE_STRV("aa", "..."),
-EINVAL);
assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
false,
NM_MAKE_STRV("aaa", ".bbb"),
-EINVAL);
assert_path_find_first_component("a/foo./b", false, NM_MAKE_STRV("a", "foo.", "b"), 0);
assert_path_find_first_component(NULL, true, NULL, 0);
assert_path_find_first_component("", true, NULL, 0);
assert_path_find_first_component("/", true, NULL, 0);
assert_path_find_first_component(".", true, NULL, 0);
assert_path_find_first_component("./", true, NULL, 0);
assert_path_find_first_component("./.", true, NULL, 0);
assert_path_find_first_component("..", true, NM_MAKE_STRV(".."), 0);
assert_path_find_first_component("/..", true, NM_MAKE_STRV(".."), 0);
assert_path_find_first_component("./..", true, NM_MAKE_STRV(".."), 0);
assert_path_find_first_component("////./././//.", true, NULL, 0);
assert_path_find_first_component("a/b/c", true, NM_MAKE_STRV("a", "b", "c"), 0);
assert_path_find_first_component("././//.///aa/bbb//./ccc",
true,
NM_MAKE_STRV("aa", "bbb", "ccc"),
0);
assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.",
true,
NM_MAKE_STRV("aa", "...", "..", "bbb", "ccc"),
0);
assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
true,
NM_MAKE_STRV("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"),
0);
assert_path_find_first_component("a/foo./b", true, NM_MAKE_STRV("a", "foo.", "b"), 0);
memset(foo, 'a', sizeof(foo) - 1);
foo[sizeof(foo) - 1] = '\0';
assert_path_find_first_component(foo, false, NULL, -EINVAL);
assert_path_find_first_component(foo, true, NULL, -EINVAL);
hoge = g_strjoin("", "a/b/c/", foo, "//d/e/.//f/", NULL);
g_assert(hoge);
assert_path_find_first_component(hoge, false, NM_MAKE_STRV("a", "b", "c"), -EINVAL);
assert_path_find_first_component(hoge, true, NM_MAKE_STRV("a", "b", "c"), -EINVAL);
}
/*****************************************************************************/
static void
assert_path_startswith(const char *path,
const char *prefix,
const char *skipped,
const char *expected)
{
const char *p;
p = nm_path_startswith(path, prefix);
g_assert_cmpstr(p, ==, expected);
if (p) {
gs_free char *q = NULL;
g_assert(skipped);
q = g_strjoin("", skipped, p, NULL);
g_assert_cmpstr(q, ==, path);
g_assert(p == path + strlen(skipped));
} else
g_assert(!skipped);
}
static void
test_path_startswith(void)
{
assert_path_startswith("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/");
assert_path_startswith("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/");
assert_path_startswith("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/");
assert_path_startswith("/foo/bar/barfoo/", "////", "/", "foo/bar/barfoo/");
assert_path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/bar/foo", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL);
assert_path_startswith("/foo/bar/barfoo/", "/fo", NULL, NULL);
}
/*****************************************************************************/
static void
assert_path_simplify(const char *in, const char *out)
{
gs_free char *p = NULL;
g_assert(in);
p = g_strdup(in);
nm_path_simplify(p);
g_assert_cmpstr(p, ==, out);
}
static void
test_path_simplify(void)
{
gs_free char *hoge = NULL;
gs_free char *hoge_out = NULL;
char foo[NAME_MAX * 2];
assert_path_simplify("", "");
assert_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc");
assert_path_simplify("//aaa/.////ccc", "/aaa/ccc");
assert_path_simplify("///", "/");
assert_path_simplify("///.//", "/");
assert_path_simplify("///.//.///", "/");
assert_path_simplify("////.././///../.", "/../..");
assert_path_simplify(".", ".");
assert_path_simplify("./", ".");
assert_path_simplify(".///.//./.", ".");
assert_path_simplify(".///.//././/", ".");
assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
"/aaa/.bbb/../c./d.dd/..eeee");
assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
"/aaa/.bbb/../c./d.dd/..eeee/..");
assert_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
"aaa/.bbb/../c./d.dd/..eeee/..");
assert_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
"../aaa/.bbb/../c./d.dd/..eeee/..");
memset(foo, 'a', sizeof(foo) - 1);
foo[sizeof(foo) - 1] = '\0';
assert_path_simplify(foo, foo);
hoge = g_strjoin("", "/", foo, NULL);
g_assert(hoge);
assert_path_simplify(hoge, hoge);
nm_clear_g_free(&hoge);
hoge =
g_strjoin("", "a////.//././//./b///././/./c/////././//./", foo, "//.//////d/e/.//f/", NULL);
g_assert(hoge);
hoge_out = g_strjoin("", "a/b/c/", foo, "//.//////d/e/.//f/", NULL);
g_assert(hoge_out);
assert_path_simplify(hoge, hoge_out);
}
/*****************************************************************************/
static void
test_hostname_is_valid(void)
{
g_assert(nm_hostname_is_valid("foobar", FALSE));
g_assert(nm_hostname_is_valid("foobar.com", FALSE));
g_assert(!nm_hostname_is_valid("foobar.com.", FALSE));
g_assert(nm_hostname_is_valid("fooBAR", FALSE));
g_assert(nm_hostname_is_valid("fooBAR.com", FALSE));
g_assert(!nm_hostname_is_valid("fooBAR.", FALSE));
g_assert(!nm_hostname_is_valid("fooBAR.com.", FALSE));
g_assert(!nm_hostname_is_valid("fööbar", FALSE));
g_assert(!nm_hostname_is_valid("", FALSE));
g_assert(!nm_hostname_is_valid(".", FALSE));
g_assert(!nm_hostname_is_valid("..", FALSE));
g_assert(!nm_hostname_is_valid("foobar.", FALSE));
g_assert(!nm_hostname_is_valid(".foobar", FALSE));
g_assert(!nm_hostname_is_valid("foo..bar", FALSE));
g_assert(!nm_hostname_is_valid("foo.bar..", FALSE));
g_assert(
!nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
FALSE));
g_assert(!nm_hostname_is_valid(
"au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local",
FALSE));
g_assert(nm_hostname_is_valid("foobar", TRUE));
g_assert(nm_hostname_is_valid("foobar.com", TRUE));
g_assert(nm_hostname_is_valid("foobar.com.", TRUE));
g_assert(nm_hostname_is_valid("fooBAR", TRUE));
g_assert(nm_hostname_is_valid("fooBAR.com", TRUE));
g_assert(!nm_hostname_is_valid("fooBAR.", TRUE));
g_assert(nm_hostname_is_valid("fooBAR.com.", TRUE));
g_assert(!nm_hostname_is_valid("fööbar", TRUE));
g_assert(!nm_hostname_is_valid("", TRUE));
g_assert(!nm_hostname_is_valid(".", TRUE));
g_assert(!nm_hostname_is_valid("..", TRUE));
g_assert(!nm_hostname_is_valid("foobar.", TRUE));
g_assert(!nm_hostname_is_valid(".foobar", TRUE));
g_assert(!nm_hostname_is_valid("foo..bar", TRUE));
g_assert(!nm_hostname_is_valid("foo.bar..", TRUE));
g_assert(
!nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
TRUE));
}
/*****************************************************************************/
NMTST_DEFINE();
int
@ -1590,6 +2184,16 @@ main(int argc, char **argv)
g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel);
g_test_add_func("/general/test_nm_ascii", test_nm_ascii);
g_test_add_func("/general/test_parse_env_file", test_parse_env_file);
g_test_add_func("/general/test_unbase64char", test_unbase64char);
g_test_add_func("/general/test_unbase64mem1", test_unbase64mem1);
g_test_add_func("/general/test_unbase64mem2", test_unbase64mem2);
g_test_add_func("/general/test_unbase64mem3", test_unbase64mem3);
g_test_add_func("/general/test_path_compare", test_path_compare);
g_test_add_func("/general/test_path_equal", test_path_equal);
g_test_add_func("/general/test_path_find_first_component", test_path_find_first_component);
g_test_add_func("/general/test_path_startswith", test_path_startswith);
g_test_add_func("/general/test_path_simplify", test_path_simplify);
g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid);
return g_test_run();
}

View file

@ -18,7 +18,6 @@ libnm_systemd_core = static_library(
'src/libsystemd/sd-id128/id128-util.c',
'src/libsystemd/sd-id128/sd-id128.c',
'nm-sd.c',
'nm-sd-utils-core.c',
'sd-adapt-core/nm-sd-adapt-core.c',
),
include_directories: [

View file

@ -1,27 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2018 Red Hat, Inc.
*/
#include "libnm-systemd-core/nm-default-systemd-core.h"
#include "nm-sd-utils-core.h"
#include "libnm-glib-aux/nm-uuid.h"
#include "nm-sd-adapt-core.h"
#include "sd-id128.h"
/*****************************************************************************/
NMUuid *
nm_sd_utils_id128_get_machine(NMUuid *out_uuid)
{
g_assert(out_uuid);
G_STATIC_ASSERT_EXPR(sizeof(*out_uuid) == sizeof(sd_id128_t));
if (sd_id128_get_machine((sd_id128_t *) out_uuid) < 0)
return NULL;
return out_uuid;
}

View file

@ -1,17 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2018 Red Hat, Inc.
*/
#ifndef __NM_SD_UTILS_CORE_H__
#define __NM_SD_UTILS_CORE_H__
/*****************************************************************************/
struct _NMUuid;
struct _NMUuid *nm_sd_utils_id128_get_machine(struct _NMUuid *out_uuid);
/*****************************************************************************/
#endif /* __NM_SD_UTILS_CORE_H__ */

View file

@ -21,58 +21,6 @@ const bool mempool_use_allowed = true;
/*****************************************************************************/
gboolean
nm_sd_utils_path_equal(const char *a, const char *b)
{
return path_equal(a, b);
}
char *
nm_sd_utils_path_simplify(char *path)
{
return path_simplify(path);
}
const char *
nm_sd_utils_path_startswith(const char *path, const char *prefix)
{
return path_startswith(path, prefix);
}
/*****************************************************************************/
int
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.
* @secure: whether the temporary memory will be cleared to avoid leaving
* secrets in memory (see also nm_explicit_bzero()).
* @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, gboolean secure, guint8 **mem, size_t *len)
{
return unbase64mem_full(p, l, secure, (void **) mem, len);
}
int
nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical)
{
@ -85,14 +33,6 @@ nm_sd_dns_name_is_valid(const char *s)
return dns_name_is_valid(s);
}
gboolean
nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot)
{
return hostname_is_valid(s,
allow_trailing_dot ? VALID_HOSTNAME_TRAILING_DOT
: (ValidHostnameFlags) 0);
}
char *
nm_sd_dns_name_normalize(const char *s)
{

View file

@ -8,25 +8,10 @@
/*****************************************************************************/
gboolean nm_sd_utils_path_equal(const char *a, const char *b);
char *nm_sd_utils_path_simplify(char *path);
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, gboolean secure, guint8 **mem, size_t *len);
/*****************************************************************************/
int
nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical);
int nm_sd_dns_name_is_valid(const char *s);
gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
int nm_sd_dns_name_is_valid(const char *s);
char *nm_sd_dns_name_normalize(const char *s);

View file

@ -12,7 +12,6 @@
#include "libnm-log-core/nm-logging.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-initrd-generator.h"
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
/*****************************************************************************/
@ -586,7 +585,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
}
}
if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE))
if (client_hostname && !nm_hostname_is_valid(client_hostname, FALSE))
client_hostname = NULL;
if (client_hostname) {