/** \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 sigt_v3; struct sigTarget_s sigt_v4; unsigned int origSigSize; int insSig = 0; fprintf(stdout, "%s:\n", rpm); if (manageFile(&fd, rpm, O_RDWR)) goto exit; if ((rc = rpmLeadRead(fd, &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; } unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES); origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES); if (signfiles) { if (includeFileSignatures(&sigh, &h)) goto exit; } if (deleting) { /* Nuke all the signature tags. */ deleteSigs(sigh); } else { /* Signature target containing header + payload */ sigt_v3.fd = fd; sigt_v3.start = headerStart; sigt_v3.fileName = rpm; sigt_v3.size = fdSize(fd) - headerStart; /* Signature target containing only header */ sigt_v4 = sigt_v3; sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES); res = replaceSignature(sigh, &sigt_v3, &sigt_v4); 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; }
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; }