libzypp 8.13.6

PublicKey.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <climits>
00013 
00014 #include <iostream>
00015 #include <vector>
00016 
00017 //#include "zypp/base/Logger.h"
00018 
00019 #include "zypp/base/Gettext.h"
00020 #include "zypp/base/String.h"
00021 #include "zypp/base/Regex.h"
00022 #include "zypp/PublicKey.h"
00023 #include "zypp/ExternalProgram.h"
00024 #include "zypp/TmpPath.h"
00025 #include "zypp/PathInfo.h"
00026 #include "zypp/base/Exception.h"
00027 #include "zypp/base/Logger.h"
00028 #include "zypp/Date.h"
00029 #include "zypp/TmpPath.h"
00030 
00031 #include <ctime>
00032 
00033 using std::endl;
00034 
00036 namespace zypp
00037 { 
00038 
00040   //
00041   //    CLASS NAME : PublicKey::Impl
00042   //
00044   struct PublicKey::Impl
00045   {
00046     Impl()
00047     {}
00048 
00049     Impl( const Pathname & keyfile )
00050     {
00051       PathInfo info( keyfile );
00052       MIL << "Takeing pubkey from " << keyfile << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyfile, "sha1") << endl;
00053 
00054       if ( !info.isExist() )
00055         ZYPP_THROW(Exception("Can't read public key from " + keyfile.asString() + ", file not found"));
00056 
00057       if ( copy( keyfile, _data_file.path() ) != 0 )
00058         ZYPP_THROW(Exception("Can't copy public key data from " + keyfile.asString() + " to " +  _data_file.path().asString() ));
00059 
00060       readFromFile();
00061     }
00062 
00063     Impl( const filesystem::TmpFile & sharedfile )
00064       : _data_file( sharedfile )
00065     { readFromFile(); }
00066 
00067     public:
00069       static shared_ptr<Impl> nullimpl()
00070       {
00071         static shared_ptr<Impl> _nullimpl( new Impl );
00072         return _nullimpl;
00073       }
00074 
00075       std::string asString() const
00076       {
00077         return str::form( "[%s-%s] [%s] [%s] [TTL %d]",
00078                           id().c_str(), str::hexstring(created(),8).substr(2).c_str(),
00079                           name().c_str(),
00080                           fingerprint().c_str(),
00081                           daysToLive() );
00082       }
00083 
00084       std::string id() const
00085       { return _id; }
00086 
00087       std::string name() const
00088       { return _name; }
00089 
00090       std::string fingerprint() const
00091       { return _fingerprint; }
00092 
00093       std::string gpgPubkeyVersion() const
00094       { return _id.empty() ? _id : str::toLower( _id.substr(8,8) ); }
00095 
00096       std::string gpgPubkeyRelease() const
00097       { return _created ? str::hexstring( _created ).substr(2) : std::string(); }
00098 
00099       Date created() const
00100       { return _created; }
00101 
00102       Date expires() const
00103       { return _expires; }
00104 
00105       std::string expiresAsString() const
00106       {
00107         if ( !_expires )
00108         { // translators: an annotation to a gpg keys expiry date
00109           return _("(does not expire)");
00110         }
00111         std::string ret( _expires.asString() );
00112         int ttl( daysToLive() );
00113         if ( ttl <= 90 )
00114         {
00115           ret += " ";
00116           if ( ttl < 0 )
00117           { // translators: an annotation to a gpg keys expiry date
00118             ret += _("(EXPIRED)");
00119           }
00120           else if ( ttl == 0 )
00121           { // translators: an annotation to a gpg keys expiry date
00122             ret += _("(expires within 24h)");
00123           }
00124           else
00125           { // translators: an annotation to a gpg keys expiry date
00126             ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl );
00127           }
00128         }
00129         return ret;
00130       }
00131 
00132       Pathname path() const
00133       { return _data_file.path(); }
00134 
00135       bool expired() const
00136       {
00137         Date exp( expires() );
00138         return( exp && exp < Date::now() );
00139       }
00140 
00141       int daysToLive() const
00142       {
00143         Date exp( expires() );
00144         if ( ! expires() )
00145           return INT_MAX;
00146         exp -= Date::now();
00147         return exp < 0 ? exp / Date::day - 1 : exp / Date::day;
00148       }
00149 
00150     protected:
00151 
00152       void readFromFile()
00153       {
00154         PathInfo info( _data_file.path() );
00155         MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
00156 
00157         static filesystem::TmpDir dir;
00158         const char* argv[] =
00159         {
00160           "gpg",
00161           "-v",
00162           "--no-default-keyring",
00163           "--fixed-list-mode",
00164           "--with-fingerprint",
00165           "--with-colons",
00166           "--homedir",
00167           dir.path().asString().c_str(),
00168           "--quiet",
00169           "--no-tty",
00170           "--no-greeting",
00171           "--batch",
00172           "--status-fd",
00173           "1",
00174           _data_file.path().asString().c_str(),
00175           NULL
00176         };
00177 
00178         ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
00179 
00180         std::string line;
00181         bool sawpub = false;
00182         bool sawsig = false;
00183 
00184         // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
00185         // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
00186         // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
00187         // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
00188         // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
00189         // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
00190         // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
00191 
00192         for ( line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
00193         {
00194           // trim trailing NL.
00195           if ( line.empty() )
00196             continue;
00197           if ( line[line.size()-1] == '\n' )
00198             line.erase( line.size()-1 );
00199 
00200           // split at ':'
00201           std::vector<std::string> words;
00202           str::splitFields( line, std::back_inserter(words), ":" );
00203           if( words.empty() )
00204             continue;
00205 
00206           if ( words[0] == "pub" )
00207           {
00208             if ( sawpub )
00209               continue;
00210             sawpub = true;
00211             // take default from pub
00212             _id      = words[4];
00213             _name    = words[9];
00214             _created = Date(str::strtonum<Date::ValueType>(words[5]));
00215             _expires = Date(str::strtonum<Date::ValueType>(words[6]));
00216 
00217           }
00218           else if ( words[0] == "sig" )
00219           {
00220             if ( sawsig || words[words.size()-2] != "13x"  )
00221               continue;
00222             sawsig = true;
00223             // update creation and expire dates from 1st signature type "13x"
00224             if ( ! words[5].empty() )
00225               _created = Date(str::strtonum<Date::ValueType>(words[5]));
00226             if ( ! words[6].empty() )
00227               _expires = Date(str::strtonum<Date::ValueType>(words[6]));
00228           }
00229           else if ( words[0] == "fpr" )
00230           {
00231             _fingerprint = words[9];
00232           }
00233           else if ( words[0] == "uid" )
00234           {
00235             if ( ! words[9].empty() )
00236               _name = words[9];
00237           }
00238         }
00239         prog.close();
00240 
00241         if ( _id.size() == 0 )
00242           ZYPP_THROW( BadKeyException( "File " + _data_file.path().asString() + " doesn't contain public key data" , _data_file.path() ) );
00243 
00244         //replace all escaped semicolon with real ':'
00245         str::replaceAll( _name, "\\x3a", ":" );
00246 
00247         MIL << "Read pubkey from " << info.path() << ": " << asString() << endl;
00248       }
00249 
00250     private:
00251       filesystem::TmpFile _data_file;
00252 
00253       std::string _id;
00254       std::string _name;
00255       std::string _fingerprint;
00256       Date        _created;
00257       Date        _expires;
00258 
00259     private:
00260       friend Impl * rwcowClone<Impl>( const Impl * rhs );
00262       Impl * clone() const
00263       { return new Impl( *this ); }
00264   };
00266 
00268   //
00269   //    METHOD NAME : PublicKey::PublicKey
00270   //    METHOD TYPE : Ctor
00271   //
00272   PublicKey::PublicKey()
00273   : _pimpl( Impl::nullimpl() )
00274   {}
00275 
00276   PublicKey::PublicKey( const Pathname & file )
00277   : _pimpl( new Impl(file) )
00278   {}
00279 
00280   PublicKey::PublicKey( const filesystem::TmpFile & sharedfile )
00281   : _pimpl( new Impl(sharedfile) )
00282   {}
00283 
00285   //
00286   //    METHOD NAME : PublicKey::~PublicKey
00287   //    METHOD TYPE : Dtor
00288   //
00289   PublicKey::~PublicKey()
00290   {}
00291 
00293   //
00294   // Forward to implementation:
00295   //
00297 
00298   std::string PublicKey::asString() const
00299   { return _pimpl->asString(); }
00300 
00301   std::string PublicKey::id() const
00302   { return _pimpl->id(); }
00303 
00304   std::string PublicKey::name() const
00305   { return _pimpl->name(); }
00306 
00307   std::string PublicKey::fingerprint() const
00308   { return _pimpl->fingerprint(); }
00309 
00310   std::string PublicKey::gpgPubkeyVersion() const
00311   { return _pimpl->gpgPubkeyVersion(); }
00312 
00313   std::string PublicKey::gpgPubkeyRelease() const
00314   { return _pimpl->gpgPubkeyRelease(); }
00315 
00316   Date PublicKey::created() const
00317   { return _pimpl->created(); }
00318 
00319   Date PublicKey::expires() const
00320   { return _pimpl->expires(); }
00321 
00322   std::string PublicKey::expiresAsString() const
00323   { return _pimpl->expiresAsString(); }
00324 
00325   bool PublicKey::expired() const
00326   { return _pimpl->expired(); }
00327 
00328   int PublicKey::daysToLive() const
00329   { return _pimpl->daysToLive(); }
00330 
00331   Pathname PublicKey::path() const
00332   { return _pimpl->path(); }
00333 
00334   bool PublicKey::operator==( PublicKey b ) const
00335   {
00336     return (   b.id() == id()
00337             && b.fingerprint() == fingerprint()
00338             && b.created() == created() );
00339   }
00340 
00341   bool PublicKey::operator==( std::string sid ) const
00342   {
00343     return sid == id();
00344   }
00345 
00346   std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
00347   {
00348     str << "[" << obj.name() << "]" << endl;
00349     str << "  fpr " << obj.fingerprint() << endl;
00350     str << "   id " << obj.id() << endl;
00351     str << "  cre " << obj.created() << endl;
00352     str << "  exp " << obj.expiresAsString() << endl;
00353     str << "  ttl " << obj.daysToLive() << endl;
00354     str << "  rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl;
00355     str << "]";
00356     return str;
00357   }
00358 
00360 } // namespace zypp