[pacman-dev] [PATCH 0/6] Package signing patches
This is a series of patches which can hopefully take package signing a small step forward. Patch 1/6 lets pacman -v print the GPG Dir Patch 2/6 updates the pacman manpage's --gpgdir section and adds a commented GPGDir option in pacman.conf which shows the user the default gpgdir. Patch 3/6 updates Makefile.am to create the default gpgdir, pubring.gpg and trustdb.gpg if they do not exist. Patch 4/6 adds a --verify option to pacman which lets the user control the level of signature verification. Valid arguments to --verify include "always", "optional", "never". Think of this as a way to override the "VerifySig" option in pacman.conf . In addition Patch 4/6 updates configure.ac to output gpgdir at the end of ./configure. Patch 5/6 updates the help text of pacman-key with regards to --gpgdir. Patch 6/6 adds a --import-trustdb option to pacman-key. This allows the user to import a selected trustdb upon confirmation. For Patch 6/6, Bash is not really my strong point and I took quite some time to get it right. Please help me check it. Thanks! Pang Yan Han (6): Let pacman -v print GPG Dir Update pacman manpage and pacman.conf for gpgdir Update Makefile.am and configure.ac for gpgdir Add --verify option for signature level pacman-key: print default gpgdir in usage pacman-key: add --import-trustdb option Makefile.am | 7 +++- configure.ac | 1 + doc/pacman-key.8.txt | 4 ++ doc/pacman.8.txt | 16 ++++++--- etc/pacman.conf.in | 1 + scripts/pacman-key.sh.in | 83 +++++++++++++++++++++++++++++++++++++++++++++- src/pacman/conf.h | 3 +- src/pacman/pacman.c | 16 +++++++++ 8 files changed, 122 insertions(+), 9 deletions(-) -- 1.7.5.rc0.101.g3d23c
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- src/pacman/pacman.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 008a806..8458c97 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -913,6 +913,7 @@ int main(int argc, char *argv[]) printf("\n"); printf("Lock File : %s\n", alpm_option_get_lockfile()); printf("Log File : %s\n", alpm_option_get_logfile()); + printf("GPG Dir : %s\n", alpm_option_get_signaturedir()); list_display("Targets :", pm_targets); } -- 1.7.5.rc0.101.g3d23c
On Sat 28 May 2011 at 22:37 +0800, Pang Yan Han wrote:
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- src/pacman/pacman.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 008a806..8458c97 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -913,6 +913,7 @@ int main(int argc, char *argv[]) printf("\n"); printf("Lock File : %s\n", alpm_option_get_lockfile()); printf("Log File : %s\n", alpm_option_get_logfile()); + printf("GPG Dir : %s\n", alpm_option_get_signaturedir()); list_display("Targets :", pm_targets); }
This one looks OK to me.
On 29/05/11 00:37, Pang Yan Han wrote:
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com> --- src/pacman/pacman.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 008a806..8458c97 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -913,6 +913,7 @@ int main(int argc, char *argv[]) printf("\n"); printf("Lock File : %s\n", alpm_option_get_lockfile()); printf("Log File : %s\n", alpm_option_get_logfile()); + printf("GPG Dir : %s\n", alpm_option_get_signaturedir()); list_display("Targets :", pm_targets); }
Signed-off-by: Allan
pacman.8.txt --gpgdir section is updated based on the pacman.conf manpage pacman.conf is updated to include the default GPGDir Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman.8.txt | 11 ++++++----- etc/pacman.conf.in | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 6270dbd..aec7fd1 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -150,11 +150,12 @@ Options to be used. *\--gpgdir* <dir>:: - Specify a directory of files used by GnuPG to verify package signatures. - This directory should contain two files: `pubring.gpg` and `trustdb.gpg`. - `pubring.gpg` holds the public keys of all packagers. `trustdb.gpg` - contains a so-called trust database, which specifies that the keys are - authentic and trusted. + Specify a directory of files used by GnuPG to verify package signatures (a + typical default is `{sysconfdir}/pacman.d/gnupg`). This directory should contain + two files: `pubring.gpg` and `trustdb.gpg`. `pubring.gpg` holds the public keys + of all packagers. `trustdb.gpg` contains a so-called trust database, which + specifies that the keys are authentic and trusted. *NOTE*: this is an absolute + path, the root path is not automatically prepended. *\--logfile* <file>:: Specify an alternate log file. This is an absolute path, regardless of diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 7b8501c..1d49fd7 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -13,6 +13,7 @@ #DBPath = @localstatedir@/lib/pacman/ #CacheDir = @localstatedir@/cache/pacman/pkg/ #LogFile = @localstatedir@/log/pacman.log +#GPGDir = @sysconfdir@/pacman.d/gnupg/ HoldPkg = pacman glibc # If upgrades are available for these packages they will be asked for first SyncFirst = pacman -- 1.7.5.rc0.101.g3d23c
On Sat, May 28, 2011 at 9:37 AM, Pang Yan Han <pangyanhan@gmail.com> wrote:
pacman.8.txt --gpgdir section is updated based on the pacman.conf manpage
pacman.conf is updated to include the default GPGDir
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman.8.txt | 11 ++++++----- etc/pacman.conf.in | 1 + 2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 6270dbd..aec7fd1 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -150,11 +150,12 @@ Options to be used.
*\--gpgdir* <dir>:: - Specify a directory of files used by GnuPG to verify package signatures. - This directory should contain two files: `pubring.gpg` and `trustdb.gpg`. - `pubring.gpg` holds the public keys of all packagers. `trustdb.gpg` - contains a so-called trust database, which specifies that the keys are - authentic and trusted. + Specify a directory of files used by GnuPG to verify package signatures (a + typical default is `{sysconfdir}/pacman.d/gnupg`). This directory should contain + two files: `pubring.gpg` and `trustdb.gpg`. `pubring.gpg` holds the public keys + of all packagers. `trustdb.gpg` contains a so-called trust database, which + specifies that the keys are authentic and trusted. *NOTE*: this is an absolute + path, the root path is not automatically prepended.
Looks good; of course this unearths another bug where we aren't properly substituting variables anymore (obvious online, but also in generated manpages too): http://www.archlinux.org/pacman/pacman.conf.5.html#_options
*\--logfile* <file>:: Specify an alternate log file. This is an absolute path, regardless of diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 7b8501c..1d49fd7 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -13,6 +13,7 @@ #DBPath = @localstatedir@/lib/pacman/ #CacheDir = @localstatedir@/cache/pacman/pkg/ #LogFile = @localstatedir@/log/pacman.log +#GPGDir = @sysconfdir@/pacman.d/gnupg/
I think I'll move it above LogFile only to keep the Dir configs together, but this works.
HoldPkg = pacman glibc # If upgrades are available for these packages they will be asked for first SyncFirst = pacman -- 1.7.5.rc0.101.g3d23c
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist. configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc) Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- Makefile.am | 7 +++++-- configure.ac | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 259a455..edae191 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,10 +24,13 @@ check-local: test/pacman test/util src/pacman src/util $(SH) $(top_srcdir)/test/util/vercmptest.sh \ $(top_builddir)/src/util/vercmp -# create the pacman DB and cache directories upon install +# create the pacman DB, cache and GPG directories, trustdb.gpg, pubring.gpg upon install install-data-local: - for dir in "$(DESTDIR)$(localstatedir)/lib/pacman" "$(DESTDIR)$(localstatedir)/cache/pacman/pkg"; do \ + for dir in "$(DESTDIR)$(localstatedir)/lib/pacman" "$(DESTDIR)$(localstatedir)/cache/pacman/pkg" "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done + for f in "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg/pubring.gpg" "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg/trustdb.gpg"; do \ + test -e "$$f" || touch "$$f"; \ + done # vim:set ts=2 sw=2 noet: diff --git a/configure.ac b/configure.ac index 02f9f40..6422f57 100644 --- a/configure.ac +++ b/configure.ac @@ -394,6 +394,7 @@ ${PACKAGE_NAME}: prefix : ${prefix} sysconfdir : $(eval echo ${sysconfdir}) conf file : $(eval echo ${sysconfdir})/pacman.conf + gpg dir : $(eval echo ${sysconfdir})/pacman.d/gnupg/ localstatedir : $(eval echo ${localstatedir}) database dir : $(eval echo ${localstatedir})/lib/pacman/ cache dir : $(eval echo ${localstatedir})/cache/pacman/pkg/ -- 1.7.5.rc0.101.g3d23c
Am 28.05.2011 16:37, schrieb Pang Yan Han:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- Makefile.am | 7 +++++-- configure.ac | 1 + 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/Makefile.am b/Makefile.am index 259a455..edae191 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,10 +24,13 @@ check-local: test/pacman test/util src/pacman src/util $(SH) $(top_srcdir)/test/util/vercmptest.sh \ $(top_builddir)/src/util/vercmp
-# create the pacman DB and cache directories upon install +# create the pacman DB, cache and GPG directories, trustdb.gpg, pubring.gpg upon install install-data-local: - for dir in "$(DESTDIR)$(localstatedir)/lib/pacman" "$(DESTDIR)$(localstatedir)/cache/pacman/pkg"; do \ + for dir in "$(DESTDIR)$(localstatedir)/lib/pacman" "$(DESTDIR)$(localstatedir)/cache/pacman/pkg" "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done + for f in "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg/pubring.gpg" "$(DESTDIR)$(sysconfdir)/pacman.d/gnupg/trustdb.gpg"; do \ + test -e "$$f" || touch "$$f"; \ + done
# vim:set ts=2 sw=2 noet: diff --git a/configure.ac b/configure.ac index 02f9f40..6422f57 100644 --- a/configure.ac +++ b/configure.ac @@ -394,6 +394,7 @@ ${PACKAGE_NAME}: prefix : ${prefix} sysconfdir : $(eval echo ${sysconfdir}) conf file : $(eval echo ${sysconfdir})/pacman.conf + gpg dir : $(eval echo ${sysconfdir})/pacman.d/gnupg/ localstatedir : $(eval echo ${localstatedir}) database dir : $(eval echo ${localstatedir})/lib/pacman/ cache dir : $(eval echo ${localstatedir})/cache/pacman/pkg/
The path should be changeable and have another default value IMO. Directories named "*.d" are typically dirs containing files for the same purpose that are read in glob order by a single tool, some examples: /etc/xinetd.d /etc/httpd/conf.d /etc/pam.d /etc/grub.d /etc/bash_completion.d /etc/ld.so.conf.d /etc/rsyslog.d /etc/udev/rules.d We should not use a .d suffix if a directory contains many files for many different things which is the case for pacman.d here... rankmirrors.sh and corresponding config-lines in pacman.conf are also misusing the .d suffix right now... I prepare some patches for that in the next few days. Marc
On 29/05/11 00:37, Pang Yan Han wrote:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com>
What about creating secring.gpg too. Not that it is used, but GPG has issues with it not being present. Also, does "touch trustdb.gpg" actually create a valid trustdb? From memory, a blank trustdb is invalid and it must be created by gpg. Allan
On Wed, Jun 1, 2011 at 5:23 PM, Allan McRae <allan@archlinux.org> wrote:
On 29/05/11 00:37, Pang Yan Han wrote:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com>
What about creating secring.gpg too. Not that it is used, but GPG has issues with it not being present.
Also, does "touch trustdb.gpg" actually create a valid trustdb? From memory, a blank trustdb is invalid and it must be created by gpg.
Allan
Hi Allan,
I'm not sure about this. I just thought that we should have the files present at the very least.
On Wed, Jun 1, 2011 at 4:23 AM, Allan McRae <allan@archlinux.org> wrote:
On 29/05/11 00:37, Pang Yan Han wrote:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com>
What about creating secring.gpg too. Not that it is used, but GPG has issues with it not being present.
Also, does "touch trustdb.gpg" actually create a valid trustdb? From memory, a blank trustdb is invalid and it must be created by gpg.
Rather than "touch", why wouldn't one just invoke gpg once to create these files? (if we want to do this at all, that is, which I'm not sure is the case) -Dan
On 02/06/11 04:09, Dan McGee wrote:
On Wed, Jun 1, 2011 at 4:23 AM, Allan McRae<allan@archlinux.org> wrote:
On 29/05/11 00:37, Pang Yan Han wrote:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com>
What about creating secring.gpg too. Not that it is used, but GPG has issues with it not being present.
Also, does "touch trustdb.gpg" actually create a valid trustdb? From memory, a blank trustdb is invalid and it must be created by gpg.
Rather than "touch", why wouldn't one just invoke gpg once to create these files? (if we want to do this at all, that is, which I'm not sure is the case)
Just to confirm, touch trustdb.gpg leads to issues: gpg: fatal: /etc/pacman.d/gnupg/trustdb.gpg: invalid trustdb Allan
Hi guys, sorry for the late reply. A lot of things cropped up over the past week. I guess this patch was a mistake. My original intent was for the files to be there since there hasn't been much discussion as to how we will distribute the actual pubring.gpg and trustdb.gpg files. Thanks for the feedback though. =) Dan is right in that gpg should be invoked to create the files if we really want to do it. On Wed, Jun 8, 2011 at 7:59 AM, Allan McRae <allan@archlinux.org> wrote:
On 02/06/11 04:09, Dan McGee wrote:
On Wed, Jun 1, 2011 at 4:23 AM, Allan McRae<allan@archlinux.org> wrote:
On 29/05/11 00:37, Pang Yan Han wrote:
install-data-local target in Makefile.am will now create the default GPGDir, trustdb.gpg, pubring.gpg if they do not exist.
configure script will now output the default gpgdir with the other info (eg. database dir, cachedir, etc)
Signed-off-by: Pang Yan Han<pangyanhan@gmail.com>
What about creating secring.gpg too. Not that it is used, but GPG has issues with it not being present.
Also, does "touch trustdb.gpg" actually create a valid trustdb? From memory, a blank trustdb is invalid and it must be created by gpg.
Rather than "touch", why wouldn't one just invoke gpg once to create these files? (if we want to do this at all, that is, which I'm not sure is the case)
Just to confirm, touch trustdb.gpg leads to issues: gpg: fatal: /etc/pacman.d/gnupg/trustdb.gpg: invalid trustdb
Allan
On Wed, Jun 8, 2011 at 9:52 PM, Pang Yan Han <pangyanhan@gmail.com> wrote:
Hi guys, sorry for the late reply. A lot of things cropped up over the past week. Never worry about that, we all get busy with things.
I guess this patch was a mistake. My original intent was for the files to be there since there hasn't been much discussion as to how we will distribute the actual pubring.gpg and trustdb.gpg files.
Thanks for the feedback though. =)
Dan is right in that gpg should be invoked to create the files if we really want to do it.
I think this at least got us to take a look at the problem you were trying to solve, so don't feel bad submitting it- we have a better idea of what we might need to do now to get things set up. -Dan
The --verify option allows the user to change pacman's default signature verification level. It must take in one of "always", "optional" and "verify". Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman.8.txt | 5 +++++ src/pacman/conf.h | 3 ++- src/pacman/pacman.c | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 1 deletions(-) diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index aec7fd1..453c446 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -165,6 +165,11 @@ Options Bypass any and all ``Are you sure?'' messages. It's not a good idea to do this unless you want to run pacman from a script. +*\--verify* <level>:: + Sets the default signature verification level to <level>. Valid values for level + are "never", "optional" and "always". This can be used to override the "VerifySig" + option in linkman:pacman.conf[5]. + Transaction Options (apply to '-S', '-R' and '-U') -------------------------------------------------- *-d, \--nodeps*:: diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 76c76cf..f741ae6 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -111,7 +111,8 @@ enum { OP_ASEXPLICIT, OP_ARCH, OP_PRINTFORMAT, - OP_GPGDIR + OP_GPGDIR, + OP_VERIFY }; /* clean method */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 8458c97..13dded1 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -438,6 +438,20 @@ static int parsearg_global(int opt) config->logfile = strndup(optarg, PATH_MAX); break; case OP_NOCONFIRM: config->noconfirm = 1; break; + case OP_VERIFY: + if (!strcmp(optarg, "always")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_ALWAYS); + } else if (!strcmp(optarg, "optional")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_OPTIONAL); + } else if (!strcmp(optarg, "never")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_NEVER); + } else { + pm_printf(PM_LOG_ERROR, _("'%s' is not a valid verify level\n"), + optarg); + return 1; + } + + break; case 'b': check_optarg(); config->dbpath = strdup(optarg); @@ -635,6 +649,7 @@ static int parseargs(int argc, char *argv[]) {"arch", required_argument, 0, OP_ARCH}, {"print-format", required_argument, 0, OP_PRINTFORMAT}, {"gpgdir", required_argument, 0, OP_GPGDIR}, + {"verify", required_argument, 0, OP_VERIFY}, {0, 0, 0, 0} }; -- 1.7.5.rc0.101.g3d23c
On Sat 28 May 2011 at 22:37 +0800, Pang Yan Han wrote:
+ case OP_VERIFY: + if (!strcmp(optarg, "always")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_ALWAYS); + } else if (!strcmp(optarg, "optional")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_OPTIONAL); + } else if (!strcmp(optarg, "never")) { + alpm_option_set_default_sigverify(PM_PGP_VERIFY_NEVER); + } else { + pm_printf(PM_LOG_ERROR, _("'%s' is not a valid verify level\n"), + optarg); + return 1; + } + + break;
You could have used the option_verifysig() function from conf.c. Maybe it would be better to store that value in a new field of the config structure (same thing in conf.c) so that it would get applied in a similar way as with setlibpaths(). -- Rémy.
Sorry I'll resend this. On Sun, May 29, 2011 at 4:52 PM, Pang Yan Han <pangyanhan@gmail.com> wrote:
---------- Forwarded message ---------- From: Pang Yan Han <pangyanhan@gmail.com> To: Date: Sun, 29 May 2011 16:39:50 +0800 Subject: [PATCH 4/6] Add --verify option for signature level The --verify option allows the user to change pacman's default signature verification level. It can take in one of "Always", "Optional" or "Verify".
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- src/pacman/conf.c | 14 ++++++++++++++ src/pacman/conf.h | 4 +++- src/pacman/pacman.c | 4 ++++ 3 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 370ec51..869c005 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -68,6 +68,7 @@ int config_free(config_t *oldconfig) free(oldconfig->rootdir); free(oldconfig->dbpath); free(oldconfig->logfile); + free(oldconfig->sigverify); free(oldconfig->xfercommand); free(oldconfig->print_format); free(oldconfig); @@ -474,6 +475,19 @@ static int setlibpaths(void) } }
+ /* Set the signature verification level to what the user requested */ + if(config->sigverify) { + pgp_verify_t verify = option_verifysig(config->sigverify); + if (verify != PM_PGP_VERIFY_UNKNOWN) { + ret = alpm_option_set_default_sigverify(verify); + if(ret != 0) { + pm_printf(PM_LOG_ERROR, _("problem setting sigverify '%s' (%s)\n"), + config->sigverify, alpm_strerrorlast()); + return ret; + } + } + } + /* add a default cachedir if one wasn't specified */ if(alpm_option_get_cachedirs() == NULL) { alpm_option_add_cachedir(CACHEDIR); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 76c76cf..d08f83c 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -41,6 +41,7 @@ typedef struct __config_t { char *dbpath; char *logfile; char *gpgdir; + char *sigverify; /* TODO how to handle cachedirs? */
unsigned short op_q_isfile; @@ -111,7 +112,8 @@ enum { OP_ASEXPLICIT, OP_ARCH, OP_PRINTFORMAT, - OP_GPGDIR + OP_GPGDIR, + OP_VERIFY };
/* clean method */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 8458c97..1e58890 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -438,6 +438,9 @@ static int parsearg_global(int opt) config->logfile = strndup(optarg, PATH_MAX); break; case OP_NOCONFIRM: config->noconfirm = 1; break; + case OP_VERIFY: + config->sigverify = strdup(optarg); + break; case 'b': check_optarg(); config->dbpath = strdup(optarg); @@ -635,6 +638,7 @@ static int parseargs(int argc, char *argv[]) {"arch", required_argument, 0, OP_ARCH}, {"print-format", required_argument, 0, OP_PRINTFORMAT}, {"gpgdir", required_argument, 0, OP_GPGDIR}, + {"verify", required_argument, 0, OP_VERIFY}, {0, 0, 0, 0} };
-- 1.7.5.rc0.101.g3d23c
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- scripts/pacman-key.sh.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index c092989..e795aad 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -56,7 +56,7 @@ usage() { echo echo "$(gettext "Options must be placed before commands. The available options are:")" printf "$(gettext " --config <file> Use an alternate config file (instead of '%s')")\n" "$CONFIG" - echo "$(gettext " --gpgdir Set an alternate directory for gnupg")" + printf "$(gettext " --gpgdir Set an alternate directory for gnupg (instead of '%s')")\n" "$PACMAN_KEYRING_DIR" echo echo "$(gettext "The available commands are:")" echo "$(gettext " -a, --add [<file(s)>] Add the specified keys (empty for stdin)")" -- 1.7.5.rc0.101.g3d23c
On Sat, May 28, 2011 at 9:37 AM, Pang Yan Han <pangyanhan@gmail.com> wrote:
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> Thanks!
--- scripts/pacman-key.sh.in | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index c092989..e795aad 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -56,7 +56,7 @@ usage() { echo echo "$(gettext "Options must be placed before commands. The available options are:")" printf "$(gettext " --config <file> Use an alternate config file (instead of '%s')")\n" "$CONFIG" - echo "$(gettext " --gpgdir Set an alternate directory for gnupg")" + printf "$(gettext " --gpgdir Set an alternate directory for gnupg (instead of '%s')")\n" "$PACMAN_KEYRING_DIR" echo echo "$(gettext "The available commands are:")" echo "$(gettext " -a, --add [<file(s)>] Add the specified keys (empty for stdin)")" -- 1.7.5.rc0.101.g3d23c
When pacman is installed, an empty trustdb is created if it is non-existent. The --import-trustdb option allows users to import their own trustdb into pacman's gpgdir to facilitate signature verification. Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman-key.8.txt | 4 ++ scripts/pacman-key.sh.in | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 0 deletions(-) diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index 8a08480..234e060 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -59,6 +59,10 @@ Commands *-h, \--help*:: Output syntax and command line options. +*\--import-trustdb* <db>:: + Overrides the trustdb with db. Confirmation from the user is required before + the trustdb is overwritten, unless the trustdb is empty or non-existent. + *-l, \--list*:: Equivalent to --list-sigs from GnuPG. diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index e795aad..7a1fa42 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -70,10 +70,26 @@ usage() { echo "$(gettext " -u, --updatedb Update the trustdb of pacman")" echo "$(gettext " -V, --version Show program version")" echo "$(gettext " --adv <params> Use pacman's keyring with advanced gpg commands")" + echo "$(gettext " --import-trustdb <db> Override pacman's trustdb")" printf "$(gettext " --reload Reload the default keys")" echo } +## From makepkg +# usage: in_array( $needle, $haystack ) +# return : 0 - found +# 1 - not found +## +in_array() { + local needle=$1; shift + [[ -z $1 ]] && return 1 # Not found + local item + for item in "$@"; do + [[ $item = $needle ]] && return 0 # Found + done + return 1 # Not found +} + version() { printf "pacman-key (pacman) %s\n" "${myver}" printf "$(gettext "\ @@ -228,6 +244,56 @@ if [[ $1 != "--version" && $1 != "-V" && $1 != "--help" && $1 != "-h" && $1 != " fi fi +import_trustdb() { + local choice= + local valid_choices=('n' 'no' 'y' 'yes') + + warning "$(gettext "This option will overwrite your existing trustdb at $PACMAN_KEYRING_DIR/trustdb.gpg with a new one.")" + + while ! in_array "$choice" "${valid_choices[@]}"; do + echo -n "$(gettext "==> Do you wish to continue (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done + + if [[ $choice = 'n' || $choice = 'no' ]]; then + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + exit 0 + fi + + # Reset choice + choice= + echo + + if [[ ! -e "${PACMAN_KEYRING_DIR}/trustdb.gpg" ]]; then + msg "$(gettext "No trustdb found at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + elif [[ $(stat -c "%s" "${PACMAN_KEYRING_DIR}/trustdb.gpg") = "0" ]]; then + msg "$(gettext "Empty trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + else + warning "$(gettext "trustdb at \"${PACMAN_KEYRING_DIR}/trustdb.gpg\" is not empty.")" + while ! in_array "$choice" "${valid_choices[@]}" ; do + echo -n "$(gettext "==> Do you wish to overwrite your pacman trustdb? (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done + + echo + if [[ $choice = 'y' || $choice = 'yes' ]]; then + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + else + msg "$(gettext "$1 is not imported")" + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + fi + fi +} + # Parse global options CONFIG="@sysconfdir@/pacman.conf" PACMAN_KEYRING_DIR="@sysconfdir@/pacman.d/gnupg" @@ -322,6 +388,21 @@ case "${command}" in ;; -h|--help) usage; exit 0 ;; + --import-trustdb) + if (( $# != 1 )); then + error "$(gettext "You need to specify exactly one trustdb!")" + exit 1 + elif [[ ! -e $1 ]]; then + error "$(gettext "$1 does not exist!")" + exit 1 + elif [[ -d $1 ]]; then + error "$(gettext "$1 is a directory and cannot be imported!")" + exit 1 + fi + + import_trustdb $1 + + ;; -V|--version) version; exit 0 ;; *) -- 1.7.5.rc0.101.g3d23c
On Sat, May 28, 2011 at 9:37 AM, Pang Yan Han <pangyanhan@gmail.com> wrote:
When pacman is installed, an empty trustdb is created if it is non-existent. The --import-trustdb option allows users to import their own trustdb into pacman's gpgdir to facilitate signature verification.
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman-key.8.txt | 4 ++ scripts/pacman-key.sh.in | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 0 deletions(-)
diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index 8a08480..234e060 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -59,6 +59,10 @@ Commands *-h, \--help*:: Output syntax and command line options.
+*\--import-trustdb* <db>:: + Overrides the trustdb with db. Confirmation from the user is required before + the trustdb is overwritten, unless the trustdb is empty or non-existent. + *-l, \--list*:: Equivalent to --list-sigs from GnuPG.
diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index e795aad..7a1fa42 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -70,10 +70,26 @@ usage() { echo "$(gettext " -u, --updatedb Update the trustdb of pacman")" echo "$(gettext " -V, --version Show program version")" echo "$(gettext " --adv <params> Use pacman's keyring with advanced gpg commands")" + echo "$(gettext " --import-trustdb <db> Override pacman's trustdb")" printf "$(gettext " --reload Reload the default keys")" echo }
+## From makepkg +# usage: in_array( $needle, $haystack ) +# return : 0 - found +# 1 - not found +## +in_array() { + local needle=$1; shift + [[ -z $1 ]] && return 1 # Not found + local item + for item in "$@"; do + [[ $item = $needle ]] && return 0 # Found + done + return 1 # Not found +} + version() { printf "pacman-key (pacman) %s\n" "${myver}" printf "$(gettext "\ @@ -228,6 +244,56 @@ if [[ $1 != "--version" && $1 != "-V" && $1 != "--help" && $1 != "-h" && $1 != " fi fi
+import_trustdb() { + local choice= + local valid_choices=('n' 'no' 'y' 'yes') + + warning "$(gettext "This option will overwrite your existing trustdb at $PACMAN_KEYRING_DIR/trustdb.gpg with a new one.")" + + while ! in_array "$choice" "${valid_choices[@]}"; do + echo -n "$(gettext "==> Do you wish to continue (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done + + if [[ $choice = 'n' || $choice = 'no' ]]; then + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + exit 0 + fi Hmm. None of this works for translated messages. Please follow the
The name "import" leads me to believe it doesn't overwrite, but I think this in fact does that. Is there any way we can actually do a merge of the existing with the trust db one is pulling from? pattern established in makepkg in the CLEANCACHE code (line ~1810). This way the same strings can be used for gettext, and "N" is the obvious default, which I think it should be. You also didn't translate 'n' or 'no'; we should just use the Y/YES from makepkg over again. Don't even worry about the valid choice stuff; if you don't type y or yes, you lose. I'd also ditch the unnecessary "is preserved" message unless other people think it is required.
+ + # Reset choice + choice= + echo + + if [[ ! -e "${PACMAN_KEYRING_DIR}/trustdb.gpg" ]]; then + msg "$(gettext "No trustdb found at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + elif [[ $(stat -c "%s" "${PACMAN_KEYRING_DIR}/trustdb.gpg") = "0" ]]; then + msg "$(gettext "Empty trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" I don't think this is the proper way to move owner trust values around- shouldn't we be using a combo and pipe of --export-ownertrust and --import-ownertrust?
+ else + warning "$(gettext "trustdb at \"${PACMAN_KEYRING_DIR}/trustdb.gpg\" is not empty.")" + while ! in_array "$choice" "${valid_choices[@]}" ; do + echo -n "$(gettext "==> Do you wish to overwrite your pacman trustdb? (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done Wait- why do we have two questions for this? Seems totally silly to me. If I tell you to import and I have nothing, you should just do it. If we determine we don't overwrite owner trust values via export/import (but amend), then we shouldn't do questions at all.
+ + echo + if [[ $choice = 'y' || $choice = 'yes' ]]; then + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + else + msg "$(gettext "$1 is not imported")" + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + fi + fi +} + # Parse global options CONFIG="@sysconfdir@/pacman.conf" PACMAN_KEYRING_DIR="@sysconfdir@/pacman.d/gnupg" @@ -322,6 +388,21 @@ case "${command}" in ;; -h|--help) usage; exit 0 ;; + --import-trustdb) + if (( $# != 1 )); then + error "$(gettext "You need to specify exactly one trustdb!")" We don't use exclamation points on other messages in this section, so we shouldn't start the trend here.
+ exit 1 + elif [[ ! -e $1 ]]; then + error "$(gettext "$1 does not exist!")" + exit 1 + elif [[ -d $1 ]]; then + error "$(gettext "$1 is a directory and cannot be imported!")" + exit 1 Why not just one -f check and a single "%s is not a trust DB file" message? Also, don't use $1 directly in gettext, you need to use substitution vars as is done everywhere else.
+ fi + + import_trustdb $1 + + ;; -V|--version) version; exit 0 ;; *) -- 1.7.5.rc0.101.g3d23c
Hi Dan, sorry for the late reply, some family matters cropped up over the past week. Do you think I should reroll this with your suggestions? iirc, the original intent of this patch was to allow the user to have a way to have a trustdb.gpg for pacman to carry out signature verification and to change it if need be. On Thu, Jun 2, 2011 at 2:02 AM, Dan McGee <dpmcgee@gmail.com> wrote:
On Sat, May 28, 2011 at 9:37 AM, Pang Yan Han <pangyanhan@gmail.com> wrote:
When pacman is installed, an empty trustdb is created if it is non-existent. The --import-trustdb option allows users to import their own trustdb into pacman's gpgdir to facilitate signature verification.
The name "import" leads me to believe it doesn't overwrite, but I think this in fact does that. Is there any way we can actually do a merge of the existing with the trust db one is pulling from?
Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- doc/pacman-key.8.txt | 4 ++ scripts/pacman-key.sh.in | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 0 deletions(-)
diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index 8a08480..234e060 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -59,6 +59,10 @@ Commands *-h, \--help*:: Output syntax and command line options.
+*\--import-trustdb* <db>:: + Overrides the trustdb with db. Confirmation from the user is required before + the trustdb is overwritten, unless the trustdb is empty or non-existent. + *-l, \--list*:: Equivalent to --list-sigs from GnuPG.
diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index e795aad..7a1fa42 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -70,10 +70,26 @@ usage() { echo "$(gettext " -u, --updatedb Update the trustdb of pacman")" echo "$(gettext " -V, --version Show program version")" echo "$(gettext " --adv <params> Use pacman's keyring with advanced gpg commands")" + echo "$(gettext " --import-trustdb <db> Override pacman's trustdb")" printf "$(gettext " --reload Reload the default keys")" echo }
+## From makepkg +# usage: in_array( $needle, $haystack ) +# return : 0 - found +# 1 - not found +## +in_array() { + local needle=$1; shift + [[ -z $1 ]] && return 1 # Not found + local item + for item in "$@"; do + [[ $item = $needle ]] && return 0 # Found + done + return 1 # Not found +} + version() { printf "pacman-key (pacman) %s\n" "${myver}" printf "$(gettext "\ @@ -228,6 +244,56 @@ if [[ $1 != "--version" && $1 != "-V" && $1 != "--help" && $1 != "-h" && $1 != " fi fi
+import_trustdb() { + local choice= + local valid_choices=('n' 'no' 'y' 'yes') + + warning "$(gettext "This option will overwrite your existing trustdb at $PACMAN_KEYRING_DIR/trustdb.gpg with a new one.")" + + while ! in_array "$choice" "${valid_choices[@]}"; do + echo -n "$(gettext "==> Do you wish to continue (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done + + if [[ $choice = 'n' || $choice = 'no' ]]; then + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + exit 0 + fi Hmm. None of this works for translated messages. Please follow the pattern established in makepkg in the CLEANCACHE code (line ~1810). This way the same strings can be used for gettext, and "N" is the obvious default, which I think it should be. You also didn't translate 'n' or 'no'; we should just use the Y/YES from makepkg over again. Don't even worry about the valid choice stuff; if you don't type y or yes, you lose.
I'd also ditch the unnecessary "is preserved" message unless other people think it is required.
+ + # Reset choice + choice= + echo + + if [[ ! -e "${PACMAN_KEYRING_DIR}/trustdb.gpg" ]]; then + msg "$(gettext "No trustdb found at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + elif [[ $(stat -c "%s" "${PACMAN_KEYRING_DIR}/trustdb.gpg") = "0" ]]; then + msg "$(gettext "Empty trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg.")" + msg "$(gettext "Importing $1...")" + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" I don't think this is the proper way to move owner trust values around- shouldn't we be using a combo and pipe of --export-ownertrust and --import-ownertrust?
+ else + warning "$(gettext "trustdb at \"${PACMAN_KEYRING_DIR}/trustdb.gpg\" is not empty.")" + while ! in_array "$choice" "${valid_choices[@]}" ; do + echo -n "$(gettext "==> Do you wish to overwrite your pacman trustdb? (y/n) ")" + read choice + choice=$(echo "$choice" | tr '[:upper:]' '[:lower:]') + done Wait- why do we have two questions for this? Seems totally silly to me. If I tell you to import and I have nothing, you should just do it. If we determine we don't overwrite owner trust values via export/import (but amend), then we shouldn't do questions at all.
+ + echo + if [[ $choice = 'y' || $choice = 'yes' ]]; then + cp $1 ${PACMAN_KEYRING_DIR}/trustdb.gpg + msg "$(gettext "Successfully imported $1 to ${PACMAN_KEYRING_DIR}/trustdb.gpg")" + else + msg "$(gettext "$1 is not imported")" + msg "$(gettext "Your original trustdb at ${PACMAN_KEYRING_DIR}/trustdb.gpg is preserved.")" + fi + fi +} + # Parse global options CONFIG="@sysconfdir@/pacman.conf" PACMAN_KEYRING_DIR="@sysconfdir@/pacman.d/gnupg" @@ -322,6 +388,21 @@ case "${command}" in ;; -h|--help) usage; exit 0 ;; + --import-trustdb) + if (( $# != 1 )); then + error "$(gettext "You need to specify exactly one trustdb!")" We don't use exclamation points on other messages in this section, so we shouldn't start the trend here.
+ exit 1 + elif [[ ! -e $1 ]]; then + error "$(gettext "$1 does not exist!")" + exit 1 + elif [[ -d $1 ]]; then + error "$(gettext "$1 is a directory and cannot be imported!")" + exit 1 Why not just one -f check and a single "%s is not a trust DB file" message? Also, don't use $1 directly in gettext, you need to use substitution vars as is done everywhere else.
+ fi + + import_trustdb $1 + + ;; -V|--version) version; exit 0 ;; *) -- 1.7.5.rc0.101.g3d23c
On Wed, Jun 8, 2011 at 9:59 PM, Pang Yan Han <pangyanhan@gmail.com> wrote:
Hi Dan, sorry for the late reply, some family matters cropped up over the past week.
Do you think I should reroll this with your suggestions? iirc, the original intent of this patch was to allow the user to have a way to have a trustdb.gpg for pacman to carry out signature verification and to change it if need be.
If it isn't too much trouble I would say go for it- I think this is a valuable option, it just needed some touchups in the implementation. -Dan
Thanks, Yan Han. -Kerrick Staley On Sat, May 28, 2011 at 9:37 AM, Pang Yan Han <pangyanhan@gmail.com> wrote:
This is a series of patches which can hopefully take package signing a small step forward.
Patch 1/6 lets pacman -v print the GPG Dir
Patch 2/6 updates the pacman manpage's --gpgdir section and adds a commented GPGDir option in pacman.conf which shows the user the default gpgdir.
Patch 3/6 updates Makefile.am to create the default gpgdir, pubring.gpg and trustdb.gpg if they do not exist.
Patch 4/6 adds a --verify option to pacman which lets the user control the level of signature verification. Valid arguments to --verify include "always", "optional", "never". Think of this as a way to override the "VerifySig" option in pacman.conf .
In addition Patch 4/6 updates configure.ac to output gpgdir at the end of ./configure.
Patch 5/6 updates the help text of pacman-key with regards to --gpgdir.
Patch 6/6 adds a --import-trustdb option to pacman-key. This allows the user to import a selected trustdb upon confirmation.
For Patch 6/6, Bash is not really my strong point and I took quite some time to get it right. Please help me check it. Thanks!
Pang Yan Han (6): Let pacman -v print GPG Dir Update pacman manpage and pacman.conf for gpgdir Update Makefile.am and configure.ac for gpgdir Add --verify option for signature level pacman-key: print default gpgdir in usage pacman-key: add --import-trustdb option
Makefile.am | 7 +++- configure.ac | 1 + doc/pacman-key.8.txt | 4 ++ doc/pacman.8.txt | 16 ++++++--- etc/pacman.conf.in | 1 + scripts/pacman-key.sh.in | 83 +++++++++++++++++++++++++++++++++++++++++++++- src/pacman/conf.h | 3 +- src/pacman/pacman.c | 16 +++++++++ 8 files changed, 122 insertions(+), 9 deletions(-)
-- 1.7.5.rc0.101.g3d23c
participants (6)
-
Allan McRae
-
Dan McGee
-
Kerrick Staley
-
Marc - A. Dahlhaus
-
Pang Yan Han
-
Rémy Oudompheng