libzypp 17.32.5
keyringwf.cc
Go to the documentation of this file.
1/*---------------------------------------------------------------------\
2| ____ _ __ __ ___ |
3| |__ / \ / / . \ . \ |
4| / / \ V /| _/ _/ |
5| / /__ | | | | | | |
6| /_____||_| |_| |_| |
7| |
8\---------------------------------------------------------------------*/
9
10#include "keyringwf.h"
11#include "logichelpers.h"
14#include <zypp/RepoInfo.h>
15#include <zypp/ZConfig.h>
16#include <zypp/Pathname.h>
17#include <zypp/PublicKey.h>
18
20#include <utility>
21#include <zypp-core/zyppng/pipelines/Expected>
23#include <zypp/ng/Context>
24#include <zypp/ng/UserRequest>
25
27
28 template <class Executor, class OpType>
29 struct ImportKeyFromRepoLogic : public LogicBase<Executor, OpType> {
30
33 using ProvideType = typename ZyppContextType::ProvideType;
34 using MediaHandle = typename ProvideType::MediaHandle;
35 using ProvideRes = typename ProvideType::Res;
36
38
39 public:
41 : _context( std::move(context) ), _keyId(std::move(keyId)), _repo( std::move(info) )
42 { }
43
45
46 using namespace zyppng::operators;
47 using zyppng::operators::operator|;
48 using zyppng::expected;
49
50 if ( _keyId.empty() || !_context )
51 return makeReadyResult(false);
52
53 const zypp::ZConfig &conf = _context->config();
54 zypp::Pathname cacheDir = conf.repoManagerRoot() / conf.pubkeyCachePath();
55
57 | [this, cacheDir]( zypp::Pathname myKey ) {
58 if ( myKey.empty() )
59 // if we did not find any keys, there is no point in checking again, break
60 return false;
61
63 try {
64 key = zypp::PublicKey( myKey );
65 } catch ( const zypp::Exception &e ) {
67 return false;
68 }
69
70 if ( !key.isValid() ) {
71 ERR << "Key [" << _keyId << "] from cache: " << cacheDir << " is not valid" << std::endl;
72 return false;
73 }
74
75 MIL << "Key [" << _keyId << "] " << key.name() << " loaded from cache" << std::endl;
76
78 context.setRepoInfo( _repo );
79 if ( ! executor()->askUserToAcceptPackageKey( key, context ) ) {
80 return false;
81 }
82
83 MIL << "User wants to import key [" << _keyId << "] " << key.name() << " from cache" << std::endl;
84 try {
85 _context->keyRing()->importKey( key, true );
86 } catch ( const zypp::KeyRingException &e ) {
88 ERR << "Failed to import key: "<<_keyId;
89 return false;
90 }
91 return true;
92 };
93 }
94
96 std::string _keyId;
98 };
99
100 struct AsyncImportKeyFromRepoExecutor : public ImportKeyFromRepoLogic< AsyncImportKeyFromRepoExecutor, zyppng::AsyncOp<bool> >
101 {
104 ERR << "Not implemented yet" << std::endl;
105 return false;
106 }
107 };
108
109
110 struct SyncImportKeyFromRepoExecutor : public ImportKeyFromRepoLogic< SyncImportKeyFromRepoExecutor, zyppng::SyncOp<bool> >
111 {
115 return report->askUserToAcceptPackageKey ( key_r, keycontext_r );
116 }
117 };
118
120 {
121 return SyncImportKeyFromRepoExecutor::run( ctx, std::move(id_r), std::move(info_r) );
122 }
123
128
129 namespace {
130
135 template <class Executor, class OpType>
136 struct VerifyFileSignatureLogic : public LogicBase<Executor, OpType>
137 {
139
140 using ZyppContextRefType = MaybeAsyncContextRef<OpType>;
141 using KeyTrust = zypp::KeyRingReport::KeyTrust;
142
143 VerifyFileSignatureLogic( ZyppContextRefType zyppContext, KeyRingRef &&keyRing, zypp::keyring::VerifyFileContext &&ctx )
144 : _zyppContext( std::move(zyppContext) )
145 , _keyRing( std::move(keyRing) )
146 , _verifyContext( std::move(ctx) )
147 { }
148
149 struct FoundKeyData {
152 bool trusted = false;
153 };
154
155 MaybeAsyncRef<FoundKeyData> findKey ( const std::string &id ) {
156
157 using zyppng::operators::operator|;
158
159 if ( id.empty() )
160 return makeReadyResult(FoundKeyData{zypp::PublicKeyData(), zypp::Pathname()});
161
162 // does key exists in trusted keyring
163 zypp::PublicKeyData trustedKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ) );
164 if ( trustedKeyData )
165 {
166 MIL << "Key is trusted: " << trustedKeyData << std::endl;
167
168 // lets look if there is an updated key in the
169 // general keyring
170 zypp::PublicKeyData generalKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().generalKeyRing() ) );
171 if ( generalKeyData )
172 {
173 // bnc #393160: Comment #30: Compare at least the fingerprint
174 // in case an attacker created a key the the same id.
175 //
176 // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
177 // to compare the subkey sets, to tell whether a key was updated.
178 // because created() remains unchanged if the primary key is not touched.
179 // For now we wait until a new subkey signs the data and treat it as a
180 // new key (else part below).
181 if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
182 && trustedKeyData.created() < generalKeyData.created() )
183 {
184 MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << std::endl;
185 _keyRing->importKey( _keyRing->pimpl().exportKey( generalKeyData, _keyRing->pimpl().generalKeyRing() ), true );
186 trustedKeyData = _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ); // re-read: invalidated by import?
187 }
188 }
189
190 return makeReadyResult( FoundKeyData{ trustedKeyData, _keyRing->pimpl().trustedKeyRing(), true } );
191 }
192 else
193 {
194 zypp::PublicKeyData generalKeyData( _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().generalKeyRing() ) );
195 if ( generalKeyData )
196 {
197 zypp::PublicKey key( _keyRing->pimpl().exportKey( generalKeyData, _keyRing->pimpl().generalKeyRing() ) );
198 MIL << "Key [" << id << "] " << key.name() << " is not trusted" << std::endl;
199
200 // ok the key is not trusted, ask the user to trust it or not
201 zypp::KeyRingReport::KeyTrust reply = executor()->askUserToAcceptKey( key, _verifyContext.keyContext() );
204 {
206
207 MIL << "User wants to trust key [" << id << "] " << key.name() << std::endl;
208
210 {
211 MIL << "User wants to import key [" << id << "] " << key.name() << std::endl;
212 _keyRing->importKey( key, true );
213 whichKeyring = _keyRing->pimpl().trustedKeyRing();
214 }
215 else
216 whichKeyring = _keyRing->pimpl().generalKeyRing();
217
218 return makeReadyResult(FoundKeyData { std::move(generalKeyData), std::move(whichKeyring), true });
219 }
220 else
221 {
222 MIL << "User does not want to trust key [" << id << "] " << key.name() << std::endl;
223 return makeReadyResult(FoundKeyData { std::move(generalKeyData), _keyRing->pimpl().generalKeyRing(), false });
224 }
225 }
226 else if ( ! _verifyContext.keyContext().empty() )
227 {
228 // try to find the key in the repository info
230 | [this, id]( bool success ) {
231 if ( !success ) {
232 return FoundKeyData{ zypp::PublicKeyData(), zypp::Pathname() };
233 }
234 return FoundKeyData{ _keyRing->pimpl().publicKeyExists( id, _keyRing->pimpl().trustedKeyRing() ), _keyRing->pimpl().trustedKeyRing(), true };
235 };
236 }
237 }
238 return makeReadyResult(FoundKeyData{ zypp::PublicKeyData(), zypp::Pathname() });
239 }
240
241 // returns std::pair<bool, zypp::keyring::VerifyFileContext>
242 auto execute () {
243
245 const zypp::Pathname & file { _verifyContext.file() };
246 const zypp::Pathname & signature { _verifyContext.signature() };
247 const std::string & filedesc { _verifyContext.shortFile() };
248
249 MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << std::endl;
250
251 // if signature does not exists, ask user if they want to accept unsigned file.
252 if( signature.empty() || (!zypp::PathInfo( signature ).isExist()) )
253 {
254 bool res = executor()->askUserToAcceptUnsignedFile( filedesc, _verifyContext.keyContext() );
255 MIL << "askUserToAcceptUnsignedFile: " << res << std::endl;
256 return makeReadyResult( makeReturn(res) );
257 }
258
259 // get the id of the signature (it might be a subkey id!)
260 _verifyContext.signatureId( _keyRing->readSignatureKeyId( signature ) ); //throws !
261 const std::string & id = _verifyContext.signatureId();
262
263 // collect the buddies
264 std::list<zypp::PublicKeyData> buddies; // Could be imported IFF the file is validated by a trusted key
265 for ( const auto & sid : _verifyContext.buddyKeys() ) {
267 WAR << "buddy " << sid << ": key id is too short to safely identify a gpg key. Skipping it." << std::endl;
268 continue;
269 }
270 if ( _keyRing->pimpl().trustedPublicKeyExists( sid ) ) {
271 MIL << "buddy " << sid << ": already in trusted key ring. Not needed." << std::endl;
272 continue;
273 }
274 auto pk = _keyRing->pimpl().publicKeyExists( sid );
275 if ( not pk ) {
276 WAR << "buddy " << sid << ": not available in the public key ring. Skipping it." << std::endl;
277 continue;
278 }
279 if ( pk.providesKey(id) ) {
280 MIL << "buddy " << sid << ": is the signing key. Handled separately." << std::endl;
281 continue;
282 }
283 MIL << "buddy " << sid << ": candidate for auto import. Remeber it." << std::endl;
284 buddies.push_back( pk );
285 }
286
287 using zyppng::operators::operator|;
288 return findKey( id ) | [this, id, buddies=std::move(buddies)]( FoundKeyData res ) {
289
290 const zypp::Pathname & file { _verifyContext.file() };
291 const zypp::KeyContext & keyContext { _verifyContext.keyContext() };
292 const zypp::Pathname & signature { _verifyContext.signature() };
293 const std::string & filedesc { _verifyContext.shortFile() };
294
295 if ( res._foundKey ) {
296
297 // we found a key but it is not trusted ( e.g. user did not want to trust it )
298 if ( !res.trusted )
299 return makeReturn(false);
300
301 // it exists, is trusted, does it validate?
302 _verifyContext.signatureIdTrusted( res._whichKeyRing == _keyRing->pimpl().trustedKeyRing() );
303 executor()->infoVerify( filedesc, res._foundKey, keyContext );
304 if ( _keyRing->pimpl().verifyFile( file, signature, res._whichKeyRing ) )
305 {
307 if ( _verifyContext.signatureIdTrusted() && not buddies.empty() ) {
308 // Check for buddy keys to be imported...
309 MIL << "Validated with trusted key: importing buddy list..." << std::endl;
310 executor()->reportAutoImportKey( buddies, res._foundKey, keyContext );
311 for ( const auto & kd : buddies ) {
312 _keyRing->importKey( _keyRing->pimpl().exportKey( kd, _keyRing->pimpl().generalKeyRing() ), true );
313 }
314 }
315 return makeReturn(_verifyContext.fileValidated()); // signature is actually successfully validated!
316 }
317 else
318 {
319 bool userAnswer = executor()->askUserToAcceptVerificationFailed( filedesc, _keyRing->pimpl().exportKey( res._foundKey, res._whichKeyRing ), keyContext );
320 MIL << "askUserToAcceptVerificationFailed: " << userAnswer << std::endl;
321 return makeReturn(userAnswer);
322 }
323 } else {
324 // signed with an unknown key...
325 MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
326 bool res = executor()->askUserToAcceptUnknownKey( filedesc, id, _verifyContext.keyContext() );
327 MIL << "askUserToAcceptUnknownKey: " << res << std::endl;
328 return makeReturn(res);
329 }
330
331 return makeReturn(false);
332 };
333 }
334
335 protected:
336 ZyppContextRefType _zyppContext;
339
340 private:
341 inline std::pair<bool, zypp::keyring::VerifyFileContext> makeReturn( bool res ){
343 return std::make_pair( res, std::move(_verifyContext) ) ;
344 }
345 };
346
347 struct AsyncVerifyFileSignatureExecutor : public VerifyFileSignatureLogic<AsyncVerifyFileSignatureExecutor, AsyncOp<std::pair<bool,zypp::keyring::VerifyFileContext>>>
348 {
349
350 using VerifyFileSignatureLogic::VerifyFileSignatureLogic;
351
352 bool askUserToAcceptUnsignedFile( const std::string &file, const zypp::KeyContext &keycontext = {} ) {
353
354 std::string label;
355 if (keycontext.empty())
356 label = zypp::str::Format(
357 // TranslatorExplanation: speaking of a file
358 _("File '%s' is unsigned, continue?")) % file;
359 else
360 label = zypp::str::Format(
361 // TranslatorExplanation: speaking of a file
362 _("File '%s' from repository '%s' is unsigned, continue?"))
363 % file % keycontext.repoInfo().asUserString();
364
365
366 auto req = BooleanChoiceRequest::create ( label, false, AcceptUnsignedFileRequest::makeData ( file, keycontext ) );
367 _zyppContext->sendUserRequest ( req );
368 return req->choice ();
369 }
370
371 KeyTrust askUserToAcceptKey( const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ) {
372
373 auto req = TrustKeyRequest::create(
374 _("Do you want to reject the key, trust temporarily, or trust always?"),
377 );
378 _zyppContext->sendUserRequest ( req );
379 return static_cast<KeyTrust>(req->choice());
380 }
381
382 void infoVerify( const std::string & file_r, const zypp::PublicKeyData & keyData_r, const zypp::KeyContext &keycontext = {} ) {
383 std::string label = zypp::str::Format( _("Key Name: %1%")) % keyData_r.name();
384 auto req = ShowMessageRequest::create( label, ShowMessageRequest::MType::Info, VerifyInfoEvent::makeData ( file_r, keyData_r, keycontext) );
385 _zyppContext->sendUserRequest ( req );
386 }
387
388 void reportAutoImportKey( const std::list<zypp::PublicKeyData> & keyDataList_r, const zypp::PublicKeyData & keySigning_r, const zypp::KeyContext &keyContext_r ) {
389 const std::string &lbl = zypp::str::Format( PL_( "Received %1% new package signing key from repository \"%2%\":",
390 "Received %1% new package signing keys from repository \"%2%\":",
391 keyDataList_r.size() )) % keyDataList_r.size() % keyContext_r.repoInfo().asUserString();
393 }
394
395 bool askUserToAcceptVerificationFailed( const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} )
396 {
397 std::string label;
398 if ( keycontext.empty() )
399 // translator: %1% is a file name
400 label = zypp::str::Format(_("Signature verification failed for file '%1%'.") ) % file;
401 else
402 // translator: %1% is a file name, %2% a repositories na me
403 label = zypp::str::Format(_("Signature verification failed for file '%1%' from repository '%2%'.") ) % file % keycontext.repoInfo().asUserString();
404
405 // @TODO use a centralized Continue string!
406 label += std::string(" ") + _("Continue?");
407 auto req = BooleanChoiceRequest::create ( label, false, AcceptFailedVerificationRequest::makeData ( file, key, keycontext ) );
408 _zyppContext->sendUserRequest ( req );
409 return req->choice ();
410 }
411
412 bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const zypp::KeyContext &keycontext = {} )
413 {
414 std::string label;
415
416 if (keycontext.empty())
417 label = zypp::str::Format(
418 // translators: the last %s is gpg key ID
419 _("File '%s' is signed with an unknown key '%s'. Continue?")) % file % id;
420 else
421 label = zypp::str::Format(
422 // translators: the last %s is gpg key ID
423 _("File '%s' from repository '%s' is signed with an unknown key '%s'. Continue?"))
424 % file % keycontext.repoInfo().asUserString() % id;
425
426 auto req = BooleanChoiceRequest::create ( label, false, AcceptUnknownKeyRequest::makeData ( file, id, keycontext ) );
427 _zyppContext->sendUserRequest ( req );
428 return req->choice ();
429 }
430 };
431
432 struct SyncVerifyFileSignatureExecutor : public VerifyFileSignatureLogic<SyncVerifyFileSignatureExecutor, SyncOp<std::pair<bool,zypp::keyring::VerifyFileContext>>>
433 {
434
435 using VerifyFileSignatureLogic::VerifyFileSignatureLogic;
436
437 bool askUserToAcceptUnsignedFile( const std::string &file, const zypp::KeyContext &keycontext = {} ) {
438 return _report->askUserToAcceptUnsignedFile( file, keycontext );
439 }
440 KeyTrust askUserToAcceptKey( const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ) {
441 return _report->askUserToAcceptKey( key, keycontext );
442 }
443 void infoVerify( const std::string & file_r, const zypp::PublicKeyData & keyData_r, const zypp::KeyContext &keycontext = {} ) {
444 return _report->infoVerify( file_r, keyData_r, keycontext );
445 }
446 void reportAutoImportKey( const std::list<zypp::PublicKeyData> & keyDataList_r, const zypp::PublicKeyData & keySigning_r, const zypp::KeyContext &keyContext_r ) {
447 return _report->reportAutoImportKey( keyDataList_r, keySigning_r, keyContext_r );
448 }
449 bool askUserToAcceptVerificationFailed( const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext = {} ) {
450 return _report->askUserToAcceptVerificationFailed( file, key, keycontext );
451 }
452 bool askUserToAcceptUnknownKey( const std::string &file, const std::string &id, const zypp::KeyContext &keycontext = {} ) {
453 return _report->askUserToAcceptUnknownKey( file, id, keycontext );
454 }
455
456 private:
458 };
459 }
460
461 std::pair<bool,zypp::keyring::VerifyFileContext> verifyFileSignature( SyncContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r )
462 {
463 auto kr = zyppContext->keyRing();
464 return SyncVerifyFileSignatureExecutor::run( std::move(zyppContext), std::move(kr), std::move(context_r) );
465 }
466
468 {
469 auto kr = zyppContext->keyRing();
470 return AsyncVerifyFileSignatureExecutor::run( std::move(zyppContext), std::move(kr), std::move(context_r) );
471 }
472
473 std::pair<bool,zypp::keyring::VerifyFileContext> verifyFileSignature( SyncContextRef zyppContext, zypp::KeyRing_Ptr keyRing, zypp::keyring::VerifyFileContext &&context_r )
474 {
475 return SyncVerifyFileSignatureExecutor::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) );
476 }
477
479 {
480 return AsyncVerifyFileSignatureExecutor::run( std::move(zyppContext), std::move(keyRing), std::move(context_r) );
481 }
482
483}
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
Base class for Exception.
Definition Exception.h:147
Class representing one GPG Public Keys data.
Definition PublicKey.h:208
static bool isSafeKeyId(const std::string &id_r)
Whether this is a long id (64bit/16byte) or even better a fingerprint.
Definition PublicKey.h:308
Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
Definition PublicKey.h:365
std::string name() const
Definition PublicKey.cc:666
bool isValid() const
Definition PublicKey.h:403
What is known about a repository.
Definition RepoInfo.h:72
Interim helper class to collect global options and settings.
Definition ZConfig.h:64
Wrapper class for stat/lstat.
Definition PathInfo.h:222
bool isExist() const
Return whether valid stat info exists.
Definition PathInfo.h:282
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.
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...
@ KEY_DONT_TRUST
User has chosen not to trust the key.
Definition userrequest.h:83
bool trusted
Definition keyringwf.cc:152
zypp::keyring::VerifyFileContext _verifyContext
Definition keyringwf.cc:338
zypp::Pathname _whichKeyRing
Definition keyringwf.cc:151
zypp::PublicKeyData _foundKey
Definition keyringwf.cc:150
zypp::callback::SendReport< zypp::KeyRingReport > _report
Definition keyringwf.cc:457
KeyRingRef _keyRing
Definition keyringwf.cc:337
#define ZYPP_ENABLE_LOGIC_BASE(Executor, OpType)
Definition Arch.h:364
UserData makeData(const std::string &file, const zypp::PublicKey &key, const zypp::KeyContext &keycontext=zypp::KeyContext())
UserData makeData(const zypp::PublicKey &key, const zypp::KeyContext &keycontext=zypp::KeyContext())
UserData makeData(const std::string &file, const std::string &id, const zypp::KeyContext &keycontext=zypp::KeyContext())
UserData makeData(const std::string &file, const zypp::KeyContext &keycontext=zypp::KeyContext())
UserData makeData(const std::list< zypp::PublicKeyData > &keyDataList_r, const zypp::PublicKeyData &keySigning_r, const zypp::KeyContext &keyContext_r)
bool provideAndImportKeyFromRepository(SyncContextRef ctx, std::string id_r, zypp::RepoInfo info_r)
Try to find the id in key cache or repository specified in info.
Definition keyringwf.cc:119
std::pair< bool, zypp::keyring::VerifyFileContext > verifyFileSignature(SyncContextRef zyppContext, zypp::keyring::VerifyFileContext &&context_r)
Follows a signature verification interacting with the user.
Definition keyringwf.cc:461
zypp::Pathname provideKey(SyncContextRef ctx, zypp::RepoInfo info, std::string keyID_r, zypp::Pathname targetDirectory_r)
UserData makeData(const std::string &file_r, const zypp::PublicKeyData &keyData_r, const zypp::KeyContext &keycontext=zypp::KeyContext())
std::conditional_t< isAsync, AsyncOpRef< T >, T > makeReadyResult(T &&result)
Definition asyncop.h:297
zypp::KeyRing_Ptr KeyRingRef
Definition context.h:29
ZyppContextRefType _zyppContext
const RepoInfo repoInfo() const
Definition KeyContext.h:18
bool empty() const
Is the context unknown?
Definition KeyContext.h:15
KeyTrust
User reply options for the askUserToTrustKey callback.
Definition KeyRing.h:52
@ KEY_TRUST_AND_IMPORT
Import the key.
Definition KeyRing.h:70
@ KEY_TRUST_TEMPORARILY
This basically means, we knew the key, but it was not trusted.
Definition KeyRing.h:61
Convenient building of std::string with boost::format.
Definition String.h:253
bool askUserToAcceptPackageKey(const zypp::PublicKey &key_r, const zypp::KeyContext &keycontext_r=zypp::KeyContext())
Definition keyringwf.cc:103
ImportKeyFromRepoLogic(ZyppContextRefType context, std::string &&keyId, zypp::RepoInfo &&info)
Definition keyringwf.cc:40
typename ProvideType::MediaHandle MediaHandle
Definition keyringwf.cc:34
MaybeAsyncContextRef< OpType > ZyppContextRefType
Definition keyringwf.cc:31
typename ZyppContextType::ProvideType ProvideType
Definition keyringwf.cc:33
bool askUserToAcceptPackageKey(const zypp::PublicKey &key_r, const zypp::KeyContext &keycontext_r=zypp::KeyContext())
Definition keyringwf.cc:113
Executor * executor()
static std::enable_if_t< detail::is_async_op_v< FOpType >, AsyncOpRef< Result > > run(Args &&...args)
auto makeReadyResult(T &&res)
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition Exception.h:437
#define PL_(MSG1, MSG2, N)
Definition Gettext.h:40
#define _(MSG)
Definition Gettext.h:37
#define MIL
Definition Logger.h:96
#define ERR
Definition Logger.h:98
#define WAR
Definition Logger.h:97