- Allow gpg to get passphrase by itself

- resolves: #1228234
This commit is contained in:
Lubos Kardos 2015-06-19 11:27:41 +02:00
parent 966f2e339b
commit 7aff53e3ab
3 changed files with 577 additions and 1 deletions

View File

@ -0,0 +1,201 @@
From 6a8924b4c9df8e3597f7b4aa3de46498d390c5a8 Mon Sep 17 00:00:00 2001
From: Lubos Kardos <lkardos@redhat.com>
Date: Tue, 9 Jun 2015 14:19:59 +0200
Subject: [PATCH 1/2] Use named pipe instead of stdin as input for gpg
This enables running gpg with access to the shell the rpmsign command
is running in. This is needed to allow gpg to get passphrase by itself.
---
sign/rpmgensig.c | 105 ++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 80 insertions(+), 25 deletions(-)
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 0bd14e3..9691f0d 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -8,6 +8,7 @@
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
+#include <libgen.h>
#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
#include <rpm/rpmmacro.h>
@@ -33,6 +34,68 @@ typedef struct sigTarget_s {
rpm_loff_t size;
} *sigTarget;
+/*
+ * There is no function for creating unique temporary fifos so create
+ * unique temporary directory and then create fifo in it.
+ */
+static char *mkTempFifo(void)
+{
+ char *tmppath = NULL, *tmpdir = NULL, *fifofn = NULL;
+ mode_t mode;
+
+ tmppath = rpmExpand("%{_tmppath}", NULL);
+ if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1))
+ goto exit;
+
+
+ tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL);
+ mode = umask(0077);
+ tmpdir = mkdtemp(tmpdir);
+ umask(mode);
+ if (tmpdir == NULL) {
+ rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n"),
+ tmpdir);
+ tmpdir = _free(tmpdir);
+ goto exit;
+ }
+
+ fifofn = rpmGetPath(tmpdir, "/fifo", NULL);
+ if (mkfifo(fifofn, 0600) == -1) {
+ rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n"), fifofn);
+ fifofn = _free(fifofn);
+ }
+
+exit:
+ if (fifofn == NULL && tmpdir != NULL)
+ unlink(tmpdir);
+
+ free(tmppath);
+ free(tmpdir);
+
+ return fifofn;
+}
+
+/* Delete fifo and then temporary directory in which it was located */
+static int rpmRmTempFifo(const char *fn)
+{
+ int rc = 0;
+ char *dfn = NULL, *dir = NULL;
+
+ if ((rc = unlink(fn)) != 0) {
+ rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n"), fn);
+ return rc;
+ }
+
+ dfn = xstrdup(fn);
+ dir = dirname(dfn);
+
+ if ((rc = rmdir(dir)) != 0)
+ rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n"), dir);
+ free(dfn);
+
+ return rc;
+}
+
static int closeFile(FD_t *fdp)
{
if (fdp == NULL || *fdp == NULL)
@@ -186,8 +249,9 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
{
int pid = 0, status;
int inpipe[2];
- int inpipe2[2];
FILE * fpipe = NULL;
+ FD_t fnamedPipe = NULL;
+ char *namedPipeName = NULL;
unsigned char buf[BUFSIZ];
ssize_t count;
ssize_t wantCount;
@@ -200,13 +264,9 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
goto exit;
}
- inpipe2[0] = inpipe2[1] = 0;
- if (pipe(inpipe2) < 0) {
- rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
- goto exit;
- }
+ namedPipeName = mkTempFifo();
- addMacro(NULL, "__plaintext_filename", NULL, "-", -1);
+ addMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1);
addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
if (!(pid = fork())) {
@@ -217,9 +277,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
(void) dup2(inpipe[0], 3);
(void) close(inpipe[1]);
- (void) dup2(inpipe2[0], STDIN_FILENO);
- (void) close(inpipe2[1]);
-
if (gpg_path && *gpg_path != '\0')
(void) setenv("GNUPGHOME", gpg_path, 1);
(void) setenv("LC_ALL", "C", 1);
@@ -240,8 +297,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
(void) close(inpipe[0]);
inpipe[0] = 0;
- (void) close(inpipe2[0]);
- inpipe2[0] = 0;
fpipe = fdopen(inpipe[1], "w");
if (!fpipe) {
@@ -257,12 +312,11 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
(void) fclose(fpipe);
fpipe = NULL;
- fpipe = fdopen(inpipe2[1], "w");
- if (!fpipe) {
- rpmlog(RPMLOG_ERR, _("fdopen failed\n"));
+ fnamedPipe = Fopen(namedPipeName, "w");
+ if (!fnamedPipe) {
+ rpmlog(RPMLOG_ERR, _("Fopen failed\n"));
goto exit;
}
- inpipe2[1] = 0;
if (Fseek(sigt->fd, sigt->start, SEEK_SET) < 0) {
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
@@ -273,8 +327,8 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
size = sigt->size;
wantCount = size < sizeof(buf) ? size : sizeof(buf);
while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) {
- fwrite(buf, sizeof(buf[0]), count, fpipe);
- if (ferror(fpipe)) {
+ Fwrite(buf, sizeof(buf[0]), count, fnamedPipe);
+ if (Ferror(fnamedPipe)) {
rpmlog(RPMLOG_ERR, _("Could not write to pipe\n"));
goto exit;
}
@@ -286,8 +340,8 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
sigt->fileName, Fstrerror(sigt->fd));
goto exit;
}
- fclose(fpipe);
- fpipe = NULL;
+ Fclose(fnamedPipe);
+ fnamedPipe = NULL;
(void) waitpid(pid, &status, 0);
pid = 0;
@@ -307,15 +361,16 @@ exit:
if (inpipe[1])
close(inpipe[1]);
- if (inpipe2[0])
- close(inpipe[0]);
-
- if (inpipe2[1])
- close(inpipe[1]);
+ if (fnamedPipe)
+ Fclose(fnamedPipe);
if (pid)
waitpid(pid, &status, 0);
+ if (namedPipeName) {
+ rpmRmTempFifo(namedPipeName);
+ free(namedPipeName);
+ }
return rc;
}
--
1.9.3

View File

@ -0,0 +1,370 @@
From 0bce5fcf270711a2e077fba0fb7c5979ea007eb5 Mon Sep 17 00:00:00 2001
From: Lubos Kardos <lkardos@redhat.com>
Date: Tue, 9 Jun 2015 18:06:29 +0200
Subject: [PATCH 2/2] Allow gpg to get passphrase by itself.
Remove rpm asking for passphrase and then passing this passphrase
to gpg via file descriptor (--passphrase-fd) but provide gpg with
access to unredirected stdin to get passphrase directly from user.
Remove also macro %__gpg_check_password_cmd because in this new signing
scheme has no sense. rpm doesn't handle passphrase in any way,
everything is done in gpg including checking of passphrase.
We did this modification because of changes in gpg behavior. Since
gpg-2.1 option "--passphrase-fd" doesn't work by default, only when
it is explicitly allowed in gpg.conf. (rhbz:#1228234)
---
macros.in | 4 +--
python/rpmsmodule.c | 9 +++---
rpmsign.c | 82 +++--------------------------------------------------
sign/rpmgensig.c | 67 +++++++++----------------------------------
sign/rpmsign.h | 3 +-
5 files changed, 23 insertions(+), 142 deletions(-)
diff --git a/macros.in b/macros.in
index 414c1be..de89420 100644
--- a/macros.in
+++ b/macros.in
@@ -538,11 +538,9 @@ package or when debugging this package.\
# Macro(s) to hold the arguments passed to GPG/PGP for package
# signing and verification.
#
-%__gpg_check_password_cmd %{__gpg} \
- gpg --batch --no-verbose --passphrase-fd 3 -u "%{_gpg_name}" -so -
%__gpg_sign_cmd %{__gpg} \
- gpg --batch --no-verbose --no-armor --passphrase-fd 3 \
+ gpg --no-verbose --no-armor \
%{?_gpg_digest_algo:--digest-algo %{_gpg_digest_algo}} \
--no-secmem-warning \
-u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}
diff --git a/python/rpmsmodule.c b/python/rpmsmodule.c
index a8289b5..0601353 100644
--- a/python/rpmsmodule.c
+++ b/python/rpmsmodule.c
@@ -8,19 +8,18 @@ static char rpms__doc__[] =
static PyObject * addSign(PyObject * self, PyObject * args, PyObject *kwds)
{
const char *path = NULL;
- const char *passPhrase = NULL;
- char * kwlist[] = { "path", "passPhrase", "keyid", "hashalgo", NULL };
+ char * kwlist[] = { "path", "keyid", "hashalgo", NULL };
struct rpmSignArgs sig, *sigp = NULL;
memset(&sig, 0, sizeof(sig));
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|si", kwlist,
- &path, &passPhrase, &sig.keyid, &sig.hashalgo))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|si", kwlist,
+ &path, &sig.keyid, &sig.hashalgo))
return NULL;
if (sig.keyid || sig.hashalgo)
sigp = &sig;
- return PyBool_FromLong(rpmPkgSign(path, sigp, passPhrase) == 0);
+ return PyBool_FromLong(rpmPkgSign(path, sigp) == 0);
}
static PyObject * delSign(PyObject * self, PyObject * args, PyObject *kwds)
diff --git a/rpmsign.c b/rpmsign.c
index b8e5598..9b93e39 100644
--- a/rpmsign.c
+++ b/rpmsign.c
@@ -41,72 +41,6 @@ static struct poptOption optionsTable[] = {
POPT_TABLEEND
};
-static int checkPassPhrase(const char * passPhrase)
-{
- int passPhrasePipe[2];
- int pid, status;
- int rc = -1;
- int xx;
-
- if (passPhrase == NULL)
- return -1;
-
- passPhrasePipe[0] = passPhrasePipe[1] = 0;
- if (pipe(passPhrasePipe))
- return -1;
-
- pid = fork();
- if (pid < 0) {
- close(passPhrasePipe[0]);
- close(passPhrasePipe[1]);
- return -1;
- }
-
- if (pid == 0) {
- char * cmd, * gpg_path;
- char *const *av;
- int fdno;
-
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(passPhrasePipe[1]);
- if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
- xx = dup2(fdno, STDIN_FILENO);
- close(fdno);
- }
- if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
- xx = dup2(fdno, STDOUT_FILENO);
- 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 (xx >= 0 && rc == 0) {
- rc = execve(av[0], av+1, environ);
- fprintf(stderr, _("Could not exec %s: %s\n"), "gpg",
- strerror(errno));
- }
- _exit(EXIT_FAILURE);
- }
-
- close(passPhrasePipe[0]);
- xx = write(passPhrasePipe[1], passPhrase, strlen(passPhrase));
- xx = write(passPhrasePipe[1], "\n", 1);
- close(passPhrasePipe[1]);
-
- if (xx >= 0 && waitpid(pid, &status, 0) >= 0)
- rc = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : 1;
-
- return rc;
-}
-
/* TODO: permit overriding macro setup on the command line */
static int doSign(poptContext optCon)
{
@@ -119,18 +53,10 @@ static int doSign(poptContext optCon)
goto exit;
}
- /* XXX FIXME: eliminate obsolete getpass() usage */
- passPhrase = getpass(_("Enter pass phrase: "));
- passPhrase = (passPhrase != NULL) ? rstrdup(passPhrase) : NULL;
- if (checkPassPhrase(passPhrase) == 0) {
- const char *arg;
- fprintf(stderr, _("Pass phrase is good.\n"));
- rc = 0;
- while ((arg = poptGetArg(optCon)) != NULL) {
- rc += rpmPkgSign(arg, NULL, passPhrase);
- }
- } else {
- fprintf(stderr, _("Pass phrase check failed or gpg key expired\n"));
+ const char *arg;
+ rc = 0;
+ while ((arg = poptGetArg(optCon)) != NULL) {
+ rc += rpmPkgSign(arg, NULL);
}
exit:
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 9691f0d..24bf39e 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -245,11 +245,9 @@ exit:
return rc;
}
-static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
+static int runGPG(sigTarget sigt, const char *sigfile)
{
int pid = 0, status;
- int inpipe[2];
- FILE * fpipe = NULL;
FD_t fnamedPipe = NULL;
char *namedPipeName = NULL;
unsigned char buf[BUFSIZ];
@@ -258,12 +256,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
rpm_loff_t size;
int rc = 1; /* assume failure */
- inpipe[0] = inpipe[1] = 0;
- if (pipe(inpipe) < 0) {
- rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
- goto exit;
- }
-
namedPipeName = mkTempFifo();
addMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1);
@@ -274,9 +266,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
char *cmd = NULL;
const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
- (void) dup2(inpipe[0], 3);
- (void) close(inpipe[1]);
-
if (gpg_path && *gpg_path != '\0')
(void) setenv("GNUPGHOME", gpg_path, 1);
(void) setenv("LC_ALL", "C", 1);
@@ -295,23 +284,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
delMacro(NULL, "__plaintext_filename");
delMacro(NULL, "__signature_filename");
- (void) close(inpipe[0]);
- inpipe[0] = 0;
-
- fpipe = fdopen(inpipe[1], "w");
- if (!fpipe) {
- rpmlog(RPMLOG_ERR, _("fdopen failed\n"));
- goto exit;
- }
- inpipe[1] = 0;
-
- if (fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : "")) < 0) {
- rpmlog(RPMLOG_ERR, _("Could not write to pipe\n"));
- goto exit;
- }
- (void) fclose(fpipe);
- fpipe = NULL;
-
fnamedPipe = Fopen(namedPipeName, "w");
if (!fnamedPipe) {
rpmlog(RPMLOG_ERR, _("Fopen failed\n"));
@@ -352,14 +324,6 @@ static int runGPG(sigTarget sigt, const char *sigfile, const char * passPhrase)
}
exit:
- if (fpipe)
- fclose(fpipe);
-
- if (inpipe[0])
- close(inpipe[0]);
-
- if (inpipe[1])
- close(inpipe[1]);
if (fnamedPipe)
Fclose(fnamedPipe);
@@ -383,8 +347,7 @@ exit:
* @param passPhrase private key pass phrase
* @return 0 on success, 1 on failure
*/
-static int makeGPGSignature(Header sigh, int ishdr, sigTarget sigt,
- const char * passPhrase)
+static int makeGPGSignature(Header sigh, int ishdr, sigTarget sigt)
{
char * sigfile = rstrscat(NULL, sigt->fileName, ".sig", NULL);
struct stat st;
@@ -392,7 +355,7 @@ static int makeGPGSignature(Header sigh, int ishdr, sigTarget sigt,
size_t pktlen = 0;
int rc = 1; /* assume failure */
- if (runGPG(sigt, sigfile, passPhrase))
+ if (runGPG(sigt, sigfile))
goto exit;
if (stat(sigfile, &st)) {
@@ -431,16 +394,15 @@ exit:
return rc;
}
-static int rpmGenSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
- const char * passPhrase)
+static int rpmGenSignature(Header sigh, sigTarget sigt1, sigTarget sigt2)
{
int ret;
- ret = makeGPGSignature(sigh, 0, sigt1, passPhrase);
+ ret = makeGPGSignature(sigh, 0, sigt1);
if (ret)
goto exit;
- ret = makeGPGSignature(sigh, 1, sigt2, passPhrase);
+ ret = makeGPGSignature(sigh, 1, sigt2);
if (ret)
goto exit;
exit:
@@ -486,8 +448,7 @@ static int sameSignature(rpmTagVal sigtag, Header h1, Header h2)
return (rc == 0);
}
-static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
- const char *passPhrase)
+static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2)
{
/* Grab a copy of the header so we can compare the result */
Header oldsigh = headerCopy(sigh);
@@ -500,7 +461,7 @@ static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
* rpmGenSignature() internals parse the actual signing result and
* adds appropriate tags for DSA/RSA.
*/
- if (rpmGenSignature(sigh, sigt1, sigt2, passPhrase) == 0) {
+ if (rpmGenSignature(sigh, sigt1, sigt2) == 0) {
/* Lets see what we got and whether its the same signature as before */
rpmTagVal sigtag = headerIsEntry(sigh, RPMSIGTAG_DSA) ?
RPMSIGTAG_DSA : RPMSIGTAG_RSA;
@@ -517,10 +478,9 @@ static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
* Create/modify elements in signature header.
* @param rpm path to package
* @param deleting adding or deleting signature?
- * @param passPhrase passPhrase (ignored when deleting)
* @return 0 on success, -1 on error
*/
-static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
+static int rpmSign(const char *rpm, int deleting)
{
FD_t fd = NULL;
FD_t ofd = NULL;
@@ -605,7 +565,7 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
sigt2 = sigt1;
sigt2.size = headerSizeof(h, HEADER_MAGIC_YES);
- res = replaceSignature(sigh, &sigt1, &sigt2, passPhrase);
+ res = replaceSignature(sigh, &sigt1, &sigt2);
if (res != 0) {
if (res == 1) {
rpmlog(RPMLOG_WARNING,
@@ -722,8 +682,7 @@ exit:
return res;
}
-int rpmPkgSign(const char *path,
- const struct rpmSignArgs * args, const char *passPhrase)
+int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
{
int rc;
@@ -739,7 +698,7 @@ int rpmPkgSign(const char *path,
}
}
- rc = rpmSign(path, 0, passPhrase);
+ rc = rpmSign(path, 0);
if (args) {
if (args->hashalgo) {
@@ -755,5 +714,5 @@ int rpmPkgSign(const char *path,
int rpmPkgDelSign(const char *path)
{
- return rpmSign(path, 1, NULL);
+ return rpmSign(path, 1);
}
diff --git a/sign/rpmsign.h b/sign/rpmsign.h
index 15b3e0f..e161aff 100644
--- a/sign/rpmsign.h
+++ b/sign/rpmsign.h
@@ -21,8 +21,7 @@ struct rpmSignArgs {
* @param passPhrase passphrase for the signing key
* @return 0 on success
*/
-int rpmPkgSign(const char *path,
- const struct rpmSignArgs * args, const char *passPhrase);
+int rpmPkgSign(const char *path, const struct rpmSignArgs * args);
/** \ingroup rpmsign
* Delete signature(s) from a package
--
1.9.3

View File

@ -27,7 +27,7 @@
Summary: The RPM package management system
Name: rpm
Version: %{rpmver}
Release: %{?snapver:0.%{snapver}.}15%{?dist}.1
Release: %{?snapver:0.%{snapver}.}16%{?dist}
Group: System Environment/Base
Url: http://www.rpm.org/
Source0: http://rpm.org/releases/rpm-4.12.x/%{name}-%{srcver}.tar.bz2
@ -66,6 +66,8 @@ Patch105: rpm-4.12.0-eu-strip-g-option.patch
# Fix golang debuginfo packages
Patch106: rpm-4.12.0-golang-debuginfo.patch
Patch107: rpm-4.12.0-whatrecommends.patch
Patch108: rpm-4.12.0-gpg-passphrase1.patch
Patch109: rpm-4.12.0-gpg-passphrase2.patch
# These are not yet upstream
Patch302: rpm-4.7.1-geode-i686.patch
@ -550,6 +552,9 @@ exit 0
%doc doc/librpm/html/*
%changelog
* Fri Jun 19 2015 Lubos Kardos <lkardos@redhat.com> 4.12.0.1-16
- Allow gpg to get passphrase by itself (#1228234)
* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 4.12.0.1-15.1
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild