+pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire *Owner, /*{{{*/
+ string URI,string URIDesc,string ShortDesc,
+ string SigFile,
+ const vector<struct IndexTarget*>* IndexTargets,
+ indexRecords* MetaIndexParser) :
+ Item(Owner), RealURI(URI), SigFile(SigFile), IndexTargets(IndexTargets),
+ MetaIndexParser(MetaIndexParser), AuthPass(false), IMSHit(false)
+{
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(URI);
+
+ // Create the item
+ Desc.Description = URIDesc;
+ Desc.Owner = this;
+ Desc.ShortDesc = ShortDesc;
+ Desc.URI = URI;
+
+ QueueURI(Desc);
+}
+ /*}}}*/
+// pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
+// ---------------------------------------------------------------------
+/* The only header we use is the last-modified header. */
+string pkgAcqMetaIndex::Custom600Headers()
+{
+ string Final = _config->FindDir("Dir::State::lists");
+ Final += URItoFileName(RealURI);
+
+ struct stat Buf;
+ if (stat(Final.c_str(),&Buf) != 0)
+ return "\nIndex-File: true";
+
+ return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+}
+ /*}}}*/
+void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string Hash, /*{{{*/
+ pkgAcquire::MethodConfig *Cfg)
+{
+ Item::Done(Message,Size,Hash,Cfg);
+
+ // MetaIndexes are done in two passes: one to download the
+ // metaindex with an appropriate method, and a second to verify it
+ // with the gpgv method
+
+ if (AuthPass == true)
+ {
+ AuthDone(Message);
+ }
+ else
+ {
+ RetrievalDone(Message);
+ if (!Complete)
+ // Still more retrieving to do
+ return;
+
+ if (SigFile == "")
+ {
+ // There was no signature file, so we are finished. Download
+ // the indexes without verification.
+ QueueIndexes(false);
+ }
+ else
+ {
+ // There was a signature file, so pass it to gpgv for
+ // verification
+
+ if (_config->FindB("Debug::pkgAcquire::Auth", false))
+ std::cerr << "Metaindex acquired, queueing gpg verification ("
+ << SigFile << "," << DestFile << ")\n";
+ AuthPass = true;
+ Desc.URI = "gpgv:" + SigFile;
+ QueueURI(Desc);
+ Mode = "gpgv";
+ }
+ }
+}
+ /*}}}*/
+void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/
+{
+ // We have just finished downloading a Release file (it is not
+ // verified yet)
+
+ string FileName = LookupTag(Message,"Filename");
+ if (FileName.empty() == true)
+ {
+ Status = StatError;
+ ErrorText = "Method gave a blank filename";
+ return;
+ }
+
+ if (FileName != DestFile)
+ {
+ Local = true;
+ Desc.URI = "copy:" + FileName;
+ QueueURI(Desc);
+ return;
+ }
+
+ // see if the download was a IMSHit
+ IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false);
+ Complete = true;
+
+ string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+
+ // If we get a IMS hit we can remove the empty file in partial
+ // othersie we move the file in place
+ if (IMSHit)
+ unlink(DestFile.c_str());
+ else
+ Rename(DestFile,FinalFile);
+
+ chmod(FinalFile.c_str(),0644);
+ DestFile = FinalFile;
+}
+ /*}}}*/
+void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/
+{
+ // At this point, the gpgv method has succeeded, so there is a
+ // valid signature from a key in the trusted keyring. We
+ // perform additional verification of its contents, and use them
+ // to verify the indexes we are about to download
+
+ if (!MetaIndexParser->Load(DestFile))
+ {
+ Status = StatAuthError;
+ ErrorText = MetaIndexParser->ErrorText;
+ return;
+ }
+
+ if (!VerifyVendor(Message))
+ {
+ return;
+ }
+
+ if (_config->FindB("Debug::pkgAcquire::Auth", false))
+ std::cerr << "Signature verification succeeded: "
+ << DestFile << std::endl;
+
+ // Download further indexes with verification
+ QueueIndexes(true);
+
+ // Done, move signature file into position
+
+ string VerifiedSigFile = _config->FindDir("Dir::State::lists") +
+ URItoFileName(RealURI) + ".gpg";
+ Rename(SigFile,VerifiedSigFile);
+ chmod(VerifiedSigFile.c_str(),0644);
+}
+ /*}}}*/
+void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/
+{
+ for (vector <struct IndexTarget*>::const_iterator Target = IndexTargets->begin();
+ Target != IndexTargets->end();
+ Target++)
+ {
+ HashString ExpectedIndexHash;
+ if (verify)
+ {
+ const indexRecords::checkSum *Record = MetaIndexParser->Lookup((*Target)->MetaKey);
+ if (!Record)
+ {
+ Status = StatAuthError;
+ ErrorText = "Unable to find expected entry "
+ + (*Target)->MetaKey + " in Meta-index file (malformed Release file?)";
+ return;
+ }
+ ExpectedIndexHash = Record->Hash;
+ if (_config->FindB("Debug::pkgAcquire::Auth", false))
+ {
+ std::cerr << "Queueing: " << (*Target)->URI << std::endl;
+ std::cerr << "Expected Hash: " << ExpectedIndexHash.toStr() << std::endl;
+ }
+ if (ExpectedIndexHash.empty())
+ {
+ Status = StatAuthError;
+ ErrorText = "Unable to find hash sum for "
+ + (*Target)->MetaKey + " in Meta-index file";
+ return;
+ }
+ }
+
+ // Queue Packages file (either diff or full packages files, depending
+ // on the users option)
+ if(_config->FindB("Acquire::PDiffs",true) == true)
+ new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description,
+ (*Target)->ShortDesc, ExpectedIndexHash);
+ else
+ new pkgAcqIndex(Owner, (*Target)->URI, (*Target)->Description,
+ (*Target)->ShortDesc, ExpectedIndexHash);
+ }
+}
+ /*}}}*/
+bool pkgAcqMetaIndex::VerifyVendor(string Message) /*{{{*/
+{
+// // Maybe this should be made available from above so we don't have
+// // to read and parse it every time?
+// pkgVendorList List;
+// List.ReadMainList();
+
+// const Vendor* Vndr = NULL;
+// for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
+// {
+// string::size_type pos = (*I).find("VALIDSIG ");
+// if (_config->FindB("Debug::Vendor", false))
+// std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
+// << std::endl;
+// if (pos != std::string::npos)
+// {
+// string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
+// if (_config->FindB("Debug::Vendor", false))
+// std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
+// std::endl;
+// Vndr = List.FindVendor(Fingerprint) != "";
+// if (Vndr != NULL);
+// break;
+// }
+// }
+ string::size_type pos;
+
+ // check for missing sigs (that where not fatal because otherwise we had
+ // bombed earlier)
+ string missingkeys;
+ string msg = _("There is no public key available for the "
+ "following key IDs:\n");
+ pos = Message.find("NO_PUBKEY ");
+ if (pos != std::string::npos)
+ {
+ string::size_type start = pos+strlen("NO_PUBKEY ");
+ string Fingerprint = Message.substr(start, Message.find("\n")-start);
+ missingkeys += (Fingerprint);
+ }
+ if(!missingkeys.empty())
+ _error->Warning("%s", string(msg+missingkeys).c_str());
+
+ string Transformed = MetaIndexParser->GetExpectedDist();
+
+ if (Transformed == "../project/experimental")
+ {
+ Transformed = "experimental";
+ }
+
+ pos = Transformed.rfind('/');
+ if (pos != string::npos)
+ {
+ Transformed = Transformed.substr(0, pos);
+ }
+
+ if (Transformed == ".")
+ {
+ Transformed = "";
+ }
+
+ if (_config->FindB("Debug::pkgAcquire::Auth", false))
+ {
+ std::cerr << "Got Codename: " << MetaIndexParser->GetDist() << std::endl;
+ std::cerr << "Expecting Dist: " << MetaIndexParser->GetExpectedDist() << std::endl;
+ std::cerr << "Transformed Dist: " << Transformed << std::endl;
+ }