[Rpm-maint] [PATCH 2/6] Add new %sepolicy section to the spec file format

Steve Lawrence slawrence at tresys.com
Wed Jul 14 20:40:44 UTC 2010


The %sepolicy section is used to describe SELinux policy to be included
in a package. It's syntax is similar to other sections (%files, %pre,
%post, etc.) in that you can provide a string and -n after the
declaration to specify policy should be added to a subpackage.

For example:

%sepolicy
 # policy in this section will be added to the main package

%sepolicy foo
 # policy in this section will be added to the '<mainpackage>-foo' subpackage

%sepolicy -n bar
 # policy in this section will be added to the 'bar' subpackage

The %sepolicy section contains zero or more %module directives, each of
which specifies a path into the build directory of a policy file, for
example:

%module policies/foo.pp
%module policies/bar.pp

After each %module directive can be zero or more options, specified in
the same format as Preamble tags. The current options are:

Base:   Whether or not the module is a base module. Values can be
        yes/1 or no/0. Defaults to no/0 if not given.

Name:   The name of the module. If not given, we assume the name is
        the basename of the module file with file extensions removed.

Types:  One or more space-separated strings specifying which policy
        types the module can work with. To explicitly state that a module
        can work with any policy type, "default" can be specified as
        the value. If not specified, we assume the module can work with
        any policy type, and assign the types as "default".

Spaces before and after the %module directive and options are ignored.
Options always apply to the previously defined %module directive.

Below is an example of this new format:

%sepolicy
%module policy/foo.pp
   Name: foo
   Types: mls
%module policy/bar.pp
   Name: bar
   Types: strict targeted mls
   Base: yes

This also adds new header tags to store the new information:
 RPMTAG_POLICYNAMES        (string array)
 RPMTAG_POLICYTYPES        (string array)
 RPMTAG_POLICYTYPESINDEXES (uint32 array)
 RPMTAG_POLICYFLAGS        (uint32 array)

The index of NAMES and FLAGS maps directly to the index of RPMTAG_POLICIES.
However, because a single policy can have multiple types, the mapping for
TYPES is not direct. For this, the index maps to TYPESINDEXES, which
contains the index of the policy that the type maps to. This is similar to
how DIRINDEXES is used to map DIRNAMES and BASENAMES. As an example, the
previous %sepolicy section would have the following header tags:

RPMTAG_POLICIES:
 0: <foo.pp data, base64 encoded>
 1: <bar.pp data, base64 encoded>

RPMTAG_POLICYNAMES:
 0: foo
 1: bar

RPMTAG_POLICYFLAGS:
 0: 0
 1: 1	# assumes flag 1 == BASE

RPMTAG_POILCYTYPES:        RPMTAG_POLICYTYPESINDEXES:
 0: mls                     0: 0
 1: strict                  1: 1
 2: targeted                2: 1
 3: mls                     3: 1
---
 Makefile.am           |    1 +
 build/Makefile.am     |    3 +-
 build/build.c         |    4 +
 build/parsePolicies.c |   90 +++++++++
 build/parseSpec.c     |    5 +
 build/policies.c      |  521 +++++++++++++++++++++++++++++++++++++++++++++++++
 build/rpmbuild.h      |   18 ++-
 build/rpmspec.h       |    1 +
 build/spec.c          |    2 +
 lib/rpmpol.h          |   24 +++
 lib/rpmtag.h          |    4 +
 preinstall.am         |    4 +
 tests/rpmgeneral.at   |    4 +
 13 files changed, 679 insertions(+), 2 deletions(-)
 create mode 100644 build/parsePolicies.c
 create mode 100644 build/policies.c
 create mode 100644 lib/rpmpol.h

diff --git a/Makefile.am b/Makefile.am
index 25cee70..8dc2340 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,6 +59,7 @@ pkginclude_HEADERS += lib/rpmlib.h
 pkginclude_HEADERS += lib/rpmds.h
 pkginclude_HEADERS += lib/rpmfi.h
 pkginclude_HEADERS += lib/rpmlegacy.h
+pkginclude_HEADERS += lib/rpmpol.h
 pkginclude_HEADERS += lib/rpmps.h
 pkginclude_HEADERS += lib/rpmprob.h
 pkginclude_HEADERS += lib/rpmtag.h
diff --git a/build/Makefile.am b/build/Makefile.am
index f5ed2f6..3ff7f5e 100644
--- a/build/Makefile.am
+++ b/build/Makefile.am
@@ -12,7 +12,8 @@ librpmbuild_la_SOURCES = \
 	build.c buildio.h expression.c files.c misc.c names.c pack.c \
 	parseBuildInstallClean.c parseChangelog.c parseDescription.c \
 	parseFiles.c parsePreamble.c parsePrep.c parseReqs.c parseScript.c \
-	parseSpec.c poptBT.c reqprov.c rpmfc.c spec.c fts.h fts.c
+	parseSpec.c poptBT.c reqprov.c rpmfc.c spec.c fts.h fts.c \
+	parsePolicies.c policies.c
 
 librpmbuild_la_LDFLAGS = -version-info 1:0:0
 librpmbuild_la_LIBADD = \
diff --git a/build/build.c b/build/build.c
index c3295b9..2564e47 100644
--- a/build/build.c
+++ b/build/build.c
@@ -260,6 +260,10 @@ rpmRC buildSpec(rpmts ts, rpmSpec spec, int what, int test)
 	    (rc = processBinaryFiles(spec, what & RPMBUILD_INSTALL, test)))
 		goto exit;
 
+	if (((what & RPMBUILD_INSTALL) || (what & RPMBUILD_PACKAGEBINARY)) &&
+	    (rc = processBinaryPolicies(spec, test)))
+		goto exit;
+
 	if (((what & RPMBUILD_PACKAGESOURCE) && !test) &&
 	    (rc = packageSources(spec)))
 		return rc;
diff --git a/build/parsePolicies.c b/build/parsePolicies.c
new file mode 100644
index 0000000..ae4d69c
--- /dev/null
+++ b/build/parsePolicies.c
@@ -0,0 +1,90 @@
+/** \ingroup rpmbuild
+ * \file build/parsePolicies.c
+ *  Parse %policies section from spec file.
+ */
+
+#include "system.h"
+
+#include <rpm/header.h>
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmfileutil.h>
+#include "debug.h"
+
+int parsePolicies(rpmSpec spec)
+{
+    int nextPart, res = PART_ERROR;
+    Package pkg;
+    int rc, argc;
+    int arg;
+    const char **argv = NULL;
+    const char *name = NULL;
+    int flag = PART_SUBNAME;
+    poptContext optCon = NULL;
+
+    struct poptOption optionsTable[] = {
+	{NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
+	{0, 0, 0, 0, 0, NULL, NULL}
+    };
+
+    if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
+	rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%policies: %s\n"),
+	       spec->lineNum, poptStrerror(rc));
+	goto exit;
+    }
+
+    optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
+    while ((arg = poptGetNextOpt(optCon)) > 0) {
+	if (arg == 'n') {
+	    flag = PART_NAME;
+	}
+    }
+
+    if (arg < -1) {
+	rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
+	       spec->lineNum,
+	       poptBadOption(optCon, POPT_BADOPTION_NOALIAS), spec->line);
+	goto exit;
+    }
+
+    if (poptPeekArg(optCon)) {
+	if (name == NULL)
+	    name = poptGetArg(optCon);
+	if (poptPeekArg(optCon)) {
+	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
+		   spec->lineNum, spec->line);
+	    goto exit;
+	}
+    }
+
+    if (lookupPackage(spec, name, flag, &pkg)) {
+	rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
+	       spec->lineNum, spec->line);
+	goto exit;
+    }
+
+    pkg->policyList = newStringBuf();
+
+    if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
+	nextPart = PART_NONE;
+    } else if (rc < 0) {
+	goto exit;
+    } else {
+	while (!(nextPart = isPart(spec->line))) {
+	    appendLineStringBuf(pkg->policyList, spec->line);
+	    if ((rc = readLine(spec, STRIP_TRAILINGSPACE | STRIP_COMMENTS)) > 0) {
+		nextPart = PART_NONE;
+		break;
+	    } else if (rc < 0) {
+		goto exit;
+	    }
+	}
+    }
+    res = nextPart;
+
+  exit:
+    argv = _free(argv);
+    optCon = poptFreeContext(optCon);
+
+    return res;
+}
diff --git a/build/parseSpec.c b/build/parseSpec.c
index f45022b..7c845f2 100644
--- a/build/parseSpec.c
+++ b/build/parseSpec.c
@@ -47,6 +47,7 @@ static const struct PartRec {
     { PART_TRIGGERIN,     LEN_AND_STR("%triggerin")},
     { PART_TRIGGERIN,     LEN_AND_STR("%trigger")},
     { PART_VERIFYSCRIPT,  LEN_AND_STR("%verifyscript")},
+    { PART_POLICIES,      LEN_AND_STR("%sepolicy")},
     {0, 0, 0}
 };
 
@@ -492,6 +493,10 @@ int parseSpec(rpmts ts, const char *specFile, const char *rootDir,
 	    parsePart = parseFiles(spec);
 	    break;
 
+	case PART_POLICIES:
+	    parsePart = parsePolicies(spec);
+	    break;
+
 	case PART_NONE:		/* XXX avoid gcc whining */
 	case PART_LAST:
 	case PART_BUILDARCHITECTURES:
diff --git a/build/policies.c b/build/policies.c
new file mode 100644
index 0000000..e94d326
--- /dev/null
+++ b/build/policies.c
@@ -0,0 +1,521 @@
+/** \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 "rpmio/rpmio_internal.h"
+#include "rpmio/base64.h"
+
+#include "debug.h"
+
+#define SKIPSPACE(s)    { while ((s) && *(s) &&  risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while ((s) && *(s) && !risspace(*(s))) (s)++; }
+
+typedef struct ModuleRec_s {
+    char *path;
+    char *name;
+    ARGV_t types;
+    uint32_t base;
+} *ModuleRec;
+
+typedef enum POLDECTag_e {
+    POLDEC_UNKNOWN = 0,
+    POLDEC_MODULE = 1,
+} POLDECTag;
+
+typedef const struct POLDEC {
+    POLDECTag tag;
+    int deprecated;
+    size_t len;
+    const char *token;
+    rpmRC(*parse) (const struct POLDEC * dec, ARGV_t * lines, Package pkg);
+} POLDEC_t;
+
+typedef enum MODATag_e {
+    MODOPT_UNKNOWN = 0,
+    MODOPT_NAME = 1,
+    MODOPT_TYPES = 2,
+    MODOPT_BASE = 3
+} MODATag;
+
+typedef const struct MODA {
+    MODATag tag;
+    int deprecated;
+    size_t len;
+    const char *token;
+} MODA_t;
+
+static rpmRC parseModule(POLDEC_t * dec, ARGV_t * pol, Package pkg);
+
+
+#define LEN_AND_STR(_tag) (sizeof(_tag)-1), _tag
+
+static POLDEC_t const policyDeclarations[] = {
+    {POLDEC_MODULE, 0, LEN_AND_STR("%module"), &parseModule},
+    {POLDEC_UNKNOWN, 0, 0, 0, 0}	/* must be last */
+};
+
+static MODA_t const moduleAttrs[] = {
+    {MODOPT_NAME, 0, LEN_AND_STR("name")},
+    {MODOPT_TYPES, 0, LEN_AND_STR("types")},
+    {MODOPT_BASE, 0, LEN_AND_STR("base")},
+    {MODOPT_UNKNOWN, 0, 0, 0}	/* must be last */
+};
+
+/* returns 0 if no, 1 if yes, -1 if unknown */
+static inline int parseYesNo(const char *s)
+{
+    if (s) {
+	if (((s[0] == 'n' || s[0] == 'N' || s[0] == '0') && strlen(s) == 1)
+	    || !rstrcasecmp(s, "no") || !rstrcasecmp(s, "false")) {
+	    return 0;
+	}
+	if (((s[0] == 'y' || s[0] == 'Y' || s[0] == '1') && strlen(s) == 1)
+	    || !rstrcasecmp(s, "yes") || !rstrcasecmp(s, "true")) {
+	    return 1;
+	}
+    }
+    return -1;
+}
+
+static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg)
+{
+    const char *buildDir = "%{_builddir}/%{?buildsubdir}/";
+    char *fullpath;
+    char *encoded = NULL;
+    uint8_t *raw = NULL;
+    ssize_t rawlen = 0;
+    int rc = RPMRC_FAIL;
+    ARGV_t av;
+    uint32_t flags = 0;
+    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;
+    }
+
+    fullpath = rpmGenPath(buildDir, NULL, mod->path);
+
+    if ((rpmioSlurp(fullpath, &raw, &rawlen)) != 0 || raw == NULL) {
+	rpmlog(RPMLOG_ERR, _("Failed to read  policy file: %s\n"), fullpath);
+	goto exit;
+    }
+
+    encoded = b64encode(raw, rawlen, -1);
+    if (!encoded) {
+	rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"), fullpath);
+	goto exit;
+    }
+
+    if (!mod->name) {
+	/* 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 exit;
+	}
+	_free(tmp);
+    }
+
+    if (!mod->types) {
+	argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
+    } else {
+	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 %%module %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);
+	}
+    }
+
+    if (mod->base) {
+	flags |= RPMPOL_FLAG_BASE;
+    }
+
+    /* 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->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, encoded);
+    headerPutString(pkg->header, RPMTAG_POLICYNAMES, mod->name);
+    headerPutUint32(pkg->header, RPMTAG_POLICYFLAGS, &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:
+    _free(encoded);
+    _free(raw);
+    _free(fullpath);
+
+    rpmtdFreeData(&policies);
+    rpmtdFreeData(&policynames);
+    rpmtdFreeData(&policyflags);
+    rpmtdFreeData(&policytypes);
+    rpmtdFreeData(&policytypesidx);
+
+    return rc;
+}
+
+static ModuleRec freeModule(ModuleRec mod)
+{
+    if (mod) {
+	_free(mod->path);
+	_free(mod->name);
+	argvFree(mod->types);
+	_free(mod);
+    }
+
+    return NULL;
+}
+
+static ModuleRec newModule(char *path)
+{
+    char *end;
+    ModuleRec mod;
+
+    if (!path) {
+	return NULL;
+    }
+
+    SKIPSPACE(path);
+    if (*path == '\0') {
+	rpmlog(RPMLOG_ERR, _("%%module requires a file path\n"));
+	return NULL;
+    }
+
+    end = path;
+    SKIPNONSPACE(end);
+    if (*end != '\0') {
+	*end++ = '\0';
+	SKIPSPACE(end);
+	if (*end != '\0') {
+	    rpmlog(RPMLOG_ERR, _("%%module takes a single token only\n"));
+	    return NULL;
+	}
+    }
+
+    mod = xcalloc(1, sizeof(*mod));
+    mod->path = strdup(path);
+
+    return mod;
+}
+
+
+static rpmRC parseModuleAttr(ModuleRec mod, MODATag key, char *val)
+{
+    char *s;
+    char *end;
+    int multitoken;
+    rpmRC rc = RPMRC_FAIL;
+
+    SKIPSPACE(val);
+    if (val == '\0') {
+	rpmlog(RPMLOG_ERR, _("Empty value for module attribute %i\n"),
+	       key);
+	goto exit;
+    }
+
+    if (!mod) {
+	rpmlog(RPMLOG_ERR, _("No %module directive given for attribute: %s\n"), val);
+	goto exit;
+    }
+
+    s = end = val;
+    SKIPNONSPACE(s);
+    SKIPSPACE(s);
+    while (*end)
+	end++;
+    multitoken = (s != end);
+
+#define SINGLE_TOKEN_ONLY \
+	if (multitoken) { \
+		rpmlog(RPMLOG_ERR, _("Option takes single token only: %s\n"), val); \
+		goto exit; \
+	}
+
+#define SINGLE_DEFINE_ONLY(ptr) \
+	if (ptr) { \
+		rpmlog(RPMLOG_ERR, _("Option specified more than once: %s\n"), val); \
+		goto exit; \
+	}
+
+    switch (key) {
+    case MODOPT_NAME:
+	SINGLE_DEFINE_ONLY(mod->name)
+	SINGLE_TOKEN_ONLY
+	mod->name = strdup(val);
+	break;
+    case MODOPT_TYPES:
+	SINGLE_DEFINE_ONLY(mod->types)
+	s = val;
+	do {
+	    SKIPNONSPACE(s);
+	    end = s;
+	    SKIPSPACE(s);
+	    *end = '\0';
+	    argvAdd(&mod->types, val);
+	    val = s;
+	} while (*val != '\0');
+	break;
+    case MODOPT_BASE:
+	SINGLE_TOKEN_ONLY
+	mod->base = parseYesNo(val);
+	if (mod->base == -1) {
+	    rpmlog(RPMLOG_ERR, _("Unknown boolean value: %s\n"), val);
+	    goto exit;
+	}
+	break;
+    default:
+	rpmlog(RPMLOG_ERR, _("Unhandled option: %s\n"), val);
+	goto exit;
+    }
+
+    rc = RPMRC_OK;
+
+  exit:
+    return rc;
+}
+
+static rpmRC parseModule(POLDEC_t * dec, ARGV_t * pol, Package pkg)
+{
+    char *line;
+    char *s;
+    ModuleRec mod = NULL;
+    MODA_t *moda;
+    rpmRC rc = RPMRC_FAIL;
+
+    if (!dec || !pol || !pkg) {
+	goto exit;
+    }
+
+    line = **pol;
+    SKIPSPACE(line);
+    if (dec->tag != POLDEC_MODULE || rstrncasecmp(line, dec->token, dec->len)) {
+	rpmlog(RPMLOG_ERR, _("parseModule() cannot parse line: %s\n"), line);
+	goto exit;
+    }
+    line += dec->len;
+
+    mod = newModule(line);
+    if (!mod) {
+	goto exit;
+    }
+
+    /* parse attributes of the module */
+    while (*pol && *((*pol) + 1)) {
+	s = line = *(*(pol) + 1);
+	SKIPSPACE(s);
+
+	for (moda = moduleAttrs; moda->token != MODOPT_UNKNOWN; moda++) {
+	    if (rstrncasecmp(s, moda->token, moda->len)) {
+		continue;
+	    }
+	    if (moda->deprecated) {
+		rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"),
+		       moda->token, line);
+	    }
+	    break;
+	}
+
+	if (moda->token == MODOPT_UNKNOWN) {
+	    rc = RPMRC_OK;
+	    goto exit;
+	}
+
+	s += moda->len;
+	SKIPSPACE(s);
+	if (*s++ != ':') {
+	    rpmlog(RPMLOG_ERR, _("Malformed option: %s\n"), line);
+	    goto exit;
+	}
+
+	SKIPSPACE(s);
+	if (*s == '\0') {
+	    rpmlog(RPMLOG_ERR, _("Empty option: %s\n"), line);
+	    goto exit;
+	}
+
+	rc = parseModuleAttr(mod, moda->tag, s);
+	if (rc != RPMRC_OK) {
+	    goto exit;
+	}
+
+	(*pol)++;
+    }
+
+  exit:
+    if (rc == RPMRC_OK) {
+	rc = writeModuleToHeader(mod, pkg);
+    }
+
+    freeModule(mod);
+
+    return rc;
+}
+
+static rpmRC processPolicies(rpmSpec spec, Package pkg, int test)
+{
+    ARGV_t policies = NULL;
+    ARGV_t pol;
+    char *linep;
+    POLDEC_t *dec;
+    rpmRC rc = RPMRC_FAIL;
+
+    if (!spec || !pkg) {
+	goto exit;
+    }
+
+    argvSplit(&policies, getStringBuf(pkg->policyList), "\n");
+    for (pol = policies; *pol != NULL; pol++) {
+	linep = *pol;
+	SKIPSPACE(linep);
+	if (*linep == '\0') {
+	    continue;
+	}
+
+	for (dec = policyDeclarations; dec->tag != POLDEC_UNKNOWN; dec++) {
+	    if (rstrncasecmp(linep, dec->token, dec->len)) {
+		continue;
+	    }
+	    if (dec->deprecated) {
+		rpmlog(RPMLOG_WARNING, _("%s is deprecated: %s\n"),
+		       dec->token, linep);
+	    }
+	    break;
+	}
+
+	if (dec->tag == POLDEC_UNKNOWN) {
+	    rpmlog(RPMLOG_ERR,  _("Unknown option in %%sepolicy section: %s\n"), linep);
+	    rc = RPMRC_FAIL;
+	    goto exit;
+	}
+
+	rc = dec->parse(dec, &pol, pkg);
+	if (rc != RPMRC_OK) {
+	    goto exit;
+	}
+    }
+
+    rc = RPMRC_OK;
+
+  exit:
+    argvFree(policies);
+
+    return rc;
+}
+
+int processBinaryPolicies(rpmSpec spec, int test)
+{
+    Package pkg;
+    int rc = RPMRC_OK;
+    char *nvr;
+
+#if WITH_SELINUX
+    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;
+}
diff --git a/build/rpmbuild.h b/build/rpmbuild.h
index c7d0da3..7e78b31 100644
--- a/build/rpmbuild.h
+++ b/build/rpmbuild.h
@@ -73,7 +73,8 @@ typedef enum rpmParseState_e {
     PART_BUILDARCHITECTURES= 29+PART_BASE,/*!< */ 
     PART_TRIGGERPOSTUN  = 30+PART_BASE, /*!< */ 
     PART_TRIGGERPREIN   = 31+PART_BASE, /*!< */ 
-    PART_LAST           = 32+PART_BASE  /*!< */ 
+    PART_POLICIES       = 32+PART_BASE, /*!< */
+    PART_LAST           = 33+PART_BASE  /*!< */
 } rpmParseState; 
 
 
@@ -221,6 +222,13 @@ int parseDescription(rpmSpec spec);
 int parseFiles(rpmSpec spec);
 
 /** \ingroup rpmbuild
+ * Parse %%sepolicy section of a spec file.
+ * @param spec		spec file control structure
+ * @return		>= 0 next rpmParseState, < 0 on error
+ */
+int parsePolicies(rpmSpec spec);
+
+/** \ingroup rpmbuild
  * Parse tags from preamble of a spec file.
  * @param spec		spec file control structure
  * @param initialPackage
@@ -368,6 +376,14 @@ int rpmlibNeedsFeature(Header h, const char * feature, const char * featureEVR);
 int processBinaryFiles(rpmSpec spec, int installSpecialDoc, int test);
 
 /** \ingroup rpmbuild
+ * Post-build processing for policy files in binary package(s).
+ * @param spec		spec file control structure
+ * @param test		don't execute scripts or package if testing
+ * @return		0 on success
+ */
+int processBinaryPolicies(rpmSpec spec, int test);
+
+/** \ingroup rpmbuild
  * Create and initialize header for source package.
  * @param spec		spec file control structure
  */
diff --git a/build/rpmspec.h b/build/rpmspec.h
index e3eac6c..4d487aa 100644
--- a/build/rpmspec.h
+++ b/build/rpmspec.h
@@ -172,6 +172,7 @@ struct Package_s {
 
     StringBuf fileFile;
     StringBuf fileList;		/* If NULL, package will not be written */
+    StringBuf policyList;
 
     Package next;
 };
diff --git a/build/spec.c b/build/spec.c
index d3e6a6a..0ec70cc 100644
--- a/build/spec.c
+++ b/build/spec.c
@@ -119,6 +119,7 @@ Package newPackage(rpmSpec spec)
     
     p->fileFile = NULL;
     p->fileList = NULL;
+    p->policyList = NULL;
 
     p->cpioList = NULL;
 
@@ -158,6 +159,7 @@ Package freePackage(Package pkg)
     pkg->ds = rpmdsFree(pkg->ds);
     pkg->fileList = freeStringBuf(pkg->fileList);
     pkg->fileFile = freeStringBuf(pkg->fileFile);
+    pkg->policyList = freeStringBuf(pkg->policyList);
     if (pkg->cpioList) {
 	rpmfi fi = pkg->cpioList;
 	pkg->cpioList = NULL;
diff --git a/lib/rpmpol.h b/lib/rpmpol.h
new file mode 100644
index 0000000..ee74a84
--- /dev/null
+++ b/lib/rpmpol.h
@@ -0,0 +1,24 @@
+#ifndef H_RPMPOL
+#define H_RPMPOL
+
+/** \ingroup rpmpol
+ * \file lib/rpmpol.h
+ * Structure(s) used for policy sets.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum rpmpolFlags_e {
+	RPMPOL_FLAG_NONE = 0,
+	RPMPOL_FLAG_BASE = (1 << 0)
+} rpmpolFlags;
+
+#define RPMPOL_TYPE_DEFAULT "default"
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif				/* H_rpmpol */
diff --git a/lib/rpmtag.h b/lib/rpmtag.h
index 3aaebfa..8ff371f 100644
--- a/lib/rpmtag.h
+++ b/lib/rpmtag.h
@@ -297,6 +297,10 @@ typedef enum rpmTag_e {
     RPMTAG_TRIGGERSCRIPTFLAGS	= 5027, /* i[] */
     RPMTAG_FILESTATUS		= 5028, /* i[] extension */
     RPMTAG_COLLECTIONS		= 5029, /* s[] list of collections */
+    RPMTAG_POLICYNAMES		= 5030,	/* s[] */
+    RPMTAG_POLICYTYPES		= 5031,	/* s[] */
+    RPMTAG_POLICYTYPESINDEXES	= 5032,	/* i[] */
+    RPMTAG_POLICYFLAGS		= 5033,	/* i[] */
 
     RPMTAG_FIRSTFREE_TAG	/*!< internal */
 } rpmTag;
diff --git a/preinstall.am b/preinstall.am
index ab3a072..4ab1c88 100644
--- a/preinstall.am
+++ b/preinstall.am
@@ -78,6 +78,10 @@ include/rpm/rpmlegacy.h: lib/rpmlegacy.h include/rpm/$(dirstamp)
 	$(INSTALL_DATA) $(top_srcdir)/lib/rpmlegacy.h include/rpm/rpmlegacy.h
 BUILT_SOURCES += include/rpm/rpmlegacy.h
 CLEANFILES += include/rpm/rpmlegacy.h
+include/rpm/rpmpol.h: lib/rpmpol.h include/rpm/$(dirstamp)
+	$(INSTALL_DATA) $(top_srcdir)/lib/rpmpol.h include/rpm/rpmpol.h
+BUILT_SOURCES += include/rpm/rpmpol.h
+CLEANFILES += include/rpm/rpmpol.h
 include/rpm/rpmps.h: lib/rpmps.h include/rpm/$(dirstamp)
 	$(INSTALL_DATA) $(top_srcdir)/lib/rpmps.h include/rpm/rpmps.h
 BUILT_SOURCES += include/rpm/rpmps.h
diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at
index 4c33f29..8f7c03e 100644
--- a/tests/rpmgeneral.at
+++ b/tests/rpmgeneral.at
@@ -181,6 +181,10 @@ PAYLOADFORMAT
 PKGID
 PLATFORM
 POLICIES
+POLICYFLAGS
+POLICYNAMES
+POLICYTYPES
+POLICYTYPESINDEXES
 POSTIN
 POSTINFLAGS
 POSTINPROG
-- 
1.6.2.5



More information about the Rpm-maint mailing list