mirror of https://github.com/dzavalishin/oskit/
1741 lines
36 KiB
C
1741 lines
36 KiB
C
|
/* FLASK */
|
||
|
|
||
|
/*
|
||
|
* Copyright (c) 1999, 2000 The University of Utah and the Flux Group.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Contributed by the Computer Security Research division,
|
||
|
* INFOSEC Research and Technology Office, NSA.
|
||
|
*
|
||
|
* This file is part of the Flux OSKit. The OSKit is free software, also known
|
||
|
* as "open source;" you can redistribute it and/or modify it under the terms
|
||
|
* of the GNU General Public License (GPL), version 2, as published by the Free
|
||
|
* Software Foundation (FSF). To explore alternate licensing terms, contact
|
||
|
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
|
||
|
*
|
||
|
* The OSKit 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 GPL for more details. You should have
|
||
|
* received a copy of the GPL along with the OSKit; see the file COPYING. If
|
||
|
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Implementation of the policy database.
|
||
|
*/
|
||
|
|
||
|
#include "policydb.h"
|
||
|
#include "services.h"
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
#include "mls.h"
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Initialize a policy database structure.
|
||
|
*/
|
||
|
int policydb_init(policydb_t * p)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
memset(p, 0, sizeof(policydb_t));
|
||
|
|
||
|
for (i = 0; i < SYM_NUM; i++) {
|
||
|
if (symtab_init(&p->symtab[i]))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (avtab_init(&p->te_avtab))
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The following *_index functions are used to
|
||
|
* define the val_to_name and val_to_struct arrays
|
||
|
* in a policy database structure. The val_to_name
|
||
|
* arrays are used when converting security context
|
||
|
* structures into string representations. The
|
||
|
* val_to_struct arrays are used when the attributes
|
||
|
* of a class, role, or user are needed.
|
||
|
*/
|
||
|
|
||
|
static int common_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
common_datum_t *comdatum;
|
||
|
|
||
|
|
||
|
comdatum = (common_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
p->p_common_val_to_name[comdatum->value - 1] = (char *) key;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int class_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
class_datum_t *cladatum;
|
||
|
|
||
|
|
||
|
cladatum = (class_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
p->p_class_val_to_name[cladatum->value - 1] = (char *) key;
|
||
|
p->class_val_to_struct[cladatum->value - 1] = cladatum;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int role_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
role_datum_t *role;
|
||
|
|
||
|
|
||
|
role = (role_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
p->p_role_val_to_name[role->value - 1] = (char *) key;
|
||
|
p->role_val_to_struct[role->value - 1] = role;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int type_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
type_datum_t *typdatum;
|
||
|
|
||
|
|
||
|
typdatum = (type_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
if (!typdatum->isalias)
|
||
|
p->p_type_val_to_name[typdatum->value - 1] = (char *) key;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
static int sens_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
level_datum_t *levdatum;
|
||
|
|
||
|
|
||
|
levdatum = (level_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
if (!levdatum->isalias)
|
||
|
p->p_sens_val_to_name[levdatum->level->sens - 1] = (char *) key;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int cat_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
cat_datum_t *catdatum;
|
||
|
|
||
|
|
||
|
catdatum = (cat_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
|
||
|
if (!catdatum->isalias)
|
||
|
p->p_cat_val_to_name[catdatum->value - 1] = (char *) key;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int user_index(hashtab_key_t key, hashtab_datum_t datum, void *datap)
|
||
|
{
|
||
|
policydb_t *p;
|
||
|
user_datum_t *usrdatum;
|
||
|
|
||
|
|
||
|
usrdatum = (user_datum_t *) datum;
|
||
|
p = (policydb_t *) datap;
|
||
|
|
||
|
p->p_user_val_to_name[usrdatum->value - 1] = (char *) key;
|
||
|
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int (*index_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) =
|
||
|
{
|
||
|
common_index,
|
||
|
class_index,
|
||
|
role_index,
|
||
|
type_index,
|
||
|
user_index
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
,sens_index,
|
||
|
cat_index
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Define the common val_to_name array and the class
|
||
|
* val_to_name and val_to_struct arrays in a policy
|
||
|
* database structure.
|
||
|
*/
|
||
|
int policydb_index_classes(policydb_t * p)
|
||
|
{
|
||
|
p->p_common_val_to_name = (char **)
|
||
|
malloc(p->p_commons.nprim * sizeof(char *));
|
||
|
if (!p->p_common_val_to_name)
|
||
|
return -1;
|
||
|
|
||
|
if (hashtab_map(p->p_commons.table, common_index, p))
|
||
|
return -1;
|
||
|
|
||
|
p->class_val_to_struct = (class_datum_t **)
|
||
|
malloc(p->p_classes.nprim * sizeof(class_datum_t *));
|
||
|
if (!p->class_val_to_struct)
|
||
|
return -1;
|
||
|
|
||
|
p->p_class_val_to_name = (char **)
|
||
|
malloc(p->p_classes.nprim * sizeof(char *));
|
||
|
if (!p->p_class_val_to_name)
|
||
|
return -1;
|
||
|
|
||
|
if (hashtab_map(p->p_classes.table, class_index, p))
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Define the other val_to_name and val_to_struct arrays
|
||
|
* in a policy database structure.
|
||
|
*/
|
||
|
int policydb_index_others(policydb_t * p)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
|
||
|
printf("security: %d users, %d roles, %d types",
|
||
|
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim);
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
printf(", %d levels", p->nlevels);
|
||
|
#endif
|
||
|
printf("\n");
|
||
|
|
||
|
printf("security: %d classes, %d access rules\n",
|
||
|
p->p_classes.nprim, p->te_avtab.nel);
|
||
|
|
||
|
avtab_hash_eval(&p->te_avtab, "security", "access rules");
|
||
|
|
||
|
p->role_val_to_struct = (role_datum_t **)
|
||
|
malloc(p->p_roles.nprim * sizeof(role_datum_t *));
|
||
|
if (!p->role_val_to_struct)
|
||
|
return -1;
|
||
|
|
||
|
p->user_val_to_struct = (user_datum_t **)
|
||
|
malloc(p->p_users.nprim * sizeof(user_datum_t *));
|
||
|
if (!p->user_val_to_struct)
|
||
|
return -1;
|
||
|
|
||
|
for (i = SYM_ROLES; i < SYM_NUM; i++) {
|
||
|
p->sym_val_to_name[i] = (char **)
|
||
|
malloc(p->symtab[i].nprim * sizeof(char *));
|
||
|
if (!p->sym_val_to_name[i])
|
||
|
return -1;
|
||
|
if (hashtab_map(p->symtab[i].table, index_f[i], p))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The following *_destroy functions are used to
|
||
|
* free any memory allocated for each kind of
|
||
|
* symbol data in the policy database.
|
||
|
*/
|
||
|
|
||
|
static int perm_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
if (key)
|
||
|
free(key);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int common_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
common_datum_t *comdatum;
|
||
|
|
||
|
if (key)
|
||
|
free(key);
|
||
|
comdatum = (common_datum_t *) datum;
|
||
|
hashtab_map(comdatum->permissions.table, perm_destroy, 0);
|
||
|
hashtab_destroy(comdatum->permissions.table);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
int constraint_expr_destroy(constraint_expr_t * expr)
|
||
|
{
|
||
|
expr->count--;
|
||
|
if (expr->count == 0) {
|
||
|
ebitmap_destroy(&expr->bitmap);
|
||
|
if (expr->left)
|
||
|
constraint_expr_destroy(expr->left);
|
||
|
if (expr->right)
|
||
|
constraint_expr_destroy(expr->right);
|
||
|
free(expr);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int class_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
class_datum_t *cladatum;
|
||
|
constraint_node_t *constraint, *ctemp;
|
||
|
|
||
|
if (key)
|
||
|
free(key);
|
||
|
cladatum = (class_datum_t *) datum;
|
||
|
hashtab_map(cladatum->permissions.table, perm_destroy, 0);
|
||
|
hashtab_destroy(cladatum->permissions.table);
|
||
|
constraint = cladatum->constraints;
|
||
|
while (constraint) {
|
||
|
constraint_expr_destroy(constraint->expr);
|
||
|
ctemp = constraint;
|
||
|
constraint = constraint->next;
|
||
|
free(ctemp);
|
||
|
}
|
||
|
if (cladatum->comkey)
|
||
|
free(cladatum->comkey);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int role_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
role_datum_t *role;
|
||
|
|
||
|
if (key)
|
||
|
free(key);
|
||
|
role = (role_datum_t *) datum;
|
||
|
ebitmap_destroy(&role->dominates);
|
||
|
ebitmap_destroy(&role->types);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
if (key)
|
||
|
free(key);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
static int sens_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
level_datum_t *levdatum;
|
||
|
|
||
|
if (key)
|
||
|
free(key);
|
||
|
levdatum = (level_datum_t *) datum;
|
||
|
if (!levdatum->isalias) {
|
||
|
ebitmap_destroy(&levdatum->level->cat);
|
||
|
free(levdatum->level);
|
||
|
}
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cat_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
if (key)
|
||
|
free(key);
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int user_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
user_datum_t *usrdatum;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
mls_range_list_t *rnode, *rtmp;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if (key)
|
||
|
free(key);
|
||
|
usrdatum = (user_datum_t *) datum;
|
||
|
ebitmap_destroy(&usrdatum->roles);
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
rnode = usrdatum->ranges;
|
||
|
while (rnode) {
|
||
|
rtmp = rnode;
|
||
|
rnode = rnode->next;
|
||
|
ebitmap_destroy(&rtmp->range.level[0].cat);
|
||
|
ebitmap_destroy(&rtmp->range.level[1].cat);
|
||
|
free(rtmp);
|
||
|
}
|
||
|
#endif
|
||
|
free(datum);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) =
|
||
|
{
|
||
|
common_destroy,
|
||
|
class_destroy,
|
||
|
role_destroy,
|
||
|
type_destroy,
|
||
|
user_destroy
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
,sens_destroy,
|
||
|
cat_destroy
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Free any memory allocated by a policy database structure.
|
||
|
*/
|
||
|
void policydb_destroy(policydb_t * p)
|
||
|
{
|
||
|
ocontext_t *c, *ctmp;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < SYM_NUM; i++) {
|
||
|
hashtab_map(p->symtab[i].table, destroy_f[i], 0);
|
||
|
hashtab_destroy(p->symtab[i].table);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < SYM_NUM; i++) {
|
||
|
if (p->sym_val_to_name[i])
|
||
|
free(p->sym_val_to_name[i]);
|
||
|
}
|
||
|
|
||
|
if (p->class_val_to_struct)
|
||
|
free(p->class_val_to_struct);
|
||
|
if (p->role_val_to_struct)
|
||
|
free(p->role_val_to_struct);
|
||
|
if (p->user_val_to_struct)
|
||
|
free(p->user_val_to_struct);
|
||
|
|
||
|
for (i = 0; i < TED_NUM; i++)
|
||
|
ebitmap_destroy(&p->te_def[i].exclude);
|
||
|
|
||
|
avtab_destroy(&p->te_avtab);
|
||
|
|
||
|
for (i = 0; i < OCON_NUM; i++) {
|
||
|
c = p->ocontexts[i];
|
||
|
while (c) {
|
||
|
ctmp = c;
|
||
|
c = c->next;
|
||
|
context_destroy(&ctmp->context[0]);
|
||
|
context_destroy(&ctmp->context[1]);
|
||
|
if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF)
|
||
|
free(ctmp->u.name);
|
||
|
free(ctmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Load the initial SIDs specified in a policy database
|
||
|
* structure into a SID table.
|
||
|
*/
|
||
|
int policydb_load_isids(policydb_t *p, sidtab_t *s)
|
||
|
{
|
||
|
ocontext_t *head, *c;
|
||
|
|
||
|
memset(s, 0, sizeof(sidtab));
|
||
|
|
||
|
head = p->ocontexts[OCON_ISID];
|
||
|
for (c = head; c; c = c->next) {
|
||
|
if (!c->context[0].user) {
|
||
|
printf("security: SID %s was never defined.\n",
|
||
|
c->u.name);
|
||
|
return -1;
|
||
|
}
|
||
|
if (sidtab_insert(s, c->sid[0], &c->context[0])) {
|
||
|
printf("security: unable to load initial SID %s.\n",
|
||
|
c->u.name);
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Return TRUE if the fields in the security context
|
||
|
* structure `c' are valid. Return FALSE otherwise.
|
||
|
*/
|
||
|
int policydb_context_isvalid(policydb_t *p, context_struct_t *c)
|
||
|
{
|
||
|
role_datum_t *role;
|
||
|
user_datum_t *usrdatum;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Role must be authorized for the type.
|
||
|
*/
|
||
|
if (!c->role || c->role > p->p_roles.nprim)
|
||
|
return FALSE;
|
||
|
role = p->role_val_to_struct[c->role - 1];
|
||
|
if (!ebitmap_get_bit(&role->types,
|
||
|
c->type - 1))
|
||
|
/* role may not be associated with type */
|
||
|
return FALSE;
|
||
|
|
||
|
/*
|
||
|
* User must be authorized for the role.
|
||
|
*/
|
||
|
if (!c->user || c->user > p->p_users.nprim)
|
||
|
return FALSE;
|
||
|
usrdatum = p->user_val_to_struct[c->user - 1];
|
||
|
if (!usrdatum)
|
||
|
return FALSE;
|
||
|
|
||
|
if (!ebitmap_get_bit(&usrdatum->roles,
|
||
|
c->role - 1))
|
||
|
/* user may not be associated with role */
|
||
|
return FALSE;
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
if (!mls_context_isvalid(p, c))
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Read and validate a security context structure
|
||
|
* from a policydb binary representation file.
|
||
|
*/
|
||
|
static int context_read_and_validate(context_struct_t * c,
|
||
|
policydb_t * p,
|
||
|
FILE * fp)
|
||
|
{
|
||
|
__u32 buf[32];
|
||
|
size_t items;
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 3, fp);
|
||
|
if (items != 3) {
|
||
|
printf("security: context truncated\n");
|
||
|
return -1;
|
||
|
}
|
||
|
c->user = le32_to_cpu(buf[0]);
|
||
|
c->role = le32_to_cpu(buf[1]);
|
||
|
c->type = le32_to_cpu(buf[2]);
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
if (mls_read_range(&c->range, fp)) {
|
||
|
printf("security: error reading MLS range of context\n");
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (!policydb_context_isvalid(p, c)) {
|
||
|
printf("security: invalid security context\n");
|
||
|
context_destroy(c);
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The following *_read functions are used to
|
||
|
* read the symbol data from a policy database
|
||
|
* binary representation file.
|
||
|
*/
|
||
|
|
||
|
static int perm_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
perm_datum_t *perdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
|
||
|
perdatum = malloc(sizeof(perm_datum_t));
|
||
|
if (!perdatum)
|
||
|
return -1;
|
||
|
memset(perdatum, 0, sizeof(perm_datum_t));
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
items = 3;
|
||
|
#else
|
||
|
items = 2;
|
||
|
#endif
|
||
|
items2 = fread(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
perdatum->value = le32_to_cpu(buf[1]);
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
perdatum->base_perms = le32_to_cpu(buf[2]);
|
||
|
#endif
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (hashtab_insert(h, key, perdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
perm_destroy(key, perdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int common_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
common_datum_t *comdatum;
|
||
|
__u32 buf[32], len, nel;
|
||
|
int items, i;
|
||
|
|
||
|
comdatum = malloc(sizeof(common_datum_t));
|
||
|
if (!comdatum)
|
||
|
return -1;
|
||
|
memset(comdatum, 0, sizeof(common_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 4, fp);
|
||
|
if (items != 4)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
comdatum->value = le32_to_cpu(buf[1]);
|
||
|
|
||
|
if (symtab_init(&comdatum->permissions))
|
||
|
goto bad;
|
||
|
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
|
||
|
nel = le32_to_cpu(buf[3]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
for (i = 0; i < nel; i++) {
|
||
|
if (perm_read(p, comdatum->permissions.table, fp))
|
||
|
goto bad;
|
||
|
}
|
||
|
|
||
|
if (hashtab_insert(h, key, comdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
common_destroy(key, comdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static constraint_expr_t *
|
||
|
constraint_expr_read(FILE * fp)
|
||
|
{
|
||
|
constraint_expr_t *expr;
|
||
|
__u32 buf[32];
|
||
|
int items;
|
||
|
|
||
|
expr = malloc(sizeof(constraint_expr_t));
|
||
|
if (!expr)
|
||
|
return NULL;
|
||
|
memset(expr, 0, sizeof(constraint_expr_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
|
||
|
expr->expr_type = le32_to_cpu(buf[0]);
|
||
|
expr->count = 1;
|
||
|
items = 0;
|
||
|
|
||
|
if (expr->expr_type == CONSTRAINT_EXPR_TYPE_ROLE_RELATION) {
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
expr->relation = le32_to_cpu(buf[0]);
|
||
|
}
|
||
|
switch (expr->expr_type) {
|
||
|
case CONSTRAINT_EXPR_TYPE_TYPE_SOURCE:
|
||
|
case CONSTRAINT_EXPR_TYPE_TYPE_TARGET:
|
||
|
case CONSTRAINT_EXPR_TYPE_ROLE_SOURCE:
|
||
|
case CONSTRAINT_EXPR_TYPE_ROLE_TARGET:
|
||
|
if (!ebitmap_read(&expr->bitmap, fp))
|
||
|
goto bad;
|
||
|
break;
|
||
|
case CONSTRAINT_EXPR_TYPE_AND:
|
||
|
case CONSTRAINT_EXPR_TYPE_OR:
|
||
|
expr->left = constraint_expr_read(fp);
|
||
|
if (!expr->left)
|
||
|
goto bad;
|
||
|
expr->right = constraint_expr_read(fp);
|
||
|
if (!expr->right)
|
||
|
goto bad;
|
||
|
break;
|
||
|
case CONSTRAINT_EXPR_TYPE_NOT:
|
||
|
expr->left = constraint_expr_read(fp);
|
||
|
if (!expr->left)
|
||
|
goto bad;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return expr;
|
||
|
|
||
|
bad:
|
||
|
constraint_expr_destroy(expr);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int class_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
class_datum_t *cladatum;
|
||
|
constraint_node_t *c, *l;
|
||
|
__u32 buf[32], len, len2, ncons, nel;
|
||
|
int items, i;
|
||
|
|
||
|
cladatum = (class_datum_t *) malloc(sizeof(class_datum_t));
|
||
|
if (!cladatum)
|
||
|
return -1;
|
||
|
memset(cladatum, 0, sizeof(class_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 6, fp);
|
||
|
if (items != 6)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
len2 = le32_to_cpu(buf[1]);
|
||
|
cladatum->value = le32_to_cpu(buf[2]);
|
||
|
|
||
|
if (symtab_init(&cladatum->permissions))
|
||
|
goto bad;
|
||
|
cladatum->permissions.nprim = le32_to_cpu(buf[3]);
|
||
|
nel = le32_to_cpu(buf[4]);
|
||
|
|
||
|
ncons = le32_to_cpu(buf[5]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (len2) {
|
||
|
cladatum->comkey = malloc(len2 + 1);
|
||
|
if (!cladatum->comkey)
|
||
|
goto bad;
|
||
|
items = fread(cladatum->comkey, 1, len2, fp);
|
||
|
if (items != len2)
|
||
|
goto bad;
|
||
|
cladatum->comkey[len2] = 0;
|
||
|
|
||
|
cladatum->comdatum = hashtab_search(p->p_commons.table,
|
||
|
cladatum->comkey);
|
||
|
if (!cladatum->comdatum) {
|
||
|
printf("security: unknown common %s\n", cladatum->comkey);
|
||
|
goto bad;
|
||
|
}
|
||
|
}
|
||
|
for (i = 0; i < nel; i++) {
|
||
|
if (perm_read(p, cladatum->permissions.table, fp))
|
||
|
goto bad;
|
||
|
}
|
||
|
|
||
|
l = NULL;
|
||
|
for (i = 0; i < ncons; i++) {
|
||
|
c = malloc(sizeof(constraint_node_t));
|
||
|
if (!c)
|
||
|
goto bad;
|
||
|
memset(c, 0, sizeof(constraint_node_t));
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
c->permissions = le32_to_cpu(buf[0]);
|
||
|
c->expr = constraint_expr_read(fp);
|
||
|
if (!c->expr)
|
||
|
goto bad;
|
||
|
if (l) {
|
||
|
l->next = c;
|
||
|
} else {
|
||
|
cladatum->constraints = c;
|
||
|
}
|
||
|
l = c;
|
||
|
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
if (mls_read_perms(&cladatum->mlsperms, fp))
|
||
|
goto bad;
|
||
|
#endif
|
||
|
|
||
|
if (hashtab_insert(h, key, cladatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
class_destroy(key, cladatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int role_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
role_datum_t *role;
|
||
|
__u32 buf[32], len;
|
||
|
int items;
|
||
|
|
||
|
role = malloc(sizeof(role_datum_t));
|
||
|
if (!role)
|
||
|
return -1;
|
||
|
memset(role, 0, sizeof(role_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
role->value = le32_to_cpu(buf[1]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (!ebitmap_read(&role->dominates, fp))
|
||
|
goto bad;
|
||
|
|
||
|
if (!ebitmap_read(&role->types, fp))
|
||
|
goto bad;
|
||
|
|
||
|
if (hashtab_insert(h, key, role))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
role_destroy(key, role, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int type_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
type_datum_t *typdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items;
|
||
|
|
||
|
typdatum = malloc(sizeof(type_datum_t));
|
||
|
if (!typdatum)
|
||
|
return -1;
|
||
|
memset(typdatum, 0, sizeof(type_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 3, fp);
|
||
|
if (items != 3)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
typdatum->value = le32_to_cpu(buf[1]);
|
||
|
typdatum->isalias = le32_to_cpu(buf[2]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (hashtab_insert(h, key, typdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
type_destroy(key, typdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
static int sens_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
level_datum_t *levdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items;
|
||
|
|
||
|
levdatum = malloc(sizeof(level_datum_t));
|
||
|
if (!levdatum)
|
||
|
return -1;
|
||
|
memset(levdatum, 0, sizeof(level_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
levdatum->isalias = le32_to_cpu(buf[1]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
levdatum->level = mls_read_level(fp);
|
||
|
if (!levdatum->level)
|
||
|
goto bad;
|
||
|
|
||
|
if (hashtab_insert(h, key, levdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
sens_destroy(key, levdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int cat_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
cat_datum_t *catdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items;
|
||
|
|
||
|
catdatum = malloc(sizeof(cat_datum_t));
|
||
|
if (!catdatum)
|
||
|
return -1;
|
||
|
memset(catdatum, 0, sizeof(cat_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 3, fp);
|
||
|
if (items != 3)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
catdatum->value = le32_to_cpu(buf[1]);
|
||
|
catdatum->isalias = le32_to_cpu(buf[2]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (hashtab_insert(h, key, catdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
cat_destroy(key, catdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static int user_read(policydb_t * p, hashtab_t h, FILE * fp)
|
||
|
{
|
||
|
char *key = 0;
|
||
|
user_datum_t *usrdatum;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
mls_range_list_t *r, *l;
|
||
|
__u32 nel, i;
|
||
|
#endif
|
||
|
__u32 buf[32], len;
|
||
|
int items;
|
||
|
|
||
|
|
||
|
usrdatum = malloc(sizeof(user_datum_t));
|
||
|
if (!usrdatum)
|
||
|
return -1;
|
||
|
memset(usrdatum, 0, sizeof(user_datum_t));
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
goto bad;
|
||
|
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
usrdatum->value = le32_to_cpu(buf[1]);
|
||
|
|
||
|
key = malloc(len + 1);
|
||
|
if (!key)
|
||
|
goto bad;
|
||
|
items = fread(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
key[len] = 0;
|
||
|
|
||
|
if (!ebitmap_read(&usrdatum->roles, fp))
|
||
|
goto bad;
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
nel = le32_to_cpu(buf[0]);
|
||
|
l = NULL;
|
||
|
for (i = 0; i < nel; i++) {
|
||
|
r = malloc(sizeof(mls_range_list_t));
|
||
|
if (!r)
|
||
|
goto bad;
|
||
|
memset(r, 0, sizeof(mls_range_list_t));
|
||
|
|
||
|
if (mls_read_range(&r->range, fp))
|
||
|
goto bad;
|
||
|
|
||
|
if (l)
|
||
|
l->next = r;
|
||
|
else
|
||
|
usrdatum->ranges = r;
|
||
|
l = r;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (hashtab_insert(h, key, usrdatum))
|
||
|
goto bad;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
bad:
|
||
|
user_destroy(key, usrdatum, NULL);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int (*read_f[SYM_NUM]) (policydb_t * p, hashtab_t h, FILE * fp) =
|
||
|
{
|
||
|
common_read,
|
||
|
class_read,
|
||
|
role_read,
|
||
|
type_read,
|
||
|
user_read
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
,sens_read,
|
||
|
cat_read
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
#define mls_config(x) \
|
||
|
((x) & POLICYDB_CONFIG_MLS) ? "mls" : "no_mls"
|
||
|
#define audit_config(x) \
|
||
|
((x) & POLICYDB_CONFIG_AUDIT) ? "audit" : "no_audit"
|
||
|
#define notify_config(x) \
|
||
|
((x) & POLICYDB_CONFIG_NOTIFY) ? "notify" : "no_notify"
|
||
|
|
||
|
/*
|
||
|
* Read the configuration data from a policy database binary
|
||
|
* representation file into a policy database structure.
|
||
|
*/
|
||
|
int policydb_read(policydb_t * p, FILE * fp)
|
||
|
{
|
||
|
ocontext_t *c, *l;
|
||
|
int i, j;
|
||
|
__u32 buf[32], len, config, nprim, nel;
|
||
|
size_t items;
|
||
|
|
||
|
config = 0;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
config |= POLICYDB_CONFIG_MLS;
|
||
|
#endif
|
||
|
#ifdef CONFIG_FLASK_AUDIT
|
||
|
config |= POLICYDB_CONFIG_AUDIT;
|
||
|
#endif
|
||
|
#ifdef CONFIG_FLASK_NOTIFY
|
||
|
config |= POLICYDB_CONFIG_NOTIFY;
|
||
|
#endif
|
||
|
|
||
|
items = fread(buf, sizeof(__u32), 5, fp);
|
||
|
if (items != 5) {
|
||
|
return -1;
|
||
|
}
|
||
|
for (i = 0; i < 5; i++)
|
||
|
buf[i] = le32_to_cpu(buf[i]);
|
||
|
|
||
|
if (buf[0] != POLICYDB_VERSION) {
|
||
|
printf("security: policydb version %d does not match my version %d\n", buf[0], POLICYDB_VERSION);
|
||
|
return -1;
|
||
|
}
|
||
|
if (buf[1] != config) {
|
||
|
printf("security: policydb configuration (%s,%s,%s) does not match my configuration (%s,%s,%s)\n",
|
||
|
mls_config(buf[1]), audit_config(buf[1]), notify_config(buf[1]),
|
||
|
mls_config(config), audit_config(config), notify_config(config));
|
||
|
if ((buf[1] & POLICYDB_CONFIG_MLS) !=
|
||
|
(config & POLICYDB_CONFIG_MLS)) {
|
||
|
printf("security: policydb MLS configuration differs from mine, unable to proceed\n");
|
||
|
return -1;
|
||
|
}
|
||
|
/*
|
||
|
* Audit or notify configuration mismatches are not fatal,
|
||
|
* but we do need to remember the policydb configuration
|
||
|
* so that we know how to parse the policydb in
|
||
|
* avtab_read.
|
||
|
*/
|
||
|
printf("security: continuing despite configuration mismatch\n");
|
||
|
config = buf[1];
|
||
|
}
|
||
|
if (buf[2] != SYM_NUM || buf[3] != TED_NUM || buf[4] != OCON_NUM) {
|
||
|
printf("security: policydb table sizes (%d,%d,%d) do not match mine (%d,%d,%d)\n", buf[2], buf[3], buf[4], SYM_NUM, TED_NUM, OCON_NUM);
|
||
|
return -1;
|
||
|
}
|
||
|
memset(p, 0, sizeof(policydb_t));
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1) {
|
||
|
return -1;
|
||
|
}
|
||
|
p->nlevels = le32_to_cpu(buf[0]);
|
||
|
#endif
|
||
|
|
||
|
for (i = 0; i < SYM_NUM; i++) {
|
||
|
if (symtab_init(&p->symtab[i]))
|
||
|
goto bad;
|
||
|
items = fread(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
goto bad;
|
||
|
nprim = le32_to_cpu(buf[0]);
|
||
|
nel = le32_to_cpu(buf[1]);
|
||
|
for (j = 0; j < nel; j++) {
|
||
|
if (read_f[i] (p, p->symtab[i].table, fp))
|
||
|
goto bad;
|
||
|
}
|
||
|
|
||
|
p->symtab[i].nprim = nprim;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < TED_NUM; i++) {
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
p->te_def[i].value = le32_to_cpu(buf[0]);
|
||
|
if (!ebitmap_read(&p->te_def[i].exclude, fp)) {
|
||
|
goto bad;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (avtab_read(&p->te_avtab, fp, config))
|
||
|
goto bad;
|
||
|
|
||
|
if (policydb_index_classes(p))
|
||
|
goto bad;
|
||
|
|
||
|
if (policydb_index_others(p))
|
||
|
goto bad;
|
||
|
|
||
|
for (i = 0; i < OCON_NUM; i++) {
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
nel = le32_to_cpu(buf[0]);
|
||
|
l = NULL;
|
||
|
for (j = 0; j < nel; j++) {
|
||
|
c = malloc(sizeof(ocontext_t));
|
||
|
if (!c) {
|
||
|
goto bad;
|
||
|
}
|
||
|
memset(c, 0, sizeof(ocontext_t));
|
||
|
if (l) {
|
||
|
l->next = c;
|
||
|
} else {
|
||
|
p->ocontexts[i] = c;
|
||
|
}
|
||
|
l = c;
|
||
|
switch (i) {
|
||
|
case OCON_ISID:
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
c->sid[0] = le32_to_cpu(buf[0]);
|
||
|
if (context_read_and_validate(&c->context[0], p, fp))
|
||
|
goto bad;
|
||
|
break;
|
||
|
case OCON_FS:
|
||
|
case OCON_NETIF:
|
||
|
items = fread(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
goto bad;
|
||
|
len = le32_to_cpu(buf[0]);
|
||
|
c->u.name = malloc(len + 1);
|
||
|
if (!c->u.name) {
|
||
|
goto bad;
|
||
|
}
|
||
|
items = fread(c->u.name, 1, len, fp);
|
||
|
if (items != len)
|
||
|
goto bad;
|
||
|
c->u.name[len] = 0;
|
||
|
if (context_read_and_validate(&c->context[0], p, fp))
|
||
|
goto bad;
|
||
|
if (context_read_and_validate(&c->context[1], p, fp))
|
||
|
goto bad;
|
||
|
break;
|
||
|
case OCON_PORT:
|
||
|
items = fread(buf, sizeof(__u32), 3, fp);
|
||
|
if (items != 3)
|
||
|
goto bad;
|
||
|
c->u.port.protocol = le32_to_cpu(buf[0]);
|
||
|
c->u.port.low_port = le32_to_cpu(buf[1]);
|
||
|
c->u.port.high_port = le32_to_cpu(buf[2]);
|
||
|
if (context_read_and_validate(&c->context[0], p, fp))
|
||
|
goto bad;
|
||
|
break;
|
||
|
case OCON_NODE:
|
||
|
items = fread(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
goto bad;
|
||
|
c->u.node.addr = le32_to_cpu(buf[0]);
|
||
|
c->u.node.mask = le32_to_cpu(buf[1]);
|
||
|
if (context_read_and_validate(&c->context[0], p, fp))
|
||
|
goto bad;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
bad:
|
||
|
policydb_destroy(p);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef __KERNEL__
|
||
|
|
||
|
/*
|
||
|
* Write a security context structure
|
||
|
* to a policydb binary representation file.
|
||
|
*/
|
||
|
static int context_write(context_struct_t * c, FILE * fp)
|
||
|
{
|
||
|
__u32 buf[32];
|
||
|
size_t items, items2;
|
||
|
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(c->user);
|
||
|
buf[items++] = cpu_to_le32(c->role);
|
||
|
buf[items++] = cpu_to_le32(c->type);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items2 != items)
|
||
|
return -1;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
if (mls_write_range(&c->range, fp))
|
||
|
return -1;
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The following *_write functions are used to
|
||
|
* write the symbol data to a policy database
|
||
|
* binary representation file.
|
||
|
*/
|
||
|
|
||
|
static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
perm_datum_t *perdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
perdatum = (perm_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(perdatum->value);
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
buf[items++] = cpu_to_le32(perdatum->base_perms);
|
||
|
#endif
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
common_datum_t *comdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
comdatum = (common_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(comdatum->value);
|
||
|
buf[items++] = cpu_to_le32(comdatum->permissions.nprim);
|
||
|
buf[items++] = cpu_to_le32(comdatum->permissions.table->nel);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
if (hashtab_map(comdatum->permissions.table, perm_write, fp))
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int constraint_expr_write(constraint_expr_t * expr, FILE * fp)
|
||
|
{
|
||
|
__u32 buf[32];
|
||
|
int items, items2;
|
||
|
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(expr->expr_type);
|
||
|
if (expr->expr_type == CONSTRAINT_EXPR_TYPE_ROLE_RELATION)
|
||
|
buf[items++] = cpu_to_le32(expr->relation);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
switch (expr->expr_type) {
|
||
|
case CONSTRAINT_EXPR_TYPE_TYPE_SOURCE:
|
||
|
case CONSTRAINT_EXPR_TYPE_TYPE_TARGET:
|
||
|
case CONSTRAINT_EXPR_TYPE_ROLE_SOURCE:
|
||
|
case CONSTRAINT_EXPR_TYPE_ROLE_TARGET:
|
||
|
if (!ebitmap_write(&expr->bitmap, fp))
|
||
|
return -1;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (expr->left) {
|
||
|
if (constraint_expr_write(expr->left, fp))
|
||
|
return -1;
|
||
|
}
|
||
|
if (expr->right) {
|
||
|
if (constraint_expr_write(expr->right, fp))
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
class_datum_t *cladatum;
|
||
|
constraint_node_t *c;
|
||
|
__u32 buf[32], len, len2, ncons;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
cladatum = (class_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
if (cladatum->comkey)
|
||
|
len2 = strlen(cladatum->comkey);
|
||
|
else
|
||
|
len2 = 0;
|
||
|
|
||
|
ncons = 0;
|
||
|
for (c = cladatum->constraints; c; c = c->next) {
|
||
|
ncons++;
|
||
|
}
|
||
|
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(len2);
|
||
|
buf[items++] = cpu_to_le32(cladatum->value);
|
||
|
buf[items++] = cpu_to_le32(cladatum->permissions.nprim);
|
||
|
buf[items++] = cpu_to_le32(cladatum->permissions.table->nel);
|
||
|
buf[items++] = cpu_to_le32(ncons);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
if (cladatum->comkey) {
|
||
|
items = fwrite(cladatum->comkey, 1, len2, fp);
|
||
|
if (items != len2)
|
||
|
return -1;
|
||
|
}
|
||
|
if (hashtab_map(cladatum->permissions.table, perm_write, fp))
|
||
|
return -1;
|
||
|
|
||
|
for (c = cladatum->constraints; c; c = c->next) {
|
||
|
buf[0] = cpu_to_le32(c->permissions);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
if (constraint_expr_write(c->expr, fp))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
if (mls_write_perms(&cladatum->mlsperms, fp))
|
||
|
return -1;
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
role_datum_t *role;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
role = (role_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(role->value);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
if (!ebitmap_write(&role->dominates, fp))
|
||
|
return -1;
|
||
|
|
||
|
if (!ebitmap_write(&role->types, fp))
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
type_datum_t *typdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
typdatum = (type_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(typdatum->value);
|
||
|
buf[items++] = cpu_to_le32(typdatum->isalias);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
level_datum_t *levdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
levdatum = (level_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(levdatum->isalias);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
if (mls_write_level(levdatum->level, fp))
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
cat_datum_t *catdatum;
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
|
||
|
catdatum = (cat_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(catdatum->value);
|
||
|
buf[items++] = cpu_to_le32(catdatum->isalias);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *p)
|
||
|
{
|
||
|
user_datum_t *usrdatum;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
mls_range_list_t *r;
|
||
|
__u32 nel;
|
||
|
#endif
|
||
|
__u32 buf[32], len;
|
||
|
int items, items2;
|
||
|
FILE *fp = p;
|
||
|
|
||
|
|
||
|
usrdatum = (user_datum_t *) datum;
|
||
|
|
||
|
len = strlen(key);
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(len);
|
||
|
buf[items++] = cpu_to_le32(usrdatum->value);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
items = fwrite(key, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
|
||
|
if (!ebitmap_write(&usrdatum->roles, fp))
|
||
|
return -1;
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
nel = 0;
|
||
|
for (r = usrdatum->ranges; r; r = r->next)
|
||
|
nel++;
|
||
|
buf[0] = cpu_to_le32(nel);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
for (r = usrdatum->ranges; r; r = r->next) {
|
||
|
if (mls_write_range(&r->range, fp))
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int (*write_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, void *datap) =
|
||
|
{
|
||
|
common_write,
|
||
|
class_write,
|
||
|
role_write,
|
||
|
type_write,
|
||
|
user_write
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
,sens_write,
|
||
|
cat_write
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Write the configuration data in a policy database
|
||
|
* structure to a policy database binary representation
|
||
|
* file.
|
||
|
*/
|
||
|
int policydb_write(policydb_t * p, FILE * fp)
|
||
|
{
|
||
|
ocontext_t *c;
|
||
|
int i, j;
|
||
|
__u32 buf[32], len, config, nel;
|
||
|
size_t items, items2;
|
||
|
|
||
|
config = 0;
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
config |= POLICYDB_CONFIG_MLS;
|
||
|
#endif
|
||
|
#ifdef CONFIG_FLASK_AUDIT
|
||
|
config |= POLICYDB_CONFIG_AUDIT;
|
||
|
#endif
|
||
|
#ifdef CONFIG_FLASK_NOTIFY
|
||
|
config |= POLICYDB_CONFIG_NOTIFY;
|
||
|
#endif
|
||
|
|
||
|
items = 0;
|
||
|
buf[items++] = cpu_to_le32(POLICYDB_VERSION);
|
||
|
buf[items++] = cpu_to_le32(config);
|
||
|
buf[items++] = cpu_to_le32(SYM_NUM);
|
||
|
buf[items++] = cpu_to_le32(TED_NUM);
|
||
|
buf[items++] = cpu_to_le32(OCON_NUM);
|
||
|
items2 = fwrite(buf, sizeof(__u32), items, fp);
|
||
|
if (items != items2)
|
||
|
return -1;
|
||
|
|
||
|
#ifdef CONFIG_FLASK_MLS
|
||
|
buf[0] = cpu_to_le32(p->nlevels);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
#endif
|
||
|
|
||
|
for (i = 0; i < SYM_NUM; i++) {
|
||
|
buf[0] = cpu_to_le32(p->symtab[i].nprim);
|
||
|
buf[1] = cpu_to_le32(p->symtab[i].table->nel);
|
||
|
items = fwrite(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
return -1;
|
||
|
if (hashtab_map(p->symtab[i].table, write_f[i], fp))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < TED_NUM; i++) {
|
||
|
buf[0] = cpu_to_le32(p->te_def[i].value);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
if (!ebitmap_write(&p->te_def[i].exclude, fp))
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (avtab_write(&p->te_avtab, fp))
|
||
|
return -1;
|
||
|
|
||
|
for (i = 0; i < OCON_NUM; i++) {
|
||
|
nel = 0;
|
||
|
for (c = p->ocontexts[i]; c; c = c->next)
|
||
|
nel++;
|
||
|
buf[0] = cpu_to_le32(nel);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
for (c = p->ocontexts[i]; c; c = c->next) {
|
||
|
switch (i) {
|
||
|
case OCON_ISID:
|
||
|
buf[0] = cpu_to_le32(c->sid[0]);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
if (context_write(&c->context[0], fp))
|
||
|
return -1;
|
||
|
break;
|
||
|
case OCON_FS:
|
||
|
case OCON_NETIF:
|
||
|
len = strlen(c->u.name);
|
||
|
buf[0] = cpu_to_le32(len);
|
||
|
items = fwrite(buf, sizeof(__u32), 1, fp);
|
||
|
if (items != 1)
|
||
|
return -1;
|
||
|
items = fwrite(c->u.name, 1, len, fp);
|
||
|
if (items != len)
|
||
|
return -1;
|
||
|
if (context_write(&c->context[0], fp))
|
||
|
return -1;
|
||
|
if (context_write(&c->context[1], fp))
|
||
|
return -1;
|
||
|
break;
|
||
|
case OCON_PORT:
|
||
|
buf[0] = c->u.port.protocol;
|
||
|
buf[1] = c->u.port.low_port;
|
||
|
buf[2] = c->u.port.high_port;
|
||
|
for (j = 0; j < 3; j++) {
|
||
|
buf[j] = cpu_to_le32(buf[j]);
|
||
|
}
|
||
|
items = fwrite(buf, sizeof(__u32), 3, fp);
|
||
|
if (items != 3)
|
||
|
return -1;
|
||
|
if (context_write(&c->context[0], fp))
|
||
|
return -1;
|
||
|
break;
|
||
|
case OCON_NODE:
|
||
|
buf[0] = cpu_to_le32(c->u.node.addr);
|
||
|
buf[1] = cpu_to_le32(c->u.node.mask);
|
||
|
items = fwrite(buf, sizeof(__u32), 2, fp);
|
||
|
if (items != 2)
|
||
|
return -1;
|
||
|
if (context_write(&c->context[0], fp))
|
||
|
return -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif
|