]> git.saurik.com Git - apt.git/commitdiff
trigger NODATA error for invalid InRelease files
authorDavid Kalnischkies <kalnischkies@gmail.com>
Mon, 17 Jun 2013 09:23:13 +0000 (11:23 +0200)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Thu, 20 Jun 2013 08:56:50 +0000 (10:56 +0200)
With the selfgrown splitting we got the problem of not recovering
from networks which just reply with invalid data like those sending
us login pages to authenticate with the network (e.g. hotels) back.

The good thing about the InRelease file is that we know that it must
be clearsigned (a Release file might or might not have a detached sig)
so if we get a file but are unable to split it something is seriously
wrong, so there is not much point in trying further.

The Acquire system already looks out for a NODATA error from gpgv,
so this adds a new error message sent to the acquire system in case
the splitting we do now ourselves failed including this magic word.

Closes: #712486
apt-pkg/contrib/gpgv.cc
apt-pkg/contrib/gpgv.h
debian/changelog
methods/gpgv.cc
test/integration/framework
test/integration/test-ubuntu-bug-346386-apt-get-update-paywall [new file with mode: 0755]
test/interactive-helper/aptwebserver.cc

index 31db7d5feb3bdd08b964f1be5f562d830607d992..f47e7ea4868f1334b7c7a5b7cbc1a5c41af690f2 100644 (file)
@@ -154,7 +154,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
         if (sigFd != -1)
            unlink(data);
         ioprintf(std::cerr, "Splitting up %s into data and signature failed", File.c_str());
-        exit(EINTERNAL);
+        exit(112);
       }
       Args.push_back(sig);
       Args.push_back(data);
index 08b10a97ac123c44d6555281c46710fc48cdd2a9..45f06905831bd86e9494a7e90e77323272f66e90 100644 (file)
 /** \brief generates and run the command to verify a file with gpgv
  *
  * If File and FileSig specify the same file it is assumed that we
- * deal with a clear-signed message. In that case the file will be
- * rewritten to be in a good-known format without uneeded whitespaces
- * and additional messages (unsigned or signed).
+ * deal with a clear-signed message. Note that the method will accept
+ * and validate files which include additional (unsigned) messages
+ * without complaining. Do NOT open files accepted by this method
+ * for reading. Use #OpenMaybeClearSignedFile to access the message
+ * instead to ensure you are only reading signed data.
+ *
+ * The method does not return, but has some noteable exit-codes:
+ * 111 signals an internal error like the inability to execute gpgv,
+ * 112 indicates a clear-signed file which doesn't include a message,
+ *  which can happen if APT is run while on a network requiring
+ *  authentication before usage (e.g. in hotels)
+ * All other exit-codes are passed-through from gpgv.
  *
  * @param File is the message (unsigned or clear-signed)
  * @param FileSig is the signature (detached or clear-signed)
index 91d4ae53607e7a4a58cc9fd78d483e967522690e..bd25df1e26f6e4a68ee3f2a2f67fd8922cd2e0ff 100644 (file)
@@ -20,6 +20,7 @@ apt (0.9.8.3) UNRELEASED; urgency=low
   * try defaults if auto-detection failed in apt-cdrom (Closes: #712433)
   * support \n and \r\n line endings in ReadMessages
   * do not redownload unchanged InRelease files
+  * trigger NODATA error for invalid InRelease files (Closes: #712486)
 
  -- David Kalnischkies <kalnischkies@gmail.com>  Sun, 09 Jun 2013 15:06:24 +0200
 
index 3f814b9f0aa5c394bca23ecc87e3c0ece12bfaee..fe8bac6c9e17634971113c75ed84f06a5640a439 100644 (file)
@@ -55,9 +55,6 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
                                         vector<string> &NoPubKeySigners)
 {
    bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
-   // setup a (empty) stringstream for formating the return value
-   std::stringstream ret;
-   ret.str("");
 
    if (Debug == true)
       std::clog << "inside VerifyGetSigners" << std::endl;
@@ -170,18 +167,19 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
       return "";
    }
    else if (WEXITSTATUS(status) == 1)
-   {
       return _("At least one invalid signature was encountered.");
-   }
    else if (WEXITSTATUS(status) == 111)
+      return _("Could not execute 'gpgv' to verify signature (is gpgv installed?)");
+   else if (WEXITSTATUS(status) == 112)
    {
-      ioprintf(ret, _("Could not execute 'gpgv' to verify signature (is gpgv installed?)"));
-      return ret.str();
+      // acquire system checks for "NODATA" to generate GPG errors (the others are only warnings)
+      std::string errmsg;
+      //TRANSLATORS: %s is a single techy word like 'NODATA'
+      strprintf(errmsg, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NODATA");
+      return errmsg;
    }
    else
-   {
       return _("Unknown error executing gpgv");
-   }
 }
 
 bool GPGVMethod::Fetch(FetchItem *Itm)
index 3f11ac23b65577d626435b6f0430090333d1f7c5..3a02cfb766a341bfc808cf40784cc4f32fb8e6d2 100644 (file)
@@ -118,6 +118,9 @@ gdb() {
        echo "gdb: run »$*«"
        APT_CONFIG=aptconfig.conf LD_LIBRARY_PATH=${BUILDDIRECTORY} $(which gdb) ${BUILDDIRECTORY}/$1
 }
+http() {
+       LD_LIBRARY_PATH=${BUILDDIRECTORY} ${BUILDDIRECTORY}/methods/http
+}
 
 exitwithstatus() {
         # error if we about to overflow, but ...
diff --git a/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall b/test/integration/test-ubuntu-bug-346386-apt-get-update-paywall
new file mode 100755 (executable)
index 0000000..1576c39
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/sh
+set -e
+
+TESTDIR=$(readlink -f $(dirname $0))
+. $TESTDIR/framework
+
+setupenvironment
+configarchitecture 'native'
+
+insertpackage 'unstable' 'unrelated' 'all' '1.0' 'stable'
+insertsource 'unstable' 'unrelated' 'all' '1.0' 'stable'
+
+echo 'ni ni ni' > aptarchive/knights
+
+setupaptarchive
+changetowebserver -o 'aptwebserver::overwrite::.*::filename=/knights'
+
+msgtest 'Acquire test file from the webserver to check' 'overwrite'
+echo '601 Configuration
+Config-Item: Acquire::http::DependOnSTDIN=0
+
+600 Acquire URI
+URI: http://localhost:8080/holygrail
+Filename: knights-talking
+' | http >/dev/null 2>&1 && msgpass || msgfail
+testfileequal knights-talking 'ni ni ni'
+
+ensure_n_canary_strings_in_dir() {
+       local DIR="$1"
+       local CANARY_STRING="$2"
+       local EXPECTED_N="$3"
+
+       msgtest "Testing in $DIR for $EXPECTED_N canary" "$CANARY_STRING"
+       local N=$(grep "$CANARY_STRING" $DIR/* 2>/dev/null |wc -l )
+       test "$N" = "$EXPECTED_N" && msgpass || msgfail "Expected $EXPECTED_N canaries, got $N"
+}
+
+LISTS='rootdir/var/lib/apt/lists'
+rm -rf rootdir/var/lib/apt/lists
+msgtest 'Got expected NODATA failure in' 'apt-get update'
+aptget update -qq 2>&1 | grep -q 'E: GPG error.*NODATA' && msgpass || msgfail
+
+ensure_n_canary_strings_in_dir $LISTS 'ni ni ni' 0
+testequal 'partial' ls $LISTS
+
+# and again with pre-existing files with "valid data" which should remain
+for f in Release Release.gpg main_binary-amd64_Packages main_source_Sources; do
+    echo 'peng neee-wom' > $LISTS/localhost:8080_dists_stable_${f}
+done
+
+msgtest 'Got expected NODATA failure in' 'apt-get update'
+aptget update -qq 2>&1 | grep -q 'E: GPG error.*NODATA' && msgpass || msgfail
+
+ensure_n_canary_strings_in_dir $LISTS 'peng neee-wom' 4
+ensure_n_canary_strings_in_dir $LISTS 'ni ni ni' 0
+
+# and now with a pre-existing InRelease file
+echo 'peng neee-wom' > $LISTS/localhost:8080_dists_stable_InRelease
+rm -f $LISTS/localhost:8080_dists_stable_Release $LISTS/localhost:8080_dists_stable_Release.gpg
+msgtest 'excpected failure of' 'apt-get update'
+aptget update -qq 2>&1 | grep -q 'E: GPG error.*NODATA' && msgpass || msgfail
+
+ensure_n_canary_strings_in_dir $LISTS 'peng neee-wom' 3
+ensure_n_canary_strings_in_dir $LISTS 'ni ni ni' 0
index de235fa0591ecb3063d22a5cbe790707b184e338..05b875673df6f985c8c50e1d6e6ff2050f950e3b 100644 (file)
@@ -435,6 +435,32 @@ int main(int const argc, const char * argv[])
               }
            }
 
+           ::Configuration::Item const *Overwrite = _config->Tree("aptwebserver::overwrite");
+           if (Overwrite != NULL)
+           {
+              for (::Configuration::Item *I = Overwrite->Child; I != NULL; I = I->Next)
+              {
+                 regex_t *pattern = new regex_t;
+                 int const res = regcomp(pattern, I->Tag.c_str(), REG_EXTENDED | REG_ICASE | REG_NOSUB);
+                 if (res != 0)
+                 {
+                    char error[300];
+                    regerror(res, pattern, error, sizeof(error));
+                    sendError(client, 500, *m, sendContent, error);
+                    continue;
+                 }
+                 if (regexec(pattern, filename.c_str(), 0, 0, 0) == 0)
+                 {
+                     filename = _config->Find("aptwebserver::overwrite::" + I->Tag + "::filename", filename);
+                     if (filename[0] == '/')
+                        filename.erase(0,1);
+                     regfree(pattern);
+                     break;
+                 }
+                 regfree(pattern);
+              }
+           }
+
            // deal with the request
            if (RealFileExists(filename) == true)
            {