- Fix permanent duplication of gpg keys in the rpm database. Also
authorMichael Andres <ma@suse.de>
Mon, 30 Jun 2008 08:30:02 +0000 (08:30 +0000)
committerMichael Andres <ma@suse.de>
Mon, 30 Jun 2008 08:30:02 +0000 (08:30 +0000)
  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
zypp/KeyRing.cc
zypp/PublicKey.cc
zypp/PublicKey.h
zypp/base/String.h
zypp/target/rpm/RpmDb.cc

index 5908b88..3072b89 100644 (file)
@@ -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
index 64f74a9..ca8e764 100644 (file)
@@ -249,6 +249,7 @@ namespace zypp
     for (list<PublicKey>::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() ) )
index 0bbd3ce..f74ed67 100644 (file)
@@ -10,6 +10,7 @@
  *
 */
 #include <iostream>
+#include <vector>
 
 //#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 <ctime>
 
@@ -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<Impl> 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<int>(std::string(datestr, 0, 4)) - 1900; // years since 1900
-           date.tm_mon = str::strtonum<int>(std::string(datestr, 5, 2)) - 1;     // months since January
-           date.tm_mday = str::strtonum<int>(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 <build@suse.de>:
-  
-        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 <build@suse.de>:
+        // 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<std::string> 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<Date::ValueType>(words[5]));
+            _expires = Date(str::strtonum<Date::ValueType>(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<Date::ValueType>(words[5]));
+            if ( ! words[6].empty() )
+              _expires = Date(str::strtonum<Date::ValueType>(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
 ///////////////////////////////////////////////////////////////////
index 92af3fe..79ba4b5 100644 (file)
@@ -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<Impl> _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
index 72c2fdd..c63022a 100644 (file)
@@ -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<std::string> words;
+     * str::split( "some line", std::back_inserter(words) )
+     * \endcode
+     *
+    */
+    template<class _OutputIterator>
+      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;
+      }
     //@}
 
     ///////////////////////////////////////////////////////////////////
index 5e9032c..78ab154 100644 (file)
@@ -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<Edition> rpm_keys = pubkeyEditions();
+  string keyshortid = pubkey_r.id().substr(8,8);
+  MIL << "Comparing '" << keyshortid << "' to: ";
   for ( set<Edition>::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<Date::ValueType>("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);
 }