Blob Blame History Raw
diff --git a/data/fwupd.service.in b/data/fwupd.service.in
index 0110ea8c..49d84153 100644
--- a/data/fwupd.service.in
+++ b/data/fwupd.service.in
@@ -10,11 +10,3 @@ BusName=org.freedesktop.fwupd
 ExecStart=@libexecdir@/fwupd/fwupd
 MemoryDenyWriteExecute=yes
 PrivateTmp=yes
-ProtectControlGroups=yes
-ProtectHome=yes
-ProtectKernelModules=yes
-ProtectSystem=full
-RestrictAddressFamilies=AF_NETLINK AF_UNIX
-RestrictRealtime=yes
-ReadWritePaths=@localstatedir@/lib/fwupd @sysconfdir@/fwupd/remotes.d -@bootdir@
-SystemCallFilter=~@mount
diff --git a/meson.build b/meson.build
index 7cc6fe85..8d58bd45 100644
--- a/meson.build
+++ b/meson.build
@@ -145,7 +145,11 @@ gudev = dependency('gudev-1.0')
 if gudev.version().version_compare('>= 232')
   conf.set('HAVE_GUDEV_232', '1')
 endif
-appstream_glib = dependency('appstream-glib', version : '>= 0.6.13')
+appstream_glib = dependency('appstream-glib', version : '>= 0.6.10')
+
+# only for appstream <= 0.6.13
+uuid = dependency('uuid')
+
 gusb = dependency('gusb', version : '>= 0.2.9')
 sqlite = dependency('sqlite3')
 libarchive = dependency('libarchive')
@@ -215,7 +219,7 @@ if get_option('enable-thunderbolt')
 endif
 
 if get_option('enable-systemd')
-  systemd = dependency('systemd', version : '>= 231')
+  systemd = dependency('systemd')
   conf.set('HAVE_SYSTEMD' , '1')
 endif
 
diff --git a/src/fu-engine.c b/src/fu-engine.c
index 79b0a147..bcc18350 100644
--- a/src/fu-engine.c
+++ b/src/fu-engine.c
@@ -54,6 +54,131 @@
 #include "fu-keyring-pkcs7.h"
 #endif
 
+#if !AS_CHECK_VERSION(0,6,12)
+#include <fnmatch.h>
+#endif
+
+#if AS_CHECK_VERSION(0,6,13)
+static gint
+as_utils_vercmp_SAFE (const gchar *version_a, const gchar *version_b)
+{
+	return as_utils_vercmp (version_a, version_b);
+}
+#else
+
+static gchar *
+as_utils_version_parse_SAFE (const gchar *version)
+{
+	const gchar *version_noprefix = version;
+	gchar *endptr = NULL;
+	guint64 tmp;
+	guint base;
+	guint i;
+
+	/* already dotted decimal */
+	if (g_strstr_len (version, -1, ".") != NULL)
+		return g_strdup (version);
+
+	/* is a date */
+	if (g_str_has_prefix (version, "20") &&
+	    strlen (version) == 8)
+		return g_strdup (version);
+
+	/* convert 0x prefixed strings to dotted decimal */
+	if (g_str_has_prefix (version, "0x")) {
+		version_noprefix += 2;
+		base = 16;
+	} else {
+		/* for non-numeric content, just return the string */
+		for (i = 0; version[i] != '\0'; i++) {
+			if (!g_ascii_isdigit (version[i]))
+				return g_strdup (version);
+		}
+		base = 10;
+	}
+
+	/* convert */
+	tmp = g_ascii_strtoull (version_noprefix, &endptr, base);
+	if (endptr != NULL && endptr[0] != '\0')
+		return g_strdup (version);
+	if (tmp == 0)
+		return g_strdup (version);
+	return as_utils_version_from_uint32 ((guint32) tmp, AS_VERSION_PARSE_FLAG_USE_TRIPLET);
+}
+
+static gint
+as_utils_vercmp_SAFE (const gchar *version_a, const gchar *version_b)
+{
+	gchar *endptr;
+	gint64 ver_a;
+	gint64 ver_b;
+	guint i;
+	guint longest_split;
+	g_autofree gchar *str_a = NULL;
+	g_autofree gchar *str_b = NULL;
+	g_auto(GStrv) split_a = NULL;
+	g_auto(GStrv) split_b = NULL;
+
+	/* sanity check */
+	if (version_a == NULL || version_b == NULL)
+		return G_MAXINT;
+
+	/* optimisation */
+	if (g_strcmp0 (version_a, version_b) == 0)
+		return 0;
+
+	/* split into sections, and try to parse */
+	str_a = as_utils_version_parse_SAFE (version_a);
+	str_b = as_utils_version_parse_SAFE (version_b);
+	split_a = g_strsplit (str_a, ".", -1);
+	split_b = g_strsplit (str_b, ".", -1);
+	longest_split = MAX (g_strv_length (split_a), g_strv_length (split_b));
+	for (i = 0; i < longest_split; i++) {
+		gboolean isnum_a = TRUE;
+		gboolean isnum_b = TRUE;
+
+		/* we lost or gained a dot */
+		if (split_a[i] == NULL)
+			return -1;
+		if (split_b[i] == NULL)
+			return 1;
+
+		/* compare integers */
+		ver_a = g_ascii_strtoll (split_a[i], &endptr, 10);
+		if (endptr != NULL && endptr[0] != '\0')
+			isnum_a = FALSE;
+		if (ver_a < 0)
+			isnum_a = FALSE;
+		ver_b = g_ascii_strtoll (split_b[i], &endptr, 10);
+		if (endptr != NULL && endptr[0] != '\0')
+			isnum_b = FALSE;
+		if (ver_b < 0)
+			isnum_b = FALSE;
+
+		/* can't compare integer with string */
+		if (isnum_a != isnum_b)
+			return G_MAXINT;
+
+		/* compare strings */
+		if (!isnum_a) {
+			gint rc = g_strcmp0 (split_a[i], split_b[i]);
+			if (rc != 0)
+				return rc;
+
+		/* compare integers */
+		} else {
+			if (ver_a < ver_b)
+				return -1;
+			if (ver_a > ver_b)
+				return 1;
+		}
+	}
+
+	/* we really shouldn't get here */
+	return 0;
+}
+#endif
+
 static void fu_engine_finalize	 (GObject *obj);
 
 struct _FuEngine
@@ -811,6 +936,77 @@ _as_app_get_screenshot_default (AsApp *app)
 #endif
 }
 
+#if !AS_CHECK_VERSION(0,6,12)
+static gboolean
+as_require_version_compare_SAFE (AsRequire *require,
+			    const gchar *version,
+			    GError **error)
+{
+	const gchar *priv__version = as_require_get_version (require);
+	AsRequireCompare priv__compare = as_require_get_compare (require);
+	gboolean ret = FALSE;
+	gint rc = 0;
+
+	switch (priv__compare) {
+	case AS_REQUIRE_COMPARE_EQ:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc == 0;
+		break;
+	case AS_REQUIRE_COMPARE_NE:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc != 0;
+		break;
+	case AS_REQUIRE_COMPARE_LT:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc < 0;
+		break;
+	case AS_REQUIRE_COMPARE_GT:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc > 0;
+		break;
+	case AS_REQUIRE_COMPARE_LE:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc <= 0;
+		break;
+	case AS_REQUIRE_COMPARE_GE:
+		rc = as_utils_vercmp_SAFE (version, priv__version);
+		ret = rc >= 0;
+		break;
+	case AS_REQUIRE_COMPARE_GLOB:
+		ret = fnmatch (priv__version, version, 0) == 0;
+		break;
+	case AS_REQUIRE_COMPARE_REGEX:
+		ret = g_regex_match_simple (priv__version, version, 0, 0);
+		break;
+	default:
+		break;
+	}
+
+	/* could not compare */
+	if (rc == G_MAXINT) {
+		g_set_error (error,
+			     AS_UTILS_ERROR,
+			     AS_UTILS_ERROR_FAILED,
+			     "failed to compare [%s] and [%s]",
+			     priv__version,
+			     version);
+		return FALSE;
+	}
+
+	/* set error */
+	if (!ret && error != NULL) {
+		g_set_error (error,
+			     AS_UTILS_ERROR,
+			     AS_UTILS_ERROR_FAILED,
+			     "failed predicate [%s %s %s]",
+			     priv__version,
+			     as_require_compare_to_string (priv__compare),
+			     version);
+	}
+	return ret;
+}
+#endif
+
 static gboolean
 fu_engine_check_version_requirement (AsApp *app,
 				   AsRequireKind kind,
@@ -836,7 +1032,11 @@ fu_engine_check_version_requirement (AsApp *app,
 	}
 
 	/* check version */
+#if AS_CHECK_VERSION(0,6,12)
 	if (!as_require_version_compare (req, version, error)) {
+#else
+	if (!as_require_version_compare_SAFE (req, version, error)) {
+#endif
 		g_prefix_error (error, "Value of %s incorrect: ", id);
 		return FALSE;
 	}
@@ -1221,7 +1421,7 @@ fu_engine_install (FuEngine *self,
 
 	/* compare to the lowest supported version, if it exists */
 	tmp = fu_device_get_version_lowest (item->device);
-	if (tmp != NULL && as_utils_vercmp (tmp, version) > 0) {
+	if (tmp != NULL && as_utils_vercmp_SAFE (tmp, version) > 0) {
 		g_set_error (error,
 			     FWUPD_ERROR,
 			     FWUPD_ERROR_VERSION_NEWER,
@@ -1240,7 +1440,7 @@ fu_engine_install (FuEngine *self,
 			     device_id);
 		return FALSE;
 	}
-	vercmp = as_utils_vercmp (tmp, version);
+	vercmp = as_utils_vercmp_SAFE (tmp, version);
 	if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) {
 		g_set_error (error,
 			     FWUPD_ERROR,
@@ -1476,7 +1676,7 @@ fu_engine_get_action_id_for_device (FuEngine *self,
 				     "Release has no firmware version");
 		return NULL;
 	}
-	vercmp = as_utils_vercmp (version, version_release);
+	vercmp = as_utils_vercmp_SAFE (version, version_release);
 	if (vercmp == 0 && (flags & FWUPD_INSTALL_FLAG_ALLOW_REINSTALL) == 0) {
 		g_set_error (error,
 			     FWUPD_ERROR,
@@ -2099,7 +2299,7 @@ fu_engine_sort_releases_cb (gconstpointer a, gconstpointer b)
 {
 	FwupdRelease *rel_a = FWUPD_RELEASE (*((FwupdRelease **) a));
 	FwupdRelease *rel_b = FWUPD_RELEASE (*((FwupdRelease **) b));
-	return as_utils_vercmp (fwupd_release_get_version (rel_a),
+	return as_utils_vercmp_SAFE (fwupd_release_get_version (rel_a),
 				fwupd_release_get_version (rel_b));
 }
 
@@ -2246,7 +2446,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error
 		gint vercmp;
 
 		/* only include older firmware */
-		vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp),
+		vercmp = as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp),
 					  fu_device_get_version (item->device));
 		if (vercmp == 0) {
 			g_string_append_printf (error_str, "%s=same, ",
@@ -2267,7 +2467,7 @@ fu_engine_get_downgrades (FuEngine *self, const gchar *device_id, GError **error
 
 		/* don't show releases we are not allowed to dowgrade to */
 		if (fu_device_get_version_lowest (item->device) != NULL) {
-			if (as_utils_vercmp (fwupd_release_get_version (rel_tmp),
+			if (as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp),
 					     fu_device_get_version_lowest (item->device)) <= 0) {
 				g_string_append_printf (error_str, "%s=lowest, ",
 							fwupd_release_get_version (rel_tmp));
@@ -2339,7 +2539,7 @@ fu_engine_get_upgrades (FuEngine *self, const gchar *device_id, GError **error)
 		gint vercmp;
 
 		/* only include older firmware */
-		vercmp = as_utils_vercmp (fwupd_release_get_version (rel_tmp),
+		vercmp = as_utils_vercmp_SAFE (fwupd_release_get_version (rel_tmp),
 					  fu_device_get_version (item->device));
 		if (vercmp == 0) {
 			g_string_append_printf (error_str, "%s=same, ",
diff --git a/src/fu-hwids.c b/src/fu-hwids.c
index 5e7aa923..92d0afdf 100644
--- a/src/fu-hwids.c
+++ b/src/fu-hwids.c
@@ -69,6 +69,56 @@ fu_hwids_has_guid (FuHwids *self, const gchar *guid)
 	return g_hash_table_lookup (self->hash_guid, guid) != NULL;
 }
 
+#if !AS_CHECK_VERSION(0,6,13)
+#include <uuid.h>
+static gchar *
+as_utils_guid_from_data (const gchar *namespace_id,
+			 const guint8 *data,
+			 gsize data_len,
+			 GError **error)
+{
+	gchar guid_new[37]; /* 36 plus NUL */
+	gsize digestlen = 20;
+	guint8 hash[20];
+	gint rc;
+	uuid_t uu_namespace;
+	uuid_t uu_new;
+	g_autoptr(GChecksum) csum = NULL;
+
+	g_return_val_if_fail (namespace_id != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+	g_return_val_if_fail (data_len != 0, FALSE);
+
+	/* convert the namespace to binary */
+	rc = uuid_parse (namespace_id, uu_namespace);
+	if (rc != 0) {
+		g_set_error (error,
+			     AS_UTILS_ERROR,
+			     AS_UTILS_ERROR_FAILED,
+			     "namespace '%s' is invalid",
+			     namespace_id);
+		return FALSE;
+	}
+
+	/* hash the namespace and then the string */
+	csum = g_checksum_new (G_CHECKSUM_SHA1);
+	g_checksum_update (csum, (guchar *) uu_namespace, 16);
+	g_checksum_update (csum, (guchar *) data, (gssize) data_len);
+	g_checksum_get_digest (csum, hash, &digestlen);
+
+	/* copy most parts of the hash 1:1 */
+	memcpy (uu_new, hash, 16);
+
+	/* set specific bits according to Section 4.1.3 */
+	uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4));
+	uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80);
+
+	/* return as a string */
+	uuid_unparse (uu_new, guid_new);
+	return g_strdup (guid_new);
+}
+#endif
+
 static gchar *
 fu_hwids_get_guid_for_str (const gchar *str, GError **error)
 {
diff --git a/src/meson.build b/src/meson.build
index 3d35dd87..9788f529 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -38,6 +38,7 @@ libfwupdprivate = static_library(
   ],
   dependencies : [
     appstream_glib,
+    uuid,
     giounix,
     gudev,
     gusb,
@@ -67,6 +68,7 @@ fwupdmgr = executable(
   ],
   dependencies : [
     appstream_glib,
+    uuid,
     giounix,
     gudev,
     gusb,
@@ -141,6 +143,7 @@ executable(
   dependencies : [
     keyring_deps,
     appstream_glib,
+    uuid,
     giounix,
     gmodule,
     gudev,
@@ -203,6 +206,7 @@ if get_option('enable-tests')
     dependencies : [
       keyring_deps,
       appstream_glib,
+      uuid,
       giounix,
       gmodule,
       gudev,
@@ -260,6 +264,7 @@ if get_option('enable-introspection')
     ],
     dependencies : [
       appstream_glib,
+      uuid,
       gir_dep,
       giounix,
       gusb,