]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/contrib/gpgv.cc
Don't download "optional" files not in Release :/.
[apt.git] / apt-pkg / contrib / gpgv.cc
index 9d798cca986713faf5bbbeb9cc94ea9e799bfd24..856d56bc1bca9048e5ff41c300adaa4c08cc5794 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 #include <stddef.h>
+
+#include <algorithm>
+#include <fstream>
 #include <iostream>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -41,13 +45,62 @@ static char * GenerateTemporaryFileTemplate(const char *basename)   /*{{{*/
    And as a cherry on the cake, we use our apt-key wrapper to do part
    of the lifting in regards to merging keyrings. Fun for the whole family.
 */
+static bool iovprintf(std::ostream &out, const char *format,
+                     va_list &args, ssize_t &size) {
+   char *S = (char*)malloc(size);
+   ssize_t const n = vsnprintf(S, size, format, args);
+   if (n > -1 && n < size) {
+      out << S;
+      free(S);
+      return true;
+   } else {
+      if (n > -1)
+        size = n + 1;
+      else
+        size *= 2;
+   }
+   free(S);
+   return false;
+}
+static void APT_PRINTF(4) apt_error(std::ostream &outterm, int const statusfd, int fd[2], const char *format, ...)
+{
+   std::ostringstream outstr;
+   std::ostream &out = (statusfd == -1) ? outterm : outstr;
+   va_list args;
+   ssize_t size = 400;
+   while (true) {
+      bool ret;
+      va_start(args,format);
+      ret = iovprintf(out, format, args, size);
+      va_end(args);
+      if (ret == true)
+        break;
+   }
+   if (statusfd != -1)
+   {
+      auto const errtag = "[APTKEY:] ERROR ";
+      outstr << '\n';
+      auto const errtext = outstr.str();
+      if (FileFd::Write(fd[1], errtag, strlen(errtag)) == false ||
+           FileFd::Write(fd[1], errtext.data(), errtext.size()) == false)
+        outterm << errtext << std::flush;
+   }
+}
 void ExecGPGV(std::string const &File, std::string const &FileGPG,
-             int const &statusfd, int fd[2])
+             int const &statusfd, int fd[2], std::string const &key)
 {
    #define EINTERNAL 111
-   std::string const aptkey = _config->FindFile("Dir::Bin::apt-key", "/usr/bin/apt-key");
+   std::string const aptkey = _config->Find("Dir::Bin::apt-key", CMAKE_INSTALL_FULL_BINDIR "/apt-key");
 
    bool const Debug = _config->FindB("Debug::Acquire::gpgv", false);
+   struct exiter {
+      std::vector<const char *> files;
+      void operator ()(int code) APT_NORETURN {
+        std::for_each(files.begin(), files.end(), unlink);
+        exit(code);
+      }
+   } local_exit;
+
 
    std::vector<const char *> Args;
    Args.reserve(10);
@@ -55,6 +108,19 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
    Args.push_back(aptkey.c_str());
    Args.push_back("--quiet");
    Args.push_back("--readonly");
+   if (key.empty() == false)
+   {
+      if (key[0] == '/')
+      {
+        Args.push_back("--keyring");
+        Args.push_back(key.c_str());
+      }
+      else
+      {
+        Args.push_back("--keyid");
+        Args.push_back(key.c_str());
+      }
+   }
    Args.push_back("verify");
 
    char statusfdstr[10];
@@ -82,6 +148,28 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
    std::vector<std::string> dataHeader;
    char * sig = NULL;
    char * data = NULL;
+   char * conf = nullptr;
+
+   // Dump the configuration so apt-key picks up the correct Dir values
+   {
+      conf = GenerateTemporaryFileTemplate("apt.conf");
+      if (conf == nullptr) {
+        apt_error(std::cerr, statusfd, fd, "Couldn't create tempfile names for passing config to apt-key");
+        local_exit(EINTERNAL);
+      }
+      int confFd = mkstemp(conf);
+      if (confFd == -1) {
+        apt_error(std::cerr, statusfd, fd, "Couldn't create temporary file %s for passing config to apt-key", conf);
+        local_exit(EINTERNAL);
+      }
+      local_exit.files.push_back(conf);
+
+      std::ofstream confStream(conf);
+      close(confFd);
+      _config->Dump(confStream);
+      confStream.close();
+      setenv("APT_CONFIG", conf, 1);
+   }
 
    if (releaseSignature == DETACHED)
    {
@@ -94,20 +182,20 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       data = GenerateTemporaryFileTemplate("apt.data");
       if (sig == NULL || data == NULL)
       {
-        ioprintf(std::cerr, "Couldn't create tempfile names for splitting up %s", File.c_str());
-        exit(EINTERNAL);
+        apt_error(std::cerr, statusfd, fd, "Couldn't create tempfile names for splitting up %s", File.c_str());
+        local_exit(EINTERNAL);
       }
 
       int const sigFd = mkstemp(sig);
       int const dataFd = mkstemp(data);
+      if (dataFd != -1)
+        local_exit.files.push_back(data);
+      if (sigFd != -1)
+        local_exit.files.push_back(sig);
       if (sigFd == -1 || dataFd == -1)
       {
-        if (dataFd != -1)
-           unlink(sig);
-        if (sigFd != -1)
-           unlink(data);
-        ioprintf(std::cerr, "Couldn't create tempfiles for splitting up %s", File.c_str());
-        exit(EINTERNAL);
+        apt_error(std::cerr, statusfd, fd, "Couldn't create tempfiles for splitting up %s", File.c_str());
+        local_exit(EINTERNAL);
       }
 
       FileFd signature;
@@ -118,12 +206,8 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       if (signature.Failed() == true || message.Failed() == true ||
            SplitClearSignedFile(File, &message, &dataHeader, &signature) == 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(112);
+        apt_error(std::cerr, statusfd, fd, "Splitting up %s into data and signature failed", File.c_str());
+        local_exit(112);
       }
       Args.push_back(sig);
       Args.push_back(data);
@@ -156,67 +240,50 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG,
       putenv((char *)"LC_MESSAGES=");
    }
 
-   if (releaseSignature == DETACHED)
+
+   // 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) {
+      apt_error(std::cerr, statusfd, fd, "Fork failed for %s to check %s", Args[0], File.c_str());
+      local_exit(EINTERNAL);
+   }
+   if(pid == 0)
    {
+      if (statusfd != -1)
+        dup2(fd[1], statusfd);
       execvp(Args[0], (char **) &Args[0]);
-      ioprintf(std::cerr, "Couldn't execute %s to check %s", Args[0], File.c_str());
-      exit(EINTERNAL);
+      apt_error(std::cerr, statusfd, fd, "Couldn't execute %s to check %s", Args[0], File.c_str());
+      local_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(Args[0], (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"), "apt-key");
-        UNLINK_EXIT(EINTERNAL);
-      }
-#undef UNLINK_EXIT
-      // we don't need the files any longer
-      unlink(sig);
-      unlink(data);
-      free(sig);
-      free(data);
-
-      // check if it exit'ed normally …
-      if (WIFEXITED(Status) == false)
-      {
-        ioprintf(std::cerr, _("Sub-process %s exited unexpectedly"), "apt-key");
-        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;
+      apt_error(std::cerr, statusfd, fd, _("Waited for %s but it wasn't there"), "apt-key");
+      local_exit(EINTERNAL);
+   }
 
-      // … and with a good exit code
-      if (WEXITSTATUS(Status) != 0)
-      {
-        ioprintf(std::cerr, _("Sub-process %s returned an error code (%u)"), "apt-key", WEXITSTATUS(Status));
-        exit(WEXITSTATUS(Status));
-      }
+   // check if it exit'ed normally …
+   if (WIFEXITED(Status) == false)
+   {
+      apt_error(std::cerr, statusfd, fd, _("Sub-process %s exited unexpectedly"), "apt-key");
+      local_exit(EINTERNAL);
+   }
 
-      // everything fine
-      exit(0);
+   // … and with a good exit code
+   if (WEXITSTATUS(Status) != 0)
+   {
+      // we forward the statuscode, so don't generate a message on the fd in this case
+      apt_error(std::cerr, -1, fd, _("Sub-process %s returned an error code (%u)"), "apt-key", WEXITSTATUS(Status));
+      local_exit(WEXITSTATUS(Status));
    }
-   exit(EINTERNAL); // unreachable safe-guard
+
+   // everything fine
+   local_exit(0);
 }
                                                                        /*}}}*/
 // SplitClearSignedFile - split message into data/signature            /*{{{*/
@@ -296,6 +363,8 @@ bool SplitClearSignedFile(std::string const &InFile, FileFd * const ContentFile,
       // all the rest is whitespace, unsigned garbage or additional message blocks we ignore
    }
    fclose(in);
+   if (buf != NULL)
+      free(buf);
 
    if (found_signature == true)
       return _error->Error("Signature in file %s wasn't closed", InFile.c_str());
@@ -324,7 +393,7 @@ bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &Me
    unlink(message);
    free(message);
 
-   MessageFile.OpenDescriptor(messageFd, FileFd::ReadWrite, true);
+   MessageFile.OpenDescriptor(messageFd, FileFd::ReadWrite | FileFd::BufferedWrite, true);
    if (MessageFile.Failed() == true)
       return _error->Error("Couldn't open temporary file to work with %s", ClearSignedFileName.c_str());