diff options
author | Thomas Haller <thaller@redhat.com> | 2018-10-19 12:21:18 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2018-10-23 10:36:07 +0200 |
commit | 410664967b81f2c735355f04dbe3f9260e2202b1 (patch) | |
tree | d96b9bd1060adc6e97f99f65d32c275ac527b548 /libnm-core | |
parent | 61717cc57553817ae5330e830195b64e42327098 (diff) |
keyfile: move keyfile utilities from src/ to libnm-core/
These utilities are concerned with valid file names (as NetworkManager
daemon requires it). This is relevant for everybody who wants to write
keyfile files directly. Hence, move it to libnm-core. Still as internal
API.
Diffstat (limited to 'libnm-core')
-rw-r--r-- | libnm-core/nm-keyfile-internal.h | 10 | ||||
-rw-r--r-- | libnm-core/nm-keyfile.c | 124 |
2 files changed, 134 insertions, 0 deletions
diff --git a/libnm-core/nm-keyfile-internal.h b/libnm-core/nm-keyfile-internal.h index 94228d951..a7c3cb09a 100644 --- a/libnm-core/nm-keyfile-internal.h +++ b/libnm-core/nm-keyfile-internal.h @@ -168,4 +168,14 @@ gboolean _nm_keyfile_a_contains_all_in_b (GKeyFile *kf_a, GKeyFile *kf_b); gboolean _nm_keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order); gboolean _nm_keyfile_has_values (GKeyFile *keyfile); +/*****************************************************************************/ + +#define NM_CONFIG_KEYFILE_PATH_IN_MEMORY NMRUNDIR "/system-connections" + +#define NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" + +gboolean nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension); + +char *nms_keyfile_utils_escape_filename (const char *filename, gboolean with_extension); + #endif /* __NM_KEYFILE_INTERNAL_H__ */ diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c index 77c1534d5..d81eb6872 100644 --- a/libnm-core/nm-keyfile.c +++ b/libnm-core/nm-keyfile.c @@ -3153,3 +3153,127 @@ nm_keyfile_write (NMConnection *connection, return info.keyfile; } + +/*****************************************************************************/ + +static const char temp_letters[] = +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* + * Check '.[a-zA-Z0-9]{6}' file suffix used for temporary files by g_file_set_contents() (mkstemp()). + */ +static gboolean +check_mkstemp_suffix (const char *path) +{ + const char *ptr; + + g_return_val_if_fail (path != NULL, FALSE); + + /* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */ + ptr = strrchr (path, '.'); + if (ptr && (strspn (ptr + 1, temp_letters) == 6) && (! ptr[7])) + return TRUE; + return FALSE; +} + +static gboolean +check_prefix_dot (const char *base) +{ + nm_assert (base && base[0]); + + return base[0] == '.'; +} + +static gboolean +check_suffix (const char *base, const char *tag) +{ + int len, tag_len; + + g_return_val_if_fail (base != NULL, TRUE); + g_return_val_if_fail (tag != NULL, TRUE); + + len = strlen (base); + tag_len = strlen (tag); + if ((len > tag_len) && !g_ascii_strcasecmp (base + len - tag_len, tag)) + return TRUE; + return FALSE; +} + +#define SWP_TAG ".swp" +#define SWPX_TAG ".swpx" +#define PEM_TAG ".pem" +#define DER_TAG ".der" + +gboolean +nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension) +{ + gs_free char *base = NULL; + + g_return_val_if_fail (filename != NULL, TRUE); + + base = g_path_get_basename (filename); + g_return_val_if_fail (base != NULL, TRUE); + + /* Ignore hidden and backup files */ + /* should_ignore_file() must mirror escape_filename() */ + if (check_prefix_dot (base) || check_suffix (base, "~")) + return TRUE; + /* Ignore temporary files */ + if (check_mkstemp_suffix (base)) + return TRUE; + /* Ignore 802.1x certificates and keys */ + if (check_suffix (base, PEM_TAG) || check_suffix (base, DER_TAG)) + return TRUE; + + if (require_extension) { + gsize l = strlen (base); + + if ( l <= NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION) + || !g_str_has_suffix (base, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)) + return TRUE; + } + + return FALSE; +} + +char * +nms_keyfile_utils_escape_filename (const char *filename, + gboolean with_extension) +{ + GString *str; + const char *f = filename; + /* keyfile used to escape with '*', do not change that behavior. + * + * But for newly added escapings, use '_' instead. + * Also, @with_extension is new-style. */ + const char ESCAPE_CHAR = with_extension ? '_' : '*'; + const char ESCAPE_CHAR2 = '_'; + + g_return_val_if_fail (filename && filename[0], NULL); + + str = g_string_sized_new (60); + + /* Convert '/' to ESCAPE_CHAR */ + for (f = filename; f[0]; f++) { + if (f[0] == '/') + g_string_append_c (str, ESCAPE_CHAR); + else + g_string_append_c (str, f[0]); + } + + /* escape_filename() must avoid anything that should_ignore_file() would reject. + * We can escape here more aggressivly then what we would read back. */ + if (check_prefix_dot (str->str)) + str->str[0] = ESCAPE_CHAR2; + if (check_suffix (str->str, "~")) + str->str[str->len - 1] = ESCAPE_CHAR2; + if ( check_mkstemp_suffix (str->str) + || check_suffix (str->str, PEM_TAG) + || check_suffix (str->str, DER_TAG)) + g_string_append_c (str, ESCAPE_CHAR2); + + if (with_extension) + g_string_append (str, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION); + + return g_string_free (str, FALSE);; +} |