diff options
-rw-r--r-- | apt-pkg/acquire-method.cc | 31 | ||||
-rw-r--r-- | apt-pkg/acquire-worker.cc | 2 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 4 | ||||
-rw-r--r-- | apt-pkg/contrib/gpgv.cc | 446 | ||||
-rw-r--r-- | apt-pkg/deb/debindexfile.cc | 11 | ||||
-rw-r--r-- | apt-pkg/tagfile.cc | 8 | ||||
-rw-r--r-- | apt-private/private-cmndline.cc | 6 | ||||
-rw-r--r-- | apt-private/private-install.cc | 4 | ||||
-rw-r--r-- | apt-private/private-json-hooks.cc | 2 | ||||
-rw-r--r-- | cmdline/apt-extracttemplates.cc | 34 | ||||
-rw-r--r-- | cmdline/apt-get.cc | 1 | ||||
-rw-r--r-- | cmdline/apt.cc | 1 | ||||
-rw-r--r-- | doc/apt-get.8.xml | 4 | ||||
-rw-r--r-- | doc/apt.8.xml | 2 | ||||
-rw-r--r-- | po/fr.po | 132 | ||||
-rw-r--r-- | po/ru.po | 14 | ||||
-rwxr-xr-x | test/integration/test-apt-extracttemplates | 7 | ||||
-rwxr-xr-x | test/integration/test-apt-sources-deb822 | 68 | ||||
-rwxr-xr-x | test/integration/test-cve-2013-1051-InRelease-parsing | 7 | ||||
-rwxr-xr-x | test/integration/test-cve-2019-3462-Release.gpg-payload | 43 | ||||
-rwxr-xr-x | test/integration/test-method-gpgv | 48 | ||||
-rw-r--r-- | test/libapt/openmaybeclearsignedfile_test.cc | 164 | ||||
-rw-r--r-- | test/libapt/tagfile_test.cc | 2 |
23 files changed, 701 insertions, 340 deletions
diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index c67c47ab8..ae5ae4a15 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -88,6 +88,37 @@ pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags) /*}}}*/ void pkgAcqMethod::SendMessage(std::string const &header, std::unordered_map<std::string, std::string> &&fields) /*{{{*/ { + auto CheckKey = [](std::string const &str) { + // Space, hyphen-minus, and alphanum are allowed for keys/headers. + return str.find_first_not_of(" -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") == std::string::npos; + }; + + auto CheckValue = [](std::string const &str) { + return std::all_of(str.begin(), str.end(), [](unsigned char c) -> bool { + return c > 127 // unicode + || (c > 31 && c < 127) // printable chars + || c == '\n' || c == '\t'; // special whitespace + }); + }; + + auto Error = [this]() { + _error->Error("SECURITY: Message contains control characters, rejecting."); + _error->DumpErrors(); + SendMessage("400 URI Failure", {{"URI", "<UNKNOWN>"}, {"Message", "SECURITY: Message contains control characters, rejecting."}}); + abort(); + }; + + if (!CheckKey(header)) + return Error(); + + for (auto const &f : fields) + { + if (!CheckKey(f.first)) + return Error(); + if (!CheckValue(f.second)) + return Error(); + } + std::cout << header << '\n'; for (auto const &f : fields) { diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc index c2bbf8bed..b36186121 100644 --- a/apt-pkg/acquire-worker.cc +++ b/apt-pkg/acquire-worker.cc @@ -98,6 +98,8 @@ bool pkgAcquire::Worker::Start() std::string Method; if (_config->Exists(confItem)) Method = _config->FindFile(confItem.c_str()); + else if (Access == "ftp" || Access == "rsh" || Access == "ssh") + return _error->Error(_("The method '%s' is unsupported and disabled by default. Consider switching to http(s). Set Dir::Bin::Methods::%s to \"%s\" to enable it again."), Access.c_str(), Access.c_str(), Access.c_str()); else Method = _config->FindDir(methodsDir) + Access; if (FileExists(Method) == false) diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index eab05de4f..8cb4b509c 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -3114,7 +3114,7 @@ FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd * co snprintf(fn, sizeof(fn), "%s/%s.XXXXXX", tempdir.c_str(), Prefix.c_str()); int const fd = mkstemp(fn); - if(ImmediateUnlink) + if (ImmediateUnlink) unlink(fn); if (fd < 0) { @@ -3130,6 +3130,8 @@ FileFd* GetTempFile(std::string const &Prefix, bool ImmediateUnlink, FileFd * co delete Fd; return nullptr; } + if (ImmediateUnlink == false) + Fd->SetFileName(fn); return Fd; } /*}}}*/ diff --git a/apt-pkg/contrib/gpgv.cc b/apt-pkg/contrib/gpgv.cc index f8ab8d715..b845528d8 100644 --- a/apt-pkg/contrib/gpgv.cc +++ b/apt-pkg/contrib/gpgv.cc @@ -20,18 +20,94 @@ #include <algorithm> #include <fstream> #include <iostream> +#include <memory> #include <sstream> #include <string> #include <vector> #include <apti18n.h> /*}}}*/ -static char * GenerateTemporaryFileTemplate(const char *basename) /*{{{*/ + +// syntactic sugar to wrap a raw pointer with a custom deleter in a std::unique_ptr +static std::unique_ptr<char, decltype(&free)> make_unique_char(void *const str = nullptr) +{ + return {static_cast<char *>(str), &free}; +} +static std::unique_ptr<FILE, decltype(&fclose)> make_unique_FILE(std::string const &filename, char const *const mode) { - std::string out; - std::string tmpdir = GetTempDir(); - strprintf(out, "%s/%s.XXXXXX", tmpdir.c_str(), basename); - return strdup(out.c_str()); + return {fopen(filename.c_str(), mode), &fclose}; +} + +class LineBuffer /*{{{*/ +{ + char *buffer = nullptr; + size_t buffer_size = 0; + int line_length = 0; + // a "normal" find_last_not_of returns npos if not found + int find_last_not_of_length(APT::StringView const bad) const + { + for (int result = line_length - 1; result >= 0; --result) + if (bad.find(buffer[result]) == APT::StringView::npos) + return result + 1; + return 0; + } + + public: + bool empty() const noexcept { return view().empty(); } + APT::StringView view() const noexcept { return {buffer, static_cast<size_t>(line_length)}; } + bool starts_with(APT::StringView const start) const { return view().substr(0, start.size()) == start; } + + bool writeTo(FileFd *const to, size_t offset = 0) const + { + if (to == nullptr) + return true; + return to->Write(buffer + offset, line_length - offset); + } + bool writeLineTo(FileFd *const to) const + { + if (to == nullptr) + return true; + buffer[line_length] = '\n'; + bool const result = to->Write(buffer, line_length + 1); + buffer[line_length] = '\0'; + return result; + } + bool writeNewLineIf(FileFd *const to, bool const condition) const + { + if (not condition || to == nullptr) + return true; + return to->Write("\n", 1); + } + + bool readFrom(FILE *stream, std::string const &InFile, bool acceptEoF = false) + { + errno = 0; + line_length = getline(&buffer, &buffer_size, stream); + if (errno != 0) + return _error->Errno("getline", "Could not read from %s", InFile.c_str()); + if (line_length == -1) + { + if (acceptEoF) + return false; + return _error->Error("Splitting of clearsigned file %s failed as it doesn't contain all expected parts", InFile.c_str()); + } + // a) remove newline characters, so we can work consistently with lines + line_length = find_last_not_of_length("\n\r"); + // b) remove trailing whitespaces as defined by rfc4880 §7.1 + line_length = find_last_not_of_length(" \t"); + buffer[line_length] = '\0'; + return true; + } + + ~LineBuffer() { free(buffer); } +}; +static bool operator==(LineBuffer const &buf, APT::StringView const exp) noexcept +{ + return buf.view() == exp; +} +static bool operator!=(LineBuffer const &buf, APT::StringView const exp) noexcept +{ + return buf.view() != exp; } /*}}}*/ // ExecGPGV - returns the command needed for verify /*{{{*/ @@ -47,11 +123,10 @@ static char * GenerateTemporaryFileTemplate(const char *basename) /*{{{*/ */ 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); + auto S = make_unique_char(malloc(size)); + ssize_t const n = vsnprintf(S.get(), size, format, args); if (n > -1 && n < size) { - out << S; - free(S); + out << S.get(); return true; } else { if (n > -1) @@ -59,7 +134,6 @@ static bool iovprintf(std::ostream &out, const char *format, 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, ...) @@ -73,7 +147,7 @@ static void APT_PRINTF(4) apt_error(std::ostream &outterm, int const statusfd, i va_start(args,format); ret = iovprintf(out, format, args, size); va_end(args); - if (ret == true) + if (ret) break; } if (statusfd != -1) @@ -81,8 +155,8 @@ static void APT_PRINTF(4) apt_error(std::ostream &outterm, int const statusfd, i 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) + if (not FileFd::Write(fd[1], errtag, strlen(errtag)) || + not FileFd::Write(fd[1], errtext.data(), errtext.size())) outterm << errtext << std::flush; } } @@ -141,83 +215,134 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, Opts = Opts->Child; for (; Opts != 0; Opts = Opts->Next) { - if (Opts->Value.empty() == true) + if (Opts->Value.empty()) continue; Args.push_back(Opts->Value.c_str()); } } enum { DETACHED, CLEARSIGNED } releaseSignature = (FileGPG != File) ? DETACHED : CLEARSIGNED; - char * sig = NULL; - char * data = NULL; - char * conf = nullptr; + auto sig = make_unique_char(); + auto data = make_unique_char(); + auto conf = make_unique_char(); // Dump the configuration so apt-key picks up the correct Dir values { - conf = GenerateTemporaryFileTemplate("apt.conf"); + { + std::string tmpfile; + strprintf(tmpfile, "%s/apt.conf.XXXXXX", GetTempDir().c_str()); + conf.reset(strdup(tmpfile.c_str())); + } 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); + int confFd = mkstemp(conf.get()); if (confFd == -1) { - apt_error(std::cerr, statusfd, fd, "Couldn't create temporary file %s for passing config to apt-key", conf); + apt_error(std::cerr, statusfd, fd, "Couldn't create temporary file %s for passing config to apt-key", conf.get()); local_exit(EINTERNAL); } - local_exit.files.push_back(conf); + local_exit.files.push_back(conf.get()); - std::ofstream confStream(conf); + std::ofstream confStream(conf.get()); close(confFd); _config->Dump(confStream); confStream.close(); - setenv("APT_CONFIG", conf, 1); + setenv("APT_CONFIG", conf.get(), 1); } if (releaseSignature == DETACHED) { - 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) + auto detached = make_unique_FILE(FileGPG, "r"); + if (detached.get() == nullptr) { - apt_error(std::cerr, statusfd, fd, "Couldn't create tempfile names for splitting up %s", File.c_str()); + apt_error(std::cerr, statusfd, fd, "Detached signature file '%s' could not be opened", FileGPG.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) + LineBuffer buf; + bool open_signature = false; + bool found_badcontent = false; + size_t found_signatures = 0; + while (buf.readFrom(detached.get(), FileGPG, true)) { - apt_error(std::cerr, statusfd, fd, "Couldn't create tempfiles for splitting up %s", File.c_str()); - local_exit(EINTERNAL); + if (open_signature) + { + if (buf == "-----END PGP SIGNATURE-----") + open_signature = false; + else if (buf.starts_with("-")) + { + // the used Radix-64 is not using dash for any value, so a valid line can't + // start with one. Header keys could, but no existent one does and seems unlikely. + // Instead it smells a lot like a header the parser didn't recognize. + apt_error(std::cerr, statusfd, fd, "Detached signature file '%s' contains unexpected line starting with a dash", FileGPG.c_str()); + local_exit(112); + } + } + else //if (not open_signature) + { + if (buf == "-----BEGIN PGP SIGNATURE-----") + { + open_signature = true; + ++found_signatures; + if (found_badcontent) + break; + } + else + { + found_badcontent = true; + if (found_signatures != 0) + break; + } + } + } + if (found_signatures == 0 && statusfd != -1) + { + // This is not an attack attempt but a file even gpgv would complain about + // likely the result of a paywall which is covered by the gpgv method + auto const errtag = "[GNUPG:] NODATA\n"; + FileFd::Write(fd[1], errtag, strlen(errtag)); + local_exit(113); + } + else if (found_badcontent) + { + apt_error(std::cerr, statusfd, fd, "Detached signature file '%s' contains lines not belonging to a signature", FileGPG.c_str()); + local_exit(112); + } + if (open_signature) + { + apt_error(std::cerr, statusfd, fd, "Detached signature file '%s' contains unclosed signatures", FileGPG.c_str()); + local_exit(112); } + Args.push_back(FileGPG.c_str()); + Args.push_back(File.c_str()); + } + else // clear-signed file + { FileFd signature; - signature.OpenDescriptor(sigFd, FileFd::WriteOnly, true); + if (GetTempFile("apt.sig", false, &signature) == nullptr) + local_exit(EINTERNAL); + sig.reset(strdup(signature.Name().c_str())); + local_exit.files.push_back(sig.get()); FileFd message; - message.OpenDescriptor(dataFd, FileFd::WriteOnly, true); + if (GetTempFile("apt.data", false, &message) == nullptr) + local_exit(EINTERNAL); + data.reset(strdup(message.Name().c_str())); + local_exit.files.push_back(data.get()); - if (signature.Failed() == true || message.Failed() == true || - SplitClearSignedFile(File, &message, nullptr, &signature) == false) + if (signature.Failed() || message.Failed() || + not SplitClearSignedFile(File, &message, nullptr, &signature)) { 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); + Args.push_back(sig.get()); + Args.push_back(data.get()); } Args.push_back(NULL); - if (Debug == true) + if (Debug) { std::clog << "Preparing to exec: "; for (std::vector<const char *>::const_iterator a = Args.begin(); *a != NULL; ++a) @@ -270,7 +395,7 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, } // check if it exit'ed normally … - if (WIFEXITED(Status) == false) + if (not WIFEXITED(Status)) { apt_error(std::cerr, statusfd, fd, _("Sub-process %s exited unexpectedly"), "apt-key"); local_exit(EINTERNAL); @@ -289,168 +414,141 @@ void ExecGPGV(std::string const &File, std::string const &FileGPG, } /*}}}*/ // SplitClearSignedFile - split message into data/signature /*{{{*/ -static int GetLineErrno(char **lineptr, size_t *n, FILE *stream, std::string const &InFile) +bool SplitClearSignedFile(std::string const &InFile, FileFd * const ContentFile, + std::vector<std::string> * const ContentHeader, FileFd * const SignatureFile) { - int result; + auto in = make_unique_FILE(InFile, "r"); + if (in.get() == nullptr) + return _error->Errno("fopen", "can not open %s", InFile.c_str()); - errno = 0; - result = getline(lineptr, n, stream); - if (errno != 0) + struct ScopedErrors + { + ScopedErrors() { _error->PushToStack(); } + ~ScopedErrors() { _error->MergeWithStack(); } + } scoped; + LineBuffer buf; + + // start of the message + if (not buf.readFrom(in.get(), InFile)) + return false; // empty or read error + if (buf != "-----BEGIN PGP SIGNED MESSAGE-----") { - _error->Errno("getline", "Could not read from %s", InFile.c_str()); - return -1; + // this might be an unsigned file we don't want to report errors for, + // but still finish unsuccessful none the less. + while (buf.readFrom(in.get(), InFile, true)) + if (buf == "-----BEGIN PGP SIGNED MESSAGE-----") + return _error->Error("Clearsigned file '%s' does not start with a signed message block.", InFile.c_str()); + + return false; } - return result; -} -bool SplitClearSignedFile(std::string const &InFile, FileFd * const ContentFile, - std::vector<std::string> * const ContentHeader, FileFd * const SignatureFile) -{ - FILE *in = fopen(InFile.c_str(), "r"); - if (in == NULL) - return _error->Errno("fopen", "can not open %s", InFile.c_str()); + // save "Hash" Armor Headers + while (true) + { + if (not buf.readFrom(in.get(), InFile)) + return false; + if (buf.empty()) + break; // empty line ends the Armor Headers + if (buf.starts_with("-")) + // § 6.2 says unknown keys should be reported to the user. We don't go that far, + // but we assume that there will never be a header key starting with a dash + return _error->Error("Clearsigned file '%s' contains unexpected line starting with a dash (%s)", InFile.c_str(), "armor"); + if (ContentHeader != nullptr && buf.starts_with("Hash: ")) + ContentHeader->push_back(buf.view().to_string()); + } - bool found_message_start = false; - bool found_message_end = false; - bool skip_until_empty_line = false; - bool found_signature = false; + // the message itself bool first_line = true; - bool signed_message_not_on_first_line = false; - bool found_garbage = false; - - char *buf = NULL; - size_t buf_size = 0; - _error->PushToStack(); - while (GetLineErrno(&buf, &buf_size, in, InFile) != -1) + while (true) { - _strrstrip(buf); - if (found_message_start == false) + if (not buf.readFrom(in.get(), InFile)) + return false; + + if (buf.starts_with("-")) { - if (strcmp(buf, "-----BEGIN PGP SIGNED MESSAGE-----") == 0) + if (buf == "-----BEGIN PGP SIGNATURE-----") + { + if (not buf.writeLineTo(SignatureFile)) + return false; + break; + } + else if (buf.starts_with("- ")) { - found_message_start = true; - skip_until_empty_line = true; + // we don't have any fields which need to be dash-escaped, + // but implementations are free to escape all lines … + if (not buf.writeNewLineIf(ContentFile, not first_line) || not buf.writeTo(ContentFile, 2)) + return false; } else - signed_message_not_on_first_line = found_garbage = true; + // § 7.1 says a client should warn, but we don't really work with files which + // should contain lines starting with a dash, so it is a lot more likely that + // this is an attempt to trick our parser vs. gpgv parser into ignoring a header + return _error->Error("Clearsigned file '%s' contains unexpected line starting with a dash (%s)", InFile.c_str(), "msg"); } - else if (skip_until_empty_line == true) + else if (not buf.writeNewLineIf(ContentFile, not first_line) || not buf.writeTo(ContentFile)) + return false; + first_line = false; + } + + // collect all signatures + bool open_signature = true; + while (true) + { + if (not buf.readFrom(in.get(), InFile, true)) + break; + + if (open_signature) { - 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); + if (buf == "-----END PGP SIGNATURE-----") + open_signature = false; + else if (buf.starts_with("-")) + // the used Radix-64 is not using dash for any value, so a valid line can't + // start with one. Header keys could, but no existent one does and seems unlikely. + // Instead it smells a lot like a header the parser didn't recognize. + return _error->Error("Clearsigned file '%s' contains unexpected line starting with a dash (%s)", InFile.c_str(), "sig"); } - else if (found_signature == false) + else //if (not open_signature) { - if (strcmp(buf, "-----BEGIN PGP SIGNATURE-----") == 0) - { - found_signature = true; - found_message_end = true; - if (SignatureFile != NULL) - { - SignatureFile->Write(buf, strlen(buf)); - SignatureFile->Write("\n", 1); - } - } - else if (found_message_end == false) // we are in the message block - { - // we don't have any fields which need dash-escaped, - // but implementations are free to encode all lines … - char const * dashfree = buf; - if (strncmp(dashfree, "- ", 2) == 0) - dashfree += 2; - if(first_line == true) // first line does not need a newline - first_line = false; - else if (ContentFile != NULL) - ContentFile->Write("\n", 1); - else - continue; - if (ContentFile != NULL) - ContentFile->Write(dashfree, strlen(dashfree)); - } + if (buf == "-----BEGIN PGP SIGNATURE-----") + open_signature = true; else - found_garbage = true; + return _error->Error("Clearsigned file '%s' contains unsigned lines.", InFile.c_str()); } - else if (found_signature == true) - { - if (SignatureFile != NULL) - { - SignatureFile->Write(buf, strlen(buf)); - SignatureFile->Write("\n", 1); - } - 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 - else - found_garbage = true; + + if (not buf.writeLineTo(SignatureFile)) + return false; } - fclose(in); - if (buf != NULL) - free(buf); + if (open_signature) + return _error->Error("Signature in file %s wasn't closed", InFile.c_str()); - // Flush the files. Errors will be checked below. + // Flush the files if (SignatureFile != nullptr) SignatureFile->Flush(); if (ContentFile != nullptr) ContentFile->Flush(); - if (found_message_start) - { - if (signed_message_not_on_first_line) - _error->Warning("Clearsigned file '%s' does not start with a signed message block.", InFile.c_str()); - else if (found_garbage) - _error->Warning("Clearsigned file '%s' contains unsigned lines.", InFile.c_str()); - } - - // An error occurred during reading - propagate it up - bool const hasErrored = _error->PendingError(); - _error->MergeWithStack(); - if (hasErrored) - return false; - - if (found_signature == true) - return _error->Error("Signature in file %s wasn't closed", InFile.c_str()); - - // if we haven't found any of them, this an unsigned file, - // so don't generate an error, but splitting was unsuccessful none-the-less - if (first_line == true && found_message_start == false && found_message_end == false) + // Catch-all for "unhandled" read/sync errors + if (_error->PendingError()) return false; - // otherwise one missing indicates a syntax error - else if (first_line == true || found_message_start == false || found_message_end == false) - return _error->Error("Splitting of file %s failed as it doesn't contain all expected parts %i %i %i", InFile.c_str(), first_line, found_message_start, found_message_end); - return true; } /*}}}*/ bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &MessageFile) /*{{{*/ { - char * const message = GenerateTemporaryFileTemplate("fileutl.message"); - int const messageFd = mkstemp(message); - if (messageFd == -1) - { - free(message); - return _error->Errno("mkstemp", "Couldn't create temporary file to work with %s", ClearSignedFileName.c_str()); - } - // we have the fd, that's enough for us - unlink(message); - free(message); - - MessageFile.OpenDescriptor(messageFd, FileFd::ReadWrite | FileFd::BufferedWrite, true); - if (MessageFile.Failed() == true) + if (GetTempFile("clearsigned.message", true, &MessageFile) == nullptr) + return false; + if (MessageFile.Failed()) return _error->Error("Couldn't open temporary file to work with %s", ClearSignedFileName.c_str()); _error->PushToStack(); bool const splitDone = SplitClearSignedFile(ClearSignedFileName, &MessageFile, NULL, NULL); bool const errorDone = _error->PendingError(); _error->MergeWithStack(); - if (splitDone == false) + if (not splitDone) { MessageFile.Close(); - if (errorDone == true) + if (errorDone) return false; // we deal with an unsigned file @@ -458,10 +556,10 @@ bool OpenMaybeClearSignedFile(std::string const &ClearSignedFileName, FileFd &Me } else // clear-signed { - if (MessageFile.Seek(0) == false) + if (not MessageFile.Seek(0)) return _error->Errno("lseek", "Unable to seek back in message for file %s", ClearSignedFileName.c_str()); } - return MessageFile.Failed() == false; + return not MessageFile.Failed(); } /*}}}*/ diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index f7e3c7a5c..25e0a3312 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -315,13 +315,10 @@ const pkgIndexFile::Type *debStringPackageIndex::GetType() const debStringPackageIndex::debStringPackageIndex(std::string const &content) : pkgDebianIndexRealFile("", false), d(NULL) { - char fn[1024]; - std::string const tempdir = GetTempDir(); - snprintf(fn, sizeof(fn), "%s/%s.XXXXXX", tempdir.c_str(), "apt-tmp-index"); - int const fd = mkstemp(fn); - File = fn; - FileFd::Write(fd, content.data(), content.length()); - close(fd); + FileFd fd; + GetTempFile("apt-tmp-index", false, &fd); + fd.Write(content.data(), content.length()); + File = fd.Name(); } debStringPackageIndex::~debStringPackageIndex() { diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 98001afd1..1e7f2867c 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -250,8 +250,12 @@ bool pkgTagFile::Step(pkgTagSection &Tag) d->chunks.erase(d->chunks.begin(), first); } - Tag.Trim(); - return true; + if ((d->Flags & pkgTagFile::SUPPORT_COMMENTS) == 0 || Tag.Count() != 0) + { + Tag.Trim(); + return true; + } + return Step(Tag); } /*}}}*/ // TagFile::Fill - Top up the buffer /*{{{*/ diff --git a/apt-private/private-cmndline.cc b/apt-private/private-cmndline.cc index 87deb6bf0..494928332 100644 --- a/apt-private/private-cmndline.cc +++ b/apt-private/private-cmndline.cc @@ -175,7 +175,7 @@ static bool addArgumentsAPTHelper(std::vector<CommandLine::Args> &Args, char con /*}}}*/ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const * const Cmd)/*{{{*/ { - if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade", + if (CmdMatches("install", "reinstall", "remove", "purge", "upgrade", "dist-upgrade", "dselect-upgrade", "autoremove", "autopurge", "full-upgrade")) { addArg(0, "show-progress", "DpkgPM::Progress", 0); @@ -239,7 +239,7 @@ static bool addArgumentsAPTGet(std::vector<CommandLine::Args> &Args, char const else if (CmdMatches("moo")) addArg(0, "color", "APT::Moo::Color", 0); - if (CmdMatches("install", "remove", "purge", "upgrade", "dist-upgrade", + if (CmdMatches("install", "reinstall", "remove", "purge", "upgrade", "dist-upgrade", "dselect-upgrade", "autoremove", "auto-remove", "autopurge", "clean", "autoclean", "auto-clean", "check", "build-dep", "full-upgrade", "source")) { @@ -291,7 +291,7 @@ static bool addArgumentsAPTMark(std::vector<CommandLine::Args> &Args, char const { addArg('f',"file","Dir::State::extended_states",CommandLine::HasArg); } - else if (CmdMatches("install", "remove", "deinstall", "purge", + else if (CmdMatches("install", "reinstall", "remove", "deinstall", "purge", "showinstall", "showinstalls", "showremove", "showremoves", "showdeinstall", "showdeinstalls", "showpurge", "showpurges")) ; diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index 1713ff308..243b75b1c 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -586,7 +586,9 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector<PseudoPkg Fix.reset(new pkgProblemResolver(Cache)); unsigned short fallback = MOD_INSTALL; - if (strcasecmp(CmdL.FileList[0],"remove") == 0) + if (strcasecmp(CmdL.FileList[0], "reinstall") == 0) + _config->Set("APT::Get::ReInstall", "true"); + else if (strcasecmp(CmdL.FileList[0],"remove") == 0) fallback = MOD_REMOVE; else if (strcasecmp(CmdL.FileList[0], "purge") == 0) { diff --git a/apt-private/private-json-hooks.cc b/apt-private/private-json-hooks.cc index b5c1a7172..65ff87924 100644 --- a/apt-private/private-json-hooks.cc +++ b/apt-private/private-json-hooks.cc @@ -387,7 +387,7 @@ bool RunJsonHook(std::string const &option, std::string const &method, const cha if (size < 0) { - if (errno != ECONNRESET) + if (errno != ECONNRESET && errno != EPIPE) _error->Error("Could not read response to hello message from hook %s: %s", Opts->Value.c_str(), strerror(errno)); goto out; } diff --git a/cmdline/apt-extracttemplates.cc b/cmdline/apt-extracttemplates.cc index bd23453f3..bc8a27dbe 100644 --- a/cmdline/apt-extracttemplates.cc +++ b/cmdline/apt-extracttemplates.cc @@ -229,29 +229,13 @@ static bool ShowHelp(CommandLine &) /*{{{*/ /* */ static string WriteFile(const char *package, const char *prefix, const char *data) { - char fn[512]; - - std::string tempdir = GetTempDir(); - snprintf(fn, sizeof(fn), "%s/%s.%s.XXXXXX", - _config->Find("APT::ExtractTemplates::TempDir", - tempdir.c_str()).c_str(), - package, prefix); - FileFd f; - if (data == NULL) - data = ""; - int fd = mkstemp(fn); - if (fd < 0) { - _error->Errno("ofstream::ofstream",_("Unable to mkstemp %s"),fn); - return string(); - } - if (!f.OpenDescriptor(fd, FileFd::WriteOnly, FileFd::None, true)) - { - _error->Errno("ofstream::ofstream",_("Unable to write to %s"),fn); - return string(); - } - f.Write(data, strlen(data)); - f.Close(); - return fn; + FileFd f; + std::string tplname; + strprintf(tplname, "%s.%s", package, prefix); + GetTempFile(tplname, false, &f); + if (data != nullptr) + f.Write(data, strlen(data)); + return f.Name(); } /*}}}*/ // WriteConfig - write out the config data from a debian package file /*{{{*/ @@ -289,6 +273,10 @@ static bool Go(CommandLine &CmdL) if (debconfver.empty() == true) return _error->Error( _("Cannot get debconf version. Is debconf installed?")); + auto const tmpdir = _config->Find("APT::ExtractTemplates::TempDir"); + if (tmpdir.empty() == false) + setenv("TMPDIR", tmpdir.c_str(), 1); + // Process each package passsed in for (unsigned int I = 0; I != CmdL.FileSize(); I++) { diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 6d25ed509..da18d2d19 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -405,6 +405,7 @@ static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/ {"update", &DoUpdate, _("Retrieve new lists of packages")}, {"upgrade", &DoUpgrade, _("Perform an upgrade")}, {"install", &DoInstall, _("Install new packages (pkg is libc6 not libc6.deb)")}, + {"reinstall", &DoInstall, _("Reinstall packages (pkg is libc6 not libc6.deb)")}, {"remove", &DoInstall, _("Remove packages")}, {"purge", &DoInstall, _("Remove packages and config files")}, {"autoremove", &DoInstall, _("Remove automatically all unused packages")}, diff --git a/cmdline/apt.cc b/cmdline/apt.cc index f508406d1..d388e4af4 100644 --- a/cmdline/apt.cc +++ b/cmdline/apt.cc @@ -63,6 +63,7 @@ static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/ // package stuff {"install", &DoInstall, _("install packages")}, + {"reinstall", &DoInstall, _("reinstall packages")}, {"remove", &DoInstall, _("remove packages")}, {"autoremove", &DoInstall, _("Remove automatically all unused packages")}, {"auto-remove", &DoInstall, nullptr}, diff --git a/doc/apt-get.8.xml b/doc/apt-get.8.xml index 184282e69..b83eabd27 100644 --- a/doc/apt-get.8.xml +++ b/doc/apt-get.8.xml @@ -143,6 +143,10 @@ with a '^' or '$' character, or create a more specific regular expression.</para></listitem> </varlistentry> + <varlistentry><term><option>reinstall</option></term> + <listitem><para><literal>reinstall</literal> is an alias for <literal>install --reinstall</literal>.</para></listitem> + </varlistentry> + <varlistentry><term><option>remove</option></term> <listitem><para><literal>remove</literal> is identical to <literal>install</literal> except that packages are removed instead of installed. Note that removing a package leaves its diff --git a/doc/apt.8.xml b/doc/apt.8.xml index 626419ec3..08492bf54 100644 --- a/doc/apt.8.xml +++ b/doc/apt.8.xml @@ -69,7 +69,7 @@ </para></listitem> </varlistentry> - <varlistentry><term><option>install</option>, <option>remove</option>, <option>purge</option> (&apt-get;)</term> + <varlistentry><term><option>install</option>, <option>reinstall</option>, <option>remove</option>, <option>purge</option> (&apt-get;)</term> <listitem><para>Performs the requested action on one or more packages specified via ®ex;, &glob; or exact match. The requested action can be overridden for specific packages by append a plus (+) to the @@ -4,13 +4,14 @@ # # Pierre Machard <pmachard@tuxfamily.org>, 2002,2003,2004. # Christian Perrier <bubulle@debian.org>, 2004-2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013. -# Julien Patriarca <leatherface@debian.org>, 2013, 2017, 2018 +# Julien Patriarca <leatherface@debian.org>, 2013, 2017, 2018. +# Baptiste Jammet <baptiste@mailoo.org>, 2019. msgid "" msgstr "" "Project-Id-Version: apt 1.0.5\n" "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n" -"POT-Creation-Date: 2019-01-23 16:49+0100\n" -"PO-Revision-Date: 2018-01-02 15:09+0100\n" +"POT-Creation-Date: 2018-12-18 15:02+0100\n" +"PO-Revision-Date: 2019-01-21 09:19+0100\n" "Last-Translator: Julien Patriarca <leatherface@debian.org>\n" "Language-Team: French <debian-l10n-french@lists.debian.org>\n" "Language: fr\n" @@ -22,7 +23,7 @@ msgstr "" #: apt-inst/contrib/arfile.cc msgid "Invalid archive signature" -msgstr "Signature d'archive invalide" +msgstr "Signature d'archive non valable" #: apt-inst/contrib/arfile.cc msgid "Error reading archive member header" @@ -35,7 +36,7 @@ msgstr "En-tête du membre d'archive %s non valable" #: apt-inst/contrib/arfile.cc msgid "Invalid archive member header" -msgstr "En-tête du membre d'archive non-valable" +msgstr "En-tête du membre d'archive non valable" #: apt-inst/contrib/arfile.cc msgid "Archive is too short" @@ -66,7 +67,7 @@ msgstr "Type d'en-tête %u inconnu pour TAR, partie %s" #: apt-inst/deb/debfile.cc #, c-format msgid "This is not a valid DEB archive, missing '%s' member" -msgstr "Ce n'est pas une archive DEB valide, partie « %s » manquante" +msgstr "Ce n'est pas une archive DEB valable, partie « %s » manquante" #: apt-inst/deb/debfile.cc #, c-format @@ -196,7 +197,7 @@ msgid "" "disabled by default." msgstr "" "Les mises à jour depuis un tel dépôt ne peuvent s'effectuer de manière " -"sécurisée, et sont donc désactivées par défaut" +"sécurisée, et sont donc désactivées par défaut." #: apt-pkg/acquire-item.cc msgid "" @@ -273,7 +274,7 @@ msgstr "Taille incohérente" #: apt-pkg/acquire-item.cc msgid "Invalid file format" -msgstr "Format de fichier invalide" +msgstr "Format de fichier non valable" #: apt-pkg/acquire-item.cc msgid "Signature error" @@ -321,7 +322,7 @@ msgid "" "architecture '%s'" msgstr "" "Le fichier configuré « %s » ne sera pas pris en compte car le dépôt « %s » " -"ne supporte pas l'architecture « %s »" +"ne prend pas en charge l'architecture « %s »" #: apt-pkg/acquire-item.cc #, c-format @@ -350,14 +351,14 @@ msgid "" "Release file for %s is expired (invalid since %s). Updates for this " "repository will not be applied." msgstr "" -"Le fichier « Release » pour %s a expiré (invalide depuis %s). Les mises à " +"Le fichier « Release » pour %s est périmé (invalide depuis %s). Les mises à " "jour depuis ce dépôt ne s'effectueront pas." #. TRANSLATOR: The first %s is the URL of the bad Release file, the second is #. the time until the file will be valid - formatted in the same way as in #. the download progress display (e.g. 7d 3h 42min 1s) #: apt-pkg/acquire-item.cc -#, fuzzy, c-format +#, c-format #| msgid "" #| "Release file for %s is expired (invalid since %s). Updates for this " #| "repository will not be applied." @@ -365,8 +366,8 @@ msgid "" "Release file for %s is not valid yet (invalid for another %s). Updates for " "this repository will not be applied." msgstr "" -"Le fichier « Release » pour %s a expiré (invalide depuis %s). Les mises à " -"jour depuis ce dépôt ne s'effectueront pas." +"Le fichier « Release » pour %s n'est pas encore valable (invalide pendant " +"encore %s). Les mises à jour depuis ce dépôt ne s'effectueront pas." #: apt-pkg/acquire-item.cc #, c-format @@ -439,7 +440,7 @@ msgstr "La méthode « %s » est volontairement désactivée par configuration #, c-format msgid "If you meant to use Tor remember to use %s instead of %s." msgstr "" -".Si vous souhaitiez utiliser Tor veuillez alors utiliser « %s » plutôt que " +".Si vous souhaitiez utiliser Tor, veuillez alors utiliser « %s » plutôt que " "« %s »." #: apt-pkg/acquire-worker.cc @@ -729,8 +730,8 @@ msgid "" "Command line option '%c' [from %s] is not understood in combination with the " "other options." msgstr "" -"L'option « %c » de la ligne de commande [%s] est inconnue quand elle est " -"utilisée avec d'autres options." +"L'option « %c » de la ligne de commande [%s] n'est pas reconnue quand elle " +"est utilisée avec d'autres options." #: apt-pkg/contrib/cmndline.cc #, c-format @@ -769,7 +770,9 @@ msgstr "L'option « %s » est trop longue" #: apt-pkg/contrib/cmndline.cc #, c-format msgid "Sense %s is not understood, try true or false." -msgstr "La signification %s n'est pas comprise, veuillez essayer vrai ou faux." +msgstr "" +"La signification %s n'est pas comprise, veuillez essayer « true » ou " +"« false »." #: apt-pkg/contrib/cmndline.cc #, c-format @@ -888,7 +891,7 @@ msgstr "" #: cmdline/apt-dump-solver.cc #, c-format msgid "Waited for %s but it wasn't there" -msgstr "A attendu %s mais il n'était pas présent" +msgstr "A attendu %s, mais il n'était pas présent" #: apt-pkg/contrib/fileutl.cc #, c-format @@ -987,7 +990,7 @@ msgstr "Impossible de mapper un fichier vide en mémoire" #: apt-pkg/contrib/mmap.cc #, c-format msgid "Couldn't make mmap of %llu bytes" -msgstr "Impossible de réaliser un mapping de %llu octets en mémoire" +msgstr "Impossible de réaliser un mappage de %llu octets en mémoire" #: apt-pkg/contrib/mmap.cc #, c-format @@ -1005,7 +1008,7 @@ msgstr "Impossible de synchroniser la « mmap »" #: apt-pkg/contrib/mmap.cc #, c-format msgid "Couldn't make mmap of %lu bytes" -msgstr "Impossible de réaliser un mapping de %lu octets en mémoire" +msgstr "Impossible de réaliser un mappage de %lu octets en mémoire" #: apt-pkg/contrib/mmap.cc msgid "Failed to truncate file" @@ -1160,23 +1163,23 @@ msgid "Unable to parse package file %s (%d)" msgstr "Impossible de traiter le fichier %s (%d)" #: apt-pkg/deb/debsystem.cc -#, fuzzy, c-format +#, c-format #| msgid "" #| "Unable to lock the administration directory (%s), is another process " #| "using it?" msgid "" "Unable to acquire the dpkg frontend lock (%s), is another process using it?" msgstr "" -"Impossible de verrouiller le répertoire d'administration (%s). Il est " -"possible qu'un autre processus l'utilise." +"Impossible d'obtenir le verrou de dpkg (%s). Il est possible qu'un autre " +"processus l'utilise." #: apt-pkg/deb/debsystem.cc -#, fuzzy, c-format +#, c-format #| msgid "Unable to lock the administration directory (%s), are you root?" msgid "Unable to acquire the dpkg frontend lock (%s), are you root?" msgstr "" -"Impossible de verrouiller le répertoire d'administration (%s). Avez-vous les " -"privilèges du superutilisateur ?" +"Impossible d'obtenir le verrou de dpkg (%s). Avez-vous les droits du " +"superutilisateur ?" #. TRANSLATORS: the %s contains the recovery command, usually #. dpkg --configure -a @@ -1202,7 +1205,7 @@ msgstr "" msgid "Unable to lock the administration directory (%s), are you root?" msgstr "" "Impossible de verrouiller le répertoire d'administration (%s). Avez-vous les " -"privilèges du superutilisateur ?" +"droits du superutilisateur ?" #: apt-pkg/deb/debsystem.cc msgid "Not locked" @@ -1442,7 +1445,7 @@ msgstr "Somme de contrôle de hachage incohérente pour %s" #: apt-pkg/init.cc #, c-format msgid "Packaging system '%s' is not supported" -msgstr "Le système de paquet « %s » n'est pas supporté" +msgstr "Le système de paquet « %s » n'est pas pris en charge" #: apt-pkg/init.cc msgid "Unable to determine a suitable packaging system type" @@ -1500,7 +1503,7 @@ msgstr "Le fichier de cache des paquets a une version incompatible" #: apt-pkg/pkgcache.cc #, c-format msgid "This APT does not support the versioning system '%s'" -msgstr "Cet APT ne supporte pas le système de version « %s »" +msgstr "Cet APT ne prend pas en charge le système de version « %s »" #: apt-pkg/pkgcache.cc #, c-format @@ -1645,8 +1648,8 @@ msgstr "Type d'épinglage %s inconnu" #, c-format msgid "%s: Value %s is outside the range of valid pin priorities (%d to %d)" msgstr "" -"%s : la valeur %s est dehors de la plage de priorités d'épinglage valide (%d " -"à %d)" +"%s : la valeur %s est en dehors de la plage de priorités d'épinglage valide " +"(%d à %d)" #: apt-pkg/policy.cc msgid "No priority (or zero) specified for pin" @@ -1711,28 +1714,28 @@ msgstr "Calcul de la mise à jour" #: apt-private/acqprogress.cc #, c-format msgid "Hit:%lu %s" -msgstr "Atteint:%lu %s" +msgstr "Atteint :%lu %s" #. TRANSLATOR: Very short word to be displayed for files processed in 'apt-get update' #. Potentially replaced later by "Hit:", "Ign:" or "Err:" if something (bad) happens #: apt-private/acqprogress.cc #, c-format msgid "Get:%lu %s" -msgstr "Réception de:%lu %s" +msgstr "Réception de :%lu %s" #. TRANSLATOR: Very short word to be displayed for files in 'apt-get update' #. which failed to download, but the error is ignored (compare "Err:") #: apt-private/acqprogress.cc #, c-format msgid "Ign:%lu %s" -msgstr "Ign:%lu %s" +msgstr "Ign :%lu %s" #. TRANSLATOR: Very short word to be displayed for files in 'apt-get update' #. which failed to download and the error is critical (compare "Ign:") #: apt-private/acqprogress.cc #, c-format msgid "Err:%lu %s" -msgstr "Err:%lu %s" +msgstr "Err :%lu %s" #: apt-private/acqprogress.cc #, c-format @@ -1760,7 +1763,7 @@ msgid "" "repository?" msgstr "" "Souhaitez-vous accepter ces modifications et continuer à mettre à jour " -"depuis ce dépôt ?" +"depuis ce dépôt ?" #: apt-private/private-cachefile.cc msgid "Correcting dependencies..." @@ -1878,7 +1881,7 @@ msgstr "Note : sélection de « %s » au lieu de « %s »\n" #: apt-private/private-cmndline.cc msgid "Most used commands:" -msgstr "Commandes les plus utilisées :" +msgstr "Commandes les plus utilisées :" #: apt-private/private-cmndline.cc #, c-format @@ -1927,7 +1930,7 @@ msgstr "Aucun paquet n'a été trouvé" #: apt-private/private-download.cc msgid "WARNING: The following packages cannot be authenticated!" -msgstr "ATTENTION : les paquets suivants n'ont pas été authentifiés !" +msgstr "ATTENTION : les paquets suivants n'ont pas été authentifiés !" #: apt-private/private-download.cc msgid "Authentication warning overridden.\n" @@ -1939,7 +1942,7 @@ msgstr "Certains paquets n'ont pas pu être authentifiés" #: apt-private/private-download.cc msgid "Install these packages without verification?" -msgstr "Faut-il installer ces paquets sans vérification ?" +msgstr "Faut-il installer ces paquets sans vérification ?" #: apt-private/private-download.cc msgid "" @@ -2008,7 +2011,7 @@ msgstr "Erreur interne, « InstallPackages » appelé avec des paquets cassés #: apt-private/private-install.cc msgid "Packages need to be removed but remove is disabled." msgstr "" -"Les paquets doivent être enlevés mais la désinstallation est désactivée." +"Les paquets doivent être enlevés, mais la désinstallation est désactivée." #: apt-private/private-install.cc msgid "" @@ -2073,8 +2076,8 @@ msgstr "Après cette opération, %so d'espace disque seront libérés.\n" #: apt-private/private-install.cc msgid "Trivial Only specified but this is not a trivial operation." msgstr "" -"L'option --trivial-only a été indiquée mais il ne s'agit pas d'une opération " -"triviale." +"L'option --trivial-only a été indiquée, mais il ne s'agit pas d'une " +"opération triviale." # The space before the exclamation mark must not be a non-breaking space; this # sentence is supposed to be typed by a user who cannot see the difference. @@ -2099,7 +2102,7 @@ msgstr "" msgid "Abort." msgstr "Annulation." -#: apt-private/private-install.cc cmdline/apt-mark.cc +#: apt-private/private-install.cc msgid "Do you want to continue?" msgstr "Souhaitez-vous continuer ?" @@ -2686,10 +2689,8 @@ msgstr[1] "" msgid "All packages are up to date." msgstr "Tous les paquets sont à jour." -#: cmdline/apt-cache.cc cmdline/apt-mark.cc -#, fuzzy, c-format -#| msgid "%s does not take any arguments" -msgid "%s does not take any arguments" +#: cmdline/apt-cache.cc +msgid "apt-cache stats does not take any arguments" msgstr "La commande apt-cache ne prend pas de paramètre" #: cmdline/apt-cache.cc @@ -2776,8 +2777,8 @@ msgstr "" "\tapt-cache [options] show pkg1 [pkg2 ...]\n" "\n" "apt-cache recherche et affiche les informations disponibles à propos\n" -"des paquets installés et installables. Il fonctionne exclusivement sur \n" -"les données trouvées dans le cache local grâce à la commande « update »\n" +"des paquets installés et installables. Il fonctionne exclusivement sur\n" +"les données trouvées dans le cache local grâce à la commande « update »\n" "d'apt-get par exemple. Les informations affichées peuvent cependant être\n" "obsolètes si la dernière mise à jour est trop ancienne, mais en revanche\n" "apt-cache fonctionne indépendamment de la disponibilité des sources\n" @@ -2994,7 +2995,7 @@ msgstr "Supprime des paquets et leurs fichiers de configuration" #: cmdline/apt-get.cc cmdline/apt.cc msgid "Remove automatically all unused packages" -msgstr "Supprime automatiquement les dépendances inutilisés" +msgstr "Supprime automatiquement les dépendances inutilisées" #: cmdline/apt-get.cc msgid "Distribution upgrade, see apt-get(8)" @@ -3049,7 +3050,7 @@ msgstr "Le téléchargement a échoué" #: cmdline/apt-helper.cc #, c-format msgid "GetSrvRec failed for %s" -msgstr "GetSrvRec a échouté pour %s" +msgstr "GetSrvRec a échoué pour %s" #: cmdline/apt-helper.cc msgid "" @@ -3064,7 +3065,7 @@ msgstr "" " apt-helper [options] cat-file fichier ...\n" " apt-helper [options] download-file uri target-path\n" "\n" -"apt-helper embarque un grand nombre de commandes que les scripts pour \n" +"apt-helper embarque un grand nombre de commandes que les scripts pour\n" "l'interpréteur de commandes peuvent utiliser\n" "par exemple, la même configuration de proxy ou d'acquisition qu'APT " "utiliserait.\n" @@ -3085,7 +3086,7 @@ msgstr "Concaténer des fichiers, avec décompression automatique" #: cmdline/apt-helper.cc msgid "detect proxy using apt.conf" -msgstr "détecter la configuration proxy en utilisant apt.conf" +msgstr "Détecter la configuration proxy en utilisant apt.conf" #: cmdline/apt-helper.cc msgid "wait for system to be online" @@ -3093,7 +3094,7 @@ msgstr "En attente de la connexion du système" #: cmdline/apt-helper.cc msgid "drop privileges before running given command" -msgstr "" +msgstr "Se débarrasser des privilèges avant d'exécuter la commande donnée" #: cmdline/apt-internal-planner.cc msgid "" @@ -3141,16 +3142,6 @@ msgid "%s was already set to automatically installed.\n" msgstr "%s était déjà marqué comme installé automatiquement.\n" #: cmdline/apt-mark.cc -msgid "No changes necessary" -msgstr "" - -#: cmdline/apt-mark.cc -#, fuzzy -#| msgid "The following NEW packages will be installed:" -msgid "The following packages will be marked as automatically installed:" -msgstr "Les NOUVEAUX paquets suivants seront installés :" - -#: cmdline/apt-mark.cc #, c-format msgid "%s was already set on hold.\n" msgstr "%s était déjà marqué comme figé (« hold »).\n" @@ -3163,8 +3154,7 @@ msgstr "%s était déjà marqué comme non figé.\n" #: cmdline/apt-mark.cc msgid "Executing dpkg failed. Are you root?" msgstr "" -"Échec de l'exécution de dpkg. Possédez-vous les privilèges du " -"superutilisateur ?" +"Échec de l'exécution de dpkg. Possédez-vous les droits du superutilisateur ?" #: cmdline/apt-mark.cc #, c-format @@ -3217,12 +3207,6 @@ msgid "Mark the given packages as manually installed" msgstr "Marquer les paquets indiqués comme installés manuellement" #: cmdline/apt-mark.cc -#, fuzzy -#| msgid "Mark the given packages as automatically installed" -msgid "Mark all dependencies of meta packages as automatically installed." -msgstr "Marquer les paquets indiqués comme installés automatiquement" - -#: cmdline/apt-mark.cc msgid "Mark a package as held back" msgstr "Marquer un paquet comme maintenu dans une version" @@ -3256,7 +3240,7 @@ msgid "" msgstr "" "Usage : apt-sortpkgs [options] fichier1 [fichier2 ...]\n" "\n" -"apt-sortpgks est un outil simple permettant de trier les informations à \n" +"apt-sortpgks est un outil simple permettant de trier les informations à\n" "propos d'un paquet. Par défaut, il trie par information de paquets " "binaires,\n" "mais l'option -s peut être utilisée pour passer au tri par paquet source.\n" @@ -3679,7 +3663,7 @@ msgstr "Le serveur http a envoyé un en-tête « Content-Range » invalide" #: methods/basehttp.cc msgid "This HTTP server has broken range support" -msgstr "Ce serveur http possède un support des limites non-valide" +msgstr "Ce serveur http possède une gestion des limites non-valide" #: methods/basehttp.cc msgid "Unknown date format" @@ -8,14 +8,14 @@ # Dmitry Astapov <adept@despammed.com>, 2004. # Yuri Kozlov <kozlov.y@gmail.com>, 2004, 2005, 2006, 2007, 2008. # Yuri Kozlov <yuray@komyakino.ru>, 2009, 2010, 2012, 2015, 2016. -# Aleksej Shilin <rootlexx@mail.ru>, 2017, 2018. # Lev Lamberov <dogsleg@debian.org>, 2018. +# Aleksej Shilin <rootlexx@mail.ru>, 2017, 2018, 2019. msgid "" msgstr "" "Project-Id-Version: apt 1.8.0\n" "Report-Msgid-Bugs-To: APT Development Team <deity@lists.debian.org>\n" "POT-Creation-Date: 2019-01-23 16:49+0100\n" -"PO-Revision-Date: 2018-10-25 19:03+0300\n" +"PO-Revision-Date: 2019-01-29 21:20+0300\n" "Last-Translator: Aleksej Shilin <rootlexx@mail.ru>\n" "Language-Team: Russian <debian-l10n-russian@lists.debian.org>\n" "Language: ru\n" @@ -3058,13 +3058,11 @@ msgstr "%s уже помечен как установленный автома� #: cmdline/apt-mark.cc msgid "No changes necessary" -msgstr "" +msgstr "Никаких изменений не требуется" #: cmdline/apt-mark.cc -#, fuzzy -#| msgid "The following NEW packages will be installed:" msgid "The following packages will be marked as automatically installed:" -msgstr "Следующие НОВЫЕ пакеты будут установлены:" +msgstr "Следующие пакеты будут помечены как установленные автоматически:" #: cmdline/apt-mark.cc #, c-format @@ -3131,10 +3129,8 @@ msgid "Mark the given packages as manually installed" msgstr "пометить указанные пакеты как установленные вручную" #: cmdline/apt-mark.cc -#, fuzzy -#| msgid "Mark the given packages as automatically installed" msgid "Mark all dependencies of meta packages as automatically installed." -msgstr "пометить указанные пакеты как установленные автоматически" +msgstr "пометить все зависимости метапакетов как установленные автоматически" #: cmdline/apt-mark.cc msgid "Mark a package as held back" diff --git a/test/integration/test-apt-extracttemplates b/test/integration/test-apt-extracttemplates index 9b07ef79f..a47257cfd 100755 --- a/test/integration/test-apt-extracttemplates +++ b/test/integration/test-apt-extracttemplates @@ -44,6 +44,13 @@ Description: Some bar var testfileequal "$TEMPLATE" "$TEMPLATE_STR" CONFIG=$(cut -f4 -d' ' $OUT) testfileequal "$CONFIG" "$CONFIG_STR" + msgtest 'No extra files or directories in extraction directory' + if [ "$(find ./extracttemplates-out | wc -l)" = '3' ]; then + msgpass + else + msgfail + ls -l ./extracttemplates-out + fi # ensure that the format of the output string has the right number of dots for s in "$CONFIG" "$TEMPLATE"; do diff --git a/test/integration/test-apt-sources-deb822 b/test/integration/test-apt-sources-deb822 index fdf26fe97..8ffe0abe6 100755 --- a/test/integration/test-apt-sources-deb822 +++ b/test/integration/test-apt-sources-deb822 @@ -14,6 +14,8 @@ BASE='# some comment # that contains a : as well #Types: meep +# a free-standing comment appears + Types: deb #Types: deb-src URIs: http://ftp.debian.org/debian @@ -291,3 +293,69 @@ testsuccessequal --nomsg "'http://ftp.debian.org/debian/dists/stable/InRelease' 'http://ftp.debian.org/debian2/dists/sid/non-free/binary-powerpc/Packages.xz' ftp.debian.org_debian2_dists_sid_non-free_binary-powerpc_Packages 0 'http://ftp.debian.org/debian2/dists/sid/non-free/binary-all/Packages.xz' ftp.debian.org_debian2_dists_sid_non-free_binary-all_Packages 0 'http://ftp.debian.org/debian2/dists/sid/non-free/i18n/Translation-en.xz' ftp.debian.org_debian2_dists_sid_non-free_i18n_Translation-en 0 " aptget update --print-uris + +EXPECTEDUK="'http://ftp.uk.debian.org/debian/dists/stretch/InRelease' ftp.uk.debian.org_debian_dists_stretch_InRelease 0 +'http://ftp.uk.debian.org/debian/dists/stretch/main/source/Sources.xz' ftp.uk.debian.org_debian_dists_stretch_main_source_Sources 0 +'http://ftp.uk.debian.org/debian/dists/stretch/contrib/source/Sources.xz' ftp.uk.debian.org_debian_dists_stretch_contrib_source_Sources 0 +'http://ftp.uk.debian.org/debian/dists/stretch/non-free/source/Sources.xz' ftp.uk.debian.org_debian_dists_stretch_non-free_source_Sources 0 +'http://ftp.uk.debian.org/debian/dists/stretch/main/binary-i386/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_main_binary-i386_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/main/binary-all/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_main_binary-all_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/main/i18n/Translation-en.xz' ftp.uk.debian.org_debian_dists_stretch_main_i18n_Translation-en 0 +'http://ftp.uk.debian.org/debian/dists/stretch/contrib/binary-i386/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_contrib_binary-i386_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/contrib/binary-all/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_contrib_binary-all_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/contrib/i18n/Translation-en.xz' ftp.uk.debian.org_debian_dists_stretch_contrib_i18n_Translation-en 0 +'http://ftp.uk.debian.org/debian/dists/stretch/non-free/binary-i386/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_non-free_binary-i386_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/non-free/binary-all/Packages.xz' ftp.uk.debian.org_debian_dists_stretch_non-free_binary-all_Packages 0 +'http://ftp.uk.debian.org/debian/dists/stretch/non-free/i18n/Translation-en.xz' ftp.uk.debian.org_debian_dists_stretch_non-free_i18n_Translation-en 0 " + +msgcleantest 'Test deb822 sources.list file comments' 'top' +cat > $SOURCES <<EOF +#NOTE: Most preferred source listed first! + + +#=== NEW MULTI-LINE FORMAT =============== +Types: deb deb-src +URIs:http://ftp.uk.debian.org/debian/ +Suites: stretch +Components: main contrib non-free +EOF +testsuccessequal --nomsg "$EXPECTEDUK" aptget update --print-uris + +msgcleantest 'Test deb822 sources.list file comments' 'bottom' +cat > $SOURCES <<EOF +Types: deb deb-src +URIs:http://ftp.uk.debian.org/debian/ +Suites: stretch +Components: main contrib non-free +#=== NEW MULTI-LINE FORMAT =============== + + +#NOTE: Most preferred source listed first! +EOF +testsuccessequal --nomsg "$EXPECTEDUK" aptget update --print-uris + +msgcleantest 'Test deb822 sources.list file comments' 'both' +cat > $SOURCES <<EOF +#=== NEW MULTI-LINE FORMAT =============== + + +#NOTE: Most preferred source listed first! +Types: deb deb-src +URIs:http://ftp.uk.debian.org/debian/ +Suites: stretch +Components: main contrib non-free +#=== NEW MULTI-LINE FORMAT =============== + + +#NOTE: Most preferred source listed first! +EOF +testsuccessequal --nomsg "$EXPECTEDUK" aptget update --print-uris + + +msgcleantest 'Test deb822 sources.list file comments' 'empty' +cat > $SOURCES <<EOF +#=== NEW MULTI-LINE FORMAT =============== + + +EOF +testempty aptget update --print-uris diff --git a/test/integration/test-cve-2013-1051-InRelease-parsing b/test/integration/test-cve-2013-1051-InRelease-parsing index 6238057c3..1f0cbda04 100755 --- a/test/integration/test-cve-2013-1051-InRelease-parsing +++ b/test/integration/test-cve-2013-1051-InRelease-parsing @@ -46,9 +46,12 @@ touch -d '+1hour' aptarchive/dists/stable/InRelease listcurrentlistsdirectory | sed '/_InRelease/ d' > listsdir.lst msgtest 'apt-get update should ignore unsigned data in the' 'InRelease' testwarningequal "Get:1 http://localhost:${APTHTTPPORT} stable InRelease [$(stat -c%s aptarchive/dists/stable/InRelease) B] +Err:1 http://localhost:${APTHTTPPORT} stable InRelease + Splitting up ${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial/localhost:${APTHTTPPORT}_dists_stable_InRelease into data and signature failed Reading package lists... -W: Clearsigned file '${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial/localhost:${APTHTTPPORT}_dists_stable_InRelease' contains unsigned lines. -W: Clearsigned file '${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/localhost:${APTHTTPPORT}_dists_stable_InRelease' contains unsigned lines." --nomsg aptget update +W: An error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://localhost:${APTHTTPPORT} stable InRelease: Splitting up ${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial/localhost:${APTHTTPPORT}_dists_stable_InRelease into data and signature failed +W: Failed to fetch http://localhost:${APTHTTPPORT}/dists/stable/InRelease Splitting up ${TMPWORKINGDIRECTORY}/rootdir/var/lib/apt/lists/partial/localhost:${APTHTTPPORT}_dists_stable_InRelease into data and signature failed +W: Some index files failed to download. They have been ignored, or old ones used instead." --nomsg aptget update testfileequal './listsdir.lst' "$(listcurrentlistsdirectory | sed '/_InRelease/ d')" # ensure there is no package diff --git a/test/integration/test-cve-2019-3462-Release.gpg-payload b/test/integration/test-cve-2019-3462-Release.gpg-payload new file mode 100755 index 000000000..fd0f96713 --- /dev/null +++ b/test/integration/test-cve-2019-3462-Release.gpg-payload @@ -0,0 +1,43 @@ +#!/bin/sh +set -e + +# This is not covered by the CVE and harmless by itself, but used in +# the exploit and while harmless it is also pointless to allow it + +TESTDIR="$(readlink -f "$(dirname "$0")")" +. "$TESTDIR/framework" + +setupenvironment +configarchitecture 'amd64' + +export APT_DONT_SIGN='InRelease' + +insertpackage 'unstable' 'foo' 'all' '1' +setupaptarchive +rm -rf rootdir/var/lib/apt/lists + +verify() { + testfailure apt update + testsuccess grep '^ Detached signature file' rootdir/tmp/testfailure.output + testfailure apt show foo +} + +msgmsg 'Payload after detached signature' +find aptarchive -name 'Release.gpg' | while read FILE; do + cp -a "$FILE" "${FILE}.bak" + echo "evil payload" >> "$FILE" +done +verify + +msgmsg 'Payload in-between detached signatures' +find aptarchive -name 'Release.gpg' | while read FILE; do + cat "${FILE}.bak" >> "$FILE" +done +verify + +msgmsg 'Payload before detached signature' +find aptarchive -name 'Release.gpg' | while read FILE; do + echo "evil payload" > "$FILE" + cat "${FILE}.bak" >> "$FILE" +done +verify diff --git a/test/integration/test-method-gpgv b/test/integration/test-method-gpgv index 70521881d..bfa5af4c2 100755 --- a/test/integration/test-method-gpgv +++ b/test/integration/test-method-gpgv @@ -71,44 +71,60 @@ testrun() { [GNUPG:] VALIDSIG 891CC50E605796A0C6E733F74BC0A39C27CE74F9 2016-09-01 1472742629 0 4 0 1 11 00 891CC50E605796A0C6E733F74BC0A39C27CE74F9' } +echo 'Test' > message.data +cat >message.sig <<EOF +-----BEGIN PGP SIGNATURE----- + +iQFEBAEBCgAuFiEENKjp0Y2zIPNn6OqgWpDRQdusja4FAlhT7+kQHGpvZUBleGFt +cGxlLm9yZwAKCRBakNFB26yNrjvEB/9/e3jA1l0fvPafx9LEXcH8CLpUFQK7ra9l +3M4YAH4JKQlTG1be7ixruBRlCTh3YiSs66fKMeJeUYoxA2HPhvbGFEjQFAxunEYg +X/LBKv1mQWa+Q34P5GBjK8kQdLCN+yJAiUErmWNQG3GPninrxsC9tY5jcWvHeP1k +V7N3MLnNqzXaCJM24mnKidC5IDadUdQ8qC8c3rjUexQ8vBz0eucH56jbqV5oOcvx +pjlW965dCPIf3OI8q6J7bIOjyY+u/PTcVlqPq3TUz/ti6RkVbKpLH0D4ll3lUTns +JQt/+gJCPxHUJphy8sccBKhW29CLELJIIafvU30E1nWn9szh2Xjq +=TB1F +-----END PGP SIGNATURE----- +EOF + + gpgvmethod() { - echo '601 Configuration + echo "601 Configuration Config-Item: Debug::Acquire::gpgv=1 Config-Item: Dir::Bin::apt-key=./faked-apt-key Config-Item: APT::Hashes::SHA1::Weak=true 600 URI Acquire -URI: file:///dev/null -Filename: /dev/zero -' | runapt "${METHODSDIR}/gpgv" +URI: file://${TMPWORKINGDIRECTORY}/message.sig +Filename: ${TMPWORKINGDIRECTORY}/message.data +" | runapt "${METHODSDIR}/gpgv" } testrun gpgvmethod() { - echo '601 Configuration + echo "601 Configuration Config-Item: Debug::Acquire::gpgv=1 Config-Item: Dir::Bin::apt-key=./faked-apt-key Config-Item: APT::Hashes::SHA1::Weak=true 600 URI Acquire -URI: file:///dev/null -Filename: /dev/zero +URI: file://${TMPWORKINGDIRECTORY}/message.sig +Filename: ${TMPWORKINGDIRECTORY}/message.data Signed-By: /dev/null,34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE -' | runapt "${METHODSDIR}/gpgv" +" | runapt "${METHODSDIR}/gpgv" } testrun gpgvmethod() { - echo '601 Configuration + echo "601 Configuration Config-Item: Debug::Acquire::gpgv=1 Config-Item: Dir::Bin::apt-key=./faked-apt-key Config-Item: APT::Hashes::SHA1::Weak=true 600 URI Acquire -URI: file:///dev/null -Filename: /dev/zero +URI: file://${TMPWORKINGDIRECTORY}/message.sig +Filename: ${TMPWORKINGDIRECTORY}/message.data Signed-By: 34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE,/dev/null -' | runapt "${METHODSDIR}/gpgv" +" | runapt "${METHODSDIR}/gpgv" } testrun @@ -122,16 +138,16 @@ testsuccess grep '^\s\+Good:\s\+$' method.output testsuccess grep 'verified because the public key is not available: GOODSIG' method.output gpgvmethod() { - echo '601 Configuration + echo "601 Configuration Config-Item: Debug::Acquire::gpgv=1 Config-Item: Dir::Bin::apt-key=./faked-apt-key Config-Item: APT::Hashes::SHA1::Weak=true 600 URI Acquire -URI: file:///dev/null -Filename: /dev/zero +URI: file://${TMPWORKINGDIRECTORY}/message.sig +Filename: ${TMPWORKINGDIRECTORY}/message.data Signed-By: 34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE! -' | runapt "${METHODSDIR}/gpgv" +" | runapt "${METHODSDIR}/gpgv" } testgpgv 'Exact matched subkey signed with long keyid' 'Good: GOODSIG 5A90D141DBAC8DAE' '34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE!' '[GNUPG:] GOODSIG 5A90D141DBAC8DAE Sebastian Subkey <subkey@example.org> [GNUPG:] VALIDSIG 34A8E9D18DB320F367E8EAA05A90D141DBAC8DAE 2018-08-16 1534459673 0 4 0 1 11 00 4281DEDBD466EAE8C1F4157E5B6896415D44C43E' diff --git a/test/libapt/openmaybeclearsignedfile_test.cc b/test/libapt/openmaybeclearsignedfile_test.cc index 1f63fb8fc..0a4d4438a 100644 --- a/test/libapt/openmaybeclearsignedfile_test.cc +++ b/test/libapt/openmaybeclearsignedfile_test.cc @@ -111,7 +111,6 @@ TEST(OpenMaybeClearSignedFileTest,SignedFileWithContentHeaders) EXPECT_TRUE(fd.Eof()); } -// That isn't how multiple signatures are done TEST(OpenMaybeClearSignedFileTest,SignedFileWithTwoSignatures) { std::string tempfile; @@ -190,19 +189,16 @@ TEST(OpenMaybeClearSignedFileTest,TwoSimpleSignedFile) "-----END PGP SIGNATURE-----"); EXPECT_TRUE(_error->empty()); EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); - EXPECT_TRUE(OpenMaybeClearSignedFile(tempfile, fd)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); if (tempfile.empty() == false) unlink(tempfile.c_str()); EXPECT_FALSE(_error->empty()); - EXPECT_TRUE(fd.IsOpen()); - char buffer[100]; - EXPECT_TRUE(fd.ReadLine(buffer, sizeof(buffer))); - EXPECT_STREQ(buffer, "Test"); - EXPECT_TRUE(fd.Eof()); - ASSERT_FALSE(_error->empty()); + EXPECT_FALSE(fd.IsOpen()); + // technically they are signed, but we just want one message + EXPECT_TRUE(_error->PendingError()); std::string msg; - _error->PopMessage(msg); + EXPECT_TRUE(_error->PopMessage(msg)); EXPECT_EQ("Clearsigned file '" + tempfile + "' contains unsigned lines.", msg); } @@ -244,19 +240,15 @@ TEST(OpenMaybeClearSignedFileTest,GarbageTop) "-----END PGP SIGNATURE-----\n"); EXPECT_FALSE(StartsWithGPGClearTextSignature(tempfile)); EXPECT_TRUE(_error->empty()); - EXPECT_TRUE(OpenMaybeClearSignedFile(tempfile, fd)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); if (tempfile.empty() == false) unlink(tempfile.c_str()); - EXPECT_TRUE(fd.IsOpen()); - char buffer[100]; - EXPECT_TRUE(fd.ReadLine(buffer, sizeof(buffer))); - EXPECT_STREQ(buffer, "Test"); - EXPECT_TRUE(fd.Eof()); + EXPECT_FALSE(fd.IsOpen()); ASSERT_FALSE(_error->empty()); - ASSERT_FALSE(_error->PendingError()); + ASSERT_TRUE(_error->PendingError()); std::string msg; - _error->PopMessage(msg); + EXPECT_TRUE(_error->PopMessage(msg)); EXPECT_EQ("Clearsigned file '" + tempfile + "' does not start with a signed message block.", msg); } @@ -313,19 +305,15 @@ TEST(OpenMaybeClearSignedFileTest,GarbageBottom) "Garbage"); EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); EXPECT_TRUE(_error->empty()); - EXPECT_TRUE(OpenMaybeClearSignedFile(tempfile, fd)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); if (tempfile.empty() == false) unlink(tempfile.c_str()); - EXPECT_TRUE(fd.IsOpen()); - char buffer[100]; - EXPECT_TRUE(fd.ReadLine(buffer, sizeof(buffer))); - EXPECT_STREQ(buffer, "Test"); - EXPECT_TRUE(fd.Eof()); + EXPECT_FALSE(fd.IsOpen()); ASSERT_FALSE(_error->empty()); - ASSERT_FALSE(_error->PendingError()); + ASSERT_TRUE(_error->PendingError()); std::string msg; - _error->PopMessage(msg); + EXPECT_TRUE(_error->PopMessage(msg)); EXPECT_EQ("Clearsigned file '" + tempfile + "' contains unsigned lines.", msg); } @@ -347,7 +335,7 @@ TEST(OpenMaybeClearSignedFileTest,BogusNoSig) std::string msg; _error->PopMessage(msg); - EXPECT_EQ("Splitting of file " + tempfile + " failed as it doesn't contain all expected parts 0 1 0", msg); + EXPECT_EQ("Splitting of clearsigned file " + tempfile + " failed as it doesn't contain all expected parts", msg); } TEST(OpenMaybeClearSignedFileTest,BogusSigStart) @@ -371,3 +359,127 @@ TEST(OpenMaybeClearSignedFileTest,BogusSigStart) _error->PopMessage(msg); EXPECT_EQ("Signature in file " + tempfile + " wasn't closed", msg); } + +TEST(OpenMaybeClearSignedFileTest,DashedSignedFile) +{ + std::string tempfile; + FileFd fd; + createTemporaryFile("dashedsignedfile", fd, &tempfile, "-----BEGIN PGP SIGNED MESSAGE-----\n" +"Hash: SHA512\n" +"\n" +"- Test\n" +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iQFEBAEBCgAuFiEENKjp0Y2zIPNn6OqgWpDRQdusja4FAlhT7+kQHGpvZUBleGFt\n" +"cGxlLm9yZwAKCRBakNFB26yNrjvEB/9/e3jA1l0fvPafx9LEXcH8CLpUFQK7ra9l\n" +"3M4YAH4JKQlTG1be7ixruBRlCTh3YiSs66fKMeJeUYoxA2HPhvbGFEjQFAxunEYg\n" +"X/LBKv1mQWa+Q34P5GBjK8kQdLCN+yJAiUErmWNQG3GPninrxsC9tY5jcWvHeP1k\n" +"V7N3MLnNqzXaCJM24mnKidC5IDadUdQ8qC8c3rjUexQ8vBz0eucH56jbqV5oOcvx\n" +"pjlW965dCPIf3OI8q6J7bIOjyY+u/PTcVlqPq3TUz/ti6RkVbKpLH0D4ll3lUTns\n" +"JQt/+gJCPxHUJphy8sccBKhW29CLELJIIafvU30E1nWn9szh2Xjq\n" +"=TB1F\n" +"-----END PGP SIGNATURE-----\n"); + EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); + EXPECT_TRUE(OpenMaybeClearSignedFile(tempfile, fd)); + if (tempfile.empty() == false) + unlink(tempfile.c_str()); + EXPECT_TRUE(fd.IsOpen()); + char buffer[100]; + EXPECT_TRUE(fd.ReadLine(buffer, sizeof(buffer))); + EXPECT_STREQ(buffer, "Test"); + EXPECT_TRUE(fd.Eof()); +} +TEST(OpenMaybeClearSignedFileTest,StrangeDashArmorFile) +{ + std::string tempfile; + FileFd fd; + createTemporaryFile("strangedashfile", fd, &tempfile, "-----BEGIN PGP SIGNED MESSAGE-----\n" +"Hash: SHA512\n" +"-Hash: SHA512\n" +"\n" +"Test\n" +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iQFEBAEBCgAuFiEENKjp0Y2zIPNn6OqgWpDRQdusja4FAlhT7+kQHGpvZUBleGFt\n" +"cGxlLm9yZwAKCRBakNFB26yNrjvEB/9/e3jA1l0fvPafx9LEXcH8CLpUFQK7ra9l\n" +"3M4YAH4JKQlTG1be7ixruBRlCTh3YiSs66fKMeJeUYoxA2HPhvbGFEjQFAxunEYg\n" +"X/LBKv1mQWa+Q34P5GBjK8kQdLCN+yJAiUErmWNQG3GPninrxsC9tY5jcWvHeP1k\n" +"V7N3MLnNqzXaCJM24mnKidC5IDadUdQ8qC8c3rjUexQ8vBz0eucH56jbqV5oOcvx\n" +"pjlW965dCPIf3OI8q6J7bIOjyY+u/PTcVlqPq3TUz/ti6RkVbKpLH0D4ll3lUTns\n" +"JQt/+gJCPxHUJphy8sccBKhW29CLELJIIafvU30E1nWn9szh2Xjq\n" +"=TB1F\n" +"-----END PGP SIGNATURE-----\n"); + EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); + if (tempfile.empty() == false) + unlink(tempfile.c_str()); + EXPECT_FALSE(_error->empty()); + EXPECT_FALSE(fd.IsOpen()); + + std::string msg; + EXPECT_TRUE(_error->PendingError()); + EXPECT_TRUE(_error->PopMessage(msg)); + EXPECT_EQ("Clearsigned file '" + tempfile + "' contains unexpected line starting with a dash (armor)", msg); +} +TEST(OpenMaybeClearSignedFileTest,StrangeDashMsgFile) +{ + std::string tempfile; + FileFd fd; + createTemporaryFile("strangedashfile", fd, &tempfile, "-----BEGIN PGP SIGNED MESSAGE-----\n" +"Hash: SHA512\n" +"\n" +"-Test\n" +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iQFEBAEBCgAuFiEENKjp0Y2zIPNn6OqgWpDRQdusja4FAlhT7+kQHGpvZUBleGFt\n" +"cGxlLm9yZwAKCRBakNFB26yNrjvEB/9/e3jA1l0fvPafx9LEXcH8CLpUFQK7ra9l\n" +"3M4YAH4JKQlTG1be7ixruBRlCTh3YiSs66fKMeJeUYoxA2HPhvbGFEjQFAxunEYg\n" +"X/LBKv1mQWa+Q34P5GBjK8kQdLCN+yJAiUErmWNQG3GPninrxsC9tY5jcWvHeP1k\n" +"V7N3MLnNqzXaCJM24mnKidC5IDadUdQ8qC8c3rjUexQ8vBz0eucH56jbqV5oOcvx\n" +"pjlW965dCPIf3OI8q6J7bIOjyY+u/PTcVlqPq3TUz/ti6RkVbKpLH0D4ll3lUTns\n" +"JQt/+gJCPxHUJphy8sccBKhW29CLELJIIafvU30E1nWn9szh2Xjq\n" +"=TB1F\n" +"-----END PGP SIGNATURE-----\n"); + EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); + if (tempfile.empty() == false) + unlink(tempfile.c_str()); + EXPECT_FALSE(_error->empty()); + EXPECT_FALSE(fd.IsOpen()); + + std::string msg; + EXPECT_TRUE(_error->PendingError()); + EXPECT_TRUE(_error->PopMessage(msg)); + EXPECT_EQ("Clearsigned file '" + tempfile + "' contains unexpected line starting with a dash (msg)", msg); +} +TEST(OpenMaybeClearSignedFileTest,StrangeDashSigFile) +{ + std::string tempfile; + FileFd fd; + createTemporaryFile("strangedashfile", fd, &tempfile, "-----BEGIN PGP SIGNED MESSAGE-----\n" +"Hash: SHA512\n" +"\n" +"Test\n" +"-----BEGIN PGP SIGNATURE-----\n" +"\n" +"iQFEBAEBCgAuFiEENKjp0Y2zIPNn6OqgWpDRQdusja4FAlhT7+kQHGpvZUBleGFt\n" +"cGxlLm9yZwAKCRBakNFB26yNrjvEB/9/e3jA1l0fvPafx9LEXcH8CLpUFQK7ra9l\n" +"3M4YAH4JKQlTG1be7ixruBRlCTh3YiSs66fKMeJeUYoxA2HPhvbGFEjQFAxunEYg\n" +"-/LBKv1mQWa+Q34P5GBjK8kQdLCN+yJAiUErmWNQG3GPninrxsC9tY5jcWvHeP1k\n" +"V7N3MLnNqzXaCJM24mnKidC5IDadUdQ8qC8c3rjUexQ8vBz0eucH56jbqV5oOcvx\n" +"pjlW965dCPIf3OI8q6J7bIOjyY+u/PTcVlqPq3TUz/ti6RkVbKpLH0D4ll3lUTns\n" +"JQt/+gJCPxHUJphy8sccBKhW29CLELJIIafvU30E1nWn9szh2Xjq\n" +"=TB1F\n" +"-----END PGP SIGNATURE-----\n"); + EXPECT_TRUE(StartsWithGPGClearTextSignature(tempfile)); + EXPECT_FALSE(OpenMaybeClearSignedFile(tempfile, fd)); + if (tempfile.empty() == false) + unlink(tempfile.c_str()); + EXPECT_FALSE(_error->empty()); + EXPECT_FALSE(fd.IsOpen()); + + std::string msg; + EXPECT_TRUE(_error->PendingError()); + EXPECT_TRUE(_error->PopMessage(msg)); + EXPECT_EQ("Clearsigned file '" + tempfile + "' contains unexpected line starting with a dash (sig)", msg); +} diff --git a/test/libapt/tagfile_test.cc b/test/libapt/tagfile_test.cc index f455a8dcc..8823ff781 100644 --- a/test/libapt/tagfile_test.cc +++ b/test/libapt/tagfile_test.cc @@ -232,6 +232,8 @@ TEST(TagFileTest, Comments) FileFd fd; createTemporaryFile("commentfile", fd, NULL, "# Leading comments should be ignored.\n" "\n" +"# A wild second comment appears!\n" +"\n" "Source: foo\n" "#Package: foo\n" "Section: bar\n" |