csomh / source-git / rpm

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