libzypp
10.5.0
|
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