blob: b5b807ee1cc185a5b06d5417c47e8db08f34e654 [file] [log] [blame]
/* Author: Karl MacMillan <kmacmillan@tresys.com>
* Jason Tang <jtang@tresys.com>
* Chris PeBenito <cpebenito@tresys.com>
*
* Copyright (C) 2004-2005 Tresys Technology, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "policydb_internal.h"
#include "module_internal.h"
#include <sepol/policydb/link.h>
#include <sepol/policydb/expand.h>
#include <sepol/policydb/module.h>
#include "debug.h"
#include "private.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define SEPOL_PACKAGE_SECTION_FC 0xf97cff90
#define SEPOL_PACKAGE_SECTION_SEUSER 0x97cff91
#define SEPOL_PACKAGE_SECTION_USER_EXTRA 0x97cff92
#define SEPOL_PACKAGE_SECTION_NETFILTER 0x97cff93
static int policy_file_seek(struct policy_file *fp, size_t offset)
{
switch (fp->type) {
case PF_USE_STDIO:
if (offset > LONG_MAX) {
errno = EFAULT;
return -1;
}
return fseek(fp->fp, (long)offset, SEEK_SET);
case PF_USE_MEMORY:
if (offset > fp->size) {
errno = EFAULT;
return -1;
}
fp->data -= fp->size - fp->len;
fp->data += offset;
fp->len = fp->size - offset;
return 0;
default:
return 0;
}
}
static size_t policy_file_length(struct policy_file *fp)
{
long prev_offset, end_offset;
switch (fp->type) {
case PF_USE_STDIO:
prev_offset = ftell(fp->fp);
fseek(fp->fp, 0L, SEEK_END);
end_offset = ftell(fp->fp);
fseek(fp->fp, prev_offset, SEEK_SET);
return end_offset;
case PF_USE_MEMORY:
return fp->size;
default:
return 0;
}
}
static int module_package_init(sepol_module_package_t * p)
{
memset(p, 0, sizeof(sepol_module_package_t));
if (sepol_policydb_create(&p->policy))
return -1;
p->version = 1;
return 0;
}
static int set_char(char **field, char *data, size_t len)
{
if (*field) {
free(*field);
*field = NULL;
}
if (len) {
*field = malloc(len);
if (!*field)
return -1;
memcpy(*field, data, len);
}
return 0;
}
int sepol_module_package_create(sepol_module_package_t ** p)
{
*p = calloc(1, sizeof(sepol_module_package_t));
if (!(*p))
return -1;
return module_package_init(*p);
}
hidden_def(sepol_module_package_create)
/* Deallocates all memory associated with a module package, including
* the pointer itself. Does nothing if p is NULL.
*/
void sepol_module_package_free(sepol_module_package_t * p)
{
if (p == NULL)
return;
sepol_policydb_free(p->policy);
free(p->file_contexts);
free(p->seusers);
free(p->user_extra);
free(p->netfilter_contexts);
free(p);
}
hidden_def(sepol_module_package_free)
char *sepol_module_package_get_file_contexts(sepol_module_package_t * p)
{
return p->file_contexts;
}
size_t sepol_module_package_get_file_contexts_len(sepol_module_package_t * p)
{
return p->file_contexts_len;
}
char *sepol_module_package_get_seusers(sepol_module_package_t * p)
{
return p->seusers;
}
size_t sepol_module_package_get_seusers_len(sepol_module_package_t * p)
{
return p->seusers_len;
}
char *sepol_module_package_get_user_extra(sepol_module_package_t * p)
{
return p->user_extra;
}
size_t sepol_module_package_get_user_extra_len(sepol_module_package_t * p)
{
return p->user_extra_len;
}
char *sepol_module_package_get_netfilter_contexts(sepol_module_package_t * p)
{
return p->netfilter_contexts;
}
size_t sepol_module_package_get_netfilter_contexts_len(sepol_module_package_t *
p)
{
return p->netfilter_contexts_len;
}
int sepol_module_package_set_file_contexts(sepol_module_package_t * p,
char *data, size_t len)
{
if (set_char(&p->file_contexts, data, len))
return -1;
p->file_contexts_len = len;
return 0;
}
int sepol_module_package_set_seusers(sepol_module_package_t * p,
char *data, size_t len)
{
if (set_char(&p->seusers, data, len))
return -1;
p->seusers_len = len;
return 0;
}
int sepol_module_package_set_user_extra(sepol_module_package_t * p,
char *data, size_t len)
{
if (set_char(&p->user_extra, data, len))
return -1;
p->user_extra_len = len;
return 0;
}
int sepol_module_package_set_netfilter_contexts(sepol_module_package_t * p,
char *data, size_t len)
{
if (set_char(&p->netfilter_contexts, data, len))
return -1;
p->netfilter_contexts_len = len;
return 0;
}
sepol_policydb_t *sepol_module_package_get_policy(sepol_module_package_t * p)
{
return p->policy;
}
/* Append each of the file contexts from each module to the base
* policy's file context. 'base_context' will be reallocated to a
* larger size (and thus it is an in/out reference
* variable). 'base_fc_len' is the length of base's file context; it
* too is a reference variable. Return 0 on success, -1 if out of
* memory. */
static int link_file_contexts(sepol_module_package_t * base,
sepol_module_package_t ** modules,
int num_modules)
{
size_t fc_len;
int i;
char *s;
fc_len = base->file_contexts_len;
for (i = 0; i < num_modules; i++) {
fc_len += modules[i]->file_contexts_len;
}
if ((s = (char *)realloc(base->file_contexts, fc_len)) == NULL) {
return -1;
}
base->file_contexts = s;
for (i = 0; i < num_modules; i++) {
memcpy(base->file_contexts + base->file_contexts_len,
modules[i]->file_contexts,
modules[i]->file_contexts_len);
base->file_contexts_len += modules[i]->file_contexts_len;
}
return 0;
}
/* Append each of the netfilter contexts from each module to the base
* policy's netfilter context. 'base_context' will be reallocated to a
* larger size (and thus it is an in/out reference
* variable). 'base_nc_len' is the length of base's netfilter contexts; it
* too is a reference variable. Return 0 on success, -1 if out of
* memory. */
static int link_netfilter_contexts(sepol_module_package_t * base,
sepol_module_package_t ** modules,
int num_modules)
{
size_t base_nc_len;
int i;
char *base_context;
base_nc_len = base->netfilter_contexts_len;
for (i = 0; i < num_modules; i++) {
base_nc_len += modules[i]->netfilter_contexts_len;
}
if ((base_context =
(char *)realloc(base->netfilter_contexts, base_nc_len)) == NULL) {
return -1;
}
base->netfilter_contexts = base_context;
for (i = 0; i < num_modules; i++) {
memcpy(base->netfilter_contexts + base->netfilter_contexts_len,
modules[i]->netfilter_contexts,
modules[i]->netfilter_contexts_len);
base->netfilter_contexts_len +=
modules[i]->netfilter_contexts_len;
}
return 0;
}
/* Links the module packages into the base. Returns 0 on success, -1
* if a requirement was not met, or -2 for all other errors. */
int sepol_link_packages(sepol_handle_t * handle,
sepol_module_package_t * base,
sepol_module_package_t ** modules, int num_modules,
int verbose)
{
policydb_t **mod_pols = NULL;
int i, retval;
if ((mod_pols = calloc(num_modules, sizeof(*mod_pols))) == NULL) {
ERR(handle, "Out of memory!");
return -2;
}
for (i = 0; i < num_modules; i++) {
mod_pols[i] = &modules[i]->policy->p;
}
retval = link_modules(handle, &base->policy->p, mod_pols, num_modules,
verbose);
free(mod_pols);
if (retval == -3) {
return -1;
} else if (retval < 0) {
return -2;
}
if (link_file_contexts(base, modules, num_modules) == -1) {
ERR(handle, "Out of memory!");
return -2;
}
if (link_netfilter_contexts(base, modules, num_modules) == -1) {
ERR(handle, "Out of memory!");
return -2;
}
return 0;
}
/* buf must be large enough - no checks are performed */
#define _read_helper_bufsize BUFSIZ
static int read_helper(char *buf, struct policy_file *file, uint32_t bytes)
{
uint32_t offset, nel, read_len;
int rc;
offset = 0;
nel = bytes;
while (nel) {
if (nel < _read_helper_bufsize)
read_len = nel;
else
read_len = _read_helper_bufsize;
rc = next_entry(&buf[offset], file, read_len);
if (rc < 0)
return -1;
offset += read_len;
nel -= read_len;
}
return 0;
}
#define MAXSECTIONS 100
/* Get the section offsets from a package file, offsets will be malloc'd to
* the appropriate size and the caller must free() them */
static int module_package_read_offsets(sepol_module_package_t * mod,
struct policy_file *file,
size_t ** offsets, uint32_t * sections)
{
uint32_t *buf = NULL, nsec;
unsigned i;
size_t *off = NULL;
int rc;
buf = malloc(sizeof(uint32_t)*3);
if (!buf) {
ERR(file->handle, "out of memory");
goto err;
}
rc = next_entry(buf, file, sizeof(uint32_t) * 3);
if (rc < 0) {
ERR(file->handle, "module package header truncated");
goto err;
}
if (le32_to_cpu(buf[0]) != SEPOL_MODULE_PACKAGE_MAGIC) {
ERR(file->handle,
"wrong magic number for module package: expected %#08x, got %#08x",
SEPOL_MODULE_PACKAGE_MAGIC, le32_to_cpu(buf[0]));
goto err;
}
mod->version = le32_to_cpu(buf[1]);
nsec = *sections = le32_to_cpu(buf[2]);
if (nsec > MAXSECTIONS) {
ERR(file->handle, "too many sections (%u) in module package",
nsec);
goto err;
}
off = (size_t *) malloc((nsec + 1) * sizeof(size_t));
if (!off) {
ERR(file->handle, "out of memory");
goto err;
}
free(buf);
buf = malloc(sizeof(uint32_t) * nsec);
if (!buf) {
ERR(file->handle, "out of memory");
goto err;
}
rc = next_entry(buf, file, sizeof(uint32_t) * nsec);
if (rc < 0) {
ERR(file->handle, "module package offset array truncated");
goto err;
}
for (i = 0; i < nsec; i++) {
off[i] = le32_to_cpu(buf[i]);
if (i && off[i] < off[i - 1]) {
ERR(file->handle, "offsets are not increasing (at %u, "
"offset %zu -> %zu", i, off[i - 1],
off[i]);
goto err;
}
}
off[nsec] = policy_file_length(file);
if (nsec && off[nsec] < off[nsec-1]) {
ERR(file->handle, "offset greater than file size (at %u, "
"offset %zu -> %zu", nsec, off[nsec - 1],
off[nsec]);
goto err;
}
*offsets = off;
free(buf);
return 0;
err:
free(buf);
free(off);
return -1;
}
/* Flags for which sections have been seen during parsing of module package. */
#define SEEN_MOD 1
#define SEEN_FC 2
#define SEEN_SEUSER 4
#define SEEN_USER_EXTRA 8
#define SEEN_NETFILTER 16
int sepol_module_package_read(sepol_module_package_t * mod,
struct sepol_policy_file *spf, int verbose)
{
struct policy_file *file = &spf->pf;
uint32_t buf[1], nsec;
size_t *offsets, len;
int rc;
unsigned i, seen = 0;
if (module_package_read_offsets(mod, file, &offsets, &nsec))
return -1;
/* we know the section offsets, seek to them and read in the data */
for (i = 0; i < nsec; i++) {
if (policy_file_seek(file, offsets[i])) {
ERR(file->handle, "error seeking to offset %zu for "
"module package section %u", offsets[i], i);
goto cleanup;
}
len = offsets[i + 1] - offsets[i];
if (len < sizeof(uint32_t)) {
ERR(file->handle, "module package section %u "
"has too small length %zu", i, len);
goto cleanup;
}
/* read the magic number, so that we know which function to call */
rc = next_entry(buf, file, sizeof(uint32_t));
if (rc < 0) {
ERR(file->handle,
"module package section %u truncated, lacks magic number",
i);
goto cleanup;
}
switch (le32_to_cpu(buf[0])) {
case SEPOL_PACKAGE_SECTION_FC:
if (seen & SEEN_FC) {
ERR(file->handle,
"found multiple file contexts sections in module package (at section %u)",
i);
goto cleanup;
}
mod->file_contexts_len = len - sizeof(uint32_t);
mod->file_contexts =
(char *)malloc(mod->file_contexts_len);
if (!mod->file_contexts) {
ERR(file->handle, "out of memory");
goto cleanup;
}
if (read_helper
(mod->file_contexts, file,
mod->file_contexts_len)) {
ERR(file->handle,
"invalid file contexts section at section %u",
i);
free(mod->file_contexts);
mod->file_contexts = NULL;
goto cleanup;
}
seen |= SEEN_FC;
break;
case SEPOL_PACKAGE_SECTION_SEUSER:
if (seen & SEEN_SEUSER) {
ERR(file->handle,
"found multiple seuser sections in module package (at section %u)",
i);
goto cleanup;
}
mod->seusers_len = len - sizeof(uint32_t);
mod->seusers = (char *)malloc(mod->seusers_len);
if (!mod->seusers) {
ERR(file->handle, "out of memory");
goto cleanup;
}
if (read_helper(mod->seusers, file, mod->seusers_len)) {
ERR(file->handle,
"invalid seuser section at section %u", i);
free(mod->seusers);
mod->seusers = NULL;
goto cleanup;
}
seen |= SEEN_SEUSER;
break;
case SEPOL_PACKAGE_SECTION_USER_EXTRA:
if (seen & SEEN_USER_EXTRA) {
ERR(file->handle,
"found multiple user_extra sections in module package (at section %u)",
i);
goto cleanup;
}
mod->user_extra_len = len - sizeof(uint32_t);
mod->user_extra = (char *)malloc(mod->user_extra_len);
if (!mod->user_extra) {
ERR(file->handle, "out of memory");
goto cleanup;
}
if (read_helper
(mod->user_extra, file, mod->user_extra_len)) {
ERR(file->handle,
"invalid user_extra section at section %u",
i);
free(mod->user_extra);
mod->user_extra = NULL;
goto cleanup;
}
seen |= SEEN_USER_EXTRA;
break;
case SEPOL_PACKAGE_SECTION_NETFILTER:
if (seen & SEEN_NETFILTER) {
ERR(file->handle,
"found multiple netfilter contexts sections in module package (at section %u)",
i);
goto cleanup;
}
mod->netfilter_contexts_len = len - sizeof(uint32_t);
mod->netfilter_contexts =
(char *)malloc(mod->netfilter_contexts_len);
if (!mod->netfilter_contexts) {
ERR(file->handle, "out of memory");
goto cleanup;
}
if (read_helper
(mod->netfilter_contexts, file,
mod->netfilter_contexts_len)) {
ERR(file->handle,
"invalid netfilter contexts section at section %u",
i);
free(mod->netfilter_contexts);
mod->netfilter_contexts = NULL;
goto cleanup;
}
seen |= SEEN_NETFILTER;
break;
case POLICYDB_MOD_MAGIC:
if (seen & SEEN_MOD) {
ERR(file->handle,
"found multiple module sections in module package (at section %u)",
i);
goto cleanup;
}
/* seek back to where the magic number was */
if (policy_file_seek(file, offsets[i]))
goto cleanup;
rc = policydb_read(&mod->policy->p, file, verbose);
if (rc < 0) {
ERR(file->handle,
"invalid module in module package (at section %u)",
i);
goto cleanup;
}
seen |= SEEN_MOD;
break;
default:
/* unknown section, ignore */
ERR(file->handle,
"unknown magic number at section %u, offset: %zx, number: %ux ",
i, offsets[i], le32_to_cpu(buf[0]));
break;
}
}
if ((seen & SEEN_MOD) == 0) {
ERR(file->handle, "missing module in module package");
goto cleanup;
}
free(offsets);
return 0;
cleanup:
free(offsets);
return -1;
}
int sepol_module_package_info(struct sepol_policy_file *spf, int *type,
char **name, char **version)
{
struct policy_file *file = &spf->pf;
sepol_module_package_t *mod = NULL;
uint32_t buf[5], len, nsec;
size_t *offsets = NULL;
unsigned i, seen = 0;
char *id;
int rc;
if (sepol_module_package_create(&mod))
return -1;
if (module_package_read_offsets(mod, file, &offsets, &nsec)) {
goto cleanup;
}
for (i = 0; i < nsec; i++) {
if (policy_file_seek(file, offsets[i])) {
ERR(file->handle, "error seeking to offset "
"%zu for module package section %u", offsets[i], i);
goto cleanup;
}
len = offsets[i + 1] - offsets[i];
if (len < sizeof(uint32_t)) {
ERR(file->handle,
"module package section %u has too small length %u",
i, len);
goto cleanup;
}
/* read the magic number, so that we know which function to call */
rc = next_entry(buf, file, sizeof(uint32_t) * 2);
if (rc < 0) {
ERR(file->handle,
"module package section %u truncated, lacks magic number",
i);
goto cleanup;
}
switch (le32_to_cpu(buf[0])) {
case SEPOL_PACKAGE_SECTION_FC:
/* skip file contexts */
if (seen & SEEN_FC) {
ERR(file->handle,
"found multiple file contexts sections in module package (at section %u)",
i);
goto cleanup;
}
seen |= SEEN_FC;
break;
case SEPOL_PACKAGE_SECTION_SEUSER:
/* skip seuser */
if (seen & SEEN_SEUSER) {
ERR(file->handle,
"found seuser sections in module package (at section %u)",
i);
goto cleanup;
}
seen |= SEEN_SEUSER;
break;
case SEPOL_PACKAGE_SECTION_USER_EXTRA:
/* skip user_extra */
if (seen & SEEN_USER_EXTRA) {
ERR(file->handle,
"found user_extra sections in module package (at section %u)",
i);
goto cleanup;
}
seen |= SEEN_USER_EXTRA;
break;
case SEPOL_PACKAGE_SECTION_NETFILTER:
/* skip netfilter contexts */
if (seen & SEEN_NETFILTER) {
ERR(file->handle,
"found multiple netfilter contexts sections in module package (at section %u)",
i);
goto cleanup;
}
seen |= SEEN_NETFILTER;
break;
case POLICYDB_MOD_MAGIC:
if (seen & SEEN_MOD) {
ERR(file->handle,
"found multiple module sections in module package (at section %u)",
i);
goto cleanup;
}
len = le32_to_cpu(buf[1]);
if (len != strlen(POLICYDB_MOD_STRING)) {
ERR(file->handle,
"module string length is wrong (at section %u)",
i);
goto cleanup;
}
/* skip id */
id = malloc(len + 1);
if (!id) {
ERR(file->handle,
"out of memory (at section %u)",
i);
goto cleanup;
}
rc = next_entry(id, file, len);
free(id);
if (rc < 0) {
ERR(file->handle,
"cannot get module string (at section %u)",
i);
goto cleanup;
}
rc = next_entry(buf, file, sizeof(uint32_t) * 5);
if (rc < 0) {
ERR(file->handle,
"cannot get module header (at section %u)",
i);
goto cleanup;
}
*type = le32_to_cpu(buf[0]);
/* if base - we're done */
if (*type == POLICY_BASE) {
*name = NULL;
*version = NULL;
seen |= SEEN_MOD;
break;
} else if (*type != POLICY_MOD) {
ERR(file->handle,
"module has invalid type %d (at section %u)",
*type, i);
goto cleanup;
}
/* read the name and version */
rc = next_entry(buf, file, sizeof(uint32_t));
if (rc < 0) {
ERR(file->handle,
"cannot get module name len (at section %u)",
i);
goto cleanup;
}
len = le32_to_cpu(buf[0]);
*name = malloc(len + 1);
if (!*name) {
ERR(file->handle, "out of memory");
goto cleanup;
}
rc = next_entry(*name, file, len);
if (rc < 0) {
ERR(file->handle,
"cannot get module name string (at section %u)",
i);
goto cleanup;
}
(*name)[len] = '\0';
rc = next_entry(buf, file, sizeof(uint32_t));
if (rc < 0) {
ERR(file->handle,
"cannot get module version len (at section %u)",
i);
goto cleanup;
}
len = le32_to_cpu(buf[0]);
*version = malloc(len + 1);
if (!*version) {
ERR(file->handle, "out of memory");
goto cleanup;
}
rc = next_entry(*version, file, len);
if (rc < 0) {
ERR(file->handle,
"cannot get module version string (at section %u)",
i);
goto cleanup;
}
(*version)[len] = '\0';
seen |= SEEN_MOD;
break;
default:
break;
}
}
if ((seen & SEEN_MOD) == 0) {
ERR(file->handle, "missing module in module package");
goto cleanup;
}
sepol_module_package_free(mod);
free(offsets);
return 0;
cleanup:
sepol_module_package_free(mod);
free(offsets);
return -1;
}
static int write_helper(char *data, size_t len, struct policy_file *file)
{
int idx = 0;
size_t len2;
while (len) {
if (len > BUFSIZ)
len2 = BUFSIZ;
else
len2 = len;
if (put_entry(&data[idx], 1, len2, file) != len2) {
return -1;
}
len -= len2;
idx += len2;
}
return 0;
}
int sepol_module_package_write(sepol_module_package_t * p,
struct sepol_policy_file *spf)
{
struct policy_file *file = &spf->pf;
policy_file_t polfile;
uint32_t buf[5], offsets[5], len, nsec = 0;
int i;
if (p->policy) {
/* compute policy length */
policy_file_init(&polfile);
polfile.type = PF_LEN;
polfile.handle = file->handle;
if (policydb_write(&p->policy->p, &polfile))
return -1;
len = polfile.len;
if (!polfile.len)
return -1;
nsec++;
} else {
/* We don't support writing a package without a module at this point */
return -1;
}
/* seusers and user_extra only supported in base at the moment */
if ((p->seusers || p->user_extra)
&& (p->policy->p.policy_type != SEPOL_POLICY_BASE)) {
ERR(file->handle,
"seuser and user_extra sections only supported in base");
return -1;
}
if (p->file_contexts)
nsec++;
if (p->seusers)
nsec++;
if (p->user_extra)
nsec++;
if (p->netfilter_contexts)
nsec++;
buf[0] = cpu_to_le32(SEPOL_MODULE_PACKAGE_MAGIC);
buf[1] = cpu_to_le32(p->version);
buf[2] = cpu_to_le32(nsec);
if (put_entry(buf, sizeof(uint32_t), 3, file) != 3)
return -1;
/* calculate offsets */
offsets[0] = (nsec + 3) * sizeof(uint32_t);
buf[0] = cpu_to_le32(offsets[0]);
i = 1;
if (p->file_contexts) {
offsets[i] = offsets[i - 1] + len;
buf[i] = cpu_to_le32(offsets[i]);
/* add a uint32_t to compensate for the magic number */
len = p->file_contexts_len + sizeof(uint32_t);
i++;
}
if (p->seusers) {
offsets[i] = offsets[i - 1] + len;
buf[i] = cpu_to_le32(offsets[i]);
len = p->seusers_len + sizeof(uint32_t);
i++;
}
if (p->user_extra) {
offsets[i] = offsets[i - 1] + len;
buf[i] = cpu_to_le32(offsets[i]);
len = p->user_extra_len + sizeof(uint32_t);
i++;
}
if (p->netfilter_contexts) {
offsets[i] = offsets[i - 1] + len;
buf[i] = cpu_to_le32(offsets[i]);
len = p->netfilter_contexts_len + sizeof(uint32_t);
i++;
}
if (put_entry(buf, sizeof(uint32_t), nsec, file) != nsec)
return -1;
/* write sections */
if (policydb_write(&p->policy->p, file))
return -1;
if (p->file_contexts) {
buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_FC);
if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
return -1;
if (write_helper(p->file_contexts, p->file_contexts_len, file))
return -1;
}
if (p->seusers) {
buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_SEUSER);
if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
return -1;
if (write_helper(p->seusers, p->seusers_len, file))
return -1;
}
if (p->user_extra) {
buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_USER_EXTRA);
if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
return -1;
if (write_helper(p->user_extra, p->user_extra_len, file))
return -1;
}
if (p->netfilter_contexts) {
buf[0] = cpu_to_le32(SEPOL_PACKAGE_SECTION_NETFILTER);
if (put_entry(buf, sizeof(uint32_t), 1, file) != 1)
return -1;
if (write_helper
(p->netfilter_contexts, p->netfilter_contexts_len, file))
return -1;
}
return 0;
}
int sepol_link_modules(sepol_handle_t * handle,
sepol_policydb_t * base,
sepol_policydb_t ** modules, size_t len, int verbose)
{
return link_modules(handle, &base->p, (policydb_t **) modules, len,
verbose);
}
int sepol_expand_module(sepol_handle_t * handle,
sepol_policydb_t * base,
sepol_policydb_t * out, int verbose, int check)
{
return expand_module(handle, &base->p, &out->p, verbose, check);
}