Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / FileChecker.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/FileChecker.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/Logger.h"
14 #include "zypp/FileChecker.h"
15 #include "zypp/ZYppFactory.h"
16 #include "zypp/Digest.h"
17 #include "zypp/KeyRing.h"
18
19 using namespace std;
20
21 #undef ZYPP_BASE_LOGGER_LOGGROUP
22 #define ZYPP_BASE_LOGGER_LOGGROUP "FileChecker"
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 { /////////////////////////////////////////////////////////////////
27
28   ChecksumFileChecker::ChecksumFileChecker( const CheckSum &checksum )
29     : _checksum(checksum)
30   {}
31
32   void ChecksumFileChecker::operator()( const Pathname &file ) const
33   {
34     //MIL << "checking " << file << " file against checksum '" << _checksum << "'" << endl;
35     callback::SendReport<DigestReport> report;
36
37     if ( _checksum.empty() )
38     {
39       MIL << "File " <<  file << " has no checksum available." << std::endl;
40       if ( report->askUserToAcceptNoDigest(file) )
41       {
42         MIL << "User accepted " <<  file << " with no checksum." << std::endl;
43         return;
44       }
45       else
46       {
47         ZYPP_THROW( ExceptionType( file.basename() + " has no checksum" ) );
48       }
49     }
50     else
51     {
52       CheckSum real_checksum( _checksum.type(), filesystem::checksum( file, _checksum.type() ));
53       if ( (real_checksum != _checksum) )
54       {
55         // Remember askUserToAcceptWrongDigest decision for at most 12hrs in memory;
56         // Actually we just want to prevent asking the same question again when the
57         // previously downloaded file is retrieved from the disk cache.
58         static std::map<std::string,std::string> exceptions;
59         static Date exceptionsAge;
60         Date now( Date::now() );
61         if ( !exceptions.empty() && now-exceptionsAge > 12*Date::hour )
62           exceptions.clear();
63
64         WAR << "File " <<  file << " has wrong checksum " << real_checksum << " (expected " << _checksum << ")" << endl;
65         if ( !exceptions.empty() && exceptions[real_checksum.checksum()] == _checksum.checksum() )
66         {
67           WAR << "User accepted " <<  file << " with WRONG CHECKSUM. (remembered)" << std::endl;
68           return;
69         }
70         else if ( report->askUserToAcceptWrongDigest( file, _checksum.checksum(), real_checksum.checksum() ) )
71         {
72           WAR << "User accepted " <<  file << " with WRONG CHECKSUM." << std::endl;
73           exceptions[real_checksum.checksum()] = _checksum.checksum();
74           exceptionsAge = now;
75           return;
76         }
77         else
78         {
79           ZYPP_THROW( ExceptionType( file.basename() + " has wrong checksum" ) );
80         }
81       }
82     }
83   }
84
85   void NullFileChecker::operator()(const Pathname &file ) const
86   {
87     MIL << "+ null check on " << file << endl;
88     return;
89   }
90
91   void CompositeFileChecker::operator()(const Pathname &file ) const
92   {
93     //MIL << _checkers.size() << " checkers" << endl;
94     for ( list<FileChecker>::const_iterator it = _checkers.begin(); it != _checkers.end(); ++it )
95     {
96       if ( *it )
97       {
98         //MIL << "+ chk" << endl;
99         (*it)(file);
100       }
101       else
102       {
103         ERR << "Invalid checker" << endl;
104       }
105     }
106   }
107
108   void CompositeFileChecker::add( const FileChecker &checker )
109   { _checkers.push_back(checker); }
110
111
112   SignatureFileChecker::SignatureFileChecker( const Pathname & signature )
113        : _signature(signature)
114   {}
115
116   SignatureFileChecker::SignatureFileChecker()
117   {}
118
119   void SignatureFileChecker::setKeyContext(const KeyContext & keycontext)
120   { _context = keycontext; }
121
122   void SignatureFileChecker::addPublicKey( const Pathname & publickey, const KeyContext & keycontext )
123   { addPublicKey( PublicKey(publickey), keycontext ); }
124
125   void SignatureFileChecker::addPublicKey( const PublicKey & publickey, const KeyContext & keycontext )
126   {
127     getZYpp()->keyRing()->importKey(publickey, false);
128     _context = keycontext;
129   }
130
131   void SignatureFileChecker::operator()(const Pathname &file ) const
132   {
133     if ( (! PathInfo(_signature).isExist()) && (!_signature.empty()) )
134     {
135       ZYPP_THROW( ExceptionType("Signature " + _signature.asString() + " not found.") );
136     }
137
138     MIL << "checking " << file << " file validity using digital signature.." << endl;
139     _fileValidated = false;
140     _fileAccepted = getZYpp()->keyRing()->verifyFileSignatureWorkflow( file, file.basename(), _signature, _fileValidated, _context );
141
142     if ( !_fileAccepted )
143       ZYPP_THROW( ExceptionType( "Signature verification failed for "  + file.basename() ) );
144  }
145
146   /******************************************************************
147   **
148   **    FUNCTION NAME : operator<<
149   **    FUNCTION TYPE : std::ostream &
150   */
151   std::ostream & operator<<( std::ostream & str, const FileChecker & obj )
152   {
153     return str;
154   }
155
156   /////////////////////////////////////////////////////////////////
157 } // namespace zypp
158 ///////////////////////////////////////////////////////////////////