]> git.saurik.com Git - apt.git/commitdiff
merged from davids bundle
authorMichael Vogt <michael.vogt@ubuntu.com>
Sat, 16 Mar 2013 08:15:46 +0000 (09:15 +0100)
committerMichael Vogt <michael.vogt@ubuntu.com>
Sat, 16 Mar 2013 08:15:46 +0000 (09:15 +0100)
12 files changed:
apt-pkg/acquire-item.cc
apt-pkg/contrib/gpgv.cc [new file with mode: 0644]
apt-pkg/contrib/gpgv.h [new file with mode: 0644]
apt-pkg/contrib/strutl.cc
apt-pkg/contrib/strutl.h
apt-pkg/deb/debmetaindex.cc
apt-pkg/indexcopy.cc
apt-pkg/indexcopy.h
apt-pkg/makefile
debian/changelog
methods/gpgv.cc
test/integration/test-ubuntu-bug-784473-InRelease-one-message-only

index a30e98858adf645763408442fc185ade9a1413e7..39b842dfb88af62b417718dc08c4b3b04714ff69 100644 (file)
@@ -1503,20 +1503,17 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
    if (AuthPass == true)
    {
       // gpgv method failed, if we have a good signature 
-      string LastGoodSigFile = _config->FindDir("Dir::State::lists");
-      if (DestFile == SigFile)
-        LastGoodSigFile.append(URItoFileName(RealURI));
-      else
-        LastGoodSigFile.append("partial/").append(URItoFileName(RealURI)).append(".gpg.reverify");
+      string LastGoodSigFile = _config->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI));
+      if (DestFile != SigFile)
+        LastGoodSigFile.append(".gpg");
+      LastGoodSigFile.append(".reverify");
 
       if(FileExists(LastGoodSigFile))
       {
+        string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
         if (DestFile != SigFile)
-        {
-           string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
-                                       URItoFileName(RealURI) + ".gpg";
-           Rename(LastGoodSigFile,VerifiedSigFile);
-        }
+           VerifiedSigFile.append(".gpg");
+        Rename(LastGoodSigFile, VerifiedSigFile);
         Status = StatTransientNetworkError;
         _error->Warning(_("A error occurred during the signature "
                           "verification. The repository is not updated "
@@ -1577,6 +1574,15 @@ pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire *Owner,                /*{{{*/
        MetaSigURI(MetaSigURI), MetaSigURIDesc(MetaSigURIDesc), MetaSigShortDesc(MetaSigShortDesc)
 {
    SigFile = DestFile;
+
+   // keep the old InRelease around in case of transistent network errors
+   string const Final = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI);
+   struct stat Buf;
+   if (stat(Final.c_str(),&Buf) == 0)
+   {
+      string const LastGoodSig = DestFile + ".reverify";
+      Rename(Final,LastGoodSig);
+   }
 }
                                                                        /*}}}*/
 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers        /*{{{*/
diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc
new file mode 100644 (file)
index 0000000..c236a72
--- /dev/null
@@ -0,0 +1,363 @@
+// -*- mode: cpp; mode: fold -*-
+// Include Files                                                       /*{{{*/
+#include<config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include<apt-pkg/configuration.h>
+#include<apt-pkg/error.h>
+#include<apt-pkg/strutl.h>
+#include<apt-pkg/fileutl.h>
+#include<apt-pkg/gpgv.h>
+
+#include <apti18n.h>
+                                                                       /*}}}*/
+char * GenerateTemporaryFileTemplate(const char *basename)             /*{{{*/
+{
+   const char *tmpdir = getenv("TMPDIR");
+#ifdef P_tmpdir
+   if (!tmpdir)
+      tmpdir = P_tmpdir;
+#endif
+   if (!tmpdir)
+      tmpdir = "/tmp";
+
+   std::string out;
+   strprintf(out,  "%s/%s.XXXXXX", tmpdir, basename);
+   return strdup(out.c_str());
+}
+                                                                       /*}}}*/
+// ExecGPGV - returns the command needed for verify                    /*{{{*/
+// ---------------------------------------------------------------------
+/* Generating the commandline for calling gpgv is somehow complicated as
+   we need to add multiple keyrings and user supplied options.
+   Also, as gpgv has no options to enforce a certain reduced style of
+   clear-signed files (=the complete content of the file is signed and
+   the content isn't encoded) we do a divide and conquer approach here
+*/
+void ExecGPGV(std::string const &File, std::string const &FileGPG,
+             int const &statusfd, int fd[2])
+{
+   #define EINTERNAL 111
+   std::string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
+   // FIXME: remove support for deprecated APT::GPGV setting
+   std::string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted"));
+   std::string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
+
+   bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
+
+   if (Debug == true)
+   {
+      std::clog << "gpgv path: " << gpgvpath << std::endl;
+      std::clog << "Keyring file: " << trustedFile << std::endl;
+      std::clog << "Keyring path: " << trustedPath << std::endl;
+   }
+
+   std::vector<std::string> keyrings;
+   if (DirectoryExists(trustedPath))
+     keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
+   if (RealFileExists(trustedFile) == true)
+     keyrings.push_back(trustedFile);
+
+   std::vector<const char *> Args;
+   Args.reserve(30);
+
+   if (keyrings.empty() == true)
+   {
+      // TRANSLATOR: %s is the trusted keyring parts directory
+      ioprintf(std::cerr, _("No keyring installed in %s."),
+           _config->FindDir("Dir::Etc::TrustedParts").c_str());
+      exit(EINTERNAL);
+   }
+
+   Args.push_back(gpgvpath.c_str());
+   Args.push_back("--ignore-time-conflict");
+
+   char statusfdstr[10];
+   if (statusfd != -1)
+   {
+      Args.push_back("--status-fd");
+      snprintf(statusfdstr, sizeof(statusfdstr), "%i", statusfd);
+      Args.push_back(statusfdstr);
+   }
+
+   for (std::vector<std::string>::const_iterator K = keyrings.begin();
+       K != keyrings.end(); ++K)
+   {
+      Args.push_back("--keyring");
+      Args.push_back(K->c_str());
+   }
+
+   Configuration::Item const *Opts;
+   Opts = _config->Tree("Acquire::gpgv::Options");
+   if (Opts != 0)
+   {
+      Opts = Opts->Child;
+      for (; Opts != 0; Opts = Opts->Next)
+      {
+        if (Opts->Value.empty() == true)
+           continue;
+        Args.push_back(Opts->Value.c_str());
+      }
+   }
+
+   int sigFd = -1;
+   int dataFd = -1;
+   std::vector<std::string> dataHeader;
+   char * sig = NULL;
+   char * data = NULL;
+
+   // file with detached signature
+   if (FileGPG != File)
+   {
+      Args.push_back(FileGPG.c_str());
+      Args.push_back(File.c_str());
+   }
+   else // clear-signed file
+   {
+      sig = GenerateTemporaryFileTemplate("apt.sig");
+      data = GenerateTemporaryFileTemplate("apt.data");
+      if (sig == NULL || data == NULL)
+      {
+        ioprintf(std::cerr, "Couldn't create tempfiles for splitting up %s", File.c_str());
+        exit(EINTERNAL);
+      }
+
+      sigFd = mkstemp(sig);
+      dataFd = mkstemp(data);
+      int const duppedSigFd = dup(sigFd);
+      int const duppedDataFd = dup(dataFd);
+
+      if (dataFd == -1 || sigFd == -1 || duppedDataFd == -1 || duppedSigFd == -1 ||
+           SplitClearSignedFile(File, duppedDataFd, &dataHeader, duppedSigFd) == false)
+      {
+        if (dataFd != -1)
+           unlink(sig);
+        if (sigFd != -1)
+           unlink(data);
+        ioprintf(std::cerr, "Splitting up %s into data and signature failed", File.c_str());
+        exit(EINTERNAL);
+      }
+      lseek(dataFd, 0, SEEK_SET);
+      lseek(sigFd, 0, SEEK_SET);
+      Args.push_back(sig);
+      Args.push_back(data);
+   }
+
+   Args.push_back(NULL);
+
+   if (Debug == true)
+   {
+      std::clog << "Preparing to exec: " << gpgvpath;
+      for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
+        std::clog << " " << *a;
+      std::clog << std::endl;
+   }
+
+   if (statusfd != -1)
+   {
+      int const nullfd = open("/dev/null", O_RDONLY);
+      close(fd[0]);
+      // Redirect output to /dev/null; we read from the status fd
+      if (statusfd != STDOUT_FILENO)
+        dup2(nullfd, STDOUT_FILENO);
+      if (statusfd != STDERR_FILENO)
+        dup2(nullfd, STDERR_FILENO);
+      // Redirect the pipe to the status fd (3)
+      dup2(fd[1], statusfd);
+
+      putenv((char *)"LANG=");
+      putenv((char *)"LC_ALL=");
+      putenv((char *)"LC_MESSAGES=");
+   }
+
+   if (FileGPG != File)
+   {
+      execvp(gpgvpath.c_str(), (char **) &Args[0]);
+      ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str());
+      exit(EINTERNAL);
+   }
+   else
+   {
+//#define UNLINK_EXIT(X) exit(X)
+#define UNLINK_EXIT(X) unlink(sig);unlink(data);exit(X)
+
+      // for clear-signed files we have created tempfiles we have to clean up
+      // and we do an additional check, so fork yet another time …
+      pid_t pid = ExecFork();
+      if(pid < 0) {
+        ioprintf(std::cerr, "Fork failed for %s to check %s", Args[0], File.c_str());
+        UNLINK_EXIT(EINTERNAL);
+      }
+      if(pid == 0)
+      {
+        if (statusfd != -1)
+           dup2(fd[1], statusfd);
+        execvp(gpgvpath.c_str(), (char **) &Args[0]);
+        ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str());
+        UNLINK_EXIT(EINTERNAL);
+      }
+
+      // Wait and collect the error code - taken from WaitPid as we need the exact Status
+      int Status;
+      while (waitpid(pid,&Status,0) != pid)
+      {
+        if (errno == EINTR)
+           continue;
+        ioprintf(std::cerr, _("Waited for %s but it wasn't there"), "gpgv");
+        UNLINK_EXIT(EINTERNAL);
+      }
+
+      // check if it exit'ed normally …
+      if (WIFEXITED(Status) == false)
+      {
+        ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "gpgv");
+        UNLINK_EXIT(EINTERNAL);
+      }
+
+      // … and with a good exit code
+      if (WEXITSTATUS(Status) != 0)
+      {
+        ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "gpgv", WEXITSTATUS(Status));
+        UNLINK_EXIT(WEXITSTATUS(Status));
+      }
+
+      /* looks like its fine. Our caller will check the status fd,
+        but we construct a good-known clear-signed file without garbage
+        and other non-sense. In a perfect world, we get the same file,
+        but empty lines, trailing whitespaces and stuff makes it inperfect … */
+      if (RecombineToClearSignedFile(File, dataFd, dataHeader, sigFd) == false)
+      {
+        _error->DumpErrors(std::cerr);
+        UNLINK_EXIT(EINTERNAL);
+      }
+
+      // everything fine, we have a clean file now!
+      UNLINK_EXIT(0);
+#undef UNLINK_EXIT
+   }
+   exit(EINTERNAL); // unreachable safe-guard
+}
+                                                                       /*}}}*/
+// RecombineToClearSignedFile - combine data/signature to message      /*{{{*/
+bool RecombineToClearSignedFile(std::string const &OutFile, int const ContentFile,
+      std::vector<std::string> const &ContentHeader, int const SignatureFile)
+{
+   FILE *clean_file = fopen(OutFile.c_str(), "w");
+   fputs("-----BEGIN PGP SIGNED MESSAGE-----\n", clean_file);
+   for (std::vector<std::string>::const_iterator h = ContentHeader.begin(); h != ContentHeader.end(); ++h)
+      fprintf(clean_file, "%s\n", h->c_str());
+   fputs("\n", clean_file);
+
+   FILE *data_file = fdopen(ContentFile, "r");
+   FILE *sig_file = fdopen(SignatureFile, "r");
+   if (data_file == NULL || sig_file == NULL)
+      return _error->Error("Couldn't open splitfiles to recombine them into %s", OutFile.c_str());
+   char *buf = NULL;
+   size_t buf_size = 0;
+   while (getline(&buf, &buf_size, data_file) != -1)
+      fputs(buf, clean_file);
+   fclose(data_file);
+   fputs("\n", clean_file);
+   while (getline(&buf, &buf_size, sig_file) != -1)
+      fputs(buf, clean_file);
+   fclose(sig_file);
+   fclose(clean_file);
+   return true;
+}
+                                                                       /*}}}*/
+// SplitClearSignedFile - split message into data/signature            /*{{{*/
+bool SplitClearSignedFile(std::string const &InFile, int const ContentFile,
+      std::vector<std::string> * const ContentHeader, int const SignatureFile)
+{
+   FILE *in = fopen(InFile.c_str(), "r");
+   if (in == NULL)
+      return _error->Errno("fopen", "can not open %s", InFile.c_str());
+
+   FILE *out_content = NULL;
+   FILE *out_signature = NULL;
+   if (ContentFile != -1)
+   {
+      out_content = fdopen(ContentFile, "w");
+      if (out_content == NULL)
+        return _error->Errno("fdopen", "Failed to open file to write content to from %s", InFile.c_str());
+   }
+   if (SignatureFile != -1)
+   {
+      out_signature = fdopen(SignatureFile, "w");
+      if (out_signature == NULL)
+        return _error->Errno("fdopen", "Failed to open file to write signature to from %s", InFile.c_str());
+   }
+
+   bool found_message_start = false;
+   bool found_message_end = false;
+   bool skip_until_empty_line = false;
+   bool found_signature = false;
+   bool first_line = true;
+
+   char *buf = NULL;
+   size_t buf_size = 0;
+   while (getline(&buf, &buf_size, in) != -1)
+   {
+      _strrstrip(buf);
+      if (found_message_start == false)
+      {
+        if (strcmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----") == 0)
+        {
+           found_message_start = true;
+           skip_until_empty_line = true;
+        }
+      }
+      else if (skip_until_empty_line == true)
+      {
+        if (strlen(buf) == 0)
+           skip_until_empty_line = false;
+        // save "Hash" Armor Headers, others aren't allowed
+        else if (ContentHeader != NULL && strncmp(buf, "Hash: ", strlen("Hash: ")) == 0)
+           ContentHeader->push_back(buf);
+      }
+      else if (found_signature == false)
+      {
+        if (strcmp(buf, "-----BEGIN PGP SIGNATURE-----") == 0)
+        {
+           found_signature = true;
+           found_message_end = true;
+           if (out_signature != NULL)
+              fprintf(out_signature, "%s\n", buf);
+        }
+        else if (found_message_end == false)
+        {
+           // we are in the message block
+           if(first_line == true) // first line does not need a newline
+           {
+              if (out_content != NULL)
+                 fprintf(out_content, "%s", buf);
+              first_line = false;
+           }
+           else if (out_content != NULL)
+              fprintf(out_content, "\n%s", buf);
+        }
+      }
+      else if (found_signature == true)
+      {
+        if (out_signature != NULL)
+           fprintf(out_signature, "%s\n", buf);
+        if (strcmp(buf, "-----END PGP SIGNATURE-----") == 0)
+           found_signature = false; // look for other signatures
+      }
+      // all the rest is whitespace, unsigned garbage or additional message blocks we ignore
+   }
+   if (out_content != NULL)
+      fclose(out_content);
+   if (out_signature != NULL)
+      fclose(out_signature);
+
+   return true;
+}
diff --git a/apt-pkg/contrib/gpgv.h b/apt-pkg/contrib/gpgv.h
new file mode 100644 (file)
index 0000000..8e04855
--- /dev/null
@@ -0,0 +1,77 @@
+// -*- mode: cpp; mode: fold -*-
+// Description                                                         /*{{{*/
+/* ######################################################################
+
+   Helpers to deal with gpgv better and more easily
+
+   ##################################################################### */
+                                                                       /*}}}*/
+#ifndef CONTRIB_GPGV_H
+#define CONTRIB_GPGV_H
+
+#include <string>
+#include <vector>
+
+#if __GNUC__ >= 4
+       #define APT_noreturn    __attribute__ ((noreturn))
+#else
+       #define APT_noreturn    /* no support */
+#endif
+
+/** \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).
+ *
+ * @param File is the message (unsigned or clear-signed)
+ * @param FileSig is the signature (detached or clear-signed)
+ */
+void ExecGPGV(std::string const &File, std::string const &FileSig,
+      int const &statusfd, int fd[2]) APT_noreturn;
+inline void ExecGPGV(std::string const &File, std::string const &FileSig,
+      int const &statusfd = -1) {
+   int fd[2];
+   ExecGPGV(File, FileSig, statusfd, fd);
+};
+
+#undef APT_noreturn
+
+/** \brief Split an inline signature into message and signature
+ *
+ *  Takes a clear-signed message and puts the first signed message
+ *  in the content file and all signatures following it into the
+ *  second. Unsigned messages, additional messages as well as
+ *  whitespaces are discarded. The resulting files are suitable to
+ *  be checked with gpgv.
+ *
+ *  If one or all Fds are -1 they will not be used and the content
+ *  which would have been written to them is discarded.
+ *
+ *  The code doesn't support dash-encoded lines as these are not
+ *  expected to be present in files we have to deal with.
+ *
+ *  @param InFile is the clear-signed file
+ *  @param ContentFile is the Fd the message will be written to
+ *  @param ContentHeader is a list of all required Amored Headers for the message
+ *  @param SignatureFile is the Fd all signatures will be written to
+ */
+bool SplitClearSignedFile(std::string const &InFile, int const ContentFile,
+      std::vector<std::string> * const ContentHeader, int const SignatureFile);
+
+/** \brief recombines message and signature to an inline signature
+ *
+ *  Reverses the splitting down by #SplitClearSignedFile by writing
+ *  a well-formed clear-signed message without unsigned messages,
+ *  additional signed messages or just trailing whitespaces
+ *
+ *  @param OutFile will be clear-signed file
+ *  @param ContentFile is the Fd the message will be read from
+ *  @param ContentHeader is a list of all required Amored Headers for the message
+ *  @param SignatureFile is the Fd all signatures will be read from
+ */
+bool RecombineToClearSignedFile(std::string const &OutFile, int const ContentFile,
+      std::vector<std::string> const &ContentHeader, int const SignatureFile);
+
+#endif
index ca096d73613aa7b277a3a8affa554f0937e37b14..9726138a0fc25bedebb2b17e9c8fd9fb2a357ad3 100644 (file)
@@ -117,7 +117,13 @@ char *_strstrip(char *String)
 
    if (*String == 0)
       return String;
-
+   return _strrstrip(String);
+}
+                                                                       /*}}}*/
+// strrstrip - Remove white space from the back of a string    /*{{{*/
+// ---------------------------------------------------------------------
+char *_strrstrip(char *String)
+{
    char *End = String + strlen(String) - 1;
    for (;End != String - 1 && (*End == ' ' || *End == '\t' || *End == '\n' ||
                               *End == '\r'); End--);
index 337139d5d53050ff746221f23d2e714ef54da590..e92f91dc0907ca102f17d90981e781ce355b23bf 100644 (file)
@@ -35,6 +35,7 @@ using std::ostream;
 
 bool UTF8ToCodeset(const char *codeset, const std::string &orig, std::string *dest);
 char *_strstrip(char *String);
+char *_strrstrip(char *String); // right strip only
 char *_strtabexpand(char *String,size_t Len);
 bool ParseQuoteWord(const char *&String,std::string &Res);
 bool ParseCWord(const char *&String,std::string &Res);
index 6c191fd953e2c61ccd0ecf63ec0278fc39b6acf3..7a88d71e3e36be9e22dc4878dd7f10e3cc0b308b 100644 (file)
@@ -229,6 +229,8 @@ vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
                                                                        /*}}}*/
 bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 {
+   bool const tryInRelease = _config->FindB("Acquire::TryInRelease", true);
+
    // special case for --print-uris
    if (GetAll) {
       vector <struct IndexTarget *> *targets = ComputeIndexTargets();
@@ -239,18 +241,27 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool const &GetAll) const
 
       // this is normally created in pkgAcqMetaSig, but if we run
       // in --print-uris mode, we add it here
-      new pkgAcqMetaIndex(Owner, MetaIndexURI("Release"),
-                         MetaIndexInfo("Release"), "Release",
-                         MetaIndexURI("Release.gpg"),
-                         ComputeIndexTargets(),
-                         new indexRecords (Dist));
+      if (tryInRelease == false)
+        new pkgAcqMetaIndex(Owner, MetaIndexURI("Release"),
+              MetaIndexInfo("Release"), "Release",
+              MetaIndexURI("Release.gpg"),
+              ComputeIndexTargets(),
+              new indexRecords (Dist));
    }
 
-   new pkgAcqMetaSig(Owner, MetaIndexURI("Release.gpg"),
-                    MetaIndexInfo("Release.gpg"), "Release.gpg",
-                    MetaIndexURI("Release"), MetaIndexInfo("Release"), "Release",
-                    ComputeIndexTargets(),
-                    new indexRecords (Dist));
+   if (tryInRelease == true)
+      new pkgAcqMetaClearSig(Owner, MetaIndexURI("InRelease"),
+           MetaIndexInfo("InRelease"), "InRelease",
+           MetaIndexURI("Release"), MetaIndexInfo("Release"), "Release",
+           MetaIndexURI("Release.gpg"), MetaIndexInfo("Release.gpg"), "Release.gpg",
+           ComputeIndexTargets(),
+           new indexRecords (Dist));
+   else
+      new pkgAcqMetaSig(Owner, MetaIndexURI("Release.gpg"),
+           MetaIndexInfo("Release.gpg"), "Release.gpg",
+           MetaIndexURI("Release"), MetaIndexInfo("Release"), "Release",
+           ComputeIndexTargets(),
+           new indexRecords (Dist));
 
    return true;
 }
index aa1f01a4a799b263ccf4d1c1c53ed91952509ee8..f53989bdbf34aca20a902f2e5a60870fff45259b 100644 (file)
@@ -593,9 +593,9 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       if(pid == 0)
       {
         if (useInRelease == true)
-           RunGPGV(inrelease, inrelease);
+           ExecGPGV(inrelease, inrelease);
         else
-           RunGPGV(release, releasegpg);
+           ExecGPGV(release, releasegpg);
       }
 
       if(!ExecWait(pid, "gpgv")) {
@@ -639,124 +639,6 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
       }
    }   
 
-   return true;
-}
-                                                                       /*}}}*/
-// SigVerify::RunGPGV - returns the command needed for verify          /*{{{*/
-// ---------------------------------------------------------------------
-/* Generating the commandline for calling gpgv is somehow complicated as
-   we need to add multiple keyrings and user supplied options. Also, as
-   the cdrom code currently can not use the gpgv method we have two places
-   these need to be done - so the place for this method is wrong but better
-   than code duplication… */
-bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
-                       int const &statusfd, int fd[2])
-{
-   if (File == FileGPG)
-   {
-      #define SIGMSG "-----BEGIN PGP SIGNED MESSAGE-----\n"
-      char buffer[sizeof(SIGMSG)];
-      FILE* gpg = fopen(File.c_str(), "r");
-      if (gpg == NULL)
-        return _error->Errno("RunGPGV", _("Could not open file %s"), File.c_str());
-      char const * const test = fgets(buffer, sizeof(buffer), gpg);
-      fclose(gpg);
-      if (test == NULL || strcmp(buffer, SIGMSG) != 0)
-        return _error->Error(_("File %s doesn't start with a clearsigned message"), File.c_str());
-      #undef SIGMSG
-   }
-
-
-   string const gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv");
-   // FIXME: remove support for deprecated APT::GPGV setting
-   string const trustedFile = _config->Find("APT::GPGV::TrustedKeyring", _config->FindFile("Dir::Etc::Trusted"));
-   string const trustedPath = _config->FindDir("Dir::Etc::TrustedParts");
-
-   bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
-
-   if (Debug == true)
-   {
-      std::clog << "gpgv path: " << gpgvpath << std::endl;
-      std::clog << "Keyring file: " << trustedFile << std::endl;
-      std::clog << "Keyring path: " << trustedPath << std::endl;
-   }
-
-   std::vector<string> keyrings;
-   if (DirectoryExists(trustedPath))
-     keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
-   if (RealFileExists(trustedFile) == true)
-     keyrings.push_back(trustedFile);
-
-   std::vector<const char *> Args;
-   Args.reserve(30);
-
-   if (keyrings.empty() == true)
-   {
-      // TRANSLATOR: %s is the trusted keyring parts directory
-      return _error->Error(_("No keyring installed in %s."),
-                          _config->FindDir("Dir::Etc::TrustedParts").c_str());
-   }
-
-   Args.push_back(gpgvpath.c_str());
-   Args.push_back("--ignore-time-conflict");
-
-   if (statusfd != -1)
-   {
-      Args.push_back("--status-fd");
-      char fd[10];
-      snprintf(fd, sizeof(fd), "%i", statusfd);
-      Args.push_back(fd);
-   }
-
-   for (vector<string>::const_iterator K = keyrings.begin();
-       K != keyrings.end(); ++K)
-   {
-      Args.push_back("--keyring");
-      Args.push_back(K->c_str());
-   }
-
-   Configuration::Item const *Opts;
-   Opts = _config->Tree("Acquire::gpgv::Options");
-   if (Opts != 0)
-   {
-      Opts = Opts->Child;
-      for (; Opts != 0; Opts = Opts->Next)
-      {
-        if (Opts->Value.empty() == true)
-           continue;
-        Args.push_back(Opts->Value.c_str());
-      }
-   }
-
-   Args.push_back(FileGPG.c_str());
-   if (FileGPG != File)
-      Args.push_back(File.c_str());
-   Args.push_back(NULL);
-
-   if (Debug == true)
-   {
-      std::clog << "Preparing to exec: " << gpgvpath;
-      for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a)
-        std::clog << " " << *a;
-      std::clog << std::endl;
-   }
-
-   if (statusfd != -1)
-   {
-      int const nullfd = open("/dev/null", O_RDONLY);
-      close(fd[0]);
-      // Redirect output to /dev/null; we read from the status fd
-      dup2(nullfd, STDOUT_FILENO);
-      dup2(nullfd, STDERR_FILENO);
-      // Redirect the pipe to the status fd (3)
-      dup2(fd[1], statusfd);
-
-      putenv((char *)"LANG=");
-      putenv((char *)"LC_ALL=");
-      putenv((char *)"LC_MESSAGES=");
-   }
-
-   execvp(gpgvpath.c_str(), (char **) &Args[0]);
    return true;
 }
                                                                        /*}}}*/
index e3de1afd97f1f6454d1a20ec43bd8802fadbc164..aa221158ec0569150d3bb6198a9e40a67046ffd3 100644 (file)
@@ -14,6 +14,9 @@
 #include <string>
 #include <stdio.h>
 
+#include <apt-pkg/gpgv.h>
+#include <apt-pkg/macros.h>
+
 #ifndef APT_8_CLEANER_HEADERS
 using std::string;
 using std::vector;
@@ -96,13 +99,15 @@ class SigVerify                                                             /*{{{*/
    bool CopyAndVerify(std::string CDROM,std::string Name,std::vector<std::string> &SigList,
                      std::vector<std::string> PkgList,std::vector<std::string> SrcList);
 
-   /** \brief generates and run the command to verify a file with gpgv */
-   static bool RunGPGV(std::string const &File, std::string const &FileOut,
-                      int const &statusfd, int fd[2]);
-   inline static bool RunGPGV(std::string const &File, std::string const &FileOut,
+   __deprecated static bool RunGPGV(std::string const &File, std::string const &FileOut,
+                      int const &statusfd, int fd[2]) {
+      ExecGPGV(File, FileOut, statusfd, fd);
+      return false;
+   };
+   __deprecated static bool RunGPGV(std::string const &File, std::string const &FileOut,
                              int const &statusfd = -1) {
-      int fd[2];
-      return RunGPGV(File, FileOut, statusfd, fd);
+      ExecGPGV(File, FileOut, statusfd);
+      return false;
    };
 };
                                                                        /*}}}*/
index 27d7ead2485d15c8d273286a86955a26f1ebb919..59729faf51d3bec540386a3e7970f85d809811ad 100644 (file)
@@ -27,15 +27,13 @@ APT_DOMAIN:=libapt-pkg$(LIBAPTPKG_MAJOR)
 SOURCE = contrib/mmap.cc contrib/error.cc contrib/strutl.cc \
          contrib/configuration.cc contrib/progress.cc contrib/cmndline.cc \
         contrib/hashsum.cc contrib/md5.cc contrib/sha1.cc \
-        contrib/sha2_internal.cc\
-         contrib/hashes.cc \
+        contrib/sha2_internal.cc contrib/hashes.cc \
         contrib/cdromutl.cc contrib/crc-16.cc contrib/netrc.cc \
-        contrib/fileutl.cc 
-HEADERS = mmap.h error.h configuration.h fileutl.h  cmndline.h netrc.h\
-         md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha2.h sha256.h\
-         sha2_internal.h \
-          hashes.h hashsum_template.h\
-         macros.h weakptr.h
+        contrib/fileutl.cc contrib/gpgv.cc
+HEADERS = mmap.h error.h configuration.h fileutl.h cmndline.h netrc.h \
+         md5.h crc-16.h cdromutl.h strutl.h sptr.h sha1.h sha2.h sha256.h \
+         sha2_internal.h hashes.h hashsum_template.h \
+         macros.h weakptr.h gpgv.h
 
 # Source code for the core main library
 SOURCE+= pkgcache.cc version.cc depcache.cc \
index 9ed9b4d616f3856b6ebbcdd0d3232d0a9467d0c7..7ebbb1cb4c9a5f87f3c4a5d3dc99dc76eae67760 100644 (file)
@@ -1,3 +1,25 @@
+apt (0.9.7.9) UNRELEASED; urgency=low
+
+  [ David Kalnischkies ]
+  * apt-pkg/indexcopy.cc:
+    - rename RunGPGV to ExecGPGV and move it to apt-pkg/contrib/gpgv.cc
+  * apt-pkg/contrib/gpgv.cc:
+    - ExecGPGV is a method which should never return, so mark it as such
+      and fix the inconsistency of returning in error cases
+    - don't close stdout/stderr if it is also the statusfd
+    - if ExecGPGV deals with a clear-signed file it will split this file
+      into data and signatures, pass it to gpgv for verification and
+      recombines it after that in a known-good way without unsigned blocks
+      and whitespaces resulting usually in more or less the same file as
+      before, but later code can be sure about the format
+  * apt-pkg/acquire-item.cc:
+    - keep the last good InRelease file around just as we do it with
+      Release.gpg in case the new one we download isn't good for us
+  * apt-pkg/deb/debmetaindex.cc:
+    - reenable InRelease by default
+
+ -- David Kalnischkies <kalnischkies@gmail.com>  Fri, 15 Mar 2013 14:15:43 +0100
+
 apt (0.9.7.8) unstable; urgency=criticial
 
   * SECURITY UPDATE: InRelease verification bypass
index 25ba0d06350e433701b85add7c392201c36b65c7..3f814b9f0aa5c394bca23ecc87e3c0ece12bfaee 100644 (file)
@@ -6,6 +6,7 @@
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/indexcopy.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/gpgv.h>
 
 #include <utime.h>
 #include <stdio.h>
@@ -70,19 +71,7 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile,
    if (pid < 0)
       return string("Couldn't spawn new process") + strerror(errno);
    else if (pid == 0)
-   {
-      _error->PushToStack();
-      bool const success = SigVerify::RunGPGV(outfile, file, 3, fd);
-      if (success == false)
-      {
-        string errmsg;
-        _error->PopMessage(errmsg);
-        _error->RevertToStack();
-        return errmsg;
-      }
-      _error->RevertToStack();
-      exit(111);
-   }
+      ExecGPGV(outfile, file, 3, fd);
    close(fd[1]);
 
    FILE *pipein = fdopen(fd[0], "r");
index d97011914054b9f2d131e5508c1d1dc983eef790..fad5488fb62d0d9d0efd1389d0eb9e842b7a5090 100755 (executable)
@@ -26,6 +26,14 @@ MD5Sum:
  2182897e0a2a0c09e760beaae117a015     2023 Packages.diff/Index
  1b895931853981ad8204d2439821b999     4144 Packages.gz'; echo; cat ${RELEASE}.old;) > ${RELEASE}
 done
-aptget update -qq > /dev/null 2> starts-with-unsigned.msg
-sed -i 's#File .*InRelease#File InRelease#' starts-with-unsigned.msg
-testfileequal starts-with-unsigned.msg "W: GPG error: file: unstable InRelease: File InRelease doesn't start with a clearsigned message"
+
+msgtest 'The unsigned garbage before signed block is' 'ignored'
+aptget update -qq > /dev/null 2>&1 && msgpass || msgfail
+
+ROOTDIR="$(readlink -f .)"
+testequal "Package files:
+ 100 ${ROOTDIR}/rootdir/var/lib/dpkg/status
+     release a=now
+ 500 file:${ROOTDIR}/aptarchive/ unstable/main i386 Packages
+     release a=unstable,n=unstable,c=main
+Pinned packages:" aptcache policy