diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2012-06-12 10:59:03 +0200 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2012-06-12 10:59:03 +0200 |
| commit | bcef41df6bdefdd95e0b7cab0428b4655accf9fa (patch) | |
| tree | c0ace88aa730e62982f7563e9fcec5397cca4cc8 /apt | |
| parent | 2d2ba80ac8aafbfc4f5a2a2ae6490ad994d57d9d (diff) | |
| parent | 43aee9eda68e374067d6d6a9c4dd3c3e9b986041 (diff) | |
| download | python-apt-bcef41df6bdefdd95e0b7cab0428b4655accf9fa.tar.gz | |
merged from the mvo branch
Diffstat (limited to 'apt')
| -rw-r--r-- | apt/auth.py | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/apt/auth.py b/apt/auth.py new file mode 100644 index 00000000..38c4bdc6 --- /dev/null +++ b/apt/auth.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# auth - authentication key management +# +# Copyright (c) 2004 Canonical +# Copyright (c) 2012 Sebastian Heinlein +# +# Author: Michael Vogt <mvo@debian.org> +# Sebastian Heinlein <devel@glatzor.de> +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +"""Handle GnuPG keys used to trust signed repositories.""" + +import atexit +import os +import os.path +import subprocess +import tempfile + +import apt_pkg +from apt_pkg import gettext as _ + + +class TrustedKey(object): + + """Represents a trusted key.""" + + def __init__(self, name, keyid, date): + self.raw_name = name + # Allow to translated some known keys + self.name = _(name) + self.keyid = keyid + self.date = date + + def __str__(self): + return "%s\n%s %s" % (self.name, self.keyid, self.date) + + +def _call_apt_key_script(*args, **kwargs): + """Run the apt-key script with the given arguments.""" + cmd = [apt_pkg.config.find_file("Dir::Bin::Apt-Key", "/usr/bin/apt-key")] + cmd.extend(args) + env = os.environ.copy() + env["LANG"] = "C" + if apt_pkg.config.find_dir("Dir") != "/": + # If the key is to be installed into a chroot we have to export the + # configuration from the chroot to the apt-key script by using + # a temporary APT_CONFIG file. The apt-key script uses apt-config shell + # internally + conf_fd, conf_name = tempfile.mkstemp(prefix="apt-key", suffix="conf") + atexit.register(os.remove, conf_name) + try: + os.write(conf_fd, apt_pkg.config.dump().encode("UTF-8")) + finally: + os.close(conf_fd) + env["APT_CONFIG"] = conf_name + proc = subprocess.Popen(cmd, env=env, universal_newlines=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + try: + proc.stdin.write(kwargs["stdin"]) + except KeyError: + pass + finally: + proc.stdin.close() + return_code = proc.wait() + output = proc.stdout.read() + if return_code: + raise SystemError("The apt-key script failed with return code %s:\n" + "%s\n%s" % (return_code, " ".join(cmd), output)) + return output.strip() + +def add_key_from_file(filename): + """Import a GnuPG key file to trust repositores signed by it. + + Keyword arguments: + filename -- the absolute path to the public GnuPG key file + """ + if not os.path.abspath(filename): + raise SystemError("An absolute path is required: %s" % filename) + if not os.access(filename, os.R_OK): + raise SystemError("Key file cannot be accessed: %s" % filename) + _call_apt_key_script("add", filename) + +def add_key_from_keyserver(keyid, keyserver): + """Import a GnuPG key file to trust repositores signed by it. + + Keyword arguments: + keyid -- the identifier of the key, e.g. 0x0EB12DSA + keyserver -- the URL or hostname of the key server + """ + _call_apt_key_script("adv", "--quiet", "--keyserver", keyserver, + "--recv", keyid) + +def add_key(content): + """Import a GnuPG key to trust repositores signed by it. + + Keyword arguments: + content -- the content of the GnuPG public key + """ + _call_apt_key_script("adv", "--quiet", "--batch", + "--import", "-", stdin=content) + +def remove_key(fingerprint): + """Remove a GnuPG key to no longer trust repositores signed by it. + + Keyword arguments: + fingerprint -- the fingerprint identifying the key + """ + _call_apt_key_script("rm", fingerprint) + +def export_key(fingerprint): + """Return the GnuPG key in text format. + + Keyword arguments: + fingerprint -- the fingerprint identifying the key + """ + return _call_apt_key_script("export", fingerprint) + +def update(): + """Update the local keyring with the archive keyring and remove from + the local keyring the archive keys which are no longer valid. The + archive keyring is shipped in the archive-keyring package of your + distribution, e.g. the debian-archive-keyring package in Debian. + """ + return _call_apt_key_script("update") + +def net_update(): + """Work similar to the update command above, but get the archive + keyring from an URI instead and validate it against a master key. + This requires an installed wget(1) and an APT build configured to + have a server to fetch from and a master keyring to validate. APT + in Debian does not support this command and relies on update + instead, but Ubuntu's APT does. + """ + return _call_apt_key_script("net-update") + +def list_keys(): + """Returns a list of TrustedKey instances for each key which is + used to trust repositories. + """ + # The output of `apt-key list` is difficult to parse since the + # --with-colons parameter isn't user + output = _call_apt_key_script("adv", "--with-colons", "--batch", + "--list-keys") + res = [] + for line in output.split("\n"): + fields = line.split(":") + if fields[0] == "pub": + key = TrustedKey(fields[9], fields[4][-8:], fields[5]) + res.append(key) + return res + +if __name__ == "__main__": + # Add some known keys we would like to see translated so that they get + # picked up by gettext + lambda: _("Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>") + lambda: _("Ubuntu CD Image Automatic Signing Key <cdimage@ubuntu.com>") + + apt_pkg.init() + for trusted_key in list_keys(): + print(trusted_key) |
