summaryrefslogtreecommitdiff
path: root/methods
diff options
context:
space:
mode:
Diffstat (limited to 'methods')
-rw-r--r--methods/cdrom.cc129
-rw-r--r--methods/gpgv.cc42
-rw-r--r--methods/http.cc82
-rw-r--r--methods/http.h3
-rw-r--r--methods/https.cc6
-rw-r--r--methods/makefile4
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)