|
19 | 19 | dnf base and callbacks for dnfdaemon dbus services |
20 | 20 | """ |
21 | 21 | from time import time |
| 22 | +from dnf.i18n import _, ucd |
| 23 | +from dnf.yum import misc |
22 | 24 |
|
23 | 25 | import dnf |
24 | 26 | import dnf.const |
|
34 | 36 | import itertools |
35 | 37 | import logging |
36 | 38 | import sys |
| 39 | +import os |
37 | 40 |
|
38 | 41 | logger = logging.getLogger('dnfdaemon.base.dnf') |
39 | 42 |
|
@@ -105,6 +108,161 @@ def contains(self, attr, needle, ignore_case=True): |
105 | 108 | else: |
106 | 109 | return self.sack.query().filter(**fdict) |
107 | 110 |
|
| 111 | +############################################################################### |
| 112 | +# code copied from dnf for non public API related |
| 113 | +# |
| 114 | +# FIXME: this is copied from dnf/base.py, because there is no public |
| 115 | +# API to handle gpg signatures. |
| 116 | +############################################################################### |
| 117 | + def _sig_check_pkg(self, po): |
| 118 | + """Verify the GPG signature of the given package object. |
| 119 | +
|
| 120 | + :param po: the package object to verify the signature of |
| 121 | + :return: (result, error_string) |
| 122 | + where result is:: |
| 123 | +
|
| 124 | + 0 = GPG signature verifies ok or verification is not required. |
| 125 | + 1 = GPG verification failed but installation of the right GPG key |
| 126 | + might help. |
| 127 | + 2 = Fatal GPG verification error, give up. |
| 128 | + """ |
| 129 | + if po.from_cmdline: |
| 130 | + check = self.conf.localpkg_gpgcheck |
| 131 | + hasgpgkey = 0 |
| 132 | + else: |
| 133 | + repo = self.repos[po.repoid] |
| 134 | + check = repo.gpgcheck |
| 135 | + hasgpgkey = not not repo.gpgkey |
| 136 | + |
| 137 | + if check: |
| 138 | + root = self.conf.installroot |
| 139 | + ts = dnf.rpm.transaction.initReadOnlyTransaction(root) |
| 140 | + sigresult = dnf.rpm.miscutils.checkSig(ts, po.localPkg()) |
| 141 | + localfn = os.path.basename(po.localPkg()) |
| 142 | + del ts |
| 143 | + if sigresult == 0: |
| 144 | + result = 0 |
| 145 | + msg = '' |
| 146 | + |
| 147 | + elif sigresult == 1: |
| 148 | + if hasgpgkey: |
| 149 | + result = 1 |
| 150 | + else: |
| 151 | + result = 2 |
| 152 | + msg = _('Public key for %s is not installed') % localfn |
| 153 | + |
| 154 | + elif sigresult == 2: |
| 155 | + result = 2 |
| 156 | + msg = _('Problem opening package %s') % localfn |
| 157 | + |
| 158 | + elif sigresult == 3: |
| 159 | + if hasgpgkey: |
| 160 | + result = 1 |
| 161 | + else: |
| 162 | + result = 2 |
| 163 | + result = 1 |
| 164 | + msg = _('Public key for %s is not trusted') % localfn |
| 165 | + |
| 166 | + elif sigresult == 4: |
| 167 | + result = 2 |
| 168 | + msg = _('Package %s is not signed') % localfn |
| 169 | + |
| 170 | + else: |
| 171 | + result = 0 |
| 172 | + msg = '' |
| 173 | + |
| 174 | + return result, msg |
| 175 | + |
| 176 | + def _get_key_for_package(self, po, askcb=None, fullaskcb=None): |
| 177 | + """Retrieve a key for a package. If needed, use the given |
| 178 | + callback to prompt whether the key should be imported. |
| 179 | +
|
| 180 | + :param po: the package object to retrieve the key of |
| 181 | + :param askcb: Callback function to use to ask permission to |
| 182 | + import a key. The arguments *askck* should take are the |
| 183 | + package object, the userid of the key, and the keyid |
| 184 | + :param fullaskcb: Callback function to use to ask permission to |
| 185 | + import a key. This differs from *askcb* in that it gets |
| 186 | + passed a dictionary so that we can expand the values passed. |
| 187 | + :raises: :class:`dnf.exceptions.Error` if there are errors |
| 188 | + retrieving the keys |
| 189 | + """ |
| 190 | + repo = self.repos[po.repoid] |
| 191 | + keyurls = repo.gpgkey |
| 192 | + key_installed = False |
| 193 | + |
| 194 | + def _prov_key_data(msg): |
| 195 | + msg += _('Failing package is: %s') % (po) + '\n ' |
| 196 | + msg += _('GPG Keys are configured as: %s') % \ |
| 197 | + (', '.join(repo.gpgkey) + '\n') |
| 198 | + return '\n\n\n' + msg |
| 199 | + |
| 200 | + user_cb_fail = False |
| 201 | + for keyurl in keyurls: |
| 202 | + keys = dnf.crypto.retrieve(keyurl, repo) |
| 203 | + |
| 204 | + for info in keys: |
| 205 | + ts = self._rpmconn.readonly_ts |
| 206 | + # Check if key is already installed |
| 207 | + if misc.keyInstalled(ts, info.rpm_id, info.timestamp) >= 0: |
| 208 | + msg = _('GPG key at %s (0x%s) is already installed') |
| 209 | + logger.info(msg, keyurl, info.short_id) |
| 210 | + continue |
| 211 | + |
| 212 | + # Try installing/updating GPG key |
| 213 | + info.url = keyurl |
| 214 | + dnf.crypto.log_key_import(info) |
| 215 | + rc = False |
| 216 | + if self.conf.assumeno: |
| 217 | + rc = False |
| 218 | + elif self.conf.assumeyes: |
| 219 | + rc = True |
| 220 | + |
| 221 | + # grab the .sig/.asc for the keyurl, if it exists if it |
| 222 | + # does check the signature on the key if it is signed by |
| 223 | + # one of our ca-keys for this repo or the global one then |
| 224 | + # rc = True else ask as normal. |
| 225 | + |
| 226 | + elif fullaskcb: |
| 227 | + rc = fullaskcb({"po": po, "userid": info.userid, |
| 228 | + "hexkeyid": info.short_id, |
| 229 | + "keyurl": keyurl, |
| 230 | + "fingerprint": info.fingerprint, |
| 231 | + "timestamp": info.timestamp}) |
| 232 | + elif askcb: |
| 233 | + rc = askcb(po, info.userid, info.short_id) |
| 234 | + |
| 235 | + if not rc: |
| 236 | + user_cb_fail = True |
| 237 | + continue |
| 238 | + |
| 239 | + # Import the key |
| 240 | + result = ts.pgpImportPubkey(misc.procgpgkey(info.raw_key)) |
| 241 | + if result != 0: |
| 242 | + msg = _('Key import failed (code %d)') % result |
| 243 | + raise dnf.exceptions.Error(_prov_key_data(msg)) |
| 244 | + logger.info(_('Key imported successfully')) |
| 245 | + key_installed = True |
| 246 | + |
| 247 | + if not key_installed and user_cb_fail: |
| 248 | + raise dnf.exceptions.Error(_("Didn't install any keys")) |
| 249 | + |
| 250 | + if not key_installed: |
| 251 | + msg = _('The GPG keys listed for the "%s" repository are ' |
| 252 | + 'already installed but they are not correct for this ' |
| 253 | + 'package.\n' |
| 254 | + 'Check that the correct key URLs are configured for ' |
| 255 | + 'this repository.') % repo.name |
| 256 | + raise dnf.exceptions.Error(_prov_key_data(msg)) |
| 257 | + |
| 258 | + # Check if the newly installed keys helped |
| 259 | + result, errmsg = self._sig_check_pkg(po) |
| 260 | + if result != 0: |
| 261 | + msg = _("Import of key(s) didn't help, wrong key(s)?") |
| 262 | + logger.info(msg) |
| 263 | + errmsg = ucd(errmsg) |
| 264 | + raise dnf.exceptions.Error(_prov_key_data(errmsg)) |
| 265 | + |
108 | 266 |
|
109 | 267 | class Packages: |
110 | 268 | """This class gives easier access to getting packages from the dnf Sack.""" |
|
0 commit comments