libzypp 9.41.1
|
00001 /*---------------------------------------------------------------------\ 00002 | ____ _ __ __ ___ | 00003 | |__ / \ / / . \ . \ | 00004 | / / \ V /| _/ _/ | 00005 | / /__ | | | | | | | 00006 | /_____||_| |_| |_| | 00007 | | 00008 \---------------------------------------------------------------------*/ 00012 #include <climits> 00013 00014 #include <iostream> 00015 #include <vector> 00016 00017 #include "zypp/base/Gettext.h" 00018 #include "zypp/base/String.h" 00019 #include "zypp/base/Regex.h" 00020 #include "zypp/PublicKey.h" 00021 #include "zypp/ExternalProgram.h" 00022 #include "zypp/TmpPath.h" 00023 #include "zypp/PathInfo.h" 00024 #include "zypp/base/Exception.h" 00025 #include "zypp/base/LogTools.h" 00026 #include "zypp/Date.h" 00027 #include "zypp/TmpPath.h" 00028 00029 #include <ctime> 00030 00031 using std::endl; 00032 00034 namespace zypp 00035 { 00036 00041 struct PublicKeyData::Impl 00042 { 00043 std::string _id; 00044 std::string _name; 00045 std::string _fingerprint; 00046 Date _created; 00047 Date _expires; 00048 00049 public: 00051 static shared_ptr<Impl> nullimpl() 00052 { 00053 static shared_ptr<Impl> _nullimpl( new Impl ); 00054 return _nullimpl; 00055 } 00056 00057 private: 00058 friend Impl * rwcowClone<Impl>( const Impl * rhs ); 00060 Impl * clone() const 00061 { return new Impl( *this ); } 00062 }; 00064 00068 00069 PublicKeyData::PublicKeyData() 00070 : _pimpl( Impl::nullimpl() ) 00071 {} 00072 00073 PublicKeyData::~PublicKeyData() 00074 {} 00075 00076 bool PublicKeyData::boolTest() const 00077 { return !_pimpl->_fingerprint.empty(); } 00078 00079 std::string PublicKeyData::id() const 00080 { return _pimpl->_id; } 00081 00082 std::string PublicKeyData::name() const 00083 { return _pimpl->_name; } 00084 00085 std::string PublicKeyData::fingerprint() const 00086 { return _pimpl->_fingerprint; } 00087 00088 Date PublicKeyData::created() const 00089 { return _pimpl->_created; } 00090 00091 Date PublicKeyData::expires() const 00092 { return _pimpl->_expires; } 00093 00094 bool PublicKeyData::expired() const 00095 { return( _pimpl->_expires && _pimpl->_expires < Date::now() ); } 00096 00097 int PublicKeyData::daysToLive() const 00098 { 00099 if ( _pimpl->_expires ) 00100 { 00101 Date exp( _pimpl->_expires - Date::now() ); 00102 return exp < 0 ? exp / Date::day - 1 : exp / Date::day; 00103 } 00104 return INT_MAX; 00105 } 00106 00107 std::string PublicKeyData::expiresAsString() const 00108 { 00109 if ( !_pimpl->_expires ) 00110 { // translators: an annotation to a gpg keys expiry date 00111 return _("(does not expire)"); 00112 } 00113 std::string ret( _pimpl->_expires.asString() ); 00114 int ttl( daysToLive() ); 00115 if ( ttl <= 90 ) 00116 { 00117 ret += " "; 00118 if ( ttl < 0 ) 00119 { // translators: an annotation to a gpg keys expiry date 00120 ret += _("(EXPIRED)"); 00121 } 00122 else if ( ttl == 0 ) 00123 { // translators: an annotation to a gpg keys expiry date 00124 ret += _("(expires within 24h)"); 00125 } 00126 else 00127 { // translators: an annotation to a gpg keys expiry date 00128 ret += str::form( _PL("(expires in %d day)", "(expires in %d days)", ttl ), ttl ); 00129 } 00130 } 00131 return ret; 00132 } 00133 00134 std::string PublicKeyData::gpgPubkeyVersion() const 00135 { return _pimpl->_id.empty() ? _pimpl->_id : str::toLower( _pimpl->_id.substr(8,8) ); } 00136 00137 std::string PublicKeyData::gpgPubkeyRelease() const 00138 { return _pimpl->_created ? str::hexstring( _pimpl->_created ).substr(2) : std::string(); } 00139 00140 std::string PublicKeyData::asString() const 00141 { 00142 return str::form( "[%s-%s] [%s] [%s] [TTL %d]", 00143 _pimpl->_id.c_str(), 00144 gpgPubkeyRelease().c_str(), 00145 _pimpl->_name.c_str(), 00146 _pimpl->_fingerprint.c_str(), 00147 daysToLive() ); 00148 } 00149 00150 std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj ) 00151 { 00152 str << "[" << obj.name() << "]" << endl; 00153 str << " fpr " << obj.fingerprint() << endl; 00154 str << " id " << obj.id() << endl; 00155 str << " cre " << Date::ValueType(obj.created()) << ' ' << obj.created() << endl; 00156 str << " exp " << Date::ValueType(obj.expires()) << ' ' << obj.expiresAsString() << endl; 00157 str << " ttl " << obj.daysToLive() << endl; 00158 str << " rpm " << obj.gpgPubkeyVersion() << "-" << obj.gpgPubkeyRelease() << endl; 00159 str << "]"; 00160 return str; 00161 } 00162 00163 bool operator==( const PublicKeyData & lhs, const PublicKeyData & rhs ) 00164 { return ( lhs.fingerprint() == rhs.fingerprint() && lhs.created() == rhs.created() ); } 00165 00166 00171 struct PublicKeyScanner::Impl 00172 { 00173 std::vector<std::string> _words; 00174 enum { pNONE, pPUB, pSIG, pFPR, pUID } _parseEntry; 00175 00176 Impl() 00177 : _parseEntry( pNONE ) 00178 {} 00179 00180 void scan( std::string & line_r, std::list<PublicKeyData> & keys_r ) 00181 { 00182 // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>: 00183 // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA: 00184 // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x: 00185 // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x: 00186 // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x: 00187 // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x: 00188 // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21] 00189 // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x: 00190 if ( line_r.empty() ) 00191 return; 00192 00193 // quick check for interesting entries 00194 _parseEntry = pNONE; 00195 switch ( line_r[0] ) 00196 { 00197 #define DOTEST( C1, C2, C3, E ) case C1: if ( line_r[1] == C2 && line_r[2] == C3 && line_r[3] == ':' ) _parseEntry = E; break 00198 DOTEST( 'p', 'u', 'b', pPUB ); 00199 DOTEST( 's', 'i', 'g', pSIG ); 00200 DOTEST( 'f', 'p', 'r', pFPR ); 00201 DOTEST( 'u', 'i', 'd', pUID ); 00202 #undef DOTEST 00203 } 00204 if ( _parseEntry == pNONE ) 00205 return; 00206 00207 if ( line_r[line_r.size()-1] == '\n' ) 00208 line_r.erase( line_r.size()-1 ); 00209 // DBG << line_r << endl; 00210 00211 _words.clear(); 00212 str::splitFields( line_r, std::back_inserter(_words), ":" ); 00213 00214 PublicKeyData * key( &keys_r.back() ); 00215 00216 switch ( _parseEntry ) 00217 { 00218 case pPUB: 00219 keys_r.push_back( PublicKeyData() ); // reset upon new key 00220 key = &keys_r.back(); 00221 key->_pimpl->_id = _words[4]; 00222 key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" ); 00223 key->_pimpl->_created = Date(str::strtonum<Date::ValueType>(_words[5])); 00224 key->_pimpl->_expires = Date(str::strtonum<Date::ValueType>(_words[6])); 00225 break; 00226 00227 case pSIG: 00228 // Update creation/modification date from signatures type "13x". 00229 if ( _words[_words.size()-2] == "13x" ) 00230 { 00231 Date cdate(str::strtonum<Date::ValueType>(_words[5])); 00232 if ( key->_pimpl->_created < cdate ) 00233 key->_pimpl->_created = cdate; 00234 } 00235 break; 00236 00237 case pFPR: 00238 if ( key->_pimpl->_fingerprint.empty() ) 00239 key->_pimpl->_fingerprint = _words[9]; 00240 break; 00241 00242 case pUID: 00243 if ( ! _words[9].empty() ) 00244 key->_pimpl->_name = str::replaceAll( _words[9], "\\x3a", ":" ); 00245 break; 00246 00247 case pNONE: 00248 break; 00249 } 00250 } 00251 }; 00253 00255 // class PublicKeyScanner 00257 00258 PublicKeyScanner::PublicKeyScanner() 00259 : _pimpl( new Impl ) 00260 {} 00261 00262 PublicKeyScanner::~PublicKeyScanner() 00263 {} 00264 00265 void PublicKeyScanner::scan( std::string line_r ) 00266 { _pimpl->scan( line_r, _keys ); } 00267 00268 00273 struct PublicKey::Impl 00274 { 00275 Impl() 00276 {} 00277 00278 Impl( const Pathname & keyFile_r ) 00279 { 00280 PathInfo info( keyFile_r ); 00281 MIL << "Taking pubkey from " << keyFile_r << " of size " << info.size() << " and sha1 " << filesystem::checksum(keyFile_r, "sha1") << endl; 00282 00283 if ( !info.isExist() ) 00284 ZYPP_THROW(Exception("Can't read public key from " + keyFile_r.asString() + ", file not found")); 00285 00286 if ( filesystem::hardlinkCopy( keyFile_r, _dataFile.path() ) != 0 ) 00287 ZYPP_THROW(Exception("Can't copy public key data from " + keyFile_r.asString() + " to " + _dataFile.path().asString() )); 00288 00289 readFromFile(); 00290 } 00291 00292 Impl( const filesystem::TmpFile & sharedFile_r ) 00293 : _dataFile( sharedFile_r ) 00294 { readFromFile(); } 00295 00296 Impl( const filesystem::TmpFile & sharedFile_r, const PublicKeyData & keyData_r ) 00297 : _dataFile( sharedFile_r ) 00298 , _keyData( keyData_r ) 00299 { 00300 if ( ! keyData_r ) 00301 { 00302 WAR << "Invalid PublicKeyData supplied: scanning from file" << endl; 00303 readFromFile(); 00304 } 00305 } 00306 00307 public: 00308 const PublicKeyData & keyData() const 00309 { return _keyData; } 00310 00311 Pathname path() const 00312 { return _dataFile.path(); } 00313 00314 const std::list<PublicKeyData> & hiddenKeys() const 00315 { return _hiddenKeys; } 00316 00317 protected: 00318 void readFromFile() 00319 { 00320 PathInfo info( _dataFile.path() ); 00321 MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl; 00322 00323 static filesystem::TmpDir dir; 00324 const char* argv[] = 00325 { 00326 "gpg", 00327 "-v", 00328 "--no-default-keyring", 00329 "--fixed-list-mode", 00330 "--with-fingerprint", 00331 "--with-colons", 00332 "--homedir", 00333 dir.path().asString().c_str(), 00334 "--quiet", 00335 "--no-tty", 00336 "--no-greeting", 00337 "--batch", 00338 "--status-fd", 00339 "1", 00340 _dataFile.path().asString().c_str(), 00341 NULL 00342 }; 00343 ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true ); 00344 00345 PublicKeyScanner scanner; 00346 for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() ) 00347 { 00348 scanner.scan( line ); 00349 } 00350 prog.close(); 00351 00352 switch ( scanner._keys.size() ) 00353 { 00354 case 0: 00355 ZYPP_THROW( BadKeyException( "File " + _dataFile.path().asString() + " doesn't contain public key data" , _dataFile.path() ) ); 00356 break; 00357 00358 case 1: 00359 // ok. 00360 _keyData = scanner._keys.back(); 00361 _hiddenKeys.clear(); 00362 break; 00363 00364 default: 00365 WAR << "File " << _dataFile.path().asString() << " contains multiple keys: " << scanner._keys << endl; 00366 _keyData = scanner._keys.back(); 00367 scanner._keys.pop_back(); 00368 _hiddenKeys.swap( scanner._keys ); 00369 break; 00370 } 00371 00372 MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl; 00373 } 00374 00375 private: 00376 filesystem::TmpFile _dataFile; 00377 PublicKeyData _keyData; 00378 std::list<PublicKeyData> _hiddenKeys; 00379 00380 public: 00382 static shared_ptr<Impl> nullimpl() 00383 { 00384 static shared_ptr<Impl> _nullimpl( new Impl ); 00385 return _nullimpl; 00386 } 00387 00388 private: 00389 friend Impl * rwcowClone<Impl>( const Impl * rhs ); 00391 Impl * clone() const 00392 { return new Impl( *this ); } 00393 }; 00395 00397 // class PublicKey 00399 PublicKey::PublicKey() 00400 : _pimpl( Impl::nullimpl() ) 00401 {} 00402 00403 PublicKey::PublicKey( const Pathname & file ) 00404 : _pimpl( new Impl( file ) ) 00405 {} 00406 00407 PublicKey::PublicKey( const filesystem::TmpFile & sharedfile ) 00408 : _pimpl( new Impl( sharedfile ) ) 00409 {} 00410 00411 PublicKey::PublicKey( const filesystem::TmpFile & sharedfile, const PublicKeyData & keydata ) 00412 : _pimpl( new Impl( sharedfile, keydata ) ) 00413 {} 00414 00415 PublicKey::~PublicKey() 00416 {} 00417 00418 const PublicKeyData & PublicKey::keyData() const 00419 { return _pimpl->keyData(); } 00420 00421 Pathname PublicKey::path() const 00422 { return _pimpl->path(); } 00423 00424 const std::list<PublicKeyData> & PublicKey::hiddenKeys() const 00425 { return _pimpl->hiddenKeys(); } 00426 00427 std::string PublicKey::id() const 00428 { return keyData().id(); } 00429 00430 std::string PublicKey::name() const 00431 { return keyData().name(); } 00432 00433 std::string PublicKey::fingerprint() const 00434 { return keyData().fingerprint(); } 00435 00436 Date PublicKey::created() const 00437 { return keyData().created(); } 00438 00439 Date PublicKey::expires() const 00440 { return keyData().expires(); } 00441 00442 bool PublicKey::expired() const 00443 { return keyData().expired(); } 00444 00445 int PublicKey::daysToLive() const 00446 { return keyData().daysToLive(); } 00447 00448 std::string PublicKey::expiresAsString() const 00449 { return keyData().expiresAsString(); } 00450 00451 std::string PublicKey::gpgPubkeyVersion() const 00452 { return keyData().gpgPubkeyVersion(); } 00453 00454 std::string PublicKey::gpgPubkeyRelease() const 00455 { return keyData().gpgPubkeyRelease(); } 00456 00457 std::string PublicKey::asString() const 00458 { return keyData().asString(); } 00459 00460 bool PublicKey::operator==( PublicKey rhs ) const 00461 { return rhs.keyData() == keyData(); } 00462 00463 bool PublicKey::operator==( std::string sid ) const 00464 { return sid == id(); } 00465 00466 std::ostream & dumpOn( std::ostream & str, const PublicKey & obj ) 00467 { return dumpOn( str, obj.keyData() ); } 00468 00470 } // namespace zypp