Blob Blame History Raw
From 966d9e6b0dec88020a5a9d7368fc95825c55d225 Mon Sep 17 00:00:00 2001
From: Jaroslav Rohel <jrohel@redhat.com>
Date: Tue, 21 Apr 2020 08:56:01 +0200
Subject: [PATCH 4/4] Append ctx_baseurl prefix to gpg_url (RhBug:1708628)

Sometime the gpg_url contains relative path to context baseurl.
In that case the code appends baseurl prefix to gpg_url. The resulting
URI is normalized (solved "//", ".", and "..")

The new function rhsm_url_base_join() introduce similar results
as utils.url_base_join() in subscription manager.
---
 rhsm/rhsm-utils.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/rhsm/rhsm-utils.c b/rhsm/rhsm-utils.c
index 6708a43a93f850f873a216d6f20aca8b7bd3225e..ee3f296d59c0c4e3c9ed63ccfe460ffdac5bfd3e 100644
--- a/rhsm/rhsm-utils.c
+++ b/rhsm/rhsm-utils.c
@@ -179,10 +179,101 @@ rhsm_json_array_is_subset_of_hash_table (JsonArray  *array,
     }
 
   return TRUE;
 }
 
+/*
+ * Join a baseurl (hostname) and url (full or relpath).
+ *
+ * If url is a full url, just return it. Otherwise combine
+ * it with base, skipping redundant seperators if needed.
+ *
+ * Simulate the behavior of subscription manager.
+ */
+static gchar *
+rhsm_url_base_join (const gchar *base,
+                    const gchar *url)
+{
+  /* handle special cases similar to subscription manager */
+  if (!url || *url == '\0')
+    return g_strdup ("");
+  if (strstr (url, "://"))
+    return g_strdup (url);
+  if (!base || *base == '\0')
+    return g_strdup (url);
+
+  /* parse URI, split to schema, host, and path */
+  g_autofree gchar *schema = NULL;
+  g_autofree gchar *host = NULL;
+  g_autofree gchar *path = NULL;
+  gchar *tmp = strstr (base, ":");
+  if (tmp)
+    schema = g_strndup (base, tmp - base);
+  if (schema)
+    {
+      if (tmp[1] == '/' && tmp[2] == '/')
+      {
+        gchar *tmp2 = strstr (tmp + 3, "/");
+        if (tmp2)
+          {
+            host = g_strndup (tmp + 3, tmp2 - tmp - 3);
+            path = g_strdup (tmp2);
+          }
+        else
+          host = g_strdup (tmp + 3);
+      }
+      else
+        path = g_strdup (tmp + 1);
+    }
+  else
+    path = g_strdup (base);
+
+  /* full_path is path from base + url */
+  g_autofree gchar *full_path = NULL;
+  if (path)
+    full_path = g_strconcat (path, "/", url, NULL);
+  else
+    full_path = g_strconcat ("/", url, NULL);
+
+  /* normalize full_path
+   * split to vector, copy vector but skip empty and "." items,
+   * for each ".." source item remove last item from destination
+   */
+  g_auto(GStrv) src_split_path = g_strsplit (full_path, "/", -1);
+  guint src_len = g_strv_length (src_split_path);
+  g_autofree gchar **dest_split_path = g_new0 (gchar *, src_len + 1);
+  guint dest_len = 0;
+  for (guint src_idx = 0; src_idx < src_len; ++src_idx)
+    {
+      gchar *src = src_split_path[src_idx];
+      if (*src == '\0' || strcmp (src, ".") == 0)
+        continue;
+      if (strcmp (src, "..") == 0)
+        {
+          if (dest_len > 0)
+            --dest_len;
+          continue;
+        }
+      dest_split_path[dest_len++] = src;
+    }
+  dest_split_path[dest_len] = NULL;
+
+  /* construct destination path */
+  g_autofree gchar *tmp_path = g_strjoinv ("/", dest_split_path);
+  g_autofree gchar *dest_path = NULL;
+  if (g_str_has_suffix (url, "/") || g_str_has_suffix (url, "/.") || g_str_has_suffix (url, "/.."))
+    dest_path = g_strconcat (tmp_path, "/", NULL);
+  else
+    dest_path = g_strdup (tmp_path);
+
+  /* construct and return final URI */
+  if (schema)
+    return g_strconcat (schema, "://", host ? host : "", "/", dest_path, NULL);
+  else
+    return g_strconcat ("/", dest_path, NULL);
+}
+
 /**
  * rhsm_utils_yum_repo_from_context:
  * @ctx: an #RHSMContext.
  *
  * Returns: (transfer full): a new #GKeyFile.
@@ -273,11 +364,12 @@ rhsm_utils_yum_repo_from_context (RHSMContext *ctx)
           g_key_file_set_integer (repofile, id, "enabled", enabled ? 1 : 0);
 
           if (json_object_has_member (repo, "gpg_url"))
             {
               const gchar *gpg_url = json_object_get_string_member (repo, "gpg_url");
-              g_key_file_set_string (repofile, id, "gpgkey", gpg_url);
+              g_autofree gchar *gpgkey = rhsm_url_base_join (ctx_baseurl, gpg_url);
+              g_key_file_set_string (repofile, id, "gpgkey", gpgkey);
               g_key_file_set_boolean (repofile, id, "gpgcheck", TRUE);
             }
           else
             {
               /* FIXME: Do we want to enforce gpgcheck? It's unsecure repo. */
-- 
2.26.2