From a3498a128bf1810f903a17df377015c65ecf1e0b Mon Sep 17 00:00:00 2001 From: Michael Andres Date: Mon, 30 Jun 2008 08:30:02 +0000 Subject: [PATCH] - Fix permanent duplication of gpg keys in the rpm database. Also retrieve correct creation and expire dates. (bnc #401259) - Invoke gpg with --homdir, otherwise command fails if executed within a wrapper. (bnc #401259) --- package/libzypp.changes | 9 +++ zypp/KeyRing.cc | 14 ++++ zypp/PublicKey.cc | 196 ++++++++++++++++++++++++++--------------------- zypp/PublicKey.h | 33 ++++---- zypp/base/String.h | 51 ++++++++++++ zypp/target/rpm/RpmDb.cc | 60 ++++++++++----- 6 files changed, 243 insertions(+), 120 deletions(-) diff --git a/package/libzypp.changes b/package/libzypp.changes index 5908b88..3072b89 100644 --- a/package/libzypp.changes +++ b/package/libzypp.changes @@ -1,4 +1,13 @@ ------------------------------------------------------------------- +Mon Jun 30 10:28:27 CEST 2008 - ma@suse.de + +- Fix permanent duplication of gpg keys in the rpm database. Also + retrieve correct creation and expire dates. (bnc #401259) +- Invoke gpg with --homdir, otherwise command fails if executed + within a wrapper. (bnc #401259) +- revision 10487 + +------------------------------------------------------------------- Thu Jun 26 12:07:33 CEST 2008 - schubi@suse.de - version 5.0.1 diff --git a/zypp/KeyRing.cc b/zypp/KeyRing.cc index 64f74a9..ca8e764 100644 --- a/zypp/KeyRing.cc +++ b/zypp/KeyRing.cc @@ -249,6 +249,7 @@ namespace zypp for (list::const_iterator it = keys.begin(); it != keys.end(); it++) { if ( id == (*it).id() ) + return true; } return false; @@ -339,6 +340,19 @@ namespace zypp { PublicKey key = exportKey( id, trustedKeyRing() ); + // lets look if there is an updated key in the + // general keyring + if ( publicKeyExists( id, generalKeyRing() ) ) + { + PublicKey untkey = exportKey( id, generalKeyRing() ); + if ( untkey.created() > key.created() ) + { + MIL << "Key " << key << " was updated. Saving new version into trusted keyring." << endl; + importKey( untkey, true ); + key = untkey; + } + } + MIL << "Key " << id << " " << key.name() << " is trusted" << endl; // it exists, is trusted, does it validates? if ( verifyFile( file, signature, trustedKeyRing() ) ) diff --git a/zypp/PublicKey.cc b/zypp/PublicKey.cc index 0bbd3ce..f74ed67 100644 --- a/zypp/PublicKey.cc +++ b/zypp/PublicKey.cc @@ -10,6 +10,7 @@ * */ #include +#include //#include "zypp/base/Logger.h" @@ -22,6 +23,7 @@ #include "zypp/base/Exception.h" #include "zypp/base/Logger.h" #include "zypp/Date.h" +#include "zypp/TmpPath.h" #include @@ -29,7 +31,7 @@ using std::endl; /////////////////////////////////////////////////////////////////// namespace zypp -{ ///////////////////////////////////////////////////////////////// +{ ///////////////////////////////////////////////////////////////// // // CLASS NAME : PublicKey::Impl // @@ -44,7 +46,7 @@ namespace zypp readFromFile(file); MIL << "Done reading key" << std::endl; } - + public: /** Offer default Impl. */ static shared_ptr nullimpl() @@ -53,21 +55,21 @@ namespace zypp return _nullimpl; } - + std::string asString() const { - return "[" + id() + "] [" + name() + "] [" + fingerprint() + "]"; + return "[" + id() + "-" + str::hexstring(created(),8).substr(2) + "] [" + name() + "] [" + fingerprint() + "]"; } - + std::string armoredData() const { return _data; } - + std::string id() const { return _id; } - + std::string name() const { return _name; } - + std::string fingerprint() const { return _fingerprint; } @@ -76,68 +78,37 @@ namespace zypp Date expires() const { return _expires; } - + Pathname path() const - { + { return _data_file.path(); //return _data_file; } - + protected: - // create Date from a string in format YYYY-MM-DD - Date createDate(const std::string &datestr) - { - // empty input - if (datestr.empty()) - { - return Date(); - } - - tm date; - memset(&date, 0, sizeof(date)); - - try - { - // set the date - date.tm_year = str::strtonum(std::string(datestr, 0, 4)) - 1900; // years since 1900 - date.tm_mon = str::strtonum(std::string(datestr, 5, 2)) - 1; // months since January - date.tm_mday = str::strtonum(std::string(datestr, 9, 2)); // day - } - catch(...) - { - WAR << "Cannot parse date string: " << datestr << std::endl; - return Date(); - } - - time_t time_epoch = ::mktime(&date); - - return Date(time_epoch); - } - void readFromFile( const Pathname &keyfile) { - static str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$"); - + PathInfo info(keyfile); - MIL << "Reading pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1")<< endl; + MIL << "Reading pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1")<< endl; if ( !info.isExist() ) ZYPP_THROW(Exception("Can't read public key from " + keyfile.asString() + ", file not found")); - + if ( copy( keyfile, _data_file.path() ) != 0 ) ZYPP_THROW(Exception("Can't copy public key data from " + keyfile.asString() + " to " + _data_file.path().asString() )); - - filesystem::TmpDir dir; - + filesystem::TmpDir dir; const char* argv[] = { "gpg", + "-v", "--no-default-keyring", - "--homedir", - dir.path().asString().c_str(), + "--fixed-list-mode", "--with-fingerprint", "--with-colons", + "--homedir", + dir.path().asString().c_str(), "--quiet", "--no-tty", "--no-greeting", @@ -147,42 +118,77 @@ namespace zypp _data_file.path().asString().c_str(), NULL }; - + ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true); - + std::string line; - int count = 0; - - // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key : - - for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ ) + bool sawpub = false; + bool sawsig = false; + + // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key : + // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA: + // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x: + // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x: + // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x: + // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21] + // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x: + + for ( line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) { - //MIL << "[" << line << "]" << std::endl; - str::smatch what; - if(str::regex_match(line, what, rxColons)) + // trim trailing NL. + if ( line.empty() ) + continue; + if ( line[line.size()-1] == '\n' ) + line.erase( line.size()-1 ); + + // split at ':' + std::vector words; + str::splitFields( line, std::back_inserter(words), ":" ); + if( words.empty() ) + continue; + + if ( words[0] == "pub" ) { - if ( what[1] == "pub" ) - { - _id = what[5]; - //replace all escaped semicolon with real - _name = str::gsub(what[10],"\\x3a",":"); - _created = createDate(what[6]); - _expires = createDate(what[7]); - //return key; - } - else if ( what[1] == "fpr" ) - { - _fingerprint = what[10]; - } - //dumpRegexpResults(what); + if ( sawpub ) + continue; + sawpub = true; + // take default from pub + _id = words[4]; + _name = words[9]; + _created = Date(str::strtonum(words[5])); + _expires = Date(str::strtonum(words[6])); + + } + else if ( words[0] == "sig" ) + { + if ( sawsig || words[words.size()-2] != "13x" ) + continue; + sawsig = true; + // update creation and expire dates from 1st signature type "13x" + if ( ! words[5].empty() ) + _created = Date(str::strtonum(words[5])); + if ( ! words[6].empty() ) + _expires = Date(str::strtonum(words[6])); + } + else if ( words[0] == "fpr" ) + { + _fingerprint = words[9]; + } + else if ( words[0] == "uid" ) + { + if ( ! words[9].empty() ) + _name = words[9]; } } prog.close(); - - if (_id.size() == 0 ) - ZYPP_THROW(BadKeyException("File " + keyfile.asString() + " doesn't contain public key data" , keyfile)); + + if ( _id.size() == 0 ) + ZYPP_THROW( BadKeyException( "File " + keyfile.asString() + " doesn't contain public key data" , keyfile ) ); + + //replace all escaped semicolon with real ':' + str::replaceAll( _name, "\\x3a", ":" ); } - + private: std::string _id; std::string _name; @@ -211,7 +217,10 @@ namespace zypp PublicKey::PublicKey( const Pathname &file ) : _pimpl( new Impl(file) ) - {} + { + MIL << *this << endl; + } + /////////////////////////////////////////////////////////////////// // // METHOD NAME : PublicKey::~PublicKey @@ -230,16 +239,16 @@ namespace zypp { return _pimpl->asString(); } - + std::string PublicKey::armoredData() const { return _pimpl->armoredData(); } - + std::string PublicKey::id() const { return _pimpl->id(); } - + std::string PublicKey::name() const { return _pimpl->name(); } - + std::string PublicKey::fingerprint() const { return _pimpl->fingerprint(); } @@ -248,20 +257,33 @@ namespace zypp Date PublicKey::expires() const { return _pimpl->expires(); } - + Pathname PublicKey::path() const { return _pimpl->path(); } bool PublicKey::operator==( PublicKey b ) const { - return (b.id() == id()) && (b.fingerprint() == fingerprint() ); + return ( b.id() == id() + && b.fingerprint() == fingerprint() + && b.created() == created() ); } - + bool PublicKey::operator==( std::string sid ) const { return sid == id(); } - + + std::ostream & dumpOn( std::ostream & str, const PublicKey & obj ) + { + str << "[" << obj.name() << "]" << endl; + str << " fpr " << obj.fingerprint() << endl; + str << " id " << obj.id() << endl; + str << " cre " << obj.created() << endl; + str << " exp " << obj.expires() << endl; + str << "]"; + return str; + } + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// diff --git a/zypp/PublicKey.h b/zypp/PublicKey.h index 92af3fe..79ba4b5 100644 --- a/zypp/PublicKey.h +++ b/zypp/PublicKey.h @@ -25,7 +25,7 @@ /////////////////////////////////////////////////////////////////// namespace zypp { ///////////////////////////////////////////////////////////////// - + /** * Exception thrown when the supplied key is * not a valid gpg key @@ -39,10 +39,10 @@ namespace zypp BadKeyException() : Exception( "Bad Key Exception" ) {} - + Pathname keyFile() const { return _keyfile; } - + /** Ctor taking message. * Use \ref ZYPP_THROW to throw exceptions. */ @@ -54,16 +54,16 @@ namespace zypp private: Pathname _keyfile; }; - - // forward declaration of class Date + + // forward declaration of class Date class Date; /////////////////////////////////////////////////////////////////// // // CLASS NAME : PublicKey // - /** + /** * Class that represent a GPG Public Key */ class PublicKey @@ -76,16 +76,16 @@ namespace zypp public: PublicKey(); - /** Ctor + /** Ctor * \throws when data does not make a key */ PublicKey(const Pathname &file); - + ~PublicKey(); - + bool isValid() const { return ( ! id().empty() && ! fingerprint().empty() && !path().empty() ); } - + std::string asString() const; std::string armoredData() const; std::string id() const; @@ -94,7 +94,7 @@ namespace zypp /** * Date when the key was created (time is 00:00:00) - */ + */ Date created() const; /** @@ -103,11 +103,11 @@ namespace zypp */ Date expires() const; - Pathname path() const; - + Pathname path() const; + bool operator==( PublicKey b ) const; bool operator==( std::string sid ) const; - + private: /** Pointer to implementation */ RWCOW_pointer _pimpl; @@ -118,7 +118,10 @@ namespace zypp inline std::ostream & operator<<( std::ostream & str, const PublicKey & obj ) { return str << obj.asString(); } - ///////////////////////////////////////////////////////////////// + /** \relates PublicKey Detailed stream output */ + std::ostream & dumpOn( std::ostream & str, const PublicKey & obj ); + + ///////////////////////////////////////////////////////////////// } // namespace zypp /////////////////////////////////////////////////////////////////// #endif // ZYPP_PUBLICKEY_H diff --git a/zypp/base/String.h b/zypp/base/String.h index 72c2fdd..c63022a 100644 --- a/zypp/base/String.h +++ b/zypp/base/String.h @@ -439,6 +439,57 @@ namespace zypp } return ret; } + + /** Split \a line_r into fields. + * Any single character in \a sepchars_r is treated as a + * field separator. The words are passed to OutputIterator + * \a result_r. + * \code + * "" -> words 0 + * ":" -> words 2 ||| + * "a" -> words 1 |a| + * ":a" -> words 2 ||a| + * "a:" -> words 2 |a|| + * ":a:" -> words 3 ||a|| + * + * \endcode + * + * \code + * std::vector words; + * str::split( "some line", std::back_inserter(words) ) + * \endcode + * + */ + template + unsigned splitFields( const C_Str & line_r, + _OutputIterator result_r, + const C_Str & sepchars_r = ":" ) + { + const char * beg = line_r; + const char * cur = beg; + unsigned ret = 0; + for ( beg = cur; *beg; beg = cur, ++result_r ) + { + // skip non sepchars + while( *cur && !::strchr( sepchars_r, *cur ) ) + ++cur; + // build string + *result_r = std::string( beg, cur-beg ); + ++ret; + // skip sepchar + if ( *cur ) + { + ++cur; + if ( ! *cur ) // ending with sepchar + { + *result_r = std::string(); // add final empty field + ++ret; + break; + } + } + } + return ret; + } //@} /////////////////////////////////////////////////////////////////// diff --git a/zypp/target/rpm/RpmDb.cc b/zypp/target/rpm/RpmDb.cc index 5e9032c..78ab154 100644 --- a/zypp/target/rpm/RpmDb.cc +++ b/zypp/target/rpm/RpmDb.cc @@ -1001,21 +1001,34 @@ void RpmDb::importPubkey( const PublicKey & pubkey_r ) // check if the key is already in the rpm database and just // return if it does. set rpm_keys = pubkeyEditions(); + string keyshortid = pubkey_r.id().substr(8,8); + MIL << "Comparing '" << keyshortid << "' to: "; for ( set::const_iterator it = rpm_keys.begin(); it != rpm_keys.end(); ++it) { string id = str::toUpper( (*it).version() ); - string keyshortid = pubkey_r.id().substr(8,8); - MIL << "Comparing '" << id << "' to '" << keyshortid << "'" << endl; + MIL << ", '" << id << "'"; if ( id == keyshortid ) { - // they match id - // FIXME id is not sufficient? - MIL << "Key " << pubkey_r << " is already in the rpm trusted keyring." << endl; - return; + // they match id + // now check if timestamp is different + Date date = Date(str::strtonum("0x" + (*it).release())); + if ( date == pubkey_r.created() ) + { + + MIL << endl << "Key " << pubkey_r << " is already in the rpm trusted keyring." << endl; + return; + } + else + { + MIL << endl << "Key " << pubkey_r << " has another version in keyring. ( " << date << " & " << pubkey_r.created() << ")" << endl; + + } + } } // key does not exists, lets import it - + MIL << endl; + RpmArgVec opts; opts.push_back ( "--import" ); opts.push_back ( "--" ); @@ -2097,17 +2110,28 @@ void RpmDb::removePackage( const string & name_r, unsigned flags ) report->start( name_r ); - try - { - doRemovePackage(name_r, flags, report); - } - catch (RpmException & excpt_r) - { - report->problem(excpt_r); //! partial fix to bug #388810, \todo allow to abort/retry failed rpm removal - report->finish(excpt_r); - ZYPP_RETHROW(excpt_r); - } - report->finish(); + do + try + { + doRemovePackage(name_r, flags, report); + report->finish(); + break; + } + catch (RpmException & excpt_r) + { + RpmRemoveReport::Action user = report->problem( excpt_r ); + + if ( user == RpmRemoveReport::ABORT ) + { + report->finish( excpt_r ); + ZYPP_RETHROW(excpt_r); + } + else if ( user == RpmRemoveReport::IGNORE ) + { + break; + } + } + while (true); } -- 2.7.4