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