[yum-commits] Branch 'yum-3_2_X' - 7 commits - docs/yum.conf.5 output.py yum/config.py yum/__init__.py yum/misc.py yum/repos.py yum/yumRepo.py

skvidal at osuosl.org skvidal at osuosl.org
Mon Jan 3 15:50:25 UTC 2011


 docs/yum.conf.5 |    8 ++
 output.py       |    3 
 yum/__init__.py |  175 +++++++++++++++++++++++++++++++++++++++++---------------
 yum/config.py   |    1 
 yum/misc.py     |   51 +++++++++++++---
 yum/repos.py    |   11 ++-
 yum/yumRepo.py  |   29 ++++++++-
 7 files changed, 218 insertions(+), 60 deletions(-)

New commits:
commit 11c4418a625e66ab45236041bdda9ba40d093095
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Thu Dec 23 15:16:29 2010 -0500

    prefix=prefix
    
    very true
    
    a tad unnecessary, though :)

diff --git a/yum/misc.py b/yum/misc.py
index 4ac419e..15e571f 100644
--- a/yum/misc.py
+++ b/yum/misc.py
@@ -611,8 +611,6 @@ def getCacheDir(tmpdir='/var/tmp', reuse=True, prefix='yum-'):
     except KeyError:
         return None # if it returns None then, well, it's bollocksed
 
-    prefix = prefix
-
     if reuse:
         # check for /var/tmp/yum-username-* - 
         prefix = '%s%s-' % (prefix, username)
commit 49e95fdb98de8a496e151b5921ac163d32ff8bd9
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Thu Dec 23 14:50:26 2010 -0500

    when we setup our repo dirs - if we're not root use the gpgdir-ro options

diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
index ff10251..0281f1a 100644
--- a/docs/yum.conf.5
+++ b/docs/yum.conf.5
@@ -658,6 +658,14 @@ option (above). If a GPG key is required to install a package from a
 repository, all keys specified for that repository will be installed.
 
 .IP
+\fBgpgcakey\fR
+A URL pointing to the ASCII-armored CA key file for the repository. This is a normal 
+gpg public key - but this key will be used to validate detached signatures of all
+other keys. The idea is you are asked to confirm import for this key. After that any other 
+gpg key needed for package or repository verification, if it has a detached signature which matches this
+key will be automatically imported without user confirmation.
+
+.IP
 \fBexclude\fR
 Same as the [main] \fBexclude\fR option but only for this repository.
 Substitution variables, described below, are honored here.
diff --git a/yum/repos.py b/yum/repos.py
index 46b8f3d..4ea4961 100644
--- a/yum/repos.py
+++ b/yum/repos.py
@@ -220,7 +220,7 @@ class RepoStorage:
         for repo in self.repos.values():
             repo.old_base_cache_dir = repo.basecachedir
             repo.basecachedir = cachedir
-            
+
 
     def setProgressBar(self, obj):
         """sets the progress bar for downloading files from repos"""
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
index f44e0dd..6a27805 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
@@ -551,8 +551,11 @@ class YumRepository(Repository, config.RepoConf):
         self.setAttribute('_dir_setup_pkgdir', pkgdir)
         self.setAttribute('_dir_setup_hdrdir', hdrdir)
         self.setAttribute('_dir_setup_persistdir', persistdir)
-        self.setAttribute('_dir_setup_gpgdir', persistdir + '/gpgdir')
-        self.setAttribute('_dir_setup_gpgcadir', persistdir + '/gpgcadir')
+        ext=''
+        if os.geteuid() != 0:
+            ext = '-ro'
+        self.setAttribute('_dir_setup_gpgdir', persistdir + '/gpgdir' + ext)
+        self.setAttribute('_dir_setup_gpgcadir', persistdir + '/gpgcadir' + ext)
 
         cookie = self.cachedir + '/' + self.metadata_cookie_fn
         self.setAttribute('_dir_setup_metadata_cookie', cookie)
commit 3f0d169e7eeb965c1e9d438fa6f278a8ab204950
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Thu Dec 23 14:48:38 2010 -0500

    when importing a gpgkey - write out a -ro version of the gpgdir for non-root users to use
    also setup the difficult-to-grok gpgoptions necessary to make a readonly GNUPGHOME work
    with a simple key validation
    
    change setCacheDir() so it can take an alternative prefix and so we don't set
    a prefix then assume something else entirely

diff --git a/yum/misc.py b/yum/misc.py
index e539c27..4ac419e 100644
--- a/yum/misc.py
+++ b/yum/misc.py
@@ -20,6 +20,7 @@ import pwd
 import fnmatch
 import bz2
 import gzip
+import shutil
 _available_compression = ['gz', 'bz2']
 try:
     import lzma
@@ -496,7 +497,7 @@ def keyInstalled(ts, keyid, timestamp):
 
     return -1
 
-def import_key_to_pubring(rawkey, keyid, cachedir=None, gpgdir=None):
+def import_key_to_pubring(rawkey, keyid, cachedir=None, gpgdir=None, make_ro_copy=True):
     # FIXME - cachedir can be removed from this method when we break api
     if gpgme is None:
         return False
@@ -519,6 +520,30 @@ def import_key_to_pubring(rawkey, keyid, cachedir=None, gpgdir=None):
     # ultimately trust the key or pygpgme is definitionally stupid
     k = ctx.get_key(keyid)
     gpgme.editutil.edit_trust(ctx, k, gpgme.VALIDITY_ULTIMATE)
+    
+    if make_ro_copy:
+
+        rodir = gpgdir + '-ro'
+        if not os.path.exists(rodir):
+            os.makedirs(rodir, mode=0755)
+            for f in glob.glob(gpgdir + '/*'):
+                basename = os.path.basename(f)
+                ro_f = rodir + '/' + basename
+                shutil.copy(f, ro_f)
+                os.chmod(ro_f, 0755)
+            fp = open(rodir + '/gpg.conf', 'w', 0755)
+            # yes it is this stupid, why do you ask?
+            opts="""lock-never    
+no-auto-check-trustdb    
+trust-model direct
+no-expensive-trust-checks
+no-permission-warning         
+preserve-permissions
+"""
+            fp.write(opts)
+            fp.close()
+
+        
     return True
     
 def return_keyids_from_pubring(gpgdir):
@@ -541,7 +566,9 @@ def valid_detached_sig(sig_file, signed_file, gpghome=None):
     if gpgme is None:
         return False
 
-    if gpghome and os.path.exists(gpghome):
+    if gpghome:
+        if not os.path.exists(gpghome):
+            return False
         os.environ['GNUPGHOME'] = gpghome
 
     if hasattr(sig_file, 'read'):
@@ -573,7 +600,7 @@ def valid_detached_sig(sig_file, signed_file, gpghome=None):
 
     return False
 
-def getCacheDir(tmpdir='/var/tmp', reuse=True):
+def getCacheDir(tmpdir='/var/tmp', reuse=True, prefix='yum-'):
     """return a path to a valid and safe cachedir - only used when not running
        as root or when --tempcache is set"""
     
@@ -584,11 +611,11 @@ def getCacheDir(tmpdir='/var/tmp', reuse=True):
     except KeyError:
         return None # if it returns None then, well, it's bollocksed
 
-    prefix = 'yum-'
+    prefix = prefix
 
     if reuse:
         # check for /var/tmp/yum-username-* - 
-        prefix = 'yum-%s-' % username    
+        prefix = '%s%s-' % (prefix, username)
         dirpath = '%s/%s*' % (tmpdir, prefix)
         cachedirs = sorted(glob.glob(dirpath))
         for thisdir in cachedirs:
commit c4d8b59cb726b682e41c3afcb3c7255c4d874c71
Merge: cf2291a... 5d81a99...
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Thu Dec 23 14:47:23 2010 -0500

    Merge branch 'yum-3_2_X' of ssh://yum.baseurl.org/srv/projects/yum/git/yum into yum-3_2_X
    
    * 'yum-3_2_X' of ssh://yum.baseurl.org/srv/projects/yum/git/yum:
      Expose base options and their completions for reuse in yum-utils.
      Do the obvious fnmatch => regex change, for searchPackageProvides
      Merge arg. checks in searchPackageProvides
      Add a comment about MIRE_GLOB and basenames not working FYI.
      Speedup provides "perl(*)" etc. by 40% ish. -- No need to check files.
      Don't check the pkg nums for each lookup, libguestfs fix. BZ 662347.

commit cf2291a9f92ee39b86cf9811feccbe7f029887dd
Merge: 751146b... 1aa7b07...
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Sat Dec 11 00:16:00 2010 -0500

    Merge branch 'yum-3_2_X' of ssh://yum.baseurl.org/srv/projects/yum/git/yum into yum-3_2_X
    
    * 'yum-3_2_X' of ssh://yum.baseurl.org/srv/projects/yum/git/yum:
      Use exception2msg in utils.py.
      Don't write when in cache mode, for comps/tags, and catch IOError for comps.
      Get the sledgehammer out and "fix" unicode exceptions. BZ 662148
      Dynamically work out the max action width, in the rpm callback. BZ 660576.
      Allow ranges of transactions in list/summary/pkg-list.
      Don't skip installed_by/etc. if repoXML or loginuid doesn't exist.
      If the .localPkg() file has a url xattr, store that in yumdb. BZ 567100
      Don't delete packages when doing a test transaction.
      Sig check one po from each repo. as we download, to save errors at the end.
      Add _override_sigchecks, to catch dynamic repos. with --nogpgcheck, BZ 573725.
      Don't offer --*ableplugin options if --noplugins is already given.

commit 751146bf73ddfd46a7bcd382e36be74fe2e56eea
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Sat Dec 11 00:11:59 2010 -0500

    big change for having gpgcakeys
    
    The idea is you define a gpgcakey for repo. This is the key that once you import will let you import everything else automatically.
    
    If you have a cakey defined then when yum goes to import any other key it will look for a .asc detached signature for that key.
    if that signature is from the cakey you've already imported then yum will import the new gpgkey w/o prompting you.
    
    this works for signed packages as well as signed repomd.xml files in repos
    
    this also moves all gpg keyrings  into a new per-repo persistent directory in /var/lib/yum/repos/$basearch/$releasever/repoid
    so we don't have to worry about a yum clean all removing our gpgkeys like we have in the past.

diff --git a/output.py b/output.py
index f99ab37..a36e66c 100755
--- a/output.py
+++ b/output.py
@@ -1228,12 +1228,15 @@ Downgrade %5.5s Package(s)
     def setupKeyImportCallbacks(self):
         confirm_func = self._cli_confirm_gpg_key_import
         gpg_import_func = self.getKeyForRepo
+        gpgca_import_func = self.getCAKeyForRepo
         if hasattr(self, 'prerepoconf'):
             self.prerepoconf.confirm_func = confirm_func
             self.prerepoconf.gpg_import_func = gpg_import_func
+            self.prerepoconf.gpgca_import_func = gpgca_import_func
         else:
             self.repos.confirm_func = confirm_func
             self.repos.gpg_import_func = gpg_import_func
+            self.repos.gpgca_import_func = gpgca_import_func
 
     def interrupt_callback(self, cbobj):
         '''Handle CTRL-C's during downloads
diff --git a/yum/__init__.py b/yum/__init__.py
index 92fa0d0..67cf5b3 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -85,6 +85,7 @@ from yum.rpmtrans import RPMTransaction,SimpleCliCallBack
 from yum.i18n import to_unicode, to_str
 
 import string
+import StringIO
 
 from weakref import proxy as weakref
 
@@ -135,6 +136,7 @@ class _YumPreRepoConf:
         self.interrupt_callback = None
         self.confirm_func = None
         self.gpg_import_func = None
+        self.gpgca_import_func = None
         self.cachedir = None
         self.cache = None
 
@@ -415,7 +417,13 @@ class YumBase(depsolve.Depsolve):
             else:
                 thisrepo.repo_config_age = repo_age
                 thisrepo.repofile = repofn
-                
+                # repos are ver/arch specific so add $basearch/$releasever
+                self.conf._repos_persistdir = os.path.normpath('%s/repos/%s/%s/'
+                     % (self.conf.persistdir,  self.yumvar.get('basearch', '$basearch'),
+                        self.yumvar.get('releasever', '$releasever')))
+                thisrepo.base_persistdir = self.conf._repos_persistdir
+
+
             if thisrepo.id in self.repo_setopts:
                 for opt in self.repo_setopts[thisrepo.id].items:
                     if not hasattr(thisrepo, opt):
@@ -575,6 +583,7 @@ class YumBase(depsolve.Depsolve):
             self.repos.setInterruptCallback(prerepoconf.interrupt_callback)
             self.repos.confirm_func = prerepoconf.confirm_func
             self.repos.gpg_import_func = prerepoconf.gpg_import_func
+            self.repos.gpgca_import_func = prerepoconf.gpgca_import_func
             if prerepoconf.cachedir is not None:
                 self.repos.setCacheDir(prerepoconf.cachedir)
             if prerepoconf.cache is not None:
@@ -4309,15 +4318,16 @@ class YumBase(depsolve.Depsolve):
         self.conf.obsoletes = old_conf_obs
         return done
 
-    def _retrievePublicKey(self, keyurl, repo=None):
+    def _retrievePublicKey(self, keyurl, repo=None, getSig=True):
         """
         Retrieve a key file
         @param keyurl: url to the key to retrieve
         Returns a list of dicts with all the keyinfo
         """
         key_installed = False
-
-        self.logger.info(_('Retrieving GPG key from %s') % keyurl)
+        
+        msg = _('Retrieving key from %s') % keyurl
+        self.verbose_logger.log(logginglevels.INFO_2, msg)
        
         # Go get the GPG key from the given URL
         try:
@@ -4336,6 +4346,33 @@ class YumBase(depsolve.Depsolve):
         except urlgrabber.grabber.URLGrabError, e:
             raise Errors.YumBaseError(_('GPG key retrieval failed: ') +
                                       to_unicode(str(e)))
+                                      
+        # check for a .asc file accompanying it - that's our gpg sig on the key
+        # suck it down and do the check
+        sigfile = None
+        valid_sig = False
+        if getSig and repo and repo.gpgcakey:
+            self.getCAKeyForRepo(repo, callback=repo.confirm_func)
+            try:
+                url = misc.to_utf8(keyurl + '.asc')
+                opts = repo._default_grabopts()
+                text = repo.id + '/gpgkeysig'
+                sigfile = urlgrabber.urlopen(url, **opts)
+
+            except urlgrabber.grabber.URLGrabError, e:
+                sigfile = None
+
+            if sigfile:
+                if not misc.valid_detached_sig(sigfile, 
+                                    StringIO.StringIO(rawkey), repo.gpgcadir):
+                    #if we decide we want to check, even though the sig failed
+                    # here is where we would do that
+                    raise Errors.YumBaseError(_('GPG key signature on key %s does not match CA Key for repo: %s') % (url, repo.id))
+                else:
+                    msg = _('GPG key signature verified against CA Key(s)')
+                    self.verbose_logger.log(logginglevels.INFO_2, msg)
+                    valid_sig = True
+            
         # Parse the key
         try:
             keys_info = misc.getgpgkeyinfo(rawkey, multiple=True)
@@ -4352,29 +4389,31 @@ class YumBase(depsolve.Depsolve):
                       _('GPG key parsing failed: key does not have value %s') + info
                 thiskey[info] = keyinfo[info]
             thiskey['hexkeyid'] = misc.keyIdToRPMVer(keyinfo['keyid']).upper()
+            thiskey['valid_sig'] = valid_sig
+            thiskey['has_sig'] = bool(sigfile)
             keys.append(thiskey)
         
         return keys
 
-    def _getKeyImportMessage(self, info, keyurl):
+    def _getKeyImportMessage(self, info, keyurl, keytype='GPG'):
         msg = None
         if keyurl.startswith("file:"):
             fname = keyurl[len("file:"):]
             pkgs = self.rpmdb.searchFiles(fname)
             if pkgs:
                 pkgs = sorted(pkgs)[-1]
-                msg = (_('Importing GPG key 0x%s:\n'
+                msg = (_('Importing %s key 0x%s:\n'
                          ' Userid : %s\n'
                          ' Package: %s (%s)\n'
                          ' From   : %s') %
-                       (info['hexkeyid'], to_unicode(info['userid']),
+                       (keytype, info['hexkeyid'], to_unicode(info['userid']),
                         pkgs, pkgs.ui_from_repo,
                         keyurl.replace("file://","")))
         if msg is None:
-            msg = (_('Importing GPG key 0x%s:\n'
+            msg = (_('Importing %s key 0x%s:\n'
                      ' Userid: "%s"\n'
                      ' From  : %s') %
-                   (info['hexkeyid'], to_unicode(info['userid']),
+                   (keytype, info['hexkeyid'], to_unicode(info['userid']),
                     keyurl.replace("file://","")))
         self.logger.critical("%s", msg)
 
@@ -4405,24 +4444,34 @@ class YumBase(depsolve.Depsolve):
                     self.logger.info(_('GPG key at %s (0x%s) is already installed') % (
                         keyurl, info['hexkeyid']))
                     continue
-
-                # Try installing/updating GPG key
-                self._getKeyImportMessage(info, keyurl)
-                rc = False
-                if self.conf.assumeyes:
-                    rc = True
-                elif fullaskcb:
-                    rc = fullaskcb({"po": po, "userid": info['userid'],
-                                    "hexkeyid": info['hexkeyid'], 
-                                    "keyurl": keyurl,
-                                    "fingerprint": info['fingerprint'],
-                                    "timestamp": info['timestamp']})
-                elif askcb:
-                    rc = askcb(po, info['userid'], info['hexkeyid'])
-
-                if not rc:
-                    raise Errors.YumBaseError, _("Not installing key")
                 
+                if repo.gpgcakey and info['has_sig'] and info['valid_sig']:
+                    key_installed = True
+                else:
+                    # Try installing/updating GPG key
+                    self._getKeyImportMessage(info, keyurl)
+                    rc = False
+                    if self.conf.assumeyes:
+                        rc = True
+                        
+                    # grab the .sig/.asc for the keyurl, if it exists
+                    # if it does check the signature on the key
+                    # if it is signed by one of our ca-keys for this repo or the global one
+                    # then rc = True
+                    # else ask as normal.
+
+                    elif fullaskcb:
+                        rc = fullaskcb({"po": po, "userid": info['userid'],
+                                        "hexkeyid": info['hexkeyid'], 
+                                        "keyurl": keyurl,
+                                        "fingerprint": info['fingerprint'],
+                                        "timestamp": info['timestamp']})
+                    elif askcb:
+                        rc = askcb(po, info['userid'], info['hexkeyid'])
+
+                    if not rc:
+                        raise Errors.YumBaseError, _("Not installing key")
+                    
                 # Import the key
                 ts = self.rpmdb.readOnlyTS()
                 result = ts.pgpImportPubkey(misc.procgpgkey(info['raw_key']))
@@ -4446,43 +4495,55 @@ class YumBase(depsolve.Depsolve):
             self.logger.info(_("Import of key(s) didn't help, wrong key(s)?"))
             raise Errors.YumBaseError, errmsg
     
-    def getKeyForRepo(self, repo, callback=None):
+    def _getAnyKeyForRepo(self, repo, destdir, keyurl_list, is_cakey=False, callback=None):
         """
         Retrieve a key for a repository If needed, prompt for if the key should
         be imported using callback
         
         @param repo: Repository object to retrieve the key of.
+        @param destdir: destination of the gpg pub ring
+        @param keyurl_list: list of urls for gpg keys
+        @param is_cakey: bool - are we pulling in a ca key or not
         @param callback: Callback function to use for asking for verification
                           of a key. Takes a dictionary of key info.
         """
-        keyurls = repo.gpgkey
+
         key_installed = False
-        for keyurl in keyurls:
-            keys = self._retrievePublicKey(keyurl, repo)
+        for keyurl in keyurl_list:
+            keys = self._retrievePublicKey(keyurl, repo, getSig=not is_cakey)
             for info in keys:
                 # Check if key is already installed
-                if info['keyid'] in misc.return_keyids_from_pubring(repo.gpgdir):
+                if hex(int(info['keyid']))[2:-1].upper() in misc.return_keyids_from_pubring(destdir):
                     self.logger.info(_('GPG key at %s (0x%s) is already imported') % (
                         keyurl, info['hexkeyid']))
+                    key_installed = True
                     continue
 
                 # Try installing/updating GPG key
-                self._getKeyImportMessage(info, keyurl)
-                rc = False
-                if self.conf.assumeyes:
-                    rc = True
-                elif callback:
-                    rc = callback({"repo": repo, "userid": info['userid'],
-                                    "hexkeyid": info['hexkeyid'], "keyurl": keyurl,
-                                    "fingerprint": info['fingerprint'],
-                                    "timestamp": info['timestamp']})
-
-
-                if not rc:
-                    raise Errors.YumBaseError, _("Not installing key for repo %s") % repo
+                if is_cakey:
+                    keytype = 'CA'
+                else:
+                    keytype = 'GPG'
+
+                if repo.gpgcakey and info['has_sig'] and info['valid_sig']:
+                    key_installed = True
+                else:
+                    self._getKeyImportMessage(info, keyurl, keytype)
+                    rc = False
+                    if self.conf.assumeyes:
+                        rc = True
+                    elif callback:
+                        rc = callback({"repo": repo, "userid": info['userid'],
+                                        "hexkeyid": info['hexkeyid'], "keyurl": keyurl,
+                                        "fingerprint": info['fingerprint'],
+                                        "timestamp": info['timestamp']})
+
+
+                    if not rc:
+                        raise Errors.YumBaseError, _("Not installing key for repo %s") % repo
                 
                 # Import the key
-                result = misc.import_key_to_pubring(info['raw_key'], info['hexkeyid'], gpgdir=repo.gpgdir)
+                result = misc.import_key_to_pubring(info['raw_key'], info['hexkeyid'], gpgdir=destdir)
                 if not result:
                     raise Errors.YumBaseError, _('Key import failed')
                 self.logger.info(_('Key imported successfully'))
@@ -4495,6 +4556,29 @@ class YumBase(depsolve.Depsolve):
                   'Check that the correct key URLs are configured for ' \
                   'this repository.') % (repo.name)
 
+    def getKeyForRepo(self, repo, callback=None):
+        """
+        Retrieve a key for a repository If needed, prompt for if the key should
+        be imported using callback
+        
+        @param repo: Repository object to retrieve the key of.
+        @param callback: Callback function to use for asking for verification
+                          of a key. Takes a dictionary of key info.
+        """
+        self._getAnyKeyForRepo(repo, repo.gpgdir, repo.gpgkey, is_cakey=False, callback=callback)
+
+    def getCAKeyForRepo(self, repo, callback=None):
+        """
+        Retrieve a key for a repository If needed, prompt for if the key should
+        be imported using callback
+        
+        @param repo: Repository object to retrieve the key of.
+        @param callback: Callback function to use for asking for verification
+                          of a key. Takes a dictionary of key info.
+        """
+
+        self._getAnyKeyForRepo(repo, repo.gpgcadir, repo.gpgcakey, is_cakey=True, callback=callback)
+
     def _limit_installonly_pkgs(self):
         """ Limit packages based on conf.installonly_limit, if any of the
             packages being installed have a provide in conf.installonlypkgs.
@@ -4772,6 +4856,7 @@ class YumBase(depsolve.Depsolve):
         newrepo.gpgcheck = self.conf.gpgcheck
         newrepo.repo_gpgcheck = self.conf.repo_gpgcheck
         newrepo.basecachedir = self.conf.cachedir
+        newrepo.base_persistdir = self.conf._repos_persistdir
 
         for key in kwargs.keys():
             if not hasattr(newrepo, key): continue # skip the ones which aren't vars
diff --git a/yum/config.py b/yum/config.py
index 14eb992..97e5e3d 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -794,6 +794,7 @@ class RepoConf(BaseConfig):
     metalink   = UrlOption()
     mediaid = Option()
     gpgkey = UrlListOption()
+    gpgcakey = UrlListOption()
     exclude = ListOption() 
     includepkgs = ListOption() 
 
diff --git a/yum/repos.py b/yum/repos.py
index 4b74ac6..f11ed52 100644
--- a/yum/repos.py
+++ b/yum/repos.py
@@ -32,9 +32,12 @@ class _wrap_ayum_getKeyForRepo:
         we have a seperate class).
         A "better" fix might be to explicitly pass the YumBase instance to
         the callback ... API change! """
-    def __init__(self, ayum):
+    def __init__(self, ayum, ca=False):
         self.ayum = weakref(ayum)
+        self.ca = ca
     def __call__(self, repo, callback=None):
+        if self.ca:
+            return self.ayum.getCAKeyForRepo(repo, callback)
         return self.ayum.getKeyForRepo(repo, callback)
 
 class RepoStorage:
@@ -57,6 +60,7 @@ class RepoStorage:
         # even quasi-useful
         # defaults to what is probably sane-ish
         self.gpg_import_func = _wrap_ayum_getKeyForRepo(ayum)
+        self.gpgca_import_func = _wrap_ayum_getKeyForRepo(ayum, ca=True)
         self.confirm_func = None
 
         # This allow listEnabled() to be O(1) most of the time.
@@ -77,7 +81,8 @@ class RepoStorage:
 
         for repo in repos:
             repo.setup(self.ayum.conf.cache, self.ayum.mediagrabber,
-                   gpg_import_func = self.gpg_import_func, confirm_func=self.confirm_func)
+                   gpg_import_func = self.gpg_import_func, confirm_func=self.confirm_func,
+                   gpgca_import_func = self.gpgca_import_func)
             # if we come back from setup NOT enabled then mark as disabled
             # so nothing else touches us
             if not repo.enabled:
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
index b0e23c6..4926e9d 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
@@ -255,6 +255,7 @@ class YumRepository(Repository, config.RepoConf):
                                  # config is very, very old
         # throw in some stubs for things that will be set by the config class
         self.basecachedir = ""
+        self.base_persistdir = ""
         self.cost = 1000
         self.copy_local = 0
         # holder for stuff we've grabbed
@@ -273,6 +274,7 @@ class YumRepository(Repository, config.RepoConf):
 
         # callbacks for gpg key importing and confirmation
         self.gpg_import_func = None
+        self.gpgca_import_func = None
         self.confirm_func = None
 
         #  The reason we want to turn this off are things like repoids
@@ -368,7 +370,8 @@ class YumRepository(Repository, config.RepoConf):
         # we exclude all vars which start with _ or are in this list:
         excluded_vars = ('mediafunc', 'sack', 'metalink_data', 'grab', 
                          'grabfunc', 'repoXML', 'cfg', 'retrieved',
-                        'mirrorlistparsed', 'gpg_import_func', 'failure_obj',
+                        'mirrorlistparsed', 'gpg_import_func', 
+                        'gpgca_import_func', 'failure_obj',
                         'callback', 'confirm_func', 'groups_added', 
                         'interrupt_callback', 'id', 'mirror_failure_obj',
                         'repo_config_age', 'groupsfilename', 'copy_local', 
@@ -541,12 +544,15 @@ class YumRepository(Repository, config.RepoConf):
         """make the necessary dirs, if possible, raise on failure"""
 
         cachedir = os.path.join(self.basecachedir, self.id)
+        persistdir = os.path.join(self.base_persistdir, self.id)
         pkgdir = os.path.join(cachedir, 'packages')
         hdrdir = os.path.join(cachedir, 'headers')
         self.setAttribute('_dir_setup_cachedir', cachedir)
         self.setAttribute('_dir_setup_pkgdir', pkgdir)
         self.setAttribute('_dir_setup_hdrdir', hdrdir)
-        self.setAttribute('_dir_setup_gpgdir', self.cachedir + '/gpgdir')
+        self.setAttribute('_dir_setup_persistdir', persistdir)
+        self.setAttribute('_dir_setup_gpgdir', persistdir + '/gpgdir')
+        self.setAttribute('_dir_setup_gpgcadir', persistdir + '/gpgcadir')
 
         cookie = self.cachedir + '/' + self.metadata_cookie_fn
         self.setAttribute('_dir_setup_metadata_cookie', cookie)
@@ -554,6 +560,14 @@ class YumRepository(Repository, config.RepoConf):
         for dir in [self.cachedir, self.pkgdir]:
             self._dirSetupMkdir_p(dir)
 
+        # persistdir is really root-only but try the make anyway and just
+        # catch the exception
+        for dir in [self.persistdir]:
+            try:
+                self._dirSetupMkdir_p(dir)
+            except Errors.RepoError, e:
+                pass
+                
         # if we're using a cachedir that's not the system one, copy over these
         # basic items from the system one
         self._preload_md_from_system_cache('repomd.xml')
@@ -583,12 +597,16 @@ class YumRepository(Repository, config.RepoConf):
             self._dirSetupMkdir_p(val)
         return ret
     cachedir = property(lambda self: self._dirGetAttr('cachedir'))
+    persistdir = property(lambda self: self._dirGetAttr('persistdir'))
+
     pkgdir   = property(lambda self: self._dirGetAttr('pkgdir'),
                         lambda self, x: self._dirSetAttr('pkgdir', x))
     hdrdir   = property(lambda self: self._dirGetAttr('hdrdir'),
                         lambda self, x: self._dirSetAttr('hdrdir', x))
     gpgdir   = property(lambda self: self._dirGetAttr('gpgdir'),
                         lambda self, x: self._dirSetAttr('gpgdir', x))
+    gpgcadir   = property(lambda self: self._dirGetAttr('gpgcadir'),  
+                        lambda self, x: self._dirSetAttr('gpgcadir', x))
     metadata_cookie = property(lambda self: self._dirGetAttr('metadata_cookie'))
 
     def baseurlSetup(self):
@@ -947,11 +965,12 @@ class YumRepository(Repository, config.RepoConf):
             fo.close()
             del fo
 
-    def setup(self, cache, mediafunc = None, gpg_import_func=None, confirm_func=None):
+    def setup(self, cache, mediafunc = None, gpg_import_func=None, confirm_func=None, gpgca_import_func=None):
         try:
             self.cache = cache
             self.mediafunc = mediafunc
             self.gpg_import_func = gpg_import_func
+            self.gpgca_import_func = gpgca_import_func
             self.confirm_func = confirm_func
         except Errors.RepoError, e:
             raise
@@ -1451,7 +1470,6 @@ class YumRepository(Repository, config.RepoConf):
                                        size=102400)
             except URLGrabError, e:
                 raise URLGrabError(-1, 'Error finding signature for repomd.xml for %s: %s' % (self, e))
-
             valid = misc.valid_detached_sig(result, filepath, self.gpgdir)
             if not valid and self.gpg_import_func:
                 try:
commit 76bbe2116cd1c0d624f48be8714223c638308eae
Author: Seth Vidal <skvidal at fedoraproject.org>
Date:   Sat Dec 11 00:09:47 2010 -0500

    - add default 'has_sig' and 'valid_sig' keys to the keyinfo dicts
    - if the thing we get back is valid gpg but has no sigs then sigs will be an empty list :( - make sure we handle that correctly
    - when we're checking a detached signature sometimes we don't care about keeping the detached signature around so accept an object that can be read()

diff --git a/yum/misc.py b/yum/misc.py
index 4fa5ed9..7dffe70 100644
--- a/yum/misc.py
+++ b/yum/misc.py
@@ -431,6 +431,8 @@ def getgpgkeyinfo(rawkey, multiple=False):
             'timestamp': key.public_key.timestamp,
             'fingerprint' : key.public_key.fingerprint,
             'raw_key' : key.raw_key,
+            'has_sig' : False,
+            'valid_sig': False,
         }
 
         # Retrieve the timestamp from the matching signature packet 
@@ -542,8 +544,14 @@ def valid_detached_sig(sig_file, signed_file, gpghome=None):
     if gpghome and os.path.exists(gpghome):
         os.environ['GNUPGHOME'] = gpghome
 
-    sig = open(sig_file, 'r')
-    signed_text = open(signed_file, 'r')
+    if hasattr(sig_file, 'read'):
+        sig = sig_file
+    else:
+        sig = open(sig_file, 'r')
+    if hasattr(signed_file, 'read'):
+        signed_text = signed_file
+    else:
+        signed_text = open(signed_file, 'r')
     plaintext = None
     ctx = gpgme.Context()
 
@@ -552,6 +560,8 @@ def valid_detached_sig(sig_file, signed_file, gpghome=None):
     except gpgme.GpgmeError, e:
         return False
     else:
+        if not sigs:
+            return False
         # is there ever a case where we care about a sig beyond the first one?
         thissig = sigs[0]
         if not thissig:


More information about the Yum-commits mailing list