If validation with the cygwin signing key fails for a purported
private mirror, retry with other supplied keys.  If this succeeds,
silently change the status of the site to "user site" and put a note
in the log file.  This change will take effect on the next setup run
or if the user selects 'Back'.

This uses a new optional argument 'retry_sig_ok' to
ini.cc:check_ini_sig().  If this is 'true', don't destroy ini_file and
ini_sig_file on a validation failure.
---
 ini.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
 site.h |  2 ++
 2 files changed, 57 insertions(+), 10 deletions(-)

diff --git a/ini.cc b/ini.cc
index 4be8263..62b7e83 100644
--- a/ini.cc
+++ b/ini.cc
@@ -18,6 +18,8 @@
    flex parsers are provided also.  We check to see if this setup.ini
    is older than the one we used last time, and if so, warn the user. */
 
+#include <algorithm>
+
 #include "ini.h"
 
 #include "csu_util/rfc1738.h"
@@ -173,7 +175,7 @@ decompress_ini (io_stream *ini_file)
 static io_stream*
 check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file,
               bool& sig_fail, const char* site, const char* sig_name,
-              HWND owner, bool main_key_only = false)
+              HWND owner, bool main_key_only = false, bool retry_sig_ok = 
false)
 {
   /* Unless the NoVerifyOption is set, check the signature for the
      current setup and record the result.  On a failed signature check
@@ -195,12 +197,15 @@ check_ini_sig (io_stream* ini_file, io_stream* 
ini_sig_file,
       }
       else if (!verify_ini_file_sig (ini_file, ini_sig_file, owner, 
main_key_only))
        {
-         note (owner, IDS_SIG_INVALID, sig_name, site);
-         delete ini_sig_file;
-         ini_sig_file = NULL;
-         delete ini_file;
-         ini_file = NULL;
          sig_fail = true;
+         if (!retry_sig_ok)
+           {
+             note (owner, IDS_SIG_INVALID, sig_name, site);
+             delete ini_sig_file;
+             ini_sig_file = NULL;
+             delete ini_file;
+             ini_file = NULL;
+           }
        }
     }
   return ini_file;
@@ -265,6 +270,27 @@ do_local_ini (HWND owner)
   return ini_error;
 }
 
+static void
+mirror_warn (site_list_type site)
+{
+  Log (LOG_BABBLE) << "Signature validation failed for " << site.url
+                  << " using the cygwin key but succeeded using other keys.  "
+                  << endLog;
+  Log (LOG_BABBLE) << "Changing status from 'mirror' to 'user site'." << 
endLog;
+  SiteList::iterator i = find (all_site_list.begin (), all_site_list.end (), 
site);
+  if (i != all_site_list.end ())
+    {
+      all_site_list.erase (i);
+      site_list_type newsite (site.url, "", "", "", false, false);
+      all_site_list.push_back (newsite);
+      selected_usersite_list.push_back (newsite);
+      SiteList::iterator j = find (selected_mirror_list.begin (),
+                                  selected_mirror_list.end (), site);
+      if (j != selected_mirror_list.end ())
+       selected_mirror_list.erase (j);
+    }
+}
+
 static bool
 do_remote_ini (HWND owner)
 {
@@ -293,14 +319,33 @@ do_remote_ini (HWND owner)
          ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
          ini_file = get_url_to_membuf (current_ini_name, owner);
 
-         // Official mirrors must be signed by the cygwin key.
-         bool main_key_only = n->from_mirrors_lst;
+         // Mirrors should be signed by the cygwin key.
+         bool main_key_only = n->is_mirror;
+
+         // If this fails for a purported private mirror, allow a
+         // retry with additional keys; if this succeeds, reclassify
+         // the site as a user site.
+         bool retry_sig_ok = n->is_mirror && !n->from_mirrors_lst;
+       retry:
          ini_file = check_ini_sig (ini_file, ini_sig_file, sig_fail,
-                                   n->url.c_str (), current_ini_sig_name.c_str 
(), owner, main_key_only);
+                                   n->url.c_str (),
+                                   current_ini_sig_name.c_str (), owner,
+                                   main_key_only, retry_sig_ok);
+         if (retry_sig_ok && sig_fail)
+           {
+             sig_fail = false;
+             retry_sig_ok = false;
+             main_key_only = false;
+             goto retry;
+           }
 
          // stop searching as soon as we find a setup file
          if (ini_file)
-           break;
+           {
+             if (n->is_mirror && !main_key_only)
+               mirror_warn (*n);
+             break;
+           }
        }
       if (ini_file)
        ini_file = decompress_ini (ini_file);
diff --git a/site.h b/site.h
index 3525931..5b01829 100644
--- a/site.h
+++ b/site.h
@@ -79,6 +79,8 @@ typedef std::vector <site_list_type> SiteList;
 
 /* user chosen sites */
 extern SiteList site_list;
+extern SiteList selected_mirror_list;
+extern SiteList selected_usersite_list;
 /* potential sites */
 extern SiteList all_site_list;
 
-- 
2.15.1

Reply via email to