- Create the cache directly from the schema (installed) file.
[platform/upstream/libzypp.git] / zypp / KeyRing.cc
index 7589b48..a7382e9 100644 (file)
@@ -50,6 +50,7 @@ namespace zypp
   static bool printLine( const std::string &line )
   {
     MIL <<  line << std::endl;
+    return true;
   }
 
   static void dumpFile(const Pathname &file)
@@ -66,15 +67,18 @@ namespace zypp
   bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
   { return _keyRingDefaultAccept; }
 
-  bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
+  bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &id )
   { return _keyRingDefaultAccept; }
 
-  bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
+  bool KeyRingReport::askUserToTrustKey( const PublicKey &key )
   { return _keyRingDefaultAccept; }
 
-  bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
+  bool KeyRingReport::askUserToImportKey( const PublicKey &key)
   { return _keyRingDefaultAccept; }
-
+  
+  bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const PublicKey &key )
+  { return _keyRingDefaultAccept; }
+  
   ///////////////////////////////////////////////////////////////////
   //
   //   CLASS NAME : KeyRing::Impl
@@ -82,10 +86,12 @@ namespace zypp
   /** KeyRing implementation. */
   struct KeyRing::Impl
   {
-    Impl()
+    Impl(const Pathname &baseTmpDir)
+    : _trusted_tmp_dir(baseTmpDir, "zypp-trusted-kr")
+   ,  _general_tmp_dir(baseTmpDir, "zypp-general-kr")
+   , _base_dir( baseTmpDir )
+
     {
-      _general_kr = _general_tmp_dir.path();
-      _trusted_kr = _trusted_tmp_dir.path();
     }
 
     /*
@@ -94,16 +100,19 @@ namespace zypp
       filesystem::assert_dir(general_kr);
       filesystem::assert_dir(trusted_kr);
 
-      _general_kr = general_kr;
-      _trusted_kr = trusted_kr;
+      generalKeyRing() = general_kr;
+      trustedKeyRing() = trusted_kr;
     }
     */
 
-    void importKey( const Pathname &keyfile, bool trusted = false);
-    PublicKey readPublicKey( const Pathname &keyfile );
-    std::string readSignatureKeyId(  const Pathname &data, const Pathname &keyfile );
-
+    void importKey( const PublicKey &key, bool trusted = false);
     void deleteKey( const std::string &id, bool trusted );
+    
+    std::string readSignatureKeyId( const Pathname &signature );
+    
+    bool isKeyTrusted( const std::string &id);
+    bool isKeyKnown( const std::string &id );
+    
     std::list<PublicKey> trustedPublicKeys();
     std::list<PublicKey> publicKeys();
 
@@ -117,25 +126,25 @@ namespace zypp
     //mutable std::map<Locale, std::string> translations;
     bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
     void importKey( const Pathname &keyfile, const Pathname &keyring);
-
-    void exportKey( std::string id, const Pathname &keyfile, bool trusted);
-
+    PublicKey exportKey( std::string id, const Pathname &keyring);
+    void dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream );
     void deleteKey( const std::string &id, const Pathname &keyring );
     std::list<PublicKey> publicKeys(const Pathname &keyring);
 
     bool publicKeyExists( std::string id, const Pathname &keyring);
 
-    Pathname _general_kr;
-    Pathname _trusted_kr;
+    const Pathname generalKeyRing() const;
+    const Pathname trustedKeyRing() const;
 
     // Used for trusted and untrusted keyrings
     TmpDir _trusted_tmp_dir;
     TmpDir _general_tmp_dir;
+    Pathname _base_dir;
   public:
     /** Offer default Impl. */
     static shared_ptr<Impl> nullimpl()
     {
-      static shared_ptr<Impl> _nullimpl( new Impl );
+      static shared_ptr<Impl> _nullimpl( new Impl( Pathname("/var/tmp") ) );
       return _nullimpl;
     }
 
@@ -146,66 +155,110 @@ namespace zypp
     { return new Impl( *this ); }
   };
 
-  void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
+
+  const Pathname KeyRing::Impl::generalKeyRing() const
   {
-    importKey( keyfile, trusted ? _trusted_kr : _general_kr );
+    return _general_tmp_dir.path();
+  }
+
+  const Pathname KeyRing::Impl::trustedKeyRing() const
+  {
+    return _trusted_tmp_dir.path();
+  }
+
+  void KeyRing::Impl::importKey( const PublicKey &key, bool trusted)
+  {
+    callback::SendReport<KeyRingSignals> emitSignal;
+    
+    importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
   }
 
   void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
   {
-    deleteKey( id, trusted ? _trusted_kr : _general_kr );
+    deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
   }
 
   std::list<PublicKey> KeyRing::Impl::publicKeys()
   {
-    return publicKeys( _general_kr );
+    return publicKeys( generalKeyRing() );
   }
 
   std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
   {
-    return publicKeys( _trusted_kr );
+    return publicKeys( trustedKeyRing() );
   }
 
   bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
   {
-    return verifyFile( file, signature, _trusted_kr );
+    return verifyFile( file, signature, trustedKeyRing() );
   }
 
   bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
   {
-    return verifyFile( file, signature, _general_kr );
+    return verifyFile( file, signature, generalKeyRing() );
   }
 
+  bool KeyRing::Impl::isKeyTrusted( const std::string &id)
+  {
+    return publicKeyExists( id, trustedKeyRing() );
+  }
+  
+  bool KeyRing::Impl::isKeyKnown( const std::string &id )
+  {
+    if ( publicKeyExists( id, trustedKeyRing() ) )
+      return true;
+    else
+      return publicKeyExists( id, generalKeyRing() );
+  }
+  
   bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
   {
+    MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
     std::list<PublicKey> keys = publicKeys(keyring);
     for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
     {
-      if ( id == (*it).id )
+      if ( id == (*it).id() )
         return true;
     }
     return false;
   }
-
-  void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
+  
+  PublicKey KeyRing::Impl::exportKey( std::string id, const Pathname &keyring)
   {
+    TmpFile tmp_file( _base_dir, "pubkey-"+id+"-" );
+    Pathname keyfile = tmp_file.path();
+    MIL << "Going to export key " << id << " from " << keyring << " to " << keyfile << endl;
+     
     try {
       std::ofstream os(keyfile.asString().c_str());
-      dumpPublicKey( id, trusted, os );
+      dumpPublicKey( id, keyring, os );
       os.close();
+      PublicKey key(keyfile);
+      return key;
+    }
+    catch (BadKeyException &e)
+    {
+      ERR << "Cannot create public key " << id << " from " << keyring << " keyring  to file " << e.keyFile() << std::endl;
+      ZYPP_THROW(Exception("Cannot create public key " + id + " from " + keyring.asString() + " keyring to file " + e.keyFile().asString() ) );
     }
     catch (std::exception &e)
     {
-      ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring  to file " << keyfile << std::endl;
+      ERR << "Cannot export key " << id << " from " << keyring << " keyring  to file " << keyfile << std::endl;
     }
+    return PublicKey();
   }
 
   void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
   {
-    Pathname keyring = trusted ? _trusted_kr : _general_kr;
+     dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream );
+  }
+  
+  void KeyRing::Impl::dumpPublicKey( const std::string &id, const Pathname &keyring, std::ostream &stream )
+  {
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--quiet",
       "--no-tty",
       "--no-greeting",
@@ -238,49 +291,55 @@ namespace zypp
     // if signature does not exists, ask user if he wants to accept unsigned file.
     if( signature.empty() || (!PathInfo(signature).isExist()) )
     {
-       bool res = report->askUserToAcceptUnsignedFile( filedesc );
-       MIL << "User decision on unsigned file: " << res << endl;
-       return res;
+      bool res = report->askUserToAcceptUnsignedFile( filedesc );
+      MIL << "User decision on unsigned file: " << res << endl;
+      return res;
     }
 
     // get the id of the signature
-    std::string id = readSignatureKeyId(file, signature);
+    std::string id = readSignatureKeyId(signature);
 
     // doeskey exists in trusted keyring
-    if ( publicKeyExists( id, _trusted_kr ) )
+    if ( publicKeyExists( id, trustedKeyRing() ) )
     {
-      TmpFile trustedKey;
-      exportKey( id, trustedKey.path(), true);
-      PublicKey key = readPublicKey(trustedKey.path());
-      MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
+      PublicKey key = exportKey( id, trustedKeyRing() );
+      
+      MIL << "Key " << id << " " << key.name() << " is trusted" << std::endl;
       // it exists, is trusted, does it validates?
-      if ( verifyFile( file, signature, _trusted_kr ) )
+      if ( verifyFile( file, signature, trustedKeyRing() ) )
         return true;
       else
-        return report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint );
+        return report->askUserToAcceptVerificationFailed( filedesc, key );
     }
     else
     {
-      if ( publicKeyExists( id, _general_kr ) )
+      if ( publicKeyExists( id, generalKeyRing() ) )
       {
-        TmpFile unKey;
-        exportKey( id, unKey.path(), false);
-        MIL << "Exported key " << id << " to " << unKey << std::endl;
-
-        PublicKey key = readPublicKey(unKey.path());
-        MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
+        PublicKey key =  exportKey( id, generalKeyRing());
+        MIL << "Exported key " << id << " to " << key.path() << std::endl;
+        MIL << "Key " << id << " " << key.name() << " is not trusted" << std::endl;
         // ok the key is not trusted, ask the user to trust it or not
-#warning We need the key details passed to the callback
-        if ( report->askUserToTrustKey(key.id, key.name, key.fingerprint) )
+        #warning We need the key details passed to the callback
+        if ( report->askUserToTrustKey( key ) )
         {
-          MIL << "User wants to trust key " << id << " " << key.name << std::endl;
+          MIL << "User wants to trust key " << id << " " << key.name() << std::endl;
           //dumpFile(unKey.path());
 
-          importKey( unKey.path(), _trusted_kr );
-          emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name, key.fingerprint );
+          Pathname which_keyring;
+          if ( report->askUserToImportKey( key ) )
+          {
+            MIL << "User wants to import key " << id << " " << key.name() << std::endl;
+            importKey( key.path(), trustedKeyRing() );
+            emitSignal->trustedKeyAdded( (const KeyRing &)(*this), key );
+            which_keyring = trustedKeyRing();
+          }
+          else
+          {
+            which_keyring = generalKeyRing();
+          }
 
           // emit key added
-          if ( verifyFile( file, signature, _trusted_kr ) )
+          if ( verifyFile( file, signature, which_keyring ) )
           {
             MIL << "File signature is verified" << std::endl;
             return true;
@@ -288,7 +347,7 @@ namespace zypp
           else
           {
             MIL << "File signature check fails" << std::endl;
-            if ( report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint ) )
+            if ( report->askUserToAcceptVerificationFailed( filedesc, key ) )
             {
               MIL << "User continues anyway." << std::endl;
               return true;
@@ -302,14 +361,15 @@ namespace zypp
         }
         else
         {
-          MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
+          MIL << "User does not want to trust key " << id << " " << key.name() << std::endl;
           return false;
         }
       }
       else
       {
         // unknown key...
-        if ( report->askUserToAcceptUnknownKey( filedesc, id, "", "" ) )
+        MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
+        if ( report->askUserToAcceptUnknownKey( filedesc, id ) )
         {
           MIL << "User wants to accept unknown key " << id << std::endl;
           return true;
@@ -324,62 +384,12 @@ namespace zypp
     return false;
   }
 
-
-  PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
-  {
-    const char* argv[] =
-    {
-      "gpg",
-      "--with-fingerprint",
-      "--with-colons",
-      "--quiet",
-      "--no-tty",
-      "--no-greeting",
-      "--batch",
-      "--status-fd",
-      "1",
-      keyfile.asString().c_str(),
-      NULL
-    };
-
-    ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
-
-    std::string line;
-    int count = 0;
-
-    str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
-
-    // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
-
-    PublicKey key;
-    for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
-    {
-      //MIL << "[" << line << "]" << std::endl;
-      str::smatch what;
-      if(str::regex_match(line, what, rxColons, str::match_extra))
-      {
-        if ( what[1] == "pub" )
-        {
-          key.id = what[5];
-          key.name = what[10];
-          //return key;
-        }
-        else if ( what[1] == "fpr" )
-        {
-          key.fingerprint = what[10];
-        }
-        //dumpRegexpResults(what);
-      }
-    }
-    prog.close();
-    return key;
-  }
-
   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
   {
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--quiet",
       "--list-public-keys",
       "--with-colons",
@@ -408,12 +418,11 @@ namespace zypp
       str::smatch what;
       if(str::regex_match(line, what, rxColons, str::match_extra))
       {
-        PublicKey key;
+        string id;
         if ( what[1] == "pub" )
         {
-          key.id = what[5];
-          key.name = what[10];
-
+          id = what[5];
+          
           std::string line2;
           for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
           {
@@ -422,13 +431,14 @@ namespace zypp
             {
               if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
               {
-                key.fingerprint = what2[10];
+                //key.fingerprint = what2[10];
                 break;
               }
             }
           }
+          PublicKey key(exportKey( id, keyring ));
           keys.push_back(key);
-          MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
+          MIL << "Found key " << "[" << key.id() << "]" << " [" << key.name() << "]" << " [" << key.fingerprint() << "]" << std::endl;
         }
         //dumpRegexpResults(what);
       }
@@ -436,12 +446,16 @@ namespace zypp
     prog.close();
     return keys;
   }
-
+    
   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
   {
+    if ( ! PathInfo(keyfile).isExist() )
+      ZYPP_THROW(KeyRingException("Tried to import not existant key " + keyfile.asString() + " into keyring " + keyring.asString()));
+    
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--quiet",
       "--no-tty",
       "--no-greeting",
@@ -468,6 +482,7 @@ namespace zypp
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--yes",
       "--quiet",
       "--no-tty",
@@ -491,14 +506,17 @@ namespace zypp
   }
 
 
-  std::string KeyRing::Impl::readSignatureKeyId( const Pathname &data, const Pathname &keyfile )
+  std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
   {
+    MIL << "Deetermining key id if signature " << signature << std::endl;
     // HACK create a tmp keyring with no keys
-    TmpDir dir;
+    TmpDir dir(_base_dir, "fake-keyring");
+    TmpFile fakeData(_base_dir, "fake-data");
 
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--quiet",
       "--no-tty",
       "--no-greeting",
@@ -508,8 +526,8 @@ namespace zypp
       "--homedir",
       dir.path().asString().c_str(),
       "--verify",
-      keyfile.asString().c_str(),
-      data.asString().c_str(),
+      signature.asString().c_str(),
+      fakeData.path().asString().c_str(),
       NULL
     };
 
@@ -531,6 +549,7 @@ namespace zypp
         //dumpRegexpResults(what);
       }
     }
+    MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
     prog.close();
     return id;
   }
@@ -540,6 +559,7 @@ namespace zypp
     const char* argv[] =
     {
       "gpg",
+      "--no-default-keyring",
       "--quiet",
       "--no-tty",
       "--batch",
@@ -582,8 +602,8 @@ namespace zypp
   //   METHOD NAME : KeyRing::KeyRing
   //   METHOD TYPE : Ctor
   //
-  KeyRing::KeyRing()
-  : _pimpl( new Impl() )
+  KeyRing::KeyRing(const Pathname &baseTmpDir)
+  : _pimpl( new Impl(baseTmpDir) )
   {}
 
   ///////////////////////////////////////////////////////////////////
@@ -609,19 +629,15 @@ namespace zypp
   //
   ///////////////////////////////////////////////////////////////////
 
-  void KeyRing::importKey( const Pathname &keyfile, bool trusted)
-  {
-    _pimpl->importKey(keyfile, trusted);
-  }
-
-  PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
+  
+  void KeyRing::importKey( const PublicKey &key, bool trusted )
   {
-    return _pimpl->readPublicKey(keyfile);
+    _pimpl->importKey( key.path(), trusted );
   }
-
-  std::string KeyRing::readSignatureKeyId(  const Pathname &data, const Pathname &keyfile )
+  
+  std::string KeyRing::readSignatureKeyId( const Pathname &signature )
   {
-    return _pimpl->readSignatureKeyId(data, keyfile);
+    return _pimpl->readSignatureKeyId(signature);
   }
 
   void KeyRing::deleteKey( const std::string &id, bool trusted )
@@ -659,6 +675,16 @@ namespace zypp
     _pimpl->dumpPublicKey( id, trusted, stream);
   }
 
+  bool KeyRing::isKeyTrusted( const std::string &id )
+  {
+    return _pimpl->isKeyTrusted(id);
+  }
+     
+  bool KeyRing::isKeyKnown( const std::string &id )
+  {
+    return _pimpl->isKeyTrusted(id);
+  }
+  
   /////////////////////////////////////////////////////////////////
 } // namespace zypp
 ///////////////////////////////////////////////////////////////////