319 lines
7.2 KiB
C
319 lines
7.2 KiB
C
/** \ingroup rpmbuild
|
|
* \file build/policies.c
|
|
* The post-build, packaging of policies
|
|
*/
|
|
|
|
#include "system.h"
|
|
|
|
#include <rpm/rpmbuild.h>
|
|
#include <rpm/argv.h>
|
|
#include <rpm/rpmlog.h>
|
|
#include <rpm/rpmpol.h>
|
|
#include <rpm/rpmbase64.h>
|
|
|
|
#include "rpmio/rpmio_internal.h"
|
|
#include "build/rpmbuild_internal.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#if WITH_SELINUX
|
|
typedef struct ModuleRec_s {
|
|
char *path;
|
|
char *data;
|
|
char *name;
|
|
ARGV_t types;
|
|
uint32_t flags;
|
|
} *ModuleRec;
|
|
|
|
static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
|
|
{
|
|
rpmRC rc = RPMRC_FAIL;
|
|
ARGV_t av;
|
|
uint32_t count;
|
|
struct rpmtd_s policies;
|
|
struct rpmtd_s policynames;
|
|
struct rpmtd_s policyflags;
|
|
struct rpmtd_s policytypes;
|
|
struct rpmtd_s policytypesidx;
|
|
rpmtdReset(&policies);
|
|
rpmtdReset(&policynames);
|
|
rpmtdReset(&policyflags);
|
|
rpmtdReset(&policytypes);
|
|
rpmtdReset(&policytypesidx);
|
|
|
|
if (!mod || !pkg) {
|
|
goto exit;
|
|
}
|
|
|
|
/* check for duplicates */
|
|
if (headerIsEntry(pkg->header, RPMTAG_POLICYNAMES)) {
|
|
int typeCount;
|
|
const char *name;
|
|
char *type;
|
|
int i;
|
|
int idx;
|
|
|
|
headerGet(pkg->header, RPMTAG_POLICYNAMES, &policynames, HEADERGET_MINMEM);
|
|
headerGet(pkg->header, RPMTAG_POLICYFLAGS, &policyflags, HEADERGET_ARGV | HEADERGET_MINMEM);
|
|
headerGet(pkg->header, RPMTAG_POLICYTYPES, &policytypes, HEADERGET_ARGV | HEADERGET_MINMEM);
|
|
headerGet(pkg->header, RPMTAG_POLICYTYPESINDEXES, &policytypesidx, HEADERGET_ARGV | HEADERGET_MINMEM);
|
|
typeCount = rpmtdCount(&policytypes);
|
|
|
|
while ((name = rpmtdNextString(&policynames))) {
|
|
int overlappingtypes = 0;
|
|
|
|
idx = rpmtdGetIndex(&policynames);
|
|
|
|
for (i = 0; i < typeCount; i++) {
|
|
if (((int *) policytypesidx.data)[i] != idx) {
|
|
continue;
|
|
}
|
|
|
|
type = ((char **) policytypes.data)[i];
|
|
|
|
if (rstreq(type, RPMPOL_TYPE_DEFAULT) ||
|
|
argvSearch(mod->types, type, NULL) ||
|
|
argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL)) {
|
|
overlappingtypes = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!overlappingtypes) {
|
|
continue;
|
|
}
|
|
|
|
if (rstreq(mod->name, name)) {
|
|
rpmlog(RPMLOG_ERR, _("Policy module '%s' duplicated with overlapping types\n"), name);
|
|
goto exit;
|
|
}
|
|
|
|
if ((mod->flags && RPMPOL_FLAG_BASE) &&
|
|
(((int *) policyflags.data)[idx] & RPMPOL_FLAG_BASE)) {
|
|
rpmlog(RPMLOG_ERR, _("Base modules '%s' and '%s' have overlapping types\n"), mod->name, name);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (headerIsEntry(pkg->header, RPMTAG_POLICIES)) {
|
|
if (!headerGet(pkg->header, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
|
|
rpmlog(RPMLOG_ERR, _("Failed to get policies from header\n"));
|
|
goto exit;
|
|
}
|
|
count = rpmtdCount(&policies);
|
|
} else {
|
|
count = 0;
|
|
}
|
|
|
|
/* save everything to the header */
|
|
headerPutString(pkg->header, RPMTAG_POLICIES, mod->data);
|
|
headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
|
|
headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &mod->flags, 1);
|
|
|
|
for (av = mod->types; av && *av; av++) {
|
|
headerPutString(pkg->header, RPMTAG_POLICYTYPES, *av);
|
|
headerPutUint32(pkg->header, RPMTAG_POLICYTYPESINDEXES, &count, 1);
|
|
}
|
|
|
|
rc = RPMRC_OK;
|
|
|
|
exit:
|
|
|
|
rpmtdFreeData(&policies);
|
|
rpmtdFreeData(&policynames);
|
|
rpmtdFreeData(&policyflags);
|
|
rpmtdFreeData(&policytypes);
|
|
rpmtdFreeData(&policytypesidx);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static ModuleRec freeModule(ModuleRec mod)
|
|
{
|
|
if (mod) {
|
|
_free(mod->path);
|
|
_free(mod->data);
|
|
_free(mod->name);
|
|
argvFree(mod->types);
|
|
_free(mod);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static ModuleRec newModule(const char *path, const char *name,
|
|
const char *types, uint32_t flags)
|
|
{
|
|
ModuleRec mod;
|
|
uint8_t *raw = NULL;
|
|
ssize_t rawlen = 0;
|
|
const char *buildDir = "%{_builddir}/%{?buildsubdir}/";
|
|
|
|
if (!path) {
|
|
rpmlog(RPMLOG_ERR, _("%%semodule requires a file path\n"));
|
|
return NULL;
|
|
}
|
|
|
|
mod = xcalloc(1, sizeof(*mod));
|
|
|
|
mod->path = rpmGenPath(buildDir, NULL, path);
|
|
|
|
if ((rpmioSlurp(mod->path, &raw, &rawlen)) != 0 || raw == NULL) {
|
|
rpmlog(RPMLOG_ERR, _("Failed to read policy file: %s\n"),
|
|
mod->path);
|
|
goto err;
|
|
}
|
|
|
|
mod->data = rpmBase64Encode(raw, rawlen, -1);
|
|
if (!mod->data) {
|
|
rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"),
|
|
mod->path);
|
|
goto err;
|
|
}
|
|
|
|
if (name) {
|
|
mod->name = xstrdup(name);
|
|
} else {
|
|
/* assume base name (minus extension) if name is not given */
|
|
char *tmp = xstrdup(mod->path);
|
|
char *bname = basename(tmp);
|
|
char *end = strchr(bname, '.');
|
|
if (end)
|
|
*end = '\0';
|
|
if (strlen(bname) > 0) {
|
|
mod->name = xstrdup(bname);
|
|
} else {
|
|
rpmlog(RPMLOG_ERR, _("Failed to determine a policy name: %s\n"),
|
|
mod->path);
|
|
_free(tmp);
|
|
goto err;
|
|
}
|
|
_free(tmp);
|
|
}
|
|
|
|
if (types) {
|
|
mod->types = argvSplitString(types, ",", ARGV_SKIPEMPTY);
|
|
argvSort(mod->types, NULL);
|
|
if (argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL) && argvCount(mod->types) > 1) {
|
|
rpmlog(RPMLOG_WARNING, _("'%s' type given with other types in %%semodule %s. Compacting types to '%s'.\n"),
|
|
RPMPOL_TYPE_DEFAULT, mod->path, RPMPOL_TYPE_DEFAULT);
|
|
mod->types = argvFree(mod->types);
|
|
argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
|
|
}
|
|
} else {
|
|
argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
|
|
}
|
|
|
|
mod->flags = flags;
|
|
|
|
return mod;
|
|
|
|
err:
|
|
freeModule(mod);
|
|
return NULL;
|
|
}
|
|
|
|
static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
|
|
{
|
|
const char *path = NULL;
|
|
char *name = NULL;
|
|
char *types = NULL;
|
|
uint32_t flags = 0;
|
|
poptContext optCon = NULL;
|
|
|
|
rpmRC rc = RPMRC_FAIL;
|
|
|
|
struct poptOption optionsTable[] = {
|
|
{"name", 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
|
|
{"types", 't', POPT_ARG_STRING, &types, 't', NULL, NULL},
|
|
{"base", 'b', POPT_ARGFLAG_OR, &flags, RPMPOL_FLAG_BASE, NULL, NULL},
|
|
POPT_TABLEEND
|
|
};
|
|
|
|
if (!spec || !pkg) {
|
|
goto exit;
|
|
}
|
|
|
|
for (ARGV_const_t pol = pkg->policyList; *pol != NULL; pol++) {
|
|
ModuleRec mod;
|
|
const char *line = *pol;
|
|
const char **argv = NULL;
|
|
int argc = 0;
|
|
int err;
|
|
|
|
if ((err = poptParseArgvString(line, &argc, &argv))) {
|
|
rpmlog(RPMLOG_ERR, _("Error parsing %s: %s\n"),
|
|
line, poptStrerror(err));
|
|
goto exit;
|
|
}
|
|
|
|
if (!rstreq(argv[0], "%semodule")) {
|
|
rpmlog(RPMLOG_ERR, _("Expecting %%semodule tag: %s\n"), line);
|
|
goto exit;
|
|
}
|
|
|
|
optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
|
|
while (poptGetNextOpt(optCon) > 0) {
|
|
}
|
|
|
|
path = poptGetArg(optCon);
|
|
if (!path) {
|
|
rpmlog(RPMLOG_ERR, _("Missing module path in line: %s\n"),
|
|
line);
|
|
goto exit;
|
|
}
|
|
|
|
if (poptPeekArg(optCon)) {
|
|
rpmlog(RPMLOG_ERR, _("Too many arguments in line: %s\n"),
|
|
line);
|
|
goto exit;
|
|
}
|
|
|
|
mod = newModule(path, name, types, flags);
|
|
if (!mod) {
|
|
goto exit;
|
|
}
|
|
|
|
if (writeModuleToHeader(mod, pkg) != RPMRC_OK) {
|
|
freeModule(mod);
|
|
goto exit;
|
|
}
|
|
|
|
freeModule(mod);
|
|
}
|
|
|
|
rc = RPMRC_OK;
|
|
|
|
exit:
|
|
|
|
return rc;
|
|
}
|
|
#endif
|
|
|
|
rpmRC processBinaryPolicies(rpmSpec spec, int test)
|
|
{
|
|
rpmRC rc = RPMRC_OK;
|
|
#if WITH_SELINUX
|
|
Package pkg;
|
|
char *nvr;
|
|
|
|
for (pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
|
|
if (pkg->policyList == NULL) {
|
|
continue;
|
|
}
|
|
|
|
nvr = headerGetAsString(pkg->header, RPMTAG_NVRA);
|
|
rpmlog(RPMLOG_NOTICE, _("Processing policies: %s\n"), nvr);
|
|
free(nvr);
|
|
|
|
if (processPolicies(spec, pkg, test) != RPMRC_OK) {
|
|
rc = RPMRC_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return rc;
|
|
}
|