The script pacman-key will manage pacman's keyring. It imports, exports, fetches from keyservers, helps in the process of trusting and updates the trust database. Signed-off-by: Denis A. Altoé Falqueto <denisfalqueto@gmail.com> --- scripts/.gitignore | 1 + scripts/Makefile.am | 3 + scripts/pacman-key.sh.in | 296 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 300 insertions(+), 0 deletions(-) create mode 100644 scripts/pacman-key.sh.in diff --git a/scripts/.gitignore b/scripts/.gitignore index eafc493..1c662de 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -4,3 +4,4 @@ rankmirrors repo-add repo-remove pkgdelta +pacman-key diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 31e8fb5..c81f703 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -7,6 +7,7 @@ bin_SCRIPTS = \ OURSCRIPTS = \ makepkg \ + pacman-key \ pacman-optimize \ pkgdelta \ rankmirrors \ @@ -14,6 +15,7 @@ OURSCRIPTS = \ EXTRA_DIST = \ makepkg.sh.in \ + pacman-key.sh.in \ pacman-optimize.sh.in \ pkgdelta.sh.in \ rankmirrors.sh.in \ @@ -60,6 +62,7 @@ $(OURSCRIPTS): Makefile @mv $@.tmp $@ makepkg: $(srcdir)/makepkg.sh.in +pacman-key: ${srcdir}/pacman-key.sh.in pacman-optimize: $(srcdir)/pacman-optimize.sh.in pkgdelta: $(srcdir)/pkgdelta.sh.in rankmirrors: $(srcdir)/rankmirrors.sh.in diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in new file mode 100644 index 0000000..5cb4066 --- /dev/null +++ b/scripts/pacman-key.sh.in @@ -0,0 +1,296 @@ +#!/bin/bash -e +# +# pacman-key - manages pacman's keyring +# @configure_input@ +# +# Copyright (c) 2010 - Denis A. Altoé Falqueto <denisfalqueto@gmail.com> +# +# 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, see <http://www.gnu.org/licenses/>. +# + +# gettext initialization +export TEXTDOMAIN='pacman' +export TEXTDOMAINDIR='@localedir@' + +# Based on apt-key, from Debian +# Author: Denis A. Altoé Falqueto <denisfalqueto at gmail dot com> +PACMAN_KEY_VERSION="@PACKAGE_VERSION@" + +# According to apt-key, gpg doesn't like to be called without a secret keyring. +# We will not really need one, because pacman will not sign packages, just verify +# their integrities. +PACMAN_SHARE_DIR="/usr/share/pacman" + +# Default parameters for the command gpg. Some more will be added when needed +GPG="gpg" +GPG_NOKEYRING="${GPG} --ignore-time-conflict --no-options --no-default-keyring" +SIG_EXT=".sig" + +# Read-only keyring with keys to be added to the keyring +ADDED_KEYS="${PACMAN_SHARE_DIR}/addedkeys.gpg" + +# Read-only keyring with keys removed from the keyring. They need to be removed before +# the keys from the added keyring be really imported +REMOVED_KEYS="${PACMAN_SHARE_DIR}/removedkeys.gpg" + +usage() { + echo "pacman-key - Pacman's keyring management utility" + echo "Usage: $(basename $0) [options] command [arguments]" + echo + echo "Manage pacman's list of trusted keys" + echo + echo "Options must be placed before commands. The abailable options are:" + echo " --config - set an alternative configuraton file to use. " + echo " Default is @sysconfdir@/pacman.conf" + echo " --gpgdir - set an alternativ home directory for gnupg. " + echo " Default is @sysconfdir@/pacman.d/gnupg" + echo + echo "The available commands are:" + echo " pacman-key add <file> ... - add the key contained in <file> ('-' for stdin)" + echo " pacman-key del <keyid> ... - remove the key <keyid>" + echo " pacman-key export <keyid> ... - output the key <keyid>" + echo " pacman-key exportall - output all trusted keys" + echo " pacman-key receive <keyserver> <keyid> ... - fetch the keyids from the specified keyserver URL" + echo " pacman-key trust <keyid> ... - set the truslevel of the given key" + echo " pacman-key updatedb - update the trustdb of pacman" + echo " pacman-key reload - reloads the keys from the keyring package" + echo " pacman-key list - list keys" + echo " pacman-key finger <keyid> ... - list fingerprints" + echo " pacman-key adv <params> - pass advanced options to gpg" + echo " pacman-key help - displays this message" + echo " pacman-key version - displays the current version" +} + +prepare_homedir() { + if [[ ! -d ${PACMAN_KEYRING_DIR} ]] ; then + mkdir -p "${PACMAN_KEYRING_DIR}" + [[ ! -f "${PACMAN_KEYRING_DIR}/secring.gpg" ]] && touch "${PACMAN_KEYRING_DIR}/secring.gpg" + [[ ! -f "${PACMAN_KEYRING_DIR}/pubring.gpg" ]] && touch "${PACMAN_KEYRING_DIR}/pubring.gpg" + chmod 700 "${PACMAN_KEYRING_DIR}" + chmod 600 "${PACMAN_KEYRING_DIR}"/* + fi +} + +add_key() { + ${GPG_PACMAN} --quiet --batch --import "$1" +} + +remove_key() { + ${GPG_PACMAN} --quiet --batch --delete-key --yes "$1" +} + +update_trustdb() { + ${GPG_PACMAN} --batch --check-trustdb +} + +list_sigs() { + ${GPG_PACMAN} --batch --list-sigs +} + +list_fingerprints() { + ${GPG_PACMAN} --batch --fingerprint $* +} + +export_key() { + ${GPG_PACMAN} --armor --export "$1" +} + +export_all() { + ${GPG_PACMAN} --armor --export +} + +trust_key() { + # Verify if the key exists in pacman's keyring + if ${GPG_PACMAN} --list-key "$1" > /dev/null 2>&1 ; then + ${GPG_PACMAN} --edit-key "$1" + else + echo >&2 "The key identified by $1 doesn't exist" + exit 1 + fi +} + +reload_keyring() { + # Verify the signature of removed keys file + if [[ -f ${REMOVED_KEYS} ]] && ! ${GPG_PACMAN} --quiet --verify ${REMOVED_KEYS}${SIG_EXT} ; then + echo >&2 "The signature of file ${REMOVED_KEYS} is not valid." + exit 1 + fi + + # Verify the signature of the added keys file + if [[ -f ${ADDED_KEYS} ]] && ! ${GPG_PACMAN} --quiet --verify ${ADDED_KEYS}${SIG_EXT} ; then + echo >&2 "The signature of file ${ADDED_KEYS} is not valid." + exit 1 + fi + + # Remove the keys from REMOVED_KEYS keyring + [[ -r ${REMOVED_KEYS} ]] && cat "${REMOVED_KEYS}" | while read key ; do + ${GPG_PACMAN} --quiet --batch --yes --delete-keys ${key} + done + + # Add keys from the current set of keys from pacman-keyring package. The web of trust will + # be updated automatically. + if [[ -r ${ADDED_KEYS} ]] ; then + add_keys=$(${GPG_NOKEYRING} --keyring ${ADDED_KEYS} --with-colons --list-keys | grep ^pub | cut -d: -f5) + for add_key in $add_keys; do + ${GPG_NOKEYRING} --quiet --batch --keyring $ADDED_KEYS --export $add_key | ${GPG_PACMAN} --import + done + fi + + # Update trustdb, just to be sure + update_trustdb +} + +receive() { + keyserver="$1" + shift + ${GPG_PACMAN} --keyserver ${keyserver} $* +} + +# PROGRAM START + +if ! type gettext &>/dev/null; then + gettext() { + echo "$@" + } +fi + +if [[ "$command" != "version" && "$command" != "help" ]] && ! which "${GPG}" >/dev/null 2>&1; then + echo >&2 "Warning: gnupg does not seem to be installed." + echo >&2 "Warning: pacman-key requires gnupg for most operations." + echo >&2 + exit 1 +fi + +# Parse global options +CONFIG="@sysconfdir@/pacman.conf" +PACMAN_KEYRING_DIR="@sysconfdir@/pacman.d/gnupg" +while [[ $1 =~ ^- ]] ; do + case "$1" in + --config) shift; CONFIG="$1" ;; + --gpgdir) shift; PACMAN_KEYRING_DIR="$1" ;; + esac + shift +done + +if [[ ! -r "$CONFIG" ]] ; then + echo >&2 "It is not possible to read $CONFIG." + exit 1 +fi +# Read GPGDIR from $CONFIG +GPGDIR=$(grep "^ *GPGDir *=" "$CONFIG" | cut -d= -f2) +if [[ "$GPGDIR" ]] ; then + PACMAN_KEYRING_DIR="$GPGDIR" +fi +GPG_PACMAN="${GPG} --homedir ${PACMAN_KEYRING_DIR}" + +prepare_homedir + +# Parse and execute command +command="$1" +if [[ -z "$command" ]]; then + usage + exit 1 +fi +shift + +case "$command" in + add) + if (( $# == 0 )) ; then + echo >&2 "You need to specify at least one key identifier" + usage + exit 1 + fi + while (( $# > 0 )) ; do + add_key $1 + shift + done + ;; + del|rm|remove) + if (( $# == 0 )) ; then + echo >&2 "You need to specify at least one key identifier" + usage + exit 1 + fi + while (( $# > 0 )) ; do + remove_key $1 + shift + done + ;; + updatedb) + update_trustdb + ;; + reload) + reload_keyring + ;; + list) + list_sigs + ;; + finger*) + if (( $# == 0 )) ; then + echo >&2 "You need to specify at least one key identifier" + usage + exit 1 + fi + list_fingerprints $* + ;; + export) + if (( $# == 0 )) ; then + echo >&2 "You need to specify at least one key identifier" + usage + exit 1 + fi + while (( $# > 0 )) ; do + export_key $1 + shift + done + ;; + exportall) + export_all + ;; + receive) + if (( $# < 2 )) ; then + echo >&2 "You need to specify the keyserver and at least one key identifier" + usage + exit 1 + fi + receive $* + ;; + trust) + if (( $# == 0 )) ; then + echo >&2 "You need to specify at least one key identifier" + usage + exit 1 + fi + while (( $# > 0 )) ; do + trust_key $1 + shift + done + ;; + adv*) + echo "Executing: ${GPG_PACMAN} $*" + ${GPG_PACMAN} $* || ret=$? + exit $ret + ;; + --help) + usage + ;; + --version) + echo "pacman-key v${PACMAN_KEY_VERSION}" + echo " This program can be freely distributed under the GPL v2" + ;; + *) + usage + exit 1 + ;; +esac -- 1.7.1.1