Skip to content

Commit d3e4d2d

Browse files
author
Tim Lauridsen
committed
fixes issues with use of non public gpg API in dnf 1.1.9 (rhbz #1338564)
1 parent 72d227d commit d3e4d2d

File tree

2 files changed

+160
-4
lines changed

2 files changed

+160
-4
lines changed

python/dnfdaemon/server/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -695,16 +695,14 @@ def set_option(self, option, value):
695695
def _check_gpg_signatures(self, pkgs):
696696
''' The the signatures of the downloaded packages '''
697697
for po in pkgs:
698-
# FIXME: Base.sigCheckPkg not public dnf api
699-
result, errmsg = self.base.sigCheckPkg(po)
698+
result, errmsg = self.base._sig_check_pkg(po)
700699
logger.debug('checking signature for : %s, %s', str(po), result)
701700
if result == 0:
702701
# Verified ok, or verify not req'd
703702
continue
704703
elif result == 1:
705-
# FIXME: Base.getKeyForPackage not public dnf api
706704
try:
707-
self.base.getKeyForPackage(po,
705+
self.base._get_key_for_package(po,
708706
fullaskcb=self._handle_gpg_import)
709707
except dnf.exceptions.Error as e:
710708
raise GPGError(str(e))

python/dnfdaemon/server/backend.py

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
dnf base and callbacks for dnfdaemon dbus services
2020
"""
2121
from time import time
22+
from dnf.i18n import _, ucd
23+
from dnf.yum import misc
2224

2325
import dnf
2426
import dnf.const
@@ -34,6 +36,7 @@
3436
import itertools
3537
import logging
3638
import sys
39+
import os
3740

3841
logger = logging.getLogger('dnfdaemon.base.dnf')
3942

@@ -105,6 +108,161 @@ def contains(self, attr, needle, ignore_case=True):
105108
else:
106109
return self.sack.query().filter(**fdict)
107110

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+
108266

109267
class Packages:
110268
"""This class gives easier access to getting packages from the dnf Sack."""

0 commit comments

Comments
 (0)