diff options
Diffstat (limited to 'methods')
-rw-r--r-- | methods/cdrom.cc | 7 | ||||
-rw-r--r-- | methods/copy.cc | 10 | ||||
-rw-r--r-- | methods/file.cc | 54 | ||||
-rw-r--r-- | methods/ftp.cc | 3 | ||||
-rw-r--r-- | methods/ftp.h | 6 | ||||
-rw-r--r-- | methods/gpgv.cc | 87 | ||||
-rw-r--r-- | methods/gzip.cc | 4 | ||||
-rw-r--r-- | methods/http.h | 34 | ||||
-rw-r--r-- | methods/https.h | 34 | ||||
-rw-r--r-- | methods/mirror.h | 10 | ||||
-rw-r--r-- | methods/rred.cc | 124 | ||||
-rw-r--r-- | methods/rsh.cc | 22 | ||||
-rw-r--r-- | methods/rsh.h | 5 | ||||
-rw-r--r-- | methods/server.h | 4 |
14 files changed, 286 insertions, 118 deletions
diff --git a/methods/cdrom.cc b/methods/cdrom.cc index 10cb29f66..d9ddecb6a 100644 --- a/methods/cdrom.cc +++ b/methods/cdrom.cc @@ -42,9 +42,9 @@ class CDROMMethod : public pkgAcqMethod bool IsCorrectCD(URI want, string MountPath, string& NewID); bool AutoDetectAndMount(const URI, string &NewID); - virtual bool Fetch(FetchItem *Itm); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; string GetID(string Name); - virtual void Exit(); + virtual void Exit() APT_OVERRIDE; public: @@ -260,7 +260,8 @@ bool CDROMMethod::Fetch(FetchItem *Itm) struct stat Buf; if (stat(Res.Filename.c_str(),&Buf) != 0) return _error->Error(_("File not found")); - + + URIStart(Res); if (NewID.empty() == false) CurrentID = NewID; Res.LastModified = Buf.st_mtime; diff --git a/methods/copy.cc b/methods/copy.cc index a8e289df5..0c9f322e6 100644 --- a/methods/copy.cc +++ b/methods/copy.cc @@ -27,7 +27,7 @@ class CopyMethod : public pkgAcqMethod { - virtual bool Fetch(FetchItem *Itm); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; void CalculateHashes(FetchItem const * const Itm, FetchResult &Res); public: @@ -38,11 +38,7 @@ class CopyMethod : public pkgAcqMethod void CopyMethod::CalculateHashes(FetchItem const * const Itm, FetchResult &Res) { Hashes Hash(Itm->ExpectedHashes); - FileFd::CompressMode CompressMode = FileFd::None; - if (_config->FindB("Acquire::GzipIndexes", false) == true) - CompressMode = FileFd::Extension; - - FileFd Fd(Res.Filename, FileFd::ReadOnly, CompressMode); + FileFd Fd(Res.Filename, FileFd::ReadOnly, FileFd::Extension); Hash.AddFD(Fd); Res.TakeHashes(Hash); } @@ -53,7 +49,7 @@ void CopyMethod::CalculateHashes(FetchItem const * const Itm, FetchResult &Res) bool CopyMethod::Fetch(FetchItem *Itm) { // this ensures that relative paths work in copy - std::string File = Itm->Uri.substr(Itm->Uri.find(':')+1); + std::string const File = Itm->Uri.substr(Itm->Uri.find(':')+1); // Stat the file and send a start message struct stat Buf; diff --git a/methods/file.cc b/methods/file.cc index 043ab04b8..40e85bce5 100644 --- a/methods/file.cc +++ b/methods/file.cc @@ -30,7 +30,7 @@ class FileMethod : public pkgAcqMethod { - virtual bool Fetch(FetchItem *Itm); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; public: @@ -48,8 +48,27 @@ bool FileMethod::Fetch(FetchItem *Itm) if (Get.Host.empty() == false) return _error->Error(_("Invalid URI, local URIS must not start with //")); - // See if the file exists struct stat Buf; + // deal with destination files which might linger around + if (lstat(Itm->DestFile.c_str(), &Buf) == 0) + { + if ((Buf.st_mode & S_IFREG) != 0) + { + if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) + { + HashStringList const hsl = Itm->ExpectedHashes; + if (Itm->ExpectedHashes.VerifyFile(File)) + { + Res.Filename = Itm->DestFile; + Res.IMSHit = true; + } + } + } + } + if (Res.IMSHit != true) + unlink(Itm->DestFile.c_str()); + + // See if the file exists if (stat(File.c_str(),&Buf) == 0) { Res.Size = Buf.st_size; @@ -57,10 +76,23 @@ bool FileMethod::Fetch(FetchItem *Itm) Res.LastModified = Buf.st_mtime; Res.IMSHit = false; if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) - Res.IMSHit = true; + { + unsigned long long const filesize = Itm->ExpectedHashes.FileSize(); + if (filesize != 0 && filesize == Res.Size) + Res.IMSHit = true; + } + + Hashes Hash(Itm->ExpectedHashes); + FileFd Fd(File, FileFd::ReadOnly); + Hash.AddFD(Fd); + Res.TakeHashes(Hash); } + if (Res.IMSHit == false) + URIStart(Res); // See if the uncompressed file exists and reuse it + FetchResult AltRes; + AltRes.Filename.clear(); std::vector<std::string> extensions = APT::Configuration::getCompressorExtensions(); for (std::vector<std::string>::const_iterator ext = extensions.begin(); ext != extensions.end(); ++ext) { @@ -69,29 +101,25 @@ bool FileMethod::Fetch(FetchItem *Itm) std::string const unfile = File.substr(0, File.length() - ext->length() - 1); if (stat(unfile.c_str(),&Buf) == 0) { - FetchResult AltRes; AltRes.Size = Buf.st_size; AltRes.Filename = unfile; AltRes.LastModified = Buf.st_mtime; AltRes.IMSHit = false; if (Itm->LastModified == Buf.st_mtime && Itm->LastModified != 0) AltRes.IMSHit = true; - - URIDone(Res,&AltRes); - return true; + break; } // no break here as we could have situations similar to '.gz' vs '.tar.gz' here } } - if (Res.Filename.empty() == true) + if (AltRes.Filename.empty() == false) + URIDone(Res,&AltRes); + else if (Res.Filename.empty() == false) + URIDone(Res); + else return _error->Error(_("File not found")); - Hashes Hash(Itm->ExpectedHashes); - FileFd Fd(Res.Filename, FileFd::ReadOnly); - Hash.AddFD(Fd); - Res.TakeHashes(Hash); - URIDone(Res); return true; } /*}}}*/ diff --git a/methods/ftp.cc b/methods/ftp.cc index 92d8573f1..1a9a1c4eb 100644 --- a/methods/ftp.cc +++ b/methods/ftp.cc @@ -39,7 +39,6 @@ // Internet stuff #include <netinet/in.h> -#include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> @@ -746,7 +745,7 @@ bool FTPConn::CreateDataFd() } // Bind and listen - if (bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) + if (::bind(DataListenFd,BindAddr->ai_addr,BindAddr->ai_addrlen) < 0) { freeaddrinfo(BindAddr); return _error->Errno("bind",_("Could not bind a socket")); diff --git a/methods/ftp.h b/methods/ftp.h index 2efd28ec6..2c4e9f57a 100644 --- a/methods/ftp.h +++ b/methods/ftp.h @@ -10,8 +10,10 @@ #ifndef APT_FTP_H #define APT_FTP_H +#include <apt-pkg/acquire-method.h> #include <apt-pkg/strutl.h> +#include <sys/socket.h> #include <sys/types.h> #include <time.h> #include <string> @@ -71,8 +73,8 @@ class FTPConn class FtpMethod : public pkgAcqMethod { - virtual bool Fetch(FetchItem *Itm); - virtual bool Configuration(std::string Message); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; + virtual bool Configuration(std::string Message) APT_OVERRIDE; FTPConn *Server; diff --git a/methods/gpgv.cc b/methods/gpgv.cc index 41f138be6..490833d8c 100644 --- a/methods/gpgv.cc +++ b/methods/gpgv.cc @@ -15,6 +15,8 @@ #include <string.h> #include <sys/wait.h> #include <unistd.h> + +#include <algorithm> #include <iostream> #include <string> #include <vector> @@ -37,14 +39,15 @@ class GPGVMethod : public pkgAcqMethod { private: string VerifyGetSigners(const char *file, const char *outfile, - vector<string> &GoodSigners, + std::string const &key, + vector<string> &GoodSigners, vector<string> &BadSigners, vector<string> &WorthlessSigners, vector<string> &NoPubKeySigners); protected: - virtual bool Fetch(FetchItem *Itm); - virtual bool Configuration(string Message); + virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE; + virtual bool Configuration(string Message) APT_OVERRIDE; public: GPGVMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {}; @@ -61,6 +64,7 @@ bool GPGVMethod::Configuration(string Message) } string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, + std::string const &key, vector<string> &GoodSigners, vector<string> &BadSigners, vector<string> &WorthlessSigners, @@ -72,6 +76,7 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, std::clog << "inside VerifyGetSigners" << std::endl; int fd[2]; + bool const keyIsID = (key.empty() == false && key[0] != '/'); if (pipe(fd) < 0) return "Couldn't create pipe"; @@ -80,12 +85,13 @@ 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) - ExecGPGV(outfile, file, 3, fd); + ExecGPGV(outfile, file, 3, fd, (keyIsID ? "" : key)); close(fd[1]); FILE *pipein = fdopen(fd[0], "r"); // Loop over the output of apt-key (which really is gnupg), and check the signatures. + std::vector<std::string> ValidSigners; size_t buffersize = 0; char *buffer = NULL; while (1) @@ -105,32 +111,31 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, std::clog << "Got BADSIG! " << std::endl; BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - - if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0) + else if (strncmp(buffer, GNUPGNOPUBKEY, sizeof(GNUPGNOPUBKEY)-1) == 0) { if (Debug == true) std::clog << "Got NO_PUBKEY " << std::endl; NoPubKeySigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0) + else if (strncmp(buffer, GNUPGNODATA, sizeof(GNUPGBADSIG)-1) == 0) { if (Debug == true) std::clog << "Got NODATA! " << std::endl; BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0) + else if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0) { if (Debug == true) std::clog << "Got KEYEXPIRED! " << std::endl; WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0) + else if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0) { if (Debug == true) std::clog << "Got REVKEYSIG! " << std::endl; WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0) + else if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0) { char *sig = buffer + sizeof(GNUPGPREFIX); char *p = sig + sizeof("GOODSIG"); @@ -141,10 +146,48 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, std::clog << "Got GOODSIG, key ID:" << sig << std::endl; GoodSigners.push_back(string(sig)); } + else if (strncmp(buffer, GNUPGVALIDSIG, sizeof(GNUPGVALIDSIG)-1) == 0) + { + char *sig = buffer + sizeof(GNUPGVALIDSIG); + char *p = sig; + while (*p && isxdigit(*p)) + p++; + *p = 0; + if (Debug == true) + std::clog << "Got VALIDSIG, key ID: " << sig << std::endl; + ValidSigners.push_back(string(sig)); + } } fclose(pipein); free(buffer); + // apt-key has a --keyid parameter, but this requires gpg, so we call it without it + // and instead check after the fact which keyids where used for verification + if (keyIsID == true) + { + if (Debug == true) + std::clog << "GoodSigs needs to be limited to keyid " << key << std::endl; + std::vector<std::string>::iterator const foundItr = std::find(ValidSigners.begin(), ValidSigners.end(), key); + bool const found = (foundItr != ValidSigners.end()); + std::copy(GoodSigners.begin(), GoodSigners.end(), std::back_insert_iterator<std::vector<std::string> >(NoPubKeySigners)); + if (found) + { + // we look for GOODSIG here as well as an expired sig is a valid sig as well (but not a good one) + std::string const goodlongkeyid = "GOODSIG " + key.substr(24, 16); + bool const foundGood = std::find(GoodSigners.begin(), GoodSigners.end(), goodlongkeyid) != GoodSigners.end(); + if (Debug == true) + std::clog << "Key " << key << " is valid sig, is " << goodlongkeyid << " also a good one? " << (foundGood ? "yes" : "no") << std::endl; + GoodSigners.clear(); + if (foundGood) + { + GoodSigners.push_back(goodlongkeyid); + NoPubKeySigners.erase(std::remove(NoPubKeySigners.begin(), NoPubKeySigners.end(), goodlongkeyid), NoPubKeySigners.end()); + } + } + else + GoodSigners.clear(); + } + int status; waitpid(pid, &status, 0); if (Debug == true) @@ -154,8 +197,18 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, if (WEXITSTATUS(status) == 0) { - if (GoodSigners.empty()) - return _("Internal error: Good signature, but could not determine key fingerprint?!"); + if (keyIsID) + { + // gpgv will report success, but we want to enforce a certain keyring + // so if we haven't found the key the valid we found is in fact invalid + if (GoodSigners.empty()) + return _("At least one invalid signature was encountered."); + } + else + { + if (GoodSigners.empty()) + return _("Internal error: Good signature, but could not determine key fingerprint?!"); + } return ""; } else if (WEXITSTATUS(status) == 1) @@ -174,11 +227,11 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, return _("Unknown error executing apt-key"); } -bool GPGVMethod::Fetch(FetchItem *Itm) +bool GPGVMethod::URIAcquire(std::string const &Message, FetchItem *Itm) { - URI Get = Itm->Uri; - string Path = Get.Host + Get.Path; // To account for relative paths - string keyID; + URI const Get = Itm->Uri; + string const Path = Get.Host + Get.Path; // To account for relative paths + std::string const key = LookupTag(Message, "Signed-By"); vector<string> GoodSigners; vector<string> BadSigners; // a worthless signature is a expired or revoked one @@ -190,7 +243,7 @@ bool GPGVMethod::Fetch(FetchItem *Itm) URIStart(Res); // Run apt-key on file, extract contents and get the key ID of the signer - string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), + string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), key, GoodSigners, BadSigners, WorthlessSigners, NoPubKeySigners); if (GoodSigners.empty() || !BadSigners.empty() || !NoPubKeySigners.empty()) diff --git a/methods/gzip.cc b/methods/gzip.cc index 65519633c..637aae124 100644 --- a/methods/gzip.cc +++ b/methods/gzip.cc @@ -32,8 +32,8 @@ const char *Prog; class GzipMethod : public pkgAcqMethod { - virtual bool Fetch(FetchItem *Itm); - virtual bool Configuration(std::string Message); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; + virtual bool Configuration(std::string Message) APT_OVERRIDE; public: diff --git a/methods/http.h b/methods/http.h index e73871931..da6139b02 100644 --- a/methods/http.h +++ b/methods/http.h @@ -99,23 +99,23 @@ struct HttpServerState: public ServerState int ServerFd; protected: - virtual bool ReadHeaderLines(std::string &Data); - virtual bool LoadNextResponse(bool const ToFile, FileFd * const File); - virtual bool WriteResponse(std::string const &Data); + virtual bool ReadHeaderLines(std::string &Data) APT_OVERRIDE; + virtual bool LoadNextResponse(bool const ToFile, FileFd * const File) APT_OVERRIDE; + virtual bool WriteResponse(std::string const &Data) APT_OVERRIDE; public: - virtual void Reset() { ServerState::Reset(); ServerFd = -1; }; + virtual void Reset() APT_OVERRIDE { ServerState::Reset(); ServerFd = -1; }; - virtual bool RunData(FileFd * const File); + virtual bool RunData(FileFd * const File) APT_OVERRIDE; - virtual bool Open(); - virtual bool IsOpen(); - virtual bool Close(); - virtual bool InitHashes(HashStringList const &ExpectedHashes); - virtual Hashes * GetHashes(); - virtual bool Die(FileFd &File); - virtual bool Flush(FileFd * const File); - virtual bool Go(bool ToFile, FileFd * const File); + virtual bool Open() APT_OVERRIDE; + virtual bool IsOpen() APT_OVERRIDE; + virtual bool Close() APT_OVERRIDE; + virtual bool InitHashes(HashStringList const &ExpectedHashes) APT_OVERRIDE; + virtual Hashes * GetHashes() APT_OVERRIDE; + virtual bool Die(FileFd &File) APT_OVERRIDE; + virtual bool Flush(FileFd * const File) APT_OVERRIDE; + virtual bool Go(bool ToFile, FileFd * const File) APT_OVERRIDE; HttpServerState(URI Srv, HttpMethod *Owner); virtual ~HttpServerState() {Close();}; @@ -124,12 +124,12 @@ struct HttpServerState: public ServerState class HttpMethod : public ServerMethod { public: - virtual void SendReq(FetchItem *Itm); + virtual void SendReq(FetchItem *Itm) APT_OVERRIDE; - virtual bool Configuration(std::string Message); + virtual bool Configuration(std::string Message) APT_OVERRIDE; - virtual ServerState * CreateServerState(URI uri); - virtual void RotateDNS(); + virtual ServerState * CreateServerState(URI uri) APT_OVERRIDE; + virtual void RotateDNS() APT_OVERRIDE; protected: std::string AutoDetectProxyCmd; diff --git a/methods/https.h b/methods/https.h index 57fc292ee..29b20b921 100644 --- a/methods/https.h +++ b/methods/https.h @@ -32,23 +32,23 @@ class HttpsServerState : public ServerState Hashes * Hash; protected: - virtual bool ReadHeaderLines(std::string &/*Data*/) { return false; } - virtual bool LoadNextResponse(bool const /*ToFile*/, FileFd * const /*File*/) { return false; } + virtual bool ReadHeaderLines(std::string &/*Data*/) APT_OVERRIDE { return false; } + virtual bool LoadNextResponse(bool const /*ToFile*/, FileFd * const /*File*/) APT_OVERRIDE { return false; } public: - virtual bool WriteResponse(std::string const &/*Data*/) { return false; } + virtual bool WriteResponse(std::string const &/*Data*/) APT_OVERRIDE { return false; } /** \brief Transfer the data from the socket */ - virtual bool RunData(FileFd * const /*File*/) { return false; } + virtual bool RunData(FileFd * const /*File*/) APT_OVERRIDE { return false; } - virtual bool Open() { return false; } - virtual bool IsOpen() { return false; } - virtual bool Close() { return false; } - virtual bool InitHashes(HashStringList const &ExpectedHashes); - virtual Hashes * GetHashes(); - virtual bool Die(FileFd &/*File*/) { return false; } - virtual bool Flush(FileFd * const /*File*/) { return false; } - virtual bool Go(bool /*ToFile*/, FileFd * const /*File*/) { return false; } + virtual bool Open() APT_OVERRIDE { return false; } + virtual bool IsOpen() APT_OVERRIDE { return false; } + virtual bool Close() APT_OVERRIDE { return false; } + virtual bool InitHashes(HashStringList const &ExpectedHashes) APT_OVERRIDE; + virtual Hashes * GetHashes() APT_OVERRIDE; + virtual bool Die(FileFd &/*File*/) APT_OVERRIDE { return false; } + virtual bool Flush(FileFd * const /*File*/) APT_OVERRIDE { return false; } + virtual bool Go(bool /*ToFile*/, FileFd * const /*File*/) APT_OVERRIDE { return false; } HttpsServerState(URI Srv, HttpsMethod *Owner); virtual ~HttpsServerState() {Close();}; @@ -59,7 +59,7 @@ class HttpsMethod : public ServerMethod // minimum speed in bytes/se that triggers download timeout handling static const int DL_MIN_SPEED = 10; - virtual bool Fetch(FetchItem *); + virtual bool Fetch(FetchItem *) APT_OVERRIDE; static size_t parse_header(void *buffer, size_t size, size_t nmemb, void *userp); static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); @@ -70,14 +70,14 @@ class HttpsMethod : public ServerMethod ServerState *Server; // Used by ServerMethods unused by https - virtual void SendReq(FetchItem *) { exit(42); } - virtual void RotateDNS() { exit(42); } + virtual void SendReq(FetchItem *) APT_OVERRIDE { exit(42); } + virtual void RotateDNS() APT_OVERRIDE { exit(42); } public: FileFd *File; - virtual bool Configuration(std::string Message); - virtual ServerState * CreateServerState(URI uri); + virtual bool Configuration(std::string Message) APT_OVERRIDE; + virtual ServerState * CreateServerState(URI uri) APT_OVERRIDE; using pkgAcqMethod::FetchResult; using pkgAcqMethod::FetchItem; diff --git a/methods/mirror.h b/methods/mirror.h index 6c0ce370e..425bea673 100644 --- a/methods/mirror.h +++ b/methods/mirror.h @@ -46,14 +46,14 @@ class MirrorMethod : public HttpMethod bool Clean(std::string dir); // we need to overwrite those to transform the url back - virtual void Fail(std::string Why, bool Transient = false); - virtual void URIStart(FetchResult &Res); - virtual void URIDone(FetchResult &Res,FetchResult *Alt = 0); - virtual bool Configuration(std::string Message); + virtual void Fail(std::string Why, bool Transient = false) APT_OVERRIDE; + virtual void URIStart(FetchResult &Res) APT_OVERRIDE; + virtual void URIDone(FetchResult &Res,FetchResult *Alt = 0) APT_OVERRIDE; + virtual bool Configuration(std::string Message) APT_OVERRIDE; public: MirrorMethod(); - virtual bool Fetch(FetchItem *Itm); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; }; diff --git a/methods/rred.cc b/methods/rred.cc index 554ac99b4..91b6dda22 100644 --- a/methods/rred.cc +++ b/methods/rred.cc @@ -21,6 +21,7 @@ #include <vector> #include <assert.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -35,7 +36,7 @@ class MemBlock { char *start; size_t size; char *free; - struct MemBlock *next; + MemBlock *next; MemBlock(size_t size) : size(size), next(NULL) { @@ -116,7 +117,7 @@ struct Change { size_t add_len; /* bytes */ char *add; - Change(int off) + Change(size_t off) { offset = off; del_cnt = add_cnt = add_len = 0; @@ -388,28 +389,37 @@ class Patch { public: - void read_diff(FileFd &f) + bool read_diff(FileFd &f, Hashes * const h) { char buffer[BLOCK_SIZE]; bool cmdwanted = true; - Change ch(0); - while(f.ReadLine(buffer, sizeof(buffer))) - { + Change ch(std::numeric_limits<size_t>::max()); + if (f.ReadLine(buffer, sizeof(buffer)) == NULL) + return _error->Error("Reading first line of patchfile %s failed", f.Name().c_str()); + do { + if (h != NULL) + h->Add(buffer); if (cmdwanted) { char *m, *c; size_t s, e; - s = strtol(buffer, &m, 10); - if (m == buffer) { - s = e = ch.offset + ch.add_cnt; - c = buffer; - } else if (*m == ',') { - m++; + errno = 0; + s = strtoul(buffer, &m, 10); + if (unlikely(m == buffer || s == std::numeric_limits<unsigned long>::max() || errno != 0)) + return _error->Error("Parsing patchfile %s failed: Expected an effected line start", f.Name().c_str()); + else if (*m == ',') { + ++m; e = strtol(m, &c, 10); + if (unlikely(m == c || e == std::numeric_limits<unsigned long>::max() || errno != 0)) + return _error->Error("Parsing patchfile %s failed: Expected an effected line end", f.Name().c_str()); + if (unlikely(e < s)) + return _error->Error("Parsing patchfile %s failed: Effected lines end %lu is before start %lu", f.Name().c_str(), e, s); } else { e = s; c = m; } + if (s > ch.offset) + return _error->Error("Parsing patchfile %s failed: Effected line is after previous effected line", f.Name().c_str()); switch(*c) { case 'a': cmdwanted = false; @@ -420,6 +430,8 @@ class Patch { ch.del_cnt = 0; break; case 'c': + if (unlikely(s == 0)) + return _error->Error("Parsing patchfile %s failed: Change command can't effect line zero", f.Name().c_str()); cmdwanted = false; ch.add = NULL; ch.add_cnt = 0; @@ -428,6 +440,8 @@ class Patch { ch.del_cnt = e - s + 1; break; case 'd': + if (unlikely(s == 0)) + return _error->Error("Parsing patchfile %s failed: Delete command can't effect line zero", f.Name().c_str()); ch.offset = s - 1; ch.del_cnt = e - s + 1; ch.add = NULL; @@ -435,9 +449,11 @@ class Patch { ch.add_len = 0; filechanges.add_change(ch); break; + default: + return _error->Error("Parsing patchfile %s failed: Unknown command", f.Name().c_str()); } } else { /* !cmdwanted */ - if (buffer[0] == '.' && buffer[1] == '\n') { + if (strcmp(buffer, ".\n") == 0) { cmdwanted = true; filechanges.add_change(ch); } else { @@ -463,7 +479,8 @@ class Patch { } } } - } + } while(f.ReadLine(buffer, sizeof(buffer))); + return true; } void write_diff(FILE *f) @@ -519,8 +536,29 @@ class RredMethod : public pkgAcqMethod { private: bool Debug; + struct PDiffFile { + std::string FileName; + HashStringList ExpectedHashes; + PDiffFile(std::string const &FileName, HashStringList const &ExpectedHashes) : + FileName(FileName), ExpectedHashes(ExpectedHashes) {} + }; + + HashStringList ReadExpectedHashesForPatch(unsigned int const patch, std::string const &Message) + { + HashStringList ExpectedHashes; + for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type) + { + std::string tagname; + strprintf(tagname, "Patch-%d-%s-Hash", patch, *type); + std::string const hashsum = LookupTag(Message, tagname.c_str()); + if (hashsum.empty() == false) + ExpectedHashes.push_back(HashString(*type, hashsum)); + } + return ExpectedHashes; + } + protected: - virtual bool Fetch(FetchItem *Itm) { + virtual bool URIAcquire(std::string const &Message, FetchItem *Itm) APT_OVERRIDE { Debug = _config->FindB("Debug::pkgAcquire::RRed", false); URI Get = Itm->Uri; std::string Path = Get.Host + Get.Path; // rred:/path - no host @@ -534,11 +572,17 @@ class RredMethod : public pkgAcqMethod { } else URIStart(Res); - std::vector<std::string> patchpaths; + std::vector<PDiffFile> patchfiles; Patch patch; if (FileExists(Path + ".ed") == true) - patchpaths.push_back(Path + ".ed"); + { + HashStringList const ExpectedHashes = ReadExpectedHashesForPatch(0, Message); + std::string const FileName = Path + ".ed"; + if (ExpectedHashes.usable() == false) + return _error->Error("No hashes found for uncompressed patch: %s", FileName.c_str()); + patchfiles.push_back(PDiffFile(FileName, ExpectedHashes)); + } else { _error->PushToStack(); @@ -546,31 +590,44 @@ class RredMethod : public pkgAcqMethod { _error->RevertToStack(); std::string const baseName = Path + ".ed."; + unsigned int seen_patches = 0; for (std::vector<std::string>::const_iterator p = patches.begin(); p != patches.end(); ++p) + { if (p->compare(0, baseName.length(), baseName) == 0) - patchpaths.push_back(*p); + { + HashStringList const ExpectedHashes = ReadExpectedHashesForPatch(seen_patches, Message); + if (ExpectedHashes.usable() == false) + return _error->Error("No hashes found for uncompressed patch %d: %s", seen_patches, p->c_str()); + patchfiles.push_back(PDiffFile(*p, ExpectedHashes)); + ++seen_patches; + } + } } std::string patch_name; - for (std::vector<std::string>::iterator I = patchpaths.begin(); - I != patchpaths.end(); + for (std::vector<PDiffFile>::iterator I = patchfiles.begin(); + I != patchfiles.end(); ++I) { - patch_name = *I; + patch_name = I->FileName; if (Debug == true) std::clog << "Patching " << Path << " with " << patch_name << std::endl; FileFd p; + Hashes patch_hash(I->ExpectedHashes); // all patches are compressed, even if the name doesn't reflect it - if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false) { - std::cerr << "Could not open patch file " << patch_name << std::endl; + if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false || + patch.read_diff(p, &patch_hash) == false) + { _error->DumpErrors(std::cerr); - abort(); + return false; } - patch.read_diff(p); p.Close(); + HashStringList const hsl = patch_hash.GetHashStringList(); + if (hsl != I->ExpectedHashes) + return _error->Error("Hash Sum mismatch for uncompressed patch %s", patch_name.c_str()); } if (Debug == true) @@ -582,7 +639,6 @@ class RredMethod : public pkgAcqMethod { FILE *out = fopen(Itm->DestFile.c_str(), "w"); Hashes hash(Itm->ExpectedHashes); - patch.apply_against_file(out, inp, &hash); fclose(out); @@ -615,6 +671,16 @@ class RredMethod : public pkgAcqMethod { return true; } + bool Configuration(std::string Message) APT_OVERRIDE + { + if (pkgAcqMethod::Configuration(Message) == false) + return false; + + DropPrivsOrDie(); + + return true; + } + public: RredMethod() : pkgAcqMethod("2.0",SingleInstance | SendConfig), Debug(false) {} }; @@ -643,7 +709,11 @@ int main(int argc, char **argv) _error->DumpErrors(std::cerr); exit(1); } - patch.read_diff(p); + if (patch.read_diff(p, NULL) == false) + { + _error->DumpErrors(std::cerr); + exit(2); + } } if (just_diff) { diff --git a/methods/rsh.cc b/methods/rsh.cc index 52349c61c..7ef2f7c7a 100644 --- a/methods/rsh.cc +++ b/methods/rsh.cc @@ -84,7 +84,7 @@ bool RSHConn::Open() if (Process != -1) return true; - if (Connect(ServerName.Host,ServerName.User) == false) + if (Connect(ServerName.Host,ServerName.Port,ServerName.User) == false) return false; return true; @@ -93,8 +93,15 @@ bool RSHConn::Open() // RSHConn::Connect - Fire up rsh and connect /*{{{*/ // --------------------------------------------------------------------- /* */ -bool RSHConn::Connect(std::string Host, std::string User) +bool RSHConn::Connect(std::string Host, unsigned int Port, std::string User) { + char *PortStr = NULL; + if (Port != 0) + { + if (asprintf (&PortStr, "%d", Port) == -1 || PortStr == NULL) + return _error->Errno("asprintf", _("Failed")); + } + // Create the pipes int Pipes[4] = {-1,-1,-1,-1}; if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0) @@ -140,6 +147,10 @@ bool RSHConn::Connect(std::string Host, std::string User) Args[i++] = "-l"; Args[i++] = User.c_str(); } + if (PortStr != NULL) { + Args[i++] = "-p"; + Args[i++] = PortStr; + } if (Host.empty() == false) { Args[i++] = Host.c_str(); } @@ -149,6 +160,9 @@ bool RSHConn::Connect(std::string Host, std::string User) exit(100); } + if (PortStr != NULL) + free(PortStr); + ReadFd = Pipes[0]; WriteFd = Pipes[3]; SetNonBlock(Pipes[0],true); @@ -158,6 +172,10 @@ bool RSHConn::Connect(std::string Host, std::string User) return true; } +bool RSHConn::Connect(std::string Host, std::string User) +{ + return Connect(Host, 0, User); +} /*}}}*/ // RSHConn::ReadLine - Very simple buffered read with timeout /*{{{*/ // --------------------------------------------------------------------- diff --git a/methods/rsh.h b/methods/rsh.h index dd259e744..e6839711b 100644 --- a/methods/rsh.h +++ b/methods/rsh.h @@ -36,6 +36,7 @@ class RSHConn // Raw connection IO bool WriteMsg(std::string &Text,bool Sync,const char *Fmt,...); bool Connect(std::string Host, std::string User); + bool Connect(std::string Host, unsigned int Port, std::string User); bool Comp(URI Other) const {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; // Connection control @@ -56,8 +57,8 @@ class RSHConn class RSHMethod : public pkgAcqMethod { - virtual bool Fetch(FetchItem *Itm); - virtual bool Configuration(std::string Message); + virtual bool Fetch(FetchItem *Itm) APT_OVERRIDE; + virtual bool Configuration(std::string Message) APT_OVERRIDE; RSHConn *Server; diff --git a/methods/server.h b/methods/server.h index 8d7d33ee6..f9f6e9071 100644 --- a/methods/server.h +++ b/methods/server.h @@ -106,7 +106,7 @@ struct ServerState class ServerMethod : public pkgAcqMethod { protected: - virtual bool Fetch(FetchItem *); + virtual bool Fetch(FetchItem *) APT_OVERRIDE; ServerState *Server; std::string NextURI; @@ -146,7 +146,7 @@ class ServerMethod : public pkgAcqMethod static time_t FailTime; static APT_NORETURN void SigTerm(int); - virtual bool Configuration(std::string Message); + virtual bool Configuration(std::string Message) APT_OVERRIDE; virtual bool Flush() { return Server->Flush(File); }; int Loop(); |