fixed sequence of ctor initializer list
[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/ZYppFactory.h"
19 #include "zypp/ZYpp.h"
20
21 #include "zypp/base/Logger.h"
22 #include "zypp/base/IOStream.h"
23 #include "zypp/base/String.h"
24 #include "zypp/Pathname.h"
25 #include "zypp/KeyRing.h"
26 #include "zypp/ExternalProgram.h"
27 #include "zypp/TmpPath.h"
28
29 using std::endl;
30 using namespace zypp::filesystem;
31 using namespace std;
32
33 #undef  ZYPP_BASE_LOGGER_LOGGROUP
34 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
35
36 ///////////////////////////////////////////////////////////////////
37 namespace zypp
38 { /////////////////////////////////////////////////////////////////
39
40   IMPL_PTR_TYPE(KeyRing);
41
42   static void dumpRegexpResults( const str::smatch &what )
43   {
44     for ( unsigned int k=0; k < what.size(); k++)
45     {
46       XXX << "[match "<< k << "] [" << what[k] << "]" << std::endl;
47     }
48   }
49
50   static bool printLine( const std::string &line )
51   {
52     MIL <<  line << std::endl;
53   }
54
55   static void dumpFile(const Pathname &file)
56   {
57     std::ifstream is(file.asString().c_str());
58     iostr::forEachLine( is, printLine);
59   }
60
61   namespace
62   {
63     bool _keyRingDefaultAccept( getenv("ZYPP_KEYRING_DEFAULT_ACCEPT_ALL") );
64   }
65
66   bool KeyRingReport::askUserToAcceptUnsignedFile( const std::string &file )
67   { return _keyRingDefaultAccept; }
68
69   bool KeyRingReport::askUserToAcceptUnknownKey( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
70   { return _keyRingDefaultAccept; }
71
72   bool KeyRingReport::askUserToTrustKey( const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
73   { return _keyRingDefaultAccept; }
74
75   bool KeyRingReport::askUserToAcceptVerificationFailed( const std::string &file, const std::string &keyid, const std::string &keyname, const std::string &fingerprint )
76   { return _keyRingDefaultAccept; }
77
78   ///////////////////////////////////////////////////////////////////
79   //
80   //    CLASS NAME : KeyRing::Impl
81   //
82   /** KeyRing implementation. */
83   struct KeyRing::Impl
84   {
85     Impl(const Pathname &baseTmpDir)
86     : _trusted_tmp_dir(baseTmpDir)
87     ,  _general_tmp_dir(baseTmpDir)
88
89     {
90       _base_dir = baseTmpDir;
91     }
92
93     /*
94     Impl( const Pathname &general_kr, const Pathname &trusted_kr )
95     {
96       filesystem::assert_dir(general_kr);
97       filesystem::assert_dir(trusted_kr);
98
99       generalKeyRing() = general_kr;
100       trustedKeyRing() = trusted_kr;
101     }
102     */
103
104     void importKey( const Pathname &keyfile, bool trusted = false);
105     PublicKey readPublicKey( const Pathname &keyfile );
106     std::string readSignatureKeyId( const Pathname &signature );
107
108     void deleteKey( const std::string &id, bool trusted );
109     std::list<PublicKey> trustedPublicKeys();
110     std::list<PublicKey> publicKeys();
111
112     void dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream );
113
114     bool verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature);
115
116     bool verifyFileSignature( const Pathname &file, const Pathname &signature);
117     bool verifyFileTrustedSignature( const Pathname &file, const Pathname &signature);
118   private:
119     //mutable std::map<Locale, std::string> translations;
120     bool verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring);
121     void importKey( const Pathname &keyfile, const Pathname &keyring);
122
123     void exportKey( std::string id, const Pathname &keyfile, bool trusted);
124
125     void deleteKey( const std::string &id, const Pathname &keyring );
126     std::list<PublicKey> publicKeys(const Pathname &keyring);
127
128     bool publicKeyExists( std::string id, const Pathname &keyring);
129
130     const Pathname generalKeyRing() const;
131     const Pathname trustedKeyRing() const;
132
133     // Used for trusted and untrusted keyrings
134     TmpDir _trusted_tmp_dir;
135     TmpDir _general_tmp_dir;
136     Pathname _base_dir;
137   public:
138     /** Offer default Impl. */
139     static shared_ptr<Impl> nullimpl()
140     {
141       static shared_ptr<Impl> _nullimpl( new Impl( Pathname("/var/tmp") ) );
142       return _nullimpl;
143     }
144
145   private:
146     friend Impl * rwcowClone<Impl>( const Impl * rhs );
147     /** clone for RWCOW_pointer */
148     Impl * clone() const
149     { return new Impl( *this ); }
150   };
151
152
153   const Pathname KeyRing::Impl::generalKeyRing() const
154   {
155     return _general_tmp_dir.path();
156   }
157
158   const Pathname KeyRing::Impl::trustedKeyRing() const
159   {
160     return _trusted_tmp_dir.path();
161   }
162
163   void KeyRing::Impl::importKey( const Pathname &keyfile, bool trusted)
164   {
165     importKey( keyfile, trusted ? trustedKeyRing() : generalKeyRing() );
166   }
167
168   void KeyRing::Impl::deleteKey( const std::string &id, bool trusted)
169   {
170     deleteKey( id, trusted ? trustedKeyRing() : generalKeyRing() );
171   }
172
173   std::list<PublicKey> KeyRing::Impl::publicKeys()
174   {
175     return publicKeys( generalKeyRing() );
176   }
177
178   std::list<PublicKey> KeyRing::Impl::trustedPublicKeys()
179   {
180     return publicKeys( trustedKeyRing() );
181   }
182
183   bool KeyRing::Impl::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
184   {
185     return verifyFile( file, signature, trustedKeyRing() );
186   }
187
188   bool KeyRing::Impl::verifyFileSignature( const Pathname &file, const Pathname &signature)
189   {
190     return verifyFile( file, signature, generalKeyRing() );
191   }
192
193   bool KeyRing::Impl::publicKeyExists( std::string id, const Pathname &keyring)
194   {
195     MIL << "Searching key [" << id << "] in keyring " << keyring << std::endl;
196     std::list<PublicKey> keys = publicKeys(keyring);
197     for (std::list<PublicKey>::const_iterator it = keys.begin(); it != keys.end(); it++)
198     {
199       if ( id == (*it).id )
200         return true;
201     }
202     return false;
203   }
204
205   void KeyRing::Impl::exportKey( std::string id, const Pathname &keyfile, bool trusted)
206   {
207     try {
208       std::ofstream os(keyfile.asString().c_str());
209       dumpPublicKey( id, trusted, os );
210       os.close();
211     }
212     catch (std::exception &e)
213     {
214       ERR << "Cannot export key " << id << " from " << (trusted ? "trusted" : "untrusted ") << " keyring  to file " << keyfile << std::endl;
215     }
216   }
217
218   void KeyRing::Impl::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
219   {
220     Pathname keyring = trusted ? trustedKeyRing() : generalKeyRing();
221     const char* argv[] =
222     {
223       "gpg",
224       "--no-default-keyring",
225       "--quiet",
226       "--no-tty",
227       "--no-greeting",
228       "--no-permission-warning",
229       "--batch",
230       "--homedir",
231       keyring.asString().c_str(),
232       "-a",
233       "--export",
234       id.c_str(),
235       NULL
236     };
237     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
238     std::string line;
239     int count;
240     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
241     {
242       stream << line;
243     }
244     prog.close();
245   }
246
247
248   bool KeyRing::Impl::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
249   {
250     callback::SendReport<KeyRingReport> report;
251     callback::SendReport<KeyRingSignals> emitSignal;
252     MIL << "Going to verify signature for " << file << " with " << signature << std::endl;
253
254     // if signature does not exists, ask user if he wants to accept unsigned file.
255     if( signature.empty() || (!PathInfo(signature).isExist()) )
256     {
257         bool res = report->askUserToAcceptUnsignedFile( filedesc );
258         MIL << "User decision on unsigned file: " << res << endl;
259         return res;
260     }
261
262     // get the id of the signature
263     std::string id = readSignatureKeyId(signature);
264
265     // doeskey exists in trusted keyring
266     if ( publicKeyExists( id, trustedKeyRing() ) )
267     {
268       TmpFile trustedKey(_base_dir);
269       exportKey( id, trustedKey.path(), true);
270       PublicKey key = readPublicKey(trustedKey.path());
271       MIL << "Key " << id << " " << key.name << " is trusted" << std::endl;
272       // it exists, is trusted, does it validates?
273       if ( verifyFile( file, signature, trustedKeyRing() ) )
274         return true;
275       else
276         return report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint );
277     }
278     else
279     {
280       if ( publicKeyExists( id, generalKeyRing() ) )
281       {
282         TmpFile unKey(_base_dir);
283         exportKey( id, unKey.path(), false);
284         MIL << "Exported key " << id << " to " << unKey << std::endl;
285
286         PublicKey key = readPublicKey(unKey.path());
287         MIL << "Key " << id << " " << key.name << " is not trusted" << std::endl;
288         // ok the key is not trusted, ask the user to trust it or not
289 #warning We need the key details passed to the callback
290         if ( report->askUserToTrustKey(key.id, key.name, key.fingerprint) )
291         {
292           MIL << "User wants to trust key " << id << " " << key.name << std::endl;
293           //dumpFile(unKey.path());
294
295           importKey( unKey.path(), trustedKeyRing() );
296           emitSignal->trustedKeyAdded( (const KeyRing &)(*this), id, key.name, key.fingerprint );
297
298           // emit key added
299           if ( verifyFile( file, signature, trustedKeyRing() ) )
300           {
301             MIL << "File signature is verified" << std::endl;
302             return true;
303           }
304           else
305           {
306             MIL << "File signature check fails" << std::endl;
307             if ( report->askUserToAcceptVerificationFailed( filedesc, key.id, key.name, key.fingerprint ) )
308             {
309               MIL << "User continues anyway." << std::endl;
310               return true;
311             }
312             else
313             {
314               MIL << "User does not want to continue" << std::endl;
315               return false;
316             }
317           }
318         }
319         else
320         {
321           MIL << "User does not want to trust key " << id << " " << key.name << std::endl;
322           return false;
323         }
324       }
325       else
326       {
327         // unknown key...
328         MIL << "File [" << file << "] ( " << filedesc << " ) signed with unknown key [" << id << "]" << std::endl;
329         if ( report->askUserToAcceptUnknownKey( filedesc, id, "", "" ) )
330         {
331           MIL << "User wants to accept unknown key " << id << std::endl;
332           return true;
333         }
334         else
335         {
336           MIL << "User does not want to accept unknown key " << id << std::endl;
337           return false;
338         }
339       }
340     }
341     return false;
342   }
343
344
345   PublicKey KeyRing::Impl::readPublicKey( const Pathname &keyfile )
346   {
347     TmpDir dir(_base_dir);
348
349     const char* argv[] =
350     {
351       "gpg",
352       "--no-default-keyring",
353       "--homedir",
354       dir.path().asString().c_str(),
355       "--with-fingerprint",
356       "--with-colons",
357       "--quiet",
358       "--no-tty",
359       "--no-greeting",
360       "--batch",
361       "--status-fd",
362       "1",
363       keyfile.asString().c_str(),
364       NULL
365     };
366
367     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
368
369     std::string line;
370     int count = 0;
371
372     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
373
374     // pub:-:1024:17:A84EDAE89C800ACA:2000-10-19:2008-06-21::-:SuSE Package Signing Key <build@suse.de>:
375
376     PublicKey key;
377     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
378     {
379       //MIL << "[" << line << "]" << std::endl;
380       str::smatch what;
381       if(str::regex_match(line, what, rxColons, str::match_extra))
382       {
383         if ( what[1] == "pub" )
384         {
385           key.id = what[5];
386           key.name = what[10];
387           //return key;
388         }
389         else if ( what[1] == "fpr" )
390         {
391           key.fingerprint = what[10];
392         }
393         //dumpRegexpResults(what);
394       }
395     }
396     prog.close();
397     return key;
398   }
399
400   std::list<PublicKey> KeyRing::Impl::publicKeys(const Pathname &keyring)
401   {
402     const char* argv[] =
403     {
404       "gpg",
405       "--no-default-keyring",
406       "--quiet",
407       "--list-public-keys",
408       "--with-colons",
409       "--with-fingerprint",
410       "--no-tty",
411       "--no-greeting",
412       "--batch",
413       "--status-fd",
414       "1",
415       "--homedir",
416       keyring.asString().c_str(),
417       NULL
418     };
419     std::list<PublicKey> keys;
420
421     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
422     std::string line;
423     int count = 0;
424
425     str::regex rxColons("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
426     str::regex rxColonsFpr("^([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):([^:]*):\n$");
427
428     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
429     {
430       //MIL << line << std::endl;
431       str::smatch what;
432       if(str::regex_match(line, what, rxColons, str::match_extra))
433       {
434         PublicKey key;
435         if ( what[1] == "pub" )
436         {
437           key.id = what[5];
438           key.name = what[10];
439
440           std::string line2;
441           for(line2 = prog.receiveLine(); !line2.empty(); line2 = prog.receiveLine(), count++ )
442           {
443             str::smatch what2;
444             if (str::regex_match(line2, what2, rxColonsFpr, str::match_extra))
445             {
446               if ( (what2[1] == "fpr") && (what2[1] != "pub") && (what2[1] !="sub"))
447               {
448                 key.fingerprint = what2[10];
449                 break;
450               }
451             }
452           }
453           keys.push_back(key);
454           MIL << "Found key " << "[" << key.id << "]" << " [" << key.name << "]" << " [" << key.fingerprint << "]" << std::endl;
455         }
456         //dumpRegexpResults(what);
457       }
458     }
459     prog.close();
460     return keys;
461   }
462
463   void KeyRing::Impl::importKey( const Pathname &keyfile, const Pathname &keyring)
464   {
465     const char* argv[] =
466     {
467       "gpg",
468       "--no-default-keyring",
469       "--quiet",
470       "--no-tty",
471       "--no-greeting",
472       "--no-permission-warning",
473       "--status-fd",
474       "1",
475       "--homedir",
476       keyring.asString().c_str(),
477       "--import",
478       keyfile.asString().c_str(),
479       NULL
480     };
481
482     int code;
483     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
484     code = prog.close();
485
486     //if ( code != 0 )
487     //  ZYPP_THROW(Exception("failed to import key"));
488   }
489
490   void KeyRing::Impl::deleteKey( const std::string &id, const Pathname &keyring )
491   {
492     const char* argv[] =
493     {
494       "gpg",
495       "--no-default-keyring",
496       "--yes",
497       "--quiet",
498       "--no-tty",
499       "--batch",
500       "--status-fd",
501       "1",
502       "--homedir",
503       keyring.asString().c_str(),
504       "--delete-keys",
505       id.c_str(),
506       NULL
507     };
508
509     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
510
511     int code = prog.close();
512     if ( code )
513       ZYPP_THROW(Exception("Failed to delete key."));
514     else
515       MIL << "Deleted key " << id << " from keyring " << keyring << std::endl;
516   }
517
518
519   std::string KeyRing::Impl::readSignatureKeyId(const Pathname &signature )
520   {
521     MIL << "Deetermining key id if signature " << signature << std::endl;
522     // HACK create a tmp keyring with no keys
523     TmpDir dir(_base_dir);
524     TmpFile fakeData(_base_dir);
525
526     const char* argv[] =
527     {
528       "gpg",
529       "--no-default-keyring",
530       "--quiet",
531       "--no-tty",
532       "--no-greeting",
533       "--batch",
534       "--status-fd",
535       "1",
536       "--homedir",
537       dir.path().asString().c_str(),
538       "--verify",
539       signature.asString().c_str(),
540       fakeData.path().asString().c_str(),
541       NULL
542     };
543
544     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
545
546     std::string line;
547     int count = 0;
548
549     str::regex rxNoKey("^\\[GNUPG:\\] NO_PUBKEY (.+)\n$");
550     std::string id;
551     for(line = prog.receiveLine(), count=0; !line.empty(); line = prog.receiveLine(), count++ )
552     {
553       //MIL << "[" << line << "]" << std::endl;
554       str::smatch what;
555       if(str::regex_match(line, what, rxNoKey, str::match_extra))
556       {
557         if ( what.size() > 1 )
558           id = what[1];
559         //dumpRegexpResults(what);
560       }
561     }
562     MIL << "Determined key id [" << id << "] for signature " << signature << std::endl;
563     prog.close();
564     return id;
565   }
566
567   bool KeyRing::Impl::verifyFile( const Pathname &file, const Pathname &signature, const Pathname &keyring)
568   {
569     const char* argv[] =
570     {
571       "gpg",
572       "--no-default-keyring",
573       "--quiet",
574       "--no-tty",
575       "--batch",
576       "--no-greeting",
577       "--status-fd",
578       "1",
579       "--homedir",
580       keyring.asString().c_str(),
581       "--verify",
582       signature.asString().c_str(),
583       file.asString().c_str(),
584       NULL
585     };
586
587     // no need to parse output for now
588     //     [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
589     //     [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
590     //     gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
591     //     [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
592     //     [GNUPG:] TRUST_UNDEFINED
593
594     //     [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
595     //     [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
596
597     ExternalProgram prog(argv,ExternalProgram::Discard_Stderr, false, -1, true);
598
599     return (prog.close() == 0) ? true : false;
600   }
601
602   ///////////////////////////////////////////////////////////////////
603
604   ///////////////////////////////////////////////////////////////////
605   //
606   //    CLASS NAME : KeyRing
607   //
608   ///////////////////////////////////////////////////////////////////
609
610   ///////////////////////////////////////////////////////////////////
611   //
612   //    METHOD NAME : KeyRing::KeyRing
613   //    METHOD TYPE : Ctor
614   //
615   KeyRing::KeyRing(const Pathname &baseTmpDir)
616   : _pimpl( new Impl(baseTmpDir) )
617   {}
618
619   ///////////////////////////////////////////////////////////////////
620   //
621   //    METHOD NAME : KeyRing::KeyRing
622   //    METHOD TYPE : Ctor
623   //
624   //KeyRing::KeyRing( const Pathname &general_kr, const Pathname &trusted_kr )
625   //: _pimpl( new Impl(general_kr, trusted_kr) )
626   //{}
627
628   ///////////////////////////////////////////////////////////////////
629   //
630   //    METHOD NAME : KeyRing::~KeyRing
631   //    METHOD TYPE : Dtor
632   //
633   KeyRing::~KeyRing()
634   {}
635
636   ///////////////////////////////////////////////////////////////////
637   //
638   // Forward to implementation:
639   //
640   ///////////////////////////////////////////////////////////////////
641
642   void KeyRing::importKey( const Pathname &keyfile, bool trusted)
643   {
644     _pimpl->importKey(keyfile, trusted);
645   }
646
647   PublicKey KeyRing::readPublicKey( const Pathname &keyfile )
648   {
649     return _pimpl->readPublicKey(keyfile);
650   }
651
652   std::string KeyRing::readSignatureKeyId( const Pathname &signature )
653   {
654     return _pimpl->readSignatureKeyId(signature);
655   }
656
657   void KeyRing::deleteKey( const std::string &id, bool trusted )
658   {
659     _pimpl->deleteKey(id, trusted);
660   }
661
662   std::list<PublicKey> KeyRing::publicKeys()
663   {
664     return _pimpl->publicKeys();
665   }
666
667   std::list<PublicKey> KeyRing::trustedPublicKeys()
668   {
669     return _pimpl->trustedPublicKeys();
670   }
671
672   bool KeyRing::verifyFileSignatureWorkflow( const Pathname &file, const std::string filedesc, const Pathname &signature)
673   {
674     return _pimpl->verifyFileSignatureWorkflow(file, filedesc, signature);
675   }
676
677   bool KeyRing::verifyFileSignature( const Pathname &file, const Pathname &signature)
678   {
679     return _pimpl->verifyFileSignature(file, signature);
680   }
681
682   bool KeyRing::verifyFileTrustedSignature( const Pathname &file, const Pathname &signature)
683   {
684     return _pimpl->verifyFileTrustedSignature(file, signature);
685   }
686
687   void KeyRing::dumpPublicKey( const std::string &id, bool trusted, std::ostream &stream )
688   {
689     _pimpl->dumpPublicKey( id, trusted, stream);
690   }
691
692   /////////////////////////////////////////////////////////////////
693 } // namespace zypp
694 ///////////////////////////////////////////////////////////////////