diff options
Diffstat (limited to 'methods')
-rw-r--r-- | methods/cdrom.cc | 129 | ||||
-rw-r--r-- | methods/gpgv.cc | 42 | ||||
-rw-r--r-- | methods/http.cc | 82 | ||||
-rw-r--r-- | methods/http.h | 3 | ||||
-rw-r--r-- | methods/https.cc | 6 | ||||
-rw-r--r-- | methods/makefile | 4 |
6 files changed, 229 insertions, 37 deletions
diff --git a/methods/cdrom.cc b/methods/cdrom.cc index 601bc11c9..9802eb46c 100644 --- a/methods/cdrom.cc +++ b/methods/cdrom.cc @@ -9,6 +9,7 @@ /*}}}*/ // Include Files /*{{{*/ #include <apt-pkg/acquire-method.h> +#include <apt-pkg/cdrom.h> #include <apt-pkg/cdromutl.h> #include <apt-pkg/error.h> #include <apt-pkg/configuration.h> @@ -17,6 +18,7 @@ #include <sys/stat.h> #include <unistd.h> +#include <dlfcn.h> #include <iostream> #include <apti18n.h> @@ -27,15 +29,20 @@ using namespace std; class CDROMMethod : public pkgAcqMethod { bool DatabaseLoaded; + bool Debug; + ::Configuration Database; string CurrentID; string CDROM; bool MountedByApt; - + pkgUdevCdromDevices UdevCdroms; + + bool IsCorrectCD(URI want, string MountPath); + bool AutoDetectAndMount(URI); virtual bool Fetch(FetchItem *Itm); string GetID(string Name); virtual void Exit(); - + public: CDROMMethod(); @@ -50,14 +57,15 @@ CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly | DatabaseLoaded(false), MountedByApt(false) { + UdevCdroms.Dlopen(); }; /*}}}*/ // CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/ // --------------------------------------------------------------------- /* */ void CDROMMethod::Exit() -{ - if (MountedByApt == true) +{ + if (MountedByApt == true) UnmountCdrom(CDROM); } /*}}}*/ @@ -81,16 +89,94 @@ string CDROMMethod::GetID(string Name) return string(); } /*}}}*/ +// CDROMMethod::AutoDetectAndMount /*{{{*/ +// --------------------------------------------------------------------- +/* Modifies class varaiable CDROM to the mountpoint */ +bool CDROMMethod::AutoDetectAndMount(URI Get) +{ + vector<struct CdromDevice> v = UdevCdroms.Scan(); + + // first check if its mounted somewhere already + for (unsigned int i=0; i < v.size(); i++) + { + if (v[i].Mounted) + { + if (Debug) + clog << "Checking mounted cdrom device " << v[i].DeviceName << endl; + if (IsCorrectCD(Get, v[i].MountPath)) + { + CDROM = v[i].MountPath; + return true; + } + } + } + + // we are not supposed to mount, exit + if (_config->FindB("APT::CDROM::NoMount",false) == true) + return false; + + // check if we have the mount point + if (!FileExists("/media/apt")) + mkdir("/media/apt", 0755); + + // now try mounting + for (unsigned int i=0; i < v.size(); i++) + { + if (!v[i].Mounted) + { + if(MountCdrom("/media/apt", v[i].DeviceName)) + { + if (IsCorrectCD(Get, "/media/apt")) + { + MountedByApt = true; + CDROM = "/media/apt"; + return true; + } else { + UnmountCdrom("/media/apt"); + } + } + } + } + + return false; +} + /*}}}*/ +// CDROMMethod::IsCorrectCD /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool CDROMMethod::IsCorrectCD(URI want, string MountPath) +{ + string NewID; + + for (unsigned int Version = 2; Version != 0; Version--) + { + if (IdentCdrom(MountPath,NewID,Version) == false) + return false; + + if (Debug) + clog << "ID " << Version << " " << NewID << endl; + + // A hit + if (Database.Find("CD::" + NewID) == want.Host) + return true; + } + + return false; +} + /*}}}*/ // CDROMMethod::Fetch - Fetch a file /*{{{*/ // --------------------------------------------------------------------- /* */ bool CDROMMethod::Fetch(FetchItem *Itm) { + FetchResult Res; + URI Get = Itm->Uri; string File = Get.Path; - FetchResult Res; + Debug = _config->FindB("Debug::Acquire::cdrom", false); - bool Debug = _config->FindB("Debug::Acquire::cdrom",false); + if (Debug) + clog << "CDROMMethod::Fetch " << Itm->Uri << endl; /* All IMS queries are returned as a hit, CDROMs are readonly so time stamps never change */ @@ -126,38 +212,31 @@ bool CDROMMethod::Fetch(FetchItem *Itm) } // We already have a CD inserted, but it is the wrong one - if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host) + if (CurrentID.empty() == false && + CurrentID != "FAIL" && + Database.Find("CD::" + CurrentID) != Get.Host) { Fail(_("Wrong CD-ROM"),true); return true; } - + CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/"); + if (Debug) + clog << "Looking for CDROM at " << CDROM << endl; + if (CDROM[0] == '.') CDROM= SafeGetCWD() + '/' + CDROM; string NewID; + while (CurrentID.empty() == true) { - bool Hit = false; + if (CDROM == "apt-udev-auto/") + AutoDetectAndMount(Get); + if(!IsMounted(CDROM)) MountedByApt = MountCdrom(CDROM); - for (unsigned int Version = 2; Version != 0; Version--) - { - if (IdentCdrom(CDROM,NewID,Version) == false) - return false; - - if (Debug == true) - clog << "ID " << Version << " " << NewID << endl; - // A hit - if (Database.Find("CD::" + NewID) == Get.Host) - { - Hit = true; - break; - } - } - - if (Hit == true) + if (IsCorrectCD(Get, CDROM)) break; // I suppose this should prompt somehow? diff --git a/methods/gpgv.cc b/methods/gpgv.cc index 9f4683e6e..150c1d315 100644 --- a/methods/gpgv.cc +++ b/methods/gpgv.cc @@ -17,13 +17,18 @@ #define GNUPGBADSIG "[GNUPG:] BADSIG" #define GNUPGNOPUBKEY "[GNUPG:] NO_PUBKEY" #define GNUPGVALIDSIG "[GNUPG:] VALIDSIG" +#define GNUPGGOODSIG "[GNUPG:] GOODSIG" +#define GNUPGKEYEXPIRED "[GNUPG:] KEYEXPIRED" +#define GNUPGREVKEYSIG "[GNUPG:] REVKEYSIG" #define GNUPGNODATA "[GNUPG:] NODATA" class GPGVMethod : public pkgAcqMethod { private: string VerifyGetSigners(const char *file, const char *outfile, - vector<string> &GoodSigners, vector<string> &BadSigners, + vector<string> &GoodSigners, + vector<string> &BadSigners, + vector<string> &WorthlessSigners, vector<string> &NoPubKeySigners); protected: @@ -37,6 +42,7 @@ class GPGVMethod : public pkgAcqMethod string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, vector<string> &GoodSigners, vector<string> &BadSigners, + vector<string> &WorthlessSigners, vector<string> &NoPubKeySigners) { // setup a (empty) stringstream for formating the return value @@ -179,15 +185,27 @@ string GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, std::cerr << "Got NODATA! " << std::endl; BadSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); } - if (strncmp(buffer, GNUPGVALIDSIG, sizeof(GNUPGVALIDSIG)-1) == 0) + if (strncmp(buffer, GNUPGKEYEXPIRED, sizeof(GNUPGKEYEXPIRED)-1) == 0) + { + if (_config->FindB("Debug::Acquire::gpgv", false)) + std::cerr << "Got KEYEXPIRED! " << std::endl; + WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); + } + if (strncmp(buffer, GNUPGREVKEYSIG, sizeof(GNUPGREVKEYSIG)-1) == 0) + { + if (_config->FindB("Debug::Acquire::gpgv", false)) + std::cerr << "Got REVKEYSIG! " << std::endl; + WorthlessSigners.push_back(string(buffer+sizeof(GNUPGPREFIX))); + } + if (strncmp(buffer, GNUPGGOODSIG, sizeof(GNUPGGOODSIG)-1) == 0) { char *sig = buffer + sizeof(GNUPGPREFIX); - char *p = sig + sizeof("VALIDSIG"); + char *p = sig + sizeof("GOODSIG"); while (*p && isxdigit(*p)) p++; *p = 0; if (_config->FindB("Debug::Acquire::gpgv", false)) - std::cerr << "Got VALIDSIG, key ID:" << sig << std::endl; + std::cerr << "Got GOODSIG, key ID:" << sig << std::endl; GoodSigners.push_back(string(sig)); } } @@ -227,6 +245,8 @@ bool GPGVMethod::Fetch(FetchItem *Itm) string keyID; vector<string> GoodSigners; vector<string> BadSigners; + // a worthless signature is a expired or revoked one + vector<string> WorthlessSigners; vector<string> NoPubKeySigners; FetchResult Res; @@ -235,13 +255,14 @@ bool GPGVMethod::Fetch(FetchItem *Itm) // Run gpgv on file, extract contents and get the key ID of the signer string msg = VerifyGetSigners(Path.c_str(), Itm->DestFile.c_str(), - GoodSigners, BadSigners, NoPubKeySigners); + GoodSigners, BadSigners, WorthlessSigners, + NoPubKeySigners); if (GoodSigners.empty() || !BadSigners.empty() || !NoPubKeySigners.empty()) { string errmsg; // In this case, something bad probably happened, so we just go // with what the other method gave us for an error message. - if (BadSigners.empty() && NoPubKeySigners.empty()) + if (BadSigners.empty() && WorthlessSigners.empty() && NoPubKeySigners.empty()) errmsg = msg; else { @@ -252,6 +273,13 @@ bool GPGVMethod::Fetch(FetchItem *Itm) I != BadSigners.end(); I++) errmsg += (*I + "\n"); } + if (!WorthlessSigners.empty()) + { + errmsg += _("The following signatures were invalid:\n"); + for (vector<string>::iterator I = WorthlessSigners.begin(); + I != WorthlessSigners.end(); I++) + errmsg += (*I + "\n"); + } if (!NoPubKeySigners.empty()) { errmsg += _("The following signatures couldn't be verified because the public key is not available:\n"); @@ -264,7 +292,7 @@ bool GPGVMethod::Fetch(FetchItem *Itm) // least one bad signature. good signatures and NoPubKey signatures // happen easily when a file is signed with multiple signatures if(GoodSigners.empty() or !BadSigners.empty()) - return _error->Error(errmsg.c_str()); + return _error->Error("%s", errmsg.c_str()); } // Just pass the raw output up, because passing it as a real data diff --git a/methods/http.cc b/methods/http.cc index 5d18b3adc..1eba0f279 100644 --- a/methods/http.cc +++ b/methods/http.cc @@ -39,6 +39,7 @@ #include <errno.h> #include <string.h> #include <iostream> +#include <map> #include <apti18n.h> // Internet stuff @@ -57,6 +58,7 @@ int HttpMethod::FailFd = -1; time_t HttpMethod::FailTime = 0; unsigned long PipelineDepth = 10; unsigned long TimeOut = 120; +bool AllowRedirect = false; bool Debug = false; URI Proxy; @@ -633,6 +635,12 @@ bool ServerState::HeaderLine(string Line) return true; } + if (stringcasecmp(Tag,"Location:") == 0) + { + Location = Val; + return true; + } + return true; } /*}}}*/ @@ -905,7 +913,9 @@ bool HttpMethod::ServerDie(ServerState *Srv) 1 - IMS hit 3 - Unrecoverable error 4 - Error with error content page - 5 - Unrecoverable non-server error (close the connection) */ + 5 - Unrecoverable non-server error (close the connection) + 6 - Try again with a new or changed URI + */ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) { // Not Modified @@ -917,6 +927,27 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) return 1; } + /* Redirect + * + * Note that it is only OK for us to treat all redirection the same + * because we *always* use GET, not other HTTP methods. There are + * three redirection codes for which it is not appropriate that we + * redirect. Pass on those codes so the error handling kicks in. + */ + if (AllowRedirect + && (Srv->Result > 300 && Srv->Result < 400) + && (Srv->Result != 300 // Multiple Choices + && Srv->Result != 304 // Not Modified + && Srv->Result != 306)) // (Not part of HTTP/1.1, reserved) + { + if (!Srv->Location.empty()) + { + NextURI = Srv->Location; + return 6; + } + /* else pass through for error message */ + } + /* We have a reply we dont handle. This should indicate a perm server failure */ if (Srv->Result < 200 || Srv->Result >= 300) @@ -1031,6 +1062,7 @@ bool HttpMethod::Configuration(string Message) if (pkgAcqMethod::Configuration(Message) == false) return false; + AllowRedirect = _config->FindB("Acquire::http::AllowRedirect",true); TimeOut = _config->FindI("Acquire::http::Timeout",TimeOut); PipelineDepth = _config->FindI("Acquire::http::Pipeline-Depth", PipelineDepth); @@ -1044,6 +1076,10 @@ bool HttpMethod::Configuration(string Message) /* */ int HttpMethod::Loop() { + typedef vector<string> StringVector; + typedef vector<string>::iterator StringVectorIterator; + map<string, StringVector> Redirected; + signal(SIGTERM,SigTerm); signal(SIGINT,SigTerm); @@ -1230,6 +1266,46 @@ int HttpMethod::Loop() break; } + // Try again with a new URL + case 6: + { + // Clear rest of response if there is content + if (Server->HaveContent) + { + File = new FileFd("/dev/null",FileFd::WriteExists); + Server->RunData(); + delete File; + File = 0; + } + + /* Detect redirect loops. No more redirects are allowed + after the same URI is seen twice in a queue item. */ + StringVector &R = Redirected[Queue->DestFile]; + bool StopRedirects = false; + if (R.size() == 0) + R.push_back(Queue->Uri); + else if (R[0] == "STOP" || R.size() > 10) + StopRedirects = true; + else + { + for (StringVectorIterator I = R.begin(); I != R.end(); I++) + if (Queue->Uri == *I) + { + R[0] = "STOP"; + break; + } + + R.push_back(Queue->Uri); + } + + if (StopRedirects == false) + Redirect(NextURI); + else + Fail(); + + break; + } + default: Fail(_("Internal error")); break; @@ -1245,9 +1321,11 @@ int HttpMethod::Loop() int main() { setlocale(LC_ALL, ""); + // ignore SIGPIPE, this can happen on write() if the socket + // closes the connection (this is dealt with via ServerDie()) + signal(SIGPIPE, SIG_IGN); HttpMethod Mth; - return Mth.Loop(); } diff --git a/methods/http.h b/methods/http.h index 6753a9901..13f02ec77 100644 --- a/methods/http.h +++ b/methods/http.h @@ -99,6 +99,7 @@ struct ServerState enum {Chunked,Stream,Closes} Encoding; enum {Header, Data} State; bool Persistent; + string Location; // This is a Persistent attribute of the server itself. bool Pipeline; @@ -143,6 +144,8 @@ class HttpMethod : public pkgAcqMethod static time_t FailTime; static void SigTerm(int); + string NextURI; + public: friend class ServerState; diff --git a/methods/https.cc b/methods/https.cc index 728869fa2..37d93e308 100644 --- a/methods/https.cc +++ b/methods/https.cc @@ -215,6 +215,11 @@ bool HttpsMethod::Fetch(FetchItem *Itm) curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + // set redirect options and default to 10 redirects + bool AllowRedirect = _config->FindI("Acquire::https::AllowRedirect", true); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, AllowRedirect); + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10); + // debug if(_config->FindB("Debug::Acquire::https", false)) curl_easy_setopt(curl, CURLOPT_VERBOSE, true); @@ -255,7 +260,6 @@ bool HttpsMethod::Fetch(FetchItem *Itm) // cleanup if(success != 0) { - unlink(File->Name().c_str()); _error->Error("%s", curl_errorstr); Fail(); return true; diff --git a/methods/makefile b/methods/makefile index d9481dbcc..134166ba3 100644 --- a/methods/makefile +++ b/methods/makefile @@ -7,7 +7,7 @@ include ../buildlib/defaults.mak BIN := $(BIN)/methods # FIXME.. -LIB_APT_PKG_MAJOR = 4.6 +LIB_APT_PKG_MAJOR = 4.8 APT_DOMAIN := libapt-pkg$(LIB_APT_PKG_MAJOR) # The file method @@ -40,7 +40,7 @@ include $(PROGRAM_H) # The cdrom method PROGRAM=cdrom -SLIBS = -lapt-pkg $(INTLLIBS) +SLIBS = -lapt-pkg -ldl $(INTLLIBS) LIB_MAKES = apt-pkg/makefile SOURCE = cdrom.cc include $(PROGRAM_H) |