On Mon, 14 Feb 2005, Martin Schulze wrote: > Quoting Andreas Barth from the release team: > > | Actually, we discussed about apt 0.6 within the release team and > | with the maintainers. IIRC, the two blocking issues are: > | > | 1. All the concepts > | - default installation, > | - key management,
Currently, apt 0.6 uses a single binary file as its keyring in /etc/apt. This has the disadvantage that modifying it requires special tools like apt-key, and so key management is a pain. The following patch makes apt use a directory in etc/apt named trusted-keys/. Keys are simply placed in that directory if the user wants to trust them for signing the Release file. [EMAIL PROTECTED]:~$ ls -l /etc/apt/trusted-keys total 12 -rw-rw-r-- 1 root root 902 Feb 16 10:00 debian-amd-2004.asc -rw-r--r-- 1 root root 751 Feb 16 09:53 debian-archive-2004.asc -rw-r--r-- 1 root root 1430 Feb 16 09:53 debian-archive-2005.asc On demand apt builds a keyring in /var/cache/apt/gpghome/trusted.gpg and uses that when checking signatures. The patch below does that. The package doesn't migrate your current /etc/apt/trusted.gpg to the new layout, tho that could be trivially added should people feel the need. As should be obvious, I'm not a C++ hacker, so let me know what needs cleaning and fixing. It works for me at least :) I think this patch should be applied to apt before it goes into sarge, as it makes some key issues easier to deal with. Peter
diff -Nur apt-0.6.25/debian/changelog apt-0.6.25.1/debian/changelog --- apt-0.6.25/debian/changelog 2004-06-09 14:33:17.000000000 +0200 +++ apt-0.6.25.1/debian/changelog 2005-02-16 13:25:50.663561131 +0100 @@ -1,3 +1,18 @@ +apt (0.6.25.1) experimental; urgency=low + + * Do away with /etc/apt/trusted.gpg. Instead we have a + /etc/apt/trusted-keys/ directory which holds files with keys. + The gpgv method updates /var/cache/apt/gpghome/trusted.gpg on + demand from the keys in /etc/apt/trusted-keys/. + * Remove apt-key, as it is no longer needed. + * Install the default debian key in /etc/apt/trusted-keys, + not in /usr/share/apt/debian-archive.gpg + * Remove debian/apt.postinst. All it handled was copying + the initial trusted.gpg to /etc. + * Add amd64 to the archtable. + + -- Peter Palfrader <[EMAIL PROTECTED]> Wed, 16 Feb 2005 13:25:44 +0100 + apt (0.6.25) experimental; urgency=low * Fix handling of two-part sources for sources.list deb-src entries in diff -Nur apt-0.6.25/buildlib/archtable apt-0.6.25.1/buildlib/archtable --- apt-0.6.25/buildlib/archtable 2002-11-09 20:59:10.000000000 +0100 +++ apt-0.6.25.1/buildlib/archtable 2005-02-16 08:53:08.274317000 +0100 @@ -24,3 +24,4 @@ ia64 ia64 s390 s390 s390x s390x +x86_64 amd64 diff -Nur apt-0.6.25/cmdline/apt-key apt-0.6.25.1/cmdline/apt-key --- apt-0.6.25/cmdline/apt-key 2004-01-15 21:19:18.000000000 +0100 +++ apt-0.6.25.1/cmdline/apt-key 1970-01-01 01:00:00.000000000 +0100 @@ -1,60 +0,0 @@ -#!/bin/sh - -set -e - -usage() { - echo "Usage: apt-key [command] [arguments]" - echo - echo "Manage apt's list of trusted keys" - echo - echo " apt-key add <file> - add the key contained in <file> ('-' for stdin)" - echo " apt-key del <keyid> - remove the key <keyid>" - echo " apt-key list - list keys" - echo -} - -command="$1" -if [ -z "$command" ]; then - usage - exit 1 -fi -shift - -if [ "$command" != "help" ] && ! which gpg >/dev/null 2>&1; then - echo >&2 "Warning: gnupg does not seem to be installed." - echo >&2 "Warning: apt-key requires gnupg for most operations." - echo >&2 -fi - -# We don't use a secret keyring, of course, but gpg panics and -# implodes if there isn't one available - -GPG="gpg --no-options --no-default-keyring --keyring /etc/apt/trusted.gpg --secret-keyring /etc/apt/secring.gpg --trustdb-name /etc/apt/trustdb.gpg" - -case "$command" in - add) - $GPG --quiet --batch --import "$1" - echo "OK" - ;; - del|rm|remove) - $GPG --quiet --batch --delete-key --yes "$1" - echo "OK" - ;; - list) - $GPG --batch --list-keys - ;; - finger*) - $GPG --batch --fingerprint - ;; - adv*) - echo "Executing: $GPG $*" - $GPG $* - ;; - help) - usage - ;; - *) - usage - exit 1 - ;; -esac diff -Nur apt-0.6.25/cmdline/makefile apt-0.6.25.1/cmdline/makefile --- apt-0.6.25/cmdline/makefile 2003-12-25 00:09:17.000000000 +0100 +++ apt-0.6.25.1/cmdline/makefile 2005-02-16 09:49:30.201016123 +0100 @@ -46,9 +46,3 @@ LIB_MAKES = apt-pkg/makefile SOURCE = apt-extracttemplates.cc include $(PROGRAM_H) - -# The apt-key program -SOURCE=apt-key -TO=$(BIN) -TARGET=program -include $(COPY_H) diff -Nur apt-0.6.25/configure apt-0.6.25.1/configure --- apt-0.6.25/configure 2004-06-09 14:34:09.000000000 +0200 +++ apt-0.6.25.1/configure 2005-02-16 08:49:55.950520272 +0100 @@ -1347,7 +1347,7 @@ cat >>confdefs.h <<_ACEOF -#define VERSION "0.6.25" +#define VERSION "0.6.25.1" _ACEOF PACKAGE="apt" diff -Nur apt-0.6.25/configure.in apt-0.6.25.1/configure.in --- apt-0.6.25/configure.in 2004-06-09 14:30:22.000000000 +0200 +++ apt-0.6.25.1/configure.in 2005-02-16 08:49:54.079930704 +0100 @@ -18,7 +18,7 @@ AC_CONFIG_HEADER(include/config.h:buildlib/config.h.in include/apti18n.h:buildlib/apti18n.h.in) dnl -- SET THIS TO THE RELEASE VERSION -- -AC_DEFINE_UNQUOTED(VERSION,"0.6.25") +AC_DEFINE_UNQUOTED(VERSION,"0.6.25.1") PACKAGE="apt" AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE") AC_SUBST(PACKAGE) diff -Nur apt-0.6.25/debian/apt.postinst apt-0.6.25.1/debian/apt.postinst --- apt-0.6.25/debian/apt.postinst 2003-12-25 00:09:17.000000000 +0100 +++ apt-0.6.25.1/debian/apt.postinst 1970-01-01 01:00:00.000000000 +0100 @@ -1,42 +0,0 @@ -#! /bin/sh - -set -e - -# summary of how this script can be called: -# * <postinst> `configure' <most-recently-configured-version> -# * <old-postinst> `abort-upgrade' <new version> -# * <conflictor's-postinst> `abort-remove' `in-favour' <package> -# <new-version> -# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' -# <failed-install-package> <version> `removing' -# <conflicting-package> <version> -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - -case "$1" in - configure) - - if ! test -f /etc/apt/trusted.gpg; then - cp /usr/share/apt/debian-archive.gpg /etc/apt/trusted.gpg - fi - - ;; - - abort-upgrade|abort-remove|abort-deconfigure) - - ;; - - *) - echo "postinst called with unknown argument \`$1'" >&2 - exit 1 - ;; -esac - -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - -#DEBHELPER# - -exit 0 - - diff -Nur apt-0.6.25/debian/rules apt-0.6.25.1/debian/rules --- apt-0.6.25/debian/rules 2004-05-09 00:10:10.000000000 +0200 +++ apt-0.6.25.1/debian/rules 2005-02-16 09:55:55.885987434 +0100 @@ -207,7 +207,9 @@ cp debian/bugscript debian/$@/usr/share/bug/$@/script - cp share/debian-archive.gpg debian/$@/usr/share/$@ + cp -r keys/ debian/$@/etc/apt/trusted-keys/ + mkdir debian/$@/var/cache/apt/gpghome + chmod 700 debian/$@/var/cache/apt/gpghome # head -n 500 ChangeLog > debian/ChangeLog @@ -218,7 +220,7 @@ dh_installchangelogs -p$@ dh_strip -p$@ dh_compress -p$@ - dh_fixperms -p$@ + dh_fixperms -p$@ --exclude var/cache/apt/gpghome dh_makeshlibs -p$@ -m$(LIBAPTPKG_MAJOR) -V '$(LIBAPTPKG_PROVIDE)' dh_installdeb -p$@ dh_shlibdeps -p$@ -l`pwd`/debian/apt/usr/lib -- -Ldebian/shlibs.local.apt diff -Nur apt-0.6.25/keys/debian-archive-2004.asc apt-0.6.25.1/keys/debian-archive-2004.asc --- apt-0.6.25/keys/debian-archive-2004.asc 1970-01-01 01:00:00.000000000 +0100 +++ apt-0.6.25.1/keys/debian-archive-2004.asc 2005-02-16 09:45:36.416455395 +0100 @@ -0,0 +1,15 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.0 (GNU/Linux) + +mIsEQAbkUgEEAMtQPa8xYMiJDVnA68aCeOYYzkGpqcz0gPo160lWo53l2K6+dP/A +7WJocrmBZQl/6c+tFQy5qPdyB7MJaCr/SdQkaz96GmGEPja9BUmYAC8KpGxEEi8x +SFbGEYBpndKobJzf2X6gA4KuPsIux0Bqd3aHz1r0N+HR1oAjEvxM4Fr5AAYptEJE +ZWJpYW4gQXJjaGl2ZSBBdXRvbWF0aWMgU2lnbmluZyBLZXkgKDIwMDQpIDxmdHBt +YXN0ZXJAZGViaWFuLm9yZz6IugQTAQIAJAUCQAbkUgIbAwUJAfJXAAYLCQgHAwID +FQIDAxYCAQIeAQIXgAAKCRBv+o75HbEU4M8XA/9R46S+8/npyNA1Yny05aDHkpKQ +i+jK6z+m+KJPHrd8TyKVr97A2LtYjmhtFXc5A5A2dLpccWIy7fJq3G22nTnarytD +MWDW5WHG/krr/1a1HthQm+Hks6gjsAITBGxahe/dUr6Fs8e7r1dGKtQgo5gDWswd +TChbmrIYXobLZhIrIIhGBBARAgAGBQJABuUWAAoJEIA/7hInFBuwE1UAnjuCr99o +3jD6rJlBXJ3GAr85iddrAJ9j1vn2EsGBYh5noLsx1M+kjLG8uQ== +=8NU+ +-----END PGP PUBLIC KEY BLOCK----- diff -Nur apt-0.6.25/keys/debian-archive-2005.asc apt-0.6.25.1/keys/debian-archive-2005.asc --- apt-0.6.25/keys/debian-archive-2005.asc 1970-01-01 01:00:00.000000000 +0100 +++ apt-0.6.25.1/keys/debian-archive-2005.asc 2005-02-16 09:45:12.277766261 +0100 @@ -0,0 +1,26 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.0 (GNU/Linux) + +mQGiBEH9wGgRBAC8D4O7cg/NDDvP2GT+yuX8duhK0DexhCy94TTNNs63YYMdXDJx +iY5V3Dt79r1ZeMmyNEdWFnvq39/0h+qQwPLbsd5eroxk/XMeBsz/OQP7FJ+f1SKe +XW68e+rp8bpT79QeXngaOUJdVUUsZs3lryCUn8F3bFRPuZF4DSssAVUpAwCgwAtu +BuEBlNnAqpE0J9JQGkJIeq0D/1oM01Czr/pkdIaFByD+ifEn0hYuKcHjqHJ8e1UV +gQ3+ZPb1ftdNF7OHdGY7tE1NH5VVNTk86tmGDc5PUXHMmMF5q/7PMJtEYus38gEn +lgD+i1rcvBKxuFNc6ahRmaETSR36ZvF1b4cnSIoGPYyw9yNEwFZdMXzqCHEK22Po +KQKbA/99b9idvjIawRnfbhWhg+0gmsZ+uZKvogwO8eKkmlkpgeaGLnO9mrXgO1Ud +fPtMF+z7OzYcQJhtBXVcUCvB3SXc/3iXZwqa6NrT+hvxmUhF4WJu1pxnKKAJmgdh +PiqOnWrJTS7Caf0tZ+hKBlvd44duf0Y72ft2m//6oIf2QbbezLRCRGViaWFuIEFy +Y2hpdmUgQXV0b21hdGljIFNpZ25pbmcgS2V5ICgyMDA1KSA8ZnRwbWFzdGVyQGRl +Ymlhbi5vcmc+iF0EExECAB0FAkH9wGgFCQHhM4AFCwcKAwQDFQMCAxYCAQIXgAAK +CRDx1T2MTzaNXag7AKCrW5rRQfUj1xbZTUrVOsxN7w4XKQCfUZgAsufbSic14TpC +S7CxkvxNaB2InAQQAQEABgUCQf3CewAKCRBv+o75HbEU4PCvA/4l8dEyPL2wdimd +P6qPqfXai6XDtetZlqeXGDlMyfYi6xZFpV2Y2eVvQg15WDV2xIJyCojUZ4n+ZMW4 +NpT2iuhWiFhRS7UmFt7YOmPGh/b0FUmVhdhEzwg5kooO5TIlGu6oPRMxbSd3kLFF +hRdAjh9naKIa5aKItOrUdNh+OXURe4hGBBMRAgAGBQJB/cP0AAoJEDsXvHQqTj6q +N3MAoJv5oYdDv5BxCsBFELR2RO/l0nnsAJ9QOUpQ/tGH8UydThKowWpD5twSBohM +BBMRAgAMBQJB/g7XBYMB4OURAAoJECjern8pmC5a4BQAoIP+yEy68hNdA2I9Xraq +cYjercF2AJ9VQAQDDFP0Km5OsNgNFKDFmeSLwohMBBMRAgAMBQJB/zWdBYMB375L +AAoJEO4l3j8c2w/jMToAniBTh+eoqhdj9C25Q4roCsT8llETAJ9lpmsGnZu6MmzR +8U/PDDKteSEZbw== +=fYNV +-----END PGP PUBLIC KEY BLOCK----- diff -Nur apt-0.6.25/methods/gpgv.cc apt-0.6.25.1/methods/gpgv.cc --- apt-0.6.25/methods/gpgv.cc 2004-01-05 20:33:28.000000000 +0100 +++ apt-0.6.25.1/methods/gpgv.cc 2005-02-16 13:26:46.783211766 +0100 @@ -1,6 +1,8 @@ #include <apt-pkg/error.h> #include <apt-pkg/acquire-method.h> #include <apt-pkg/strutl.h> +#include <apt-pkg/fileutl.h> +#include <apti18n.h> #include <sys/stat.h> #include <unistd.h> @@ -10,6 +12,8 @@ #include <errno.h> #include <sys/wait.h> #include <iostream> +#include <dirent.h> + #define GNUPGPREFIX "[GNUPG:]" #define GNUPGBADSIG "[GNUPG:] BADSIG" @@ -23,6 +27,9 @@ vector<string> &GoodSigners, vector<string> &BadSigners, vector<string> &NoPubKeySigners); + bool GPGVMethod::updateTrustedKeys(string Dir, string gpgHome, string + trustedKeys, string gpgpath); + protected: virtual bool Fetch(FetchItem *Itm); @@ -31,6 +38,145 @@ GPGVMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {}; }; + +bool GPGVMethod::updateTrustedKeys(string Dir, string gpgHome, string trustedKeys, string gpgpath) +{ + if (_config->FindB("Debug::Acquire::gpgv", false)) + std::cerr << "Checking if keyring is uptodate" << std::endl; + + DIR *D = opendir(Dir.c_str()); + if (D == 0) + return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); + + vector<string> List; + + for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) + { + if (Ent->d_name[0] == '.') + continue; + + // Skip bad file names ala run-parts + /* + const char *C = Ent->d_name; + for (; *C != 0; C++) + if (isalpha(*C) == 0 && isdigit(*C) == 0 && *C != '_' && *C != '-') + break; + if (*C != 0) + continue; + */ + + // Make sure it is a file and not something else + string File = flCombine(Dir,Ent->d_name); + struct stat St; + if (stat(File.c_str(),&St) != 0 || S_ISREG(St.st_mode) == 0) + continue; + + List.push_back(File); + } + closedir(D); + + sort(List.begin(),List.end()); + + + bool updateRequired = false; + struct stat buff; + time_t trustedKeys_mtime; + + if (stat(trustedKeys.c_str(), &buff) != 0 && errno != ENOENT) + return _error->Errno("stat","Stat on %s failed.",trustedKeys.c_str()); + if (errno != ENOENT) + trustedKeys_mtime = buff.st_mtime; + else + trustedKeys_mtime = 0; + + if (stat(Dir.c_str(), &buff) != 0) + return _error->Errno("stat","Stat on %s failed.",Dir.c_str()); + if (trustedKeys_mtime < buff.st_mtime) + updateRequired = true; + + + for (vector<string>::const_iterator I = List.begin(); !updateRequired && I != List.end(); I++) + { + string keyfile = *I; + if (stat(keyfile.c_str(), &buff) != 0) + return _error->Errno("stat","Stat on %s failed.",keyfile.c_str()); + if (trustedKeys_mtime < buff.st_mtime) + updateRequired = true; + } + + if (!updateRequired) { + if (_config->FindB("Debug::Acquire::gpgv", false)) + std::cerr << "No update required" << std::endl; + return true; + } + + if (_config->FindB("Debug::Acquire::gpgv", false)) + std::cerr << "Rebuilding trusted.gpg" << std::endl; + + if (unlink(trustedKeys.c_str()) != 0 && errno != ENOENT) + return _error->Errno("unlink","Removing %s failed.",trustedKeys.c_str()); + + + for (vector<string>::const_iterator I = List.begin(); I != List.end(); I++) + { + string keyfile = *I; + if (_config->FindB("Debug::Acquire::gpgv", false)) + { + std::cerr << "Importing: " << keyfile << std::endl; + } + + pid_t pid = fork(); + if (pid < 0) + { + return (string("Couldn't spawn new process") + strerror(errno)).c_str(); + } + else if (pid == 0) + { + if (_config->FindB("Debug::Acquire::gpgv", false)) + { + std::cerr << "Preparing to exec: " << gpgpath + << " --batch --homedir " << gpgHome + << " --no-default-keyring --keyring " << trustedKeys + << " --import " << keyfile << std::endl; + } + int nullfd = open("/dev/null", O_RDONLY); + dup2(nullfd, STDOUT_FILENO); + dup2(nullfd, STDERR_FILENO); + + execlp(gpgpath.c_str(), gpgpath.c_str(), "--batch", "--homedir", gpgHome.c_str(), + "--no-default-keyring", "--keyring", trustedKeys.c_str(), + "--import", keyfile.c_str(), NULL); + exit(111); + } + + int status; + waitpid(pid, &status, 0); + if (_config->FindB("Debug::Acquire::gpgv", false)) + { + std::cerr << "gpg exited" << std::endl; + } + + + if (WEXITSTATUS(status) == 0) + { + continue; + } + else if (WEXITSTATUS(status) == 1) + { + return _error->Error(_("Could not add %s to keyring %s."), keyfile.c_str(), trustedKeys.c_str()); + } + else if (WEXITSTATUS(status) == 111) + { + return _error->Error(_("Could not execute %s to add key to keyring (is gnupg installed?)"), gpgpath.c_str()); + } + else + { + return _error->Error(_("Unknown error executing gpg for import)")); + } + } + return true; +} + const char *GPGVMethod::VerifyGetSigners(const char *file, const char *outfile, vector<string> &GoodSigners, vector<string> &BadSigners, @@ -45,16 +191,34 @@ FILE *pipein; int status; struct stat buff; - string gpgvpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpgv"); - string pubringpath = _config->Find("Apt::GPGV::TrustedKeyring", "/etc/apt/trusted.gpg"); + string gpgpath = _config->Find("Dir::Bin::gpg", "/usr/bin/gpg"); + string gpgvpath = _config->Find("Dir::Bin::gpgv", "/usr/bin/gpgv"); + string gpghome = _config->Find("Apt::GPGV::GnuPGhome", "/var/cache/apt/gpghome"); + string pubringpath = gpghome + "/trusted.gpg"; + string pubkeyspath = _config->Find("Apt::GPGV::TrustedKeys", "/etc/apt/trusted-keys"); if (_config->FindB("Debug::Acquire::gpgv", false)) { - std::cerr << "gpgv path: " << gpgvpath << std::endl; - std::cerr << "Keyring path: " << pubringpath << std::endl; + std::cerr << "gpg path: " << gpgpath << std::endl; + std::cerr << "gpgv path: " << gpgvpath << std::endl; + std::cerr << "gpghome: " << gpghome << std::endl; + std::cerr << "pubringpath: " << pubringpath << std::endl; + std::cerr << "pubkeyspath: " << pubkeyspath << std::endl; } - if (stat(pubringpath.c_str(), &buff) != 0) - return (string("Couldn't access keyring: ") + strerror(errno)).c_str(); + if (stat(pubkeyspath.c_str(), &buff) != 0) + return (string("Couldn't access public keys directory ") + pubkeyspath +": " + strerror(errno)).c_str(); + if (! S_ISDIR(buff.st_mode)) + return (string("Public keys directory ") + pubkeyspath + " is not a directory: " + strerror(errno)).c_str(); + + if (stat(gpghome.c_str(), &buff) != 0) + return (string("Couldn't access GnuPGhome directory ") + gpghome +": " + strerror(errno)).c_str(); + if (! S_ISDIR(buff.st_mode)) + return (string("GnuPGhome ") + gpghome + " is not a directory: " + strerror(errno)).c_str(); + + + if (updateTrustedKeys(pubkeyspath, gpghome, pubringpath, gpgpath) == false) + return (string("Assembling trusted.gpg from trusted-keys/ failed.").c_str()); + if (pipe(fd) < 0) { @@ -71,7 +235,8 @@ if (_config->FindB("Debug::Acquire::gpgv", false)) { std::cerr << "Preparing to exec: " << gpgvpath - << " --status-fd 3 --keyring " << pubringpath + << " --status-fd 3 --homedir " << gpghome + << " --keyring " << pubringpath << " " << file << " " << outfile << std::endl; } int nullfd = open("/dev/null", O_RDONLY); @@ -85,7 +250,8 @@ putenv("LANG="); putenv("LC_ALL="); putenv("LC_MESSAGES="); - execlp(gpgvpath.c_str(), gpgvpath.c_str(), "--status-fd", "3", "--keyring", + execlp(gpgvpath.c_str(), gpgvpath.c_str(), "--status-fd", "3", + "--homedir", gpghome.c_str(), "--keyring", pubringpath.c_str(), file, outfile, NULL); exit(111); @@ -152,7 +318,7 @@ waitpid(pid, &status, 0); if (_config->FindB("Debug::Acquire::gpgv", false)) { - std::cerr <<"gpgv exited\n"; + std::cerr <<"gpgv exited" << std::endl; } if (WEXITSTATUS(status) == 0) Binary files apt-0.6.25/share/debian-archive.gpg and apt-0.6.25.1/share/debian-archive.gpg differ