2000-08-28 03:18:25 +08:00
|
|
|
/** \ingroup rpmbuild
|
|
|
|
* \file build/pack.c
|
2000-01-25 04:02:32 +08:00
|
|
|
* Assemble components of an RPM package.
|
|
|
|
*/
|
|
|
|
|
1998-07-26 05:00:26 +08:00
|
|
|
#include "system.h"
|
|
|
|
|
2010-01-05 21:25:31 +08:00
|
|
|
#include <errno.h>
|
2013-08-17 22:26:30 +08:00
|
|
|
#include <sys/wait.h>
|
2010-01-05 21:25:31 +08:00
|
|
|
|
2008-01-30 19:53:51 +08:00
|
|
|
#include <rpm/rpmlib.h> /* RPMSIGTAG*, rpmReadPackageFile */
|
2008-01-30 23:05:29 +08:00
|
|
|
#include <rpm/rpmfileutil.h>
|
|
|
|
#include <rpm/rpmlog.h>
|
1998-01-13 05:31:29 +08:00
|
|
|
|
2008-01-30 23:05:29 +08:00
|
|
|
#include "rpmio/rpmio_internal.h" /* fdInitDigest, fdFiniDigest */
|
2007-11-23 18:37:54 +08:00
|
|
|
#include "lib/fsm.h"
|
|
|
|
#include "lib/signature.h"
|
|
|
|
#include "lib/rpmlead.h"
|
2010-08-25 20:41:09 +08:00
|
|
|
#include "build/rpmbuild_internal.h"
|
|
|
|
#include "build/rpmbuild_misc.h"
|
2008-01-30 23:05:29 +08:00
|
|
|
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "debug.h"
|
1998-01-13 05:31:29 +08:00
|
|
|
|
2013-11-25 15:59:27 +08:00
|
|
|
static int rpmPackageFilesArchive(rpmfiles fi, int isSrc,
|
|
|
|
FD_t cfd, ARGV_t dpaths,
|
|
|
|
rpm_loff_t * archiveSize, char ** failedFile)
|
2013-11-12 18:23:20 +08:00
|
|
|
{
|
2013-11-19 01:53:52 +08:00
|
|
|
int rc = 0;
|
2013-11-25 15:59:27 +08:00
|
|
|
rpmfi archive = rpmfiNewArchiveWriter(cfd, fi);
|
2013-11-12 18:23:20 +08:00
|
|
|
|
2013-11-19 01:53:52 +08:00
|
|
|
while (!rc && (rc = rpmfiNext(archive)) >= 0) {
|
2013-11-12 18:23:20 +08:00
|
|
|
/* Copy file into archive. */
|
2013-11-20 19:36:34 +08:00
|
|
|
FD_t rfd = NULL;
|
|
|
|
const char *path = dpaths[rpmfiFX(archive)];
|
|
|
|
|
|
|
|
rfd = Fopen(path, "r.ufdio");
|
|
|
|
if (Ferror(rfd)) {
|
2013-11-26 16:51:23 +08:00
|
|
|
rc = RPMERR_OPEN_FAILED;
|
2013-11-20 19:36:34 +08:00
|
|
|
} else {
|
|
|
|
rc = rpmfiArchiveWriteFile(archive, rfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc && failedFile)
|
|
|
|
*failedFile = xstrdup(path);
|
|
|
|
if (rfd) {
|
|
|
|
/* preserve any prior errno across close */
|
|
|
|
int myerrno = errno;
|
|
|
|
Fclose(rfd);
|
|
|
|
errno = myerrno;
|
|
|
|
}
|
2013-11-12 18:23:20 +08:00
|
|
|
}
|
|
|
|
|
2013-11-26 16:51:23 +08:00
|
|
|
if (rc == RPMERR_ITER_END)
|
2013-11-19 01:53:52 +08:00
|
|
|
rc = 0;
|
2013-11-12 18:23:20 +08:00
|
|
|
|
|
|
|
/* Finish the payload stream */
|
|
|
|
if (!rc)
|
2013-11-19 01:53:52 +08:00
|
|
|
rc = rpmfiArchiveClose(archive);
|
|
|
|
|
2014-09-18 16:00:48 +08:00
|
|
|
if (archiveSize)
|
|
|
|
*archiveSize = (rc == 0) ? rpmfiArchiveTell(archive) : 0;
|
|
|
|
|
2013-11-19 01:53:52 +08:00
|
|
|
rpmfiFree(archive);
|
2013-11-12 18:23:20 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2001-01-11 22:13:04 +08:00
|
|
|
/**
|
2001-01-26 04:26:35 +08:00
|
|
|
* @todo Create transaction set *much* earlier.
|
2001-01-11 22:13:04 +08:00
|
|
|
*/
|
2017-03-02 18:35:38 +08:00
|
|
|
static rpmRC cpio_doio(FD_t fdo, Package pkg, const char * fmodeMacro,
|
2019-10-03 19:58:11 +08:00
|
|
|
int pld_algo,
|
|
|
|
rpm_loff_t *archiveSize, char ** pldig)
|
1998-04-08 07:58:01 +08:00
|
|
|
{
|
2007-12-18 16:10:03 +08:00
|
|
|
char *failedFile = NULL;
|
2000-01-25 04:02:32 +08:00
|
|
|
FD_t cfd;
|
2012-04-24 17:36:26 +08:00
|
|
|
int fsmrc;
|
2011-03-16 00:58:31 +08:00
|
|
|
|
|
|
|
(void) Fflush(fdo);
|
2011-05-18 16:55:59 +08:00
|
|
|
cfd = Fdopen(fdDup(Fileno(fdo)), fmodeMacro);
|
2001-05-04 05:00:18 +08:00
|
|
|
if (cfd == NULL)
|
2007-12-07 15:28:39 +08:00
|
|
|
return RPMRC_FAIL;
|
2001-02-02 23:04:44 +08:00
|
|
|
|
2019-10-03 19:58:11 +08:00
|
|
|
/* Calculate alternative (uncompressed) payload digest while writing */
|
|
|
|
fdInitDigestID(cfd, pld_algo, RPMTAG_PAYLOADDIGESTALT, 0);
|
2013-04-15 18:53:45 +08:00
|
|
|
fsmrc = rpmPackageFilesArchive(pkg->cpioList, headerIsSource(pkg->header),
|
2013-11-19 16:20:53 +08:00
|
|
|
cfd, pkg->dpaths,
|
2017-03-02 18:35:38 +08:00
|
|
|
archiveSize, &failedFile);
|
2019-10-03 19:58:11 +08:00
|
|
|
fdFiniDigest(cfd, RPMTAG_PAYLOADDIGESTALT, (void **)pldig, NULL, 1);
|
2011-03-16 00:58:31 +08:00
|
|
|
|
2012-01-11 21:11:37 +08:00
|
|
|
if (fsmrc) {
|
2013-11-26 22:28:31 +08:00
|
|
|
char *emsg = rpmfileStrerror(fsmrc);
|
2001-06-20 14:29:20 +08:00
|
|
|
if (failedFile)
|
2012-07-02 21:15:41 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("create archive failed on file %s: %s\n"),
|
2013-02-20 03:55:24 +08:00
|
|
|
failedFile, emsg);
|
2001-06-20 14:29:20 +08:00
|
|
|
else
|
2013-02-20 03:55:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("create archive failed: %s\n"), emsg);
|
|
|
|
free(emsg);
|
1998-11-20 02:10:28 +08:00
|
|
|
}
|
2011-03-16 00:58:31 +08:00
|
|
|
|
2011-05-18 17:04:12 +08:00
|
|
|
free(failedFile);
|
2012-01-11 21:11:37 +08:00
|
|
|
Fclose(cfd);
|
1999-01-06 07:13:56 +08:00
|
|
|
|
2012-01-11 21:11:37 +08:00
|
|
|
return (fsmrc == 0) ? RPMRC_OK : RPMRC_FAIL;
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
2011-05-18 18:23:29 +08:00
|
|
|
static rpmRC addFileToTag(rpmSpec spec, const char * file,
|
|
|
|
Header h, rpmTagVal tag, int append)
|
1998-10-12 04:58:58 +08:00
|
|
|
{
|
2011-05-18 18:23:29 +08:00
|
|
|
StringBuf sb = NULL;
|
2011-05-18 17:47:50 +08:00
|
|
|
rpmRC rc = RPMRC_FAIL; /* assume failure */
|
2019-10-07 19:04:46 +08:00
|
|
|
int flags = ALLOW_EMPTY;
|
1998-10-12 04:58:58 +08:00
|
|
|
|
2011-05-18 18:23:29 +08:00
|
|
|
/* no script file is not an error */
|
|
|
|
if (file == NULL)
|
|
|
|
return RPMRC_OK;
|
|
|
|
|
2019-10-07 19:04:46 +08:00
|
|
|
sb = newStringBuf();
|
2019-06-11 15:50:01 +08:00
|
|
|
#pragma omp critical
|
|
|
|
{
|
2011-05-18 17:47:50 +08:00
|
|
|
if (append) {
|
|
|
|
const char *s = headerGetString(h, tag);
|
|
|
|
if (s) {
|
|
|
|
appendLineStringBuf(sb, s);
|
|
|
|
headerDel(h, tag);
|
|
|
|
}
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
2011-05-18 17:47:50 +08:00
|
|
|
|
2019-10-07 19:04:46 +08:00
|
|
|
if (readManifest(spec, file, rpmTagGetName(tag), flags, NULL, &sb) >= 0) {
|
|
|
|
headerPutString(h, tag, getStringBuf(sb));
|
|
|
|
rc = RPMRC_OK;
|
1998-10-12 04:58:58 +08:00
|
|
|
}
|
1999-10-28 07:18:10 +08:00
|
|
|
|
2019-06-11 15:50:01 +08:00
|
|
|
} /* omp critical */
|
2019-10-07 19:04:46 +08:00
|
|
|
freeStringBuf(sb);
|
2008-03-25 01:01:12 +08:00
|
|
|
|
2011-05-18 17:47:50 +08:00
|
|
|
return rc;
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
1998-10-12 04:58:58 +08:00
|
|
|
|
2007-12-07 16:43:53 +08:00
|
|
|
static rpmRC processScriptFiles(rpmSpec spec, Package pkg)
|
1996-02-19 10:24:47 +08:00
|
|
|
{
|
2000-01-25 04:02:32 +08:00
|
|
|
struct TriggerFileEntry *p;
|
2010-03-11 18:06:49 +08:00
|
|
|
int addflags = 0;
|
2011-05-18 18:23:29 +08:00
|
|
|
rpmRC rc = RPMRC_FAIL;
|
|
|
|
Header h = pkg->header;
|
2014-07-02 19:26:49 +08:00
|
|
|
struct TriggerFileEntry *tfa[] = {pkg->triggerFiles,
|
|
|
|
pkg->fileTriggerFiles,
|
|
|
|
pkg->transFileTriggerFiles};
|
|
|
|
|
|
|
|
rpmTagVal progTags[] = {RPMTAG_TRIGGERSCRIPTPROG,
|
|
|
|
RPMTAG_FILETRIGGERSCRIPTPROG,
|
|
|
|
RPMTAG_TRANSFILETRIGGERSCRIPTPROG};
|
|
|
|
|
|
|
|
rpmTagVal flagTags[] = {RPMTAG_TRIGGERSCRIPTFLAGS,
|
|
|
|
RPMTAG_FILETRIGGERSCRIPTFLAGS,
|
|
|
|
RPMTAG_TRANSFILETRIGGERSCRIPTFLAGS};
|
|
|
|
|
|
|
|
rpmTagVal scriptTags[] = {RPMTAG_TRIGGERSCRIPTS,
|
|
|
|
RPMTAG_FILETRIGGERSCRIPTS,
|
|
|
|
RPMTAG_TRANSFILETRIGGERSCRIPTS};
|
2015-05-04 22:29:46 +08:00
|
|
|
rpmTagVal priorityTags[] = {0,
|
|
|
|
RPMTAG_FILETRIGGERPRIORITIES,
|
|
|
|
RPMTAG_TRANSFILETRIGGERPRIORITIES};
|
2014-07-02 19:26:49 +08:00
|
|
|
int i;
|
2000-01-25 04:02:32 +08:00
|
|
|
|
2011-05-18 18:23:29 +08:00
|
|
|
if (addFileToTag(spec, pkg->preInFile, h, RPMTAG_PREIN, 1) ||
|
|
|
|
addFileToTag(spec, pkg->preUnFile, h, RPMTAG_PREUN, 1) ||
|
|
|
|
addFileToTag(spec, pkg->preTransFile, h, RPMTAG_PRETRANS, 1) ||
|
|
|
|
addFileToTag(spec, pkg->postInFile, h, RPMTAG_POSTIN, 1) ||
|
|
|
|
addFileToTag(spec, pkg->postUnFile, h, RPMTAG_POSTUN, 1) ||
|
|
|
|
addFileToTag(spec, pkg->postTransFile, h, RPMTAG_POSTTRANS, 1) ||
|
|
|
|
addFileToTag(spec, pkg->verifyFile, h, RPMTAG_VERIFYSCRIPT, 1))
|
|
|
|
{
|
|
|
|
goto exit;
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
|
|
|
|
2010-03-11 18:06:49 +08:00
|
|
|
|
2014-07-02 19:26:49 +08:00
|
|
|
for (i = 0; i < sizeof(tfa)/sizeof(tfa[0]); i++) {
|
|
|
|
addflags = 0;
|
|
|
|
/* if any trigger has flags, we need to add flags entry for all of them */
|
|
|
|
for (p = tfa[i]; p != NULL; p = p->next) {
|
|
|
|
if (p->flags) {
|
|
|
|
addflags = 1;
|
|
|
|
break;
|
|
|
|
}
|
2010-03-11 18:06:49 +08:00
|
|
|
}
|
2008-06-17 17:10:01 +08:00
|
|
|
|
2014-07-02 19:26:49 +08:00
|
|
|
for (p = tfa[i]; p != NULL; p = p->next) {
|
|
|
|
headerPutString(h, progTags[i], p->prog);
|
|
|
|
|
2015-05-04 22:29:46 +08:00
|
|
|
if (priorityTags[i]) {
|
|
|
|
headerPutUint32(h, priorityTags[i], &p->priority, 1);
|
|
|
|
}
|
|
|
|
|
2014-07-02 19:26:49 +08:00
|
|
|
if (addflags) {
|
|
|
|
headerPutUint32(h, flagTags[i], &p->flags, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->script) {
|
|
|
|
headerPutString(h, scriptTags[i], p->script);
|
|
|
|
} else if (p->fileName) {
|
|
|
|
if (addFileToTag(spec, p->fileName, h, scriptTags[i], 0)) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* This is dumb. When the header supports NULL string */
|
|
|
|
/* this will go away. */
|
|
|
|
headerPutString(h, scriptTags[i], "");
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-18 18:23:29 +08:00
|
|
|
rc = RPMRC_OK;
|
2000-01-25 04:02:32 +08:00
|
|
|
|
2011-05-18 18:23:29 +08:00
|
|
|
exit:
|
|
|
|
return rc;
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
|
|
|
|
2018-11-21 22:36:35 +08:00
|
|
|
struct charInDepData {
|
|
|
|
char c;
|
|
|
|
int present;
|
|
|
|
};
|
|
|
|
|
|
|
|
static rpmRC charInDepCb(void *cbdata, rpmrichParseType type,
|
|
|
|
const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
|
|
|
|
rpmrichOp op, char **emsg) {
|
|
|
|
struct charInDepData *data = cbdata;
|
2019-03-07 21:25:52 +08:00
|
|
|
if (e && data && memchr(e, data->c, el))
|
2018-11-21 22:36:35 +08:00
|
|
|
data->present = 1;
|
|
|
|
|
|
|
|
return RPMRC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int haveCharInDep(Package pkg, char c)
|
2012-04-23 16:04:02 +08:00
|
|
|
{
|
2018-11-21 22:36:35 +08:00
|
|
|
struct charInDepData data = {c, 0};
|
2014-09-10 17:23:19 +08:00
|
|
|
for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
|
|
|
|
rpmds ds = rpmdsInit(pkg->dependencies[i]);
|
|
|
|
while (rpmdsNext(ds) >= 0) {
|
2018-11-21 22:36:35 +08:00
|
|
|
if (rpmdsIsRich(ds)) {
|
|
|
|
const char *depstr = rpmdsN(ds);
|
|
|
|
rpmrichParse(&depstr, NULL, charInDepCb, &data);
|
|
|
|
} else {
|
|
|
|
const char *evr = rpmdsEVR(ds);
|
|
|
|
if (strchr(evr, c))
|
|
|
|
data.present = 1;
|
|
|
|
}
|
|
|
|
if (data.present)
|
2014-09-10 17:23:19 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2012-04-23 16:04:02 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-12 22:45:27 +08:00
|
|
|
static int haveRichDep(Package pkg)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
|
|
|
|
rpmds ds = rpmdsInit(pkg->dependencies[i]);
|
|
|
|
rpmTagVal tagN = rpmdsTagN(ds);
|
2018-11-21 21:59:19 +08:00
|
|
|
if (tagN != RPMTAG_REQUIRENAME &&
|
|
|
|
tagN != RPMTAG_RECOMMENDNAME &&
|
|
|
|
tagN != RPMTAG_SUGGESTNAME &&
|
|
|
|
tagN != RPMTAG_SUPPLEMENTNAME &&
|
|
|
|
tagN != RPMTAG_ENHANCENAME &&
|
|
|
|
tagN != RPMTAG_CONFLICTNAME)
|
2014-09-12 22:45:27 +08:00
|
|
|
continue;
|
|
|
|
while (rpmdsNext(ds) >= 0) {
|
2015-08-31 22:40:20 +08:00
|
|
|
if (rpmdsIsRich(ds))
|
2014-09-12 22:45:27 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-27 17:11:06 +08:00
|
|
|
static char *getIOFlags(Package pkg)
|
2000-01-25 04:02:32 +08:00
|
|
|
{
|
2017-02-27 17:11:06 +08:00
|
|
|
char *rpmio_flags;
|
2010-08-23 14:51:52 +08:00
|
|
|
const char *s;
|
2002-12-22 04:37:37 +08:00
|
|
|
|
2000-06-23 09:19:45 +08:00
|
|
|
/* Save payload information */
|
2013-04-15 18:44:09 +08:00
|
|
|
if (headerIsSource(pkg->header))
|
2001-12-07 02:34:49 +08:00
|
|
|
rpmio_flags = rpmExpand("%{?_source_payload}", NULL);
|
2007-12-02 03:06:00 +08:00
|
|
|
else
|
2001-12-07 02:34:49 +08:00
|
|
|
rpmio_flags = rpmExpand("%{?_binary_payload}", NULL);
|
2007-12-02 03:06:00 +08:00
|
|
|
|
2011-05-18 16:55:59 +08:00
|
|
|
/* If not configured or bogus, fall back to gz */
|
|
|
|
if (rpmio_flags[0] != 'w') {
|
|
|
|
free(rpmio_flags);
|
2000-06-23 09:19:45 +08:00
|
|
|
rpmio_flags = xstrdup("w9.gzdio");
|
|
|
|
}
|
|
|
|
s = strchr(rpmio_flags, '.');
|
|
|
|
if (s) {
|
2011-05-18 20:53:54 +08:00
|
|
|
char *buf = NULL;
|
2008-04-15 14:16:05 +08:00
|
|
|
const char *compr = NULL;
|
2013-04-15 18:44:09 +08:00
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADFORMAT, "cpio");
|
2008-06-17 17:10:01 +08:00
|
|
|
|
2011-02-15 20:39:29 +08:00
|
|
|
if (rstreq(s+1, "ufdio")) {
|
|
|
|
compr = NULL;
|
|
|
|
} else if (rstreq(s+1, "gzdio")) {
|
2008-04-15 14:16:05 +08:00
|
|
|
compr = "gzip";
|
2009-04-13 18:58:39 +08:00
|
|
|
#if HAVE_BZLIB_H
|
2009-08-31 16:08:05 +08:00
|
|
|
} else if (rstreq(s+1, "bzdio")) {
|
2008-04-15 14:16:05 +08:00
|
|
|
compr = "bzip2";
|
2000-06-23 09:19:45 +08:00
|
|
|
/* Add prereq on rpm version that understands bzip2 payloads */
|
2013-04-15 19:08:24 +08:00
|
|
|
(void) rpmlibNeedsFeature(pkg, "PayloadIsBzip2", "3.0.5-1");
|
2009-04-13 18:58:39 +08:00
|
|
|
#endif
|
|
|
|
#if HAVE_LZMA_H
|
2009-08-31 16:08:05 +08:00
|
|
|
} else if (rstreq(s+1, "xzdio")) {
|
2009-03-18 15:42:23 +08:00
|
|
|
compr = "xz";
|
2013-04-15 19:08:24 +08:00
|
|
|
(void) rpmlibNeedsFeature(pkg, "PayloadIsXz", "5.2-1");
|
2009-08-31 16:08:05 +08:00
|
|
|
} else if (rstreq(s+1, "lzdio")) {
|
2009-03-18 17:24:52 +08:00
|
|
|
compr = "lzma";
|
2013-04-15 19:08:24 +08:00
|
|
|
(void) rpmlibNeedsFeature(pkg, "PayloadIsLzma", "4.4.6-1");
|
2017-08-09 22:42:56 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ZSTD
|
|
|
|
} else if (rstreq(s+1, "zstdio")) {
|
|
|
|
compr = "zstd";
|
|
|
|
/* Add prereq on rpm version that understands zstd payloads */
|
|
|
|
(void) rpmlibNeedsFeature(pkg, "PayloadIsZstd", "5.4.18-1");
|
2009-04-13 18:58:39 +08:00
|
|
|
#endif
|
2008-04-15 14:16:05 +08:00
|
|
|
} else {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Unknown payload compression: %s\n"),
|
|
|
|
rpmio_flags);
|
2017-02-27 17:11:06 +08:00
|
|
|
rpmio_flags = _free(rpmio_flags);
|
2008-04-15 14:16:05 +08:00
|
|
|
goto exit;
|
2000-06-23 09:19:45 +08:00
|
|
|
}
|
2008-04-15 14:16:05 +08:00
|
|
|
|
2011-02-15 20:39:29 +08:00
|
|
|
if (compr)
|
2013-04-15 18:44:09 +08:00
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADCOMPRESSOR, compr);
|
2008-03-23 20:48:49 +08:00
|
|
|
buf = xstrdup(rpmio_flags);
|
2000-07-10 07:10:25 +08:00
|
|
|
buf[s - rpmio_flags] = '\0';
|
2013-04-15 18:44:09 +08:00
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADFLAGS, buf+1);
|
2008-03-23 20:48:49 +08:00
|
|
|
free(buf);
|
2000-06-23 09:19:45 +08:00
|
|
|
}
|
2017-02-27 17:11:06 +08:00
|
|
|
exit:
|
|
|
|
return rpmio_flags;
|
|
|
|
}
|
|
|
|
|
2017-02-28 19:12:57 +08:00
|
|
|
static void finalizeDeps(Package pkg)
|
|
|
|
{
|
|
|
|
/* check if the package has a dependency with a '~' */
|
2018-11-21 22:36:35 +08:00
|
|
|
if (haveCharInDep(pkg, '~'))
|
2017-02-28 19:12:57 +08:00
|
|
|
(void) rpmlibNeedsFeature(pkg, "TildeInVersions", "4.10.0-1");
|
|
|
|
|
2016-09-10 17:39:23 +08:00
|
|
|
/* check if the package has a dependency with a '^' */
|
|
|
|
if (haveCharInDep(pkg, '^'))
|
|
|
|
(void) rpmlibNeedsFeature(pkg, "CaretInVersions", "4.15.0-1");
|
|
|
|
|
2017-02-28 19:12:57 +08:00
|
|
|
/* check if the package has a rich dependency */
|
|
|
|
if (haveRichDep(pkg))
|
|
|
|
(void) rpmlibNeedsFeature(pkg, "RichDependencies", "4.12.0-1");
|
|
|
|
|
|
|
|
/* All dependencies added finally, write them into the header */
|
|
|
|
for (int i = 0; i < PACKAGE_NUM_DEPS; i++) {
|
|
|
|
/* Nuke any previously added dependencies from the header */
|
|
|
|
headerDel(pkg->header, rpmdsTagN(pkg->dependencies[i]));
|
|
|
|
headerDel(pkg->header, rpmdsTagEVR(pkg->dependencies[i]));
|
|
|
|
headerDel(pkg->header, rpmdsTagF(pkg->dependencies[i]));
|
|
|
|
headerDel(pkg->header, rpmdsTagTi(pkg->dependencies[i]));
|
|
|
|
/* ...and add again, now with automatic dependencies included */
|
|
|
|
rpmdsPutToHeader(pkg->dependencies[i], pkg->header);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-01 13:22:32 +08:00
|
|
|
static void *nullDigest(int algo, int ascii)
|
|
|
|
{
|
|
|
|
void *d = NULL;
|
|
|
|
DIGEST_CTX ctx = rpmDigestInit(algo, 0);
|
|
|
|
rpmDigestFinal(ctx, &d, NULL, ascii);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2017-03-01 19:38:52 +08:00
|
|
|
static rpmRC fdJump(FD_t fd, off_t offset)
|
|
|
|
{
|
|
|
|
if (Fseek(fd, offset, SEEK_SET) < 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
|
|
|
|
Fdescr(fd), Fstrerror(fd));
|
|
|
|
return RPMRC_FAIL;
|
|
|
|
}
|
|
|
|
return RPMRC_OK;
|
|
|
|
}
|
|
|
|
|
2017-03-01 20:06:45 +08:00
|
|
|
static rpmRC fdConsume(FD_t fd, off_t start, off_t nbytes)
|
|
|
|
{
|
|
|
|
size_t bufsiz = 32*BUFSIZ;
|
|
|
|
unsigned char buf[bufsiz];
|
|
|
|
off_t left = nbytes;
|
|
|
|
ssize_t nb;
|
|
|
|
|
|
|
|
if (start && fdJump(fd, start))
|
|
|
|
return RPMRC_FAIL;
|
|
|
|
|
|
|
|
while (left > 0) {
|
|
|
|
nb = Fread(buf, 1, (left < bufsiz) ? left : bufsiz, fd);
|
|
|
|
if (nb > 0)
|
|
|
|
left -= nb;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (left) {
|
2017-10-06 05:00:49 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Failed to read %jd bytes in file %s: %s\n"),
|
|
|
|
(intmax_t) nbytes, Fdescr(fd), Fstrerror(fd));
|
2017-03-01 20:06:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return (left == 0) ? RPMRC_OK : RPMRC_FAIL;
|
|
|
|
}
|
|
|
|
|
2017-03-01 19:50:36 +08:00
|
|
|
static rpmRC writeHdr(FD_t fd, Header pkgh)
|
|
|
|
{
|
|
|
|
/* Reallocate the header into one contiguous region for writing. */
|
|
|
|
Header h = headerReload(headerCopy(pkgh), RPMTAG_HEADERIMMUTABLE);
|
|
|
|
rpmRC rc = RPMRC_FAIL;
|
|
|
|
|
|
|
|
if (h == NULL) {
|
|
|
|
rpmlog(RPMLOG_ERR,_("Unable to create immutable header region\n"));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Unable to write header to %s: %s\n"),
|
|
|
|
Fdescr(fd), Fstrerror(fd));
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
(void) Fflush(fd);
|
|
|
|
rc = RPMRC_OK;
|
|
|
|
|
|
|
|
exit:
|
|
|
|
headerFree(h);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
/*
|
|
|
|
* This is more than just a little insane:
|
|
|
|
* In order to write the signature, we need to know the size and
|
|
|
|
* the size and digests of the header and payload, which are located
|
|
|
|
* after the signature on disk. We also need a digest of the compressed
|
|
|
|
* payload for the main header, and of course the payload is after the
|
|
|
|
* header on disk. So we need to create placeholders for both the
|
|
|
|
* signature and main header that exactly match the final sizes, calculate
|
|
|
|
* the payload digest, then generate and write the real main header to
|
|
|
|
* be able to FINALLY calculate the digests we need for the signature
|
|
|
|
* header. In other words, we need to write things in the exact opposite
|
|
|
|
* order to how the RPM format is laid on disk.
|
|
|
|
*/
|
2017-02-27 17:11:06 +08:00
|
|
|
static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp,
|
2017-06-08 22:08:09 +08:00
|
|
|
const char *fileName, char **cookie,
|
|
|
|
rpm_time_t buildTime, const char* buildHost)
|
2017-02-27 17:11:06 +08:00
|
|
|
{
|
|
|
|
FD_t fd = NULL;
|
|
|
|
char * rpmio_flags = NULL;
|
|
|
|
char * SHA1 = NULL;
|
2017-03-08 20:36:39 +08:00
|
|
|
char * SHA256 = NULL;
|
2017-02-27 17:11:06 +08:00
|
|
|
uint8_t * MD5 = NULL;
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
char * pld = NULL;
|
2019-10-03 19:58:11 +08:00
|
|
|
char * upld = NULL;
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
uint32_t pld_algo = PGPHASHALGO_SHA256; /* TODO: macro configuration */
|
2017-02-27 17:11:06 +08:00
|
|
|
rpmRC rc = RPMRC_FAIL; /* assume failure */
|
2017-03-02 18:35:38 +08:00
|
|
|
rpm_loff_t archiveSize = 0;
|
2017-03-01 20:06:45 +08:00
|
|
|
off_t sigStart, hdrStart, payloadStart, payloadEnd;
|
2017-02-27 17:11:06 +08:00
|
|
|
|
|
|
|
if (pkgidp)
|
|
|
|
*pkgidp = NULL;
|
|
|
|
|
|
|
|
rpmio_flags = getIOFlags(pkg);
|
|
|
|
if (!rpmio_flags)
|
|
|
|
goto exit;
|
2000-06-23 09:19:45 +08:00
|
|
|
|
2017-02-28 19:12:57 +08:00
|
|
|
finalizeDeps(pkg);
|
2014-09-09 17:58:08 +08:00
|
|
|
|
1998-01-13 05:31:29 +08:00
|
|
|
/* Create and add the cookie */
|
|
|
|
if (cookie) {
|
2017-06-08 22:08:09 +08:00
|
|
|
rasprintf(cookie, "%s %d", buildHost, buildTime);
|
2013-04-15 18:44:09 +08:00
|
|
|
headerPutString(pkg->header, RPMTAG_COOKIE, *cookie);
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
|
2019-10-03 19:58:11 +08:00
|
|
|
/* Create a dummy payload digests to get the header size right */
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
pld = nullDigest(pld_algo, 1);
|
|
|
|
headerPutUint32(pkg->header, RPMTAG_PAYLOADDIGESTALGO, &pld_algo, 1);
|
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
|
2019-10-03 19:58:11 +08:00
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADDIGESTALT, pld);
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
pld = _free(pld);
|
1998-01-13 05:31:29 +08:00
|
|
|
|
2014-09-08 18:46:48 +08:00
|
|
|
/* Check for UTF-8 encoding of string tags, add encoding tag if all good */
|
2017-02-27 17:02:51 +08:00
|
|
|
if (checkForEncoding(pkg->header, 1))
|
2017-02-28 19:01:32 +08:00
|
|
|
goto exit;
|
2014-09-08 18:46:48 +08:00
|
|
|
|
1998-01-13 05:31:29 +08:00
|
|
|
/* Open the output file */
|
2014-04-30 16:45:13 +08:00
|
|
|
fd = Fopen(fileName, "w+.ufdio");
|
1999-11-13 01:20:49 +08:00
|
|
|
if (fd == NULL || Ferror(fd)) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Could not open %s: %s\n"),
|
1999-11-13 01:20:49 +08:00
|
|
|
fileName, Fstrerror(fd));
|
2000-11-07 21:16:43 +08:00
|
|
|
goto exit;
|
1996-03-30 04:06:02 +08:00
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
|
2000-12-03 05:53:44 +08:00
|
|
|
/* Write the lead section into the package. */
|
2017-02-27 17:02:51 +08:00
|
|
|
if (rpmLeadWrite(fd, pkg->header)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd));
|
2016-10-27 15:48:26 +08:00
|
|
|
goto exit;
|
1996-02-19 10:24:47 +08:00
|
|
|
}
|
|
|
|
|
2014-04-30 16:45:13 +08:00
|
|
|
/* Save the position of signature section */
|
|
|
|
sigStart = Ftell(fd);
|
|
|
|
|
|
|
|
/* Generate and write a placeholder signature header */
|
2017-03-01 13:22:32 +08:00
|
|
|
SHA1 = nullDigest(PGPHASHALGO_SHA1, 1);
|
2017-03-08 20:36:39 +08:00
|
|
|
SHA256 = nullDigest(PGPHASHALGO_SHA256, 1);
|
2017-03-01 13:22:32 +08:00
|
|
|
MD5 = nullDigest(PGPHASHALGO_MD5, 0);
|
2017-03-08 20:36:39 +08:00
|
|
|
if (rpmGenerateSignature(SHA256, SHA1, MD5, 0, 0, fd))
|
2000-11-07 21:16:43 +08:00
|
|
|
goto exit;
|
2017-03-01 13:22:32 +08:00
|
|
|
SHA1 = _free(SHA1);
|
2017-03-08 20:36:39 +08:00
|
|
|
SHA256 = _free(SHA256);
|
2017-03-01 13:22:32 +08:00
|
|
|
MD5 = _free(MD5);
|
2000-12-03 05:53:44 +08:00
|
|
|
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
/* Write a placeholder header. */
|
2017-02-28 19:24:15 +08:00
|
|
|
hdrStart = Ftell(fd);
|
2017-03-01 19:50:36 +08:00
|
|
|
if (writeHdr(fd, pkg->header))
|
2000-11-07 21:16:43 +08:00
|
|
|
goto exit;
|
2000-12-03 05:53:44 +08:00
|
|
|
|
2014-04-30 16:45:13 +08:00
|
|
|
/* Write payload section (cpio archive) */
|
2017-03-01 20:06:45 +08:00
|
|
|
payloadStart = Ftell(fd);
|
2019-10-03 19:58:11 +08:00
|
|
|
if (cpio_doio(fd, pkg, rpmio_flags, pld_algo, &archiveSize, &upld))
|
2014-04-30 16:45:13 +08:00
|
|
|
goto exit;
|
2017-02-28 19:24:15 +08:00
|
|
|
payloadEnd = Ftell(fd);
|
2000-12-03 05:53:44 +08:00
|
|
|
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
/* Re-read payload to calculate compressed digest */
|
|
|
|
fdInitDigestID(fd, pld_algo, RPMTAG_PAYLOADDIGEST, 0);
|
|
|
|
if (fdConsume(fd, payloadStart, payloadEnd - payloadStart))
|
|
|
|
goto exit;
|
|
|
|
fdFiniDigest(fd, RPMTAG_PAYLOADDIGEST, (void **)&pld, NULL, 1);
|
|
|
|
|
2019-10-03 19:58:11 +08:00
|
|
|
/* Insert the payload digests in main header */
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
headerDel(pkg->header, RPMTAG_PAYLOADDIGEST);
|
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADDIGEST, pld);
|
2019-10-03 19:58:11 +08:00
|
|
|
headerDel(pkg->header, RPMTAG_PAYLOADDIGESTALT);
|
|
|
|
headerPutString(pkg->header, RPMTAG_PAYLOADDIGESTALT, upld);
|
Implement a digest on the compressed payload content (#163)
There needs to be a way to verify the payload before trying to uncompress
and unpack it:
- We have digests on the contents of individual files, but detecting
corruption in middle of installation, after all sorts of scripts might
have already run, is no good at all
- Compresssion libraries have vulnerabilities of their own
- The RPMv3 digest covering the payload is the obsolete MD5, and furthermore
it covers the header AND the payload, which is extremely cumbersome
to begin with but also vulnerable because it's in the unprotected
signature header.
This adds two tags: one for the actual digest, and another for the
algorithm, much like with filedigests. The digest tag is specified
as a string array to leave room for future expansion: the idea is
that there could be intermediate snapshots over the payload, and
the last one is always on the entire payload, so an array of just
one is compatible with this specification.
Getting the digest into the main header is fairly complicated since the
package format on-disk is exactly in the opposite order of how we need
to write things there, add a lenghty comment to writeRPM() to explain.
The MD5 digest needs to die, really - it forces a second read over
the entire header + payload for what is practically worthless hash.
Note that there's no code to actually verify this digest at the moment,
nor is there a way to configure the used algorithm, SHA256 is used as the
default for now.
2017-03-01 21:03:55 +08:00
|
|
|
pld = _free(pld);
|
|
|
|
|
|
|
|
/* Write the final header */
|
|
|
|
if (fdJump(fd, hdrStart))
|
|
|
|
goto exit;
|
|
|
|
if (writeHdr(fd, pkg->header))
|
|
|
|
goto exit;
|
|
|
|
|
2017-03-01 20:06:45 +08:00
|
|
|
/* Calculate digests: SHA on header, legacy MD5 on header + payload */
|
|
|
|
fdInitDigestID(fd, PGPHASHALGO_MD5, RPMTAG_SIGMD5, 0);
|
|
|
|
fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMTAG_SHA1HEADER, 0);
|
2017-03-08 20:36:39 +08:00
|
|
|
fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMTAG_SHA256HEADER, 0);
|
2017-03-01 20:06:45 +08:00
|
|
|
if (fdConsume(fd, hdrStart, payloadStart - hdrStart))
|
2014-04-30 16:45:13 +08:00
|
|
|
goto exit;
|
2017-03-01 20:06:45 +08:00
|
|
|
fdFiniDigest(fd, RPMTAG_SHA1HEADER, (void **)&SHA1, NULL, 1);
|
2017-03-08 20:36:39 +08:00
|
|
|
fdFiniDigest(fd, RPMTAG_SHA256HEADER, (void **)&SHA256, NULL, 1);
|
2000-12-03 05:53:44 +08:00
|
|
|
|
2017-03-01 20:06:45 +08:00
|
|
|
if (fdConsume(fd, 0, payloadEnd - payloadStart))
|
2014-04-30 16:45:13 +08:00
|
|
|
goto exit;
|
2017-02-27 14:39:15 +08:00
|
|
|
fdFiniDigest(fd, RPMTAG_SIGMD5, (void **)&MD5, NULL, 0);
|
2014-04-30 16:45:13 +08:00
|
|
|
|
2017-03-01 19:38:52 +08:00
|
|
|
if (fdJump(fd, sigStart))
|
2014-04-30 16:45:13 +08:00
|
|
|
goto exit;
|
|
|
|
|
|
|
|
/* Generate the signature. Now with right values */
|
2017-03-08 20:36:39 +08:00
|
|
|
if (rpmGenerateSignature(SHA256, SHA1, MD5, payloadEnd - hdrStart, archiveSize, fd))
|
2014-04-30 16:45:13 +08:00
|
|
|
goto exit;
|
2017-02-27 17:02:51 +08:00
|
|
|
|
|
|
|
rc = RPMRC_OK;
|
1996-06-28 01:21:31 +08:00
|
|
|
|
2000-11-07 21:16:43 +08:00
|
|
|
exit:
|
2011-05-27 20:38:54 +08:00
|
|
|
free(rpmio_flags);
|
|
|
|
free(SHA1);
|
2017-03-08 20:36:39 +08:00
|
|
|
free(SHA256);
|
2019-11-08 18:32:14 +08:00
|
|
|
free(upld);
|
2002-12-24 10:41:45 +08:00
|
|
|
|
|
|
|
/* XXX Fish the pkgid out of the signature header. */
|
2014-04-30 16:45:13 +08:00
|
|
|
if (pkgidp != NULL) {
|
|
|
|
if (MD5 != NULL) {
|
|
|
|
*pkgidp = MD5;
|
2008-05-26 20:25:11 +08:00
|
|
|
}
|
2017-08-31 18:15:06 +08:00
|
|
|
} else {
|
|
|
|
free(MD5);
|
2002-12-24 10:41:45 +08:00
|
|
|
}
|
|
|
|
|
2011-05-19 16:08:07 +08:00
|
|
|
Fclose(fd);
|
|
|
|
|
2007-12-07 15:28:39 +08:00
|
|
|
if (rc == RPMRC_OK)
|
2007-10-09 19:50:42 +08:00
|
|
|
rpmlog(RPMLOG_NOTICE, _("Wrote: %s\n"), fileName);
|
2000-11-07 21:16:43 +08:00
|
|
|
else
|
2007-12-03 22:33:18 +08:00
|
|
|
(void) unlink(fileName);
|
2000-11-07 21:16:43 +08:00
|
|
|
|
|
|
|
return rc;
|
1995-12-21 06:49:40 +08:00
|
|
|
}
|
|
|
|
|
2010-10-22 18:31:34 +08:00
|
|
|
static const rpmTagVal copyTags[] = {
|
2000-01-25 04:02:32 +08:00
|
|
|
RPMTAG_CHANGELOGTIME,
|
|
|
|
RPMTAG_CHANGELOGNAME,
|
|
|
|
RPMTAG_CHANGELOGTEXT,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2010-08-24 18:39:42 +08:00
|
|
|
static rpmRC checkPackages(char *pkgcheck)
|
2008-11-10 22:52:29 +08:00
|
|
|
{
|
|
|
|
int fail = rpmExpandNumeric("%{?_nonzero_exit_pkgcheck_terminate_build}");
|
|
|
|
int xx;
|
|
|
|
|
|
|
|
rpmlog(RPMLOG_NOTICE, _("Executing \"%s\":\n"), pkgcheck);
|
|
|
|
xx = system(pkgcheck);
|
|
|
|
if (WEXITSTATUS(xx) == -1 || WEXITSTATUS(xx) == 127) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Execution of \"%s\" failed.\n"), pkgcheck);
|
2010-09-21 16:37:21 +08:00
|
|
|
if (fail) return RPMRC_NOTFOUND;
|
2008-11-10 22:52:29 +08:00
|
|
|
}
|
|
|
|
if (WEXITSTATUS(xx) != 0) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Package check \"%s\" failed.\n"), pkgcheck);
|
|
|
|
if (fail) return RPMRC_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RPMRC_OK;
|
|
|
|
}
|
|
|
|
|
2019-05-07 17:47:34 +08:00
|
|
|
static rpmRC checkPackageSet(Package pkgs)
|
|
|
|
{
|
|
|
|
char *pkglist = NULL;
|
|
|
|
char *pkgcheck_set = NULL;
|
|
|
|
|
|
|
|
for (Package pkg = pkgs; pkg != NULL; pkg = pkg->next) {
|
|
|
|
if (pkg->filename)
|
|
|
|
rstrscat(&pkglist, pkg->filename, " ", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
pkgcheck_set = rpmExpand("%{?_build_pkgcheck_set} ", pkglist, NULL);
|
|
|
|
|
|
|
|
/* run only if _build_pkgcheck_set is defined */
|
|
|
|
if (pkgcheck_set[0] != ' ')
|
|
|
|
checkPackages(pkgcheck_set);
|
|
|
|
|
|
|
|
free(pkgcheck_set);
|
|
|
|
free(pkglist);
|
|
|
|
return RPMRC_OK;
|
|
|
|
}
|
|
|
|
|
2019-05-07 17:09:42 +08:00
|
|
|
/* watchout, argument is modified */
|
|
|
|
static rpmRC ensureDir(char *binRpm)
|
|
|
|
{
|
|
|
|
rpmRC rc = RPMRC_OK;
|
|
|
|
char *binDir = strchr(binRpm, '/');
|
|
|
|
char *dn = NULL;
|
|
|
|
if (binDir) {
|
|
|
|
struct stat st;
|
|
|
|
*binDir = '\0';
|
|
|
|
dn = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
|
|
|
|
if (stat(dn, &st) < 0) {
|
|
|
|
switch (errno) {
|
|
|
|
case ENOENT:
|
|
|
|
if (mkdir(dn, 0755) == 0 || errno == EEXIST)
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rpmlog(RPMLOG_ERR,_("cannot create %s: %s\n"),
|
|
|
|
dn, strerror(errno));
|
|
|
|
rc = RPMRC_FAIL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(dn);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rpmRC getPkgFilename(Header h, char **filename)
|
1999-09-18 07:18:24 +08:00
|
|
|
{
|
2019-05-07 16:12:08 +08:00
|
|
|
const char *errorString;
|
2019-05-07 17:09:42 +08:00
|
|
|
char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
|
|
|
|
char *binRpm = headerFormat(h, binFormat, &errorString);
|
|
|
|
rpmRC rc = RPMRC_FAIL;
|
|
|
|
|
|
|
|
if (binRpm == NULL) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Could not generate output "
|
|
|
|
"filename for package %s: %s\n"),
|
|
|
|
headerGetString(h, RPMTAG_NAME), errorString);
|
|
|
|
} else {
|
|
|
|
*filename = rpmGetPath("%{_rpmdir}/", binRpm, NULL);
|
|
|
|
rc = ensureDir(binRpm);
|
|
|
|
}
|
|
|
|
free(binFormat);
|
|
|
|
free(binRpm);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static rpmRC packageBinary(rpmSpec spec, Package pkg, const char *cookie, int cheating, char** filename)
|
|
|
|
{
|
2019-05-07 16:12:08 +08:00
|
|
|
rpmRC rc = RPMRC_OK;
|
1995-12-21 06:49:40 +08:00
|
|
|
|
2019-05-07 16:12:08 +08:00
|
|
|
if (pkg->fileList == NULL)
|
|
|
|
return rc;
|
2010-12-23 15:24:25 +08:00
|
|
|
|
2019-05-07 16:12:08 +08:00
|
|
|
if ((rc = processScriptFiles(spec, pkg)))
|
|
|
|
return rc;
|
1998-07-25 23:33:15 +08:00
|
|
|
|
2019-05-07 16:12:08 +08:00
|
|
|
if (cookie) {
|
|
|
|
headerPutString(pkg->header, RPMTAG_COOKIE, cookie);
|
|
|
|
}
|
1999-11-13 01:20:49 +08:00
|
|
|
|
2019-05-07 16:12:08 +08:00
|
|
|
/* Copy changelog from src rpm */
|
2019-06-11 20:22:07 +08:00
|
|
|
#pragma omp critical
|
2019-05-07 19:28:13 +08:00
|
|
|
headerCopyTags(spec->sourcePackage->header, pkg->header, copyTags);
|
2019-05-07 16:12:08 +08:00
|
|
|
|
|
|
|
headerPutString(pkg->header, RPMTAG_RPMVERSION, VERSION);
|
|
|
|
headerPutString(pkg->header, RPMTAG_BUILDHOST, spec->buildHost);
|
|
|
|
headerPutUint32(pkg->header, RPMTAG_BUILDTIME, &(spec->buildTime), 1);
|
|
|
|
|
|
|
|
if (spec->sourcePkgId != NULL) {
|
|
|
|
headerPutBin(pkg->header, RPMTAG_SOURCEPKGID, spec->sourcePkgId,16);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cheating) {
|
|
|
|
(void) rpmlibNeedsFeature(pkg, "ShortCircuited", "4.9.0-1");
|
|
|
|
}
|
2010-06-23 20:37:56 +08:00
|
|
|
|
2019-05-07 17:09:42 +08:00
|
|
|
if ((rc = getPkgFilename(pkg->header, filename)))
|
|
|
|
return rc;
|
1998-03-21 06:38:00 +08:00
|
|
|
|
2019-05-07 16:12:08 +08:00
|
|
|
rc = writeRPM(pkg, NULL, *filename, NULL, spec->buildTime, spec->buildHost);
|
|
|
|
if (rc == RPMRC_OK) {
|
|
|
|
/* Do check each written package if enabled */
|
|
|
|
char *pkgcheck = rpmExpand("%{?_build_pkgcheck} ", *filename, NULL);
|
|
|
|
if (pkgcheck[0] != ' ') {
|
|
|
|
rc = checkPackages(pkgcheck);
|
2017-05-25 23:15:27 +08:00
|
|
|
}
|
2019-05-07 16:12:08 +08:00
|
|
|
free(pkgcheck);
|
|
|
|
}
|
|
|
|
return rc;
|
2017-05-25 23:15:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rpmRC packageBinaries(rpmSpec spec, const char *cookie, int cheating)
|
|
|
|
{
|
2019-05-07 17:47:34 +08:00
|
|
|
rpmRC rc = RPMRC_OK;
|
2017-05-25 23:15:27 +08:00
|
|
|
Package pkg;
|
|
|
|
|
2019-05-07 19:34:01 +08:00
|
|
|
/* Run binary creation in parallel */
|
|
|
|
#pragma omp parallel
|
|
|
|
#pragma omp single
|
2017-05-25 23:15:27 +08:00
|
|
|
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
|
2019-05-07 19:34:01 +08:00
|
|
|
#pragma omp task
|
|
|
|
{
|
2019-05-07 17:55:13 +08:00
|
|
|
pkg->rc = packageBinary(spec, pkg, cookie, cheating, &pkg->filename);
|
2019-05-07 19:34:01 +08:00
|
|
|
rpmlog(RPMLOG_DEBUG,
|
|
|
|
_("Finished binary package job, result %d, filename %s\n"),
|
|
|
|
pkg->rc, pkg->filename);
|
2019-05-07 17:55:13 +08:00
|
|
|
if (pkg->rc) {
|
2019-05-07 19:34:01 +08:00
|
|
|
#pragma omp critical
|
2019-05-07 17:55:13 +08:00
|
|
|
rc = pkg->rc;
|
|
|
|
}
|
2019-05-07 19:34:01 +08:00
|
|
|
} /* omp task */
|
|
|
|
if (rc)
|
|
|
|
break;
|
2008-11-10 22:52:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now check the package set if enabled */
|
2019-05-07 17:47:34 +08:00
|
|
|
if (rc == RPMRC_OK)
|
|
|
|
checkPackageSet(spec->packages);
|
|
|
|
|
|
|
|
return rc;
|
1995-12-21 06:49:40 +08:00
|
|
|
}
|
|
|
|
|
2010-09-01 19:00:54 +08:00
|
|
|
rpmRC packageSources(rpmSpec spec, char **cookie)
|
1998-03-21 06:38:00 +08:00
|
|
|
{
|
2013-04-15 18:23:48 +08:00
|
|
|
Package sourcePkg = spec->sourcePackage;
|
2007-12-07 16:43:53 +08:00
|
|
|
rpmRC rc;
|
2017-05-18 17:19:11 +08:00
|
|
|
uint32_t one = 1;
|
1998-03-21 06:38:00 +08:00
|
|
|
|
2000-01-25 04:02:32 +08:00
|
|
|
/* Add some cruft */
|
2013-04-15 18:23:48 +08:00
|
|
|
headerPutString(sourcePkg->header, RPMTAG_RPMVERSION, VERSION);
|
2017-06-08 22:08:09 +08:00
|
|
|
headerPutString(sourcePkg->header, RPMTAG_BUILDHOST, spec->buildHost);
|
|
|
|
headerPutUint32(sourcePkg->header, RPMTAG_BUILDTIME, &(spec->buildTime), 1);
|
2017-05-18 17:19:11 +08:00
|
|
|
headerPutUint32(sourcePkg->header, RPMTAG_SOURCEPACKAGE, &one, 1);
|
1998-03-21 06:38:00 +08:00
|
|
|
|
2018-10-26 16:30:47 +08:00
|
|
|
if (spec->buildrequires) {
|
|
|
|
(void) rpmlibNeedsFeature(sourcePkg, "DynamicBuildRequires", "4.15.0-1");
|
|
|
|
}
|
|
|
|
|
2000-01-25 04:02:32 +08:00
|
|
|
/* XXX this should be %_srpmdir */
|
2019-05-07 17:41:22 +08:00
|
|
|
{ sourcePkg->filename = rpmGetPath("%{_srcrpmdir}/", spec->sourceRpmName,NULL);
|
|
|
|
char *pkgcheck = rpmExpand("%{?_build_pkgcheck_srpm} ", sourcePkg->filename, NULL);
|
1998-01-13 05:31:29 +08:00
|
|
|
|
2002-12-24 10:41:45 +08:00
|
|
|
spec->sourcePkgId = NULL;
|
2019-05-07 17:41:22 +08:00
|
|
|
rc = writeRPM(sourcePkg, &spec->sourcePkgId, sourcePkg->filename, cookie, spec->buildTime, spec->buildHost);
|
2002-12-24 10:41:45 +08:00
|
|
|
|
2008-11-10 22:52:29 +08:00
|
|
|
/* Do check SRPM package if enabled */
|
|
|
|
if (rc == RPMRC_OK && pkgcheck[0] != ' ') {
|
|
|
|
rc = checkPackages(pkgcheck);
|
|
|
|
}
|
|
|
|
|
2011-05-27 20:38:54 +08:00
|
|
|
free(pkgcheck);
|
2000-01-25 04:02:32 +08:00
|
|
|
}
|
|
|
|
return rc;
|
1995-12-21 06:49:40 +08:00
|
|
|
}
|