Commit 32f78ae6 authored by Thomas Haller's avatar Thomas Haller

libnm: expose nm_utils_is_json_object() utility function

Since we possibly already link against libjansson, we can also expose some
helper utils which allows nmcli to do basic validation of JSON without
requiring to duplicate the effort of using libjansson.

Also, tighten up the cecks to ensure that we have a JSON object at hand.
We are really interested in that and not of arrays or literals.
parent c3586ce0
......@@ -329,7 +329,6 @@ gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
/***********************************************************/
gboolean _nm_utils_check_valid_json (const char *json, GError **error);
gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port);
#endif
......@@ -1175,7 +1175,7 @@ team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
gs_free_error GError *error = NULL;
conf = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
if (conf && conf[0] && !_nm_utils_check_valid_json (conf, &error)) {
if (conf && conf[0] && !nm_utils_is_json_object (conf, &error)) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid team configuration: %s"),
error->message);
......
......@@ -117,7 +117,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
if (priv->config) {
if (!_nm_utils_check_valid_json (priv->config, error)) {
if (!nm_utils_is_json_object (priv->config, error)) {
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_PORT_SETTING_NAME,
......
......@@ -89,7 +89,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
if (priv->config) {
if (!_nm_utils_check_valid_json (priv->config, error)) {
if (!nm_utils_is_json_object (priv->config, error)) {
g_prefix_error (error,
"%s.%s: ",
NM_SETTING_TEAM_SETTING_NAME,
......
......@@ -4407,8 +4407,20 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to)
}
#if WITH_JANSSON
/**
* nm_utils_is_json_object:
* @str: the JSON string to test
* @error: optional error reason
*
* Returns: whether the passed string is valid JSON.
* If libnm is not compiled with libjansson support, this check will
* also return %TRUE for possibly invalid inputs. If that is a problem
* for you, you must validate the JSON yourself.
*
* Since: 1.6
*/
gboolean
_nm_utils_check_valid_json (const char *str, GError **error)
nm_utils_is_json_object (const char *str, GError **error)
{
json_t *json;
json_error_t jerror;
......@@ -4419,7 +4431,7 @@ _nm_utils_check_valid_json (const char *str, GError **error)
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
"value is NULL or empty");
str ? _("value is NULL") : _("value is empty"));
return FALSE;
}
......@@ -4428,9 +4440,19 @@ _nm_utils_check_valid_json (const char *str, GError **error)
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
"%s at position %d",
jerror.text,
jerror.position);
_("invalid JSON at position %d (%s)"),
jerror.position,
jerror.text);
return FALSE;
}
/* valid JSON (depending on the definition) can also be a literal.
* Here we only allow objects. */
if (!json_is_object (json)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("is not a JSON object"));
return FALSE;
}
......@@ -4522,17 +4544,48 @@ out:
#else /* WITH_JANSSON */
gboolean
_nm_utils_check_valid_json (const char *str, GError **error)
nm_utils_is_json_object (const char *str, GError **error)
{
g_return_val_if_fail (!error || !*error, FALSE);
if (str) {
/* libjansson also requires only utf-8 encoding. */
if (!g_utf8_validate (str, -1, NULL)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("not valid utf-8"));
return FALSE;
}
while (g_ascii_isspace (str[0]))
str++;
}
if (!str || !str[0]) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
"value is NULL or empty");
str ? _("value is NULL") : _("value is empty"));
return FALSE;
}
return TRUE;
/* do some very basic validation to see if this might be a JSON object. */
if (str[0] == '{') {
g_size l;
l = strlen (str) - 1;
while (l > 0 && g_ascii_isspace (str[l]))
l--;
if (str[l] == '}')
return TRUE;
}
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("is not a JSON object"));
return FALSE;
}
gboolean
......
......@@ -90,6 +90,9 @@ gboolean nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
gboolean nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type);
gboolean nm_utils_wpa_psk_valid (const char *psk);
NM_AVAILABLE_IN_1_6
gboolean nm_utils_is_json_object (const char *json, GError **error);
GVariant *nm_utils_ip4_dns_to_variant (char **dns);
char **nm_utils_ip4_dns_from_variant (GVariant *value);
GVariant *nm_utils_ip4_addresses_to_variant (GPtrArray *addresses,
......
......@@ -4685,7 +4685,7 @@ _json_config_check_valid (const char *conf, gboolean expected)
gs_free_error GError *error = NULL;
gboolean res;
res = _nm_utils_check_valid_json (conf, &error);
res = nm_utils_is_json_object (conf, &error);
g_assert_cmpint (res, ==, expected);
g_assert (res || error);
}
......
......@@ -1086,4 +1086,5 @@ global:
libnm_1_6_0 {
nm_capability_get_type;
nm_utils_is_json_object;
} libnm_1_4_0;
......@@ -4258,7 +4258,7 @@ read_team_config (shvarFile *ifcfg, const char *key, GError **error)
}
svUnescape (value);
if (value && value[0] && !_nm_utils_check_valid_json (value, &local_error)) {
if (value && value[0] && !nm_utils_is_json_object (value, &local_error)) {
PARSE_WARNING ("ignoring invalid team configuration: %s", local_error->message);
g_clear_pointer (&value, g_free);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment