From 7aff53e3aba0519f6afcdeb87e06d516ae449090 Mon Sep 17 00:00:00 2001 From: Lubos Kardos Date: Jun 19 2015 09:28:32 +0000 Subject: - Allow gpg to get passphrase by itself - resolves: #1228234 --- diff --git a/rpm-4.12.0-gpg-passphrase1.patch b/rpm-4.12.0-gpg-passphrase1.patch new file mode 100644 index 0000000..1354ec2 --- /dev/null +++ b/rpm-4.12.0-gpg-passphrase1.patch @@ -0,0 +1,201 @@ +From 6a8924b4c9df8e3597f7b4aa3de46498d390c5a8 Mon Sep 17 00:00:00 2001 +From: Lubos Kardos +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 + #include + #include ++#include + + #include /* RPMSIGTAG & related */ + #include +@@ -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 + diff --git a/rpm-4.12.0-gpg-passphrase2.patch b/rpm-4.12.0-gpg-passphrase2.patch new file mode 100644 index 0000000..215be9e --- /dev/null +++ b/rpm-4.12.0-gpg-passphrase2.patch @@ -0,0 +1,370 @@ +From 0bce5fcf270711a2e077fba0fb7c5979ea007eb5 Mon Sep 17 00:00:00 2001 +From: Lubos Kardos +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 + diff --git a/rpm.spec b/rpm.spec index cec377f..7a10cfd 100644 --- a/rpm.spec +++ b/rpm.spec @@ -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 4.12.0.1-16 +- Allow gpg to get passphrase by itself (#1228234) + * Thu Jun 18 2015 Fedora Release Engineering - 4.12.0.1-15.1 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild