keyfile: merge branch 'th/keyfile-parsing-bgo776484'

https://bugzilla.gnome.org/show_bug.cgi?id=776484
This commit is contained in:
Thomas Haller
2017-01-05 12:30:12 +01:00
11 changed files with 333 additions and 216 deletions

View File

@@ -1683,6 +1683,7 @@ EXTRA_DIST += \
src/settings/plugins/keyfile/tests/keyfiles/Test_Missing_ID_UUID \
src/settings/plugins/keyfile/tests/keyfiles/Test_Enum_Property \
src/settings/plugins/keyfile/tests/keyfiles/Test_Flags_Property \
src/settings/plugins/keyfile/tests/keyfiles/Test_dcb_connection \
\
src/settings/plugins/keyfile/tests/keyfiles/test-ca-cert.pem \
src/settings/plugins/keyfile/tests/keyfiles/test-key-and-cert.pem

View File

@@ -108,19 +108,24 @@ read_array_of_uint (GKeyFile *file,
NMSetting *setting,
const char *key)
{
GArray *array = NULL;
gs_unref_array GArray *array = NULL;
gsize length;
int i;
gint *tmp;
gsize i;
gs_free int *tmp = NULL;
tmp = nm_keyfile_plugin_kf_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
array = g_array_sized_new (FALSE, FALSE, sizeof (guint32), length);
if (length > G_MAXUINT)
return;
for (i = 0; i < length; i++)
array = g_array_sized_new (FALSE, FALSE, sizeof (guint), length);
for (i = 0; i < length; i++) {
if (tmp[i] < 0)
return;
g_array_append_val (array, tmp[i]);
}
g_object_set (setting, key, array, NULL);
g_array_unref (array);
}
static gboolean
@@ -706,19 +711,18 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
g_strfreev (keys);
}
static void
static gsize
unescape_semicolons (char *str)
{
int i;
gsize len = strlen (str);
gsize i, j;
for (i = 0; i < len; i++) {
if (str[i] == '\\' && str[i+1] == ';') {
memmove(str + i, str + i + 1, len - (i + 1));
len--;
}
str[len] = '\0';
for (i = 0, j = 0; str[i]; ) {
if (str[i] == '\\' && str[i+1] == ';')
i++;
str[j++] = str[i++];;
}
str[j] = '\0';
return j;
}
static GBytes *
@@ -728,77 +732,121 @@ get_bytes (KeyfileReaderInfo *info,
gboolean zero_terminate,
gboolean unescape_semicolon)
{
GByteArray *array = NULL;
char *tmp_string;
gint *tmp_list;
gs_free char *tmp_string = NULL;
gboolean may_be_int_list = TRUE;
gsize length;
int i;
if (!nm_keyfile_plugin_kf_has_key (info->keyfile, setting_name, key, NULL))
return NULL;
/* New format: just a string
* Old format: integer list; e.g. 11;25;38;
*/
tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
if (tmp_string) {
GRegex *regex;
GMatchInfo *match_info;
const char *pattern = "^[[:space:]]*[[:digit:]]{1,3}[[:space:]]*;([[:space:]]*[[:digit:]]{1,3}[[:space:]]*;)*([[:space:]]*)?$";
regex = g_regex_new (pattern, 0, 0, NULL);
g_regex_match (regex, tmp_string, 0, &match_info);
if (!g_match_info_matches (match_info)) {
/* Handle as a simple string (ie, new format) */
if (unescape_semicolon)
unescape_semicolons (tmp_string);
length = strlen (tmp_string);
if (zero_terminate)
length++;
array = g_byte_array_sized_new (length);
g_byte_array_append (array, (guint8 *) tmp_string, length);
}
g_match_info_free (match_info);
g_regex_unref (regex);
g_free (tmp_string);
}
if (!array) {
gboolean already_warned = FALSE;
/* Old format; list of ints */
tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
if (!tmp_list) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid binary property"));
return NULL;
}
array = g_byte_array_sized_new (length);
for (i = 0; i < length; i++) {
int val = tmp_list[i];
unsigned char v = (unsigned char) (val & 0xFF);
if (val < 0 || val > 255) {
if ( !already_warned
&& !handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
val)) {
g_free (tmp_list);
g_byte_array_free (array, TRUE);
return NULL;
}
already_warned = TRUE;
} else
g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
}
g_free (tmp_list);
}
if (array->len == 0) {
g_byte_array_free (array, TRUE);
if (!tmp_string)
return NULL;
} else
return g_byte_array_free_to_bytes (array);
/* if the string is empty, we return an empty GBytes array.
* Note that for NM_SETTING_802_1X_PASSWORD_RAW both %NULL and
* an empty GBytes are valid, and shall be destinguished. */
if (!tmp_string[0]) {
/* note that even if @zero_terminate is TRUE, we return an empty
* byte-array. The reason is that zero_terminate is there to terminate
* *valid* strings. It's not there to terminated invalid (empty) strings.
*/
return g_bytes_new_take (tmp_string, 0);
}
for (length = 0; tmp_string[length]; length++) {
const char ch = tmp_string[length];
if ( !g_ascii_isspace (ch)
&& !g_ascii_isdigit (ch)
&& ch != ';') {
may_be_int_list = FALSE;
length += strlen (&tmp_string[length]);
break;
}
}
/* Try to parse the string as a integer list. */
if (may_be_int_list && length > 0) {
gs_free guint8 *bin_data = NULL;
const char *const s = tmp_string;
gsize i, d;
const gsize BIN_DATA_LEN = (length / 2 + 3);
bin_data = g_malloc (BIN_DATA_LEN);
#define DIGIT(c) ((c) - '0')
i = 0;
d = 0;
while (TRUE) {
int n;
/* leading whitespace */
while (g_ascii_isspace (s[i]))
i++;
if (s[i] == '\0')
break;
/* then expect 1 to 3 digits */
if (!g_ascii_isdigit (s[i])) {
d = 0;
break;
}
n = DIGIT (s[i]);
i++;
if (g_ascii_isdigit (s[i])) {
n = 10 * n + DIGIT (s[i]);
i++;
if (g_ascii_isdigit (s[i])) {
n = 10 * n + DIGIT (s[i]);
i++;
}
}
if (n > 255) {
d = 0;
break;
}
bin_data[d++] = n;
nm_assert (d < BIN_DATA_LEN);
/* allow whitespace after the digit. */
while (g_ascii_isspace (s[i]))
i++;
/* need a semicolon as separator. */
if (s[i] != ';') {
d = 0;
break;
}
i++;
}
#undef DIGIT
/* Old format; list of ints. We already did a strict validation of the
* string format before. We expect that this conversion cannot fail. */
if (d > 0) {
/* note that @zero_terminate does not add a terminating '\0' to
* binary data as an integer list.
*
* But we add a '\0' to the bin_data pointer, just to avoid somebody
* (erronously!) reading the binary data as C-string.
*
* @d itself does not entail the '\0'. */
nm_assert (d + 1 <= BIN_DATA_LEN);
bin_data = g_realloc (bin_data, d + 1);
bin_data[d] = '\0';
return g_bytes_new_take (g_steal_pointer (&bin_data), d);
}
}
/* Handle as a simple string (ie, new format) */
if (unescape_semicolon)
length = unescape_semicolons (tmp_string);
if (zero_terminate)
length++;
if (length == 0)
return NULL;
tmp_string = g_realloc (tmp_string, length + (zero_terminate ? 0 : 1));
return g_bytes_new_take (g_steal_pointer (&tmp_string), length);
}
static void

View File

@@ -112,6 +112,30 @@ nm_keyfile_plugin_kf_set_##stype##_list (GKeyFile *kf, \
DEFINE_KF_LIST_WRAPPER(integer, gint*, gint);
DEFINE_KF_LIST_WRAPPER(string, gchar **, const gchar* const);
void
nm_keyfile_plugin_kf_set_integer_list_uint8 (GKeyFile *kf,
const char *group,
const char *key,
const guint8 *data,
gsize length)
{
gsize i;
gsize l = length * 4 + 2;
gs_free char *value = g_malloc (l);
char *s = value;
g_return_if_fail (kf);
g_return_if_fail (!length || data);
g_return_if_fail (group && group[0]);
g_return_if_fail (key && key[0]);
value[0] = '\0';
for (i = 0; i < length; i++)
nm_utils_strbuf_append (&s, &l, "%d;", (int) data[i]);
nm_assert (l > 0);
nm_keyfile_plugin_kf_set_value (kf, group, key, value);
}
/* Single value helpers */
#define DEFINE_KF_WRAPPER(stype, get_ctype, set_ctype) \
get_ctype \

View File

@@ -47,6 +47,12 @@ void nm_keyfile_plugin_kf_set_##stype##_list (GKeyFile *kf, \
DEFINE_KF_LIST_WRAPPER_PROTO(integer, gint*, gint)
DEFINE_KF_LIST_WRAPPER_PROTO(string, gchar**, const gchar* const)
void nm_keyfile_plugin_kf_set_integer_list_uint8 (GKeyFile *kf,
const char *group,
const char *key,
const guint8 *list,
gsize length);
/* Single-value helpers */
#define DEFINE_KF_WRAPPER_PROTO(stype, get_ctype, set_ctype) \
get_ctype nm_keyfile_plugin_kf_get_##stype (GKeyFile *kf, \

View File

@@ -73,19 +73,25 @@ write_array_of_uint (GKeyFile *file,
const GValue *value)
{
GArray *array;
int i;
int *tmp_array;
guint i;
gs_free int *tmp_array = NULL;
array = (GArray *) g_value_get_boxed (value);
if (!array || !array->len)
return;
g_return_if_fail (g_array_get_element_size (array) == sizeof (guint));
tmp_array = g_new (gint, array->len);
for (i = 0; i < array->len; i++)
tmp_array[i] = g_array_index (array, int, i);
for (i = 0; i < array->len; i++) {
guint v = g_array_index (array, guint, i);
if (v > G_MAXINT)
g_return_if_reached ();
tmp_array[i] = (int) v;
}
nm_keyfile_plugin_kf_set_integer_list (file, nm_setting_get_name (setting), key, tmp_array, array->len);
g_free (tmp_array);
}
static void
@@ -294,9 +300,8 @@ ssid_writer (KeyfileWriterInfo *info,
gsize ssid_len;
const char *setting_name = nm_setting_get_name (setting);
gboolean new_format = TRUE;
unsigned int semicolons = 0;
int i, *tmp_array;
char *ssid;
gsize semicolons = 0;
gsize i;
g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES));
@@ -304,14 +309,17 @@ ssid_writer (KeyfileWriterInfo *info,
if (!bytes)
return;
ssid_data = g_bytes_get_data (bytes, &ssid_len);
if (ssid_len == 0)
if (!ssid_data || !ssid_len) {
nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, "");
return;
}
/* Check whether each byte is printable. If not, we have to use an
* integer list, otherwise we can just use a string.
*/
for (i = 0; i < ssid_len; i++) {
char c = ssid_data[i] & 0xFF;
const char c = ssid_data[i];
if (!g_ascii_isprint (c)) {
new_format = FALSE;
break;
@@ -321,28 +329,26 @@ ssid_writer (KeyfileWriterInfo *info,
}
if (new_format) {
ssid = g_malloc0 (ssid_len + semicolons + 1);
gs_free char *ssid = NULL;
if (semicolons == 0)
memcpy (ssid, ssid_data, ssid_len);
ssid = g_strndup ((char *) ssid_data, ssid_len);
else {
/* Escape semicolons with backslashes to make strings
* containing ';', such as '16;17;' unambiguous */
int j = 0;
gsize j = 0;
ssid = g_malloc (ssid_len + semicolons + 1);
for (i = 0; i < ssid_len; i++) {
if (ssid_data[i] == ';')
ssid[j++] = '\\';
ssid[j++] = ssid_data[i];
}
ssid[j] = '\0';
}
nm_keyfile_plugin_kf_set_string (info->keyfile, setting_name, key, ssid);
g_free (ssid);
} else {
tmp_array = g_new (gint, ssid_len);
for (i = 0; i < ssid_len; i++)
tmp_array[i] = (int) ssid_data[i];
nm_keyfile_plugin_kf_set_integer_list (info->keyfile, setting_name, key, tmp_array, ssid_len);
g_free (tmp_array);
}
} else
nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, ssid_data, ssid_len);
}
static void
@@ -353,9 +359,8 @@ password_raw_writer (KeyfileWriterInfo *info,
{
const char *setting_name = nm_setting_get_name (setting);
GBytes *array;
int *tmp_array;
gsize i, len;
const char *data;
gsize len;
const guint8 *data;
g_return_if_fail (G_VALUE_HOLDS (value, G_TYPE_BYTES));
@@ -363,14 +368,9 @@ password_raw_writer (KeyfileWriterInfo *info,
if (!array)
return;
data = g_bytes_get_data (array, &len);
if (!data || !len)
return;
tmp_array = g_new (gint, len);
for (i = 0; i < len; i++)
tmp_array[i] = (int) data[i];
nm_keyfile_plugin_kf_set_integer_list (info->keyfile, setting_name, key, tmp_array, len);
g_free (tmp_array);
if (!data)
len = 0;
nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, data, len);
}
typedef struct ObjectType {
@@ -729,17 +729,8 @@ write_setting_value (NMSetting *setting,
bytes = g_value_get_boxed (value);
data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
if (data != NULL && len > 0) {
int *tmp_array;
int i;
tmp_array = g_new (gint, len);
for (i = 0; i < len; i++)
tmp_array[i] = (int) data[i];
nm_keyfile_plugin_kf_set_integer_list (info->keyfile, setting_name, key, tmp_array, len);
g_free (tmp_array);
}
if (data != NULL && len > 0)
nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, data, len);
} else if (type == G_TYPE_STRV) {
char **array;

View File

@@ -27,6 +27,85 @@
/*****************************************************************************/
void
nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
{
switch (*len) {
case 0:
return;
case 1:
(*buf)[0] = '\0';
*len = 0;
(*buf)++;
return;
default:
(*buf)[0] = c;
(*buf)[1] = '\0';
(*len)--;
(*buf)++;
return;
}
}
void
nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
{
gsize src_len;
switch (*len) {
case 0:
return;
case 1:
if (!str || !*str) {
(*buf)[0] = '\0';
return;
}
(*buf)[0] = '\0';
*len = 0;
(*buf)++;
return;
default:
if (!str || !*str) {
(*buf)[0] = '\0';
return;
}
src_len = g_strlcpy (*buf, str, *len);
if (src_len >= *len) {
*buf = &(*buf)[*len];
*len = 0;
} else {
*buf = &(*buf)[src_len];
*len -= src_len;
}
return;
}
}
void
nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
{
char *p = *buf;
va_list args;
gint retval;
if (*len == 0)
return;
va_start (args, format);
retval = g_vsnprintf (p, *len, format, args);
va_end (args);
if (retval >= *len) {
*buf = &p[*len];
*len = 0;
} else {
*buf = &p[retval];
*len -= retval;
}
}
/*****************************************************************************/
/* _nm_utils_ascii_str_to_int64:
*
* A wrapper for g_ascii_strtoll, that checks whether the whole string

View File

@@ -24,6 +24,25 @@
/*****************************************************************************/
static inline void
_nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
{
NM_SET_OUT (p_buf_len, len);
NM_SET_OUT (p_buf_ptr, buf);
buf[0] = '\0';
}
#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \
G_STMT_START { \
G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) > sizeof (char *)); \
_nm_utils_strbuf_init ((buf), sizeof (buf), (p_buf_ptr), (p_buf_len)); \
} G_STMT_END
void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
/*****************************************************************************/
gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
gint _nm_utils_ascii_str_to_bool (const char *str,

View File

@@ -1771,83 +1771,6 @@ nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len)
return TRUE;
}
void
nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
{
switch (*len) {
case 0:
return;
case 1:
(*buf)[0] = '\0';
*len = 0;
(*buf)++;
return;
default:
(*buf)[0] = c;
(*buf)[1] = '\0';
(*len)--;
(*buf)++;
return;
}
}
void
nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
{
gsize src_len;
switch (*len) {
case 0:
return;
case 1:
if (!str || !*str) {
(*buf)[0] = '\0';
return;
}
(*buf)[0] = '\0';
*len = 0;
(*buf)++;
return;
default:
if (!str || !*str) {
(*buf)[0] = '\0';
return;
}
src_len = g_strlcpy (*buf, str, *len);
if (src_len >= *len) {
*buf = &(*buf)[*len];
*len = 0;
} else {
*buf = &(*buf)[src_len];
*len -= src_len;
}
return;
}
}
void
nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
{
char *p = *buf;
va_list args;
gint retval;
if (*len == 0)
return;
va_start (args, format);
retval = g_vsnprintf (p, *len, format, args);
va_end (args);
if (retval >= *len) {
*buf = &p[*len];
*len = 0;
} else {
*buf = &p[retval];
*len -= retval;
}
}
const char *
nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
gsize n_descs,

View File

@@ -262,23 +262,6 @@ fcn_name (lookup_type val) \
/*****************************************************************************/
static inline void
_nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
{
NM_SET_OUT (p_buf_len, len);
NM_SET_OUT (p_buf_ptr, buf);
buf[0] = '\0';
}
#define nm_utils_strbuf_init(buf, p_buf_ptr, p_buf_len) \
G_STMT_START { \
G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) > sizeof (char *)); \
_nm_utils_strbuf_init ((buf), sizeof (buf), (p_buf_ptr), (p_buf_len)); \
} G_STMT_END
void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
const char *nm_utils_get_ip_config_method (NMConnection *connection,
GType ip_setting_type);

View File

@@ -0,0 +1,33 @@
[connection]
id=dcb connection 1
uuid=ac3c251e-260f-49b6-8ceb-12d37ea00751
type=ethernet
autoconnect=false
permissions=
secondaries=
[ethernet]
mac-address-blacklist=
[dcb]
app-fcoe-flags=1
app-fip-flags=1
app-iscsi-flags=1
priority-bandwidth=0;0;0;0;0;0;0;0;
priority-flow-control=0;0;0;0;0;0;0;0;
priority-flow-control-flags=1
priority-group-bandwidth=100;0;0;0;0;0;0;0;
priority-group-flags=1
priority-group-id=0;0;0;0;0;0;0;0;
priority-strict-bandwidth=0;0;0;0;0;0;0;0;
priority-traffic-class=0;0;0;0;0;0;0;0;
[ipv4]
dns-search=
method=auto
[ipv6]
addr-gen-mode=stable-privacy
dns-search=
ip6-privacy=0
method=auto

View File

@@ -1786,6 +1786,14 @@ test_write_wired_8021x_tls_connection_blob (void)
g_free (new_priv_key);
}
static void
test_read_dcb_connection (void)
{
gs_unref_object NMConnection *connection = NULL;
connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_dcb_connection");
}
static void
test_read_infiniband_connection (void)
{
@@ -2622,6 +2630,8 @@ int main (int argc, char **argv)
g_test_add_func ("/keyfile/test_write_wired_8021x_tls_connection_path", test_write_wired_8021x_tls_connection_path);
g_test_add_func ("/keyfile/test_write_wired_8021x_tls_connection_blob", test_write_wired_8021x_tls_connection_blob);
g_test_add_func ("/keyfile/test_read_dcb_connection", test_read_dcb_connection);
g_test_add_func ("/keyfile/test_read_infiniband_connection", test_read_infiniband_connection);
g_test_add_func ("/keyfile/test_write_infiniband_connection", test_write_infiniband_connection);