diff options
author | Steve Lawrence <slawrence@tresys.com> | 2010-08-30 16:32:29 -0400 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2010-09-01 09:04:27 +0300 |
commit | 383e27564853fd4c387ca1d4a69f223140a0daca (patch) | |
tree | 571b403fff31673d43b75b25f31a43b39291fbe9 | |
parent | 5779fb12e26ca1793df7ee50972de80dbf26992e (diff) | |
download | rpm-383e27564853fd4c387ca1d4a69f223140a0daca.tar.gz |
Add new %sepolicy section to the spec file format
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 %semodule directives, with the
following format:
%semodule [OPTIONS] path/to/module.pp
The available options are:
-b, --base
The module is a base module
-n, --name=NAME
The name of the module. If not given, assumes the name is the basename of
the module file with file extensions removed.
-t, --types=TYPES
One or more comma-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,
assumes the module can work with any policy type, and assigns the types as
"default".
Below is an example of this new format:
%sepolicy
%semodule -n foo -t mls policy/foo.pp
%semodule -n bar -t strict,targeted,mls -b policy/bar.pp
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
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | build/Makefile.am | 1 | ||||
-rw-r--r-- | build/build.c | 4 | ||||
-rw-r--r-- | build/parsePolicies.c | 91 | ||||
-rw-r--r-- | build/parseSpec.c | 5 | ||||
-rw-r--r-- | build/policies.c | 320 | ||||
-rw-r--r-- | build/rpmbuild_internal.h | 20 | ||||
-rw-r--r-- | build/rpmspec.h | 1 | ||||
-rw-r--r-- | build/spec.c | 2 | ||||
-rw-r--r-- | lib/rpmpol.h | 24 | ||||
-rw-r--r-- | lib/rpmtag.h | 4 | ||||
-rw-r--r-- | preinstall.am | 4 | ||||
-rw-r--r-- | tests/rpmgeneral.at | 4 |
13 files changed, 480 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 798549a26..dfee93397 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 36f3d6316..a16841388 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -13,6 +13,7 @@ librpmbuild_la_SOURCES = \ 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 \ + parsePolicies.c policies.c \ rpmbuild_internal.h rpmbuild_misc.h librpmbuild_la_LDFLAGS = -version-info 1:0:0 diff --git a/build/build.c b/build/build.c index 64c4d6c2a..d02953493 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 000000000..c66d82f65 --- /dev/null +++ b/build/parsePolicies.c @@ -0,0 +1,91 @@ +/** \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 "build/rpmbuild_internal.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 6078e0eca..38ba5e206 100644 --- a/build/parseSpec.c +++ b/build/parseSpec.c @@ -57,6 +57,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} }; @@ -603,6 +604,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 000000000..8874494dc --- /dev/null +++ b/build/policies.c @@ -0,0 +1,320 @@ +/** \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 "build/rpmbuild_internal.h" +#include "rpmio/base64.h" + +#include "debug.h" + +typedef struct ModuleRec_s { + char *path; + char *data; + char *name; + ARGV_t types; + uint32_t flags; +} *ModuleRec; + +static rpmRC writeModuleToHeader(ModuleRec mod, Package pkg) +{ + int 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 = b64encode(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; + + ARGV_t policies = NULL; + ARGV_t pol; + 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; + } + + argvSplit(&policies, getStringBuf(pkg->policyList), "\n"); + for (pol = policies; *pol != NULL; pol++) { + ModuleRec mod; + 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: + 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_internal.h b/build/rpmbuild_internal.h index 2c63a1278..d3fa72472 100644 --- a/build/rpmbuild_internal.h +++ b/build/rpmbuild_internal.h @@ -70,7 +70,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; @@ -143,6 +144,14 @@ RPM_GNUC_INTERNAL 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 + */ +RPM_GNUC_INTERNAL +int parsePolicies(rpmSpec spec); + +/** \ingroup rpmbuild * Parse tags from preamble of a spec file. * @param spec spec file control structure * @param initialPackage @@ -256,6 +265,15 @@ RPM_GNUC_INTERNAL int processBinaryFiles(rpmSpec spec, int installSpecialDoc, int test); /** \ingroup rpmbuild + * Post-build processing for policies in binary package(s). + * @param spec spec file control structure + * @param test don't execute scripts or package if testing + * @return 0 on success + */ +RPM_GNUC_INTERNAL +int processBinaryPolicies(rpmSpec spec, int test); + +/** \ingroup rpmbuild * Post-build processing for source package. * @param spec spec file control structure * @return 0 on success diff --git a/build/rpmspec.h b/build/rpmspec.h index cd57d0ad2..8b677a277 100644 --- a/build/rpmspec.h +++ b/build/rpmspec.h @@ -119,6 +119,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 92998074b..92136fc7e 100644 --- a/build/spec.c +++ b/build/spec.c @@ -100,6 +100,7 @@ Package newPackage(rpmSpec spec) p->autoProv = 1; p->autoReq = 1; p->fileList = newStringBuf(); + p->policyList = NULL; if (spec->packages == NULL) { spec->packages = p; @@ -129,6 +130,7 @@ static 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 000000000..ee74a84fc --- /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 3aaebfa40..8ff371f96 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 7f64837b0..39cf3f87d 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 4c33f290f..8f7c03e3b 100644 --- a/tests/rpmgeneral.at +++ b/tests/rpmgeneral.at @@ -181,6 +181,10 @@ PAYLOADFORMAT PKGID PLATFORM POLICIES +POLICYFLAGS +POLICYNAMES +POLICYTYPES +POLICYTYPESINDEXES POSTIN POSTINFLAGS POSTINPROG |