709224c73c154108a6c1adb8bedfaa6dec1c4b63
[platform/upstream/libzypp.git] / zypp / KeyRing.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/KeyRing.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sys/file.h>
15 #include <cstdio>
16 #include <unistd.h>
17
18 #include "zypp/TmpPath.h"
19 #include "zypp/ZYppFactory.h"
20 #include "zypp/ZYpp.h"
21
22 #include "zypp/base/LogTools.h"
23 #include "zypp/base/IOStream.h"
24 #include "zypp/base/String.h"
25 #include "zypp/base/Regex.h"
26 #include "zypp/base/Gettext.h"
27 #include "zypp/base/WatchFile.h"
28 #include "zypp/PathInfo.h"
29 #include "zypp/KeyRing.h"
30 #include "zypp/ExternalProgram.h"
31 #include "zypp/TmpPath.h"
32
33 using std::endl;
34
35 #undef  ZYPP_BASE_LOGGER_LOGGROUP
36 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
37
38 /** \todo Fix duplicate define in PublicKey/KeyRing */
39 #define GPG_BINARY "/usr/bin/gpg2"
40
41 ///////////////////////////////////////////////////////////////////
42 namespace zypp
43 { /////////////////////////////////////////////////////////////////
44
45   IMPL_PTR_TYPE(KeyRing);
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
67   KeyRingReport::KeyTrust
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   namespace
84   {
85     ///////////////////////////////////////////////////////////////////
86     /// \class CachedPublicKeyData
87     /// \brief Functor returning the keyrings data (cached).
88     /// \code
89     ///   const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
90     /// \endcode
91     ///////////////////////////////////////////////////////////////////
92     struct CachedPublicKeyData // : private base::NonCopyable - but KeyRing uses RWCOW though also NonCopyable :(
93     {
94       const std::list<PublicKeyData> & operator()( const Pathname & keyring_r ) const
95       { return getData( keyring_r ); }
96
97     private:
98       struct Cache
99       {
100         // Empty copy ctor to allow insert into std::map as
101         // scoped_ptr is noncopyable.
102         Cache() {}
103         Cache( const Cache & rhs ) {}
104
105         void assertCache( const Pathname & keyring_r )
106         {
107           // .kbx since gpg2-2.1
108           if ( !_keyringK )
109             _keyringK.reset( new WatchFile( keyring_r/"pubring.kbx", WatchFile::NO_INIT ) );
110           if ( !_keyringP )
111             _keyringP.reset( new WatchFile( keyring_r/"pubring.gpg", WatchFile::NO_INIT ) );
112         }
113
114         bool hasChanged() const
115         {
116           bool k = _keyringK->hasChanged();     // be sure both files are checked
117           bool p = _keyringP->hasChanged();
118           return k || p;
119         }
120
121         std::list<PublicKeyData> _data;
122
123       private:
124         scoped_ptr<WatchFile> _keyringK;
125         scoped_ptr<WatchFile> _keyringP;
126       };
127
128       typedef std::map<Pathname,Cache> CacheMap;
129
130       const std::list<PublicKeyData> & getData( const Pathname & keyring_r ) const
131       {
132         Cache & cache( _cacheMap[keyring_r] );
133         // init new cache entry
134         cache.assertCache( keyring_r );
135         return getData( keyring_r, cache );
136       }
137
138       const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
139       {
140         if ( cache_r.hasChanged() )
141         {
142           const char* argv[] =
143           {
144             GPG_BINARY,
145             "--list-public-keys",
146             "--homedir", keyring_r.c_str(),
147             "--no-default-keyring",
148             "--quiet",
149             "--with-colons",
150             "--fixed-list-mode",
151             "--with-fingerprint",
152             "--with-sig-list",
153             "--no-tty",
154             "--no-greeting",
155             "--batch",
156             "--status-fd", "1",
157             NULL
158           };
159
160           PublicKeyScanner scanner;
161           ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
162           for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
163           {
164             scanner.scan( line );
165           }
166           prog.close();
167
168           cache_r._data.swap( scanner._keys );
169           MIL << "Found keys: " << cache_r._data  << endl;
170         }
171         return cache_r._data;
172       }
173
174       mutable CacheMap _cacheMap;
175     };
176     ///////////////////////////////////////////////////////////////////
177   }
178
179   ///////////////////////////////////////////////////////////////////
180   //
181   //    CLASS NAME : KeyRing::Impl
182   //
183   /** KeyRing implementation. */
184   struct KeyRing::Impl
185   {
186     Impl( const Pathname & baseTmpDir )
187     : _trusted_tmp_dir( baseTmpDir, "zypp-trusted-kr" )
188     , _general_tmp_dir( baseTmpDir, "zypp-general-kr" )
189     , _base_dir( baseTmpDir )
190     {
191       MIL << "Current KeyRing::DefaultAccept: " << _keyRingDefaultAccept << endl;
192     }
193
194     void importKey( const PublicKey & key, bool trusted = false );
195     void multiKeyImport( const Pathname & keyfile_r, bool trusted_r = false );
196     void deleteKey( const std::string & id, bool trusted );
197
198     std::string readSignatureKeyId( const Pathname & signature );
199
200     bool isKeyTrusted( const std::string & id )
201     { return bool(publicKeyExists( id, trustedKeyRing() )); }
202     bool isKeyKnown( const std::string & id )
203     { return publicKeyExists( id, trustedKeyRing() ) || publicKeyExists( id, generalKeyRing() ); }
204
205     std::list<PublicKey> trustedPublicKeys()
206     { return publicKeys( trustedKeyRing() ); }
207     std::list<PublicKey> publicKeys()
208     { return publicKeys( generalKeyRing() ); }
209
210     const std::list<PublicKeyData> & trustedPublicKeyData()
211     { return publicKeyData( trustedKeyRing() ); }
212     const std::list<PublicKeyData> & publicKeyData()
213     { return publicKeyData( generalKeyRing() ); }
214
215     void dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
216     { dumpPublicKey( id, ( trusted ? trustedKeyRing() : generalKeyRing() ), stream ); }
217
218     PublicKey exportPublicKey( const PublicKeyData & keyData )
219     { return exportKey( keyData, generalKeyRing() ); }
220     PublicKey exportTrustedPublicKey( const PublicKeyData & keyData )
221     { return exportKey( keyData, trustedKeyRing() ); }
222
223     bool verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext = KeyContext());
224
225     bool verifyFileSignature( const Pathname & file, const Pathname & signature )
226     { return verifyFile( file, signature, generalKeyRing() ); }
227     bool verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
228     { return verifyFile( file, signature, trustedKeyRing() ); }
229
230   private:
231     bool verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring );
232     void importKey( const Pathname & keyfile, const Pathname & keyring );
233
234     PublicKey exportKey( const std::string & id, const Pathname & keyring );
235     PublicKey exportKey( const PublicKeyData & keyData, const Pathname & keyring );
236
237     void dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream );
238     filesystem::TmpFile dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring );
239
240     void deleteKey( const std::string & id, const Pathname & keyring );
241
242     std::list<PublicKey> publicKeys( const Pathname & keyring);
243     const std::list<PublicKeyData> & publicKeyData( const Pathname & keyring )
244     { return cachedPublicKeyData( keyring ); }
245
246     /** Get \ref PublicKeyData for ID (\c false if ID is not found). */
247     PublicKeyData publicKeyExists( const std::string & id, const Pathname & keyring );
248
249     const Pathname generalKeyRing() const
250     { return _general_tmp_dir.path(); }
251     const Pathname trustedKeyRing() const
252     { return _trusted_tmp_dir.path(); }
253
254     // Used for trusted and untrusted keyrings
255     filesystem::TmpDir _trusted_tmp_dir;
256     filesystem::TmpDir _general_tmp_dir;
257     Pathname _base_dir;
258
259   private:
260     /** Functor returning the keyrings data (cached).
261      * \code
262      *  const std::list<PublicKeyData> & cachedPublicKeyData( const Pathname & keyring );
263      * \endcode
264      */
265     CachedPublicKeyData cachedPublicKeyData;
266   };
267   ///////////////////////////////////////////////////////////////////
268
269
270   void KeyRing::Impl::importKey( const PublicKey & key, bool trusted )
271   {
272     importKey( key.path(), trusted ? trustedKeyRing() : generalKeyRing() );
273
274     if ( trusted )
275     {
276       callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
277       callback::SendReport<KeyRingSignals> emitSignal;
278
279       rpmdbEmitSignal->trustedKeyAdded( key );
280       emitSignal->trustedKeyAdded( key );
281     }
282   }
283
284   void KeyRing::Impl::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
285   {
286     importKey( keyfile_r, trusted_r ? trustedKeyRing() : generalKeyRing() );
287   }
288
289   void KeyRing::Impl::deleteKey( const std::string & id, bool trusted )
290   {
291     PublicKey key;
292
293     if ( trusted )
294     {
295         key = exportKey( id, trustedKeyRing() );
296     }
297
298     deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
299
300     if ( trusted )
301     {
302       callback::SendReport<target::rpm::KeyRingSignals> rpmdbEmitSignal;
303       callback::SendReport<KeyRingSignals> emitSignal;
304
305       rpmdbEmitSignal->trustedKeyRemoved( key );
306       emitSignal->trustedKeyRemoved( key );
307     }
308   }
309
310   PublicKeyData KeyRing::Impl::publicKeyExists( const std::string & id, const Pathname & keyring )
311   {
312     MIL << "Searching key [" << id << "] in keyring " << keyring << endl;
313     PublicKeyData ret;
314     for ( const PublicKeyData & key : publicKeyData( keyring ) )
315     {
316       if ( key.providesKey( id ) )
317       {
318         ret = key;
319         break;
320       }
321     }
322     return ret;
323   }
324
325   PublicKey KeyRing::Impl::exportKey( const PublicKeyData & keyData, const Pathname & keyring )
326   {
327     return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
328   }
329
330   PublicKey KeyRing::Impl::exportKey( const std::string & id, const Pathname & keyring )
331   {
332     PublicKeyData keyData( publicKeyExists( id, keyring ) );
333     if ( keyData )
334       return PublicKey( dumpPublicKeyToTmp( keyData.id(), keyring ), keyData );
335
336     // Here: key not found
337     WAR << "No key " << id << " to export from " << keyring << endl;
338     return PublicKey();
339   }
340
341
342   void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
343   {
344     const char* argv[] =
345     {
346       GPG_BINARY,
347       "-a",
348       "--export",
349       "--homedir", keyring.asString().c_str(),
350       "--no-default-keyring",
351       "--quiet",
352       "--no-tty",
353       "--no-greeting",
354       "--no-permission-warning",
355       "--batch",
356       id.c_str(),
357       NULL
358     };
359     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
360     for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
361     {
362       stream << line;
363     }
364     prog.close();
365   }
366
367   filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
368   {
369     filesystem::TmpFile tmpFile( _base_dir, "pubkey-"+id+"-" );
370     MIL << "Going to export key " << id << " from " << keyring << " to " << tmpFile.path() << endl;
371
372     std::ofstream os( tmpFile.path().c_str() );
373     dumpPublicKey( id, keyring, os );
374     os.close();
375     return tmpFile;
376   }
377
378   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & context )
379   {
380     sigValid_r = false; // set true if signature is actually successfully validated!
381
382     callback::SendReport<KeyRingReport> report;
383     MIL << "Going to verify signature for " << filedesc << " ( " << file << " ) with " << signature << endl;
384
385     // if signature does not exists, ask user if he wants to accept unsigned file.
386     if( signature.empty() || (!PathInfo( signature ).isExist()) )
387     {
388       bool res = report->askUserToAcceptUnsignedFile( filedesc, context );
389       MIL << "askUserToAcceptUnsignedFile: " << res << endl;
390       return res;
391     }
392
393     // get the id of the signature (it might be a subkey id!)
394     std::string id = readSignatureKeyId( signature );
395
396     // does key exists in trusted keyring
397     PublicKeyData trustedKeyData( publicKeyExists( id, trustedKeyRing() ) );
398     if ( trustedKeyData )
399     {
400       MIL << "Key is trusted: " << trustedKeyData << endl;
401
402       // lets look if there is an updated key in the
403       // general keyring
404       PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
405       if ( generalKeyData )
406       {
407         // bnc #393160: Comment #30: Compare at least the fingerprint
408         // in case an attacker created a key the the same id.
409         //
410         // FIXME: bsc#1008325: For keys using subkeys, we'd actually need
411         // to compare the subkey sets, to tell whether a key was updated.
412         // because created() remains unchanged if the primary key is not touched.
413         // For now we wait until a new subkey signs the data and treat it as a
414         //  new key (else part below).
415         if ( trustedKeyData.fingerprint() == generalKeyData.fingerprint()
416            && trustedKeyData.created() < generalKeyData.created() )
417         {
418           MIL << "Key was updated. Saving new version into trusted keyring: " << generalKeyData << endl;
419           importKey( exportKey( generalKeyData, generalKeyRing() ), true );
420           trustedKeyData = publicKeyExists( id, trustedKeyRing() ); // re-read: invalidated by import?
421         }
422       }
423
424       // it exists, is trusted, does it validate?
425       report->infoVerify( filedesc, trustedKeyData, context );
426       if ( verifyFile( file, signature, trustedKeyRing() ) )
427       {
428         return (sigValid_r=true);       // signature is actually successfully validated!
429       }
430       else
431       {
432         bool res = report->askUserToAcceptVerificationFailed( filedesc, exportKey( trustedKeyData, trustedKeyRing() ), context );
433         MIL << "askUserToAcceptVerificationFailed: " << res << endl;
434         return res;
435       }
436     }
437     else
438     {
439       PublicKeyData generalKeyData( publicKeyExists( id, generalKeyRing() ) );
440       if ( generalKeyData )
441       {
442         PublicKey key( exportKey( generalKeyData, generalKeyRing() ) );
443         MIL << "Exported key " << id << " to " << key.path() << endl;
444         MIL << "Key " << id << " " << key.name() << " is not trusted" << endl;
445
446         // ok the key is not trusted, ask the user to trust it or not
447         KeyRingReport::KeyTrust reply = report->askUserToAcceptKey( key, context );
448         if ( reply == KeyRingReport::KEY_TRUST_TEMPORARILY ||
449             reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
450         {
451           MIL << "User wants to trust key " << id << " " << key.name() << endl;
452
453           Pathname whichKeyring;
454           if ( reply == KeyRingReport::KEY_TRUST_AND_IMPORT )
455           {
456             MIL << "User wants to import key " << id << " " << key.name() << endl;
457             importKey( key, true );
458             whichKeyring = trustedKeyRing();
459           }
460           else
461             whichKeyring = generalKeyRing();
462
463           // does it validate?
464           report->infoVerify( filedesc, generalKeyData, context );
465           if ( verifyFile( file, signature, whichKeyring ) )
466           {
467             return (sigValid_r=true);   // signature is actually successfully validated!
468           }
469           else
470           {
471             bool res = report->askUserToAcceptVerificationFailed( filedesc, key, context );
472             MIL << "askUserToAcceptVerificationFailed: " << res << endl;
473             return res;
474           }
475         }
476         else
477         {
478           MIL << "User does not want to trust key " << id << " " << key.name() << endl;
479           return false;
480         }
481       }
482       else
483       {
484         // signed with an unknown key...
485         MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << endl;
486         bool res = report->askUserToAcceptUnknownKey( filedesc, id, context );
487         MIL << "askUserToAcceptUnknownKey: " << res << endl;
488         return res;
489       }
490     }
491     return false;
492   }
493
494   std::list<PublicKey> KeyRing::Impl::publicKeys( const Pathname & keyring )
495   {
496     const std::list<PublicKeyData> & keys( publicKeyData( keyring ) );
497     std::list<PublicKey> ret;
498
499     for_( it, keys.begin(), keys.end() )
500     {
501       PublicKey key( exportKey( *it, keyring ) );
502       ret.push_back( key );
503       MIL << "Found key " << key << endl;
504     }
505     return ret;
506   }
507
508   void KeyRing::Impl::importKey( const Pathname & keyfile, const Pathname & keyring )
509   {
510     if ( ! PathInfo( keyfile ).isExist() )
511       // TranslatorExplanation first %s is key name, second is keyring name
512       ZYPP_THROW(KeyRingException( str::Format(_("Tried to import not existent key %s into keyring %s"))
513                                    % keyfile.asString()
514                                    % keyring.asString() ));
515
516     const char* argv[] =
517     {
518       GPG_BINARY,
519       "--import",
520       "--homedir", keyring.asString().c_str(),
521       "--no-default-keyring",
522       "--quiet",
523       "--no-tty",
524       "--no-greeting",
525       "--no-permission-warning",
526       "--status-fd", "1",
527       keyfile.asString().c_str(),
528       NULL
529     };
530
531     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
532     prog.close();
533   }
534
535   void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
536   {
537     const char* argv[] =
538     {
539       GPG_BINARY,
540       "--delete-keys",
541       "--homedir", keyring.asString().c_str(),
542       "--no-default-keyring",
543       "--yes",
544       "--quiet",
545       "--no-tty",
546       "--batch",
547       "--status-fd", "1",
548       id.c_str(),
549       NULL
550     };
551
552     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
553
554     int code = prog.close();
555     if ( code )
556       ZYPP_THROW(Exception(_("Failed to delete key.")));
557     else
558       MIL << "Deleted key " << id << " from keyring " << keyring << endl;
559   }
560
561   std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
562   {
563     if ( ! PathInfo( signature ).isFile() )
564       ZYPP_THROW(Exception( str::Format(_("Signature file %s not found")) % signature.asString() ));
565
566     MIL << "Determining key id of signature " << signature << endl;
567     const char* argv[] =
568     {
569       GPG_BINARY,
570       "--list-packets",
571       signature.asString().c_str(),
572       NULL
573     };
574     ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
575
576     // :signature packet: algo 1, keyid 1397BC53640DB551
577     //         version 4, created 1501094968, md5len 0, sigclass 0x00
578     //         digest algo 8, begin of digest 15 89
579     //         hashed subpkt 2 len 4 (sig created 2017-07-26)
580     //         subpkt 16 len 8 (issuer key ID 1397BC53640DB551)
581     //         data: [4095 bits]
582     std::string id;
583     for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
584     {
585       if ( id.empty() && str::startsWith( line, ":signature packet:" ) )
586       {
587         static const str::regex rxKeyId( " keyid +([0-9A-Z]+)" );
588         str::smatch what;
589         if( str::regex_match( line, what, rxKeyId ) )
590           id = what[1];
591       }
592     }
593
594     MIL << "Determined key id [" << id << "] for signature " << signature << endl;
595     prog.close();
596     return id;
597   }
598
599   bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
600   {
601     const char* argv[] =
602     {
603       GPG_BINARY,
604       "--verify",
605       "--homedir", keyring.asString().c_str(),
606       "--no-default-keyring",
607       "--quiet",
608       "--no-tty",
609       "--batch",
610       "--no-greeting",
611       "--status-fd", "1",
612       signature.asString().c_str(),
613       file.asString().c_str(),
614       NULL
615     };
616
617     // no need to parse output for now
618     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
619     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
620     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
621     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
622     //     [GNUPG:] TRUST_UNDEFINED
623
624     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
625     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
626
627     ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
628
629     return ( prog.close() == 0 ) ? true : false;
630   }
631
632   ///////////////////////////////////////////////////////////////////
633
634   ///////////////////////////////////////////////////////////////////
635   //
636   //    CLASS NAME : KeyRing
637   //
638   ///////////////////////////////////////////////////////////////////
639
640   KeyRing::KeyRing( const Pathname & baseTmpDir )
641   : _pimpl( new Impl( baseTmpDir ) )
642   {}
643
644   KeyRing::~KeyRing()
645   {}
646
647
648   void KeyRing::importKey( const PublicKey & key, bool trusted )
649   { _pimpl->importKey( key, trusted ); }
650
651   void KeyRing::multiKeyImport( const Pathname & keyfile_r, bool trusted_r )
652   { _pimpl->multiKeyImport( keyfile_r, trusted_r ); }
653
654   std::string KeyRing::readSignatureKeyId( const Pathname & signature )
655   { return _pimpl->readSignatureKeyId( signature ); }
656
657   void KeyRing::deleteKey( const std::string & id, bool trusted )
658   { _pimpl->deleteKey( id, trusted ); }
659
660   std::list<PublicKey> KeyRing::publicKeys()
661   { return _pimpl->publicKeys(); }
662
663   std:: list<PublicKey> KeyRing::trustedPublicKeys()
664   { return _pimpl->trustedPublicKeys(); }
665
666   std::list<PublicKeyData> KeyRing::publicKeyData()
667   { return _pimpl->publicKeyData(); }
668
669   std::list<PublicKeyData> KeyRing::trustedPublicKeyData()
670   { return _pimpl->trustedPublicKeyData(); }
671
672   bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string & filedesc, const Pathname & signature, bool & sigValid_r, const KeyContext & keycontext )
673   { return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, sigValid_r, keycontext ); }
674
675   bool KeyRing::verifyFileSignatureWorkflow( const Pathname & file, const std::string filedesc, const Pathname & signature, const KeyContext & keycontext )
676   { bool unused; return _pimpl->verifyFileSignatureWorkflow( file, filedesc, signature, unused, keycontext ); }
677
678   bool KeyRing::verifyFileSignature( const Pathname & file, const Pathname & signature )
679   { return _pimpl->verifyFileSignature( file, signature ); }
680
681   bool KeyRing::verifyFileTrustedSignature( const Pathname & file, const Pathname & signature )
682   { return _pimpl->verifyFileTrustedSignature( file, signature ); }
683
684   void KeyRing::dumpPublicKey( const std::string & id, bool trusted, std::ostream & stream )
685   { _pimpl->dumpPublicKey( id, trusted, stream ); }
686
687   PublicKey KeyRing::exportPublicKey( const PublicKeyData & keyData )
688   { return _pimpl->exportPublicKey( keyData ); }
689
690   PublicKey KeyRing::exportTrustedPublicKey( const PublicKeyData & keyData )
691   { return _pimpl->exportTrustedPublicKey( keyData ); }
692
693   bool KeyRing::isKeyTrusted( const std::string & id )
694   { return _pimpl->isKeyTrusted( id ); }
695
696   bool KeyRing::isKeyKnown( const std::string & id )
697   { return _pimpl->isKeyKnown( id ); }
698
699   /////////////////////////////////////////////////////////////////
700 } // namespace zypp
701 ///////////////////////////////////////////////////////////////////