2010-10-22 23:28:08 +08:00
|
|
|
/** \ingroup rpmcli
|
|
|
|
* \file lib/rpmchecksig.c
|
|
|
|
* Verify the signature of a package.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "system.h"
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <popt.h>
|
2015-06-09 20:19:59 +08:00
|
|
|
#include <libgen.h>
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
|
|
|
|
#include <rpm/rpmmacro.h>
|
|
|
|
#include <rpm/rpmpgp.h>
|
|
|
|
#include <rpm/rpmsign.h>
|
|
|
|
#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
|
|
|
|
#include <rpm/rpmlog.h>
|
|
|
|
#include <rpm/rpmstring.h>
|
2015-07-22 01:00:43 +08:00
|
|
|
#include <rpmio/rpmio_internal.h>
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
#include "lib/rpmlead.h"
|
|
|
|
#include "lib/signature.h"
|
2017-06-08 21:29:40 +08:00
|
|
|
#include "sign/rpmsignfiles.h"
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
typedef struct sigTarget_s {
|
|
|
|
FD_t fd;
|
|
|
|
const char *fileName;
|
|
|
|
off_t start;
|
|
|
|
rpm_loff_t size;
|
|
|
|
} *sigTarget;
|
|
|
|
|
2015-06-09 20:19:59 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2010-10-22 23:28:08 +08:00
|
|
|
static int closeFile(FD_t *fdp)
|
|
|
|
{
|
|
|
|
if (fdp == NULL || *fdp == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* close and reset *fdp to NULL */
|
|
|
|
(void) Fclose(*fdp);
|
|
|
|
*fdp = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*/
|
|
|
|
static int manageFile(FD_t *fdp, const char *fn, int flags)
|
|
|
|
{
|
|
|
|
FD_t fd;
|
2014-06-30 16:20:19 +08:00
|
|
|
const char *fmode;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
if (fdp == NULL || fn == NULL) /* programmer error */
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* open a file and set *fdp */
|
|
|
|
if (*fdp == NULL && fn != NULL) {
|
2017-02-27 23:37:18 +08:00
|
|
|
switch (flags & O_ACCMODE) {
|
2014-05-15 16:15:27 +08:00
|
|
|
case O_WRONLY:
|
|
|
|
fmode = "w.ufdio";
|
|
|
|
break;
|
|
|
|
case O_RDONLY:
|
|
|
|
fmode = "r.ufdio";
|
|
|
|
break;
|
2014-06-30 16:20:19 +08:00
|
|
|
default:
|
2014-05-15 16:15:27 +08:00
|
|
|
case O_RDWR:
|
|
|
|
fmode = "r+.ufdio";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fd = Fopen(fn, fmode);
|
2010-10-22 23:28:08 +08:00
|
|
|
if (fd == NULL || Ferror(fd)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), fn,
|
|
|
|
Fstrerror(fd));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
*fdp = fd;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no operation */
|
|
|
|
if (*fdp != NULL && fn != NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* XXX never reached */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Copy header+payload, calculating digest(s) on the fly.
|
2015-07-22 01:00:35 +08:00
|
|
|
* @param sfdp source file
|
|
|
|
* @param sfnp source path
|
|
|
|
* @param tfdp destination file
|
|
|
|
* @param tfnp destination path
|
2010-10-22 23:28:08 +08:00
|
|
|
*/
|
|
|
|
static int copyFile(FD_t *sfdp, const char *sfnp,
|
|
|
|
FD_t *tfdp, const char *tfnp)
|
|
|
|
{
|
|
|
|
unsigned char buf[BUFSIZ];
|
|
|
|
ssize_t count;
|
|
|
|
int rc = 1;
|
|
|
|
|
|
|
|
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
|
|
|
|
{
|
|
|
|
if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: Fwrite failed: %s\n"), tfnp,
|
|
|
|
Fstrerror(*tfdp));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: Fread failed: %s\n"), sfnp, Fstrerror(*sfdp));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
if (Fflush(*tfdp) != 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: Fflush failed: %s\n"), tfnp,
|
|
|
|
Fstrerror(*tfdp));
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate generated signature and insert to header if it looks sane.
|
|
|
|
* NSS doesn't support everything GPG does. Basic tests to see if the
|
|
|
|
* generated signature is something we can use.
|
2017-05-26 19:10:10 +08:00
|
|
|
* Return generated signature tag data on success, NULL on failure.
|
2010-10-22 23:28:08 +08:00
|
|
|
*/
|
2017-05-26 19:10:10 +08:00
|
|
|
static rpmtd makeSigTag(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
2011-11-07 18:56:03 +08:00
|
|
|
pgpDigParams sigp = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
rpmTagVal sigtag;
|
2017-05-26 19:10:10 +08:00
|
|
|
rpmtd sigtd = NULL;
|
2011-11-07 20:47:03 +08:00
|
|
|
unsigned int hash_algo;
|
|
|
|
unsigned int pubkey_algo;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2011-11-09 19:55:08 +08:00
|
|
|
if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) {
|
2011-10-23 19:23:12 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n"));
|
2010-10-22 23:28:08 +08:00
|
|
|
goto exit;
|
2011-10-23 19:23:12 +08:00
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2011-11-07 20:47:03 +08:00
|
|
|
hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO);
|
|
|
|
if (rpmDigestLength(hash_algo) == 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n"), hash_algo);
|
2010-10-22 23:28:08 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2011-11-07 20:47:03 +08:00
|
|
|
pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO);
|
|
|
|
switch (pubkey_algo) {
|
2010-10-22 23:28:08 +08:00
|
|
|
case PGPPUBKEYALGO_DSA:
|
|
|
|
sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG;
|
|
|
|
break;
|
|
|
|
case PGPPUBKEYALGO_RSA:
|
|
|
|
sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP;
|
|
|
|
break;
|
|
|
|
default:
|
2011-11-07 20:47:03 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n"),
|
|
|
|
pubkey_algo);
|
2010-10-22 23:28:08 +08:00
|
|
|
goto exit;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-05-26 19:10:10 +08:00
|
|
|
/* Looks sane, create the tag data */
|
|
|
|
sigtd = rpmtdNew();
|
|
|
|
sigtd->count = pktlen;
|
|
|
|
sigtd->data = memcpy(xmalloc(pktlen), pkt, pktlen);;
|
|
|
|
sigtd->type = RPM_BIN_TYPE;
|
|
|
|
sigtd->tag = sigtag;
|
|
|
|
sigtd->flags |= RPMTD_ALLOCED;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
exit:
|
2011-11-09 19:55:08 +08:00
|
|
|
pgpDigParamsFree(sigp);
|
2017-05-26 19:10:10 +08:00
|
|
|
return sigtd;
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
|
2015-06-10 00:06:29 +08:00
|
|
|
static int runGPG(sigTarget sigt, const char *sigfile)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
2014-05-15 16:15:27 +08:00
|
|
|
int pid = 0, status;
|
2015-06-09 20:19:59 +08:00
|
|
|
FD_t fnamedPipe = NULL;
|
|
|
|
char *namedPipeName = NULL;
|
2014-05-15 16:15:27 +08:00
|
|
|
unsigned char buf[BUFSIZ];
|
|
|
|
ssize_t count;
|
|
|
|
ssize_t wantCount;
|
|
|
|
rpm_loff_t size;
|
2010-10-22 23:28:08 +08:00
|
|
|
int rc = 1; /* assume failure */
|
|
|
|
|
2015-06-09 20:19:59 +08:00
|
|
|
namedPipeName = mkTempFifo();
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1);
|
|
|
|
rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
if (!(pid = fork())) {
|
|
|
|
char *const *av;
|
|
|
|
char *cmd = NULL;
|
|
|
|
const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
|
|
|
|
|
|
|
|
if (gpg_path && *gpg_path != '\0')
|
|
|
|
(void) setenv("GNUPGHOME", gpg_path, 1);
|
|
|
|
|
|
|
|
unsetenv("MALLOC_CHECK_");
|
|
|
|
cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
|
|
|
|
rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
|
|
|
|
if (!rc)
|
|
|
|
rc = execve(av[0], av+1, environ);
|
|
|
|
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
|
|
|
|
strerror(errno));
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPopMacro(NULL, "__plaintext_filename");
|
|
|
|
rpmPopMacro(NULL, "__signature_filename");
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2015-06-09 20:19:59 +08:00
|
|
|
fnamedPipe = Fopen(namedPipeName, "w");
|
|
|
|
if (!fnamedPipe) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Fopen failed\n"));
|
2014-05-15 16:15:27 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Fseek(sigt->fd, sigt->start, SEEK_SET) < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
|
|
|
|
sigt->fileName, Fstrerror(sigt->fd));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = sigt->size;
|
|
|
|
wantCount = size < sizeof(buf) ? size : sizeof(buf);
|
|
|
|
while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) {
|
2015-06-09 20:19:59 +08:00
|
|
|
Fwrite(buf, sizeof(buf[0]), count, fnamedPipe);
|
|
|
|
if (Ferror(fnamedPipe)) {
|
2014-05-15 16:15:27 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Could not write to pipe\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
size -= count;
|
|
|
|
wantCount = size < sizeof(buf) ? size : sizeof(buf);
|
|
|
|
}
|
|
|
|
if (count < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not read from file %s: %s\n"),
|
|
|
|
sigt->fileName, Fstrerror(sigt->fd));
|
|
|
|
goto exit;
|
|
|
|
}
|
2015-06-09 20:19:59 +08:00
|
|
|
Fclose(fnamedPipe);
|
|
|
|
fnamedPipe = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
(void) waitpid(pid, &status, 0);
|
2014-05-15 16:15:27 +08:00
|
|
|
pid = 0;
|
2010-10-22 23:28:08 +08:00
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
|
|
|
|
} else {
|
|
|
|
rc = 0;
|
|
|
|
}
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2010-10-22 23:28:08 +08:00
|
|
|
exit:
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2015-06-09 20:19:59 +08:00
|
|
|
if (fnamedPipe)
|
|
|
|
Fclose(fnamedPipe);
|
2014-05-15 16:15:27 +08:00
|
|
|
|
|
|
|
if (pid)
|
|
|
|
waitpid(pid, &status, 0);
|
|
|
|
|
2015-06-09 20:19:59 +08:00
|
|
|
if (namedPipeName) {
|
|
|
|
rpmRmTempFifo(namedPipeName);
|
|
|
|
free(namedPipeName);
|
|
|
|
}
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2010-10-22 23:28:08 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate GPG signature(s) for a header+payload file.
|
|
|
|
* @param sigh signature header
|
|
|
|
* @param ishdr header-only signature?
|
2014-05-15 16:15:27 +08:00
|
|
|
* @param sigt signature target
|
2010-10-22 23:28:08 +08:00
|
|
|
* @param passPhrase private key pass phrase
|
2017-05-24 21:45:46 +08:00
|
|
|
* @return generated sigtag on success, 0 on failure
|
2010-10-22 23:28:08 +08:00
|
|
|
*/
|
2017-05-26 19:10:10 +08:00
|
|
|
static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
2014-05-15 16:15:27 +08:00
|
|
|
char * sigfile = rstrscat(NULL, sigt->fileName, ".sig", NULL);
|
2010-10-22 23:28:08 +08:00
|
|
|
struct stat st;
|
|
|
|
uint8_t * pkt = NULL;
|
|
|
|
size_t pktlen = 0;
|
2017-05-26 19:10:10 +08:00
|
|
|
rpmtd sigtd = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2015-06-10 00:06:29 +08:00
|
|
|
if (runGPG(sigt, sigfile))
|
2010-10-22 23:28:08 +08:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (stat(sigfile, &st)) {
|
|
|
|
/* GPG failed to write signature */
|
|
|
|
rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
pktlen = st.st_size;
|
|
|
|
rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", pktlen);
|
|
|
|
pkt = xmalloc(pktlen);
|
|
|
|
|
|
|
|
{ FD_t fd;
|
|
|
|
|
2017-05-26 19:10:10 +08:00
|
|
|
int rc = 0;
|
2010-10-22 23:28:08 +08:00
|
|
|
fd = Fopen(sigfile, "r.ufdio");
|
|
|
|
if (fd != NULL && !Ferror(fd)) {
|
|
|
|
rc = Fread(pkt, sizeof(*pkt), pktlen, fd);
|
|
|
|
(void) Fclose(fd);
|
|
|
|
}
|
|
|
|
if (rc != pktlen) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", pktlen);
|
|
|
|
|
|
|
|
/* Parse the signature, change signature tag as appropriate. */
|
2017-05-26 19:10:10 +08:00
|
|
|
sigtd = makeSigTag(sigh, ishdr, pkt, pktlen);
|
2010-10-22 23:28:08 +08:00
|
|
|
exit:
|
|
|
|
(void) unlink(sigfile);
|
|
|
|
free(sigfile);
|
|
|
|
free(pkt);
|
|
|
|
|
2017-05-26 19:10:10 +08:00
|
|
|
return sigtd;
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void deleteSigs(Header sigh)
|
|
|
|
{
|
|
|
|
headerDel(sigh, RPMSIGTAG_GPG);
|
|
|
|
headerDel(sigh, RPMSIGTAG_PGP);
|
|
|
|
headerDel(sigh, RPMSIGTAG_DSA);
|
|
|
|
headerDel(sigh, RPMSIGTAG_RSA);
|
|
|
|
headerDel(sigh, RPMSIGTAG_PGP5);
|
|
|
|
}
|
|
|
|
|
2017-05-26 19:32:33 +08:00
|
|
|
static int haveSignature(rpmtd sigtd, Header h)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
2017-05-26 19:32:33 +08:00
|
|
|
pgpDigParams sig1 = NULL;
|
|
|
|
pgpDigParams sig2 = NULL;
|
|
|
|
struct rpmtd_s oldtd;
|
|
|
|
int rc = 0; /* assume no */
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2017-05-26 19:32:33 +08:00
|
|
|
if (!headerGet(h, rpmtdTag(sigtd), &oldtd, HEADERGET_DEFAULT))
|
|
|
|
return rc;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2017-05-26 19:32:33 +08:00
|
|
|
pgpPrtParams(sigtd->data, sigtd->count, PGPTAG_SIGNATURE, &sig1);
|
|
|
|
while (rpmtdNext(&oldtd) >= 0 && rc == 0) {
|
|
|
|
pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2);
|
|
|
|
if (pgpDigParamsCmp(sig1, sig2) == 0)
|
|
|
|
rc = 1;
|
|
|
|
pgpDigParamsFree(sig2);
|
|
|
|
}
|
2011-11-09 19:55:08 +08:00
|
|
|
pgpDigParamsFree(sig1);
|
2017-05-26 19:32:33 +08:00
|
|
|
rpmtdFreeData(&oldtd);
|
|
|
|
|
|
|
|
return rc;
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
|
2017-05-26 17:14:08 +08:00
|
|
|
static int replaceSignature(Header sigh, sigTarget sigt_v3, sigTarget sigt_v4)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
|
|
|
int rc = -1;
|
2017-05-26 19:10:10 +08:00
|
|
|
rpmtd sigtd = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2017-05-26 17:14:08 +08:00
|
|
|
/* Make the cheaper v4 signature first */
|
2017-05-26 19:10:10 +08:00
|
|
|
if ((sigtd = makeGPGSignature(sigh, 1, sigt_v4)) == NULL)
|
|
|
|
goto exit;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2017-05-26 17:14:08 +08:00
|
|
|
/* See if we already have a signature by the same key and parameters */
|
2017-05-26 19:32:33 +08:00
|
|
|
if (haveSignature(sigtd, sigh)) {
|
2017-05-26 17:14:08 +08:00
|
|
|
rc = 1;
|
|
|
|
goto exit;
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
2017-05-26 19:32:33 +08:00
|
|
|
/* Nuke all signature tags */
|
|
|
|
deleteSigs(sigh);
|
|
|
|
|
|
|
|
if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
|
|
|
|
goto exit;
|
2017-05-26 19:10:10 +08:00
|
|
|
rpmtdFree(sigtd);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2017-05-26 17:14:08 +08:00
|
|
|
/* Assume the same signature test holds for v3 signature too */
|
2017-05-26 19:10:10 +08:00
|
|
|
if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)
|
|
|
|
goto exit;
|
|
|
|
|
|
|
|
if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
|
2017-05-26 17:14:08 +08:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
exit:
|
2017-05-26 19:10:10 +08:00
|
|
|
rpmtdFree(sigtd);
|
2010-10-22 23:28:08 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2015-07-22 01:00:43 +08:00
|
|
|
static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)
|
2015-07-22 01:00:38 +08:00
|
|
|
{
|
2017-03-02 14:56:11 +08:00
|
|
|
struct rpmtd_s td;
|
2015-07-22 01:00:43 +08:00
|
|
|
rpmtd utd = &td;
|
2015-07-22 01:00:38 +08:00
|
|
|
Header nh;
|
|
|
|
Header oh;
|
|
|
|
|
|
|
|
if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) {
|
|
|
|
oh = headerCopyLoad(utd->data);
|
2017-03-02 14:56:11 +08:00
|
|
|
nh = headerCopy(oh);
|
2015-07-22 01:00:38 +08:00
|
|
|
headerFree(oh);
|
|
|
|
rpmtdFreeData(utd);
|
|
|
|
headerFree(*hdrp);
|
|
|
|
*hdrp = headerLink(nh);
|
|
|
|
headerFree(nh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Place file signatures into the signature header where they belong
The original file signing puts the file signatures into the main header
immutable region, invalidating all previous signatures and digests so
the package no longer appears to be what it was when it came out of the
assembly line. Which is bad. Doing that also requires recalculating
everything again which is just added complexity, and since it adds
stuff to different place from the rest of the signing, it requires yet
complexity to deal with that. Moving the file signatures into the
signature header solves all that and allows removing a big pile of
now unnecessary code.
Because this means retrofitting tags bass-ackwards into the signature
header, the tag definitions are backwards to everything else. Other
options would certainly be possible, but this makes things look more
normal on the signature header side. "Users" only ever see the
unchanged file signature tags as they have always been.
This also means the signature header can be MUCH bigger than ever before,
so bump up the limit (to 64MB, arbitrary something for now), and
permit string array types to be migrated from the signature header
on package read.
Caveats:
This loses the check for identical existing signatures to keep the
complexity down, it's hardly a critical thing and can be added back later.
While file signing could now be done separately to other signing, that
is not handled here.
2017-10-10 16:44:10 +08:00
|
|
|
static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
|
2015-07-22 01:00:43 +08:00
|
|
|
{
|
2017-06-09 15:27:55 +08:00
|
|
|
#ifdef WITH_IMAEVM
|
Place file signatures into the signature header where they belong
The original file signing puts the file signatures into the main header
immutable region, invalidating all previous signatures and digests so
the package no longer appears to be what it was when it came out of the
assembly line. Which is bad. Doing that also requires recalculating
everything again which is just added complexity, and since it adds
stuff to different place from the rest of the signing, it requires yet
complexity to deal with that. Moving the file signatures into the
signature header solves all that and allows removing a big pile of
now unnecessary code.
Because this means retrofitting tags bass-ackwards into the signature
header, the tag definitions are backwards to everything else. Other
options would certainly be possible, but this makes things look more
normal on the signature header side. "Users" only ever see the
unchanged file signature tags as they have always been.
This also means the signature header can be MUCH bigger than ever before,
so bump up the limit (to 64MB, arbitrary something for now), and
permit string array types to be migrated from the signature header
on package read.
Caveats:
This loses the check for identical existing signatures to keep the
complexity down, it's hardly a critical thing and can be added back later.
While file signing could now be done separately to other signing, that
is not handled here.
2017-10-10 16:44:10 +08:00
|
|
|
rpmRC rc;
|
2016-04-27 16:05:29 +08:00
|
|
|
char *key;
|
2015-07-22 01:00:46 +08:00
|
|
|
char *keypass;
|
2015-07-22 01:00:43 +08:00
|
|
|
|
|
|
|
key = rpmExpand("%{?_file_signing_key}", NULL);
|
|
|
|
|
2017-06-09 17:33:23 +08:00
|
|
|
keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
|
2016-04-26 06:33:28 +08:00
|
|
|
if (rstreq(keypass, "")) {
|
|
|
|
free(keypass);
|
2015-07-22 01:00:46 +08:00
|
|
|
keypass = NULL;
|
2016-04-26 06:33:28 +08:00
|
|
|
}
|
2015-07-22 01:00:46 +08:00
|
|
|
|
Place file signatures into the signature header where they belong
The original file signing puts the file signatures into the main header
immutable region, invalidating all previous signatures and digests so
the package no longer appears to be what it was when it came out of the
assembly line. Which is bad. Doing that also requires recalculating
everything again which is just added complexity, and since it adds
stuff to different place from the rest of the signing, it requires yet
complexity to deal with that. Moving the file signatures into the
signature header solves all that and allows removing a big pile of
now unnecessary code.
Because this means retrofitting tags bass-ackwards into the signature
header, the tag definitions are backwards to everything else. Other
options would certainly be possible, but this makes things look more
normal on the signature header side. "Users" only ever see the
unchanged file signature tags as they have always been.
This also means the signature header can be MUCH bigger than ever before,
so bump up the limit (to 64MB, arbitrary something for now), and
permit string array types to be migrated from the signature header
on package read.
Caveats:
This loses the check for identical existing signatures to keep the
complexity down, it's hardly a critical thing and can be added back later.
While file signing could now be done separately to other signing, that
is not handled here.
2017-10-10 16:44:10 +08:00
|
|
|
rc = rpmSignFiles(*sigp, *hdrp, key, keypass);
|
2015-07-22 01:00:43 +08:00
|
|
|
|
2016-04-26 06:33:28 +08:00
|
|
|
free(keypass);
|
|
|
|
free(key);
|
2015-07-22 01:00:43 +08:00
|
|
|
return rc;
|
2017-06-09 15:27:55 +08:00
|
|
|
#else
|
|
|
|
rpmlog(RPMLOG_ERR, _("file signing support not built in\n"));
|
|
|
|
return RPMRC_FAIL;
|
|
|
|
#endif
|
2015-07-22 01:00:43 +08:00
|
|
|
}
|
|
|
|
|
2010-10-22 23:28:08 +08:00
|
|
|
/** \ingroup rpmcli
|
|
|
|
* Create/modify elements in signature header.
|
|
|
|
* @param rpm path to package
|
|
|
|
* @param deleting adding or deleting signature?
|
2015-07-22 01:00:43 +08:00
|
|
|
* @param signfiles sign files if non-zero
|
2010-10-22 23:28:08 +08:00
|
|
|
* @return 0 on success, -1 on error
|
|
|
|
*/
|
2015-07-22 01:00:43 +08:00
|
|
|
static int rpmSign(const char *rpm, int deleting, int signfiles)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
|
|
|
FD_t fd = NULL;
|
|
|
|
FD_t ofd = NULL;
|
2014-05-15 16:15:27 +08:00
|
|
|
char *trpm = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
Header sigh = NULL;
|
2014-05-15 16:15:27 +08:00
|
|
|
Header h = NULL;
|
2016-04-26 06:33:28 +08:00
|
|
|
char *msg = NULL;
|
2010-10-22 23:28:08 +08:00
|
|
|
int res = -1; /* assume failure */
|
2011-04-21 15:47:31 +08:00
|
|
|
rpmRC rc;
|
|
|
|
struct rpmtd_s utd;
|
2014-05-15 16:15:27 +08:00
|
|
|
off_t headerStart;
|
2014-05-15 16:15:27 +08:00
|
|
|
off_t sigStart;
|
2017-05-24 19:51:49 +08:00
|
|
|
struct sigTarget_s sigt_v3;
|
|
|
|
struct sigTarget_s sigt_v4;
|
2014-05-15 16:15:27 +08:00
|
|
|
unsigned int origSigSize;
|
|
|
|
int insSig = 0;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2011-04-21 15:47:31 +08:00
|
|
|
fprintf(stdout, "%s:\n", rpm);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
if (manageFile(&fd, rpm, O_RDWR))
|
2011-04-21 15:47:31 +08:00
|
|
|
goto exit;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2016-10-27 15:56:34 +08:00
|
|
|
if ((rc = rpmLeadRead(fd, NULL, &msg)) != RPMRC_OK) {
|
2011-07-07 16:55:28 +08:00
|
|
|
rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg);
|
2011-04-21 15:47:31 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
sigStart = Ftell(fd);
|
2016-10-24 13:38:26 +08:00
|
|
|
rc = rpmReadSignature(fd, &sigh, &msg);
|
2014-02-01 20:51:09 +08:00
|
|
|
if (rc != RPMRC_OK) {
|
2011-04-21 15:47:31 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
|
|
|
|
(msg && *msg ? msg : "\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
headerStart = Ftell(fd);
|
|
|
|
if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), rpm, msg);
|
2011-04-21 15:47:31 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2014-05-15 16:15:27 +08:00
|
|
|
|
|
|
|
if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
|
2011-04-21 15:47:31 +08:00
|
|
|
goto exit;
|
2014-05-15 16:15:27 +08:00
|
|
|
}
|
2011-04-21 15:47:31 +08:00
|
|
|
|
2015-07-22 01:00:43 +08:00
|
|
|
unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
|
2014-05-15 16:15:27 +08:00
|
|
|
origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
Place file signatures into the signature header where they belong
The original file signing puts the file signatures into the main header
immutable region, invalidating all previous signatures and digests so
the package no longer appears to be what it was when it came out of the
assembly line. Which is bad. Doing that also requires recalculating
everything again which is just added complexity, and since it adds
stuff to different place from the rest of the signing, it requires yet
complexity to deal with that. Moving the file signatures into the
signature header solves all that and allows removing a big pile of
now unnecessary code.
Because this means retrofitting tags bass-ackwards into the signature
header, the tag definitions are backwards to everything else. Other
options would certainly be possible, but this makes things look more
normal on the signature header side. "Users" only ever see the
unchanged file signature tags as they have always been.
This also means the signature header can be MUCH bigger than ever before,
so bump up the limit (to 64MB, arbitrary something for now), and
permit string array types to be migrated from the signature header
on package read.
Caveats:
This loses the check for identical existing signatures to keep the
complexity down, it's hardly a critical thing and can be added back later.
While file signing could now be done separately to other signing, that
is not handled here.
2017-10-10 16:44:10 +08:00
|
|
|
if (signfiles) {
|
|
|
|
if (includeFileSignatures(&sigh, &h))
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2011-04-21 15:47:31 +08:00
|
|
|
if (deleting) { /* Nuke all the signature tags. */
|
|
|
|
deleteSigs(sigh);
|
|
|
|
} else {
|
2014-05-15 16:15:27 +08:00
|
|
|
/* Signature target containing header + payload */
|
2017-05-24 19:51:49 +08:00
|
|
|
sigt_v3.fd = fd;
|
|
|
|
sigt_v3.start = headerStart;
|
|
|
|
sigt_v3.fileName = rpm;
|
|
|
|
sigt_v3.size = fdSize(fd) - headerStart;
|
2014-05-15 16:15:27 +08:00
|
|
|
|
|
|
|
/* Signature target containing only header */
|
2017-05-24 19:51:49 +08:00
|
|
|
sigt_v4 = sigt_v3;
|
|
|
|
sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES);
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2017-05-24 19:51:49 +08:00
|
|
|
res = replaceSignature(sigh, &sigt_v3, &sigt_v4);
|
2011-04-21 15:47:31 +08:00
|
|
|
if (res != 0) {
|
|
|
|
if (res == 1) {
|
|
|
|
rpmlog(RPMLOG_WARNING,
|
|
|
|
_("%s already contains identical signature, skipping\n"),
|
|
|
|
rpm);
|
|
|
|
/* Identical signature is not an error */
|
|
|
|
res = 0;
|
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2014-05-26 21:32:06 +08:00
|
|
|
res = -1;
|
2011-04-21 15:47:31 +08:00
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
/* Try to make new signature smaller to have size of original signature */
|
|
|
|
rpmtdReset(&utd);
|
|
|
|
if (headerGet(sigh, RPMSIGTAG_RESERVEDSPACE, &utd, HEADERGET_MINMEM)) {
|
|
|
|
int diff;
|
|
|
|
int count;
|
|
|
|
char *reservedSpace = NULL;
|
|
|
|
|
|
|
|
count = utd.count;
|
|
|
|
diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize;
|
|
|
|
|
|
|
|
if (diff < count) {
|
|
|
|
reservedSpace = xcalloc(count - diff, sizeof(char));
|
|
|
|
headerDel(sigh, RPMSIGTAG_RESERVEDSPACE);
|
|
|
|
rpmtdReset(&utd);
|
|
|
|
utd.tag = RPMSIGTAG_RESERVEDSPACE;
|
|
|
|
utd.count = count - diff;
|
|
|
|
utd.type = RPM_BIN_TYPE;
|
|
|
|
utd.data = reservedSpace;
|
|
|
|
headerPut(sigh, &utd, HEADERPUT_DEFAULT);
|
|
|
|
free(reservedSpace);
|
|
|
|
insSig = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-21 15:47:31 +08:00
|
|
|
/* Reallocate the signature into one contiguous region. */
|
|
|
|
sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES);
|
|
|
|
if (sigh == NULL) /* XXX can't happen */
|
|
|
|
goto exit;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
if (insSig) {
|
|
|
|
/* Insert new signature into original rpm */
|
|
|
|
if (Fseek(fd, sigStart, SEEK_SET) < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
|
|
|
|
rpm, Fstrerror(fd));
|
|
|
|
goto exit;
|
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
if (rpmWriteSignature(fd, sigh)) {
|
2014-05-21 20:40:28 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), rpm,
|
|
|
|
Fstrerror(fd));
|
2014-05-15 16:15:27 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
2014-05-26 21:36:26 +08:00
|
|
|
res = 0;
|
2014-05-15 16:15:27 +08:00
|
|
|
} else {
|
|
|
|
/* Replace orignal rpm with new rpm containing new signature */
|
|
|
|
rasprintf(&trpm, "%s.XXXXXX", rpm);
|
|
|
|
ofd = rpmMkTemp(trpm);
|
|
|
|
if (ofd == NULL || Ferror(ofd)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
2011-04-21 15:47:31 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
/* Write the lead/signature of the output rpm */
|
2016-10-27 15:48:26 +08:00
|
|
|
rc = rpmLeadWrite(ofd, h);
|
2014-05-15 16:15:27 +08:00
|
|
|
if (rc != RPMRC_OK) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
|
|
|
|
Fstrerror(ofd));
|
|
|
|
goto exit;
|
|
|
|
}
|
2011-04-21 15:47:31 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
if (rpmWriteSignature(ofd, sigh)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
|
|
|
|
Fstrerror(ofd));
|
|
|
|
goto exit;
|
|
|
|
}
|
2014-05-15 16:15:27 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
if (Fseek(fd, headerStart, SEEK_SET) < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
|
|
|
|
rpm, Fstrerror(fd));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
/* Append the header and archive from the temp file */
|
|
|
|
if (copyFile(&fd, rpm, &ofd, trpm) == 0) {
|
|
|
|
struct stat st;
|
2010-10-22 23:28:08 +08:00
|
|
|
|
2014-05-15 16:15:27 +08:00
|
|
|
/* Move final target into place, restore file permissions. */
|
|
|
|
if (stat(rpm, &st) == 0 && unlink(rpm) == 0 &&
|
|
|
|
rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) {
|
|
|
|
res = 0;
|
|
|
|
} else {
|
|
|
|
rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n"),
|
|
|
|
rpm, strerror(errno));
|
|
|
|
}
|
2011-05-25 15:20:45 +08:00
|
|
|
}
|
2011-04-21 16:09:28 +08:00
|
|
|
}
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
exit:
|
|
|
|
if (fd) (void) closeFile(&fd);
|
|
|
|
if (ofd) (void) closeFile(&ofd);
|
|
|
|
|
2016-10-24 16:33:40 +08:00
|
|
|
headerFree(sigh);
|
2014-05-15 16:15:27 +08:00
|
|
|
headerFree(h);
|
2016-04-26 06:33:28 +08:00
|
|
|
free(msg);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
/* Clean up intermediate target */
|
|
|
|
if (trpm) {
|
|
|
|
(void) unlink(trpm);
|
|
|
|
free(trpm);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-06-10 00:06:29 +08:00
|
|
|
int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (args) {
|
|
|
|
if (args->hashalgo) {
|
|
|
|
char *algo = NULL;
|
|
|
|
rasprintf(&algo, "%d", args->hashalgo);
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPushMacro(NULL, "_gpg_digest_algo", NULL, algo, RMIL_GLOBAL);
|
2010-10-22 23:28:08 +08:00
|
|
|
free(algo);
|
|
|
|
}
|
|
|
|
if (args->keyid) {
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPushMacro(NULL, "_gpg_name", NULL, args->keyid, RMIL_GLOBAL);
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-12 04:27:52 +08:00
|
|
|
rc = rpmSign(path, 0, args ? args->signfiles : 0);
|
2010-10-22 23:28:08 +08:00
|
|
|
|
|
|
|
if (args) {
|
|
|
|
if (args->hashalgo) {
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPopMacro(NULL, "_gpg_digest_algo");
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
if (args->keyid) {
|
2016-10-24 18:09:38 +08:00
|
|
|
rpmPopMacro(NULL, "_gpg_name");
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-05-29 21:11:55 +08:00
|
|
|
int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args)
|
2010-10-22 23:28:08 +08:00
|
|
|
{
|
2015-07-22 01:00:43 +08:00
|
|
|
return rpmSign(path, 1, 0);
|
2010-10-22 23:28:08 +08:00
|
|
|
}
|