libzypp  17.30.2
KeyRing.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <fstream>
14 #include <optional>
15 #include <sys/file.h>
16 #include <cstdio>
17 #include <unistd.h>
18 
19 #include <zypp/TmpPath.h>
20 #include <zypp/ZYppFactory.h>
21 #include <zypp/ZYpp.h>
22 
23 #include <zypp/base/LogTools.h>
24 #include <zypp/base/IOStream.h>
25 #include <zypp/base/String.h>
26 #include <zypp/base/Regex.h>
27 #include <zypp/base/Gettext.h>
28 #include <zypp-core/fs/WatchFile>
29 #include <zypp/PathInfo.h>
30 #include <zypp/KeyRing.h>
31 #include <zypp/ExternalProgram.h>
32 #include <zypp/TmpPath.h>
33 #include <zypp/ZYppCallbacks.h> // JobReport::instance
34 #include <zypp/KeyManager.h>
35 
36 using std::endl;
37 
38 #undef ZYPP_BASE_LOGGER_LOGGROUP
39 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
40 
42 namespace zypp
43 {
44 
46 
47  namespace
48  {
49  KeyRing::DefaultAccept _keyRingDefaultAccept( KeyRing::ACCEPT_NOTHING );
50  }
51 
52  KeyRing::DefaultAccept KeyRing::defaultAccept()
53  { return _keyRingDefaultAccept; }
54 
55  void KeyRing::setDefaultAccept( DefaultAccept value_r )
56  {
57  MIL << "Set new KeyRing::DefaultAccept: " << value_r << endl;
58  _keyRingDefaultAccept = value_r;
59  }
60 
61  void KeyRingReport::infoVerify( const std::string & file_r, const PublicKeyData & keyData_r, const KeyContext & keycontext )
62  {}
63 
64  bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string & file, const KeyContext & keycontext )
65  { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNSIGNED_FILE ); }
66 
68  KeyRingReport::askUserToAcceptKey( const PublicKey & key, const KeyContext & keycontext )
69  {
70  if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_KEY_TEMPORARILY ) )
71  return KEY_TRUST_TEMPORARILY;
72  if ( _keyRingDefaultAccept.testFlag( KeyRing::TRUST_AND_IMPORT_KEY ) )
73  return KEY_TRUST_AND_IMPORT;
74  return KEY_DONT_TRUST;
75  }
76 
77  bool KeyRingReport::askUserToAcceptUnknownKey( const std::string & file, const std::string & id, const KeyContext & keycontext )
78  { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_UNKNOWNKEY ); }
79 
80  bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string & file, const PublicKey & key, const KeyContext & keycontext )
81  { return _keyRingDefaultAccept.testFlag( KeyRing::ACCEPT_VERIFICATION_FAILED ); }
82 
83  bool KeyRingReport::askUserToAcceptPackageKey(const PublicKey &key_r, const KeyContext &keycontext_r)
84  {
86  data.set("PublicKey", key_r);
87  data.set("KeyContext", keycontext_r);
88  report(data);
89 
90  if ( data.hasvalue("TrustKey") )
91  return data.get<bool>("TrustKey");
92  return false;
93  }
94 
95  void KeyRingReport::reportNonImportedKeys(const std::set<Edition> &keys_r)
96  {
98  data.set("Keys", keys_r);
99  report(data);
100  }
101 
102  void KeyRingReport::reportAutoImportKey( const std::list<PublicKeyData> & keyDataList_r,
103  const PublicKeyData & keySigning_r,
104  const KeyContext &keyContext_r )
105  {
107  data.set( "KeyDataList", keyDataList_r );
108  data.set( "KeySigning", keySigning_r );
109  data.set( "KeyContext", keyContext_r );
110  report( data );
111  }
112 
113  namespace
114  {
122  struct CachedPublicKeyData : private base::NonCopyable
123  {
124  const std::list<PublicKeyData> & operator()( const Pathname & keyring_r ) const
125  { return getData( keyring_r ); }
126 
127  void setDirty( const Pathname & keyring_r )
128  { _cacheMap[keyring_r].setDirty(); }
129 
136  struct Manip {
137  NON_COPYABLE_BUT_MOVE( Manip );
138  Manip( CachedPublicKeyData & cache_r, Pathname keyring_r )
139  : _cache { cache_r }
140  , _keyring { std::move(keyring_r) }
141  {}
142 
143  KeyManagerCtx & keyManagerCtx() {
144  if ( not _context ) {
146  }
147  // frankly: don't remember why an explicit setDirty was introduced and
148  // why WatchFile was not enough. Maybe some corner case when the keyrings
149  // are created?
150  _cache.setDirty( _keyring );
151  return _context.value();
152  }
153 
154  private:
155  CachedPublicKeyData & _cache;
156  Pathname _keyring;
157  std::optional<KeyManagerCtx> _context;
158  };
160 
162  Manip manip( Pathname keyring_r ) { return Manip( *this, std::move(keyring_r) ); }
163 
164  private:
165  struct Cache
166  {
167  Cache() {}
168 
169  void setDirty()
170  {
171  _keyringK.reset();
172  _keyringP.reset();
173  }
174 
175  void assertCache( const Pathname & keyring_r )
176  {
177  // .kbx since gpg2-2.1
178  if ( !_keyringK )
179  _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
180  if ( !_keyringP )
181  _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
182  }
183 
184  bool hasChanged() const
185  {
186  bool k = _keyringK->hasChanged(); // be sure both files are checked
187  bool p = _keyringP->hasChanged();
188  return k || p;
189  }
190 
191  std::list<PublicKeyData> _data;
192 
193  private:
194 
197  };
198 
199  typedef std::map<Pathname,Cache> CacheMap;
200 
201  const std::list<PublicKeyData> & getData( const Pathname & keyring_r ) const
202  {
203  Cache & cache( _cacheMap[keyring_r] );
204  // init new cache entry
205  cache.assertCache( keyring_r );
206  return getData( keyring_r, cache );
207  }
208 
209  const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
210  {
211  if ( cache_r.hasChanged() ) {
212  cache_r._data = KeyManagerCtx::createForOpenPGP( keyring_r ).listKeys();
213  MIL << "Found keys: " << cache_r._data << endl;
214  }
215  return cache_r._data;
216  }
217 
218  mutable CacheMap _cacheMap;
219  };
221 
222 
223  }
224 
226  //
227  // CLASS NAME : KeyRing::Impl
228  //
231  {
232  Impl( const Pathname & baseTmpDir )
233  : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
234  , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
235  , _base_dir( baseTmpDir )
236  {
237  MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
238  }
239 
240  void importKey( const PublicKey & key, bool trusted = false );
241  void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false );
242  void deleteKey( const std::string & id, bool trusted );
243 
244  std::string readSignatureKeyId( const Pathname & signature );
245 
246  bool isKeyTrusted( const std::string & id )
247  { return bool(publicKeyExists( id, trustedKeyRing() )); }
248  bool isKeyKnown( const std::string & id )
249  { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); }
250 
251  std::list<PublicKey> trustedPublicKeys()
252  { return publicKeys( trustedKeyRing() ); }
253  std::list<PublicKey> publicKeys()
254  { return publicKeys( generalKeyRing() ); }
255 
256  const std::list<PublicKeyData> & trustedPublicKeyData()
257  { return publicKeyData( trustedKeyRing() ); }
258  const std::list<PublicKeyData> & publicKeyData()
259  { return publicKeyData( generalKeyRing() ); }
260 
261  void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
262  { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); }
263 
265  { return exportKey( keyData, generalKeyRing() ); }
267  { return exportKey( keyData, trustedKeyRing() ); }
268 
270  {
271  // Assert result and return value are in sync
272  context_r.fileAccepted( _verifyFileSignatureWorkflow( context_r ) );
273  return context_r.fileAccepted();
274  }
276 
277  bool verifyFileSignature( const Pathname & file, const Pathname & signature )
278  { return verifyFile( file, signature, generalKeyRing() ); }
279  bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
280  { return verifyFile( file, signature, trustedKeyRing() ); }
281 
282  PublicKeyData publicKeyExists( const std::string & id )
283  { return publicKeyExists(id, generalKeyRing());}
284  PublicKeyData trustedPublicKeyExists( const std::string & id )
285  { return publicKeyExists(id, trustedKeyRing());}
286 
287  bool provideAndImportKeyFromRepositoryWorkflow (const std::string &id_r , const RepoInfo &info_r );
288 
289  void allowPreload( bool yesno_r )
290  { _allowPreload = yesno_r; }
291 
292  private:
294  CachedPublicKeyData::Manip keyRingManip( const Pathname & keyring )
295  { return cachedPublicKeyData.manip( keyring ); }
296 
297  bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring );
298  void importKey( const Pathname & keyfile, const Pathname & keyring );
299 
300  PublicKey exportKey( const std::string & id, const Pathname & keyring );
301  PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring );
302  PublicKey exportKey( const PublicKey & key, const Pathname & keyring )
303  { return exportKey( key.keyData(), keyring ); }
304 
305  void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream );
306  filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring );
307 
308  void deleteKey( const std::string & id, const Pathname & keyring );
309 
310  std::list<PublicKey> publicKeys( const Pathname & keyring);
311  const std::list<PublicKeyData> & publicKeyData( const Pathname & keyring )
312  { return cachedPublicKeyData( keyring ); }
313 
315  PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring );
317  void preloadCachedKeys();
318 
319  const Pathname generalKeyRing() const
320  { return _general_tmp_dir.path(); }
321  const Pathname trustedKeyRing() const
322  { return _trusted_tmp_dir.path(); }
323 
324  // Used for trusted and untrusted keyrings
328  bool _allowPreload = false; //< General keyring may be preloaded with keys cached on the system.
329 
330  private:
336  CachedPublicKeyData cachedPublicKeyData;
337  };
339 
340  namespace
341  {
343  struct ImportKeyCBHelper
344  {
345  void operator()( const PublicKey & key_r )
346  {
347  try {
348  _rpmdbEmitSignal->trustedKeyAdded( key_r );
349  _emitSignal->trustedKeyAdded( key_r );
350  }
351  catch ( const Exception & excp )
352  {
353  ERR << "Could not import key into rpmdb: " << excp << endl;
354  // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
356  }
357  }
358 
359  private:
360  callback::SendReport<target::rpm::KeyRingSignals> _rpmdbEmitSignal;
361  callback::SendReport<KeyRingSignals> _emitSignal;
362  };
363  } // namespace
364 
365 
366  void KeyRing::Impl::importKey( const PublicKey & key, bool trusted )
367  {
368  importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
369  MIL << "Imported key " << key << " to " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
370 
371  if ( trusted )
372  {
373  ImportKeyCBHelper emitSignal;
374  if ( key.hiddenKeys().empty() )
375  {
376  emitSignal( key );
377  }
378  else
379  {
380  // multiple keys: Export individual keys ascii armored to import in rpmdb
381  emitSignal( exportKey( key, trustedKeyRing() ) );
382  for ( const PublicKeyData & hkey : key.hiddenKeys() )
383  emitSignal( exportKey( hkey, trustedKeyRing() ) );
384  }
385  }
386  }
387 
388  void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
389  {
390  importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
391  }
392 
393  void KeyRing::Impl::deleteKey( const std::string & id, bool trusted )
394  {
395  PublicKeyData keyDataToDel( publicKeyExists( id, trusted ? trustedKeyRing() : generalKeyRing() ) );
396  if ( ! keyDataToDel )
397  {
398  WAR << "Key to delete [" << id << "] is not in " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
399  return;
400  }
401  deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
402  MIL << "Deleted key [" << id << "] from " << (trusted ? "trustedKeyRing" : "generalKeyRing" ) << endl;
403 
404  if ( trusted )
405  try {
406  PublicKey key( keyDataToDel );
407 
409  rpmdbEmitSignal->trustedKeyRemoved( key );
410 
412  emitSignal->trustedKeyRemoved( key );
413  }
414  catch ( const Exception & excp )
415  {
416  ERR << "Could not delete key from rpmmdb: " << excp << endl;
417  // TODO: JobReport as hotfix for bsc#1057188; should bubble up and go through some callback
419  }
420  }
421 
422  PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring )
423  {
424  if ( _allowPreload && keyring == generalKeyRing() ) {
425  _allowPreload = false;
426  preloadCachedKeys();
427  }
428 
429  PublicKeyData ret;
430  for ( const PublicKeyData & key : publicKeyData( keyring ) )
431  {
432  if ( key.providesKey( id ) )
433  {
434  ret = key;
435  break;
436  }
437  }
438  DBG << (ret ? "Found" : "No") << " key [" << id << "] in keyring " << keyring << endl;
439  return ret;
440  }
441 
443  {
444  MIL << "preloadCachedKeys into general keyring..." << endl;
445  CachedPublicKeyData::Manip manip { keyRingManip( generalKeyRing() ) }; // Provides the context if we want to manip a cached keyring.
446 
447  // For now just load the 'gpg-pubkey-*.{asc,key}' files into the general keyring,
448  // if their id (derived from the filename) is not in the trusted ring.
449  // TODO: Head for a persistent general keyring.
450  std::set<Pathname> cachedirs;
451  ZConfig & conf { ZConfig::instance() };
452  cachedirs.insert( conf.pubkeyCachePath() );
453  cachedirs.insert( "/usr/lib/rpm/gnupg/keys" );
454  if ( Pathname r = conf.systemRoot(); r != "/" && not r.empty() ) {
455  cachedirs.insert( r / conf.pubkeyCachePath() );
456  cachedirs.insert( r / "/usr/lib/rpm/gnupg/keys" );
457  }
458  if ( Pathname r = conf.repoManagerRoot(); r != "/" && not r.empty() ) {
459  cachedirs.insert( r / conf.pubkeyCachePath() );
460  cachedirs.insert( r / "/usr/lib/rpm/gnupg/keys" );
461  }
462 
463  std::map<std::string,Pathname> keyCandidates; // Collect one file path per keyid
464  const str::regex rx { "^gpg-pubkey-([[:xdigit:]]{8,})(-[[:xdigit:]]{8,})?\\.(asc|key)$" };
465  for ( const auto & cache : cachedirs ) {
466  dirForEach( cache,
467  [&rx,&keyCandidates]( const Pathname & dir_r, const char *const file_r )->bool {
468  str::smatch what;
469  if ( str::regex_match( file_r, what, rx ) ) {
470  Pathname & remember { keyCandidates[what[1]] };
471  if ( remember.empty() ) {
472  remember = dir_r / file_r;
473  }
474  }
475  return true;
476  }
477  );
478  }
479 
480  for ( const auto & p : keyCandidates ) {
481  // Avoid checking the general keyring while it is flagged dirty.
482  // Checking the trusted ring is ok, and most keys will be there anyway.
483  const std::string & id { p.first };
484  const Pathname & path { p.second };
485  if ( isKeyTrusted(id) )
486  continue;
487  if ( manip.keyManagerCtx().importKey( path ) ) {
488  DBG << "preload key file " << path << endl;
489  }
490  else {
491  WAR << "Skipping: Can't preload key file " << path << endl;
492  }
493  }
494  }
495 
496  PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
497  {
498  return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
499  }
500 
501  PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring )
502  {
503  PublicKeyData keyData( publicKeyExists( id, keyring ) );
504  if ( keyData )
505  return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
506 
507  // Here: key not found
508  WAR << "No key [" << id << "] to export from " << keyring << endl;
509  return PublicKey();
510  }
511 
512 
513  void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
514  {
515  KeyManagerCtx::createForOpenPGP( keyring ).exportKey(id, stream);
516  }
517 
518  filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
519  {
520  filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
521  MIL << "Going to export key [" << id << "] from " << keyring << " to " << tmpFile.path() << endl;
522 
523  std::ofstream os( tmpFile.path().c_str() );
524  dumpPublicKey( id, keyring, os );
525  os.close();
526  return tmpFile;
527  }
528 
530  {
531  context_r.resetResults();
532  const Pathname & file { context_r.file() };
533  const Pathname & signature { context_r.signature() };
534  const std::string & filedesc { context_r.shortFile() };
535  const KeyContext & keyContext { context_r.keyContext() };
536 
538  MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
539 
540  // if signature does not exists, ask user if they want to accept unsigned file.
541  if( signature.empty() || (!PathInfo( signature ).isExist()) )
542  {
543  bool res = report->askUserToAcceptUnsignedFile( filedesc, keyContext );
544  MIL << "askUserToAcceptUnsignedFile: " << res << endl;
545  return res;
546  }
547 
548  // get the id of the signature (it might be a subkey id!)
549  context_r.signatureId( readSignatureKeyId( signature ) );
550  const std::string & id = context_r.signatureId();
551  PublicKeyData foundKey;
552  Pathname whichKeyring;
553 
554  std::list<PublicKeyData> buddies; // Could be imported IFF the file is validated by a trusted key
555  for ( const auto & sid : context_r.buddyKeys() ) {
556  if ( not PublicKeyData::isSafeKeyId( sid ) ) {
557  WAR << "buddy " << sid << ": key id is too short to safely identify a gpg key. Skipping it." << endl;
558  continue;
559  }
560  if ( trustedPublicKeyExists( sid ) ) {
561  MIL << "buddy " << sid << ": already in trusted key ring. Not needed." << endl;
562  continue;
563  }
564  auto pk = publicKeyExists( sid );
565  if ( not pk ) {
566  WAR << "buddy " << sid << ": not available in the public key ring. Skipping it." << endl;
567  continue;
568  }
569  if ( pk.providesKey(id) ) {
570  MIL << "buddy " << sid << ": is the signing key. Handled separately." << endl;
571  continue;
572  }
573  MIL << "buddy " << sid << ": candidate for auto import. Remeber it." << endl;
574  buddies.push_back( pk );
575  }
576 
577  if ( !id.empty() ) {
578 
579  // does key exists in trusted keyring
580  PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) );
581  if ( trustedKeyData )
582  {
583  MIL << "Key is trusted: " << trustedKeyData << endl;
584 
585  // lets look if there is an updated key in the
586  // general keyring
587  PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
588  if ( generalKeyData )
589  {
590  // bnc #393160: Comment #30: Compare at least the fingerprint
591  // in case an attacker created a key the the same id.
592  //
593  // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
594  // to compare the subkey sets, to tell whether a key was updated.
595  // because created() remains unchanged if the primary key is not touched.
596  // For now we wait until a new subkey signs the data and treat it as a
597  // new key (else part below).
598  if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
599  && trustedKeyData.created() < generalKeyData.created() )
600  {
601  MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
602  importKey( exportKey( generalKeyData, generalKeyRing() ), true );
603  trustedKeyData = publicKeyExists( id, trustedKeyRing() ); // re-read: invalidated by import?
604  }
605  }
606 
607  foundKey = trustedKeyData;
608  whichKeyring = trustedKeyRing();
609  }
610  else
611  {
612  PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
613  if ( generalKeyData )
614  {
615  PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
616  MIL << "Key [" << id << "] " << key.name() << " is not trusted" << endl;
617 
618  // ok the key is not trusted, ask the user to trust it or not
619  KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, keyContext );
620  if ( reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
622  {
623  MIL << "User wants to trust key [" << id << "] " << key.name() << endl;
624 
626  {
627  MIL << "User wants to import key [" << id << "] " << key.name() << endl;
628  importKey( key, true );
629  whichKeyring = trustedKeyRing();
630  }
631  else
632  whichKeyring = generalKeyRing();
633 
634  foundKey = generalKeyData;
635  }
636  else
637  {
638  MIL << "User does not want to trust key [" << id << "] " << key.name() << endl;
639  return false;
640  }
641  }
642  else if ( ! keyContext.empty() )
643  {
644  // try to find the key in the repository info
645  if ( provideAndImportKeyFromRepositoryWorkflow( id, keyContext.repoInfo() ) ) {
646  whichKeyring = trustedKeyRing();
647  foundKey = PublicKeyData( publicKeyExists( id, trustedKeyRing() ) );
648  }
649  }
650  }
651  }
652 
653  if ( foundKey ) {
654  // it exists, is trusted, does it validate?
655  context_r.signatureIdTrusted( whichKeyring == trustedKeyRing() );
656  report->infoVerify( filedesc, foundKey, keyContext );
657  if ( verifyFile( file, signature, whichKeyring ) )
658  {
659  context_r.fileValidated( true );
660  if ( context_r.signatureIdTrusted() && not buddies.empty() ) {
661  // Check for buddy keys to be imported...
662  MIL << "Validated with trusted key: importing buddy list..." << endl;
663  report->reportAutoImportKey( buddies, foundKey, keyContext );
664  for ( const auto & kd : buddies ) {
665  importKey( exportKey( kd, generalKeyRing() ), true );
666  }
667  }
668  return context_r.fileValidated(); // signature is actually successfully validated!
669  }
670  else
671  {
672  bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( foundKey, whichKeyring ), keyContext );
673  MIL << "askUserToAcceptVerificationFailed: " << res << endl;
674  return res;
675  }
676  } else {
677  // signed with an unknown key...
678  MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
679  bool res = report->askUserToAcceptUnknownKey( filedesc, id, keyContext );
680  MIL << "askUserToAcceptUnknownKey: " << res << endl;
681  return res;
682  }
683 
684  return false;
685  }
686 
687  bool KeyRing::Impl::provideAndImportKeyFromRepositoryWorkflow(const std::string &id_r, const RepoInfo &info_r)
688  {
689  if ( id_r.empty() )
690  return false;
691 
692  const ZConfig &conf = ZConfig::instance();
693  Pathname cacheDir = conf.repoManagerRoot() / conf.pubkeyCachePath();
694 
695  Pathname myKey = info_r.provideKey( id_r, cacheDir );
696  if ( myKey.empty() )
697  // if we did not find any keys, there is no point in checking again, break
698  return false;
699 
701 
702  PublicKey key;
703  try {
704  key = PublicKey( myKey );
705  } catch ( const Exception &e ) {
706  ZYPP_CAUGHT(e);
707  return false;
708  }
709 
710  if ( !key.isValid() ) {
711  ERR << "Key [" << id_r << "] from cache: " << cacheDir << " is not valid" << endl;
712  return false;
713  }
714 
715  MIL << "Key [" << id_r << "] " << key.name() << " loaded from cache" << endl;
716 
717  KeyContext context;
718  context.setRepoInfo( info_r );
719  if ( ! report->askUserToAcceptPackageKey( key, context ) ) {
720  return false;
721  }
722 
723  MIL << "User wants to import key [" << id_r << "] " << key.name() << " from cache" << endl;
724  try {
725  importKey( key, true );
726  } catch ( const KeyRingException &e ) {
727  ZYPP_CAUGHT(e);
728  ERR << "Failed to import key: "<<id_r;
729  return false;
730  }
731 
732  return true;
733  }
734 
735  std::list<PublicKey> KeyRing::Impl::publicKeys( const Pathname & keyring )
736  {
737  const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
738  std::list<PublicKey> ret;
739 
740  for_( it, keys.begin(), keys.end() )
741  {
742  PublicKey key( exportKey( *it, keyring ) );
743  ret.push_back( key );
744  MIL << "Found key " << key << endl;
745  }
746  return ret;
747  }
748 
749  void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring )
750  {
751  if ( ! PathInfo( keyfile ).isExist() )
752  // TranslatorExplanation first %s is key name, second is keyring name
753  ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
754  % keyfile.asString()
755  % keyring.asString() ));
756 
757  CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
758  if ( ! manip.keyManagerCtx().importKey( keyfile ) )
759  ZYPP_THROW(KeyRingException(_("Failed to import key.")));
760  }
761 
762  void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
763  {
764  CachedPublicKeyData::Manip manip { keyRingManip( keyring ) }; // Provides the context if we want to manip a cached keyring.
765  if ( ! manip.keyManagerCtx().deleteKey( id ) )
766  ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
767  }
768 
769  std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
770  {
771  if ( ! PathInfo( signature ).isFile() )
772  ZYPP_THROW(KeyRingException( str::Format(_("Signature file %s not found")) % signature.asString() ));
773 
774  MIL << "Determining key id of signature " << signature << endl;
775 
776  std::list<std::string> fprs = KeyManagerCtx::createForOpenPGP().readSignatureFingerprints( signature );
777  if ( ! fprs.empty() ) {
778  std::string &id = fprs.back();
779  MIL << "Determined key id [" << id << "] for signature " << signature << endl;
780  return id;
781  }
782  return std::string();
783  }
784 
785  bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
786  {
787  return KeyManagerCtx::createForOpenPGP( keyring ).verify( file, signature );
788  }
789 
791 
793  //
794  // CLASS NAME : KeyRing
795  //
797 
798  KeyRing::KeyRing( const Pathname & baseTmpDir )
799  : _pimpl( new Impl( baseTmpDir ) )
800  {}
801 
803  {}
804 
805  void KeyRing::allowPreload( bool yesno_r )
806  { _pimpl->allowPreload( yesno_r ); }
807 
808 
809  void KeyRing::importKey( const PublicKey & key, bool trusted )
810  { _pimpl->importKey( key, trusted ); }
811 
812  void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
813  { _pimpl->multiKeyImport( keyfile_r, trusted_r ); }
814 
815  std::string KeyRing::readSignatureKeyId( const Pathname & signature )
816  { return _pimpl->readSignatureKeyId( signature ); }
817 
818  void KeyRing::deleteKey( const std::string & id, bool trusted )
819  { _pimpl->deleteKey( id, trusted ); }
820 
821  std::list<PublicKey> KeyRing::publicKeys()
822  { return _pimpl->publicKeys(); }
823 
824  std:: list<PublicKey> KeyRing::trustedPublicKeys()
825  { return _pimpl->trustedPublicKeys(); }
826 
827  std::list<PublicKeyData> KeyRing::publicKeyData()
828  { return _pimpl->publicKeyData(); }
829 
830  std::list<PublicKeyData> KeyRing::trustedPublicKeyData()
831  { return _pimpl->trustedPublicKeyData(); }
832 
833  PublicKeyData KeyRing::publicKeyData( const std::string &id_r )
834  { return _pimpl->publicKeyExists( id_r ); }
835 
837  { return _pimpl->trustedPublicKeyExists( id_r ); }
838 
839  bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext )
840  {
841  sigValid_r = false; // just in case....
842  keyring::VerifyFileContext context( file, signature );
843  context.shortFile( filedesc );
844  context.keyContext( keycontext );
845  verifyFileSignatureWorkflow( context );
846  sigValid_r = context.fileValidated();
847  return context.fileAccepted();
848  }
849 
850  bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string filedesc, const Pathname & signature, const KeyContext & keycontext )
851  {
852  keyring::VerifyFileContext context( file, signature );
853  context.shortFile( filedesc );
854  context.keyContext( keycontext );
855  verifyFileSignatureWorkflow( context );
856  return context.fileAccepted();
857  }
858 
860  { return _pimpl->verifyFileSignatureWorkflow( context_r ); }
861 
862  bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature )
863  { return _pimpl->verifyFileSignature( file, signature ); }
864 
865  bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
866  { return _pimpl->verifyFileTrustedSignature( file, signature ); }
867 
868  bool KeyRing::provideAndImportKeyFromRepositoryWorkflow(const std::string &id, const RepoInfo &info)
869  {
870  return _pimpl->provideAndImportKeyFromRepositoryWorkflow( id, info );
871  }
872 
873  void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
874  { _pimpl->dumpPublicKey( id, trusted, stream ); }
875 
877  { return _pimpl->exportPublicKey( keyData ); }
878 
880  { return _pimpl->exportTrustedPublicKey( keyData ); }
881 
882  bool KeyRing::isKeyTrusted( const std::string & id )
883  { return _pimpl->isKeyTrusted( id ); }
884 
885  bool KeyRing::isKeyKnown( const std::string & id )
886  { return _pimpl->isKeyKnown( id ); }
887 
889 } // namespace zypp
callback::SendReport< KeyRingSignals > _emitSignal
Definition: KeyRing.cc:361
std::list< PublicKeyData > _data
Definition: KeyRing.cc:191
scoped_ptr< WatchFile > _keyringK
Definition: KeyRing.cc:195
CachedPublicKeyData & _cache
Definition: KeyRing.cc:155
Pathname _keyring
Definition: KeyRing.cc:156
scoped_ptr< WatchFile > _keyringP
Definition: KeyRing.cc:196
std::optional< KeyManagerCtx > _context
Definition: KeyRing.cc:157
callback::SendReport< target::rpm::KeyRingSignals > _rpmdbEmitSignal
Definition: KeyRing.cc:360
CacheMap _cacheMap
Definition: KeyRing.cc:218
Wrapper for GPGME.
Base class for Exception.
Definition: Exception.h:146
std::string asUserHistory() const
A single (multiline) string composed of asUserString and historyAsString.
Definition: Exception.cc:91
bool exportKey(const std::string &id, std::ostream &stream)
Exports the key with id into the given stream, returns true on success.
Definition: KeyManager.cc:415
std::list< PublicKeyData > listKeys()
Returns a list of all public keys found in the current keyring.
Definition: KeyManager.cc:319
bool verify(const Pathname &file, const Pathname &signature)
Tries to verify file using signature, returns true on success.
Definition: KeyManager.cc:410
static KeyManagerCtx createForOpenPGP()
Creates a new KeyManagerCtx for PGP using a volatile temp.
Definition: KeyManager.cc:270
std::list< std::string > readSignatureFingerprints(const Pathname &signature)
Reads all fingerprints from the signature file , returns a list of all found fingerprints.
Definition: KeyManager.cc:570
Gpg key handling.
Definition: KeyRing.h:187
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id, const RepoInfo &info)
Try to find the id in key cache or repository specified in info.
Definition: KeyRing.cc:868
bool isKeyKnown(const std::string &id)
true if the key id is knows, that means at least exist on the untrusted keyring
Definition: KeyRing.cc:885
std::list< PublicKey > publicKeys()
Get a list of public keys in the keyring (incl.
Definition: KeyRing.cc:821
std::list< PublicKey > trustedPublicKeys()
Get a list of trusted public keys in the keyring (incl.
Definition: KeyRing.cc:824
static DefaultAccept defaultAccept()
Get the active accept bits.
Definition: KeyRing.cc:52
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition: KeyRing.cc:873
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
Verifies a file against a signature, with no user interaction.
Definition: KeyRing.cc:862
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Initial import from RpmDb.
Definition: KeyRing.cc:812
KeyRing(const Pathname &baseTmpDir)
Default ctor.
Definition: KeyRing.cc:798
~KeyRing()
Dtor.
Definition: KeyRing.cc:802
PublicKey exportPublicKey(const PublicKeyData &keyData)
Export a public key identified by its key data.
Definition: KeyRing.cc:876
std::string readSignatureKeyId(const Pathname &signature)
reads the public key id from a signature
Definition: KeyRing.cc:815
void allowPreload(bool yesno_r)
The general keyring may be populated with known keys stored on the system.
Definition: KeyRing.cc:805
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:865
void importKey(const PublicKey &key, bool trusted=false)
imports a key from a file.
Definition: KeyRing.cc:809
bool verifyFileSignatureWorkflow(const Pathname &file, const std::string &filedesc, const Pathname &signature, bool &sigValid_r, const KeyContext &keycontext=KeyContext())
Follows a signature verification interacting with the user.
Definition: KeyRing.cc:839
RW_pointer< Impl > _pimpl
Pointer to implementation.
Definition: KeyRing.h:366
void deleteKey(const std::string &id, bool trusted=false)
removes a key from the keyring.
Definition: KeyRing.cc:818
std::list< PublicKeyData > trustedPublicKeyData()
Get a list of trusted public key data in the keyring (key data only)
Definition: KeyRing.cc:830
static void setDefaultAccept(DefaultAccept value_r)
Set the active accept bits.
Definition: KeyRing.cc:55
std::list< PublicKeyData > publicKeyData()
Get a list of public key data in the keyring (key data only)
Definition: KeyRing.cc:827
@ TRUST_KEY_TEMPORARILY
Definition: KeyRing.h:207
@ ACCEPT_VERIFICATION_FAILED
Definition: KeyRing.h:209
@ ACCEPT_UNKNOWNKEY
Definition: KeyRing.h:206
@ ACCEPT_NOTHING
Definition: KeyRing.h:204
@ TRUST_AND_IMPORT_KEY
Definition: KeyRing.h:208
@ ACCEPT_UNSIGNED_FILE
Definition: KeyRing.h:205
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Export a trusted public key identified by its key data.
Definition: KeyRing.cc:879
bool isKeyTrusted(const std::string &id)
true if the key id is trusted
Definition: KeyRing.cc:882
Class representing one GPG Public Keys data.
Definition: PublicKey.h:207
Date created() const
Creation / last modification date (latest selfsig).
Definition: PublicKey.cc:429
static bool isSafeKeyId(const std::string &id_r)
Whether this is a long id (64bit/16byte) or even better a fingerprint.
Definition: PublicKey.h:302
std::string id() const
Key ID.
Definition: PublicKey.cc:417
std::string fingerprint() const
Key fingerprint.
Definition: PublicKey.cc:423
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition: PublicKey.h:359
Pathname path() const
File containing the ASCII armored key.
Definition: PublicKey.cc:645
const std::list< PublicKeyData > & hiddenKeys() const
Additional keys data in case the ASCII armored blob contains multiple keys.
Definition: PublicKey.cc:648
std::string name() const
Definition: PublicKey.cc:665
const PublicKeyData & keyData() const
The public keys data (.
Definition: PublicKey.cc:642
bool isValid() const
Definition: PublicKey.h:397
What is known about a repository.
Definition: RepoInfo.h:72
Pathname provideKey(const std::string &keyID_r, const Pathname &targetDirectory_r) const
downloads all configured gpg keys into the defined directory
Definition: RepoInfo.cc:535
Interim helper class to collect global options and settings.
Definition: ZConfig.h:64
Pathname repoManagerRoot() const
The RepoManager root directory.
Definition: ZConfig.cc:854
static ZConfig & instance()
Singleton ctor.
Definition: ZConfig.cc:823
Pathname pubkeyCachePath() const
Path where the pubkey caches.
Definition: ZConfig.cc:946
Typesafe passing of user data via callbacks.
Definition: UserData.h:39
bool hasvalue(const std::string &key_r) const
Whether key_r is in data and value is not empty.
Definition: UserData.h:101
bool set(const std::string &key_r, AnyType val_r)
Set the value for key (nonconst version always returns true).
Definition: UserData.h:118
const Tp & get(const std::string &key_r) const
Pass back a const Tp & reference to key_r value.
Definition: UserData.h:175
Wrapper class for ::stat/::lstat.
Definition: PathInfo.h:221
const std::string & asString() const
String representation.
Definition: Pathname.h:91
bool empty() const
Test for an empty path.
Definition: Pathname.h:114
const char * c_str() const
String representation.
Definition: Pathname.h:110
Provide a new empty temporary directory and recursively delete it when no longer needed.
Definition: TmpPath.h:178
Provide a new empty temporary file and delete it when no longer needed.
Definition: TmpPath.h:128
Pathname path() const
Definition: TmpPath.cc:146
I/O context for KeyRing::verifyFileSignatureWorkflow.
bool fileValidated() const
Whether the signature was actually successfully verified.
const KeyContext & keyContext() const
KeyContext passed to callbacks
std::string shortFile() const
Short name for file (default: basename).
const Pathname & file() const
File to verify.
const BuddyKeys & buddyKeys() const
bool signatureIdTrusted() const
Whether the SignatureId is in the trusted keyring (not temp.
const Pathname & signature() const
Detached signature or empty.
void resetResults()
Reset all result values to safe defaults.
const std::string & signatureId() const
The id of the gpg key which signed the file.
bool fileAccepted() const
May return true due to user interaction or global defaults even if the signature was not actually ver...
Regular expression.
Definition: Regex.h:95
Regular expression match result.
Definition: Regex.h:168
Definition: Arch.h:352
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26
int dirForEach(const Pathname &dir_r, const StrMatcher &matcher_r, function< bool(const Pathname &, const char *const)> fnc_r)
Definition: PathInfo.cc:32
bool regex_match(const std::string &s, smatch &matches, const regex &regex)
\relates regex \ingroup ZYPP_STR_REGEX \relates regex \ingroup ZYPP_STR_REGEX
Definition: Regex.h:70
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
IMPL_PTR_TYPE(Application)
static bool error(const std::string &msg_r, const UserData &userData_r=UserData())
send error text
void setRepoInfo(const RepoInfo &repoinfo)
Definition: KeyContext.h:19
virtual void infoVerify(const std::string &file_r, const PublicKeyData &keyData_r, const KeyContext &keycontext=KeyContext())
Informal callback showing the trusted key that will be used for verification.
Definition: KeyRing.cc:61
void reportNonImportedKeys(const std::set< Edition > &keys_r)
Notify the user about keys that were not imported from the rpm key database into zypp keyring.
Definition: KeyRing.cc:95
constexpr static const char * KEYS_NOT_IMPORTED_REPORT
generic reports UserData::type
Definition: KeyRing.h:130
KeyTrust
User reply options for the askUserToTrustKey callback.
Definition: KeyRing.h:52
@ KEY_TRUST_AND_IMPORT
Import the key.
Definition: KeyRing.h:70
@ KEY_DONT_TRUST
User has chosen not to trust the key.
Definition: KeyRing.h:56
@ KEY_TRUST_TEMPORARILY
This basically means, we knew the key, but it was not trusted.
Definition: KeyRing.h:61
virtual bool askUserToAcceptUnsignedFile(const std::string &file, const KeyContext &keycontext=KeyContext())
Definition: KeyRing.cc:64
bool askUserToAcceptPackageKey(const PublicKey &key_r, const KeyContext &keycontext_r=KeyContext())
Ask user to trust and/or import the package key to trusted keyring, using ReportBase::report.
Definition: KeyRing.cc:83
void reportAutoImportKey(const std::list< PublicKeyData > &keyDataList_r, const PublicKeyData &keySigning_r, const KeyContext &keyContext_r)
Notify that a repository auto imported new package signing keys.
Definition: KeyRing.cc:102
virtual KeyTrust askUserToAcceptKey(const PublicKey &key, const KeyContext &keycontext=KeyContext())
Ask user to trust and/or import the key to trusted keyring.
Definition: KeyRing.cc:68
virtual bool askUserToAcceptUnknownKey(const std::string &file, const std::string &id, const KeyContext &keycontext=KeyContext())
we DONT know the key, only its id, but we have never seen it, the difference with trust key is that i...
Definition: KeyRing.cc:77
constexpr static const char * REPORT_AUTO_IMPORT_KEY
generic reports UserData::type
Definition: KeyRing.h:149
constexpr static const char * ACCEPT_PACKAGE_KEY_REQUEST
generic reports UserData::type
Definition: KeyRing.h:117
virtual bool askUserToAcceptVerificationFailed(const std::string &file, const PublicKey &key, const KeyContext &keycontext=KeyContext())
The file filedesc is signed but the verification failed.
Definition: KeyRing.cc:80
KeyRing implementation.
Definition: KeyRing.cc:231
void importKey(const PublicKey &key, bool trusted=false)
Definition: KeyRing.cc:366
PublicKeyData trustedPublicKeyExists(const std::string &id)
Definition: KeyRing.cc:284
void preloadCachedKeys()
Load key files cached on the system into the generalKeyRing.
Definition: KeyRing.cc:442
bool provideAndImportKeyFromRepositoryWorkflow(const std::string &id_r, const RepoInfo &info_r)
Definition: KeyRing.cc:687
CachedPublicKeyData::Manip keyRingManip(const Pathname &keyring)
Impl helper providing on demand a KeyManagerCtx to manip a cached keyring.
Definition: KeyRing.cc:294
PublicKeyData publicKeyExists(const std::string &id)
Definition: KeyRing.cc:282
PublicKey exportKey(const std::string &id, const Pathname &keyring)
Definition: KeyRing.cc:501
PublicKey exportPublicKey(const PublicKeyData &keyData)
Definition: KeyRing.cc:264
bool verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
Definition: KeyRing.cc:269
const std::list< PublicKeyData > & trustedPublicKeyData()
Definition: KeyRing.cc:256
bool isKeyKnown(const std::string &id)
Definition: KeyRing.cc:248
bool verifyFileTrustedSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:279
void allowPreload(bool yesno_r)
Definition: KeyRing.cc:289
PublicKey exportTrustedPublicKey(const PublicKeyData &keyData)
Definition: KeyRing.cc:266
std::list< PublicKey > publicKeys()
Definition: KeyRing.cc:253
Impl(const Pathname &baseTmpDir)
Definition: KeyRing.cc:232
bool verifyFile(const Pathname &file, const Pathname &signature, const Pathname &keyring)
Definition: KeyRing.cc:785
const Pathname generalKeyRing() const
Definition: KeyRing.cc:319
filesystem::TmpDir _general_tmp_dir
Definition: KeyRing.cc:326
const std::list< PublicKeyData > & publicKeyData()
Definition: KeyRing.cc:258
bool verifyFileSignature(const Pathname &file, const Pathname &signature)
Definition: KeyRing.cc:277
std::list< PublicKey > trustedPublicKeys()
Definition: KeyRing.cc:251
CachedPublicKeyData cachedPublicKeyData
Functor returning the keyrings data (cached).
Definition: KeyRing.cc:336
std::string readSignatureKeyId(const Pathname &signature)
Definition: KeyRing.cc:769
const std::list< PublicKeyData > & publicKeyData(const Pathname &keyring)
Definition: KeyRing.cc:311
void multiKeyImport(const Pathname &keyfile_r, bool trusted_r=false)
Definition: KeyRing.cc:388
void deleteKey(const std::string &id, bool trusted)
Definition: KeyRing.cc:393
const Pathname trustedKeyRing() const
Definition: KeyRing.cc:321
bool _verifyFileSignatureWorkflow(keyring::VerifyFileContext &context_r)
Definition: KeyRing.cc:529
filesystem::TmpFile dumpPublicKeyToTmp(const std::string &id, const Pathname &keyring)
Definition: KeyRing.cc:518
PublicKey exportKey(const PublicKey &key, const Pathname &keyring)
Definition: KeyRing.cc:302
Pathname _base_dir
Definition: KeyRing.cc:327
filesystem::TmpDir _trusted_tmp_dir
Definition: KeyRing.cc:325
bool isKeyTrusted(const std::string &id)
Definition: KeyRing.cc:246
void dumpPublicKey(const std::string &id, bool trusted, std::ostream &stream)
Definition: KeyRing.cc:261
virtual void report(const UserData &userData_r=UserData())
The most generic way of sending/receiving data.
Definition: Callback.h:155
Convenient building of std::string with boost::format.
Definition: String.h:253
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:28
#define NON_COPYABLE_BUT_MOVE(CLASS)
Delete copy ctor and copy assign but enable default move.
Definition: Easy.h:79
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:436
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define _(MSG)
Definition: Gettext.h:37
#define DBG
Definition: Logger.h:95
#define MIL
Definition: Logger.h:96
#define ERR
Definition: Logger.h:98
#define WAR
Definition: Logger.h:97