/** \ingroup rpmcli * \file lib/rpmchecksig.c * Verify the signature of a package. */ #include "system.h" #include #include #include #include #include /* RPMSIGTAG & related */ #include #include #include #include /* rpmMkTemp() */ #include #include #include #include "lib/rpmlead.h" #include "lib/signature.h" #include "lib/rpmsignfiles.h" #include "debug.h" #if !defined(__GLIBC__) && !defined(__APPLE__) char ** environ = NULL; #endif typedef struct sigTarget_s { FD_t fd; const char *fileName; off_t start; 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) 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; const char *fmode; if (fdp == NULL || fn == NULL) /* programmer error */ return 1; /* open a file and set *fdp */ if (*fdp == NULL && fn != NULL) { switch(flags & O_ACCMODE) { case O_WRONLY: fmode = "w.ufdio"; break; case O_RDONLY: fmode = "r.ufdio"; break; default: case O_RDWR: fmode = "r+.ufdio"; break; } fd = Fopen(fn, fmode); 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. * @param sfdp source file * @param sfnp source path * @param tfdp destination file * @param tfnp destination path */ 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. * Return 0 on success, 1 on failure. */ static int putSignature(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen) { pgpDigParams sigp = NULL; rpmTagVal sigtag; struct rpmtd_s sigtd; int rc = 1; /* assume failure */ unsigned int hash_algo; unsigned int pubkey_algo; if (pgpPrtParams(pkt, pktlen, PGPTAG_SIGNATURE, &sigp)) { rpmlog(RPMLOG_ERR, _("Unsupported PGP signature\n")); goto exit; } hash_algo = pgpDigParamsAlgo(sigp, PGPVAL_HASHALGO); if (rpmDigestLength(hash_algo) == 0) { rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %u\n"), hash_algo); goto exit; } pubkey_algo = pgpDigParamsAlgo(sigp, PGPVAL_PUBKEYALGO); switch (pubkey_algo) { case PGPPUBKEYALGO_DSA: sigtag = ishdr ? RPMSIGTAG_DSA : RPMSIGTAG_GPG; break; case PGPPUBKEYALGO_RSA: sigtag = ishdr ? RPMSIGTAG_RSA : RPMSIGTAG_PGP; break; default: rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %u\n"), pubkey_algo); goto exit; break; } /* Looks sane, insert into header */ rpmtdReset(&sigtd); sigtd.count = pktlen; sigtd.data = pkt; sigtd.type = RPM_BIN_TYPE; sigtd.tag = sigtag; /* Argh, reversed return codes */ rc = (headerPut(sigh, &sigtd, HEADERPUT_DEFAULT) == 0); exit: pgpDigParamsFree(sigp); return rc; } static int runGPG(sigTarget sigt, const char *sigfile) { int pid = 0, status; FD_t fnamedPipe = NULL; char *namedPipeName = NULL; unsigned char buf[BUFSIZ]; ssize_t count; ssize_t wantCount; rpm_loff_t size; int rc = 1; /* assume failure */ namedPipeName = mkTempFifo(); rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1); rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1); 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); } rpmPopMacro(NULL, "__plaintext_filename"); rpmPopMacro(NULL, "__signature_filename"); fnamedPipe = Fopen(namedPipeName, "w"); if (!fnamedPipe) { rpmlog(RPMLOG_ERR, _("Fopen failed\n")); 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) { Fwrite(buf, sizeof(buf[0]), count, fnamedPipe); if (Ferror(fnamedPipe)) { 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; } Fclose(fnamedPipe); fnamedPipe = NULL; (void) waitpid(pid, &status, 0); pid = 0; if (!WIFEXITED(status) || WEXITSTATUS(status)) { rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status)); } else { rc = 0; } exit: if (fnamedPipe) Fclose(fnamedPipe); if (pid) waitpid(pid, &status, 0); if (namedPipeName) { rpmRmTempFifo(namedPipeName); free(namedPipeName); } return rc; } /** * Generate GPG signature(s) for a header+payload file. * @param sigh signature header * @param ishdr header-only signature? * @param sigt signature target * @param passPhrase private key pass phrase * @return 0 on success, 1 on failure */ static int makeGPGSignature(Header sigh, int ishdr, sigTarget sigt) { char * sigfile = rstrscat(NULL, sigt->fileName, ".sig", NULL); struct stat st; uint8_t * pkt = NULL; size_t pktlen = 0; int rc = 1; /* assume failure */ if (runGPG(sigt, sigfile)) 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; rc = 0; 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. */ rc = putSignature(sigh, ishdr, pkt, pktlen); exit: (void) unlink(sigfile); free(sigfile); free(pkt); return rc; } static int rpmGenSignature(Header sigh, sigTarget sigt1, sigTarget sigt2) { int ret; ret = makeGPGSignature(sigh, 0, sigt1); if (ret) goto exit; ret = makeGPGSignature(sigh, 1, sigt2); if (ret) goto exit; exit: return ret; } /** * Retrieve signature from header tag * @param sigh signature header * @param sigtag signature tag * @return parsed pgp dig or NULL */ static pgpDigParams getSig(Header sigh, rpmTagVal sigtag) { struct rpmtd_s pkt; pgpDigParams sig = NULL; if (headerGet(sigh, sigtag, &pkt, HEADERGET_DEFAULT) && pkt.data != NULL) { pgpPrtParams(pkt.data, pkt.count, PGPTAG_SIGNATURE, &sig); rpmtdFreeData(&pkt); } return sig; } 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); } static int sameSignature(rpmTagVal sigtag, Header h1, Header h2) { pgpDigParams sig1 = getSig(h1, sigtag); pgpDigParams sig2 = getSig(h2, sigtag);; int rc = pgpDigParamsCmp(sig1, sig2); pgpDigParamsFree(sig1); pgpDigParamsFree(sig2); return (rc == 0); } 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); int rc = -1; /* Nuke all signature tags */ deleteSigs(sigh); /* * rpmGenSignature() internals parse the actual signing result and * adds appropriate tags for DSA/RSA. */ 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; rc = sameSignature(sigtag, sigh, oldsigh); } headerFree(oldsigh); return rc; } static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag) { struct rpmtd_s copytd, td; rpmtd utd = &td; Header nh; Header oh; HeaderIterator hi; if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) { nh = headerNew(); oh = headerCopyLoad(utd->data); hi = headerInitIterator(oh); while (headerNext(hi, ©td)) { if (copytd.data) headerPut(nh, ©td, HEADERPUT_DEFAULT); rpmtdFreeData(©td); } headerFreeIterator(hi); headerFree(oh); rpmtdFreeData(utd); headerFree(*hdrp); *hdrp = headerLink(nh); headerFree(nh); } } static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp, off_t sigStart, off_t sigTargetSize, char *SHA1, uint8_t *MD5) { off_t archiveSize; rpmRC rc = RPMRC_OK; if (Fseek(fd, sigStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } /* Get payload size from signature tag */ archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE); if (!archiveSize) { archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE); } /* Set reserved space to 0 */ rpmPushMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL); /* Replace old digests in sigh */ rc = rpmGenerateSignature(SHA1, MD5, sigTargetSize, archiveSize, fd); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("generateSignature failed\n")); goto exit; } if (Fseek(fd, sigStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } headerFree(*sigp); rc = rpmReadSignature(fd, sigp, NULL); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n")); goto exit; } exit: return rc; } static rpmRC includeFileSignatures(FD_t fd, const char *rpm, Header *sigp, Header *hdrp, off_t sigStart, off_t headerStart) { FD_t ofd = NULL; char *trpm = NULL; char *key; char *keypass; char *SHA1 = NULL; uint8_t *MD5 = NULL; size_t sha1len; size_t md5len; off_t sigTargetSize; rpmRC rc = RPMRC_OK; struct rpmtd_s osigtd; char *o_sha1 = NULL; uint8_t o_md5[16]; #ifndef WITH_IMAEVM rpmlog(RPMLOG_ERR, _("missing libimaevm\n")); return RPMRC_FAIL; #endif unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE); key = rpmExpand("%{?_file_signing_key}", NULL); keypass = rpmExpand("%{_file_signing_key_password}", NULL); if (rstreq(keypass, "")) { free(keypass); keypass = NULL; } rc = rpmSignFiles(*hdrp, key, keypass); if (rc != RPMRC_OK) { goto exit; } *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE); if (*hdrp == NULL) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("headerReload failed\n")); goto exit; } ofd = rpmMkTempFile(NULL, &trpm); if (ofd == NULL || Ferror(ofd)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n")); goto exit; } /* Copy archive to temp file */ if (copyFile(&fd, rpm, &ofd, trpm)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("copyFile failed\n")); goto exit; } if (Fseek(fd, headerStart, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } /* Start MD5 calculation */ fdInitDigest(fd, PGPHASHALGO_MD5, 0); /* Write header to rpm and recalculate SHA1 */ fdInitDigest(fd, PGPHASHALGO_SHA1, 0); rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("headerWrite failed\n")); goto exit; } fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, &sha1len, 1); /* Copy archive from temp file */ if (Fseek(ofd, 0, SEEK_SET) < 0) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"), rpm, Fstrerror(fd)); goto exit; } if (copyFile(&ofd, trpm, &fd, rpm)) { rc = RPMRC_FAIL; rpmlog(RPMLOG_ERR, _("copyFile failed\n")); goto exit; } unlink(trpm); sigTargetSize = Ftell(fd) - headerStart; fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&MD5, &md5len, 0); if (headerGet(*sigp, RPMSIGTAG_MD5, &osigtd, HEADERGET_DEFAULT)) { memcpy(o_md5, osigtd.data, 16); rpmtdFreeData(&osigtd); } if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) { o_sha1 = xstrdup(osigtd.data); rpmtdFreeData(&osigtd); } if (memcmp(MD5, o_md5, md5len) == 0 && strcmp(SHA1, o_sha1) == 0) rpmlog(RPMLOG_WARNING, _("%s already contains identical file signatures\n"), rpm); else replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA1, MD5); exit: free(trpm); free(MD5); free(SHA1); free(o_sha1); free(keypass); free(key); if (ofd) (void) closeFile(&ofd); return rc; } /** \ingroup rpmcli * Create/modify elements in signature header. * @param rpm path to package * @param deleting adding or deleting signature? * @param signfiles sign files if non-zero * @return 0 on success, -1 on error */ static int rpmSign(const char *rpm, int deleting, int signfiles) { FD_t fd = NULL; FD_t ofd = NULL; char *trpm = NULL; Header sigh = NULL; Header h = NULL; char *msg = NULL; int res = -1; /* assume failure */ rpmRC rc; struct rpmtd_s utd; off_t headerStart; off_t sigStart; struct sigTarget_s sigt1; struct sigTarget_s sigt2; unsigned int origSigSize; int insSig = 0; fprintf(stdout, "%s:\n", rpm); if (manageFile(&fd, rpm, O_RDWR)) goto exit; if ((rc = rpmLeadRead(fd, NULL, NULL, &msg)) != RPMRC_OK) { rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg); goto exit; } sigStart = Ftell(fd); rc = rpmReadSignature(fd, &sigh, &msg); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm, (msg && *msg ? msg : "\n")); goto exit; } headerStart = Ftell(fd); if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), rpm, msg); goto exit; } if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) { rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n")); goto exit; } if (signfiles) { includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart); } unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES); origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES); if (deleting) { /* Nuke all the signature tags. */ deleteSigs(sigh); } else { /* Signature target containing header + payload */ sigt1.fd = fd; sigt1.start = headerStart; sigt1.fileName = rpm; sigt1.size = fdSize(fd) - headerStart; /* Signature target containing only header */ sigt2 = sigt1; sigt2.size = headerSizeof(h, HEADER_MAGIC_YES); res = replaceSignature(sigh, &sigt1, &sigt2); 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; } goto exit; } res = -1; } /* 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; } } /* Reallocate the signature into one contiguous region. */ sigh = headerReload(sigh, RPMTAG_HEADERSIGNATURES); if (sigh == NULL) /* XXX can't happen */ goto exit; 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; } if (rpmWriteSignature(fd, sigh)) { rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), rpm, Fstrerror(fd)); goto exit; } res = 0; } 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; } /* Write the lead/signature of the output rpm */ rc = rpmLeadWrite(ofd, h); if (rc != RPMRC_OK) { rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm, Fstrerror(ofd)); goto exit; } if (rpmWriteSignature(ofd, sigh)) { rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm, Fstrerror(ofd)); goto exit; } 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; /* 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)); } } } exit: if (fd) (void) closeFile(&fd); if (ofd) (void) closeFile(&ofd); headerFree(sigh); headerFree(h); free(msg); /* Clean up intermediate target */ if (trpm) { (void) unlink(trpm); free(trpm); } return res; } int rpmPkgSign(const char *path, const struct rpmSignArgs * args) { int rc; if (args) { if (args->hashalgo) { char *algo = NULL; rasprintf(&algo, "%d", args->hashalgo); rpmPushMacro(NULL, "_gpg_digest_algo", NULL, algo, RMIL_GLOBAL); free(algo); } if (args->keyid) { rpmPushMacro(NULL, "_gpg_name", NULL, args->keyid, RMIL_GLOBAL); } } rc = rpmSign(path, 0, args ? args->signfiles : 0); if (args) { if (args->hashalgo) { rpmPopMacro(NULL, "_gpg_digest_algo"); } if (args->keyid) { rpmPopMacro(NULL, "_gpg_name"); } } return rc; } int rpmPkgDelSign(const char *path) { return rpmSign(path, 1, 0); }