Add a brand new rpmsign utility for package signing

- Signing (and deleting) are different from everything else in rpm
  in that it needs very little of rpm's facilities. For example access
  to the rpmdb is not needed at all. Splitting this to a separate,
  small utility allows various possibilities, like severely limiting
  its access from SELinux POV, control of signature generation with
  cli arguments (the main rpm executable is already overcrowded with
  options). It's also the first step to allow reasonably splitting
  rpm signing to a separate package; not everybody needs to sign
  packages, yet signing support needs to drag in GPG and whatnot.
- Reimplement / refactor various librpm signature generation helpers
  into somewhat saner internal versions.
This commit is contained in:
Panu Matilainen 2010-09-03 14:40:18 +03:00
parent 8f75ac30fb
commit df0b760e7e
3 changed files with 195 additions and 4 deletions

View File

@ -78,7 +78,7 @@ pkginclude_HEADERS += build/rpmspec.h
rpmbindir = `echo $(bindir) | $(SED) -e s,usr/bin,bin,`
rpmbin_PROGRAMS = rpm
bin_PROGRAMS = rpm2cpio rpmbuild
bin_PROGRAMS = rpm2cpio rpmbuild rpmsign
rpmlibexec_PROGRAMS =
rpmconfig_SCRIPTS = find-provides find-requires mkinstalldirs \
@ -98,6 +98,12 @@ rpm_LDADD = libcliutils.la
rpm_LDADD += build/librpmbuild.la lib/librpm.la rpmio/librpmio.la
rpm_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
rpmsign_SOURCES = rpmsign.c debug.h system.h
rpmsign_CPPFLAGS = $(AM_CPPFLAGS)
rpmsign_LDADD = libcliutils.la
rpmsign_LDADD += lib/librpm.la rpmio/librpmio.la
rpmsign_LDADD += @WITH_NSS_LIB@ @WITH_POPT_LIB@ @WITH_ZLIB_LIB@
rpmbuild_SOURCES = rpmbuild.c debug.h system.h
rpmbuild_CPPFLAGS = $(AM_CPPFLAGS)
rpmbuild_LDADD = libcliutils.la
@ -191,8 +197,6 @@ install-exec-hook:
@LN_S@ ../../bin/rpm $(DESTDIR)$(bindir)/rpmquery
rm -f $(DESTDIR)$(bindir)/rpmverify
@LN_S@ ../../bin/rpm $(DESTDIR)$(bindir)/rpmverify
rm -f $(DESTDIR)$(bindir)/rpmsign
@LN_S@ ../../bin/rpm $(DESTDIR)$(bindir)/rpmsign
rm -f $(DESTDIR)$(bindir)/rpmdb
@LN_S@ ../../bin/rpm $(DESTDIR)$(bindir)/rpmdb
@ -206,7 +210,6 @@ install-data-local:
# XXX to appease distcheck we need to remove "stuff" here...
uninstall-local:
@rm -f $(DESTDIR)$(bindir)/rpmquery
@rm -f $(DESTDIR)$(bindir)/rpmsign
@rm -f $(DESTDIR)$(bindir)/rpmverify
@rm -f $(DESTDIR)$(bindir)/rpmdb
@rm -rf $(DESTDIR)$(rpmconfigdir)/platform/

View File

@ -6,6 +6,7 @@ cliutils.c
rpm2cpio.c
rpmqv.c
rpmbuild.c
rpmsign.c
build/build.c
build/expression.c
build/files.c

187
rpmsign.c Normal file
View File

@ -0,0 +1,187 @@
#include "system.h"
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
#include <rpm/rpmcli.h>
#include "cliutils.h"
#include "debug.h"
#if !defined(__GLIBC__) && !defined(__APPLE__)
char ** environ = NULL;
#endif
enum modes {
MODE_ADDSIGN = (1 << 0),
MODE_RESIGN = (1 << 1),
MODE_DELSIGN = (1 << 2),
};
static int mode = 0;
static struct poptOption optionsTable[] = {
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0,
N_("Common options for all rpm modes and executables:"), NULL },
{ "addsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_ADDSIGN,
N_("sign package(s)"), NULL },
{ "resign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_RESIGN,
N_("sign package(s) (identical to --addsign)"), NULL },
{ "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
N_("delete package signatures"), NULL },
POPT_AUTOALIAS
POPT_AUTOHELP
POPT_TABLEEND
};
static rpmSigTag lookupSignatureType(void)
{
rpmSigTag rc = 0;
char *name = rpmExpand("%{?_signature}", NULL);
if (!(name && *name != '\0'))
rc = 0;
else if (!rstrcasecmp(name, "none"))
rc = 0;
else if (!rstrcasecmp(name, "pgp"))
rc = RPMSIGTAG_PGP;
else if (!rstrcasecmp(name, "pgp5")) /* XXX legacy */
rc = RPMSIGTAG_PGP;
else if (!rstrcasecmp(name, "gpg"))
rc = RPMSIGTAG_GPG;
else
rc = -1; /* Invalid %_signature spec in macro file */
name = _free(name);
return rc;
}
static int checkPassPhrase(const char * passPhrase)
{
int passPhrasePipe[2];
int pid, status;
int rc;
int xx;
if (passPhrase == NULL)
return -1;
passPhrasePipe[0] = passPhrasePipe[1] = 0;
xx = pipe(passPhrasePipe);
if (!(pid = fork())) {
char * cmd, * gpg_path;
char *const *av;
int fdno;
xx = close(STDIN_FILENO);
xx = close(STDOUT_FILENO);
xx = close(passPhrasePipe[1]);
if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
xx = dup2(fdno, STDIN_FILENO);
xx = close(fdno);
}
if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
xx = dup2(fdno, STDOUT_FILENO);
xx = close(fdno);
}
xx = dup2(passPhrasePipe[0], 3);
unsetenv("MALLOC_CHECK_");
gpg_path = rpmExpand("%{?_gpg_path}", NULL);
if (!rstreq(gpg_path, ""))
setenv("GNUPGHOME", gpg_path, 1);
cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
if (!rc)
rc = execve(av[0], av+1, environ);
fprintf(stderr, _("Could not exec %s: %s\n"), "gpg",
strerror(errno));
_exit(EXIT_FAILURE);
}
xx = close(passPhrasePipe[0]);
xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
xx = write(passPhrasePipe[1], "\n", 1);
xx = close(passPhrasePipe[1]);
(void) waitpid(pid, &status, 0);
return ((WIFEXITED(status) && WEXITSTATUS(status) == 0)) ? 0 : 1;
}
/* TODO: permit overriding macro setup on the command line */
static int doSign(ARGV_const_t args)
{
int rc = EXIT_FAILURE;
int sigTag = lookupSignatureType();
char * passPhrase = NULL;
char * name = rpmExpand("%{?_gpg_name}", NULL);
if (rstreq(name, "")) {
fprintf(stderr, _("You must set \"%%_gpg_name\" in your macro file\n"));
goto exit;
}
switch (sigTag) {
case RPMSIGTAG_PGP:
case RPMSIGTAG_GPG:
case RPMSIGTAG_DSA:
case RPMSIGTAG_RSA:
break;
default:
fprintf(stderr, _("Invalid %%_signature spec in macro file.\n"));
goto exit;
break;
}
/* XXX FIXME: eliminate obsolete getpass() usage */
passPhrase = getpass(_("Enter pass phrase: "));
passPhrase = (passPhrase != NULL) ? rstrdup(passPhrase) : NULL;
if (checkPassPhrase(passPhrase) == 0) {
fprintf(stderr, _("Pass phrase is good.\n"));
rc = rpmcliSign(args, 0, sigTag, passPhrase);
} else {
fprintf(stderr, _("Pass phrase check failed\n"));
}
exit:
free(name);
return rc;
}
int main(int argc, char *argv[])
{
int ec = EXIT_FAILURE;
poptContext optCon = rpmcliInit(argc, argv, optionsTable);
ARGV_const_t args = NULL;
if (argc <= 1) {
printUsage(optCon, stderr, 0);
goto exit;
}
args = (ARGV_const_t) poptGetArgs(optCon);
if (args == NULL) {
argerror(_("no arguments given"));
}
switch (mode) {
case MODE_ADDSIGN:
case MODE_RESIGN:
ec = doSign(args);
break;
case MODE_DELSIGN:
ec = rpmcliSign(args, 1, 0, NULL);
break;
default:
argerror(_("only one major mode may be specified"));
break;
}
exit:
rpmcliFini(optCon);
return ec;
}