mirror of
https://github.com/topjohnwu/selinux.git
synced 2024-12-11 13:26:01 +00:00
Merge remote-tracking branch 'aosp/upstream-master' into mymerge
This commit is contained in:
commit
10ca689116
@ -11,7 +11,6 @@ common_src_files := \
|
||||
common_cflags := \
|
||||
-Wall -Wshadow -O2 \
|
||||
-pipe -fno-strict-aliasing \
|
||||
-Wno-return-type
|
||||
|
||||
ifeq ($(HOST_OS),darwin)
|
||||
common_cflags += -DDARWIN
|
||||
|
@ -1,3 +1,8 @@
|
||||
* Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep.
|
||||
* fix double free on name-based type transitions, from Stephen Smalley.
|
||||
* switch operations to extended perms, from Jeff Vander Stoep.
|
||||
* policy_define.c: fix compiler warnings, from Nick Kralevich.
|
||||
* Remove uses of -Wno-return-type, from Dan Albert.
|
||||
* Fix -Wreturn-type issues, from Dan Albert.
|
||||
* dispol: display operations as ranges, from Jeff Vander Stoep.
|
||||
* dispol: Extend to display operations, from Stephen Smalley.
|
||||
|
@ -1521,7 +1521,8 @@ int define_compute_type_helper(int which, avrule_t ** rule)
|
||||
ebitmap_node_t *node;
|
||||
avrule_t *avrule;
|
||||
class_perm_node_t *perm;
|
||||
int i, add = 1;
|
||||
uint32_t i;
|
||||
int add = 1;
|
||||
|
||||
avrule = malloc(sizeof(avrule_t));
|
||||
if (!avrule) {
|
||||
@ -1728,32 +1729,27 @@ avrule_t *define_cond_pol_list(avrule_t * avlist, avrule_t * sl)
|
||||
return sl;
|
||||
}
|
||||
|
||||
#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
|
||||
#define operation_perm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
|
||||
#define operation_perm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
|
||||
|
||||
typedef struct av_operations_range {
|
||||
typedef struct av_ioctl_range {
|
||||
uint16_t low;
|
||||
uint16_t high;
|
||||
} av_operations_range_t;
|
||||
} av_ioctl_range_t;
|
||||
|
||||
struct av_operations_range_list {
|
||||
struct av_ioctl_range_list {
|
||||
uint8_t omit;
|
||||
av_operations_range_t range;
|
||||
struct av_operations_range_list *next;
|
||||
av_ioctl_range_t range;
|
||||
struct av_ioctl_range_list *next;
|
||||
};
|
||||
|
||||
int avrule_sort_operations(
|
||||
struct av_operations_range_list **rangehead)
|
||||
int avrule_sort_ioctls(struct av_ioctl_range_list **rangehead)
|
||||
{
|
||||
struct av_operations_range_list *r, *r2, *sorted, *sortedhead = NULL;
|
||||
struct av_ioctl_range_list *r, *r2, *sorted, *sortedhead = NULL;
|
||||
|
||||
/* order list by range.low */
|
||||
for (r = *rangehead; r != NULL; r = r->next) {
|
||||
sorted = malloc(sizeof(struct av_operations_range_list));
|
||||
sorted = malloc(sizeof(struct av_ioctl_range_list));
|
||||
if (sorted == NULL)
|
||||
goto error;
|
||||
memcpy(sorted, r, sizeof(struct av_operations_range_list));
|
||||
memcpy(sorted, r, sizeof(struct av_ioctl_range_list));
|
||||
sorted->next = NULL;
|
||||
if (sortedhead == NULL) {
|
||||
sortedhead = sorted;
|
||||
@ -1792,9 +1788,9 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int avrule_merge_operations(struct av_operations_range_list **rangehead)
|
||||
int avrule_merge_ioctls(struct av_ioctl_range_list **rangehead)
|
||||
{
|
||||
struct av_operations_range_list *r, *tmp;
|
||||
struct av_ioctl_range_list *r, *tmp;
|
||||
r = *rangehead;
|
||||
while (r != NULL && r->next != NULL) {
|
||||
/* merge */
|
||||
@ -1812,14 +1808,14 @@ int avrule_merge_operations(struct av_operations_range_list **rangehead)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avrule_read_operations(struct av_operations_range_list **rangehead)
|
||||
int avrule_read_ioctls(struct av_ioctl_range_list **rangehead)
|
||||
{
|
||||
char *id;
|
||||
struct av_operations_range_list *rnew, *r = NULL;
|
||||
struct av_ioctl_range_list *rnew, *r = NULL;
|
||||
*rangehead = NULL;
|
||||
uint8_t omit = 0;
|
||||
|
||||
/* read in all the operations */
|
||||
/* read in all the ioctl commands */
|
||||
while ((id = queue_remove(id_queue))) {
|
||||
if (strcmp(id,"~") == 0) {
|
||||
/* these are values to be omitted */
|
||||
@ -1837,7 +1833,7 @@ int avrule_read_operations(struct av_operations_range_list **rangehead)
|
||||
free(id);
|
||||
} else {
|
||||
/* read in new low value */
|
||||
rnew = malloc(sizeof(struct av_operations_range_list));
|
||||
rnew = malloc(sizeof(struct av_ioctl_range_list));
|
||||
if (rnew == NULL)
|
||||
goto error;
|
||||
rnew->next = NULL;
|
||||
@ -1862,11 +1858,11 @@ error:
|
||||
}
|
||||
|
||||
/* flip to included ranges */
|
||||
int avrule_omit_operations(struct av_operations_range_list **rangehead)
|
||||
int avrule_omit_ioctls(struct av_ioctl_range_list **rangehead)
|
||||
{
|
||||
struct av_operations_range_list *rnew, *r, *newhead, *r2;
|
||||
struct av_ioctl_range_list *rnew, *r, *newhead, *r2;
|
||||
|
||||
rnew = calloc(1, sizeof(struct av_operations_range_list));
|
||||
rnew = calloc(1, sizeof(struct av_ioctl_range_list));
|
||||
if (!rnew)
|
||||
goto error;
|
||||
|
||||
@ -1884,7 +1880,7 @@ int avrule_omit_operations(struct av_operations_range_list **rangehead)
|
||||
|
||||
while (r) {
|
||||
r2->range.high = r->range.low - 1;
|
||||
rnew = calloc(1, sizeof(struct av_operations_range_list));
|
||||
rnew = calloc(1, sizeof(struct av_ioctl_range_list));
|
||||
if (!rnew)
|
||||
goto error;
|
||||
r2->next = rnew;
|
||||
@ -1910,27 +1906,27 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int avrule_operation_ranges(struct av_operations_range_list **rangelist)
|
||||
int avrule_ioctl_ranges(struct av_ioctl_range_list **rangelist)
|
||||
{
|
||||
struct av_operations_range_list *rangehead;
|
||||
struct av_ioctl_range_list *rangehead;
|
||||
uint8_t omit;
|
||||
|
||||
/* read in ranges to include and omit */
|
||||
if (avrule_read_operations(&rangehead))
|
||||
if (avrule_read_ioctls(&rangehead))
|
||||
return -1;
|
||||
omit = rangehead->omit;
|
||||
if (rangehead == NULL) {
|
||||
yyerror("error processing ioctl operations");
|
||||
yyerror("error processing ioctl commands");
|
||||
return -1;
|
||||
}
|
||||
/* sort and merge the input operations */
|
||||
if (avrule_sort_operations(&rangehead))
|
||||
/* sort and merge the input ioctls */
|
||||
if (avrule_sort_ioctls(&rangehead))
|
||||
return -1;
|
||||
if (avrule_merge_operations(&rangehead))
|
||||
if (avrule_merge_ioctls(&rangehead))
|
||||
return -1;
|
||||
/* flip ranges if these are ommited*/
|
||||
if (omit) {
|
||||
if (avrule_omit_operations(&rangehead))
|
||||
if (avrule_omit_ioctls(&rangehead))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1938,10 +1934,12 @@ int avrule_operation_ranges(struct av_operations_range_list **rangelist)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
int define_te_avtab_xperms_helper(int which, avrule_t ** rule)
|
||||
{
|
||||
char *id;
|
||||
class_perm_node_t *perms, *tail = NULL, *cur_perms = NULL;
|
||||
class_datum_t *cladatum;
|
||||
perm_datum_t *perdatum = NULL;
|
||||
ebitmap_t tclasses;
|
||||
ebitmap_node_t *node;
|
||||
avrule_t *avrule;
|
||||
@ -1959,7 +1957,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
avrule->line = policydb_lineno;
|
||||
avrule->source_line = source_lineno;
|
||||
avrule->source_filename = strdup(source_file);
|
||||
avrule->ops = NULL;
|
||||
avrule->xperms = NULL;
|
||||
if (!avrule->source_filename) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
@ -1968,7 +1966,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
while ((id = queue_remove(id_queue))) {
|
||||
if (set_types
|
||||
(&avrule->stypes, id, &add,
|
||||
which == AVRULE_NEVERALLOW ? 1 : 0)) {
|
||||
which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
@ -1982,7 +1980,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
}
|
||||
if (set_types
|
||||
(&avrule->ttypes, id, &add,
|
||||
which == AVRULE_NEVERALLOW ? 1 : 0)) {
|
||||
which == AVRULE_XPERMS_NEVERALLOW ? 1 : 0)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
@ -1994,6 +1992,7 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
goto out;
|
||||
|
||||
perms = NULL;
|
||||
id = queue_head(id_queue);
|
||||
ebitmap_for_each_bit(&tclasses, node, i) {
|
||||
if (!ebitmap_node_get_bit(node, i))
|
||||
continue;
|
||||
@ -2011,6 +2010,29 @@ int define_te_avtab_operation_helper(int which, avrule_t ** rule)
|
||||
if (tail)
|
||||
tail->next = cur_perms;
|
||||
tail = cur_perms;
|
||||
|
||||
cladatum = policydbp->class_val_to_struct[i];
|
||||
perdatum = hashtab_search(cladatum->permissions.table, id);
|
||||
if (!perdatum) {
|
||||
if (cladatum->comdatum) {
|
||||
perdatum = hashtab_search(cladatum->comdatum->
|
||||
permissions.table,
|
||||
id);
|
||||
}
|
||||
}
|
||||
if (!perdatum) {
|
||||
yyerror2("permission %s is not defined"
|
||||
" for class %s", id,
|
||||
policydbp->p_class_val_to_name[i]);
|
||||
continue;
|
||||
} else if (!is_perm_in_scope (id, policydbp->p_class_val_to_name[i])) {
|
||||
yyerror2("permission %s of class %s is"
|
||||
" not within scope", id,
|
||||
policydbp->p_class_val_to_name[i]);
|
||||
continue;
|
||||
} else {
|
||||
cur_perms->data |= 1U << (perdatum->s.value - 1);
|
||||
}
|
||||
}
|
||||
|
||||
ebitmap_destroy(&tclasses);
|
||||
@ -2023,95 +2045,102 @@ out:
|
||||
}
|
||||
|
||||
/* index of the u32 containing the permission */
|
||||
#define OP_IDX(x) (x >> 5)
|
||||
#define XPERM_IDX(x) (x >> 5)
|
||||
/* set bits 0 through x-1 within the u32 */
|
||||
#define OP_SETBITS(x) ((1 << (x & 0x1f)) - 1)
|
||||
#define XPERM_SETBITS(x) ((1 << (x & 0x1f)) - 1)
|
||||
/* low value for this u32 */
|
||||
#define OP_LOW(x) (x << 5)
|
||||
#define XPERM_LOW(x) (x << 5)
|
||||
/* high value for this u32 */
|
||||
#define OP_HIGH(x) (((x + 1) << 5) - 1)
|
||||
void avrule_operation_setrangebits(uint16_t low, uint16_t high, av_operations_t *ops)
|
||||
#define XPERM_HIGH(x) (((x + 1) << 5) - 1)
|
||||
void avrule_xperm_setrangebits(uint16_t low, uint16_t high,
|
||||
av_extended_perms_t *xperms)
|
||||
{
|
||||
unsigned int i;
|
||||
uint16_t h = high + 1;
|
||||
/* for each u32 that this low-high range touches, set type permissions */
|
||||
for (i = OP_IDX(low); i <= OP_IDX(high); i++) {
|
||||
/* for each u32 that this low-high range touches, set driver permissions */
|
||||
for (i = XPERM_IDX(low); i <= XPERM_IDX(high); i++) {
|
||||
/* set all bits in u32 */
|
||||
if ((low <= OP_LOW(i)) && (high >= OP_HIGH(i)))
|
||||
ops->perms[i] |= ~0U;
|
||||
if ((low <= XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
|
||||
xperms->perms[i] |= ~0U;
|
||||
/* set low bits */
|
||||
else if ((low <= OP_LOW(i)) && (high < OP_HIGH(i)))
|
||||
ops->perms[i] |= OP_SETBITS(h);
|
||||
else if ((low <= XPERM_LOW(i)) && (high < XPERM_HIGH(i)))
|
||||
xperms->perms[i] |= XPERM_SETBITS(h);
|
||||
/* set high bits */
|
||||
else if ((low > OP_LOW(i)) && (high >= OP_HIGH(i)))
|
||||
ops->perms[i] |= ~0U - OP_SETBITS(low);
|
||||
else if ((low > XPERM_LOW(i)) && (high >= XPERM_HIGH(i)))
|
||||
xperms->perms[i] |= ~0U - XPERM_SETBITS(low);
|
||||
/* set middle bits */
|
||||
else if ((low > OP_LOW(i)) && (high <= OP_HIGH(i)))
|
||||
ops->perms[i] |= OP_SETBITS(h) - OP_SETBITS(low);
|
||||
else if ((low > XPERM_LOW(i)) && (high <= XPERM_HIGH(i)))
|
||||
xperms->perms[i] |= XPERM_SETBITS(h) - XPERM_SETBITS(low);
|
||||
}
|
||||
}
|
||||
|
||||
int avrule_operation_used(av_operations_t *ops)
|
||||
int avrule_xperms_used(av_extended_perms_t *xperms)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sizeof(ops->perms)/sizeof(ops->perms[0]); i++) {
|
||||
if (ops->perms[i])
|
||||
for (i = 0; i < sizeof(xperms->perms)/sizeof(xperms->perms[0]); i++) {
|
||||
if (xperms->perms[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OP_TYPE(x) (x >> 8)
|
||||
#define OP_NUM(x) (x & 0xff)
|
||||
#define OP_CMD(type, num) ((type << 8) + num)
|
||||
int avrule_operation_partialtype(struct av_operations_range_list *rangelist,
|
||||
av_operations_t *complete_type,
|
||||
av_operations_t **operations)
|
||||
/*
|
||||
* using definitions found in kernel document ioctl-number.txt
|
||||
* The kernel components of an ioctl command are:
|
||||
* dir, size, driver, and fucntion. Only the driver and function fields
|
||||
* are considered here
|
||||
*/
|
||||
#define IOC_DRIV(x) (x >> 8)
|
||||
#define IOC_FUNC(x) (x & 0xff)
|
||||
#define IOC_CMD(driver, func) ((driver << 8) + func)
|
||||
int avrule_ioctl_partialdriver(struct av_ioctl_range_list *rangelist,
|
||||
av_extended_perms_t *complete_driver,
|
||||
av_extended_perms_t **extended_perms)
|
||||
{
|
||||
struct av_operations_range_list *r;
|
||||
av_operations_t *ops;
|
||||
struct av_ioctl_range_list *r;
|
||||
av_extended_perms_t *xperms;
|
||||
uint8_t low, high;
|
||||
|
||||
ops = calloc(1, sizeof(av_operations_t));
|
||||
if (!ops) {
|
||||
xperms = calloc(1, sizeof(av_extended_perms_t));
|
||||
if (!xperms) {
|
||||
yyerror("out of memory");
|
||||
return - 1;
|
||||
}
|
||||
|
||||
r = rangelist;
|
||||
while(r) {
|
||||
low = OP_TYPE(r->range.low);
|
||||
high = OP_TYPE(r->range.high);
|
||||
if (complete_type) {
|
||||
if (!operation_perm_test(low, complete_type->perms))
|
||||
operation_perm_set(low, ops->perms);
|
||||
if (!operation_perm_test(high, complete_type->perms))
|
||||
operation_perm_set(high, ops->perms);
|
||||
low = IOC_DRIV(r->range.low);
|
||||
high = IOC_DRIV(r->range.high);
|
||||
if (complete_driver) {
|
||||
if (!xperm_test(low, complete_driver->perms))
|
||||
xperm_set(low, xperms->perms);
|
||||
if (!xperm_test(high, complete_driver->perms))
|
||||
xperm_set(high, xperms->perms);
|
||||
} else {
|
||||
operation_perm_set(low, ops->perms);
|
||||
operation_perm_set(high, ops->perms);
|
||||
xperm_set(low, xperms->perms);
|
||||
xperm_set(high, xperms->perms);
|
||||
}
|
||||
r = r->next;
|
||||
}
|
||||
if (avrule_operation_used(ops)) {
|
||||
*operations = ops;
|
||||
if (avrule_xperms_used(xperms)) {
|
||||
*extended_perms = xperms;
|
||||
} else {
|
||||
free(ops);
|
||||
*operations = NULL;
|
||||
free(xperms);
|
||||
*extended_perms = NULL;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int avrule_operation_completetype(struct av_operations_range_list *rangelist,
|
||||
av_operations_t **operations)
|
||||
int avrule_ioctl_completedriver(struct av_ioctl_range_list *rangelist,
|
||||
av_extended_perms_t **extended_perms)
|
||||
{
|
||||
struct av_operations_range_list *r;
|
||||
av_operations_t *ops;
|
||||
struct av_ioctl_range_list *r;
|
||||
av_extended_perms_t *xperms;
|
||||
uint16_t low, high;
|
||||
ops = calloc(1, sizeof(av_operations_t));
|
||||
if (!ops) {
|
||||
xperms = calloc(1, sizeof(av_extended_perms_t));
|
||||
if (!xperms) {
|
||||
yyerror("out of memory");
|
||||
return - 1;
|
||||
}
|
||||
@ -2119,83 +2148,86 @@ int avrule_operation_completetype(struct av_operations_range_list *rangelist,
|
||||
r = rangelist;
|
||||
while(r) {
|
||||
/*
|
||||
* Any type that has numbers 0x00 - 0xff is a complete type,
|
||||
* Any driver code that has sequence 0x00 - 0xff is a complete code,
|
||||
*
|
||||
* if command number = 0xff, then round high up to next type,
|
||||
* else 0x00 - 0xfe keep current type
|
||||
* if command number = 0xff, then round high up to next code,
|
||||
* else 0x00 - 0xfe keep current code
|
||||
* of this range. temporarily u32 for the + 1
|
||||
* to account for possible rollover before right shift
|
||||
*/
|
||||
high = OP_TYPE((uint32_t) (r->range.high + 1));
|
||||
/* if 0x00 keep current type else 0x01 - 0xff round up to next type */
|
||||
low = OP_TYPE(r->range.low);
|
||||
if (OP_NUM(r->range.low))
|
||||
high = IOC_DRIV((uint32_t) (r->range.high + 1));
|
||||
/* if 0x00 keep current driver code else 0x01 - 0xff round up to next code*/
|
||||
low = IOC_DRIV(r->range.low);
|
||||
if (IOC_FUNC(r->range.low))
|
||||
low++;
|
||||
if (high > low)
|
||||
avrule_operation_setrangebits(low, high - 1, ops);
|
||||
avrule_xperm_setrangebits(low, high - 1, xperms);
|
||||
r = r->next;
|
||||
}
|
||||
if (avrule_operation_used(ops)) {
|
||||
*operations = ops;
|
||||
if (avrule_xperms_used(xperms)) {
|
||||
xperms->driver = 0x00;
|
||||
xperms->specified = AVRULE_XPERMS_IOCTLDRIVER;
|
||||
*extended_perms = xperms;
|
||||
} else {
|
||||
free(ops);
|
||||
*operations = NULL;
|
||||
free(xperms);
|
||||
*extended_perms = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int avrule_operation_num(struct av_operations_range_list *rangelist,
|
||||
av_operations_t **operations, unsigned int type)
|
||||
int avrule_ioctl_func(struct av_ioctl_range_list *rangelist,
|
||||
av_extended_perms_t **extended_perms, unsigned int driver)
|
||||
{
|
||||
struct av_operations_range_list *r;
|
||||
av_operations_t *ops;
|
||||
struct av_ioctl_range_list *r;
|
||||
av_extended_perms_t *xperms;
|
||||
uint16_t low, high;
|
||||
|
||||
*operations = NULL;
|
||||
ops = calloc(1, sizeof(av_operations_t));
|
||||
if (!ops) {
|
||||
*extended_perms = NULL;
|
||||
xperms = calloc(1, sizeof(av_extended_perms_t));
|
||||
if (!xperms) {
|
||||
yyerror("out of memory");
|
||||
return - 1;
|
||||
}
|
||||
|
||||
r = rangelist;
|
||||
/* for the passed in types, find the ranges that apply */
|
||||
/* for the passed in driver code, find the ranges that apply */
|
||||
while (r) {
|
||||
low = r->range.low;
|
||||
high = r->range.high;
|
||||
if ((type != OP_TYPE(low)) && (type != OP_TYPE(high))) {
|
||||
if ((driver != IOC_DRIV(low)) && (driver != IOC_DRIV(high))) {
|
||||
r = r->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == OP_TYPE(low)) {
|
||||
if (high > OP_CMD(type, 0xff))
|
||||
high = OP_CMD(type, 0xff);
|
||||
if (driver == IOC_DRIV(low)) {
|
||||
if (high > IOC_CMD(driver, 0xff))
|
||||
high = IOC_CMD(driver, 0xff);
|
||||
|
||||
} else {
|
||||
if (low < OP_CMD(type, 0))
|
||||
low = OP_CMD(type, 0);
|
||||
if (low < IOC_CMD(driver, 0))
|
||||
low = IOC_CMD(driver, 0);
|
||||
}
|
||||
|
||||
low = OP_NUM(low);
|
||||
high = OP_NUM(high);
|
||||
avrule_operation_setrangebits(low, high, ops);
|
||||
ops->type = type;
|
||||
low = IOC_FUNC(low);
|
||||
high = IOC_FUNC(high);
|
||||
avrule_xperm_setrangebits(low, high, xperms);
|
||||
xperms->driver = driver;
|
||||
xperms->specified = AVRULE_XPERMS_IOCTLFUNCTION;
|
||||
r = r->next;
|
||||
}
|
||||
|
||||
if (avrule_operation_used(ops)) {
|
||||
*operations = ops;
|
||||
if (avrule_xperms_used(xperms)) {
|
||||
*extended_perms = xperms;
|
||||
} else {
|
||||
free(ops);
|
||||
*operations = NULL;
|
||||
free(xperms);
|
||||
*extended_perms = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
|
||||
void avrule_ioctl_freeranges(struct av_ioctl_range_list *rangelist)
|
||||
{
|
||||
struct av_operations_range_list *r, *tmp;
|
||||
struct av_ioctl_range_list *r, *tmp;
|
||||
r = rangelist;
|
||||
while (r) {
|
||||
tmp = r;
|
||||
@ -2204,12 +2236,12 @@ void avrule_operation_freeranges(struct av_operations_range_list *rangelist)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int operation_for_each_bit(unsigned int *bit, av_operations_t *ops)
|
||||
unsigned int xperms_for_each_bit(unsigned int *bit, av_extended_perms_t *xperms)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = *bit; i < sizeof(ops->perms)*8; i++) {
|
||||
if (operation_perm_test(i,ops->perms)) {
|
||||
operation_perm_clear(i, ops->perms);
|
||||
for (i = *bit; i < sizeof(xperms->perms)*8; i++) {
|
||||
if (xperm_test(i,xperms->perms)) {
|
||||
xperm_clear(i, xperms->perms);
|
||||
*bit = i;
|
||||
return 1;
|
||||
}
|
||||
@ -2236,6 +2268,10 @@ int avrule_cpy(avrule_t *dest, avrule_t *src)
|
||||
}
|
||||
dest->line = src->line;
|
||||
dest->source_filename = strdup(source_file);
|
||||
if (!dest->source_filename) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
}
|
||||
dest->source_line = src->source_line;
|
||||
|
||||
/* increment through the class perms and copy over */
|
||||
@ -2261,14 +2297,75 @@ int avrule_cpy(avrule_t *dest, avrule_t *src)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int define_te_avtab_operation(int which)
|
||||
int define_te_avtab_ioctl(avrule_t *avrule_template)
|
||||
{
|
||||
avrule_t *avrule;
|
||||
struct av_ioctl_range_list *rangelist;
|
||||
av_extended_perms_t *complete_driver, *partial_driver, *xperms;
|
||||
unsigned int i;
|
||||
|
||||
|
||||
/* organize ioctl ranges */
|
||||
if (avrule_ioctl_ranges(&rangelist))
|
||||
return -1;
|
||||
|
||||
/* create rule for ioctl driver types that are entirely enabled */
|
||||
if (avrule_ioctl_completedriver(rangelist, &complete_driver))
|
||||
return -1;
|
||||
if (complete_driver) {
|
||||
avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
|
||||
if (!avrule) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
}
|
||||
if (avrule_cpy(avrule, avrule_template))
|
||||
return -1;
|
||||
avrule->xperms = complete_driver;
|
||||
append_avrule(avrule);
|
||||
}
|
||||
|
||||
/* flag ioctl driver codes that are partially enabled */
|
||||
if (avrule_ioctl_partialdriver(rangelist, complete_driver, &partial_driver))
|
||||
return -1;
|
||||
|
||||
if (!partial_driver || !avrule_xperms_used(partial_driver))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* create rule for each partially used driver codes
|
||||
* "partially used" meaning that the code number e.g. socket 0x89
|
||||
* has some permission bits set and others not set.
|
||||
*/
|
||||
i = 0;
|
||||
while (xperms_for_each_bit(&i, partial_driver)) {
|
||||
if (avrule_ioctl_func(rangelist, &xperms, i))
|
||||
return -1;
|
||||
|
||||
if (xperms) {
|
||||
avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
|
||||
if (!avrule) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
}
|
||||
if (avrule_cpy(avrule, avrule_template))
|
||||
return -1;
|
||||
avrule->xperms = xperms;
|
||||
append_avrule(avrule);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (partial_driver)
|
||||
free(partial_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int define_te_avtab_extended_perms(int which)
|
||||
{
|
||||
char *id;
|
||||
avrule_t *avrule_template;
|
||||
avrule_t *avrule;
|
||||
struct av_operations_range_list *rangelist;
|
||||
av_operations_t *complete_type, *partial_type, *ops;
|
||||
unsigned int i;
|
||||
avrule_t *avrule_template;
|
||||
|
||||
if (pass == 1) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
@ -2279,65 +2376,18 @@ int define_te_avtab_operation(int which)
|
||||
}
|
||||
|
||||
/* populate avrule template with source/target/tclass */
|
||||
if (define_te_avtab_operation_helper(which, &avrule_template))
|
||||
if (define_te_avtab_xperms_helper(which, &avrule_template))
|
||||
return -1;
|
||||
|
||||
/* organize operation ranges */
|
||||
if (avrule_operation_ranges(&rangelist))
|
||||
return -1;
|
||||
|
||||
/* create rule for ioctl operation types that are entirely enabled */
|
||||
if (avrule_operation_completetype(rangelist, &complete_type))
|
||||
return -1;
|
||||
if (complete_type) {
|
||||
avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
|
||||
if (!avrule) {
|
||||
yyerror("out of memory");
|
||||
id = queue_remove(id_queue);
|
||||
if (strcmp(id,"ioctl") == 0) {
|
||||
if (define_te_avtab_ioctl(avrule_template))
|
||||
return -1;
|
||||
}
|
||||
if (avrule_cpy(avrule, avrule_template))
|
||||
return -1;
|
||||
avrule->ops = complete_type;
|
||||
if (which == AVRULE_OPNUM_ALLOWED)
|
||||
avrule->specified = AVRULE_OPTYPE_ALLOWED;
|
||||
else if (which == AVRULE_OPNUM_AUDITALLOW)
|
||||
avrule->specified = AVRULE_OPTYPE_AUDITALLOW;
|
||||
else if (which == AVRULE_OPNUM_DONTAUDIT)
|
||||
avrule->specified = AVRULE_OPTYPE_DONTAUDIT;
|
||||
|
||||
append_avrule(avrule);
|
||||
free(id);
|
||||
} else {
|
||||
yyerror("only ioctl extended permissions are supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* flag ioctl types that are partially enabled */
|
||||
if (avrule_operation_partialtype(rangelist, complete_type, &partial_type))
|
||||
return -1;
|
||||
|
||||
if (!partial_type || !avrule_operation_used(partial_type))
|
||||
goto done;
|
||||
|
||||
/* create rule for each partially enabled type */
|
||||
i = 0;
|
||||
while (operation_for_each_bit(&i, partial_type)) {
|
||||
if (avrule_operation_num(rangelist, &ops, i))
|
||||
return -1;
|
||||
|
||||
if (ops) {
|
||||
avrule = (avrule_t *) calloc(1, sizeof(avrule_t));
|
||||
if (!avrule) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
}
|
||||
if (avrule_cpy(avrule, avrule_template))
|
||||
return -1;
|
||||
avrule->ops = ops;
|
||||
append_avrule(avrule);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (partial_type)
|
||||
free(partial_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2365,7 +2415,7 @@ int define_te_avtab_helper(int which, avrule_t ** rule)
|
||||
avrule->line = policydb_lineno;
|
||||
avrule->source_line = source_lineno;
|
||||
avrule->source_filename = strdup(source_file);
|
||||
avrule->ops = NULL;
|
||||
avrule->xperms = NULL;
|
||||
if (!avrule->source_filename) {
|
||||
yyerror("out of memory");
|
||||
return -1;
|
||||
@ -2745,7 +2795,7 @@ static int dominate_role_recheck(hashtab_key_t key __attribute__ ((unused)),
|
||||
role_datum_t *rdp = (role_datum_t *) arg;
|
||||
role_datum_t *rdatum = (role_datum_t *) datum;
|
||||
ebitmap_node_t *node;
|
||||
int i;
|
||||
uint32_t i;
|
||||
|
||||
/* Don't bother to process against self role */
|
||||
if (rdatum->s.value == rdp->s.value)
|
||||
@ -3291,8 +3341,14 @@ int define_filename_trans(void)
|
||||
append_filename_trans(ftr);
|
||||
|
||||
ftr->name = strdup(name);
|
||||
ftr->stypes = stypes;
|
||||
ftr->ttypes = ttypes;
|
||||
if (type_set_cpy(&ftr->stypes, &stypes)) {
|
||||
yyerror("out of memory");
|
||||
goto bad;
|
||||
}
|
||||
if (type_set_cpy(&ftr->ttypes, &ttypes)) {
|
||||
yyerror("out of memory");
|
||||
goto bad;
|
||||
}
|
||||
ftr->tclass = c + 1;
|
||||
ftr->otype = otype;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ int define_roleattribute(void);
|
||||
int define_filename_trans(void);
|
||||
int define_sens(void);
|
||||
int define_te_avtab(int which);
|
||||
int define_te_avtab_operation(int which);
|
||||
int define_te_avtab_extended_perms(int which);
|
||||
int define_typealias(void);
|
||||
int define_typeattribute(void);
|
||||
int define_typebounds(void);
|
||||
|
@ -126,6 +126,10 @@ typedef int (* require_func_t)(int pass);
|
||||
%token AUDITALLOW
|
||||
%token AUDITDENY
|
||||
%token DONTAUDIT
|
||||
%token ALLOWXPERM
|
||||
%token AUDITALLOWXPERM
|
||||
%token DONTAUDITXPERM
|
||||
%token NEVERALLOWXPERM
|
||||
%token SOURCE
|
||||
%token TARGET
|
||||
%token SAMEUSER
|
||||
@ -457,9 +461,10 @@ te_avtab_def : allow_def
|
||||
| auditdeny_def
|
||||
| dontaudit_def
|
||||
| neverallow_def
|
||||
| operation_allow_def
|
||||
| operation_auditallow_def
|
||||
| operation_dontaudit_def
|
||||
| xperm_allow_def
|
||||
| xperm_auditallow_def
|
||||
| xperm_dontaudit_def
|
||||
| xperm_neverallow_def
|
||||
;
|
||||
allow_def : ALLOW names names ':' names names ';'
|
||||
{if (define_te_avtab(AVRULE_ALLOWED)) return -1; }
|
||||
@ -476,14 +481,17 @@ dontaudit_def : DONTAUDIT names names ':' names names ';'
|
||||
neverallow_def : NEVERALLOW names names ':' names names ';'
|
||||
{if (define_te_avtab(AVRULE_NEVERALLOW)) return -1; }
|
||||
;
|
||||
operation_allow_def : ALLOW names names ':' names operations ';'
|
||||
{if (define_te_avtab_operation(AVRULE_OPNUM_ALLOWED)) return -1; }
|
||||
xperm_allow_def : ALLOWXPERM names names ':' names identifier xperms ';'
|
||||
{if (define_te_avtab_extended_perms(AVRULE_XPERMS_ALLOWED)) return -1; }
|
||||
;
|
||||
operation_auditallow_def: AUDITALLOW names names ':' names operations ';'
|
||||
{if (define_te_avtab_operation(AVRULE_OPNUM_AUDITALLOW)) return -1; }
|
||||
xperm_auditallow_def : AUDITALLOWXPERM names names ':' names identifier xperms ';'
|
||||
{if (define_te_avtab_extended_perms(AVRULE_XPERMS_AUDITALLOW)) return -1; }
|
||||
;
|
||||
operation_dontaudit_def : DONTAUDIT names names ':' names operations ';'
|
||||
{if (define_te_avtab_operation(AVRULE_OPNUM_DONTAUDIT)) return -1; }
|
||||
xperm_dontaudit_def : DONTAUDITXPERM names names ':' names identifier xperms ';'
|
||||
{if (define_te_avtab_extended_perms(AVRULE_XPERMS_DONTAUDIT)) return -1; }
|
||||
;
|
||||
xperm_neverallow_def : NEVERALLOWXPERM names names ':' names identifier xperms ';'
|
||||
{if (define_te_avtab_extended_perms(AVRULE_XPERMS_NEVERALLOW)) return -1; }
|
||||
;
|
||||
attribute_role_def : ATTRIBUTE_ROLE identifier ';'
|
||||
{if (define_attrib_role()) return -1; }
|
||||
@ -749,26 +757,26 @@ genfs_context_def : GENFSCON filesystem path '-' identifier security_context_def
|
||||
ipv4_addr_def : IPV4_ADDR
|
||||
{ if (insert_id(yytext,0)) return -1; }
|
||||
;
|
||||
operations : operation
|
||||
xperms : xperm
|
||||
{ if (insert_separator(0)) return -1; }
|
||||
| nested_operation_set
|
||||
| nested_xperm_set
|
||||
{ if (insert_separator(0)) return -1; }
|
||||
| tilde operation
|
||||
| tilde xperm
|
||||
{ if (insert_id("~", 0)) return -1; }
|
||||
| tilde nested_operation_set
|
||||
| tilde nested_xperm_set
|
||||
{ if (insert_id("~", 0)) return -1;
|
||||
if (insert_separator(0)) return -1; }
|
||||
;
|
||||
nested_operation_set : '{' nested_operation_list '}'
|
||||
nested_xperm_set : '{' nested_xperm_list '}'
|
||||
;
|
||||
nested_operation_list : nested_operation_element
|
||||
| nested_operation_list nested_operation_element
|
||||
nested_xperm_list : nested_xperm_element
|
||||
| nested_xperm_list nested_xperm_element
|
||||
;
|
||||
nested_operation_element: operation '-' { if (insert_id("-", 0)) return -1; } operation
|
||||
| operation
|
||||
| nested_operation_set
|
||||
nested_xperm_element: xperm '-' { if (insert_id("-", 0)) return -1; } xperm
|
||||
| xperm
|
||||
| nested_xperm_set
|
||||
;
|
||||
operation : number
|
||||
xperm : number
|
||||
{ if (insert_id(yytext,0)) return -1; }
|
||||
;
|
||||
security_context_def : identifier ':' identifier ':' identifier opt_mls_range_def
|
||||
|
@ -142,6 +142,14 @@ AUDITDENY |
|
||||
auditdeny { return(AUDITDENY); }
|
||||
DONTAUDIT |
|
||||
dontaudit { return(DONTAUDIT); }
|
||||
ALLOWXPERM |
|
||||
allowxperm { return(ALLOWXPERM); }
|
||||
AUDITALLOWXPERM |
|
||||
auditallowxperm { return(AUDITALLOWXPERM); }
|
||||
DONTAUDITXPERM |
|
||||
dontauditxperm { return(DONTAUDITXPERM); }
|
||||
NEVERALLOWXPERM |
|
||||
neverallowxperm { return(NEVERALLOWXPERM); }
|
||||
SOURCE |
|
||||
source { return(SOURCE); }
|
||||
TARGET |
|
||||
|
@ -54,56 +54,6 @@ int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
|
||||
#define next_bit_in_range(i, p) \
|
||||
((i + 1 < sizeof(p)*8) && operation_perm_test((i + 1), p))
|
||||
|
||||
int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp)
|
||||
{
|
||||
uint16_t value;
|
||||
uint16_t low_bit;
|
||||
uint16_t low_value;
|
||||
unsigned int bit;
|
||||
unsigned int in_range = 0;
|
||||
|
||||
fprintf(fp, "{ ");
|
||||
for (bit = 0; bit < sizeof(ops->perms)*8; bit++) {
|
||||
if (!operation_perm_test(bit, ops->perms))
|
||||
continue;
|
||||
|
||||
if (in_range && next_bit_in_range(bit, ops->perms)) {
|
||||
/* continue until high value found */
|
||||
continue;
|
||||
} else if (next_bit_in_range(bit, ops->perms)) {
|
||||
/* low value */
|
||||
low_bit = bit;
|
||||
in_range = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key->specified & AVTAB_OPNUM) {
|
||||
value = ops->type<<8 | bit;
|
||||
low_value = ops->type<<8 | low_bit;
|
||||
if (in_range)
|
||||
fprintf(fp, "0x%hx-0x%hx ", low_value, value);
|
||||
else
|
||||
fprintf(fp, "0x%hx ", value);
|
||||
} else if (key->specified & AVTAB_OPTYPE) {
|
||||
value = bit << 8;
|
||||
low_value = low_bit << 8;
|
||||
if (in_range)
|
||||
fprintf(fp, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
|
||||
else
|
||||
fprintf(fp, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
|
||||
|
||||
}
|
||||
if (in_range)
|
||||
in_range = 0;
|
||||
}
|
||||
fprintf(fp, "}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int render_type(uint32_t type, policydb_t * p, FILE * fp)
|
||||
{
|
||||
fprintf(fp, "%s", p->p_type_val_to_name[type - 1]);
|
||||
@ -197,16 +147,15 @@ int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
|
||||
render_type(datum->data, p, fp);
|
||||
fprintf(fp, ";\n");
|
||||
}
|
||||
} else if (key->specified & AVTAB_OP) {
|
||||
if (key->specified & (AVTAB_OPNUM_ALLOWED|AVTAB_OPTYPE_ALLOWED))
|
||||
fprintf(fp, "allow ");
|
||||
else if (key->specified & (AVTAB_OPNUM_AUDITALLOW|AVTAB_OPTYPE_AUDITALLOW))
|
||||
fprintf(fp, "auditallow ");
|
||||
else if (key->specified & (AVTAB_OPNUM_DONTAUDIT|AVTAB_OPTYPE_DONTAUDIT))
|
||||
fprintf(fp, "dontaudit ");
|
||||
} else if (key->specified & AVTAB_XPERMS) {
|
||||
if (key->specified & AVTAB_XPERMS_ALLOWED)
|
||||
fprintf(fp, "allowxperm ");
|
||||
else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
|
||||
fprintf(fp, "auditallowxperm ");
|
||||
else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
|
||||
fprintf(fp, "dontauditxperm ");
|
||||
render_key(key, p, fp);
|
||||
render_operations(datum->ops, key, fp);
|
||||
fprintf(fp, ";\n");
|
||||
fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms));
|
||||
} else {
|
||||
fprintf(fp, " ERROR: no valid rule type specified\n");
|
||||
return -1;
|
||||
|
@ -1,3 +1,30 @@
|
||||
* label_file: fix memory leaks and uninitialized jump, from William Roberts.
|
||||
* Replace selabel_digest hash function, from Richard Haines.
|
||||
* Fix selabel_open(3) services if no digest requested, from Richard Haines.
|
||||
* Add selabel_digest function, from Richard Haines.
|
||||
* Fix parallel build with swig python, from Jason Zaman.
|
||||
* Flush the class/perm string mapping cache on policy reload, from Stephen Smalley.
|
||||
* Fix restorecon when path has no context, from Nir Soffer.
|
||||
* Free memory when processing media and x specfiles, from Richard Haines.
|
||||
* Fix mmap memory release for file labeling, from Richard Haines.
|
||||
* Add explicit dependency for pywrap on selinux.py, from Wenzong Fan.
|
||||
* Add policy context validation to sefcontext_compile, from Richard Haines.
|
||||
* Do not treat an empty file_contexts(.local) as an error, from Stephen Smalley.
|
||||
* Fail hard on invalid property_contexts entries, from Stephen Smalley.
|
||||
* Fail hard on invalid file_contexts entries, from Stephen Smalley.
|
||||
* Support context validation on file_contexts.bin, from Stephen Smalley.
|
||||
* Test for file_contexts.bin format by magic number, from Stephen Smalley.
|
||||
* Add selabel_cmp interface and label_file backend, from Stephen Smalley.
|
||||
* Support specifying file_contexts.bin file path, from Stephen Smalley.
|
||||
* Support file_contexts.bin without file_contexts, from Stephen Smalley.
|
||||
* Simplify procattr cache, from Stephen Smalley.
|
||||
* Use /proc/thread-self when available, from Stephen Smalley.
|
||||
* Add const to selinux_opt for label backends, from Richard Haines.
|
||||
* Fix binary file labels for regexes with metachars, from Richard Haines.
|
||||
* Fix file labels for regexes with metachars, from Jeff Vander Stoep.
|
||||
* Fix if file_contexts not '\n' terminated, from Richard Haines.
|
||||
* Enhance file context support, from Richard Haines.
|
||||
* Fix property processing and cleanup formatting, from Richard Haines.
|
||||
* Add read_spec_entries function to replace sscanf, from Richard Haines.
|
||||
* Support consistent mode size for bin files, from Richard Haines.
|
||||
* Expunge remaining references to flask.h and av_permissions.h, from Stephen Smalley.
|
||||
|
@ -49,8 +49,10 @@ struct selabel_handle;
|
||||
#define SELABEL_OPT_PATH 3
|
||||
/* select a subset of the search space as an optimization (file backend) */
|
||||
#define SELABEL_OPT_SUBSET 4
|
||||
/* require a hash calculation on spec files */
|
||||
#define SELABEL_OPT_DIGEST 5
|
||||
/* total number of options */
|
||||
#define SELABEL_NOPT 5
|
||||
#define SELABEL_NOPT 6
|
||||
|
||||
/*
|
||||
* Label operations
|
||||
@ -69,7 +71,8 @@ struct selabel_handle;
|
||||
* @errno set on failure.
|
||||
*/
|
||||
struct selabel_handle *selabel_open(unsigned int backend,
|
||||
struct selinux_opt *opts, unsigned nopts);
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts);
|
||||
|
||||
/**
|
||||
* selabel_close - Close a labeling handle.
|
||||
@ -105,6 +108,43 @@ int selabel_lookup_best_match(struct selabel_handle *rec, char **con,
|
||||
int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
|
||||
const char *key, const char **aliases, int type);
|
||||
|
||||
/**
|
||||
* selabel_digest - Retrieve the SHA1 digest and the list of specfiles used to
|
||||
* generate the digest. The SELABEL_OPT_DIGEST option must
|
||||
* be set in selabel_open() to initiate the digest generation.
|
||||
* @handle: specifies backend instance to query
|
||||
* @digest: returns a pointer to the SHA1 digest.
|
||||
* @digest_len: returns length of digest in bytes.
|
||||
* @specfiles: a list of specfiles used in the SHA1 digest generation.
|
||||
* The list is NULL terminated and will hold @num_specfiles entries.
|
||||
* @num_specfiles: number of specfiles in the list.
|
||||
*
|
||||
* Return %0 on success, -%1 with @errno set on failure.
|
||||
*/
|
||||
int selabel_digest(struct selabel_handle *rec,
|
||||
unsigned char **digest, size_t *digest_len,
|
||||
char ***specfiles, size_t *num_specfiles);
|
||||
|
||||
enum selabel_cmp_result {
|
||||
SELABEL_SUBSET,
|
||||
SELABEL_EQUAL,
|
||||
SELABEL_SUPERSET,
|
||||
SELABEL_INCOMPARABLE
|
||||
};
|
||||
|
||||
/**
|
||||
* selabel_cmp - Compare two label configurations.
|
||||
* @h1: handle for the first label configuration
|
||||
* @h2: handle for the first label configuration
|
||||
*
|
||||
* Compare two label configurations.
|
||||
* Return %SELABEL_SUBSET if @h1 is a subset of @h2, %SELABEL_EQUAL
|
||||
* if @h1 is identical to @h2, %SELABEL_SUPERSET if @h1 is a superset
|
||||
* of @h2, and %SELABEL_INCOMPARABLE if @h1 and @h2 are incomparable.
|
||||
*/
|
||||
enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
|
||||
struct selabel_handle *h2);
|
||||
|
||||
/**
|
||||
* selabel_stats - log labeling operation statistics.
|
||||
* @handle: specifies backend instance to query
|
||||
|
61
libselinux/man/man3/selabel_digest.3
Normal file
61
libselinux/man/man3/selabel_digest.3
Normal file
@ -0,0 +1,61 @@
|
||||
.TH "selabel_digest" "3" "16 Sept 2015" "" "SELinux API documentation"
|
||||
.SH "NAME"
|
||||
selabel_digest \- Return digest of specfiles and list of files used
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
.B #include <selinux/selinux.h>
|
||||
.br
|
||||
.B #include <selinux/label.h>
|
||||
.sp
|
||||
.BI "int selabel_digest(struct selabel_handle *" hnd ,
|
||||
.in +\w'int selabel_digest('u
|
||||
.BI "unsigned char **" digest ,
|
||||
.BI "size_t *" digest_len ,
|
||||
.br
|
||||
.BI "char ***" specfiles,
|
||||
.BI "size_t *" num_specfiles ");"
|
||||
.in
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
.BR selabel_digest ()
|
||||
performs an operation on the handle
|
||||
.IR hnd ,
|
||||
returning the results of the SHA1 digest pointed to by
|
||||
.IR digest ,
|
||||
whose length will be
|
||||
.IR digest_len .
|
||||
The list of specfiles used in the SHA1 digest calculation is returned in
|
||||
.I specfiles
|
||||
with the number of entries in
|
||||
.IR num_specfiles .
|
||||
.sp
|
||||
To enable
|
||||
.BR selabel_digest ()
|
||||
to return this information the
|
||||
.B SELABEL_OPT_DIGEST
|
||||
option must be enable in
|
||||
.BR selabel_open (3).
|
||||
.sp
|
||||
The result of
|
||||
.BR selabel_digest ()
|
||||
must not be used after
|
||||
.BR selabel_close (3).
|
||||
.
|
||||
.SH "RETURN VALUE"
|
||||
On success, zero is returned. On error, \-1 is returned and
|
||||
.I errno
|
||||
is set appropriately.
|
||||
.
|
||||
.SH "ERRORS"
|
||||
.TP
|
||||
.B EINVAL
|
||||
No digest available (returned if
|
||||
.B SELABEL_OPT_DIGEST
|
||||
option not enabled).
|
||||
.TP
|
||||
.B ENOMEM
|
||||
An attempt to allocate memory failed.
|
||||
.
|
||||
.SH "SEE ALSO"
|
||||
.BR selabel_open (3),
|
||||
.BR selinux (8)
|
@ -12,7 +12,7 @@ selabel_open, selabel_close \- userspace SELinux labeling interface
|
||||
.sp
|
||||
.BI "struct selabel_handle *selabel_open(int " backend ,
|
||||
.in +\w'struct selabel_handle *selabel_open('u
|
||||
.BI "struct selinux_opt *" options ,
|
||||
.BI "const struct selinux_opt *" options ,
|
||||
.br
|
||||
.BI "unsigned " nopt ");"
|
||||
.in
|
||||
@ -67,6 +67,11 @@ A non-null value for this option enables context validation. By default,
|
||||
is used; a custom validation function can be provided via
|
||||
.BR selinux_set_callback (3).
|
||||
Note that an invalid context may not be treated as an error unless it is actually encountered during a lookup operation.
|
||||
.TP
|
||||
.B SELABEL_OPT_DIGEST
|
||||
A non-null value for this option enables the generation of an SHA1 digest of
|
||||
the spec files loaded as described in
|
||||
.BR selabel_digest (3)
|
||||
.
|
||||
.SH "BACKENDS"
|
||||
.TP
|
||||
|
@ -1,15 +1,67 @@
|
||||
.TH "sefcontext_compile" "8" "27 Jun 2013" "dwalsh@redhat.com" "SELinux Command Line documentation"
|
||||
.TH "sefcontext_compile" "8" "12 Aug 2015" "dwalsh@redhat.com" "SELinux Command Line documentation"
|
||||
.SH "NAME"
|
||||
sefcontext_compile \- compile file context regular expression files
|
||||
.
|
||||
.SH "SYNOPSIS"
|
||||
.B sefcontext_compile inputfile
|
||||
.B sefcontext_compile
|
||||
.RB [ \-o
|
||||
.IR outputfile ]
|
||||
.RB [ \-p
|
||||
.IR policyfile ]
|
||||
.I inputfile
|
||||
.
|
||||
.SH "DESCRIPTION"
|
||||
sefcontext_compile is used libsemanage to compile file context regular expressions into prce format. sefcontext_compile writes the compiled prce file with the .bin suffix appended "inputfile".bin. This compiled file is used by libselinux file labeling functions.
|
||||
.B sefcontext_compile
|
||||
is used to compile file context regular expressions into
|
||||
.BR prce (3)
|
||||
format.
|
||||
.sp
|
||||
The compiled file is used by libselinux file labeling functions.
|
||||
.sp
|
||||
By default
|
||||
.B sefcontext_compile
|
||||
writes the compiled prce file with the
|
||||
.B .bin
|
||||
suffix appended (e.g. \fIinputfile\fB.bin\fR).
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-o
|
||||
Specify an
|
||||
.I outputfile
|
||||
that must be a fully qualified file name as the
|
||||
.B .bin
|
||||
suffix is not automatically added.
|
||||
.TP
|
||||
.B \-p
|
||||
Specify a binary
|
||||
.I policyfile
|
||||
that will be used to validate the context entries in the
|
||||
.I inputfile
|
||||
.br
|
||||
If an invalid context is found the pcre formatted file will not be written and
|
||||
an error will be returned.
|
||||
|
||||
.SH "EXAMPLE"
|
||||
.SH "RETURN VALUE"
|
||||
On error -1 is returned. On success 0 is returned.
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.B Example 1:
|
||||
.br
|
||||
sefcontext_compile /etc/selinux/targeted/contexts/files/file_contexts
|
||||
.sp
|
||||
Results in the following file being generated:
|
||||
.RS
|
||||
/etc/selinux/targeted/contexts/files/file_contexts.bin
|
||||
.RE
|
||||
.sp
|
||||
.B Example 2:
|
||||
.br
|
||||
sefcontext_compile -o new_fc.bin /etc/selinux/targeted/contexts/files/file_contexts
|
||||
.sp
|
||||
Results in the following file being generated in the cwd:
|
||||
.RS
|
||||
new_fc.bin
|
||||
.RE
|
||||
.
|
||||
.SH AUTHOR
|
||||
Dan Walsh, <dwalsh@redhat.com>
|
||||
|
@ -29,11 +29,12 @@ LIBPC=libselinux.pc
|
||||
SWIGIF= selinuxswig_python.i selinuxswig_python_exception.i
|
||||
SWIGRUBYIF= selinuxswig_ruby.i
|
||||
SWIGCOUT= selinuxswig_wrap.c
|
||||
SWIGPYOUT= selinux.py
|
||||
SWIGRUBYCOUT= selinuxswig_ruby_wrap.c
|
||||
SWIGLOBJ:= $(patsubst %.c,$(PYPREFIX)%.lo,$(SWIGCOUT))
|
||||
SWIGRUBYLOBJ:= $(patsubst %.c,%.lo,$(SWIGRUBYCOUT))
|
||||
SWIGSO=$(PYPREFIX)_selinux.so
|
||||
SWIGFILES=$(SWIGSO) selinux.py
|
||||
SWIGFILES=$(SWIGSO) $(SWIGPYOUT)
|
||||
SWIGRUBYSO=$(RUBYPREFIX)_selinux.so
|
||||
LIBSO=$(TARGET).$(LIBVERSION)
|
||||
AUDIT2WHYLOBJ=$(PYPREFIX)audit2why.lo
|
||||
@ -90,7 +91,7 @@ SWIGRUBY = swig -Wall -ruby -o $(SWIGRUBYCOUT) -outdir ./
|
||||
|
||||
all: $(LIBA) $(LIBSO) $(LIBPC)
|
||||
|
||||
pywrap: all $(SWIGSO) $(AUDIT2WHYSO)
|
||||
pywrap: all $(SWIGFILES) $(AUDIT2WHYSO)
|
||||
|
||||
rubywrap: all $(SWIGRUBYSO)
|
||||
|
||||
@ -135,6 +136,8 @@ $(AUDIT2WHYSO): $(AUDIT2WHYLOBJ)
|
||||
$(SWIGCOUT): $(SWIGIF)
|
||||
$(SWIG) $<
|
||||
|
||||
$(SWIGPYOUT): $(SWIGCOUT)
|
||||
|
||||
$(SWIGRUBYCOUT): $(SWIGRUBYIF)
|
||||
$(SWIGRUBY) $<
|
||||
|
||||
@ -154,7 +157,7 @@ install-pywrap: pywrap
|
||||
test -d $(PYLIBDIR)/site-packages/selinux || install -m 755 -d $(PYLIBDIR)/site-packages/selinux
|
||||
install -m 755 $(SWIGSO) $(PYLIBDIR)/site-packages/selinux/_selinux.so
|
||||
install -m 755 $(AUDIT2WHYSO) $(PYLIBDIR)/site-packages/selinux/audit2why.so
|
||||
install -m 644 selinux.py $(PYLIBDIR)/site-packages/selinux/__init__.py
|
||||
install -m 644 $(SWIGPYOUT) $(PYLIBDIR)/site-packages/selinux/__init__.py
|
||||
|
||||
install-rubywrap: rubywrap
|
||||
test -d $(RUBYINSTALL) || install -m 755 -d $(RUBYINSTALL)
|
||||
|
@ -10,11 +10,26 @@
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
static int selinux_enabled;
|
||||
|
||||
static int avc_reset_callback(uint32_t event __attribute__((unused)),
|
||||
security_id_t ssid __attribute__((unused)),
|
||||
security_id_t tsid __attribute__((unused)),
|
||||
security_class_t tclass __attribute__((unused)),
|
||||
access_vector_t perms __attribute__((unused)),
|
||||
access_vector_t *out_retained __attribute__((unused)))
|
||||
{
|
||||
flush_class_cache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void avc_init_once(void)
|
||||
{
|
||||
selinux_enabled = is_selinux_enabled();
|
||||
if (selinux_enabled == 1)
|
||||
avc_open(NULL, 0);
|
||||
if (selinux_enabled == 1) {
|
||||
if (avc_open(NULL, 0))
|
||||
return;
|
||||
avc_add_callback(avc_reset_callback, AVC_CALLBACK_RESET,
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int selinux_check_access(const char *scon, const char *tcon, const char *class, const char *perm, void *aux) {
|
||||
@ -33,9 +48,11 @@ int selinux_check_access(const char *scon, const char *tcon, const char *class,
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = avc_context_to_sid(tcon, &tcon_id);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = avc_context_to_sid(tcon, &tcon_id);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
(void) avc_netlink_check_nb();
|
||||
|
||||
sclass = string_to_security_class(class);
|
||||
if (sclass == 0) {
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include "callbacks.h"
|
||||
#include "label_internal.h"
|
||||
@ -17,7 +18,8 @@
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
typedef int (*selabel_initfunc)(struct selabel_handle *rec,
|
||||
struct selinux_opt *opts, unsigned nopts);
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts);
|
||||
|
||||
static selabel_initfunc initfuncs[] = {
|
||||
&selabel_file_init,
|
||||
@ -64,15 +66,21 @@ static char *selabel_sub(struct selabel_sub *ptr, const char *src)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list)
|
||||
struct selabel_sub *selabel_subs_init(const char *path,
|
||||
struct selabel_sub *list,
|
||||
struct selabel_digest *digest)
|
||||
{
|
||||
char buf[1024];
|
||||
FILE *cfg = fopen(path, "r");
|
||||
struct selabel_sub *sub;
|
||||
struct selabel_sub *sub = NULL;
|
||||
struct stat sb;
|
||||
|
||||
if (!cfg)
|
||||
return list;
|
||||
|
||||
if (fstat(fileno(cfg), &sb) < 0)
|
||||
return list;
|
||||
|
||||
while (fgets_unlocked(buf, sizeof(buf) - 1, cfg)) {
|
||||
char *ptr = NULL;
|
||||
char *src = buf;
|
||||
@ -114,6 +122,10 @@ struct selabel_sub *selabel_subs_init(const char *path, struct selabel_sub *list
|
||||
sub->next = list;
|
||||
list = sub;
|
||||
}
|
||||
|
||||
if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
|
||||
goto err;
|
||||
|
||||
out:
|
||||
fclose(cfg);
|
||||
return list;
|
||||
@ -124,11 +136,63 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static inline struct selabel_digest *selabel_is_digest_set
|
||||
(const struct selinux_opt *opts,
|
||||
unsigned n,
|
||||
struct selabel_digest *entry)
|
||||
{
|
||||
struct selabel_digest *digest = NULL;
|
||||
|
||||
while (n--) {
|
||||
if (opts[n].type == SELABEL_OPT_DIGEST &&
|
||||
opts[n].value == (char *)1) {
|
||||
digest = calloc(1, sizeof(*digest));
|
||||
if (!digest)
|
||||
goto err;
|
||||
|
||||
digest->digest = calloc(1, DIGEST_SPECFILE_SIZE + 1);
|
||||
if (!digest->digest)
|
||||
goto err;
|
||||
|
||||
digest->specfile_list = calloc(DIGEST_FILES_MAX,
|
||||
sizeof(char *));
|
||||
if (!digest->specfile_list)
|
||||
goto err;
|
||||
|
||||
entry = digest;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
err:
|
||||
free(digest->digest);
|
||||
free(digest->specfile_list);
|
||||
free(digest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void selabel_digest_fini(struct selabel_digest *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
free(ptr->digest);
|
||||
free(ptr->hashbuf);
|
||||
|
||||
if (ptr->specfile_list) {
|
||||
for (i = 0; ptr->specfile_list[i]; i++)
|
||||
free(ptr->specfile_list[i]);
|
||||
free(ptr->specfile_list);
|
||||
}
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Validation functions
|
||||
*/
|
||||
|
||||
static inline int selabel_is_validate_set(struct selinux_opt *opts, unsigned n)
|
||||
static inline int selabel_is_validate_set(const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
while (n--)
|
||||
if (opts[n].type == SELABEL_OPT_VALIDATE)
|
||||
@ -251,7 +315,8 @@ selabel_lookup_bm_common(struct selabel_handle *rec, int translating,
|
||||
*/
|
||||
|
||||
struct selabel_handle *selabel_open(unsigned int backend,
|
||||
struct selinux_opt *opts, unsigned nopts)
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
{
|
||||
struct selabel_handle *rec = NULL;
|
||||
|
||||
@ -270,8 +335,10 @@ struct selabel_handle *selabel_open(unsigned int backend,
|
||||
|
||||
rec->subs = NULL;
|
||||
rec->dist_subs = NULL;
|
||||
rec->digest = selabel_is_digest_set(opts, nopts, rec->digest);
|
||||
|
||||
if ((*initfuncs[backend])(rec, opts, nopts)) {
|
||||
free(rec->spec_file);
|
||||
free(rec);
|
||||
rec = NULL;
|
||||
}
|
||||
@ -366,10 +433,37 @@ int selabel_lookup_best_match_raw(struct selabel_handle *rec, char **con,
|
||||
return *con ? 0 : -1;
|
||||
}
|
||||
|
||||
enum selabel_cmp_result selabel_cmp(struct selabel_handle *h1,
|
||||
struct selabel_handle *h2)
|
||||
{
|
||||
if (!h1->func_cmp || h1->func_cmp != h2->func_cmp)
|
||||
return SELABEL_INCOMPARABLE;
|
||||
|
||||
return h1->func_cmp(h1, h2);
|
||||
}
|
||||
|
||||
int selabel_digest(struct selabel_handle *rec,
|
||||
unsigned char **digest, size_t *digest_len,
|
||||
char ***specfiles, size_t *num_specfiles)
|
||||
{
|
||||
if (!rec->digest) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*digest = rec->digest->digest;
|
||||
*digest_len = DIGEST_SPECFILE_SIZE;
|
||||
*specfiles = rec->digest->specfile_list;
|
||||
*num_specfiles = rec->digest->specfile_cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void selabel_close(struct selabel_handle *rec)
|
||||
{
|
||||
selabel_subs_fini(rec->subs);
|
||||
selabel_subs_fini(rec->dist_subs);
|
||||
if (rec->digest)
|
||||
selabel_digest_fini(rec->digest);
|
||||
rec->func_close(rec);
|
||||
free(rec->spec_file);
|
||||
free(rec);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Property Service contexts backend for labeling Android
|
||||
* Property Service contexts backend for labeling Android
|
||||
* property keys
|
||||
*/
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
/* A property security context specification. */
|
||||
typedef struct spec {
|
||||
struct selabel_lookup_rec lr; /* holds contexts for lookup result */
|
||||
char *property_key; /* property key string */
|
||||
char *property_key; /* property key string */
|
||||
} spec_t;
|
||||
|
||||
/* Our stored configuration */
|
||||
@ -56,21 +56,23 @@ static int nodups_specs(struct saved_data *data, const char *path)
|
||||
for (ii = 0; ii < data->nspec; ii++) {
|
||||
curr_spec = &spec_arr[ii];
|
||||
for (jj = ii + 1; jj < data->nspec; jj++) {
|
||||
if (!strcmp(spec_arr[jj].property_key, curr_spec->property_key)) {
|
||||
if (!strcmp(spec_arr[jj].property_key,
|
||||
curr_spec->property_key)) {
|
||||
rc = -1;
|
||||
errno = EINVAL;
|
||||
if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
|
||||
selinux_log(SELINUX_ERROR,
|
||||
"%s: Multiple different specifications for %s (%s and %s).\n",
|
||||
path,
|
||||
curr_spec->property_key,
|
||||
spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw);
|
||||
if (strcmp(spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw)) {
|
||||
selinux_log
|
||||
(SELINUX_ERROR,
|
||||
"%s: Multiple different specifications for %s (%s and %s).\n",
|
||||
path, curr_spec->property_key,
|
||||
spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw);
|
||||
} else {
|
||||
selinux_log(SELINUX_ERROR,
|
||||
"%s: Multiple same specifications for %s.\n",
|
||||
path,
|
||||
curr_spec->property_key);
|
||||
selinux_log
|
||||
(SELINUX_ERROR,
|
||||
"%s: Multiple same specifications for %s.\n",
|
||||
path, curr_spec->property_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,36 +94,29 @@ static int process_line(struct selabel_handle *rec,
|
||||
if (items <= 0)
|
||||
return items;
|
||||
if (items != 2) {
|
||||
selinux_log(SELINUX_WARNING,
|
||||
"%s: line %u is missing fields, skipping\n", path,
|
||||
selinux_log(SELINUX_ERROR,
|
||||
"%s: line %u is missing fields\n", path,
|
||||
lineno);
|
||||
return 0;
|
||||
free(prop);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pass == 1) {
|
||||
if (pass == 0) {
|
||||
free(prop);
|
||||
free(context);
|
||||
} else if (pass == 1) {
|
||||
/* On the second pass, process and store the specification in spec. */
|
||||
spec_arr[nspec].property_key = strdup(prop);
|
||||
if (!spec_arr[nspec].property_key) {
|
||||
selinux_log(SELINUX_WARNING,
|
||||
"%s: out of memory at line %u on prop %s\n",
|
||||
path, lineno, prop);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
spec_arr[nspec].lr.ctx_raw = strdup(context);
|
||||
if (!spec_arr[nspec].lr.ctx_raw) {
|
||||
selinux_log(SELINUX_WARNING,
|
||||
"%s: out of memory at line %u on context %s\n",
|
||||
path, lineno, context);
|
||||
return -1;
|
||||
}
|
||||
spec_arr[nspec].property_key = prop;
|
||||
spec_arr[nspec].lr.ctx_raw = context;
|
||||
|
||||
if (rec->validating) {
|
||||
if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
|
||||
selinux_log(SELINUX_WARNING,
|
||||
selinux_log(SELINUX_ERROR,
|
||||
"%s: line %u has invalid context %s\n",
|
||||
path, lineno, spec_arr[nspec].lr.ctx_raw);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,7 +125,7 @@ static int process_line(struct selabel_handle *rec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
@ -149,7 +144,7 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path)
|
||||
if (!path)
|
||||
return -1;
|
||||
|
||||
/* Open the specification file. */
|
||||
@ -164,17 +159,18 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
|
||||
/*
|
||||
* Two passes of the specification file. First is to get the size.
|
||||
* After the first pass, the spec array is malloced to the appropriate
|
||||
* size. Second pass is to populate the spec array and check for
|
||||
* After the first pass, the spec array is malloced to the appropriate
|
||||
* size. Second pass is to populate the spec array and check for
|
||||
* dups.
|
||||
*/
|
||||
maxnspec = UINT_MAX / sizeof(spec_t);
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
data->nspec = 0;
|
||||
|
||||
while (fgets(line_buf, sizeof line_buf - 1, fp)
|
||||
while (fgets(line_buf, sizeof(line_buf) - 1, fp)
|
||||
&& data->nspec < maxnspec) {
|
||||
if (process_line(rec, path, line_buf, pass, ++lineno) != 0)
|
||||
if (process_line(rec, path, line_buf, pass, ++lineno)
|
||||
!= 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -186,7 +182,6 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
}
|
||||
|
||||
if (pass == 0) {
|
||||
|
||||
if (data->nspec == 0) {
|
||||
status = 0;
|
||||
goto finish;
|
||||
@ -204,7 +199,12 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
|
||||
qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
|
||||
|
||||
status = 0;
|
||||
status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
digest_gen_hash(rec->digest);
|
||||
|
||||
finish:
|
||||
fclose(fp);
|
||||
return status;
|
||||
@ -234,7 +234,7 @@ static void closef(struct selabel_handle *rec)
|
||||
|
||||
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
||||
const char *key,
|
||||
int __attribute__ ((unused)) type)
|
||||
int __attribute__((unused)) type)
|
||||
{
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
spec_t *spec_arr = data->spec_arr;
|
||||
@ -267,12 +267,13 @@ finish:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stats(struct selabel_handle __attribute__ ((unused)) * rec)
|
||||
static void stats(struct selabel_handle __attribute__((unused)) *rec)
|
||||
{
|
||||
selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
|
||||
}
|
||||
|
||||
int selabel_property_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
int selabel_property_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
{
|
||||
struct saved_data *data;
|
||||
|
@ -234,7 +234,8 @@ db_stats(struct selabel_handle *rec)
|
||||
* selabel_open() handler
|
||||
*/
|
||||
static catalog_t *
|
||||
db_init(struct selinux_opt *opts, unsigned nopts, struct selabel_handle *rec)
|
||||
db_init(const struct selinux_opt *opts, unsigned nopts,
|
||||
struct selabel_handle *rec)
|
||||
{
|
||||
catalog_t *catalog;
|
||||
FILE *filp;
|
||||
@ -243,6 +244,7 @@ db_init(struct selinux_opt *opts, unsigned nopts, struct selabel_handle *rec)
|
||||
size_t line_len = 0;
|
||||
unsigned int line_num = 0;
|
||||
unsigned int i;
|
||||
struct stat sb;
|
||||
|
||||
/*
|
||||
* Initialize catalog data structure
|
||||
@ -279,6 +281,12 @@ db_init(struct selinux_opt *opts, unsigned nopts, struct selabel_handle *rec)
|
||||
free(catalog);
|
||||
return NULL;
|
||||
}
|
||||
if (fstat(fileno(filp), &sb) < 0)
|
||||
return NULL;
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
rec->spec_file = strdup(path);
|
||||
|
||||
/*
|
||||
@ -311,6 +319,11 @@ db_init(struct selinux_opt *opts, unsigned nopts, struct selabel_handle *rec)
|
||||
}
|
||||
free(line_buf);
|
||||
|
||||
if (digest_add_specfile(rec->digest, filp, NULL, sb.st_size, path) < 0)
|
||||
goto out_error;
|
||||
|
||||
digest_gen_hash(rec->digest);
|
||||
|
||||
fclose(filp);
|
||||
|
||||
return catalog;
|
||||
@ -332,7 +345,7 @@ out_error:
|
||||
* Initialize selabel_handle and load the entries of specfile
|
||||
*/
|
||||
int selabel_db_init(struct selabel_handle *rec,
|
||||
struct selinux_opt *opts, unsigned nopts)
|
||||
const struct selinux_opt *opts, unsigned nopts)
|
||||
{
|
||||
rec->func_close = &db_close;
|
||||
rec->func_lookup = &db_lookup;
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Author : Stephen Smalley <sds@tycho.nsa.gov>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
@ -15,13 +16,11 @@
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <pcre.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "callbacks.h"
|
||||
#include "label_internal.h"
|
||||
#include "label_file.h"
|
||||
@ -72,12 +71,14 @@ static int nodups_specs(struct saved_data *data, const char *path)
|
||||
for (ii = 0; ii < data->nspec; ii++) {
|
||||
curr_spec = &spec_arr[ii];
|
||||
for (jj = ii + 1; jj < data->nspec; jj++) {
|
||||
if ((!strcmp(spec_arr[jj].regex_str, curr_spec->regex_str))
|
||||
if ((!strcmp(spec_arr[jj].regex_str,
|
||||
curr_spec->regex_str))
|
||||
&& (!spec_arr[jj].mode || !curr_spec->mode
|
||||
|| spec_arr[jj].mode == curr_spec->mode)) {
|
||||
rc = -1;
|
||||
errno = EINVAL;
|
||||
if (strcmp(spec_arr[jj].lr.ctx_raw, curr_spec->lr.ctx_raw)) {
|
||||
if (strcmp(spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw)) {
|
||||
COMPAT_LOG
|
||||
(SELINUX_ERROR,
|
||||
"%s: Multiple different specifications for %s (%s and %s).\n",
|
||||
@ -96,136 +97,9 @@ static int nodups_specs(struct saved_data *data, const char *path)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int compile_regex(struct saved_data *data, struct spec *spec, const char **errbuf)
|
||||
{
|
||||
const char *tmperrbuf;
|
||||
char *reg_buf, *anchored_regex, *cp;
|
||||
struct stem *stem_arr = data->stem_arr;
|
||||
size_t len;
|
||||
int erroff;
|
||||
|
||||
if (spec->regcomp)
|
||||
return 0; /* already done */
|
||||
|
||||
/* Skip the fixed stem. */
|
||||
reg_buf = spec->regex_str;
|
||||
if (spec->stem_id >= 0)
|
||||
reg_buf += stem_arr[spec->stem_id].len;
|
||||
|
||||
/* Anchor the regular expression. */
|
||||
len = strlen(reg_buf);
|
||||
cp = anchored_regex = malloc(len + 3);
|
||||
if (!anchored_regex)
|
||||
return -1;
|
||||
|
||||
/* Create ^...$ regexp. */
|
||||
*cp++ = '^';
|
||||
cp = mempcpy(cp, reg_buf, len);
|
||||
*cp++ = '$';
|
||||
*cp = '\0';
|
||||
|
||||
/* Compile the regular expression. */
|
||||
spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf, &erroff, NULL);
|
||||
free(anchored_regex);
|
||||
if (!spec->regex) {
|
||||
if (errbuf)
|
||||
*errbuf=tmperrbuf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
|
||||
if (!spec->sd && tmperrbuf) {
|
||||
if (errbuf)
|
||||
*errbuf=tmperrbuf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Done. */
|
||||
spec->regcomp = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_line(struct selabel_handle *rec,
|
||||
const char *path, const char *prefix,
|
||||
char *line_buf, unsigned lineno)
|
||||
{
|
||||
int items, len, rc;
|
||||
char *regex = NULL, *type = NULL, *context = NULL;
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
struct spec *spec_arr;
|
||||
unsigned int nspec = data->nspec;
|
||||
const char *errbuf = NULL;
|
||||
|
||||
items = read_spec_entries(line_buf, 3, ®ex, &type, &context);
|
||||
if (items <= 0)
|
||||
return items;
|
||||
|
||||
if (items < 2) {
|
||||
COMPAT_LOG(SELINUX_WARNING,
|
||||
"%s: line %u is missing fields, skipping\n", path,
|
||||
lineno);
|
||||
if (items == 1)
|
||||
free(regex);
|
||||
return 0;
|
||||
} else if (items == 2) {
|
||||
/* The type field is optional. */
|
||||
free(context);
|
||||
context = type;
|
||||
type = 0;
|
||||
}
|
||||
|
||||
len = get_stem_from_spec(regex);
|
||||
if (len && prefix && strncmp(prefix, regex, len)) {
|
||||
/* Stem of regex does not match requested prefix, discard. */
|
||||
free(regex);
|
||||
free(type);
|
||||
free(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = grow_specs(data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
spec_arr = data->spec_arr;
|
||||
|
||||
/* process and store the specification in spec. */
|
||||
spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
|
||||
spec_arr[nspec].regex_str = regex;
|
||||
if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
|
||||
COMPAT_LOG(SELINUX_WARNING, "%s: line %u has invalid regex %s: %s\n",
|
||||
path, lineno, regex, (errbuf ? errbuf : "out of memory"));
|
||||
}
|
||||
|
||||
/* Convert the type string to a mode format */
|
||||
spec_arr[nspec].type_str = type;
|
||||
spec_arr[nspec].mode = 0;
|
||||
if (type) {
|
||||
mode_t mode = string_to_mode(type);
|
||||
if (mode == (mode_t)-1) {
|
||||
COMPAT_LOG(SELINUX_WARNING, "%s: line %u has invalid file type %s\n",
|
||||
path, lineno, type);
|
||||
mode = 0;
|
||||
}
|
||||
spec_arr[nspec].mode = mode;
|
||||
}
|
||||
|
||||
spec_arr[nspec].lr.ctx_raw = context;
|
||||
|
||||
/* Determine if specification has
|
||||
* any meta characters in the RE */
|
||||
spec_hasMetaChars(&spec_arr[nspec]);
|
||||
|
||||
if (strcmp(context, "<<none>>") && rec->validating)
|
||||
compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
|
||||
|
||||
data->nspec = ++nspec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *sb)
|
||||
static int load_mmap(struct selabel_handle *rec, const char *path,
|
||||
struct stat *sb, bool isbinary,
|
||||
struct selabel_digest *digest)
|
||||
{
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
char mmap_path[PATH_MAX + 1];
|
||||
@ -239,9 +113,16 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
uint32_t i, magic, version;
|
||||
uint32_t entry_len, stem_map_len, regex_array_len;
|
||||
|
||||
rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path);
|
||||
if (rc >= (int)sizeof(mmap_path))
|
||||
return -1;
|
||||
if (isbinary) {
|
||||
len = strlen(path);
|
||||
if (len >= sizeof(mmap_path))
|
||||
return -1;
|
||||
strcpy(mmap_path, path);
|
||||
} else {
|
||||
rc = snprintf(mmap_path, sizeof(mmap_path), "%s.bin", path);
|
||||
if (rc >= (int)sizeof(mmap_path))
|
||||
return -1;
|
||||
}
|
||||
|
||||
mmapfd = open(mmap_path, O_RDONLY | O_CLOEXEC);
|
||||
if (mmapfd < 0)
|
||||
@ -259,12 +140,6 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mmap_stat.st_mtime == sb->st_mtime &&
|
||||
mmap_stat.st_mtim.tv_nsec < sb->st_mtim.tv_nsec) {
|
||||
close(mmapfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ok, read it in... */
|
||||
len = mmap_stat.st_size;
|
||||
len += (sysconf(_SC_PAGE_SIZE) - 1);
|
||||
@ -285,8 +160,8 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
}
|
||||
|
||||
/* save where we mmap'd the file to cleanup on close() */
|
||||
mmap_area->addr = addr;
|
||||
mmap_area->len = len;
|
||||
mmap_area->addr = mmap_area->next_addr = addr;
|
||||
mmap_area->len = mmap_area->next_len = len;
|
||||
mmap_area->next = data->mmap_areas;
|
||||
data->mmap_areas = mmap_area;
|
||||
|
||||
@ -357,7 +232,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
|
||||
/* Check for stem_len wrap around. */
|
||||
if (stem_len < UINT32_MAX) {
|
||||
buf = (char *)mmap_area->addr;
|
||||
buf = (char *)mmap_area->next_addr;
|
||||
/* Check if over-run before null check. */
|
||||
rc = next_entry(NULL, mmap_area, (stem_len + 1));
|
||||
if (rc < 0)
|
||||
@ -395,7 +270,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
for (i = 0; i < regex_array_len; i++) {
|
||||
struct spec *spec;
|
||||
int32_t stem_id, meta_chars;
|
||||
uint32_t mode = 0;
|
||||
uint32_t mode = 0, prefix_len = 0;
|
||||
|
||||
rc = grow_specs(data);
|
||||
if (rc < 0)
|
||||
@ -428,6 +303,14 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
}
|
||||
spec->lr.ctx_raw = str_buf;
|
||||
|
||||
if (strcmp(spec->lr.ctx_raw, "<<none>>") && rec->validating) {
|
||||
if (selabel_validate(rec, &spec->lr) < 0) {
|
||||
selinux_log(SELINUX_ERROR,
|
||||
"%s: context %s is invalid\n", mmap_path, spec->lr.ctx_raw);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process regex string */
|
||||
rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
|
||||
if (rc < 0 || !entry_len) {
|
||||
@ -435,7 +318,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
goto err;
|
||||
}
|
||||
|
||||
spec->regex_str = (char *)mmap_area->addr;
|
||||
spec->regex_str = (char *)mmap_area->next_addr;
|
||||
rc = next_entry(NULL, mmap_area, entry_len);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
@ -460,7 +343,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
if (stem_id < 0 || stem_id >= stem_map_len)
|
||||
if (stem_id < 0 || stem_id >= (int32_t)stem_map_len)
|
||||
spec->stem_id = -1;
|
||||
else
|
||||
spec->stem_id = stem_map[stem_id];
|
||||
@ -471,6 +354,15 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
goto err;
|
||||
|
||||
spec->hasMetaChars = meta_chars;
|
||||
/* and prefix length for use by selabel_lookup_best_match */
|
||||
if (version >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN) {
|
||||
rc = next_entry(&prefix_len, mmap_area,
|
||||
sizeof(uint32_t));
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
spec->prefix_len = prefix_len;
|
||||
}
|
||||
|
||||
/* Process regex and study_data entries */
|
||||
rc = next_entry(&entry_len, mmap_area, sizeof(uint32_t));
|
||||
@ -478,7 +370,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
rc = -1;
|
||||
goto err;
|
||||
}
|
||||
spec->regex = (pcre *)mmap_area->addr;
|
||||
spec->regex = (pcre *)mmap_area->next_addr;
|
||||
rc = next_entry(NULL, mmap_area, entry_len);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
@ -496,7 +388,7 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
rc = -1;
|
||||
goto err;
|
||||
}
|
||||
spec->lsd.study_data = (void *)mmap_area->addr;
|
||||
spec->lsd.study_data = (void *)mmap_area->next_addr;
|
||||
spec->lsd.flags |= PCRE_EXTRA_STUDY_DATA;
|
||||
rc = next_entry(NULL, mmap_area, entry_len);
|
||||
if (rc < 0)
|
||||
@ -512,27 +404,36 @@ static int load_mmap(struct selabel_handle *rec, const char *path, struct stat *
|
||||
|
||||
data->nspec++;
|
||||
}
|
||||
/* win */
|
||||
rc = 0;
|
||||
|
||||
rc = digest_add_specfile(digest, NULL, addr, mmap_stat.st_size,
|
||||
mmap_path);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
err:
|
||||
free(stem_map);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int process_file(const char *path, const char *suffix, struct selabel_handle *rec, const char *prefix)
|
||||
static int process_file(const char *path, const char *suffix,
|
||||
struct selabel_handle *rec,
|
||||
const char *prefix, struct selabel_digest *digest)
|
||||
{
|
||||
FILE *fp;
|
||||
struct stat sb;
|
||||
unsigned int lineno;
|
||||
size_t line_len;
|
||||
size_t line_len = 0;
|
||||
char *line_buf = NULL;
|
||||
int rc;
|
||||
char stack_path[PATH_MAX + 1];
|
||||
bool isbinary = false;
|
||||
uint32_t magic;
|
||||
|
||||
/* append the path suffix if we have one */
|
||||
if (suffix) {
|
||||
rc = snprintf(stack_path, sizeof(stack_path), "%s.%s", path, suffix);
|
||||
rc = snprintf(stack_path, sizeof(stack_path),
|
||||
"%s.%s", path, suffix);
|
||||
if (rc >= (int)sizeof(stack_path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
@ -541,38 +442,74 @@ static int process_file(const char *path, const char *suffix, struct selabel_han
|
||||
}
|
||||
|
||||
/* Open the specification file. */
|
||||
if ((fp = fopen(path, "r")) == NULL)
|
||||
return -1;
|
||||
__fsetlocking(fp, FSETLOCKING_BYCALLER);
|
||||
fp = fopen(path, "r");
|
||||
if (fp) {
|
||||
__fsetlocking(fp, FSETLOCKING_BYCALLER);
|
||||
|
||||
if (fstat(fileno(fp), &sb) < 0)
|
||||
return -1;
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
if (fstat(fileno(fp), &sb) < 0)
|
||||
return -1;
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
magic = 0;
|
||||
if (fread(&magic, sizeof magic, 1, fp) != 1) {
|
||||
if (ferror(fp)) {
|
||||
errno = EINVAL;
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
clearerr(fp);
|
||||
}
|
||||
|
||||
if (magic == SELINUX_MAGIC_COMPILED_FCONTEXT) {
|
||||
/* file_contexts.bin format */
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
isbinary = true;
|
||||
} else {
|
||||
rewind(fp);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Text file does not exist, so clear the timestamp
|
||||
* so that we will always pass the timestamp comparison
|
||||
* with the bin file in load_mmap().
|
||||
*/
|
||||
sb.st_mtime = 0;
|
||||
}
|
||||
|
||||
rc = load_mmap(rec, path, &sb);
|
||||
rc = load_mmap(rec, path, &sb, isbinary, digest);
|
||||
if (rc == 0)
|
||||
goto out;
|
||||
|
||||
if (!fp)
|
||||
return -1; /* no text or bin file */
|
||||
|
||||
/*
|
||||
* The do detailed validation of the input and fill the spec array
|
||||
* Then do detailed validation of the input and fill the spec array
|
||||
*/
|
||||
lineno = 0;
|
||||
rc = 0;
|
||||
while (getline(&line_buf, &line_len, fp) > 0) {
|
||||
rc = process_line(rec, path, prefix, line_buf, ++lineno);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = digest_add_specfile(digest, fp, NULL, sb.st_size, path);
|
||||
|
||||
out:
|
||||
free(line_buf);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
static void closef(struct selabel_handle *rec);
|
||||
|
||||
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
@ -597,22 +534,27 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
|
||||
/* Process local and distribution substitution files */
|
||||
if (!path) {
|
||||
rec->dist_subs = selabel_subs_init(selinux_file_context_subs_dist_path(), rec->dist_subs);
|
||||
rec->subs = selabel_subs_init(selinux_file_context_subs_path(), rec->subs);
|
||||
rec->dist_subs =
|
||||
selabel_subs_init(selinux_file_context_subs_dist_path(),
|
||||
rec->dist_subs, rec->digest);
|
||||
rec->subs = selabel_subs_init(selinux_file_context_subs_path(),
|
||||
rec->subs, rec->digest);
|
||||
path = selinux_file_context_path();
|
||||
} else {
|
||||
snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path);
|
||||
rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs);
|
||||
rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs,
|
||||
rec->digest);
|
||||
snprintf(subs_file, sizeof(subs_file), "%s.subs", path);
|
||||
rec->subs = selabel_subs_init(subs_file, rec->subs);
|
||||
rec->subs = selabel_subs_init(subs_file, rec->subs,
|
||||
rec->digest);
|
||||
}
|
||||
|
||||
rec->spec_file = strdup(path);
|
||||
|
||||
/*
|
||||
/*
|
||||
* The do detailed validation of the input and fill the spec array
|
||||
*/
|
||||
status = process_file(path, NULL, rec, prefix);
|
||||
status = process_file(path, NULL, rec, prefix, rec->digest);
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
@ -623,21 +565,25 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
}
|
||||
|
||||
if (!baseonly) {
|
||||
status = process_file(path, "homedirs", rec, prefix);
|
||||
status = process_file(path, "homedirs", rec, prefix,
|
||||
rec->digest);
|
||||
if (status && errno != ENOENT)
|
||||
goto finish;
|
||||
|
||||
status = process_file(path, "local", rec, prefix);
|
||||
status = process_file(path, "local", rec, prefix,
|
||||
rec->digest);
|
||||
if (status && errno != ENOENT)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
digest_gen_hash(rec->digest);
|
||||
|
||||
status = sort_specs(data);
|
||||
|
||||
status = 0;
|
||||
finish:
|
||||
if (status)
|
||||
free(data->spec_arr);
|
||||
closef(rec);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -731,7 +677,7 @@ static struct spec *lookup_common(struct selabel_handle *rec,
|
||||
if (partial)
|
||||
pcre_options |= PCRE_PARTIAL_SOFT;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Check for matching specifications in reverse order, so that
|
||||
* the last matching specification is used.
|
||||
*/
|
||||
@ -857,6 +803,96 @@ out:
|
||||
return lr;
|
||||
}
|
||||
|
||||
static enum selabel_cmp_result incomp(struct spec *spec1, struct spec *spec2, const char *reason, int i, int j)
|
||||
{
|
||||
selinux_log(SELINUX_INFO,
|
||||
"selabel_cmp: mismatched %s on entry %d: (%s, %x, %s) vs entry %d: (%s, %x, %s)\n",
|
||||
reason,
|
||||
i, spec1->regex_str, spec1->mode, spec1->lr.ctx_raw,
|
||||
j, spec2->regex_str, spec2->mode, spec2->lr.ctx_raw);
|
||||
return SELABEL_INCOMPARABLE;
|
||||
}
|
||||
|
||||
static enum selabel_cmp_result cmp(struct selabel_handle *h1,
|
||||
struct selabel_handle *h2)
|
||||
{
|
||||
struct saved_data *data1 = (struct saved_data *)h1->data;
|
||||
struct saved_data *data2 = (struct saved_data *)h2->data;
|
||||
unsigned int i, nspec1 = data1->nspec, j, nspec2 = data2->nspec;
|
||||
struct spec *spec_arr1 = data1->spec_arr, *spec_arr2 = data2->spec_arr;
|
||||
struct stem *stem_arr1 = data1->stem_arr, *stem_arr2 = data2->stem_arr;
|
||||
bool skipped1 = false, skipped2 = false;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
while (i < nspec1 && j < nspec2) {
|
||||
struct spec *spec1 = &spec_arr1[i];
|
||||
struct spec *spec2 = &spec_arr2[j];
|
||||
|
||||
/*
|
||||
* Because sort_specs() moves exact pathnames to the
|
||||
* end, we might need to skip over additional regex
|
||||
* entries that only exist in one of the configurations.
|
||||
*/
|
||||
if (!spec1->hasMetaChars && spec2->hasMetaChars) {
|
||||
j++;
|
||||
skipped2 = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spec1->hasMetaChars && !spec2->hasMetaChars) {
|
||||
i++;
|
||||
skipped1 = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spec1->regcomp && spec2->regcomp) {
|
||||
size_t len1, len2;
|
||||
int rc;
|
||||
|
||||
rc = pcre_fullinfo(spec1->regex, NULL, PCRE_INFO_SIZE, &len1);
|
||||
assert(rc == 0);
|
||||
rc = pcre_fullinfo(spec2->regex, NULL, PCRE_INFO_SIZE, &len2);
|
||||
assert(rc == 0);
|
||||
if (len1 != len2 ||
|
||||
memcmp(spec1->regex, spec2->regex, len1))
|
||||
return incomp(spec1, spec2, "regex", i, j);
|
||||
} else {
|
||||
if (strcmp(spec1->regex_str, spec2->regex_str))
|
||||
return incomp(spec1, spec2, "regex_str", i, j);
|
||||
}
|
||||
|
||||
if (spec1->mode != spec2->mode)
|
||||
return incomp(spec1, spec2, "mode", i, j);
|
||||
|
||||
if (spec1->stem_id == -1 && spec2->stem_id != -1)
|
||||
return incomp(spec1, spec2, "stem_id", i, j);
|
||||
if (spec2->stem_id == -1 && spec1->stem_id != -1)
|
||||
return incomp(spec1, spec2, "stem_id", i, j);
|
||||
if (spec1->stem_id != -1 && spec2->stem_id != -1) {
|
||||
struct stem *stem1 = &stem_arr1[spec1->stem_id];
|
||||
struct stem *stem2 = &stem_arr2[spec2->stem_id];
|
||||
if (stem1->len != stem2->len ||
|
||||
strncmp(stem1->buf, stem2->buf, stem1->len))
|
||||
return incomp(spec1, spec2, "stem", i, j);
|
||||
}
|
||||
|
||||
if (strcmp(spec1->lr.ctx_raw, spec2->lr.ctx_raw))
|
||||
return incomp(spec1, spec2, "ctx_raw", i, j);
|
||||
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if ((skipped1 || i < nspec1) && !skipped2)
|
||||
return SELABEL_SUPERSET;
|
||||
if ((skipped2 || j < nspec2) && !skipped1)
|
||||
return SELABEL_SUBSET;
|
||||
if (skipped1 && skipped2)
|
||||
return SELABEL_INCOMPARABLE;
|
||||
return SELABEL_EQUAL;
|
||||
}
|
||||
|
||||
|
||||
static void stats(struct selabel_handle *rec)
|
||||
{
|
||||
@ -882,8 +918,9 @@ static void stats(struct selabel_handle *rec)
|
||||
}
|
||||
}
|
||||
|
||||
int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
int selabel_file_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
{
|
||||
struct saved_data *data;
|
||||
|
||||
@ -898,6 +935,7 @@ int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
rec->func_lookup = &lookup;
|
||||
rec->func_partial_match = &partial_match;
|
||||
rec->func_lookup_best_match = &lookup_best_match;
|
||||
rec->func_cmp = &cmp;
|
||||
|
||||
return init(rec, opts, nopts);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "callbacks.h"
|
||||
#include "label_internal.h"
|
||||
|
||||
#define SELINUX_MAGIC_COMPILED_FCONTEXT 0xf97cff8a
|
||||
@ -11,10 +12,11 @@
|
||||
#define SELINUX_COMPILED_FCONTEXT_NOPCRE_VERS 1
|
||||
#define SELINUX_COMPILED_FCONTEXT_PCRE_VERS 2
|
||||
#define SELINUX_COMPILED_FCONTEXT_MODE 3
|
||||
#define SELINUX_COMPILED_FCONTEXT_PREFIX_LEN 4
|
||||
|
||||
#define SELINUX_COMPILED_FCONTEXT_MAX_VERS SELINUX_COMPILED_FCONTEXT_MODE
|
||||
#define SELINUX_COMPILED_FCONTEXT_MAX_VERS SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
|
||||
|
||||
/* Prior to verison 8.20, libpcre did not have pcre_free_study() */
|
||||
/* Prior to version 8.20, libpcre did not have pcre_free_study() */
|
||||
#if (PCRE_MAJOR < 8 || (PCRE_MAJOR == 8 && PCRE_MINOR < 20))
|
||||
#define pcre_free_study pcre_free
|
||||
#endif
|
||||
@ -47,8 +49,10 @@ struct stem {
|
||||
|
||||
/* Where we map the file in during selabel_open() */
|
||||
struct mmap_area {
|
||||
void *addr; /* Start of area - gets incremented by next_entry() */
|
||||
size_t len; /* Length - gets decremented by next_entry() */
|
||||
void *addr; /* Start addr + len used to release memory at close */
|
||||
size_t len;
|
||||
void *next_addr; /* Incremented by next_entry() */
|
||||
size_t next_len; /* Decremented by next_entry() */
|
||||
struct mmap_area *next;
|
||||
};
|
||||
|
||||
@ -147,6 +151,7 @@ static inline void spec_hasMetaChars(struct spec *spec)
|
||||
end = c + len;
|
||||
|
||||
spec->hasMetaChars = 0;
|
||||
spec->prefix_len = len;
|
||||
|
||||
/* Look at each character in the RE specification string for a
|
||||
* meta character. Return when any meta character reached. */
|
||||
@ -163,6 +168,7 @@ static inline void spec_hasMetaChars(struct spec *spec)
|
||||
case '(':
|
||||
case '{':
|
||||
spec->hasMetaChars = 1;
|
||||
spec->prefix_len = c - spec->regex_str;
|
||||
return;
|
||||
case '\\': /* skip the next character */
|
||||
c++;
|
||||
@ -173,7 +179,6 @@ static inline void spec_hasMetaChars(struct spec *spec)
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move exact pathname specifications to the end. */
|
||||
@ -200,9 +205,9 @@ static inline int sort_specs(struct saved_data *data)
|
||||
}
|
||||
|
||||
/*
|
||||
* now the exact pathnames are at the end, but they are in the reverse order.
|
||||
* since 'front' is now the first of the 'exact' we can run that part of the
|
||||
* array switching the front and back element.
|
||||
* now the exact pathnames are at the end, but they are in the reverse
|
||||
* order. Since 'front' is now the first of the 'exact' we can run
|
||||
* that part of the array switching the front and back element.
|
||||
*/
|
||||
back = data->nspec - 1;
|
||||
while (front < back) {
|
||||
@ -242,7 +247,8 @@ static inline int get_stem_from_spec(const char *const buf)
|
||||
/*
|
||||
* return the stemid given a string and a length
|
||||
*/
|
||||
static inline int find_stem(struct saved_data *data, const char *buf, int stem_len)
|
||||
static inline int find_stem(struct saved_data *data, const char *buf,
|
||||
int stem_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -272,6 +278,7 @@ static inline int store_stem(struct saved_data *data, char *buf, int stem_len)
|
||||
}
|
||||
data->stem_arr[num].len = stem_len;
|
||||
data->stem_arr[num].buf = buf;
|
||||
data->stem_arr[num].from_mmap = 0;
|
||||
data->num_stems++;
|
||||
|
||||
return num;
|
||||
@ -306,14 +313,161 @@ static inline int find_stem_from_spec(struct saved_data *data, const char *buf)
|
||||
* current buffer). */
|
||||
static inline int next_entry(void *buf, struct mmap_area *fp, size_t bytes)
|
||||
{
|
||||
if (bytes > fp->len)
|
||||
if (bytes > fp->next_len)
|
||||
return -1;
|
||||
|
||||
if (buf)
|
||||
memcpy(buf, fp->addr, bytes);
|
||||
memcpy(buf, fp->next_addr, bytes);
|
||||
|
||||
fp->next_addr = (char *)fp->next_addr + bytes;
|
||||
fp->next_len -= bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int compile_regex(struct saved_data *data, struct spec *spec,
|
||||
const char **errbuf)
|
||||
{
|
||||
const char *tmperrbuf;
|
||||
char *reg_buf, *anchored_regex, *cp;
|
||||
struct stem *stem_arr = data->stem_arr;
|
||||
size_t len;
|
||||
int erroff;
|
||||
|
||||
if (spec->regcomp)
|
||||
return 0; /* already done */
|
||||
|
||||
/* Skip the fixed stem. */
|
||||
reg_buf = spec->regex_str;
|
||||
if (spec->stem_id >= 0)
|
||||
reg_buf += stem_arr[spec->stem_id].len;
|
||||
|
||||
/* Anchor the regular expression. */
|
||||
len = strlen(reg_buf);
|
||||
cp = anchored_regex = malloc(len + 3);
|
||||
if (!anchored_regex)
|
||||
return -1;
|
||||
|
||||
/* Create ^...$ regexp. */
|
||||
*cp++ = '^';
|
||||
memcpy(cp, reg_buf, len);
|
||||
cp += len;
|
||||
*cp++ = '$';
|
||||
*cp = '\0';
|
||||
|
||||
/* Compile the regular expression. */
|
||||
spec->regex = pcre_compile(anchored_regex, PCRE_DOTALL, &tmperrbuf,
|
||||
&erroff, NULL);
|
||||
free(anchored_regex);
|
||||
if (!spec->regex) {
|
||||
if (errbuf)
|
||||
*errbuf = tmperrbuf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spec->sd = pcre_study(spec->regex, 0, &tmperrbuf);
|
||||
if (!spec->sd && tmperrbuf) {
|
||||
if (errbuf)
|
||||
*errbuf = tmperrbuf;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Done. */
|
||||
spec->regcomp = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This service is used by label_file.c process_file() and
|
||||
* utils/sefcontext_compile.c */
|
||||
static inline int process_line(struct selabel_handle *rec,
|
||||
const char *path, const char *prefix,
|
||||
char *line_buf, unsigned lineno)
|
||||
{
|
||||
int items, len, rc;
|
||||
char *regex = NULL, *type = NULL, *context = NULL;
|
||||
struct saved_data *data = (struct saved_data *)rec->data;
|
||||
struct spec *spec_arr;
|
||||
unsigned int nspec = data->nspec;
|
||||
const char *errbuf = NULL;
|
||||
|
||||
items = read_spec_entries(line_buf, 3, ®ex, &type, &context);
|
||||
if (items <= 0)
|
||||
return items;
|
||||
|
||||
if (items < 2) {
|
||||
COMPAT_LOG(SELINUX_ERROR,
|
||||
"%s: line %u is missing fields\n", path,
|
||||
lineno);
|
||||
if (items == 1)
|
||||
free(regex);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
} else if (items == 2) {
|
||||
/* The type field is optional. */
|
||||
context = type;
|
||||
type = 0;
|
||||
}
|
||||
|
||||
len = get_stem_from_spec(regex);
|
||||
if (len && prefix && strncmp(prefix, regex, len)) {
|
||||
/* Stem of regex does not match requested prefix, discard. */
|
||||
free(regex);
|
||||
free(type);
|
||||
free(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = grow_specs(data);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
spec_arr = data->spec_arr;
|
||||
|
||||
/* process and store the specification in spec. */
|
||||
spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
|
||||
spec_arr[nspec].regex_str = regex;
|
||||
|
||||
spec_arr[nspec].type_str = type;
|
||||
spec_arr[nspec].mode = 0;
|
||||
|
||||
spec_arr[nspec].lr.ctx_raw = context;
|
||||
|
||||
/*
|
||||
* bump data->nspecs to cause closef() to cover it in its free
|
||||
* but do not bump nspec since it's used below.
|
||||
*/
|
||||
data->nspec++;
|
||||
|
||||
if (rec->validating &&
|
||||
compile_regex(data, &spec_arr[nspec], &errbuf)) {
|
||||
COMPAT_LOG(SELINUX_ERROR,
|
||||
"%s: line %u has invalid regex %s: %s\n",
|
||||
path, lineno, regex,
|
||||
(errbuf ? errbuf : "out of memory"));
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type) {
|
||||
mode_t mode = string_to_mode(type);
|
||||
|
||||
if (mode == (mode_t)-1) {
|
||||
COMPAT_LOG(SELINUX_ERROR,
|
||||
"%s: line %u has invalid file type %s\n",
|
||||
path, lineno, type);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
spec_arr[nspec].mode = mode;
|
||||
}
|
||||
|
||||
/* Determine if specification has
|
||||
* any meta characters in the RE */
|
||||
spec_hasMetaChars(&spec_arr[nspec]);
|
||||
|
||||
if (strcmp(context, "<<none>>") && rec->validating)
|
||||
compat_validate(rec, &spec_arr[nspec].lr, path, lineno);
|
||||
|
||||
fp->addr = (char *)fp->addr + bytes;
|
||||
fp->len -= bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -10,23 +10,30 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#include "dso.h"
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Installed backends
|
||||
*/
|
||||
int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_media_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_x_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_file_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_media_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_x_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_db_init(struct selabel_handle *rec,
|
||||
struct selinux_opt *opts, unsigned nopts) hidden;
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
int selabel_property_init(struct selabel_handle *rec,
|
||||
struct selinux_opt *opts, unsigned nopts) hidden;
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts) hidden;
|
||||
|
||||
/*
|
||||
* Labeling internal structures
|
||||
@ -38,8 +45,31 @@ struct selabel_sub {
|
||||
struct selabel_sub *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculate an SHA1 hash of all the files used to build the specs.
|
||||
* The hash value is held in rec->digest if SELABEL_OPT_DIGEST set. To
|
||||
* calculate the hash the hashbuf will hold a concatenation of all the files
|
||||
* used. This is released once the value has been calculated.
|
||||
*/
|
||||
#define DIGEST_SPECFILE_SIZE SHA1_HASH_SIZE
|
||||
#define DIGEST_FILES_MAX 8
|
||||
struct selabel_digest {
|
||||
unsigned char *digest; /* SHA1 digest of specfiles */
|
||||
unsigned char *hashbuf; /* buffer to hold specfiles */
|
||||
size_t hashbuf_size; /* buffer size */
|
||||
size_t specfile_cnt; /* how many specfiles processed */
|
||||
char **specfile_list; /* and their names */
|
||||
};
|
||||
|
||||
extern int digest_add_specfile(struct selabel_digest *digest, FILE *fp,
|
||||
char *from_addr,
|
||||
size_t buf_len,
|
||||
const char *path);
|
||||
extern void digest_gen_hash(struct selabel_digest *digest);
|
||||
|
||||
extern struct selabel_sub *selabel_subs_init(const char *path,
|
||||
struct selabel_sub *list);
|
||||
struct selabel_sub *list,
|
||||
struct selabel_digest *digest);
|
||||
|
||||
struct selabel_lookup_rec {
|
||||
char * ctx_raw;
|
||||
@ -63,6 +93,8 @@ struct selabel_handle {
|
||||
const char *key,
|
||||
const char **aliases,
|
||||
int type);
|
||||
enum selabel_cmp_result (*func_cmp)(struct selabel_handle *h1,
|
||||
struct selabel_handle *h2);
|
||||
|
||||
/* supports backend-specific state information */
|
||||
void *data;
|
||||
@ -76,6 +108,8 @@ struct selabel_handle {
|
||||
/* substitution support */
|
||||
struct selabel_sub *dist_subs;
|
||||
struct selabel_sub *subs;
|
||||
/* ptr to SHA1 hash information if SELABEL_OPT_DIGEST set */
|
||||
struct selabel_digest *digest;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -90,7 +124,7 @@ selabel_validate(struct selabel_handle *rec,
|
||||
*/
|
||||
extern int myprintf_compat;
|
||||
extern void __attribute__ ((format(printf, 1, 2)))
|
||||
(*myprintf) (const char *fmt,...);
|
||||
(*myprintf) (const char *fmt, ...);
|
||||
|
||||
#define COMPAT_LOG(type, fmt...) if (myprintf_compat) \
|
||||
myprintf(fmt); \
|
||||
|
@ -67,7 +67,7 @@ static int process_line(const char *path, char *line_buf, int pass,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
FILE *fp;
|
||||
@ -136,7 +136,12 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
}
|
||||
free(line_buf);
|
||||
|
||||
status = 0;
|
||||
status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
digest_gen_hash(rec->digest);
|
||||
|
||||
finish:
|
||||
fclose(fp);
|
||||
return status;
|
||||
@ -161,7 +166,7 @@ static void close(struct selabel_handle *rec)
|
||||
if (spec_arr)
|
||||
free(spec_arr);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
free(data);
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
||||
@ -201,8 +206,9 @@ static void stats(struct selabel_handle *rec)
|
||||
data->nspec, total);
|
||||
}
|
||||
|
||||
int selabel_media_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
int selabel_media_init(struct selabel_handle *rec,
|
||||
const struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
{
|
||||
struct saved_data *data;
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "label_internal.h"
|
||||
|
||||
/*
|
||||
@ -15,11 +17,8 @@
|
||||
* replace sscanf to read entries from spec files. The file and
|
||||
* property services now use these.
|
||||
*/
|
||||
|
||||
/* Read an entry from a spec file (e.g. file_contexts) */
|
||||
static inline int read_spec_entry(char **entry, char **ptr)
|
||||
static inline int read_spec_entry(char **entry, char **ptr, int *len)
|
||||
{
|
||||
int entry_len = 0;
|
||||
*entry = NULL;
|
||||
char *tmp_buf = NULL;
|
||||
|
||||
@ -27,15 +26,18 @@ static inline int read_spec_entry(char **entry, char **ptr)
|
||||
(*ptr)++;
|
||||
|
||||
tmp_buf = *ptr;
|
||||
*len = 0;
|
||||
|
||||
while (!isspace(**ptr) && **ptr != '\0') {
|
||||
(*ptr)++;
|
||||
entry_len++;
|
||||
(*len)++;
|
||||
}
|
||||
|
||||
*entry = strndup(tmp_buf, entry_len);
|
||||
if (!*entry)
|
||||
return -1;
|
||||
if (*len) {
|
||||
*entry = strndup(tmp_buf, *len);
|
||||
if (!*entry)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -48,15 +50,20 @@ static inline int read_spec_entry(char **entry, char **ptr)
|
||||
*
|
||||
* This function calls read_spec_entry() to do the actual string processing.
|
||||
*/
|
||||
int read_spec_entries(char *line_buf, int num_args, ...)
|
||||
int hidden read_spec_entries(char *line_buf, int num_args, ...)
|
||||
{
|
||||
char **spec_entry, *buf_p;
|
||||
int len, rc, items;
|
||||
int len, rc, items, entry_len = 0;
|
||||
va_list ap;
|
||||
|
||||
len = strlen(line_buf);
|
||||
if (line_buf[len - 1] == '\n')
|
||||
line_buf[len - 1] = '\0';
|
||||
else
|
||||
/* Handle case if line not \n terminated by bumping
|
||||
* the len for the check below (as the line is NUL
|
||||
* terminated by getline(3)) */
|
||||
len++;
|
||||
|
||||
buf_p = line_buf;
|
||||
while (isspace(*buf_p))
|
||||
@ -69,7 +76,8 @@ int read_spec_entries(char *line_buf, int num_args, ...)
|
||||
/* Process the spec file entries */
|
||||
va_start(ap, num_args);
|
||||
|
||||
for (items = 0; items < num_args; items++) {
|
||||
items = 0;
|
||||
while (items < num_args) {
|
||||
spec_entry = va_arg(ap, char **);
|
||||
|
||||
if (len - 1 == buf_p - line_buf) {
|
||||
@ -77,12 +85,93 @@ int read_spec_entries(char *line_buf, int num_args, ...)
|
||||
return items;
|
||||
}
|
||||
|
||||
rc = read_spec_entry(spec_entry, &buf_p);
|
||||
rc = read_spec_entry(spec_entry, &buf_p, &entry_len);
|
||||
if (rc < 0) {
|
||||
va_end(ap);
|
||||
return rc;
|
||||
}
|
||||
if (entry_len)
|
||||
items++;
|
||||
}
|
||||
va_end(ap);
|
||||
return items;
|
||||
}
|
||||
|
||||
/* Once all the specfiles are in the hash_buf, generate the hash. */
|
||||
void hidden digest_gen_hash(struct selabel_digest *digest)
|
||||
{
|
||||
Sha1Context context;
|
||||
|
||||
/* If SELABEL_OPT_DIGEST not set then just return */
|
||||
if (!digest)
|
||||
return;
|
||||
|
||||
Sha1Initialise(&context);
|
||||
Sha1Update(&context, digest->hashbuf, digest->hashbuf_size);
|
||||
Sha1Finalise(&context, (SHA1_HASH *)digest->digest);
|
||||
free(digest->hashbuf);
|
||||
digest->hashbuf = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* digest_add_specfile - Add a specfile to the hashbuf and if gen_hash true
|
||||
* then generate the hash.
|
||||
* @digest: pointer to the selabel_digest struct
|
||||
* @fp: file pointer for fread(3) or NULL if not.
|
||||
* @from_addr: pointer at start of buffer for memcpy or NULL if not (used for
|
||||
* mmap(3) files).
|
||||
* @buf_len: length of buffer to copy.
|
||||
* @path: pointer to the specfile.
|
||||
*
|
||||
* Return %0 on success, -%1 with @errno set on failure.
|
||||
*/
|
||||
int hidden digest_add_specfile(struct selabel_digest *digest, FILE *fp,
|
||||
char *from_addr, size_t buf_len,
|
||||
const char *path)
|
||||
{
|
||||
unsigned char *tmp_buf;
|
||||
|
||||
/* If SELABEL_OPT_DIGEST not set then just return */
|
||||
if (!digest)
|
||||
return 0;
|
||||
|
||||
if (digest->hashbuf_size + buf_len < digest->hashbuf_size) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
digest->hashbuf_size += buf_len;
|
||||
|
||||
tmp_buf = realloc(digest->hashbuf, digest->hashbuf_size);
|
||||
if (!tmp_buf)
|
||||
return -1;
|
||||
|
||||
digest->hashbuf = tmp_buf;
|
||||
|
||||
if (fp) {
|
||||
rewind(fp);
|
||||
if (fread(digest->hashbuf + (digest->hashbuf_size - buf_len),
|
||||
1, buf_len, fp) != buf_len)
|
||||
return -1;
|
||||
|
||||
rewind(fp);
|
||||
} else if (from_addr) {
|
||||
tmp_buf = memcpy(digest->hashbuf +
|
||||
(digest->hashbuf_size - buf_len),
|
||||
from_addr, buf_len);
|
||||
if (!tmp_buf)
|
||||
return -1;
|
||||
}
|
||||
/* Now add path to list */
|
||||
digest->specfile_list[digest->specfile_cnt] = strdup(path);
|
||||
if (!digest->specfile_list[digest->specfile_cnt])
|
||||
return -1;
|
||||
|
||||
digest->specfile_cnt++;
|
||||
if (digest->specfile_cnt > DIGEST_FILES_MAX) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ static int process_line(const char *path, char *line_buf, int pass,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
unsigned n)
|
||||
{
|
||||
FILE *fp;
|
||||
@ -163,7 +163,12 @@ static int init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
}
|
||||
free(line_buf);
|
||||
|
||||
status = 0;
|
||||
status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
digest_gen_hash(rec->digest);
|
||||
|
||||
finish:
|
||||
fclose(fp);
|
||||
return status;
|
||||
@ -188,7 +193,7 @@ static void close(struct selabel_handle *rec)
|
||||
if (spec_arr)
|
||||
free(spec_arr);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
free(data);
|
||||
}
|
||||
|
||||
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
|
||||
@ -227,7 +232,7 @@ static void stats(struct selabel_handle *rec)
|
||||
data->nspec, total);
|
||||
}
|
||||
|
||||
int selabel_x_init(struct selabel_handle *rec, struct selinux_opt *opts,
|
||||
int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
|
||||
unsigned nopts)
|
||||
{
|
||||
struct saved_data *data;
|
||||
|
@ -11,8 +11,6 @@
|
||||
|
||||
#define UNSET (char *) -1
|
||||
|
||||
static __thread pid_t cpid;
|
||||
static __thread pid_t tid;
|
||||
static __thread char *prev_current = UNSET;
|
||||
static __thread char * prev_exec = UNSET;
|
||||
static __thread char * prev_fscreate = UNSET;
|
||||
@ -24,15 +22,6 @@ static pthread_key_t destructor_key;
|
||||
static int destructor_key_initialized = 0;
|
||||
static __thread char destructor_initialized;
|
||||
|
||||
extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
|
||||
extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
|
||||
|
||||
static int __selinux_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
|
||||
{
|
||||
return __register_atfork (prepare, parent, child,
|
||||
&__dso_handle == NULL ? NULL : __dso_handle);
|
||||
}
|
||||
|
||||
static pid_t gettid(void)
|
||||
{
|
||||
return syscall(__NR_gettid);
|
||||
@ -52,14 +41,6 @@ static void procattr_thread_destructor(void __attribute__((unused)) *unused)
|
||||
free(prev_sockcreate);
|
||||
}
|
||||
|
||||
static void free_procattr(void)
|
||||
{
|
||||
procattr_thread_destructor(NULL);
|
||||
tid = 0;
|
||||
cpid = getpid();
|
||||
prev_current = prev_exec = prev_fscreate = prev_keycreate = prev_sockcreate = UNSET;
|
||||
}
|
||||
|
||||
void __attribute__((destructor)) procattr_destructor(void);
|
||||
|
||||
void hidden __attribute__((destructor)) procattr_destructor(void)
|
||||
@ -79,7 +60,6 @@ static inline void init_thread_destructor(void)
|
||||
static void init_procattr(void)
|
||||
{
|
||||
if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
|
||||
__selinux_atfork(NULL, NULL, free_procattr);
|
||||
destructor_key_initialized = 1;
|
||||
}
|
||||
}
|
||||
@ -88,21 +68,26 @@ static int openattr(pid_t pid, const char *attr, int flags)
|
||||
{
|
||||
int fd, rc;
|
||||
char *path;
|
||||
|
||||
if (cpid != getpid())
|
||||
free_procattr();
|
||||
pid_t tid;
|
||||
|
||||
if (pid > 0)
|
||||
rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
|
||||
else {
|
||||
if (!tid)
|
||||
tid = gettid();
|
||||
rc = asprintf(&path, "/proc/thread-self/attr/%s", attr);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
fd = open(path, flags | O_CLOEXEC);
|
||||
if (fd >= 0 || errno != ENOENT)
|
||||
goto out;
|
||||
free(path);
|
||||
tid = gettid();
|
||||
rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
|
||||
}
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
fd = open(path, flags | O_CLOEXEC);
|
||||
out:
|
||||
free(path);
|
||||
return fd;
|
||||
}
|
||||
@ -120,9 +105,6 @@ static int getprocattrcon_raw(char ** context,
|
||||
__selinux_once(once, init_procattr);
|
||||
init_thread_destructor();
|
||||
|
||||
if (cpid != getpid())
|
||||
free_procattr();
|
||||
|
||||
switch (attr[0]) {
|
||||
case 'c':
|
||||
prev_context = prev_current;
|
||||
@ -220,9 +202,6 @@ static int setprocattrcon_raw(const char * context,
|
||||
__selinux_once(once, init_procattr);
|
||||
init_thread_destructor();
|
||||
|
||||
if (cpid != getpid())
|
||||
free_procattr();
|
||||
|
||||
switch (attr[0]) {
|
||||
case 'c':
|
||||
prev_context = &prev_current;
|
||||
|
@ -102,6 +102,8 @@ hidden_proto(security_get_initial_context);
|
||||
hidden_proto(security_get_initial_context_raw);
|
||||
hidden_proto(selinux_reset_config);
|
||||
|
||||
hidden void flush_class_cache(void);
|
||||
|
||||
extern int load_setlocaldefs hidden;
|
||||
extern int require_seusers hidden;
|
||||
extern int selinux_page_size hidden;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
%pythoncode %{
|
||||
|
||||
import shutil, os, stat
|
||||
import shutil, os, errno, stat
|
||||
|
||||
DISABLED = -1
|
||||
PERMISSIVE = 0
|
||||
@ -26,7 +26,12 @@ def restorecon(path, recursive=False):
|
||||
status, context = matchpathcon(path, mode)
|
||||
|
||||
if status == 0:
|
||||
status, oldcontext = lgetfilecon(path)
|
||||
try:
|
||||
status, oldcontext = lgetfilecon(path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.ENODATA:
|
||||
raise
|
||||
oldcontext = None
|
||||
if context != oldcontext:
|
||||
lsetfilecon(path, context)
|
||||
|
||||
|
214
libselinux/src/sha1.c
Normal file
214
libselinux/src/sha1.c
Normal file
@ -0,0 +1,214 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LibSha1
|
||||
//
|
||||
// Implementation of SHA1 hash function.
|
||||
// Original author: Steve Reid <sreid@sea-to-sky.net>
|
||||
// Contributions by: James H. Brown <jbrown@burgoyne.com>, Saul Kravitz <Saul.Kravitz@celera.com>,
|
||||
// and Ralph Giles <giles@ghostscript.com>
|
||||
// Modified by WaterJuice retaining Public Domain license.
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
|
||||
// Modified to stop symbols being exported for libselinux shared library - October 2015
|
||||
// Richard Haines <richard_c_haines@btinternet.com>
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// IMPORTS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "sha1.h"
|
||||
#include "dso.h"
|
||||
#include <memory.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TYPES
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t c [64];
|
||||
uint32_t l [16];
|
||||
} CHAR64LONG16;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// INTERNAL FUNCTIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
// blk0() and blk() perform the initial expand.
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
// (R0+R1), R2, R3, R4 are the different operations used in SHA1
|
||||
#define R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk0(i)+ 0x5A827999 + rol(v,5); w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + blk(i) + 0x5A827999 + rol(v,5); w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0x6ED9EBA1 + rol(v,5); w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + blk(i) + 0x8F1BBCDC + rol(v,5); w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z += (w^x^y) + blk(i) + 0xCA62C1D6 + rol(v,5); w=rol(w,30);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TransformFunction
|
||||
//
|
||||
// Hash a single 512-bit block. This is the core of the algorithm
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static
|
||||
void
|
||||
TransformFunction
|
||||
(
|
||||
uint32_t state[5],
|
||||
const uint8_t buffer[64]
|
||||
)
|
||||
{
|
||||
uint32_t a;
|
||||
uint32_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
uint32_t e;
|
||||
uint8_t workspace[64];
|
||||
CHAR64LONG16* block = (CHAR64LONG16*) workspace;
|
||||
|
||||
memcpy( block, buffer, 64 );
|
||||
|
||||
// Copy context->state[] to working vars
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
// 4 rounds of 20 operations each. Loop unrolled.
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
// Add the working vars back into context.state[]
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Initialise
|
||||
//
|
||||
// Initialises an SHA1 Context. Use this to initialise/reset a context.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void hidden
|
||||
Sha1Initialise
|
||||
(
|
||||
Sha1Context* Context
|
||||
)
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
Context->State[0] = 0x67452301;
|
||||
Context->State[1] = 0xEFCDAB89;
|
||||
Context->State[2] = 0x98BADCFE;
|
||||
Context->State[3] = 0x10325476;
|
||||
Context->State[4] = 0xC3D2E1F0;
|
||||
Context->Count[0] = 0;
|
||||
Context->Count[1] = 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Update
|
||||
//
|
||||
// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on
|
||||
// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void hidden
|
||||
Sha1Update
|
||||
(
|
||||
Sha1Context* Context,
|
||||
void* Buffer,
|
||||
uint32_t BufferSize
|
||||
)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
|
||||
j = (Context->Count[0] >> 3) & 63;
|
||||
if( (Context->Count[0] += BufferSize << 3) < (BufferSize << 3) )
|
||||
{
|
||||
Context->Count[1]++;
|
||||
}
|
||||
|
||||
Context->Count[1] += (BufferSize >> 29);
|
||||
if( (j + BufferSize) > 63 )
|
||||
{
|
||||
i = 64 - j;
|
||||
memcpy( &Context->Buffer[j], Buffer, i );
|
||||
TransformFunction(Context->State, Context->Buffer);
|
||||
for( ; i + 63 < BufferSize; i += 64 )
|
||||
{
|
||||
TransformFunction(Context->State, (uint8_t*)Buffer + i);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
|
||||
memcpy( &Context->Buffer[j], &((uint8_t*)Buffer)[i], BufferSize - i );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Finalise
|
||||
//
|
||||
// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After
|
||||
// calling this, Sha1Initialised must be used to reuse the context.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void hidden
|
||||
Sha1Finalise
|
||||
(
|
||||
Sha1Context* Context,
|
||||
SHA1_HASH* Digest
|
||||
)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t finalcount[8];
|
||||
|
||||
for( i=0; i<8; i++ )
|
||||
{
|
||||
finalcount[i] = (unsigned char)((Context->Count[(i >= 4 ? 0 : 1)]
|
||||
>> ((3-(i & 3)) * 8) ) & 255); // Endian independent
|
||||
}
|
||||
Sha1Update( Context, (uint8_t*)"\x80", 1 );
|
||||
while( (Context->Count[0] & 504) != 448 )
|
||||
{
|
||||
Sha1Update( Context, (uint8_t*)"\0", 1 );
|
||||
}
|
||||
|
||||
Sha1Update( Context, finalcount, 8 ); // Should cause a Sha1TransformFunction()
|
||||
for( i=0; i<SHA1_HASH_SIZE; i++ )
|
||||
{
|
||||
Digest->bytes[i] = (uint8_t)((Context->State[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
|
||||
}
|
||||
}
|
85
libselinux/src/sha1.h
Normal file
85
libselinux/src/sha1.h
Normal file
@ -0,0 +1,85 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LibSha1
|
||||
//
|
||||
// Implementation of SHA1 hash function.
|
||||
// Original author: Steve Reid <sreid@sea-to-sky.net>
|
||||
// Contributions by: James H. Brown <jbrown@burgoyne.com>, Saul Kravitz <Saul.Kravitz@celera.com>,
|
||||
// and Ralph Giles <giles@ghostscript.com>
|
||||
// Modified by WaterJuice retaining Public Domain license.
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain - June 2013 waterjuice.org
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _sha1_h_
|
||||
#define _sha1_h_
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// IMPORTS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TYPES
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Sha1Context - This must be initialised using Sha1Initialised. Do not modify the contents of this structure directly.
|
||||
typedef struct
|
||||
{
|
||||
uint32_t State[5];
|
||||
uint32_t Count[2];
|
||||
uint8_t Buffer[64];
|
||||
} Sha1Context;
|
||||
|
||||
#define SHA1_HASH_SIZE ( 160 / 8 )
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bytes [SHA1_HASH_SIZE];
|
||||
} SHA1_HASH;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PUBLIC FUNCTIONS
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Initialise
|
||||
//
|
||||
// Initialises an SHA1 Context. Use this to initialise/reset a context.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
Sha1Initialise
|
||||
(
|
||||
Sha1Context* Context
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Update
|
||||
//
|
||||
// Adds data to the SHA1 context. This will process the data and update the internal state of the context. Keep on
|
||||
// calling this function until all the data has been added. Then call Sha1Finalise to calculate the hash.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
Sha1Update
|
||||
(
|
||||
Sha1Context* Context,
|
||||
void* Buffer,
|
||||
uint32_t BufferSize
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Sha1Finalise
|
||||
//
|
||||
// Performs the final calculation of the hash and returns the digest (20 byte buffer containing 160bit hash). After
|
||||
// calling this, Sha1Initialised must be used to reuse the context.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
Sha1Finalise
|
||||
(
|
||||
Sha1Context* Context,
|
||||
SHA1_HASH* Digest
|
||||
);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif //_sha1_h_
|
@ -158,6 +158,28 @@ err1:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hidden void flush_class_cache(void)
|
||||
{
|
||||
struct discover_class_node *cur = discover_class_cache, *prev = NULL;
|
||||
size_t i;
|
||||
|
||||
while (cur != NULL) {
|
||||
free(cur->name);
|
||||
|
||||
for (i = 0; i < MAXVECTORS; i++)
|
||||
free(cur->perms[i]);
|
||||
|
||||
free(cur->perms);
|
||||
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
|
||||
free(prev);
|
||||
}
|
||||
|
||||
discover_class_cache = NULL;
|
||||
}
|
||||
|
||||
security_class_t string_to_security_class(const char *s)
|
||||
{
|
||||
struct discover_class_node *node;
|
||||
|
@ -28,7 +28,7 @@ LDLIBS += -L../src -lselinux -L$(LIBDIR)
|
||||
|
||||
TARGETS=$(patsubst %.c,%,$(wildcard *.c))
|
||||
|
||||
sefcontext_compile: LDLIBS += -lpcre
|
||||
sefcontext_compile: LDLIBS += -lpcre ../src/libselinux.a -lsepol
|
||||
|
||||
ifeq ($(DISABLE_AVC),y)
|
||||
UNUSED_TARGETS+=compute_av compute_create compute_member compute_relabel
|
||||
|
@ -7,117 +7,62 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <sepol/sepol.h>
|
||||
|
||||
#include "../src/label_file.h"
|
||||
|
||||
static int process_file(struct saved_data *data, const char *filename)
|
||||
const char *policy_file;
|
||||
static int ctx_err;
|
||||
|
||||
static int validate_context(char **ctxp)
|
||||
{
|
||||
char *ctx = *ctxp;
|
||||
|
||||
if (policy_file && sepol_check_context(ctx) < 0) {
|
||||
ctx_err = -1;
|
||||
return ctx_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_file(struct selabel_handle *rec, const char *filename)
|
||||
{
|
||||
struct spec *spec;
|
||||
unsigned int line_num;
|
||||
int rc;
|
||||
char *line_buf = NULL;
|
||||
size_t line_len;
|
||||
ssize_t len;
|
||||
size_t line_len = 0;
|
||||
FILE *context_file;
|
||||
const char *prefix = NULL;
|
||||
|
||||
context_file = fopen(filename, "r");
|
||||
if (!context_file) {
|
||||
fprintf(stderr, "Error opening %s: %s\n", filename, strerror(errno));
|
||||
fprintf(stderr, "Error opening %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
line_num = 0;
|
||||
while ((len = getline(&line_buf, &line_len, context_file)) != -1) {
|
||||
char *context = NULL;
|
||||
char *mode = NULL;
|
||||
char *regex = NULL;
|
||||
char *cp, *anchored_regex;
|
||||
pcre *re;
|
||||
pcre_extra *sd;
|
||||
const char *err;
|
||||
int items, erroff, rc;
|
||||
size_t regex_len;
|
||||
int32_t stem_id;
|
||||
|
||||
line_num++;
|
||||
|
||||
items = read_spec_entries(line_buf, 3, ®ex, &mode, &context);
|
||||
if (items < 0)
|
||||
return -1;
|
||||
|
||||
if (items == 0)
|
||||
continue;
|
||||
else if (items == 1) {
|
||||
fprintf(stderr,
|
||||
"line: %u has invalid entry - skipping: %s\n",
|
||||
line_num, line_buf);
|
||||
continue;
|
||||
} else if (items == 2) {
|
||||
context = mode;
|
||||
mode = NULL;
|
||||
rc = 0;
|
||||
while (getline(&line_buf, &line_len, context_file) > 0) {
|
||||
rc = process_line(rec, filename, prefix, line_buf, ++line_num);
|
||||
if (rc || ctx_err) {
|
||||
/* With -p option need to check and fail if ctx err as
|
||||
* process_line() context validation on Linux does not
|
||||
* return an error, but does print the error line to
|
||||
* stderr. Android will set both to error and print
|
||||
* the error line. */
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = grow_specs(data);
|
||||
if (rc) {
|
||||
fprintf(stderr, "grow_specs failed: %s\n", strerror(errno));
|
||||
return rc;
|
||||
}
|
||||
|
||||
spec = &data->spec_arr[data->nspec];
|
||||
|
||||
spec->lr.ctx_raw = context;
|
||||
spec->mode = string_to_mode(mode);
|
||||
if (spec->mode == (mode_t)-1) {
|
||||
fprintf(stderr, "%s: line %u has invalid file type %s\n",
|
||||
regex, line_num + 1, mode);
|
||||
spec->mode = 0;
|
||||
}
|
||||
free(mode);
|
||||
spec->regex_str = regex;
|
||||
|
||||
stem_id = find_stem_from_spec(data, regex);
|
||||
spec->stem_id = stem_id;
|
||||
/* skip past the fixed stem part */
|
||||
if (stem_id != -1)
|
||||
regex += data->stem_arr[stem_id].len;
|
||||
|
||||
regex_len = strlen(regex);
|
||||
cp = anchored_regex = malloc(regex_len + 3);
|
||||
if (!cp) {
|
||||
fprintf(stderr, "Malloc Failed: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
*cp++ = '^';
|
||||
memcpy(cp, regex, regex_len);
|
||||
cp += regex_len;
|
||||
*cp++ = '$';
|
||||
*cp = '\0';
|
||||
|
||||
spec_hasMetaChars(spec);
|
||||
|
||||
re = pcre_compile(anchored_regex, PCRE_DOTALL, &err, &erroff, NULL);
|
||||
if (!re) {
|
||||
fprintf(stderr, "PCRE compilation failed for %s at offset %d: %s\n", anchored_regex, erroff, err);
|
||||
return -1;
|
||||
}
|
||||
spec->regex = re;
|
||||
|
||||
sd = pcre_study(re, 0, &err);
|
||||
if (!sd) {
|
||||
fprintf(stderr, "PCRE study failed for %s: %s\n", anchored_regex, err);
|
||||
return -1;
|
||||
}
|
||||
free(anchored_regex);
|
||||
spec->sd = sd;
|
||||
|
||||
data->nspec++;
|
||||
}
|
||||
|
||||
out:
|
||||
free(line_buf);
|
||||
fclose(context_file);
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,18 +74,19 @@ static int process_file(struct saved_data *data, const char *filename)
|
||||
* char - pcre version string EXCLUDING nul
|
||||
* u32 - number of stems
|
||||
* ** Stems
|
||||
* u32 - length of stem EXCLUDING nul
|
||||
* char - stem char array INCLUDING nul
|
||||
* u32 - length of stem EXCLUDING nul
|
||||
* char - stem char array INCLUDING nul
|
||||
* u32 - number of regexs
|
||||
* ** Regexes
|
||||
* u32 - length of upcoming context INCLUDING nul
|
||||
* char - char array of the raw context
|
||||
* u32 - length of upcoming context INCLUDING nul
|
||||
* char - char array of the raw context
|
||||
* u32 - length of the upcoming regex_str
|
||||
* char - char array of the original regex string including the stem.
|
||||
* u32 - mode bits for >= SELINUX_COMPILED_FCONTEXT_MODE
|
||||
* mode_t for <= SELINUX_COMPILED_FCONTEXT_PCRE_VERS
|
||||
* s32 - stemid associated with the regex
|
||||
* u32 - spec has meta characters
|
||||
* u32 - The specs prefix_len if >= SELINUX_COMPILED_FCONTEXT_PREFIX_LEN
|
||||
* u32 - data length of the pcre regex
|
||||
* char - a bufer holding the raw pcre regex info
|
||||
* u32 - data length of the pcre regex study daya
|
||||
@ -214,6 +160,7 @@ static int write_binary_file(struct saved_data *data, int fd)
|
||||
char *context = specs[i].lr.ctx_raw;
|
||||
char *regex_str = specs[i].regex_str;
|
||||
mode_t mode = specs[i].mode;
|
||||
size_t prefix_len = specs[i].prefix_len;
|
||||
int32_t stem_id = specs[i].stem_id;
|
||||
pcre *re = specs[i].regex;
|
||||
pcre_extra *sd = get_pcre_extra(&specs[i]);
|
||||
@ -259,6 +206,12 @@ static int write_binary_file(struct saved_data *data, int fd)
|
||||
if (len != 1)
|
||||
goto err;
|
||||
|
||||
/* For SELINUX_COMPILED_FCONTEXT_PREFIX_LEN */
|
||||
to_write = prefix_len;
|
||||
len = fwrite(&to_write, sizeof(to_write), 1, bin_file);
|
||||
if (len != 1)
|
||||
goto err;
|
||||
|
||||
/* determine the size of the pcre data in bytes */
|
||||
rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
|
||||
if (rc < 0)
|
||||
@ -301,7 +254,7 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
static int free_specs(struct saved_data *data)
|
||||
static void free_specs(struct saved_data *data)
|
||||
{
|
||||
struct spec *specs = data->spec_arr;
|
||||
unsigned int num_entries = data->nspec;
|
||||
@ -311,59 +264,144 @@ static int free_specs(struct saved_data *data)
|
||||
free(specs[i].lr.ctx_raw);
|
||||
free(specs[i].lr.ctx_trans);
|
||||
free(specs[i].regex_str);
|
||||
free(specs[i].type_str);
|
||||
pcre_free(specs[i].regex);
|
||||
pcre_free_study(specs[i].sd);
|
||||
}
|
||||
free(specs);
|
||||
|
||||
num_entries = data->num_stems;
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
for (i = 0; i < num_entries; i++)
|
||||
free(data->stem_arr[i].buf);
|
||||
}
|
||||
free(data->stem_arr);
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [-o out_file] [-p policy_file] fc_file\n"
|
||||
"Where:\n\t"
|
||||
"-o Optional file name of the PCRE formatted binary\n\t"
|
||||
" file to be output. If not specified the default\n\t"
|
||||
" will be fc_file with the .bin suffix appended.\n\t"
|
||||
"-p Optional binary policy file that will be used to\n\t"
|
||||
" validate contexts defined in the fc_file.\n\t"
|
||||
"fc_file The text based file contexts file to be processed.\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct saved_data data;
|
||||
const char *path;
|
||||
const char *path = NULL;
|
||||
const char *out_file = NULL;
|
||||
char stack_path[PATH_MAX + 1];
|
||||
int rc;
|
||||
char *tmp= NULL;
|
||||
int fd;
|
||||
char *tmp = NULL;
|
||||
int fd, rc, opt;
|
||||
FILE *policy_fp = NULL;
|
||||
struct stat buf;
|
||||
struct selabel_handle *rec = NULL;
|
||||
struct saved_data *data = NULL;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s input_file\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
if (argc < 2)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "o:p:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'o':
|
||||
out_file = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
policy_file = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
path = argv[1];
|
||||
if (optind >= argc)
|
||||
usage(argv[0]);
|
||||
|
||||
path = argv[optind];
|
||||
if (stat(path, &buf) < 0) {
|
||||
fprintf(stderr, "Can not stat: %s: %m\n", path);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rc = process_file(&data, path);
|
||||
/* Open binary policy if supplied. */
|
||||
if (policy_file) {
|
||||
policy_fp = fopen(policy_file, "r");
|
||||
|
||||
if (!policy_fp) {
|
||||
fprintf(stderr, "Failed to open policy: %s\n",
|
||||
policy_file);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sepol_set_policydb_from_file(policy_fp) < 0) {
|
||||
fprintf(stderr, "Failed to load policy: %s\n",
|
||||
policy_file);
|
||||
fclose(policy_fp);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate dummy handle for process_line() function */
|
||||
rec = (struct selabel_handle *)calloc(1, sizeof(*rec));
|
||||
if (!rec) {
|
||||
fprintf(stderr, "Failed to calloc handle\n");
|
||||
if (policy_fp)
|
||||
fclose(policy_fp);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rec->backend = SELABEL_CTX_FILE;
|
||||
|
||||
/* Need to set validation on to get the bin file generated by the
|
||||
* process_line function, however as the bin file being generated
|
||||
* may not be related to the currently loaded policy (that it
|
||||
* would be validated against), then set callback to ignore any
|
||||
* validation - unless the -p option is used in which case if an
|
||||
* error is detected, the process will be aborted. */
|
||||
rec->validating = 1;
|
||||
selinux_set_callback(SELINUX_CB_VALIDATE,
|
||||
(union selinux_callback)&validate_context);
|
||||
|
||||
data = (struct saved_data *)calloc(1, sizeof(*data));
|
||||
if (!data) {
|
||||
fprintf(stderr, "Failed to calloc saved_data\n");
|
||||
free(rec);
|
||||
if (policy_fp)
|
||||
fclose(policy_fp);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rec->data = data;
|
||||
|
||||
rc = process_file(rec, path);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto err;
|
||||
|
||||
rc = sort_specs(&data);
|
||||
rc = sort_specs(data);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto err;
|
||||
|
||||
if (out_file)
|
||||
rc = snprintf(stack_path, sizeof(stack_path), "%s", out_file);
|
||||
else
|
||||
rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
|
||||
|
||||
rc = snprintf(stack_path, sizeof(stack_path), "%s.bin", path);
|
||||
if (rc < 0 || rc >= (int)sizeof(stack_path))
|
||||
return rc;
|
||||
goto err;
|
||||
|
||||
if (asprintf(&tmp, "%sXXXXXX", stack_path) < 0)
|
||||
return -1;
|
||||
tmp = malloc(strlen(stack_path) + 7);
|
||||
if (!tmp)
|
||||
goto err;
|
||||
|
||||
rc = sprintf(tmp, "%sXXXXXX", stack_path);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
|
||||
fd = mkstemp(tmp);
|
||||
if (fd < 0)
|
||||
@ -372,23 +410,30 @@ int main(int argc, char *argv[])
|
||||
rc = fchmod(fd, buf.st_mode);
|
||||
if (rc < 0) {
|
||||
perror("fchmod failed to set permission on compiled regexs");
|
||||
goto err;
|
||||
goto err_unlink;
|
||||
}
|
||||
|
||||
rc = write_binary_file(&data, fd);
|
||||
|
||||
rc = write_binary_file(data, fd);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
goto err_unlink;
|
||||
|
||||
rename(tmp, stack_path);
|
||||
rc = free_specs(&data);
|
||||
rc = rename(tmp, stack_path);
|
||||
if (rc < 0)
|
||||
goto err;
|
||||
goto err_unlink;
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (policy_fp)
|
||||
fclose(policy_fp);
|
||||
|
||||
free_specs(data);
|
||||
free(rec);
|
||||
free(data);
|
||||
free(tmp);
|
||||
return rc;
|
||||
|
||||
err_unlink:
|
||||
unlink(tmp);
|
||||
err:
|
||||
rc = -1;
|
||||
goto out;
|
||||
|
188
libselinux/utils/selabel_digest.c
Normal file
188
libselinux/utils/selabel_digest.c
Normal file
@ -0,0 +1,188 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
|
||||
static size_t digest_len;
|
||||
|
||||
static void usage(const char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s -b backend [-d] [-v] [-B] [-i] [-f file]\n\n"
|
||||
"Where:\n\t"
|
||||
"-b The backend - \"file\", \"media\", \"x\", \"db\" or "
|
||||
"\"prop\"\n\t"
|
||||
"-v Run \"cat <specfile_list> | openssl dgst -sha1 -hex\"\n\t"
|
||||
" on the list of specfiles to compare the SHA1 digests.\n\t"
|
||||
"-B Use base specfiles only (valid for \"-b file\" only).\n\t"
|
||||
"-i Do not request a digest.\n\t"
|
||||
"-f Optional file containing the specs (defaults to\n\t"
|
||||
" those used by loaded policy).\n\n",
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int run_check_digest(char *cmd, char *selabel_digest)
|
||||
{
|
||||
FILE *fp;
|
||||
char files_digest[128];
|
||||
char *files_ptr;
|
||||
int rc = 0;
|
||||
|
||||
fp = popen(cmd, "r");
|
||||
if (!fp) {
|
||||
printf("Failed to run command line\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only expect one line "(stdin)= x.." so read and find first space */
|
||||
while (fgets(files_digest, sizeof(files_digest) - 1, fp) != NULL)
|
||||
;
|
||||
|
||||
files_ptr = strstr(files_digest, " ");
|
||||
|
||||
rc = strncmp(selabel_digest, files_ptr + 1, digest_len * 2);
|
||||
if (rc) {
|
||||
printf("Failed validation:\n\tselabel_digest: %s\n\t"
|
||||
"files_digest: %s\n",
|
||||
selabel_digest, files_ptr + 1);
|
||||
} else {
|
||||
printf("Passed validation - digest: %s\n", selabel_digest);
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int backend = 0, rc, opt, i, validate = 0;
|
||||
char *baseonly = NULL, *file = NULL, *digest = (char *)1;
|
||||
char **specfiles = NULL;
|
||||
unsigned char *sha1_digest = NULL;
|
||||
size_t num_specfiles;
|
||||
|
||||
char cmd_buf[4096];
|
||||
char *cmd_ptr;
|
||||
char *sha1_buf;
|
||||
|
||||
struct selabel_handle *hnd;
|
||||
struct selinux_opt selabel_option[] = {
|
||||
{ SELABEL_OPT_PATH, file },
|
||||
{ SELABEL_OPT_BASEONLY, baseonly },
|
||||
{ SELABEL_OPT_DIGEST, digest }
|
||||
};
|
||||
|
||||
if (argc < 3)
|
||||
usage(argv[0]);
|
||||
|
||||
while ((opt = getopt(argc, argv, "ib:Bvf:")) > 0) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
if (!strcasecmp(optarg, "file")) {
|
||||
backend = SELABEL_CTX_FILE;
|
||||
} else if (!strcmp(optarg, "media")) {
|
||||
backend = SELABEL_CTX_MEDIA;
|
||||
} else if (!strcmp(optarg, "x")) {
|
||||
backend = SELABEL_CTX_X;
|
||||
} else if (!strcmp(optarg, "db")) {
|
||||
backend = SELABEL_CTX_DB;
|
||||
} else if (!strcmp(optarg, "prop")) {
|
||||
backend = SELABEL_CTX_ANDROID_PROP;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown backend: %s\n",
|
||||
optarg);
|
||||
usage(argv[0]);
|
||||
}
|
||||
break;
|
||||
case 'B':
|
||||
baseonly = (char *)1;
|
||||
break;
|
||||
case 'v':
|
||||
validate = 1;
|
||||
break;
|
||||
case 'i':
|
||||
digest = NULL;
|
||||
break;
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
memset(cmd_buf, 0, sizeof(cmd_buf));
|
||||
|
||||
selabel_option[0].value = file;
|
||||
selabel_option[1].value = baseonly;
|
||||
selabel_option[2].value = digest;
|
||||
|
||||
hnd = selabel_open(backend, selabel_option, 3);
|
||||
if (!hnd) {
|
||||
switch (errno) {
|
||||
case EOVERFLOW:
|
||||
fprintf(stderr, "ERROR Number of specfiles or specfile"
|
||||
" buffer caused an overflow.\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "ERROR: selabel_open: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = selabel_digest(hnd, &sha1_digest, &digest_len, &specfiles,
|
||||
&num_specfiles);
|
||||
|
||||
if (rc) {
|
||||
switch (errno) {
|
||||
case EINVAL:
|
||||
fprintf(stderr, "No digest available.\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "selabel_digest ERROR: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
sha1_buf = malloc(digest_len * 2 + 1);
|
||||
if (!sha1_buf) {
|
||||
fprintf(stderr, "Could not malloc buffer ERROR: %s\n",
|
||||
strerror(errno));
|
||||
rc = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
printf("SHA1 digest: ");
|
||||
for (i = 0; i < digest_len; i++)
|
||||
sprintf(&(sha1_buf[i * 2]), "%02x", sha1_digest[i]);
|
||||
|
||||
printf("%s\n", sha1_buf);
|
||||
printf("calculated using the following specfile(s):\n");
|
||||
|
||||
if (specfiles) {
|
||||
cmd_ptr = &cmd_buf[0];
|
||||
sprintf(cmd_ptr, "/usr/bin/cat ");
|
||||
cmd_ptr = &cmd_buf[0] + strlen(cmd_buf);
|
||||
|
||||
for (i = 0; i < num_specfiles; i++) {
|
||||
sprintf(cmd_ptr, "%s ", specfiles[i]);
|
||||
cmd_ptr += strlen(specfiles[i]) + 1;
|
||||
printf("%s\n", specfiles[i]);
|
||||
}
|
||||
sprintf(cmd_ptr, "| /usr/bin/openssl dgst -sha1 -hex");
|
||||
|
||||
if (validate)
|
||||
rc = run_check_digest(cmd_buf, sha1_buf);
|
||||
}
|
||||
|
||||
free(sha1_buf);
|
||||
err:
|
||||
selabel_close(hnd);
|
||||
return rc;
|
||||
}
|
@ -1,3 +1,12 @@
|
||||
* semanage_migrate_store: Load libsepol.so.1 instead of libsepol.so, from Laurent Bigonville.
|
||||
* Store homedir_template and users_extra in policy store, from Steve Lawrence
|
||||
* Fix null pointer dereference in semanage_module_key_destroy, from Yuli Khodorkovskiy.
|
||||
* Add semanage_module_extract() to extract a module as CIL or HLL, from Yuli Khodorkovskiy.
|
||||
* semanage_migrate_store: add -r <root> option for migrating inside chroots, from Petr Lautrbach.
|
||||
* Add file_contexts and seusers to the store, from Yuli Khodorkovskiy.
|
||||
* Add policy binary and file_contexts.local to the store, from Yuli Khodorkovskiy.
|
||||
* Allow to install compressed modules without a compression extension,
|
||||
from Petr Lautrbach.
|
||||
* Do not copy contexts in semanage_migrate_store, from Jason Zaman.
|
||||
* Fix logic in bunzip for uncompressed pp files, from Thomas Hurd.
|
||||
* Fix fname[] initialization in test_utilities.c, from Petr Lautrbach.
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <semanage/handle.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct semanage_module_key semanage_module_key_t;
|
||||
|
||||
@ -41,6 +42,22 @@ int semanage_module_remove(semanage_handle_t *, char *module_name);
|
||||
modules, only name at this time */
|
||||
typedef struct semanage_module_info semanage_module_info_t;
|
||||
|
||||
/* Look up a module using @modkey. The module's raw data is returned as a
|
||||
* @mapped_data blob and size of the mapped_data is returned as @data_len.
|
||||
* @modinfo contains additional information which can be used by the caller such
|
||||
* as the high level language extension of @mapped_data.
|
||||
*
|
||||
* On success, the caller is responsible for unmapping @mapped_data with munmap(),
|
||||
* destroying @modinfo with semanage_module_info_destroy(), and freeing @modinfo.
|
||||
*
|
||||
* Returns 0 on success and -1 on error.
|
||||
*/
|
||||
int semanage_module_extract(semanage_handle_t *sh,
|
||||
semanage_module_key_t *modkey,
|
||||
int extract_cil,
|
||||
void **mapped_data,
|
||||
size_t *data_len,
|
||||
semanage_module_info_t **modinfo);
|
||||
int semanage_module_list(semanage_handle_t *,
|
||||
semanage_module_info_t **, int *num_modules);
|
||||
void semanage_module_info_datum_destroy(semanage_module_info_t *);
|
||||
|
@ -55,10 +55,8 @@ int bool_policydb_dbase_init(semanage_handle_t * handle,
|
||||
{
|
||||
|
||||
if (dbase_policydb_init(handle,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
&SEMANAGE_BOOL_RTABLE,
|
||||
&SEMANAGE_BOOL_POLICYDB_RTABLE,
|
||||
&dconfig->dbase) < 0)
|
||||
|
@ -66,6 +66,12 @@ static int semanage_direct_commit(semanage_handle_t * sh);
|
||||
static int semanage_direct_install(semanage_handle_t * sh, char *data,
|
||||
size_t data_len, const char *module_name, const char *lang_ext);
|
||||
static int semanage_direct_install_file(semanage_handle_t * sh, const char *module_name);
|
||||
static int semanage_direct_extract(semanage_handle_t * sh,
|
||||
semanage_module_key_t *modkey,
|
||||
int extract_cil,
|
||||
void **mapped_data,
|
||||
size_t *data_len,
|
||||
semanage_module_info_t **modinfo);
|
||||
static int semanage_direct_remove(semanage_handle_t * sh, char *module_name);
|
||||
static int semanage_direct_list(semanage_handle_t * sh,
|
||||
semanage_module_info_t ** modinfo,
|
||||
@ -100,6 +106,7 @@ static struct semanage_policy_table direct_funcs = {
|
||||
.begin_trans = semanage_direct_begintrans,
|
||||
.commit = semanage_direct_commit,
|
||||
.install = semanage_direct_install,
|
||||
.extract = semanage_direct_extract,
|
||||
.install_file = semanage_direct_install_file,
|
||||
.remove = semanage_direct_remove,
|
||||
.list = semanage_direct_list,
|
||||
@ -196,10 +203,8 @@ int semanage_direct_connect(semanage_handle_t * sh)
|
||||
goto err;
|
||||
|
||||
if (fcontext_file_dbase_init(sh,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_FC_LOCAL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_FC_LOCAL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC_LOCAL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
|
||||
semanage_fcontext_dbase_local(sh)) < 0)
|
||||
goto err;
|
||||
|
||||
@ -250,18 +255,14 @@ int semanage_direct_connect(semanage_handle_t * sh)
|
||||
goto err;
|
||||
|
||||
if (fcontext_file_dbase_init(sh,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_FC),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_FC),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_FC),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
|
||||
semanage_fcontext_dbase_policy(sh)) < 0)
|
||||
goto err;
|
||||
|
||||
if (seuser_file_dbase_init(sh,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_SEUSERS),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_SEUSERS),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_SEUSERS),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS),
|
||||
semanage_seuser_dbase_policy(sh)) < 0)
|
||||
goto err;
|
||||
|
||||
@ -502,15 +503,32 @@ exit:
|
||||
* the file into '*data'.
|
||||
* Returns the total number of bytes in memory .
|
||||
* Returns -1 if file could not be opened or mapped. */
|
||||
static ssize_t map_file(semanage_handle_t *sh, int fd, char **data,
|
||||
static ssize_t map_file(semanage_handle_t *sh, const char *path, char **data,
|
||||
int *compressed)
|
||||
{
|
||||
ssize_t size = -1;
|
||||
char *uncompress;
|
||||
if ((size = bunzip(sh, fdopen(fd, "r"), &uncompress)) > 0) {
|
||||
int fd = -1;
|
||||
FILE *file = NULL;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
ERR(sh, "Unable to open %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = fdopen(fd, "r");
|
||||
if (file == NULL) {
|
||||
ERR(sh, "Unable to open %s\n", path);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((size = bunzip(sh, file, &uncompress)) > 0) {
|
||||
*data = mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
|
||||
if (*data == MAP_FAILED) {
|
||||
free(uncompress);
|
||||
fclose(file);
|
||||
return -1;
|
||||
} else {
|
||||
memcpy(*data, uncompress, size);
|
||||
@ -529,6 +547,8 @@ static ssize_t map_file(semanage_handle_t *sh, int fd, char **data,
|
||||
*compressed = 0;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -604,7 +624,7 @@ static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
ofilename = semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS);
|
||||
ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
|
||||
if (ofilename == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@ -892,9 +912,8 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int semanage_compile_hll(semanage_handle_t *sh,
|
||||
semanage_module_info_t *modinfos,
|
||||
int num_modinfos)
|
||||
static int semanage_compile_module(semanage_handle_t *sh,
|
||||
semanage_module_info_t *modinfo)
|
||||
{
|
||||
char cil_path[PATH_MAX];
|
||||
char hll_path[PATH_MAX];
|
||||
@ -907,19 +926,108 @@ static int semanage_compile_hll(semanage_handle_t *sh,
|
||||
ssize_t hll_data_len = 0;
|
||||
ssize_t bzip_status;
|
||||
int status = 0;
|
||||
int i, compressed;
|
||||
int in_fd = -1;
|
||||
int compressed;
|
||||
size_t cil_data_len;
|
||||
size_t err_data_len;
|
||||
|
||||
if (!strcasecmp(modinfo->lang_ext, "cil")) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_get_hll_compiler_path(sh, modinfo->lang_ext, &compiler_path);
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_module_get_path(
|
||||
sh,
|
||||
modinfo,
|
||||
SEMANAGE_MODULE_PATH_CIL,
|
||||
cil_path,
|
||||
sizeof(cil_path));
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_module_get_path(
|
||||
sh,
|
||||
modinfo,
|
||||
SEMANAGE_MODULE_PATH_HLL,
|
||||
hll_path,
|
||||
sizeof(hll_path));
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((hll_data_len = map_file(sh, hll_path, &hll_data, &compressed)) <= 0) {
|
||||
ERR(sh, "Unable to read file %s\n", hll_path);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len);
|
||||
if (err_data_len > 0) {
|
||||
for (start = end = err_data; end < err_data + err_data_len; end++) {
|
||||
if (*end == '\n') {
|
||||
fprintf(stderr, "%s: ", modinfo->name);
|
||||
fwrite(start, 1, end - start + 1, stderr);
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (end != start) {
|
||||
fprintf(stderr, "%s: ", modinfo->name);
|
||||
fwrite(start, 1, end - start, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bzip_status = bzip(sh, cil_path, cil_data, cil_data_len);
|
||||
if (bzip_status == -1) {
|
||||
ERR(sh, "Failed to bzip %s\n", cil_path);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (sh->conf->remove_hll == 1) {
|
||||
status = unlink(hll_path);
|
||||
if (status != 0) {
|
||||
ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_direct_write_langext(sh, "cil", modinfo);
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (hll_data_len > 0) {
|
||||
munmap(hll_data, hll_data_len);
|
||||
}
|
||||
free(cil_data);
|
||||
free(err_data);
|
||||
free(compiler_path);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int semanage_compile_hll_modules(semanage_handle_t *sh,
|
||||
semanage_module_info_t *modinfos,
|
||||
int num_modinfos)
|
||||
{
|
||||
int status = 0;
|
||||
int i;
|
||||
char cil_path[PATH_MAX];
|
||||
|
||||
assert(sh);
|
||||
assert(modinfos);
|
||||
|
||||
for (i = 0; i < num_modinfos; i++) {
|
||||
if (!strcasecmp(modinfos[i].lang_ext, "cil")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = semanage_module_get_path(
|
||||
sh,
|
||||
&modinfos[i],
|
||||
@ -931,101 +1039,19 @@ static int semanage_compile_hll(semanage_handle_t *sh,
|
||||
}
|
||||
|
||||
if (semanage_get_ignore_module_cache(sh) == 0 &&
|
||||
access(cil_path, F_OK) == 0) {
|
||||
access(cil_path, F_OK) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = semanage_get_hll_compiler_path(sh, modinfos[i].lang_ext, &compiler_path);
|
||||
if (status != 0) {
|
||||
status = semanage_compile_module(sh, &modinfos[i]);
|
||||
if (status < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_module_get_path(
|
||||
sh,
|
||||
&modinfos[i],
|
||||
SEMANAGE_MODULE_PATH_HLL,
|
||||
hll_path,
|
||||
sizeof(hll_path));
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((in_fd = open(hll_path, O_RDONLY)) == -1) {
|
||||
ERR(sh, "Unable to open %s\n", hll_path);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((hll_data_len = map_file(sh, in_fd, &hll_data, &compressed)) <= 0) {
|
||||
ERR(sh, "Unable to read file %s\n", hll_path);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (in_fd >= 0) close(in_fd);
|
||||
in_fd = -1;
|
||||
|
||||
status = semanage_pipe_data(sh, compiler_path, hll_data, (size_t)hll_data_len, &cil_data, &cil_data_len, &err_data, &err_data_len);
|
||||
if (err_data_len > 0) {
|
||||
for (start = end = err_data; end < err_data + err_data_len; end++) {
|
||||
if (*end == '\n') {
|
||||
fprintf(stderr, "%s: ", modinfos[i].name);
|
||||
fwrite(start, 1, end - start + 1, stderr);
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (end != start) {
|
||||
fprintf(stderr, "%s: ", modinfos[i].name);
|
||||
fwrite(start, 1, end - start, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (sh->conf->remove_hll == 1) {
|
||||
status = unlink(hll_path);
|
||||
if (status != 0) {
|
||||
ERR(sh, "Error while removing HLL file %s: %s", hll_path, strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
status = semanage_direct_write_langext(sh, "cil", &modinfos[i]);
|
||||
if (status != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
bzip_status = bzip(sh, cil_path, cil_data, cil_data_len);
|
||||
if (bzip_status == -1) {
|
||||
ERR(sh, "Failed to bzip %s\n", cil_path);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (hll_data_len > 0) munmap(hll_data, hll_data_len);
|
||||
hll_data_len = 0;
|
||||
|
||||
free(cil_data);
|
||||
free(err_data);
|
||||
free(compiler_path);
|
||||
cil_data = NULL;
|
||||
err_data = NULL;
|
||||
compiler_path = NULL;
|
||||
cil_data_len = 0;
|
||||
err_data_len = 0;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
|
||||
cleanup:
|
||||
if (hll_data_len > 0) munmap(hll_data, hll_data_len);
|
||||
if (in_fd >= 0) close(in_fd);
|
||||
free(cil_data);
|
||||
free(err_data);
|
||||
free(compiler_path);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1041,7 +1067,8 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
size_t fc_buffer_len = 0;
|
||||
const char *ofilename = NULL;
|
||||
const char *path;
|
||||
int retval = -1, num_modinfos = 0, i;
|
||||
int retval = -1, num_modinfos = 0, i, missing_policy_kern = 0,
|
||||
missing_seusers = 0, missing_fc = 0, missing = 0;
|
||||
sepol_policydb_t *out = NULL;
|
||||
struct cil_db *cildb = NULL;
|
||||
semanage_module_info_t *modinfos = NULL;
|
||||
@ -1143,8 +1170,36 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
modified |= dontaudit_modified;
|
||||
modified |= preserve_tunables_modified;
|
||||
|
||||
/* This is for systems that have already migrated with an older version
|
||||
* of semanage_migrate_store. The older version did not copy policy.kern so
|
||||
* the policy binary must be rebuilt here.
|
||||
*/
|
||||
if (!sh->do_rebuild && !modified) {
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL);
|
||||
|
||||
if (access(path, F_OK) != 0) {
|
||||
missing_policy_kern = 1;
|
||||
}
|
||||
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC);
|
||||
|
||||
if (access(path, F_OK) != 0) {
|
||||
missing_fc = 1;
|
||||
}
|
||||
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
|
||||
|
||||
if (access(path, F_OK) != 0) {
|
||||
missing_seusers = 1;
|
||||
}
|
||||
}
|
||||
|
||||
missing |= missing_policy_kern;
|
||||
missing |= missing_fc;
|
||||
missing |= missing_seusers;
|
||||
|
||||
/* If there were policy changes, or explicitly requested, rebuild the policy */
|
||||
if (sh->do_rebuild || modified) {
|
||||
if (sh->do_rebuild || modified || missing) {
|
||||
/* =================== Module expansion =============== */
|
||||
|
||||
retval = semanage_get_active_modules(sh, &modinfos, &num_modinfos);
|
||||
@ -1156,7 +1211,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
retval = semanage_compile_hll(sh, modinfos, num_modinfos);
|
||||
retval = semanage_compile_hll_modules(sh, modinfos, num_modinfos);
|
||||
if (retval < 0) {
|
||||
ERR(sh, "Failed to compile hll files into cil files.\n");
|
||||
goto cleanup;
|
||||
@ -1217,6 +1272,9 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
if (retval < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* remove FC_TMPL now that it is now longer needed */
|
||||
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
|
||||
|
||||
pfcontexts->dtable->drop_cache(pfcontexts->dbase);
|
||||
|
||||
/* SEUsers */
|
||||
@ -1302,6 +1360,43 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
if (retval < 0)
|
||||
goto cleanup;
|
||||
|
||||
retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL),
|
||||
sh->conf->file_mode);
|
||||
if (retval < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL);
|
||||
if (access(path, F_OK) == 0) {
|
||||
retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC_LOCAL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC_LOCAL),
|
||||
sh->conf->file_mode);
|
||||
if (retval < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC);
|
||||
if (access(path, F_OK) == 0) {
|
||||
retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC),
|
||||
sh->conf->file_mode);
|
||||
if (retval < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
path = semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS);
|
||||
if (access(path, F_OK) == 0) {
|
||||
retval = semanage_copy_file(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_SEUSERS),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS),
|
||||
sh->conf->file_mode);
|
||||
if (retval < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* run genhomedircon if its enabled, this should be the last operation
|
||||
* which requires the out policydb */
|
||||
if (!sh->conf->disable_genhomedircon) {
|
||||
@ -1321,11 +1416,6 @@ static int semanage_direct_commit(semanage_handle_t * sh)
|
||||
sepol_policydb_free(out);
|
||||
out = NULL;
|
||||
|
||||
/* remove files that are automatically generated and no longer needed */
|
||||
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
|
||||
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL));
|
||||
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA));
|
||||
|
||||
if (sh->do_rebuild || modified || bools_modified || fcontexts_modified) {
|
||||
retval = semanage_install_sandbox(sh);
|
||||
}
|
||||
@ -1432,19 +1522,12 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
|
||||
char *data = NULL;
|
||||
ssize_t data_len = 0;
|
||||
int compressed = 0;
|
||||
int in_fd = -1;
|
||||
char *path = NULL;
|
||||
char *filename;
|
||||
char *lang_ext;
|
||||
char *lang_ext = NULL;
|
||||
char *separator;
|
||||
|
||||
if ((in_fd = open(install_filename, O_RDONLY)) == -1) {
|
||||
ERR(sh, "Unable to open %s: %s\n", install_filename, strerror(errno));
|
||||
retval = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((data_len = map_file(sh, in_fd, &data, &compressed)) <= 0) {
|
||||
if ((data_len = map_file(sh, install_filename, &data, &compressed)) <= 0) {
|
||||
ERR(sh, "Unable to read file %s\n", install_filename);
|
||||
retval = -1;
|
||||
goto cleanup;
|
||||
@ -1467,30 +1550,114 @@ static int semanage_direct_install_file(semanage_handle_t * sh,
|
||||
goto cleanup;
|
||||
}
|
||||
*separator = '\0';
|
||||
lang_ext = separator + 1;
|
||||
}
|
||||
|
||||
separator = strrchr(filename, '.');
|
||||
if (separator == NULL) {
|
||||
ERR(sh, "Module does not have a valid extension.");
|
||||
retval = -1;
|
||||
goto cleanup;
|
||||
if (lang_ext == NULL) {
|
||||
ERR(sh, "Module does not have a valid extension.");
|
||||
retval = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
*separator = '\0';
|
||||
lang_ext = separator + 1;
|
||||
}
|
||||
*separator = '\0';
|
||||
|
||||
lang_ext = separator + 1;
|
||||
|
||||
retval = semanage_direct_install(sh, data, data_len, filename, lang_ext);
|
||||
|
||||
cleanup:
|
||||
if (in_fd != -1) {
|
||||
close(in_fd);
|
||||
}
|
||||
if (data_len > 0) munmap(data, data_len);
|
||||
free(path);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int semanage_direct_extract(semanage_handle_t * sh,
|
||||
semanage_module_key_t *modkey,
|
||||
int extract_cil,
|
||||
void **mapped_data,
|
||||
size_t *data_len,
|
||||
semanage_module_info_t **modinfo)
|
||||
{
|
||||
char module_path[PATH_MAX];
|
||||
char input_file[PATH_MAX];
|
||||
enum semanage_module_path_type file_type;
|
||||
int rc = -1;
|
||||
semanage_module_info_t *_modinfo = NULL;
|
||||
ssize_t _data_len;
|
||||
char *_data;
|
||||
int compressed;
|
||||
|
||||
/* get path of module */
|
||||
rc = semanage_module_get_path(
|
||||
sh,
|
||||
(const semanage_module_info_t *)modkey,
|
||||
SEMANAGE_MODULE_PATH_NAME,
|
||||
module_path,
|
||||
sizeof(module_path));
|
||||
if (rc != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (access(module_path, F_OK) != 0) {
|
||||
ERR(sh, "Module does not exist: %s", module_path);
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = semanage_module_get_module_info(sh,
|
||||
modkey,
|
||||
&_modinfo);
|
||||
if (rc != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (extract_cil || strcmp(_modinfo->lang_ext, "cil") == 0) {
|
||||
file_type = SEMANAGE_MODULE_PATH_CIL;
|
||||
} else {
|
||||
file_type = SEMANAGE_MODULE_PATH_HLL;
|
||||
}
|
||||
|
||||
/* get path of what to extract */
|
||||
rc = semanage_module_get_path(
|
||||
sh,
|
||||
_modinfo,
|
||||
file_type,
|
||||
input_file,
|
||||
sizeof(input_file));
|
||||
if (rc != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (extract_cil == 1 && strcmp(_modinfo->lang_ext, "cil") && access(input_file, F_OK) != 0) {
|
||||
rc = semanage_compile_module(sh, _modinfo);
|
||||
if (rc < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
_data_len = map_file(sh, input_file, &_data, &compressed);
|
||||
if (_data_len <= 0) {
|
||||
ERR(sh, "Error mapping file: %s", input_file);
|
||||
rc = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*modinfo = _modinfo;
|
||||
*data_len = (size_t)_data_len;
|
||||
*mapped_data = _data;
|
||||
|
||||
cleanup:
|
||||
if (rc != 0) {
|
||||
semanage_module_info_destroy(sh, _modinfo);
|
||||
free(_modinfo);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Removes a module from the sandbox. Returns 0 on success, -1 if out
|
||||
* of memory, -2 if module not found or could not be removed. */
|
||||
static int semanage_direct_remove(semanage_handle_t * sh, char *module_name)
|
||||
|
@ -51,10 +51,8 @@ int iface_policydb_dbase_init(semanage_handle_t * handle,
|
||||
{
|
||||
|
||||
if (dbase_policydb_init(handle,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
&SEMANAGE_IFACE_RTABLE,
|
||||
&SEMANAGE_IFACE_POLICYDB_RTABLE,
|
||||
&dconfig->dbase) < 0)
|
||||
|
@ -30,6 +30,7 @@ LIBSEMANAGE_1.0 {
|
||||
LIBSEMANAGE_1.1 {
|
||||
global:
|
||||
semanage_module_install;
|
||||
semanage_module_extract;
|
||||
semanage_get_hll_compiler_path;
|
||||
semanage_get_ignore_module_cache;
|
||||
semanage_set_ignore_module_cache;
|
||||
|
@ -142,6 +142,23 @@ int semanage_module_install_file(semanage_handle_t * sh,
|
||||
return sh->funcs->install_file(sh, module_name);
|
||||
}
|
||||
|
||||
int semanage_module_extract(semanage_handle_t * sh,
|
||||
semanage_module_key_t *modkey,
|
||||
int extract_cil,
|
||||
void **mapped_data,
|
||||
size_t *data_len,
|
||||
semanage_module_info_t **modinfo) {
|
||||
if (sh->funcs->extract == NULL) {
|
||||
ERR(sh,
|
||||
"No get function defined for this connection type.");
|
||||
return -1;
|
||||
} else if (!sh->is_connected) {
|
||||
ERR(sh, "Not connected.");
|
||||
return -1;
|
||||
}
|
||||
return sh->funcs->extract(sh, modkey, extract_cil, mapped_data, data_len, modinfo);
|
||||
}
|
||||
|
||||
/* Legacy function that remains to preserve ABI
|
||||
* compatibility. Please use semanage_module_install instead.
|
||||
*/
|
||||
@ -673,10 +690,12 @@ int semanage_module_key_destroy(semanage_handle_t *sh,
|
||||
{
|
||||
assert(sh);
|
||||
|
||||
if (modkey) {
|
||||
free(modkey->name);
|
||||
if (!modkey) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(modkey->name);
|
||||
|
||||
return semanage_module_key_init(sh, modkey);
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,8 @@ int node_policydb_dbase_init(semanage_handle_t * handle,
|
||||
{
|
||||
|
||||
if (dbase_policydb_init(handle,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
&SEMANAGE_NODE_RTABLE,
|
||||
&SEMANAGE_NODE_POLICYDB_RTABLE,
|
||||
&dconfig->dbase) < 0)
|
||||
|
@ -52,6 +52,14 @@ struct semanage_policy_table {
|
||||
/* Install a policy module */
|
||||
int (*install_file) (struct semanage_handle *, const char *);
|
||||
|
||||
/* Extract a policy module */
|
||||
int (*extract) (struct semanage_handle *,
|
||||
semanage_module_key_t *,
|
||||
int extract_cil,
|
||||
void **,
|
||||
size_t *,
|
||||
semanage_module_info_t **);
|
||||
|
||||
/* Remove a policy module */
|
||||
int (*remove) (struct semanage_handle *, char *);
|
||||
|
||||
|
@ -50,10 +50,8 @@ int port_policydb_dbase_init(semanage_handle_t * handle,
|
||||
{
|
||||
|
||||
if (dbase_policydb_init(handle,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
&SEMANAGE_PORT_RTABLE,
|
||||
&SEMANAGE_PORT_POLICYDB_RTABLE,
|
||||
&dconfig->dbase) < 0)
|
||||
|
@ -110,10 +110,14 @@ static const char *semanage_sandbox_paths[SEMANAGE_STORE_NUM_PATHS] = {
|
||||
"/disable_dontaudit",
|
||||
"/preserve_tunables",
|
||||
"/modules/disabled",
|
||||
"/policy.kern",
|
||||
"/file_contexts.local",
|
||||
"/file_contexts",
|
||||
"/seusers"
|
||||
};
|
||||
|
||||
static char const * const semanage_final_prefix[SEMANAGE_FINAL_NUM] = {
|
||||
"/tmp",
|
||||
"/final",
|
||||
"",
|
||||
};
|
||||
|
||||
@ -664,7 +668,7 @@ static int semanage_filename_select(const struct dirent *d)
|
||||
|
||||
/* Copies a file from src to dst. If dst already exists then
|
||||
* overwrite it. Returns 0 on success, -1 on error. */
|
||||
static int semanage_copy_file(const char *src, const char *dst, mode_t mode)
|
||||
int semanage_copy_file(const char *src, const char *dst, mode_t mode)
|
||||
{
|
||||
int in, out, retval = 0, amount_read, n, errsv = errno;
|
||||
char tmp[PATH_MAX];
|
||||
@ -943,9 +947,7 @@ int semanage_make_final(semanage_handle_t *sh)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Copy in exported databases.
|
||||
* i = 1 to avoid copying the top level directory.
|
||||
*/
|
||||
// Build final directory structure
|
||||
int i;
|
||||
for (i = 1; i < SEMANAGE_FINAL_PATH_NUM; i++) {
|
||||
if (strlen(semanage_final_path(SEMANAGE_FINAL_TMP, i)) >= sizeof(fn)) {
|
||||
@ -959,12 +961,6 @@ int semanage_make_final(semanage_handle_t *sh)
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
semanage_copy_file(
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX, i),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, i),
|
||||
sh->conf->file_mode);
|
||||
/* ignore errors, these files may not exist */
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@ -1431,11 +1427,11 @@ int semanage_split_fc(semanage_handle_t * sh)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fc = open(semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC),
|
||||
fc = open(semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC),
|
||||
O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
|
||||
if (fc < 0) {
|
||||
ERR(sh, "Could not open %s for writing.",
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_FC));
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC));
|
||||
goto cleanup;
|
||||
}
|
||||
hd = open(semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL),
|
||||
@ -1460,8 +1456,7 @@ int semanage_split_fc(semanage_handle_t * sh)
|
||||
} else {
|
||||
if (write(fc, buf, strlen(buf)) < 0) {
|
||||
ERR(sh, "Write to %s failed.",
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_FC));
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_FC));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -2019,8 +2014,7 @@ int semanage_read_policydb(semanage_handle_t * sh, sepol_policydb_t * in)
|
||||
FILE *infile = NULL;
|
||||
|
||||
if ((kernel_filename =
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL)) == NULL) {
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL)) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
if ((infile = fopen(kernel_filename, "r")) == NULL) {
|
||||
@ -2061,7 +2055,7 @@ int semanage_write_policydb(semanage_handle_t * sh, sepol_policydb_t * out)
|
||||
FILE *outfile = NULL;
|
||||
|
||||
if ((kernel_filename =
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_KERNEL)) == NULL) {
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL)) == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
if ((outfile = fopen(kernel_filename, "wb")) == NULL) {
|
||||
|
@ -55,6 +55,10 @@ enum semanage_sandbox_defs {
|
||||
SEMANAGE_DISABLE_DONTAUDIT,
|
||||
SEMANAGE_PRESERVE_TUNABLES,
|
||||
SEMANAGE_MODULES_DISABLED,
|
||||
SEMANAGE_STORE_KERNEL,
|
||||
SEMANAGE_STORE_FC_LOCAL,
|
||||
SEMANAGE_STORE_FC,
|
||||
SEMANAGE_STORE_SEUSERS,
|
||||
SEMANAGE_STORE_NUM_PATHS
|
||||
};
|
||||
|
||||
@ -148,4 +152,6 @@ int semanage_nc_sort(semanage_handle_t * sh,
|
||||
size_t buf_len,
|
||||
char **sorted_buf, size_t * sorted_buf_len);
|
||||
|
||||
int semanage_copy_file(const char *src, const char *dst, mode_t mode);
|
||||
|
||||
#endif
|
||||
|
@ -23,6 +23,7 @@
|
||||
%header %{
|
||||
#include <stdlib.h>
|
||||
#include <semanage/semanage.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define STATUS_SUCCESS 0
|
||||
#define STATUS_ERR -1
|
||||
@ -103,6 +104,10 @@
|
||||
%apply int *OUTPUT { unsigned int * };
|
||||
%apply int *OUTPUT { uint16_t * };
|
||||
|
||||
%include <cstring.i>
|
||||
/* This is needed to properly mmaped binary data in SWIG */
|
||||
%cstring_output_allocate_size(void **mapped_data, size_t *data_len, munmap(*$1, *$2));
|
||||
|
||||
%typemap(in, numinputs=0) char **(char *temp=NULL) {
|
||||
$1 = &temp;
|
||||
}
|
||||
|
@ -50,10 +50,8 @@ int user_base_policydb_dbase_init(semanage_handle_t * handle,
|
||||
{
|
||||
|
||||
if (dbase_policydb_init(handle,
|
||||
semanage_final_path(SEMANAGE_FINAL_SELINUX,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_final_path(SEMANAGE_FINAL_TMP,
|
||||
SEMANAGE_KERNEL),
|
||||
semanage_path(SEMANAGE_ACTIVE, SEMANAGE_STORE_KERNEL),
|
||||
semanage_path(SEMANAGE_TMP, SEMANAGE_STORE_KERNEL),
|
||||
&SEMANAGE_USER_BASE_RTABLE,
|
||||
&SEMANAGE_USER_BASE_POLICYDB_RTABLE,
|
||||
&dconfig->dbase) < 0)
|
||||
|
@ -10,7 +10,7 @@ from optparse import OptionParser
|
||||
|
||||
import ctypes
|
||||
|
||||
sepol = ctypes.cdll.LoadLibrary('libsepol.so')
|
||||
sepol = ctypes.cdll.LoadLibrary('libsepol.so.1')
|
||||
|
||||
try:
|
||||
import selinux
|
||||
@ -180,7 +180,7 @@ def rebuild_policy():
|
||||
|
||||
|
||||
def oldroot_path():
|
||||
return "/etc/selinux"
|
||||
return "%s/etc/selinux" % ROOT
|
||||
|
||||
def oldstore_path(store):
|
||||
return "%s/%s/modules/active" % (oldroot_path(), store)
|
||||
@ -192,7 +192,7 @@ def disabledmodules_path(store):
|
||||
return "%s/disabled" % newmodules_path(store)
|
||||
|
||||
def newroot_path():
|
||||
return PATH
|
||||
return "%s%s" % (ROOT, PATH)
|
||||
|
||||
def newstore_path(store):
|
||||
return "%s/%s/active" % (newroot_path(), store)
|
||||
@ -219,6 +219,8 @@ if __name__ == "__main__":
|
||||
help="Disable rebuilding policy after migration (default: no)")
|
||||
parser.add_option("-P", "--path", dest="path",
|
||||
help="Set path for the policy store (default: /var/lib/selinux)")
|
||||
parser.add_option("-r", "--root", dest="root",
|
||||
help="Set an alternative root for the migration (default: /)")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
@ -231,6 +233,10 @@ if __name__ == "__main__":
|
||||
if PATH is None:
|
||||
PATH = "/var/lib/selinux"
|
||||
|
||||
ROOT = options.root
|
||||
if ROOT is None:
|
||||
ROOT = ""
|
||||
|
||||
# List of paths that go in the active 'root'
|
||||
TOPPATHS = [
|
||||
"commit_num",
|
||||
@ -241,9 +247,13 @@ if __name__ == "__main__":
|
||||
"file_contexts.local",
|
||||
"seusers",
|
||||
"users.local",
|
||||
"users_extra",
|
||||
"users_extra.local",
|
||||
"disable_dontaudit",
|
||||
"preserve_tunables" ]
|
||||
"preserve_tunables",
|
||||
"policy.kern",
|
||||
"file_contexts",
|
||||
"homedir_template"]
|
||||
|
||||
|
||||
create_dir(newroot_path(), 0o755)
|
||||
|
@ -46,6 +46,7 @@ cil_src_files := \
|
||||
cil/src/cil_build_ast.c \
|
||||
cil/src/cil.c \
|
||||
cil/src/cil_copy_ast.c \
|
||||
cil/src/cil_find.c \
|
||||
cil/src/cil_fqn.c \
|
||||
cil/src/cil_lexer.l \
|
||||
cil/src/cil_list.c \
|
||||
|
@ -1,8 +1,25 @@
|
||||
* Add neverallow support for ioctl extended permissions, from Jeff Vander Stoep.
|
||||
* Improve CIL block and macro call recursion detection, from Steve Lawrence
|
||||
* Fix CIL uninitialized false positive in cil_binary, from Yuli Khodorkovskiy
|
||||
* Provide error in CIL if classperms are empty, from Yuli Khodorkovskiy
|
||||
* Add userattribute{set} functionality to CIL, from Yuli Khodorkovskiy
|
||||
* fix CIL blockinherit copying segfault and add macro restrictions, from Steve Lawrence
|
||||
* fix CIL NULL pointer dereference when copying classpermission/set, from Steve Lawrence
|
||||
* Add CIL support for ioctl whitelists, from Steve Lawrence
|
||||
* Fix memory leak when destroying avtab, from Steve Lawrence
|
||||
* Replace sscanf in module_to_cil, from Yuli Khodorkovskiy.
|
||||
* Improve CIL resolution error messages, from Steve Lawrence
|
||||
* Fix policydb_read for policy versions < 24, from Stephen Smalley.
|
||||
* Added CIL bounds checking and refactored CIL Neverallow checking, from James Carter
|
||||
* Refactored libsepol Neverallow and bounds (hierarchy) checking, from James Carter
|
||||
* Treat types like an attribute in the attr_type_map, from James Carter
|
||||
* Add new ebitmap function named ebitmap_match_any(), from James Carter
|
||||
* switch operations to extended perms, from Jeff Vander Stoep.
|
||||
* Write auditadm_r and secadm_r roles to base module when writing CIL, from Steve Lawrence
|
||||
* Fix module to CIL to only associate declared roleattributes with in-scope types, from Steve Lawrence
|
||||
* Don't allow categories/sensitivities inside blocks in CIL, from Yuli Khodorkovskiy.
|
||||
* Replace fmemopen() with internal function in libsepol, from James Carter.
|
||||
* Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy.
|
||||
* Verify users prior to evaluating users in cil, from Yuli Khodorkovskiy.
|
||||
* Binary modules do not support ioctl rules, from Stephen Smalley.
|
||||
* Add support for ioctl command whitelisting, from Jeff Vander Stoep.
|
||||
* Don't use symbol versioning for static object files, from Yuli Khodorkovskiy.
|
||||
|
@ -70,11 +70,11 @@ asm(".symver cil_filecons_to_string_nopdb, cil_filecons_to_string@@LIBSEPOL_1.1"
|
||||
#endif
|
||||
|
||||
int cil_sym_sizes[CIL_SYM_ARRAY_NUM][CIL_SYM_NUM] = {
|
||||
{64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
|
||||
{64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
{64, 64, 64, 1 << 13, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
|
||||
{64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
};
|
||||
|
||||
static void cil_init_keys(void)
|
||||
@ -122,6 +122,8 @@ static void cil_init_keys(void)
|
||||
CIL_KEY_TYPE = cil_strpool_add("type");
|
||||
CIL_KEY_ROLE = cil_strpool_add("role");
|
||||
CIL_KEY_USER = cil_strpool_add("user");
|
||||
CIL_KEY_USERATTRIBUTE = cil_strpool_add("userattribute");
|
||||
CIL_KEY_USERATTRIBUTESET = cil_strpool_add("userattributeset");
|
||||
CIL_KEY_SENSITIVITY = cil_strpool_add("sensitivity");
|
||||
CIL_KEY_CATEGORY = cil_strpool_add("category");
|
||||
CIL_KEY_CATSET = cil_strpool_add("categoryset");
|
||||
@ -223,6 +225,11 @@ static void cil_init_keys(void)
|
||||
CIL_KEY_ROOT = cil_strpool_add("<root>");
|
||||
CIL_KEY_NODE = cil_strpool_add("<node>");
|
||||
CIL_KEY_PERM = cil_strpool_add("perm");
|
||||
CIL_KEY_ALLOWX = cil_strpool_add("allowx");
|
||||
CIL_KEY_AUDITALLOWX = cil_strpool_add("auditallowx");
|
||||
CIL_KEY_DONTAUDITX = cil_strpool_add("dontauditx");
|
||||
CIL_KEY_PERMISSIONX = cil_strpool_add("permissionx");
|
||||
CIL_KEY_IOCTL = cil_strpool_add("ioctl");
|
||||
}
|
||||
|
||||
void cil_db_init(struct cil_db **db)
|
||||
@ -257,12 +264,15 @@ void cil_db_init(struct cil_db **db)
|
||||
cil_type_init(&(*db)->selftype);
|
||||
(*db)->selftype->datum.name = CIL_KEY_SELF;
|
||||
(*db)->selftype->datum.fqn = CIL_KEY_SELF;
|
||||
|
||||
(*db)->num_types_and_attrs = 0;
|
||||
(*db)->num_classes = 0;
|
||||
(*db)->num_types = 0;
|
||||
(*db)->num_roles = 0;
|
||||
(*db)->num_users = 0;
|
||||
(*db)->num_cats = 0;
|
||||
(*db)->val_to_type = NULL;
|
||||
(*db)->val_to_role = NULL;
|
||||
(*db)->val_to_user = NULL;
|
||||
|
||||
(*db)->disable_dontaudit = CIL_FALSE;
|
||||
(*db)->disable_neverallow = CIL_FALSE;
|
||||
@ -305,6 +315,7 @@ void cil_db_destroy(struct cil_db **db)
|
||||
cil_strpool_destroy();
|
||||
free((*db)->val_to_type);
|
||||
free((*db)->val_to_role);
|
||||
free((*db)->val_to_user);
|
||||
|
||||
free(*db);
|
||||
*db = NULL;
|
||||
@ -340,7 +351,7 @@ int cil_add_file(cil_db_t *db, char *name, char *data, size_t size)
|
||||
|
||||
rc = cil_parser(name, buffer, size + 2, &db->parse);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to parse %s\n", name);
|
||||
cil_log(CIL_INFO, "Failed to parse %s\n", name);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -370,7 +381,7 @@ int cil_compile_nopdb(struct cil_db *db)
|
||||
cil_log(CIL_INFO, "Building AST from Parse Tree\n");
|
||||
rc = cil_build_ast(db, db->parse->root, db->ast->root);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to build ast\n");
|
||||
cil_log(CIL_INFO, "Failed to build ast\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -380,21 +391,21 @@ int cil_compile_nopdb(struct cil_db *db)
|
||||
cil_log(CIL_INFO, "Resolving AST\n");
|
||||
rc = cil_resolve_ast(db, db->ast->root);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to resolve ast\n");
|
||||
cil_log(CIL_INFO, "Failed to resolve ast\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_log(CIL_INFO, "Qualifying Names\n");
|
||||
rc = cil_fqn_qualify(db->ast->root);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to qualify names\n");
|
||||
cil_log(CIL_INFO, "Failed to qualify names\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_log(CIL_INFO, "Compile post process\n");
|
||||
rc = cil_post_process(db);
|
||||
if (rc != SEPOL_OK ) {
|
||||
cil_log(CIL_ERR, "Post process failed\n");
|
||||
cil_log(CIL_INFO, "Post process failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -546,6 +557,12 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
|
||||
case CIL_USER:
|
||||
cil_destroy_user(*data);
|
||||
break;
|
||||
case CIL_USERATTRIBUTE:
|
||||
cil_destroy_userattribute(*data);
|
||||
break;
|
||||
case CIL_USERATTRIBUTESET:
|
||||
cil_destroy_userattributeset(*data);
|
||||
break;
|
||||
case CIL_USERPREFIX:
|
||||
cil_destroy_userprefix(*data);
|
||||
break;
|
||||
@ -652,6 +669,12 @@ void cil_destroy_data(void **data, enum cil_flavor flavor)
|
||||
case CIL_AVRULE:
|
||||
cil_destroy_avrule(*data);
|
||||
break;
|
||||
case CIL_AVRULEX:
|
||||
cil_destroy_avrulex(*data);
|
||||
break;
|
||||
case CIL_PERMISSIONX:
|
||||
cil_destroy_permissionx(*data);
|
||||
break;
|
||||
case CIL_ROLETRANSITION:
|
||||
cil_destroy_roletransition(*data);
|
||||
break;
|
||||
@ -782,6 +805,7 @@ int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_i
|
||||
*sym_index = CIL_SYM_CLASSPERMSETS;
|
||||
break;
|
||||
case CIL_USER:
|
||||
case CIL_USERATTRIBUTE:
|
||||
*sym_index = CIL_SYM_USERS;
|
||||
break;
|
||||
case CIL_ROLE:
|
||||
@ -823,6 +847,9 @@ int cil_flavor_to_symtab_index(enum cil_flavor flavor, enum cil_sym_index *sym_i
|
||||
case CIL_POLICYCAP:
|
||||
*sym_index = CIL_SYM_POLICYCAPS;
|
||||
break;
|
||||
case CIL_PERMISSIONX:
|
||||
*sym_index = CIL_SYM_PERMX;
|
||||
break;
|
||||
default:
|
||||
*sym_index = CIL_SYM_UNKNOWN;
|
||||
cil_log(CIL_INFO, "Failed to find flavor: %d\n", flavor);
|
||||
@ -909,6 +936,10 @@ const char * cil_node_to_string(struct cil_tree_node *node)
|
||||
return CIL_KEY_CLASSPERMISSIONSET;
|
||||
case CIL_USER:
|
||||
return CIL_KEY_USER;
|
||||
case CIL_USERATTRIBUTE:
|
||||
return CIL_KEY_USERATTRIBUTE;
|
||||
case CIL_USERATTRIBUTESET:
|
||||
return CIL_KEY_USERATTRIBUTESET;
|
||||
case CIL_USERPREFIX:
|
||||
return CIL_KEY_USERPREFIX;
|
||||
case CIL_USERROLE:
|
||||
@ -993,6 +1024,20 @@ const char * cil_node_to_string(struct cil_tree_node *node)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CIL_AVRULEX:
|
||||
switch (((struct cil_avrulex *)node->data)->rule_kind) {
|
||||
case CIL_AVRULE_ALLOWED:
|
||||
return CIL_KEY_ALLOWX;
|
||||
case CIL_AVRULE_AUDITALLOW:
|
||||
return CIL_KEY_AUDITALLOWX;
|
||||
case CIL_AVRULE_DONTAUDIT:
|
||||
return CIL_KEY_DONTAUDITX;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case CIL_PERMISSIONX:
|
||||
return CIL_KEY_PERMISSIONX;
|
||||
case CIL_ROLETRANSITION:
|
||||
return CIL_KEY_ROLETRANSITION;
|
||||
case CIL_TYPE_RULE:
|
||||
@ -2078,6 +2123,31 @@ void cil_avrule_init(struct cil_avrule **avrule)
|
||||
(*avrule)->classperms = NULL;
|
||||
}
|
||||
|
||||
void cil_permissionx_init(struct cil_permissionx **permx)
|
||||
{
|
||||
*permx = cil_malloc(sizeof(**permx));
|
||||
|
||||
cil_symtab_datum_init(&(*permx)->datum);
|
||||
(*permx)->kind = CIL_NONE;
|
||||
(*permx)->obj_str = NULL;
|
||||
(*permx)->obj = NULL;
|
||||
(*permx)->expr_str = NULL;
|
||||
(*permx)->perms = NULL;
|
||||
}
|
||||
|
||||
void cil_avrulex_init(struct cil_avrulex **avrule)
|
||||
{
|
||||
*avrule = cil_malloc(sizeof(**avrule));
|
||||
|
||||
(*avrule)->rule_kind = CIL_NONE;
|
||||
(*avrule)->src_str = NULL;
|
||||
(*avrule)->src = NULL;
|
||||
(*avrule)->tgt_str = NULL;
|
||||
(*avrule)->tgt = NULL;
|
||||
(*avrule)->permx_str = NULL;
|
||||
(*avrule)->permx = NULL;
|
||||
}
|
||||
|
||||
void cil_type_rule_init(struct cil_type_rule **type_rule)
|
||||
{
|
||||
*type_rule = cil_malloc(sizeof(**type_rule));
|
||||
@ -2325,6 +2395,26 @@ void cil_user_init(struct cil_user **user)
|
||||
(*user)->roles = NULL;
|
||||
(*user)->dftlevel = NULL;
|
||||
(*user)->range = NULL;
|
||||
(*user)->value = 0;
|
||||
}
|
||||
|
||||
void cil_userattribute_init(struct cil_userattribute **attr)
|
||||
{
|
||||
*attr = cil_malloc(sizeof(**attr));
|
||||
|
||||
cil_symtab_datum_init(&(*attr)->datum);
|
||||
|
||||
(*attr)->expr_list = NULL;
|
||||
(*attr)->users = NULL;
|
||||
}
|
||||
|
||||
void cil_userattributeset_init(struct cil_userattributeset **attrset)
|
||||
{
|
||||
*attrset = cil_malloc(sizeof(**attrset));
|
||||
|
||||
(*attrset)->attr_str = NULL;
|
||||
(*attrset)->str_expr = NULL;
|
||||
(*attrset)->datum_expr = NULL;
|
||||
}
|
||||
|
||||
void cil_userlevel_init(struct cil_userlevel **usrlvl)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -112,7 +112,7 @@ int cil_roletype_to_policydb(policydb_t *pdb, const struct cil_db *db, struct ci
|
||||
*
|
||||
* @return SEPOL_OK upon success or an error otherwise.
|
||||
*/
|
||||
int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type);
|
||||
int cil_type_to_policydb(policydb_t *pdb, struct cil_type *cil_type, void *type_value_to_cil[]);
|
||||
|
||||
/**
|
||||
* Insert cil typealias structure into sepol policydb.
|
||||
@ -144,7 +144,7 @@ int cil_typepermissive_to_policydb(policydb_t *pdb, struct cil_typepermissive *c
|
||||
*
|
||||
* @return SEPOL_OK upon success or an error otherwise.
|
||||
*/
|
||||
int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr);
|
||||
int cil_typeattribute_to_policydb(policydb_t *pdb, struct cil_typeattribute *cil_attr, void *type_value_to_cil[]);
|
||||
|
||||
/**
|
||||
* Insert cil attribute structure into sepol type->attribute bitmap.
|
||||
@ -184,12 +184,13 @@ int cil_user_to_policydb(policydb_t *pdb, struct cil_user *cil_user);
|
||||
/**
|
||||
* Insert cil userrole structure into sepol policydb.
|
||||
*
|
||||
* @param[in] pdb THe policy database to insert the userrole into.
|
||||
* @param[in] datum The cil_userrole datum.
|
||||
* @param[in] pdb The policy database to insert the userrole into.
|
||||
* @param[in] db The cil database
|
||||
* @param[in] datum The cil_user
|
||||
*
|
||||
* @return SEPOL_OK upon success or SEPOL_ERR otherwise.
|
||||
*/
|
||||
int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_userrole *userrole);
|
||||
int cil_userrole_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_user *user);
|
||||
|
||||
/**
|
||||
* Insert cil bool structure into sepol policydb.
|
||||
@ -250,7 +251,7 @@ int cil_type_rule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct c
|
||||
*
|
||||
* @return SEPOL_OK upon success or an error otherwise.
|
||||
*/
|
||||
int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule, struct cil_list *neverallows);
|
||||
int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_avrule *cil_avrule);
|
||||
|
||||
/**
|
||||
* Insert cil booleanif structure into sepol policydb. This populates the
|
||||
@ -262,7 +263,7 @@ int cil_avrule_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_
|
||||
*
|
||||
* @return SEPOL_OK upon success or an error otherwise.
|
||||
*/
|
||||
int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, struct cil_list *neverallows, hashtab_t filename_trans_table);
|
||||
int cil_booleanif_to_policydb(policydb_t *pdb, const struct cil_db *db, struct cil_tree_node *node, hashtab_t filename_trans_table);
|
||||
|
||||
/**
|
||||
* Insert cil role transition structure into sepol policydb.
|
||||
|
@ -1196,10 +1196,132 @@ void cil_destroy_user(struct cil_user *user)
|
||||
}
|
||||
|
||||
cil_symtab_datum_destroy(&user->datum);
|
||||
cil_list_destroy(&user->roles, CIL_FALSE);
|
||||
ebitmap_destroy(user->roles);
|
||||
free(user->roles);
|
||||
free(user);
|
||||
}
|
||||
|
||||
int cil_gen_userattribute(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_END
|
||||
};
|
||||
int syntax_len = sizeof(syntax)/sizeof(*syntax);
|
||||
char *key = NULL;
|
||||
struct cil_userattribute *attr = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
if (parse_current == NULL || ast_node == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_userattribute_init(&attr);
|
||||
|
||||
key = parse_current->next->data;
|
||||
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)attr, (hashtab_key_t)key, CIL_SYM_USERS, CIL_USERATTRIBUTE);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Bad userattribute declaration at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_destroy_userattribute(attr);
|
||||
cil_clear_node(ast_node);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_destroy_userattribute(struct cil_userattribute *attr)
|
||||
{
|
||||
struct cil_list_item *expr = NULL;
|
||||
struct cil_list_item *next = NULL;
|
||||
|
||||
if (attr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr->expr_list != NULL) {
|
||||
/* we don't want to destroy the expression stacks (cil_list) inside
|
||||
* this list cil_list_destroy destroys sublists, so we need to do it
|
||||
* manually */
|
||||
expr = attr->expr_list->head;
|
||||
while (expr != NULL) {
|
||||
next = expr->next;
|
||||
cil_list_item_destroy(&expr, CIL_FALSE);
|
||||
expr = next;
|
||||
}
|
||||
free(attr->expr_list);
|
||||
attr->expr_list = NULL;
|
||||
}
|
||||
|
||||
cil_symtab_datum_destroy(&attr->datum);
|
||||
ebitmap_destroy(attr->users);
|
||||
free(attr->users);
|
||||
free(attr);
|
||||
}
|
||||
|
||||
int cil_gen_userattributeset(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING | CIL_SYN_LIST,
|
||||
CIL_SYN_END
|
||||
};
|
||||
int syntax_len = sizeof(syntax)/sizeof(*syntax);
|
||||
struct cil_userattributeset *attrset = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
if (db == NULL || parse_current == NULL || ast_node == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_userattributeset_init(&attrset);
|
||||
|
||||
attrset->attr_str = parse_current->next->data;
|
||||
|
||||
rc = cil_gen_expr(parse_current->next->next, CIL_USER, &attrset->str_expr);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
ast_node->data = attrset;
|
||||
ast_node->flavor = CIL_USERATTRIBUTESET;
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Bad userattributeset declaration at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_destroy_userattributeset(attrset);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_destroy_userattributeset(struct cil_userattributeset *attrset)
|
||||
{
|
||||
if (attrset == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cil_list_destroy(&attrset->str_expr, CIL_TRUE);
|
||||
cil_list_destroy(&attrset->datum_expr, CIL_FALSE);
|
||||
|
||||
free(attrset);
|
||||
}
|
||||
|
||||
int cil_gen_userlevel(__attribute__((unused)) struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
@ -1903,6 +2025,169 @@ void cil_destroy_avrule(struct cil_avrule *rule)
|
||||
free(rule);
|
||||
}
|
||||
|
||||
int cil_fill_permissionx(struct cil_tree_node *parse_current, struct cil_permissionx *permx)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_LIST,
|
||||
CIL_SYN_END
|
||||
};
|
||||
int syntax_len = sizeof(syntax)/sizeof(*syntax);
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (parse_current->data == CIL_KEY_IOCTL) {
|
||||
permx->kind = CIL_PERMX_KIND_IOCTL;
|
||||
} else {
|
||||
cil_log(CIL_ERR, "Unknown permissionx kind, %s. Must be \"ioctl\"\n", (char *)parse_current->data);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
permx->obj_str = parse_current->next->data;
|
||||
|
||||
rc = cil_gen_expr(parse_current->next->next, CIL_PERMISSIONX, &permx->expr_str);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Bad permissionx content at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_LIST,
|
||||
CIL_SYN_END
|
||||
};
|
||||
int syntax_len = sizeof(syntax)/sizeof(*syntax);
|
||||
char *key = NULL;
|
||||
struct cil_permissionx *permx = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
if (parse_current == NULL || ast_node == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_permissionx_init(&permx);
|
||||
|
||||
key = parse_current->next->data;
|
||||
|
||||
rc = cil_gen_node(db, ast_node, (struct cil_symtab_datum*)permx, (hashtab_key_t)key, CIL_SYM_PERMX, CIL_PERMISSIONX);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_fill_permissionx(parse_current->next->next->cl_head, permx);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Bad permissionx statement at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_destroy_permissionx(permx);
|
||||
cil_clear_node(ast_node);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_destroy_permissionx(struct cil_permissionx *permx)
|
||||
{
|
||||
if (permx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cil_symtab_datum_destroy(&permx->datum);
|
||||
|
||||
cil_list_destroy(&permx->expr_str, CIL_TRUE);
|
||||
ebitmap_destroy(permx->perms);
|
||||
free(permx->perms);
|
||||
free(permx);
|
||||
}
|
||||
|
||||
int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING,
|
||||
CIL_SYN_STRING | CIL_SYN_LIST,
|
||||
CIL_SYN_END
|
||||
};
|
||||
int syntax_len = sizeof(syntax)/sizeof(*syntax);
|
||||
struct cil_avrulex *rule = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
if (parse_current == NULL || ast_node == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cil_avrulex_init(&rule);
|
||||
|
||||
rule->rule_kind = rule_kind;
|
||||
rule->src_str = parse_current->next->data;
|
||||
rule->tgt_str = parse_current->next->next->data;
|
||||
|
||||
if (parse_current->next->next->next->cl_head == NULL) {
|
||||
rule->permx_str = parse_current->next->next->next->data;
|
||||
} else {
|
||||
cil_permissionx_init(&rule->permx);
|
||||
|
||||
rc = cil_fill_permissionx(parse_current->next->next->next->cl_head, rule->permx);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
ast_node->data = rule;
|
||||
ast_node->flavor = CIL_AVRULEX;
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
cil_log(CIL_ERR, "Bad allowx rule at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_destroy_avrulex(rule);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_destroy_avrulex(struct cil_avrulex *rule)
|
||||
{
|
||||
if (rule == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rule->permx_str == NULL && rule->permx != NULL) {
|
||||
cil_destroy_permissionx(rule->permx);
|
||||
}
|
||||
|
||||
free(rule);
|
||||
}
|
||||
|
||||
int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind)
|
||||
{
|
||||
enum cil_syntax syntax[] = {
|
||||
@ -2217,8 +2502,8 @@ static enum cil_flavor __cil_get_expr_operator_flavor(const char *op)
|
||||
else if (op == CIL_KEY_EQ) return CIL_EQ; /* Only conditional */
|
||||
else if (op == CIL_KEY_NEQ) return CIL_NEQ; /* Only conditional */
|
||||
else if (op == CIL_KEY_XOR) return CIL_XOR;
|
||||
else if (op == CIL_KEY_ALL) return CIL_ALL; /* Only set */
|
||||
else if (op == CIL_KEY_RANGE) return CIL_RANGE; /* Only catset */
|
||||
else if (op == CIL_KEY_ALL) return CIL_ALL; /* Only set and permissionx */
|
||||
else if (op == CIL_KEY_RANGE) return CIL_RANGE; /* Only catset and permissionx */
|
||||
else return CIL_NONE;
|
||||
}
|
||||
|
||||
@ -5587,27 +5872,14 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
|
||||
}
|
||||
|
||||
if (macro != NULL) {
|
||||
if (parse_current->data == CIL_KEY_MACRO) {
|
||||
if (parse_current->data == CIL_KEY_MACRO ||
|
||||
parse_current->data == CIL_KEY_TUNABLE ||
|
||||
parse_current->data == CIL_KEY_IN ||
|
||||
parse_current->data == CIL_KEY_BLOCK ||
|
||||
parse_current->data == CIL_KEY_BLOCKINHERIT ||
|
||||
parse_current->data == CIL_KEY_BLOCKABSTRACT) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Found macro at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_log(CIL_ERR, "Macros cannot be defined within macro statement\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (parse_current->data == CIL_KEY_TUNABLE) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Found tunable at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_log(CIL_ERR, "Tunables cannot be defined within macro statement\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (parse_current->data == CIL_KEY_IN) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Found in at line %d of %s\n",
|
||||
parse_current->line, parse_current->path);
|
||||
cil_log(CIL_ERR, "in-statements cannot be defined within macro statement\n");
|
||||
cil_log(CIL_ERR, "%s is not allowed in macros (%s:%d)\n", (char *)parse_current->data, parse_current->path, parse_current->line);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@ -5705,6 +5977,11 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_USER) {
|
||||
rc = cil_gen_user(db, parse_current, ast_node);
|
||||
} else if (parse_current->data == CIL_KEY_USERATTRIBUTE) {
|
||||
rc = cil_gen_userattribute(db, parse_current, ast_node);
|
||||
} else if (parse_current->data == CIL_KEY_USERATTRIBUTESET) {
|
||||
rc = cil_gen_userattributeset(db, parse_current, ast_node);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_USERLEVEL) {
|
||||
rc = cil_gen_userlevel(db, parse_current, ast_node);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
@ -5789,6 +6066,18 @@ int __cil_build_ast_node_helper(struct cil_tree_node *parse_current, uint32_t *f
|
||||
} else if (parse_current->data == CIL_KEY_NEVERALLOW) {
|
||||
rc = cil_gen_avrule(parse_current, ast_node, CIL_AVRULE_NEVERALLOW);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_ALLOWX) {
|
||||
rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_ALLOWED);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_AUDITALLOWX) {
|
||||
rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_AUDITALLOW);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_DONTAUDITX) {
|
||||
rc = cil_gen_avrulex(parse_current, ast_node, CIL_AVRULE_DONTAUDIT);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_PERMISSIONX) {
|
||||
rc = cil_gen_permissionx(db, parse_current, ast_node);
|
||||
*finished = CIL_TREE_SKIP_NEXT;
|
||||
} else if (parse_current->data == CIL_KEY_TYPETRANSITION) {
|
||||
rc = cil_gen_typetransition(db, parse_current, ast_node);
|
||||
} else if (parse_current->data == CIL_KEY_TYPECHANGE) {
|
||||
|
@ -80,6 +80,10 @@ int cil_gen_sidorder(struct cil_db *db, struct cil_tree_node *parse_current, str
|
||||
void cil_destroy_sidorder(struct cil_sidorder *sidorder);
|
||||
int cil_gen_user(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
void cil_destroy_user(struct cil_user *user);
|
||||
int cil_gen_userattribute(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
void cil_destroy_userattribute(struct cil_userattribute *attr);
|
||||
int cil_gen_userattributeset(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
void cil_destroy_userattributeset(struct cil_userattributeset *attrset);
|
||||
int cil_gen_userlevel(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
void cil_destroy_userlevel(struct cil_userlevel *usrlvl);
|
||||
int cil_gen_userrange(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
@ -107,6 +111,10 @@ void cil_destroy_roleattributeset(struct cil_roleattributeset *attrset);
|
||||
int cil_gen_rolebounds(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
|
||||
void cil_destroy_avrule(struct cil_avrule *rule);
|
||||
int cil_gen_avrulex(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
|
||||
void cil_destroy_avrulex(struct cil_avrulex *rule);
|
||||
int cil_gen_permissionx(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
void cil_destroy_permissionx(struct cil_permissionx *permx);
|
||||
int cil_gen_type_rule(struct cil_tree_node *parse_current, struct cil_tree_node *ast_node, uint32_t rule_kind);
|
||||
void cil_destroy_type_rule(struct cil_type_rule *rule);
|
||||
int cil_gen_type(struct cil_db *db, struct cil_tree_node *parse_current, struct cil_tree_node *ast_node);
|
||||
|
@ -282,6 +282,8 @@ int cil_copy_classpermission(__attribute__((unused)) struct cil_db *db, void *da
|
||||
}
|
||||
}
|
||||
|
||||
cil_classpermission_init(&new);
|
||||
|
||||
cil_copy_classperms_list(orig->classperms, &new->classperms);
|
||||
|
||||
*copy = new;
|
||||
@ -294,6 +296,8 @@ int cil_copy_classpermissionset(__attribute__((unused)) struct cil_db *db, void
|
||||
struct cil_classpermissionset *orig = data;
|
||||
struct cil_classpermissionset *new = NULL;
|
||||
|
||||
cil_classpermissionset_init(&new);
|
||||
|
||||
new->set_str = orig->set_str;
|
||||
|
||||
cil_copy_classperms_list(orig->classperms, &new->classperms);
|
||||
@ -388,6 +392,41 @@ int cil_copy_user(__attribute__((unused)) struct cil_db *db, void *data, void **
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
int cil_copy_userattribute(__attribute__((unused)) struct cil_db *db, void *data, void **copy, symtab_t *symtab)
|
||||
{
|
||||
struct cil_userattribute *orig = data;
|
||||
struct cil_userattribute *new = NULL;
|
||||
char *key = orig->datum.name;
|
||||
struct cil_symtab_datum *datum = NULL;
|
||||
|
||||
cil_symtab_get_datum(symtab, key, &datum);
|
||||
if (datum == NULL) {
|
||||
cil_userattribute_init(&new);
|
||||
*copy = new;
|
||||
} else {
|
||||
*copy = datum;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
|
||||
{
|
||||
struct cil_userattributeset *orig = data;
|
||||
struct cil_userattributeset *new = NULL;
|
||||
|
||||
cil_userattributeset_init(&new);
|
||||
|
||||
new->attr_str = orig->attr_str;
|
||||
|
||||
cil_copy_expr(db, orig->str_expr, &new->str_expr);
|
||||
cil_copy_expr(db, orig->datum_expr, &new->datum_expr);
|
||||
|
||||
*copy = new;
|
||||
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
int cil_copy_userrole(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
|
||||
{
|
||||
struct cil_userrole *orig = data;
|
||||
@ -760,6 +799,59 @@ int cil_copy_avrule(__attribute__((unused)) struct cil_db *db, void *data, void
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
void cil_copy_fill_permissionx(struct cil_db *db, struct cil_permissionx *orig, struct cil_permissionx *new)
|
||||
{
|
||||
new->kind = orig->kind;
|
||||
new->obj_str = orig->obj_str;
|
||||
cil_copy_expr(db, orig->expr_str, &new->expr_str);
|
||||
}
|
||||
|
||||
int cil_copy_permissionx(struct cil_db *db, void *data, void **copy, symtab_t *symtab)
|
||||
{
|
||||
struct cil_permissionx *orig = data;
|
||||
struct cil_permissionx *new = NULL;
|
||||
char *key = orig->datum.name;
|
||||
struct cil_symtab_datum *datum = NULL;
|
||||
|
||||
|
||||
cil_symtab_get_datum(symtab, key, &datum);
|
||||
if (datum != NULL) {
|
||||
cil_log(CIL_INFO, "cil_copy_permissionx: permissionx cannot be redefined\n");
|
||||
return SEPOL_ERR;
|
||||
}
|
||||
|
||||
cil_permissionx_init(&new);
|
||||
cil_copy_fill_permissionx(db, orig, new);
|
||||
|
||||
*copy = new;
|
||||
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
|
||||
int cil_copy_avrulex(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
|
||||
{
|
||||
struct cil_avrulex *orig = data;
|
||||
struct cil_avrulex *new = NULL;
|
||||
|
||||
cil_avrulex_init(&new);
|
||||
|
||||
new->rule_kind = orig->rule_kind;
|
||||
new->src_str = orig->src_str;
|
||||
new->tgt_str = orig->tgt_str;
|
||||
|
||||
if (new->permx_str != NULL) {
|
||||
new->permx_str = orig->permx_str;
|
||||
} else {
|
||||
cil_permissionx_init(&new->permx);
|
||||
cil_copy_fill_permissionx(db, orig->permx, new->permx);
|
||||
}
|
||||
|
||||
*copy = new;
|
||||
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
int cil_copy_type_rule(__attribute__((unused)) struct cil_db *db, void *data, void **copy, __attribute__((unused)) symtab_t *symtab)
|
||||
{
|
||||
struct cil_type_rule *orig = data;
|
||||
@ -1660,6 +1752,12 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
|
||||
case CIL_USER:
|
||||
copy_func = &cil_copy_user;
|
||||
break;
|
||||
case CIL_USERATTRIBUTE:
|
||||
copy_func = &cil_copy_userattribute;
|
||||
break;
|
||||
case CIL_USERATTRIBUTESET:
|
||||
copy_func = &cil_copy_userattributeset;
|
||||
break;
|
||||
case CIL_USERROLE:
|
||||
copy_func = &cil_copy_userrole;
|
||||
break;
|
||||
@ -1732,6 +1830,12 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
|
||||
case CIL_AVRULE:
|
||||
copy_func = &cil_copy_avrule;
|
||||
break;
|
||||
case CIL_AVRULEX:
|
||||
copy_func = &cil_copy_avrulex;
|
||||
break;
|
||||
case CIL_PERMISSIONX:
|
||||
copy_func = &cil_copy_permissionx;
|
||||
break;
|
||||
case CIL_TYPE_RULE:
|
||||
copy_func = &cil_copy_type_rule;
|
||||
break;
|
||||
@ -1909,7 +2013,14 @@ int __cil_copy_node_helper(struct cil_tree_node *orig, __attribute__((unused)) u
|
||||
|
||||
if (new->flavor == CIL_BLOCKINHERIT) {
|
||||
blockinherit = new->data;
|
||||
cil_list_append(blockinherit->block->bi_nodes, CIL_NODE, new);
|
||||
// if a blockinherit statement is copied before blockinherit are
|
||||
// resolved (like in an in-statement), the block will not have been
|
||||
// resolved yet, so there's nothing to append yet. This is fine,
|
||||
// the copied blockinherit statement will be handled later, as if
|
||||
// it wasn't in an in-statement
|
||||
if (blockinherit->block != NULL) {
|
||||
cil_list_append(blockinherit->block->bi_nodes, CIL_NODE, new);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->cl_head == NULL) {
|
||||
|
@ -57,6 +57,8 @@ int cil_copy_sid(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_sidcontext(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_sidorder(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_user(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_userattribute(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_userattributeset(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_userrole(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_userlevel(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
int cil_copy_userrange(struct cil_db *db, void *data, void **copy, symtab_t *symtab);
|
||||
|
305
libsepol/cil/src/cil_find.c
Normal file
305
libsepol/cil/src/cil_find.c
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those
|
||||
* of the authors and should not be interpreted as representing official policies,
|
||||
* either expressed or implied, of Tresys Technology, LLC.
|
||||
*/
|
||||
|
||||
#include <sepol/policydb/ebitmap.h>
|
||||
|
||||
#include "cil_internal.h"
|
||||
#include "cil_flavor.h"
|
||||
#include "cil_list.h"
|
||||
#include "cil_log.h"
|
||||
#include "cil_symtab.h"
|
||||
|
||||
struct cil_args_find {
|
||||
enum cil_flavor flavor;
|
||||
void *target;
|
||||
struct cil_list *matching;
|
||||
int match_self;
|
||||
};
|
||||
|
||||
static int cil_type_match_any(struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
|
||||
{
|
||||
enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
|
||||
enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
|
||||
|
||||
if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
|
||||
struct cil_type *t1 = (struct cil_type *)d1;
|
||||
struct cil_type *t2 = (struct cil_type *)d2;
|
||||
if (t1->value == t2->value) {
|
||||
return CIL_TRUE;
|
||||
}
|
||||
} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
|
||||
struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
|
||||
struct cil_type *t = (struct cil_type *)d2;
|
||||
if (ebitmap_get_bit(a->types, t->value)) {
|
||||
return CIL_TRUE;
|
||||
}
|
||||
} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
|
||||
struct cil_type *t = (struct cil_type *)d1;
|
||||
struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
|
||||
if (ebitmap_get_bit(a->types, t->value)) {
|
||||
return CIL_TRUE;
|
||||
}
|
||||
} else {
|
||||
/* Both are attributes */
|
||||
struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
|
||||
struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
|
||||
return ebitmap_match_any(a1->types, a2->types);
|
||||
}
|
||||
return CIL_FALSE;
|
||||
}
|
||||
|
||||
static int cil_type_matches(ebitmap_t *matches, struct cil_symtab_datum *d1, struct cil_symtab_datum *d2)
|
||||
{
|
||||
int rc = SEPOL_OK;
|
||||
enum cil_flavor f1 = ((struct cil_tree_node*)d1->nodes->head->data)->flavor;
|
||||
enum cil_flavor f2 = ((struct cil_tree_node*)d2->nodes->head->data)->flavor;
|
||||
|
||||
if (f1 != CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
|
||||
struct cil_type *t1 = (struct cil_type *)d1;
|
||||
struct cil_type *t2 = (struct cil_type *)d2;
|
||||
if (t1->value == t2->value) {
|
||||
ebitmap_set_bit(matches, t1->value, 1);
|
||||
}
|
||||
} else if (f1 == CIL_TYPEATTRIBUTE && f2 != CIL_TYPEATTRIBUTE) {
|
||||
struct cil_typeattribute *a = (struct cil_typeattribute *)d1;
|
||||
struct cil_type *t = (struct cil_type *)d2;
|
||||
if (ebitmap_get_bit(a->types, t->value)) {
|
||||
ebitmap_set_bit(matches, t->value, 1);
|
||||
}
|
||||
} else if (f1 != CIL_TYPEATTRIBUTE && f2 == CIL_TYPEATTRIBUTE) {
|
||||
struct cil_type *t = (struct cil_type *)d1;
|
||||
struct cil_typeattribute *a = (struct cil_typeattribute *)d2;
|
||||
if (ebitmap_get_bit(a->types, t->value)) {
|
||||
ebitmap_set_bit(matches, t->value, 1);
|
||||
}
|
||||
} else {
|
||||
/* Both are attributes */
|
||||
struct cil_typeattribute *a1 = (struct cil_typeattribute *)d1;
|
||||
struct cil_typeattribute *a2 = (struct cil_typeattribute *)d2;
|
||||
rc = ebitmap_and(matches, a1->types, a2->types);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* s1 is the src type that is matched with a self
|
||||
* s2, and t2 are the source and type of the other rule
|
||||
*/
|
||||
static int cil_self_match_any(struct cil_symtab_datum *s1, struct cil_symtab_datum *s2, struct cil_symtab_datum *t2)
|
||||
{
|
||||
int rc;
|
||||
struct cil_tree_node *n1 = s1->nodes->head->data;
|
||||
if (n1->flavor != CIL_TYPEATTRIBUTE) {
|
||||
rc = cil_type_match_any(s1, t2);
|
||||
} else {
|
||||
struct cil_typeattribute *a = (struct cil_typeattribute *)s1;
|
||||
ebitmap_t map;
|
||||
ebitmap_init(&map);
|
||||
rc = cil_type_matches(&map, s2, t2);
|
||||
if (rc < 0) {
|
||||
ebitmap_destroy(&map);
|
||||
goto exit;
|
||||
}
|
||||
if (map.node == NULL) {
|
||||
rc = CIL_FALSE;
|
||||
goto exit;
|
||||
}
|
||||
rc = ebitmap_match_any(&map, a->types);
|
||||
ebitmap_destroy(&map);
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cil_classperms_match_any(struct cil_classperms *cp1, struct cil_classperms *cp2)
|
||||
{
|
||||
struct cil_class *c1 = cp1->class;
|
||||
struct cil_class *c2 = cp2->class;
|
||||
struct cil_list_item *i1, *i2;
|
||||
|
||||
if (&c1->datum != &c2->datum) return CIL_FALSE;
|
||||
|
||||
cil_list_for_each(i1, cp1->perms) {
|
||||
struct cil_perm *p1 = i1->data;
|
||||
cil_list_for_each(i2, cp2->perms) {
|
||||
struct cil_perm *p2 = i2->data;
|
||||
if (&p1->datum == &p2->datum) return CIL_TRUE;
|
||||
}
|
||||
}
|
||||
return CIL_FALSE;
|
||||
}
|
||||
|
||||
static int __cil_classperms_list_match_any(struct cil_classperms *cp1, struct cil_list *cpl2)
|
||||
{
|
||||
int rc;
|
||||
struct cil_list_item *curr;
|
||||
|
||||
cil_list_for_each(curr, cpl2) {
|
||||
if (curr->flavor == CIL_CLASSPERMS) {
|
||||
struct cil_classperms *cp = curr->data;
|
||||
if (FLAVOR(cp->class) == CIL_CLASS) {
|
||||
rc = cil_classperms_match_any(cp1, cp);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
} else { /* MAP */
|
||||
struct cil_list_item *i = NULL;
|
||||
cil_list_for_each(i, cp->perms) {
|
||||
struct cil_perm *cmp = i->data;
|
||||
rc = __cil_classperms_list_match_any(cp1, cmp->classperms);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
}
|
||||
}
|
||||
} else { /* SET */
|
||||
struct cil_classperms_set *cp_set = curr->data;
|
||||
struct cil_classpermission *cp = cp_set->set;
|
||||
rc = __cil_classperms_list_match_any(cp1, cp->classperms);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
}
|
||||
}
|
||||
return CIL_FALSE;
|
||||
}
|
||||
|
||||
static int cil_classperms_list_match_any(struct cil_list *cpl1, struct cil_list *cpl2)
|
||||
{
|
||||
int rc;
|
||||
struct cil_list_item *curr;
|
||||
|
||||
cil_list_for_each(curr, cpl1) {
|
||||
if (curr->flavor == CIL_CLASSPERMS) {
|
||||
struct cil_classperms *cp = curr->data;
|
||||
if (FLAVOR(cp->class) == CIL_CLASS) {
|
||||
rc = __cil_classperms_list_match_any(cp, cpl2);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
} else { /* MAP */
|
||||
struct cil_list_item *i = NULL;
|
||||
cil_list_for_each(i, cp->perms) {
|
||||
struct cil_perm *cmp = i->data;
|
||||
rc = cil_classperms_list_match_any(cmp->classperms, cpl2);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
}
|
||||
}
|
||||
} else { /* SET */
|
||||
struct cil_classperms_set *cp_set = curr->data;
|
||||
struct cil_classpermission *cp = cp_set->set;
|
||||
rc = cil_classperms_list_match_any(cp->classperms, cpl2);
|
||||
if (rc == CIL_TRUE) return CIL_TRUE;
|
||||
}
|
||||
}
|
||||
return CIL_FALSE;
|
||||
}
|
||||
|
||||
int cil_find_matching_avrule(struct cil_tree_node *node, struct cil_avrule *avrule, struct cil_avrule *target, struct cil_list *matching, int match_self)
|
||||
{
|
||||
int rc = SEPOL_OK;
|
||||
struct cil_symtab_datum *s1 = avrule->src;
|
||||
struct cil_symtab_datum *t1 = avrule->tgt;
|
||||
struct cil_list *cp1 = avrule->classperms;
|
||||
struct cil_symtab_datum *s2 = target->src;
|
||||
struct cil_symtab_datum *t2 = target->tgt;
|
||||
struct cil_list *cp2 = target->classperms;
|
||||
|
||||
if (match_self != CIL_TRUE && avrule == target) goto exit;
|
||||
|
||||
if (avrule->rule_kind != target->rule_kind) goto exit;
|
||||
|
||||
if (!cil_type_match_any(s1, s2)) goto exit;
|
||||
|
||||
if (t1->fqn != CIL_KEY_SELF && t2->fqn != CIL_KEY_SELF) {
|
||||
if (!cil_type_match_any(t1, t2)) goto exit;
|
||||
} else {
|
||||
if (t1->fqn == CIL_KEY_SELF && t2->fqn == CIL_KEY_SELF) {
|
||||
/* The earlier check whether s1 and s2 matches is all that is needed */
|
||||
} else if (t1->fqn == CIL_KEY_SELF) {
|
||||
rc = cil_self_match_any(s1, s2, t2);
|
||||
if (rc < 0) {
|
||||
goto exit;
|
||||
} else if (rc == CIL_FALSE) {
|
||||
rc = SEPOL_OK;
|
||||
goto exit;
|
||||
}
|
||||
} else if (t2->fqn == CIL_KEY_SELF) {
|
||||
rc = cil_self_match_any(s2, s1, t1);
|
||||
if (rc < 0) {
|
||||
goto exit;
|
||||
} else if (rc == CIL_FALSE) {
|
||||
rc = SEPOL_OK;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cil_classperms_list_match_any(cp1, cp2)) {
|
||||
cil_list_append(matching, CIL_NODE, node);
|
||||
}
|
||||
|
||||
rc = SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_find_matching_avrule_in_ast(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
|
||||
{
|
||||
int rc = SEPOL_OK;
|
||||
struct cil_args_find *args = extra_args;
|
||||
|
||||
if (node->flavor == CIL_BLOCK) {
|
||||
struct cil_block *blk = node->data;
|
||||
if (blk->is_abstract == CIL_TRUE) {
|
||||
*finished = CIL_TREE_SKIP_HEAD;
|
||||
goto exit;
|
||||
}
|
||||
} else if (node->flavor == CIL_MACRO) {
|
||||
*finished = CIL_TREE_SKIP_HEAD;
|
||||
goto exit;
|
||||
} else if (node->flavor == CIL_AVRULE) {
|
||||
rc = cil_find_matching_avrule(node, node->data, args->target, args->matching, args->match_self);
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self)
|
||||
{
|
||||
int rc;
|
||||
struct cil_args_find args;
|
||||
|
||||
args.flavor = flavor;
|
||||
args.target = target;
|
||||
args.matching = matching;
|
||||
args.match_self = match_self;
|
||||
|
||||
rc = cil_tree_walk(current, __cil_find_matching_avrule_in_ast, NULL, NULL, &args);
|
||||
if (rc) {
|
||||
cil_log(CIL_ERR, "An error occured while searching for avrule in AST\n");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
39
libsepol/cil/src/cil_find.h
Normal file
39
libsepol/cil/src/cil_find.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2011 Tresys Technology, LLC. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those
|
||||
* of the authors and should not be interpreted as representing official policies,
|
||||
* either expressed or implied, of Tresys Technology, LLC.
|
||||
*/
|
||||
|
||||
#include "cil_flavor.h"
|
||||
#include "cil_tree.h"
|
||||
#include "cil_list.h"
|
||||
|
||||
#ifndef CIL_FIND_H_
|
||||
#define CIL_FIND_H_
|
||||
|
||||
int cil_find_matching_avrule_in_ast(struct cil_tree_node *current, enum cil_flavor flavor, void *target, struct cil_list *matching, int match_self);
|
||||
|
||||
#endif
|
@ -63,6 +63,7 @@ enum cil_flavor {
|
||||
CIL_CLASSPERMISSIONSET,
|
||||
CIL_USERPREFIX,
|
||||
CIL_USERROLE,
|
||||
CIL_USERATTRIBUTESET,
|
||||
CIL_USERLEVEL,
|
||||
CIL_USERRANGE,
|
||||
CIL_USERBOUNDS,
|
||||
@ -83,6 +84,7 @@ enum cil_flavor {
|
||||
CIL_SIDORDER,
|
||||
CIL_ROLEALLOW,
|
||||
CIL_AVRULE,
|
||||
CIL_AVRULEX,
|
||||
CIL_ROLETRANSITION,
|
||||
CIL_TYPE_RULE,
|
||||
CIL_NAMETYPETRANSITION,
|
||||
@ -163,6 +165,7 @@ enum cil_flavor {
|
||||
CIL_MAP_CLASS,
|
||||
CIL_CLASSPERMISSION,
|
||||
CIL_USER,
|
||||
CIL_USERATTRIBUTE,
|
||||
CIL_ROLE,
|
||||
CIL_ROLEATTRIBUTE,
|
||||
CIL_TYPE,
|
||||
@ -180,6 +183,7 @@ enum cil_flavor {
|
||||
CIL_CONTEXT,
|
||||
CIL_IPADDR,
|
||||
CIL_POLICYCAP,
|
||||
CIL_PERMISSIONX
|
||||
};
|
||||
|
||||
|
||||
|
@ -102,6 +102,7 @@ static int __cil_fqn_qualify_blocks(__attribute__((unused)) hashtab_key_t k, has
|
||||
case CIL_SYM_LEVELRANGES:
|
||||
case CIL_SYM_IPADDRS:
|
||||
case CIL_SYM_NAMES:
|
||||
case CIL_SYM_PERMX:
|
||||
/* These do not show up in the kernal policy */
|
||||
break;
|
||||
case CIL_SYM_POLICYCAPS:
|
||||
|
@ -127,6 +127,8 @@ char *CIL_KEY_TRANS;
|
||||
char *CIL_KEY_TYPE;
|
||||
char *CIL_KEY_ROLE;
|
||||
char *CIL_KEY_USER;
|
||||
char *CIL_KEY_USERATTRIBUTE;
|
||||
char *CIL_KEY_USERATTRIBUTESET;
|
||||
char *CIL_KEY_SENSITIVITY;
|
||||
char *CIL_KEY_CATEGORY;
|
||||
char *CIL_KEY_CATSET;
|
||||
@ -216,6 +218,11 @@ char *CIL_KEY_DEFAULTTYPE;
|
||||
char *CIL_KEY_ROOT;
|
||||
char *CIL_KEY_NODE;
|
||||
char *CIL_KEY_PERM;
|
||||
char *CIL_KEY_ALLOWX;
|
||||
char *CIL_KEY_AUDITALLOWX;
|
||||
char *CIL_KEY_DONTAUDITX;
|
||||
char *CIL_KEY_PERMISSIONX;
|
||||
char *CIL_KEY_IOCTL;
|
||||
|
||||
/*
|
||||
Symbol Table Array Indices
|
||||
@ -239,6 +246,7 @@ enum cil_sym_index {
|
||||
CIL_SYM_POLICYCAPS,
|
||||
CIL_SYM_IPADDRS,
|
||||
CIL_SYM_NAMES,
|
||||
CIL_SYM_PERMX,
|
||||
CIL_SYM_NUM,
|
||||
CIL_SYM_UNKNOWN,
|
||||
CIL_SYM_PERMS // Special case for permissions. This symtab is not included in arrays
|
||||
@ -279,11 +287,15 @@ struct cil_db {
|
||||
struct cil_list *userprefixes;
|
||||
struct cil_list *selinuxusers;
|
||||
struct cil_list *names;
|
||||
int num_types_and_attrs;
|
||||
int num_classes;
|
||||
int num_cats;
|
||||
int num_types;
|
||||
int num_roles;
|
||||
int num_users;
|
||||
struct cil_type **val_to_type;
|
||||
struct cil_role **val_to_role;
|
||||
struct cil_user **val_to_user;
|
||||
int disable_dontaudit;
|
||||
int disable_neverallow;
|
||||
int preserve_tunables;
|
||||
@ -410,14 +422,27 @@ struct cil_sidorder {
|
||||
struct cil_user {
|
||||
struct cil_symtab_datum datum;
|
||||
struct cil_user *bounds;
|
||||
struct cil_list *roles;
|
||||
ebitmap_t *roles;
|
||||
struct cil_level *dftlevel;
|
||||
struct cil_levelrange *range;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct cil_userattribute {
|
||||
struct cil_symtab_datum datum;
|
||||
struct cil_list *expr_list;
|
||||
ebitmap_t *users;
|
||||
};
|
||||
|
||||
struct cil_userattributeset {
|
||||
char *attr_str;
|
||||
struct cil_list *str_expr;
|
||||
struct cil_list *datum_expr;
|
||||
};
|
||||
|
||||
struct cil_userrole {
|
||||
char *user_str;
|
||||
struct cil_user *user;
|
||||
void *user;
|
||||
char *role_str;
|
||||
void *role;
|
||||
};
|
||||
@ -552,6 +577,26 @@ struct cil_avrule {
|
||||
struct cil_list *classperms;
|
||||
};
|
||||
|
||||
#define CIL_PERMX_KIND_IOCTL 1
|
||||
struct cil_permissionx {
|
||||
struct cil_symtab_datum datum;
|
||||
uint32_t kind;
|
||||
char *obj_str;
|
||||
void *obj;
|
||||
struct cil_list *expr_str;
|
||||
ebitmap_t *perms;
|
||||
};
|
||||
|
||||
struct cil_avrulex {
|
||||
uint32_t rule_kind;
|
||||
char *src_str;
|
||||
void *src; /* type, alias, or attribute */
|
||||
char *tgt_str;
|
||||
void *tgt; /* type, alias, or attribute */
|
||||
char *permx_str;
|
||||
struct cil_permissionx *permx;
|
||||
};
|
||||
|
||||
#define CIL_TYPE_TRANSITION 16
|
||||
#define CIL_TYPE_MEMBER 32
|
||||
#define CIL_TYPE_CHANGE 64
|
||||
@ -928,6 +973,8 @@ void cil_condblock_init(struct cil_condblock **cb);
|
||||
void cil_tunable_init(struct cil_tunable **ciltun);
|
||||
void cil_tunif_init(struct cil_tunableif **tif);
|
||||
void cil_avrule_init(struct cil_avrule **avrule);
|
||||
void cil_avrulex_init(struct cil_avrulex **avrulex);
|
||||
void cil_permissionx_init(struct cil_permissionx **permx);
|
||||
void cil_type_rule_init(struct cil_type_rule **type_rule);
|
||||
void cil_roletransition_init(struct cil_roletransition **roletrans);
|
||||
void cil_roleallow_init(struct cil_roleallow **role_allow);
|
||||
@ -972,5 +1019,7 @@ void cil_default_init(struct cil_default **def);
|
||||
void cil_defaultrange_init(struct cil_defaultrange **def);
|
||||
void cil_handleunknown_init(struct cil_handleunknown **unk);
|
||||
void cil_mls_init(struct cil_mls **mls);
|
||||
void cil_userattribute_init(struct cil_userattribute **attribute);
|
||||
void cil_userattributeset_init(struct cil_userattributeset **attrset);
|
||||
|
||||
#endif
|
||||
|
@ -1155,11 +1155,6 @@ int __cil_gen_policy_node_helper(struct cil_tree_node *node, uint32_t *finished,
|
||||
case CIL_USER:
|
||||
cil_multimap_insert(users, node->data, NULL, CIL_USERROLE, CIL_NONE);
|
||||
break;
|
||||
case CIL_USERROLE: {
|
||||
struct cil_userrole *userrole = node->data;
|
||||
cil_multimap_insert(users, &userrole->user->datum, (struct cil_symtab_datum *)userrole->role, CIL_USERROLE, CIL_ROLE);
|
||||
}
|
||||
break;
|
||||
case CIL_CATALIAS: {
|
||||
struct cil_alias *alias = node->data;
|
||||
struct cil_symtab_datum *datum = alias->actual;
|
||||
|
@ -339,28 +339,53 @@ static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *fini
|
||||
case CIL_MACRO:
|
||||
*finished = CIL_TREE_SKIP_HEAD;
|
||||
break;
|
||||
case CIL_TYPE: {
|
||||
struct cil_type *type = node->data;
|
||||
if (type->datum.nodes->head->data == node) {
|
||||
// multiple AST nodes can point to the same cil_type data (like if
|
||||
// copied from a macro). This check ensures we only count the
|
||||
// duplicates once
|
||||
type->value = db->num_types;
|
||||
db->num_types++;
|
||||
case CIL_CLASS: {
|
||||
struct cil_class *class = node->data;
|
||||
if (class->datum.nodes->head->data == node) {
|
||||
// Multiple nodes can point to the same datum. Only count once.
|
||||
db->num_classes++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_TYPE: {
|
||||
struct cil_type *type = node->data;
|
||||
if (type->datum.nodes->head->data == node) {
|
||||
// Multiple nodes can point to the same datum. Only count once.
|
||||
type->value = db->num_types;
|
||||
db->num_types++;
|
||||
db->num_types_and_attrs++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_TYPEATTRIBUTE: {
|
||||
struct cil_typeattribute *attr = node->data;
|
||||
if (attr->datum.nodes->head->data == node) {
|
||||
// Multiple nodes can point to the same datum. Only count once.
|
||||
db->num_types_and_attrs++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CIL_ROLE: {
|
||||
struct cil_role *role = node->data;
|
||||
if (role->datum.nodes->head->data == node) {
|
||||
// multiple AST nodes can point to the same cil_role data (like if
|
||||
// copied from a macro). This check ensures we only count the
|
||||
// duplicates once
|
||||
// Multiple nodes can point to the same datum. Only count once.
|
||||
role->value = db->num_roles;
|
||||
db->num_roles++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_USER: {
|
||||
struct cil_user *user = node->data;
|
||||
if (user->datum.nodes->head->data == node) {
|
||||
// multiple AST nodes can point to the same cil_user data (like if
|
||||
// copied from a macro). This check ensures we only count the
|
||||
// duplicates once
|
||||
user->value = db->num_users;
|
||||
db->num_users++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_NETIFCON:
|
||||
db->netifcon->count++;
|
||||
break;
|
||||
@ -432,6 +457,14 @@ static int __cil_post_db_array_helper(struct cil_tree_node *node, __attribute__(
|
||||
db->val_to_role[role->value] = role;
|
||||
break;
|
||||
}
|
||||
case CIL_USER: {
|
||||
struct cil_user *user= node->data;
|
||||
if (db->val_to_user == NULL) {
|
||||
db->val_to_user = cil_malloc(sizeof(*db->val_to_user) * db->num_users);
|
||||
}
|
||||
db->val_to_user[user->value] = user;
|
||||
break;
|
||||
}
|
||||
case CIL_USERPREFIX: {
|
||||
cil_list_append(db->userprefixes, CIL_USERPREFIX, node->data);
|
||||
break;
|
||||
@ -624,6 +657,54 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __evaluate_user_expression(struct cil_userattribute *attr, struct cil_db *db)
|
||||
{
|
||||
int rc;
|
||||
|
||||
attr->users = cil_malloc(sizeof(*attr->users));
|
||||
rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->users, db->num_users, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to expand user attribute to bitmap\n");
|
||||
ebitmap_destroy(attr->users);
|
||||
free(attr->users);
|
||||
attr->users = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_user_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_tree_node *node = datum->nodes->head->data;
|
||||
struct cil_userattribute *attr = NULL;
|
||||
struct cil_user *user = NULL;
|
||||
|
||||
ebitmap_init(bitmap);
|
||||
|
||||
if (node->flavor == CIL_USERATTRIBUTE) {
|
||||
attr = (struct cil_userattribute *)datum;
|
||||
if (attr->users == NULL) {
|
||||
rc = __evaluate_user_expression(attr, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
ebitmap_union(bitmap, attr->users);
|
||||
} else {
|
||||
user = (struct cil_user *)datum;
|
||||
if (ebitmap_set_bit(bitmap, user->value, 1)) {
|
||||
cil_log(CIL_ERR, "Failed to set user bit\n");
|
||||
ebitmap_destroy(bitmap);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __evaluate_role_expression(struct cil_roleattribute *attr, struct cil_db *db)
|
||||
{
|
||||
int rc;
|
||||
@ -668,6 +749,70 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __evaluate_permissionx_expression(struct cil_permissionx *permx, struct cil_db *db)
|
||||
{
|
||||
int rc;
|
||||
|
||||
permx->perms = cil_malloc(sizeof(*permx->perms));
|
||||
ebitmap_init(permx->perms);
|
||||
|
||||
rc = __cil_expr_to_bitmap(permx->expr_str, permx->perms, 0x10000, db); // max is one more than 0xFFFF
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to expand permissionx expression\n");
|
||||
ebitmap_destroy(permx->perms);
|
||||
free(permx->perms);
|
||||
permx->perms = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_permx_str_to_int(char *permx_str, uint16_t *val)
|
||||
{
|
||||
char *endptr = NULL;
|
||||
long lval = strtol(permx_str, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0') {
|
||||
cil_log(CIL_ERR, "permissionx value %s not valid number\n", permx_str);
|
||||
goto exit;
|
||||
}
|
||||
if (lval < 0x0000 || lval > 0xFFFF) {
|
||||
cil_log(CIL_ERR, "permissionx value %s must be between 0x0000 and 0xFFFF\n", permx_str);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*val = (uint16_t)lval;
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return SEPOL_ERR;
|
||||
}
|
||||
|
||||
static int __cil_permx_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
uint16_t val;
|
||||
|
||||
ebitmap_init(bitmap);
|
||||
|
||||
rc = __cil_permx_str_to_int((char*)datum, &val);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ebitmap_set_bit(bitmap, (unsigned int)val, 1)) {
|
||||
cil_log(CIL_ERR, "Failed to set permissionx bit\n");
|
||||
ebitmap_destroy(bitmap);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_perm_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
|
||||
{
|
||||
struct cil_perm *perm = (struct cil_perm *)datum;
|
||||
@ -778,7 +923,7 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
|
||||
static int __cil_cat_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_symtab_datum *d1 = i1->data;
|
||||
@ -818,6 +963,39 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_permissionx_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
char *p1 = i1->data;
|
||||
char *p2 = i2->data;
|
||||
uint16_t v1;
|
||||
uint16_t v2;
|
||||
uint32_t i;
|
||||
|
||||
rc = __cil_permx_str_to_int(p1, &v1);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_permx_str_to_int(p2, &v2);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = v1; i <= v2; i++) {
|
||||
if (ebitmap_set_bit(bitmap, i, 1)) {
|
||||
cil_log(CIL_ERR, "Failed to set permissionx bit\n");
|
||||
ebitmap_destroy(bitmap);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flavor flavor, ebitmap_t *bitmap, int max, struct cil_db *db)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
@ -830,6 +1008,9 @@ static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flav
|
||||
case CIL_ROLE:
|
||||
rc = __cil_role_to_bitmap(curr->data, bitmap, db);
|
||||
break;
|
||||
case CIL_USER:
|
||||
rc = __cil_user_to_bitmap(curr->data, bitmap, db);
|
||||
break;
|
||||
case CIL_PERM:
|
||||
rc = __cil_perm_to_bitmap(curr->data, bitmap, db);
|
||||
break;
|
||||
@ -846,6 +1027,10 @@ static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flav
|
||||
if (rc != SEPOL_OK) {
|
||||
ebitmap_destroy(bitmap);
|
||||
}
|
||||
} else if (flavor == CIL_PERMISSIONX) {
|
||||
// permissionx expressions aren't resolved into anything, so curr->flavor
|
||||
// is just a CIL_STRING, not a CIL_DATUM, so just check on flavor for those
|
||||
rc = __cil_permx_to_bitmap(curr->data, bitmap, db);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -878,18 +1063,27 @@ static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max,
|
||||
goto exit;
|
||||
}
|
||||
} else if (op == CIL_RANGE) {
|
||||
if (flavor != CIL_CAT) {
|
||||
cil_log(CIL_INFO, "Range operation only supported for categories\n");
|
||||
if (flavor == CIL_CAT) {
|
||||
ebitmap_init(&tmp);
|
||||
rc = __cil_cat_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_INFO, "Failed to expand category range\n");
|
||||
ebitmap_destroy(&tmp);
|
||||
goto exit;
|
||||
}
|
||||
} else if (flavor == CIL_PERMISSIONX) {
|
||||
ebitmap_init(&tmp);
|
||||
rc = __cil_permissionx_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_INFO, "Failed to expand category range\n");
|
||||
ebitmap_destroy(&tmp);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
cil_log(CIL_INFO, "Range operation only supported for categories permissionx\n");
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
ebitmap_init(&tmp);
|
||||
rc = __cil_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_INFO, "Failed to expand category range\n");
|
||||
ebitmap_destroy(&tmp);
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
rc = __cil_expr_to_bitmap_helper(curr->next, flavor, &b1, max, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
@ -1025,6 +1219,30 @@ static int __cil_post_db_attr_helper(struct cil_tree_node *node, __attribute__((
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_AVRULEX: {
|
||||
struct cil_avrulex *rule = node->data;
|
||||
if (rule->permx_str == NULL) {
|
||||
rc = __evaluate_permissionx_expression(rule->permx, db);
|
||||
if (rc != SEPOL_OK) goto exit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_PERMISSIONX: {
|
||||
struct cil_permissionx *permx = node->data;
|
||||
rc = __evaluate_permissionx_expression(permx, db);
|
||||
if (rc != SEPOL_OK) goto exit;
|
||||
break;
|
||||
}
|
||||
case CIL_USERATTRIBUTE: {
|
||||
struct cil_userattribute *attr = node->data;
|
||||
if (attr->users == NULL) {
|
||||
rc = __evaluate_user_expression(attr, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1130,6 +1348,102 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __cil_user_assign_roles(struct cil_user *user, struct cil_symtab_datum *datum)
|
||||
{
|
||||
struct cil_tree_node *node = datum->nodes->head->data;
|
||||
struct cil_role *role = NULL;
|
||||
struct cil_roleattribute *attr = NULL;
|
||||
|
||||
if (user->roles == NULL) {
|
||||
user->roles = cil_malloc(sizeof(*user->roles));
|
||||
ebitmap_init(user->roles);
|
||||
}
|
||||
|
||||
if (node->flavor == CIL_ROLE) {
|
||||
role = (struct cil_role *)datum;
|
||||
if (ebitmap_set_bit(user->roles, role->value, 1)) {
|
||||
cil_log(CIL_INFO, "Failed to set bit in user roles bitmap\n");
|
||||
goto exit;
|
||||
}
|
||||
} else if (node->flavor == CIL_ROLEATTRIBUTE) {
|
||||
attr = (struct cil_roleattribute *)datum;
|
||||
ebitmap_union(user->roles, attr->roles);
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return SEPOL_ERR;
|
||||
}
|
||||
|
||||
static int __cil_post_db_userrole_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_db *db = extra_args;
|
||||
struct cil_block *blk = NULL;
|
||||
struct cil_userrole *userrole = NULL;
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_symtab_datum *role_datum = NULL;
|
||||
struct cil_tree_node *user_node = NULL;
|
||||
struct cil_userattribute *u_attr = NULL;
|
||||
unsigned int i;
|
||||
struct cil_user *user = NULL;
|
||||
ebitmap_node_t *unode = NULL;
|
||||
|
||||
switch (node->flavor) {
|
||||
case CIL_BLOCK: {
|
||||
blk = node->data;
|
||||
if (blk->is_abstract == CIL_TRUE) {
|
||||
*finished = CIL_TREE_SKIP_HEAD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CIL_MACRO: {
|
||||
*finished = CIL_TREE_SKIP_HEAD;
|
||||
break;
|
||||
}
|
||||
case CIL_USERROLE: {
|
||||
userrole = node->data;
|
||||
user_datum = userrole->user;
|
||||
role_datum = userrole->role;
|
||||
user_node = user_datum->nodes->head->data;
|
||||
|
||||
if (user_node->flavor == CIL_USERATTRIBUTE) {
|
||||
u_attr = userrole->user;
|
||||
|
||||
ebitmap_for_each_bit(u_attr->users, unode, i) {
|
||||
if (!ebitmap_get_bit(u_attr->users, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
user = db->val_to_user[i];
|
||||
|
||||
rc = __cil_user_assign_roles(user, role_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user = userrole->user;
|
||||
|
||||
rc = __cil_user_assign_roles(user, role_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
exit:
|
||||
cil_log(CIL_INFO, "cil_post_db_userrole_helper failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __evaluate_level_expression(struct cil_level *level, struct cil_db *db)
|
||||
{
|
||||
if (level->cats != NULL) {
|
||||
@ -1601,6 +1915,12 @@ static int cil_post_db(struct cil_db *db)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_tree_walk(db->ast->root, __cil_post_db_userrole_helper, NULL, NULL, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_INFO, "Failed during userrole association\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_tree_walk(db->ast->root, __cil_post_db_classperms_helper, NULL, NULL, db);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_INFO, "Failed to evaluate class mapping permissions expressions\n");
|
||||
|
@ -99,7 +99,32 @@ static void cil_reset_user(struct cil_user *user)
|
||||
user->bounds = NULL;
|
||||
user->dftlevel = NULL;
|
||||
user->range = NULL;
|
||||
cil_list_destroy(&user->roles, CIL_FALSE);
|
||||
}
|
||||
|
||||
static void cil_reset_userattr(struct cil_userattribute *attr)
|
||||
{
|
||||
struct cil_list_item *expr = NULL;
|
||||
struct cil_list_item *next = NULL;
|
||||
|
||||
/* during a re-resolve, we need to reset the lists of expression stacks associated with this attribute from a userattribute statement */
|
||||
if (attr->expr_list != NULL) {
|
||||
/* we don't want to destroy the expression stacks (cil_list) inside
|
||||
* this list cil_list_destroy destroys sublists, so we need to do it
|
||||
* manually */
|
||||
expr = attr->expr_list->head;
|
||||
while (expr != NULL) {
|
||||
next = expr->next;
|
||||
cil_list_item_destroy(&expr, CIL_FALSE);
|
||||
expr = next;
|
||||
}
|
||||
free(attr->expr_list);
|
||||
attr->expr_list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void cil_reset_userattributeset(struct cil_userattributeset *uas)
|
||||
{
|
||||
cil_list_destroy(&uas->datum_expr, CIL_FALSE);
|
||||
}
|
||||
|
||||
static void cil_reset_selinuxuser(struct cil_selinuxuser *selinuxuser)
|
||||
@ -403,6 +428,12 @@ int __cil_reset_node(struct cil_tree_node *node, __attribute__((unused)) uint32
|
||||
case CIL_USER:
|
||||
cil_reset_user(node->data);
|
||||
break;
|
||||
case CIL_USERATTRIBUTE:
|
||||
cil_reset_userattr(node->data);
|
||||
break;
|
||||
case CIL_USERATTRIBUTESET:
|
||||
cil_reset_userattributeset(node->data);
|
||||
break;
|
||||
case CIL_SELINUXUSERDEFAULT:
|
||||
case CIL_SELINUXUSER:
|
||||
cil_reset_selinuxuser(node->data);
|
||||
|
@ -51,7 +51,7 @@ struct cil_args_resolve {
|
||||
struct cil_db *db;
|
||||
enum cil_pass pass;
|
||||
uint32_t *changed;
|
||||
struct cil_tree_node *callstack;
|
||||
char *last_resolved_name;
|
||||
struct cil_tree_node *optstack;
|
||||
struct cil_tree_node *boolif;
|
||||
struct cil_tree_node *macro;
|
||||
@ -319,6 +319,75 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_permissionx(struct cil_tree_node *current, struct cil_permissionx *permx, void *extra_args)
|
||||
{
|
||||
struct cil_symtab_datum *obj_datum = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, permx->obj_str, CIL_SYM_CLASSES, extra_args, &obj_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
permx->obj = (struct cil_class*)obj_datum;
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_avrulex(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
struct cil_args_resolve *args = extra_args;
|
||||
struct cil_db *db = NULL;
|
||||
|
||||
struct cil_avrulex *rule = current->data;
|
||||
struct cil_symtab_datum *src_datum = NULL;
|
||||
struct cil_symtab_datum *tgt_datum = NULL;
|
||||
struct cil_symtab_datum *permx_datum = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
if (args != NULL) {
|
||||
db = args->db;
|
||||
}
|
||||
|
||||
rc = cil_resolve_name(current, rule->src_str, CIL_SYM_TYPES, args, &src_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
rule->src = src_datum;
|
||||
cil_type_used(src_datum);
|
||||
|
||||
if (rule->tgt_str == CIL_KEY_SELF) {
|
||||
rule->tgt = db->selftype;
|
||||
} else {
|
||||
rc = cil_resolve_name(current, rule->tgt_str, CIL_SYM_TYPES, args, &tgt_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
rule->tgt = tgt_datum;
|
||||
cil_type_used(tgt_datum);
|
||||
}
|
||||
|
||||
if (rule->permx_str != NULL) {
|
||||
rc = cil_resolve_name(current, rule->permx_str, CIL_SYM_PERMX, args, &permx_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
rule->permx = (struct cil_permissionx*)permx_datum;
|
||||
} else {
|
||||
rc = cil_resolve_permissionx(current, rule->permx, extra_args);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_type_rule(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
struct cil_type_rule *rule = current->data;
|
||||
@ -750,12 +819,6 @@ int cil_resolve_userrole(struct cil_tree_node *current, void *extra_args)
|
||||
}
|
||||
userrole->role = role_datum;
|
||||
|
||||
if (userrole->user->roles == NULL) {
|
||||
cil_list_init(&userrole->user->roles, CIL_LIST_ITEM);
|
||||
}
|
||||
|
||||
cil_list_append(userrole->user->roles, CIL_ROLE, userrole->role);
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
@ -768,12 +831,22 @@ int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args)
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_symtab_datum *lvl_datum = NULL;
|
||||
struct cil_user *user = NULL;
|
||||
struct cil_tree_node *user_node = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, usrlvl->user_str, CIL_SYM_USERS, extra_args, &user_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user_node = user_datum->nodes->head->data;
|
||||
|
||||
if (user_node->flavor != CIL_USER) {
|
||||
cil_log(CIL_ERR, "Userlevel must be a user\n");
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user = (struct cil_user*)user_datum;
|
||||
|
||||
if (usrlvl->level_str != NULL) {
|
||||
@ -811,12 +884,22 @@ int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args)
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_symtab_datum *range_datum = NULL;
|
||||
struct cil_user *user = NULL;
|
||||
struct cil_tree_node *user_node = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, userrange->user_str, CIL_SYM_USERS, extra_args, &user_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user_node = user_datum->nodes->head->data;
|
||||
|
||||
if (user_node->flavor != CIL_USER) {
|
||||
cil_log(CIL_ERR, "Userrange must be a user: %s\n", user_datum->fqn);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user = (struct cil_user*)user_datum;
|
||||
|
||||
if (userrange->range_str != NULL) {
|
||||
@ -852,12 +935,22 @@ int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
struct cil_userprefix *userprefix = current->data;
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_tree_node *user_node = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, userprefix->user_str, CIL_SYM_USERS, extra_args, &user_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user_node = user_datum->nodes->head->data;
|
||||
|
||||
if (user_node->flavor != CIL_USER) {
|
||||
cil_log(CIL_ERR, "Userprefix must be a user: %s\n", user_datum->fqn);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
userprefix->user = (struct cil_user*)user_datum;
|
||||
|
||||
exit:
|
||||
@ -869,18 +962,27 @@ int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args)
|
||||
struct cil_selinuxuser *selinuxuser = current->data;
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_symtab_datum *lvlrange_datum = NULL;
|
||||
struct cil_tree_node *user_node = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, selinuxuser->user_str, CIL_SYM_USERS, extra_args, &user_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
user_node = user_datum->nodes->head->data;
|
||||
|
||||
if (user_node->flavor != CIL_USER) {
|
||||
cil_log(CIL_ERR, "Selinuxuser must be a user: %s\n", user_datum->fqn);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
selinuxuser->user = (struct cil_user*)user_datum;
|
||||
|
||||
if (selinuxuser->range_str != NULL) {
|
||||
rc = cil_resolve_name(current, selinuxuser->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Unable to resolve name: %s\n", selinuxuser->range_str);
|
||||
goto exit;
|
||||
}
|
||||
selinuxuser->range = (struct cil_levelrange*)lvlrange_datum;
|
||||
@ -1455,7 +1557,6 @@ int cil_resolve_cats(struct cil_tree_node *current, struct cil_cats *cats, void
|
||||
|
||||
rc = cil_resolve_expr(CIL_CATSET, cats->str_expr, &cats->datum_expr, current, extra_args);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR,"Unable to resolve categories\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -1647,34 +1748,48 @@ int cil_resolve_context(struct cil_tree_node *current, struct cil_context *conte
|
||||
struct cil_symtab_datum *user_datum = NULL;
|
||||
struct cil_symtab_datum *role_datum = NULL;
|
||||
struct cil_symtab_datum *type_datum = NULL;
|
||||
struct cil_tree_node *type_node = NULL;
|
||||
struct cil_tree_node *node = NULL;
|
||||
struct cil_symtab_datum *lvlrange_datum = NULL;
|
||||
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
rc = cil_resolve_name(current, context->user_str, CIL_SYM_USERS, extra_args, &user_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Unable to resolve name: %s\n", context->user_str);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
node = user_datum->nodes->head->data;
|
||||
|
||||
if (node->flavor != CIL_USER) {
|
||||
cil_log(CIL_ERR, "Context user must be a user: %s\n", user_datum->fqn);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->user = (struct cil_user*)user_datum;
|
||||
|
||||
rc = cil_resolve_name(current, context->role_str, CIL_SYM_ROLES, extra_args, &role_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Unable to resolve name: %s\n", context->role_str);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
node = role_datum->nodes->head->data;
|
||||
if (node->flavor != CIL_ROLE) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Context role not a role: %s\n", role_datum->fqn);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
context->role = (struct cil_role*)role_datum;
|
||||
|
||||
rc = cil_resolve_name(current, context->type_str, CIL_SYM_TYPES, extra_args, &type_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Unable to resolve name: %s\n", context->type_str);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
type_node = type_datum->nodes->head->data;
|
||||
node = type_datum->nodes->head->data;
|
||||
|
||||
if (type_node->flavor != CIL_TYPE && type_node->flavor != CIL_TYPEALIAS) {
|
||||
if (node->flavor != CIL_TYPE && node->flavor != CIL_TYPEALIAS) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Type not a type or type alias\n");
|
||||
goto exit;
|
||||
@ -1684,7 +1799,6 @@ int cil_resolve_context(struct cil_tree_node *current, struct cil_context *conte
|
||||
if (context->range_str != NULL) {
|
||||
rc = cil_resolve_name(current, context->range_str, CIL_SYM_LEVELRANGES, extra_args, &lvlrange_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Unable to resolve name: %s\n", context->range_str);
|
||||
goto exit;
|
||||
}
|
||||
context->range = (struct cil_levelrange*)lvlrange_datum;
|
||||
@ -2095,6 +2209,73 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_print_recursive_blockinherit(struct cil_tree_node *bi_node, struct cil_tree_node *terminating_node)
|
||||
{
|
||||
struct cil_list *trace = NULL;
|
||||
struct cil_list_item *item = NULL;
|
||||
struct cil_tree_node *curr = NULL;
|
||||
|
||||
cil_list_init(&trace, CIL_NODE);
|
||||
|
||||
for (curr = bi_node; curr != terminating_node; curr = curr->parent) {
|
||||
if (curr->flavor == CIL_BLOCK) {
|
||||
cil_list_prepend(trace, CIL_NODE, curr);
|
||||
} else {
|
||||
if (curr != bi_node) {
|
||||
cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_blockinherit *)curr->data)->block));
|
||||
}
|
||||
cil_list_prepend(trace, CIL_NODE, curr);
|
||||
}
|
||||
}
|
||||
cil_list_prepend(trace, CIL_NODE, terminating_node);
|
||||
|
||||
cil_list_for_each(item, trace) {
|
||||
curr = item->data;
|
||||
cil_log(CIL_ERR, " %s:%d: ", curr->path, curr->line);
|
||||
|
||||
if (curr->flavor == CIL_BLOCK) {
|
||||
cil_log(CIL_ERR, "block %s\n", DATUM(curr->data)->name);
|
||||
} else {
|
||||
cil_log(CIL_ERR, "blockinherit %s\n", ((struct cil_blockinherit *)curr->data)->block_str);
|
||||
}
|
||||
}
|
||||
|
||||
cil_list_destroy(&trace, CIL_FALSE);
|
||||
}
|
||||
|
||||
int cil_check_recursive_blockinherit(struct cil_tree_node *bi_node)
|
||||
{
|
||||
struct cil_tree_node *curr = NULL;
|
||||
struct cil_blockinherit *bi = NULL;
|
||||
struct cil_block *block = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
bi = bi_node->data;
|
||||
|
||||
for (curr = bi_node->parent; curr != NULL; curr = curr->parent) {
|
||||
if (curr->flavor != CIL_BLOCK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
block = curr->data;
|
||||
|
||||
if (block != bi->block) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cil_log(CIL_ERR, "Recursive blockinherit found:\n");
|
||||
cil_print_recursive_blockinherit(bi_node, curr);
|
||||
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
struct cil_block *block = current->data;
|
||||
@ -2118,6 +2299,11 @@ int cil_resolve_blockinherit_copy(struct cil_tree_node *current, void *extra_arg
|
||||
}
|
||||
|
||||
cil_list_for_each(item, block->bi_nodes) {
|
||||
rc = cil_check_recursive_blockinherit(item->data);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_copy_ast(db, current, item->data);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to copy block contents into blockinherit\n");
|
||||
@ -2351,7 +2537,6 @@ int cil_resolve_default(struct cil_tree_node *current, void *extra_args)
|
||||
cil_list_for_each(curr, def->class_strs) {
|
||||
rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to resolve class %s in %s\n", (char *)curr->data, cil_node_to_string(current));
|
||||
goto exit;
|
||||
}
|
||||
cil_list_append(def->class_datums, CIL_CLASS, datum);
|
||||
@ -2375,7 +2560,6 @@ int cil_resolve_defaultrange(struct cil_tree_node *current, void *extra_args)
|
||||
cil_list_for_each(curr, def->class_strs) {
|
||||
rc = cil_resolve_name(current, (char *)curr->data, CIL_SYM_CLASSES, extra_args, &datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to resolve class %s in defaultrange\n", (char *)curr->data);
|
||||
goto exit;
|
||||
}
|
||||
cil_list_append(def->class_datums, CIL_CLASS, datum);
|
||||
@ -2387,6 +2571,80 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cil_print_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *terminating_node)
|
||||
{
|
||||
struct cil_list *trace = NULL;
|
||||
struct cil_list_item * item = NULL;
|
||||
struct cil_tree_node *curr = NULL;
|
||||
|
||||
cil_list_init(&trace, CIL_NODE);
|
||||
|
||||
for (curr = call_node; curr != terminating_node; curr = curr->parent) {
|
||||
if (curr->flavor == CIL_CALL) {
|
||||
if (curr != call_node) {
|
||||
cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)curr->data)->macro));
|
||||
}
|
||||
cil_list_prepend(trace, CIL_NODE, curr);
|
||||
}
|
||||
}
|
||||
|
||||
if (terminating_node->flavor == CIL_MACRO) {
|
||||
cil_list_prepend(trace, CIL_NODE, terminating_node);
|
||||
} else {
|
||||
cil_list_prepend(trace, CIL_NODE, NODE(((struct cil_call *)terminating_node->data)->macro));
|
||||
}
|
||||
|
||||
cil_list_for_each(item, trace) {
|
||||
curr = item->data;
|
||||
cil_log(CIL_ERR, " %s:%d: ", curr->path, curr->line);
|
||||
|
||||
if (curr->flavor == CIL_MACRO) {
|
||||
cil_log(CIL_ERR, "macro %s\n", DATUM(curr->data)->name);
|
||||
} else {
|
||||
cil_log(CIL_ERR, "call %s\n", ((struct cil_call *)curr->data)->macro_str);
|
||||
}
|
||||
}
|
||||
|
||||
cil_list_destroy(&trace, CIL_FALSE);
|
||||
}
|
||||
|
||||
int cil_check_recursive_call(struct cil_tree_node *call_node, struct cil_tree_node *macro_node)
|
||||
{
|
||||
struct cil_tree_node *curr = NULL;
|
||||
struct cil_call * call = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
for (curr = call_node; curr != NULL; curr = curr->parent) {
|
||||
if (curr->flavor == CIL_CALL) {
|
||||
if (curr == call_node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
call = curr->data;
|
||||
if (call->macro != macro_node->data) {
|
||||
continue;
|
||||
}
|
||||
} else if (curr->flavor == CIL_MACRO) {
|
||||
if (curr != macro_node) {
|
||||
rc = SEPOL_OK;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
cil_log(CIL_ERR, "Recursive macro call found:\n");
|
||||
cil_print_recursive_call(call_node, curr);
|
||||
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = SEPOL_OK;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
struct cil_call *new_call = current->data;
|
||||
@ -2408,7 +2666,7 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
|
||||
macro_node = macro_datum->nodes->head->data;
|
||||
|
||||
if (macro_node->flavor != CIL_MACRO) {
|
||||
printf("Failed to resolve macro %s\n", new_call->macro_str);
|
||||
printf("Failed to resolve %s to a macro\n", new_call->macro_str);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
@ -2623,6 +2881,12 @@ int cil_resolve_call1(struct cil_tree_node *current, void *extra_args)
|
||||
|
||||
if (new_call->copied == 0) {
|
||||
new_call->copied = 1;
|
||||
|
||||
rc = cil_check_recursive_call(current, macro_node);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_copy_ast(db, macro_node, current);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to copy macro, rc: %d\n", rc);
|
||||
@ -2974,6 +3238,48 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args)
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_userattributeset *attrusers = current->data;
|
||||
struct cil_symtab_datum *attr_datum = NULL;
|
||||
struct cil_tree_node *attr_node = NULL;
|
||||
struct cil_userattribute *attr = NULL;
|
||||
|
||||
rc = cil_resolve_name(current, attrusers->attr_str, CIL_SYM_USERS, extra_args, &attr_datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
attr_node = attr_datum->nodes->head->data;
|
||||
|
||||
if (attr_node->flavor != CIL_USERATTRIBUTE) {
|
||||
rc = SEPOL_ERR;
|
||||
cil_log(CIL_ERR, "Attribute user not an attribute\n");
|
||||
goto exit;
|
||||
}
|
||||
attr = (struct cil_userattribute*)attr_datum;
|
||||
|
||||
rc = cil_resolve_expr(CIL_USERATTRIBUTESET, attrusers->str_expr, &attrusers->datum_expr, current, extra_args);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = cil_verify_no_self_reference(attr_datum, attrusers->datum_expr);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (attr->expr_list == NULL) {
|
||||
cil_list_init(&attr->expr_list, CIL_USERATTRIBUTE);
|
||||
}
|
||||
|
||||
cil_list_append(attr->expr_list, CIL_LIST, attrusers->datum_expr);
|
||||
|
||||
return SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
|
||||
{
|
||||
@ -3128,6 +3434,12 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
|
||||
case CIL_AVRULE:
|
||||
rc = cil_resolve_avrule(node, args);
|
||||
break;
|
||||
case CIL_AVRULEX:
|
||||
rc = cil_resolve_avrulex(node, args);
|
||||
break;
|
||||
case CIL_PERMISSIONX:
|
||||
rc = cil_resolve_permissionx(node, (struct cil_permissionx*)node->data, args);
|
||||
break;
|
||||
case CIL_TYPE_RULE:
|
||||
rc = cil_resolve_type_rule(node, args);
|
||||
break;
|
||||
@ -3228,6 +3540,9 @@ int __cil_resolve_ast_node(struct cil_tree_node *node, void *extra_args)
|
||||
case CIL_DEFAULTRANGE:
|
||||
rc = cil_resolve_defaultrange(node, args);
|
||||
break;
|
||||
case CIL_USERATTRIBUTESET:
|
||||
rc = cil_resolve_userattributeset(node, args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -3250,6 +3565,7 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, __attribute__((unu
|
||||
struct cil_tree_node *optstack = args->optstack;
|
||||
struct cil_tree_node *boolif = args->boolif;
|
||||
struct cil_tree_node *blockstack = args->blockstack;
|
||||
struct cil_tree_node *macro = args->macro;
|
||||
|
||||
if (node == NULL) {
|
||||
goto exit;
|
||||
@ -3272,6 +3588,17 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, __attribute__((unu
|
||||
}
|
||||
}
|
||||
|
||||
if (macro != NULL) {
|
||||
if (node->flavor == CIL_BLOCKINHERIT ||
|
||||
node->flavor == CIL_BLOCK ||
|
||||
node->flavor == CIL_BLOCKABSTRACT ||
|
||||
node->flavor == CIL_MACRO) {
|
||||
cil_log(CIL_ERR, "%s statement is not allowed in macros (%s:%d)\n", cil_node_to_string(node), node->path, node->line);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (boolif != NULL) {
|
||||
if (!(node->flavor == CIL_CONDBLOCK ||
|
||||
node->flavor == CIL_AVRULE ||
|
||||
@ -3304,14 +3631,22 @@ int __cil_resolve_ast_node_helper(struct cil_tree_node *node, __attribute__((unu
|
||||
}
|
||||
|
||||
rc = __cil_resolve_ast_node(node, extra_args);
|
||||
if (rc == SEPOL_ENOENT && optstack != NULL) {
|
||||
struct cil_optional *opt = (struct cil_optional *)optstack->data;
|
||||
cil_log(CIL_WARN, "Disabling optional %s at %d of %s\n", opt->datum.name, node->parent->line, node->parent->path);
|
||||
/* disable an optional if something failed to resolve */
|
||||
opt->enabled = CIL_FALSE;
|
||||
rc = SEPOL_OK;
|
||||
} else if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Failed to resolve %s statement at %d of %s\n", cil_node_to_string(node), node->line, node->path);
|
||||
if (rc == SEPOL_ENOENT) {
|
||||
enum cil_log_level lvl = CIL_ERR;
|
||||
|
||||
if (optstack != NULL) {
|
||||
lvl = CIL_WARN;
|
||||
|
||||
struct cil_optional *opt = (struct cil_optional *)optstack->data;
|
||||
struct cil_tree_node *opt_node = opt->datum.nodes->head->data;
|
||||
cil_log(lvl, "Disabling optional '%s' at line %d of %s: ", opt->datum.name, opt_node->line, opt_node->path);
|
||||
/* disable an optional if something failed to resolve */
|
||||
opt->enabled = CIL_FALSE;
|
||||
rc = SEPOL_OK;
|
||||
}
|
||||
|
||||
cil_log(lvl, "Failed to resolve '%s' in %s statement at line %d of %s\n",
|
||||
args->last_resolved_name, cil_node_to_string(node), node->line, node->path);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -3325,7 +3660,6 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex
|
||||
{
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_args_resolve *args = extra_args;
|
||||
struct cil_tree_node *callstack = NULL;
|
||||
struct cil_tree_node *optstack = NULL;
|
||||
struct cil_tree_node *parent = NULL;
|
||||
struct cil_tree_node *blockstack = NULL;
|
||||
@ -3335,36 +3669,18 @@ int __cil_resolve_ast_first_child_helper(struct cil_tree_node *current, void *ex
|
||||
goto exit;
|
||||
}
|
||||
|
||||
callstack = args->callstack;
|
||||
optstack = args->optstack;
|
||||
parent = current->parent;
|
||||
blockstack = args->blockstack;
|
||||
|
||||
if (parent->flavor == CIL_CALL || parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
|
||||
if (parent->flavor == CIL_OPTIONAL || parent->flavor == CIL_BLOCK) {
|
||||
/* push this node onto a stack */
|
||||
cil_tree_node_init(&new);
|
||||
|
||||
new->data = parent->data;
|
||||
new->flavor = parent->flavor;
|
||||
|
||||
if (parent->flavor == CIL_CALL) {
|
||||
if (callstack != NULL) {
|
||||
struct cil_tree_node *curr = NULL;
|
||||
struct cil_call *new_call = new->data;
|
||||
for (curr = callstack->cl_head; curr != NULL;
|
||||
curr = curr->cl_head) {
|
||||
struct cil_call *curr_call = curr->data;
|
||||
if (curr_call->macro == new_call->macro) {
|
||||
cil_log(CIL_ERR, "Recursive macro call found\n");
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
callstack->parent = new;
|
||||
new->cl_head = callstack;
|
||||
}
|
||||
args->callstack = new;
|
||||
} else if (parent->flavor == CIL_OPTIONAL) {
|
||||
if (parent->flavor == CIL_OPTIONAL) {
|
||||
if (optstack != NULL) {
|
||||
optstack->parent = new;
|
||||
new->cl_head = optstack;
|
||||
@ -3403,15 +3719,7 @@ int __cil_resolve_ast_last_child_helper(struct cil_tree_node *current, void *ext
|
||||
|
||||
parent = current->parent;
|
||||
|
||||
if (parent->flavor == CIL_CALL) {
|
||||
/* pop off the stack */
|
||||
struct cil_tree_node *callstack = args->callstack;
|
||||
args->callstack = callstack->cl_head;
|
||||
if (callstack->cl_head) {
|
||||
callstack->cl_head->parent = NULL;
|
||||
}
|
||||
free(callstack);
|
||||
} else if (parent->flavor == CIL_MACRO) {
|
||||
if (parent->flavor == CIL_MACRO) {
|
||||
args->macro = NULL;
|
||||
} else if (parent->flavor == CIL_OPTIONAL) {
|
||||
struct cil_tree_node *optstack;
|
||||
@ -3460,7 +3768,7 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
|
||||
extra_args.db = db;
|
||||
extra_args.pass = pass;
|
||||
extra_args.changed = &changed;
|
||||
extra_args.callstack = NULL;
|
||||
extra_args.last_resolved_name = NULL;
|
||||
extra_args.optstack = NULL;
|
||||
extra_args.boolif= NULL;
|
||||
extra_args.macro = NULL;
|
||||
@ -3552,12 +3860,6 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
|
||||
|
||||
/* reset the arguments */
|
||||
changed = 0;
|
||||
while (extra_args.callstack != NULL) {
|
||||
struct cil_tree_node *curr = extra_args.callstack;
|
||||
struct cil_tree_node *next = curr->cl_head;
|
||||
free(curr);
|
||||
extra_args.callstack = next;
|
||||
}
|
||||
while (extra_args.optstack != NULL) {
|
||||
struct cil_tree_node *curr = extra_args.optstack;
|
||||
struct cil_tree_node *next = curr->cl_head;
|
||||
@ -3579,6 +3881,12 @@ int cil_resolve_ast(struct cil_db *db, struct cil_tree_node *current)
|
||||
|
||||
rc = SEPOL_OK;
|
||||
exit:
|
||||
__cil_ordered_lists_destroy(&extra_args.sidorder_lists);
|
||||
__cil_ordered_lists_destroy(&extra_args.classorder_lists);
|
||||
__cil_ordered_lists_destroy(&extra_args.catorder_lists);
|
||||
__cil_ordered_lists_destroy(&extra_args.sensitivityorder_lists);
|
||||
cil_list_destroy(&extra_args.in_list, CIL_FALSE);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3734,8 +4042,6 @@ int cil_resolve_name(struct cil_tree_node *ast_node, char *name, enum cil_sym_in
|
||||
exit:
|
||||
if (rc != SEPOL_OK) {
|
||||
*datum = NULL;
|
||||
cil_log(CIL_WARN, "Failed to resolve %s in %s statement on line %d of %s\n",
|
||||
name, cil_node_to_string(ast_node), ast_node->line, ast_node->path);
|
||||
}
|
||||
|
||||
if (*datum != NULL) {
|
||||
@ -3752,5 +4058,7 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
args->last_resolved_name = name;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ int cil_resolve_userlevel(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_userrange(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_userbounds(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_userprefix(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_userattributeset(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_selinuxuser(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_roletype(struct cil_tree_node *current, void *extra_args);
|
||||
int cil_resolve_roletransition(struct cil_tree_node *current, void *extra_args);
|
||||
|
@ -640,15 +640,18 @@ void cil_tree_print_node(struct cil_tree_node *node)
|
||||
case CIL_USERROLE: {
|
||||
struct cil_userrole *userrole = node->data;
|
||||
cil_log(CIL_INFO, "USERROLE:");
|
||||
struct cil_symtab_datum *datum = NULL;
|
||||
|
||||
if (userrole->user != NULL) {
|
||||
cil_log(CIL_INFO, " %s", userrole->user->datum.name);
|
||||
datum = userrole->user;
|
||||
cil_log(CIL_INFO, " %s", datum->name);
|
||||
} else if (userrole->user_str != NULL) {
|
||||
cil_log(CIL_INFO, " %s", userrole->user_str);
|
||||
}
|
||||
|
||||
if (userrole->role != NULL) {
|
||||
cil_log(CIL_INFO, " %s", ((struct cil_symtab_datum *)userrole->role)->name);
|
||||
datum = userrole->role;
|
||||
cil_log(CIL_INFO, " %s", datum->name);
|
||||
} else if (userrole->role_str != NULL) {
|
||||
cil_log(CIL_INFO, " %s", userrole->role_str);
|
||||
}
|
||||
@ -785,6 +788,21 @@ void cil_tree_print_node(struct cil_tree_node *node)
|
||||
cil_log(CIL_INFO, "ROLEATTRIBUTE: %s\n", attr->datum.name);
|
||||
return;
|
||||
}
|
||||
case CIL_USERATTRIBUTESET: {
|
||||
struct cil_userattributeset *attr = node->data;
|
||||
|
||||
cil_log(CIL_INFO, "(USERATTRIBUTESET %s ", attr->attr_str);
|
||||
|
||||
cil_tree_print_expr(attr->datum_expr, attr->str_expr);
|
||||
|
||||
cil_log(CIL_INFO, "\n");
|
||||
return;
|
||||
}
|
||||
case CIL_USERATTRIBUTE: {
|
||||
struct cil_userattribute *attr = node->data;
|
||||
cil_log(CIL_INFO, "USERATTRIBUTE: %s\n", attr->datum.name);
|
||||
return;
|
||||
}
|
||||
case CIL_ROLEBOUNDS: {
|
||||
struct cil_bounds *bnds = node->data;
|
||||
cil_log(CIL_INFO, "ROLEBOUNDS: role: %s, bounds: %s\n", bnds->parent_str, bnds->child_str);
|
||||
|
@ -179,8 +179,8 @@ int cil_verify_expr_syntax(struct cil_tree_node *current, enum cil_flavor op, en
|
||||
syntax_len = 2;
|
||||
break;
|
||||
case CIL_RANGE:
|
||||
if (expr_flavor != CIL_CAT) {
|
||||
cil_log(CIL_ERR,"Operator (%s) only valid for catset expression\n", (char*)current->data);
|
||||
if (expr_flavor != CIL_CAT && expr_flavor != CIL_PERMISSIONX) {
|
||||
cil_log(CIL_ERR,"Operator (%s) only valid for catset and permissionx expression\n", (char*)current->data);
|
||||
goto exit;
|
||||
}
|
||||
syntax[1] = CIL_SYN_STRING;
|
||||
@ -737,16 +737,8 @@ int __cil_verify_context(struct cil_db *db, struct cil_context *ctx)
|
||||
int found = CIL_FALSE;
|
||||
|
||||
if (user->roles != NULL) {
|
||||
cil_list_for_each(curr, user->roles) {
|
||||
struct cil_role *userrole = curr->data;
|
||||
if (userrole == role) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr == NULL) {
|
||||
cil_log(CIL_ERR, "Role %s is invalid for user %s\n",
|
||||
ctx->role_str, ctx->user_str);
|
||||
if (!ebitmap_get_bit(user->roles, role->value)) {
|
||||
cil_log(CIL_ERR, "Role %s is invalid for user %s\n", ctx->role_str, ctx->user_str);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
@ -1494,13 +1486,22 @@ static int __cil_verify_classpermission(struct cil_tree_node *node)
|
||||
int rc = SEPOL_ERR;
|
||||
struct cil_classpermission *cp = node->data;
|
||||
|
||||
if (cp->classperms == NULL) {
|
||||
cil_log(CIL_ERR, "Classpermission %s does not have a classpermissionset at line %d of %s\n", cp->datum.name, node->line, node->path);
|
||||
rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_classperms(cp->classperms, &cp->datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Found circular class permissions involving the set %s at line %d of %s\n",cp->datum.name, node->line, node->path);
|
||||
return rc;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return SEPOL_OK;
|
||||
rc = SEPOL_OK;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct cil_verify_map_args {
|
||||
@ -1515,12 +1516,20 @@ static int __verify_map_perm_classperms(__attribute__((unused)) hashtab_key_t k,
|
||||
struct cil_verify_map_args *map_args = args;
|
||||
struct cil_perm *cmp = (struct cil_perm *)d;
|
||||
|
||||
if (cmp->classperms == NULL) {
|
||||
cil_log(CIL_ERR, "Map class %s does not have a classmapping for %s at line %d of %s\n", map_args->class->datum.name, cmp->datum.name, map_args->node->line, map_args->node->path);
|
||||
map_args->rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = __cil_verify_classperms(cmp->classperms, &cmp->datum);
|
||||
if (rc != SEPOL_OK) {
|
||||
cil_log(CIL_ERR, "Found circular class permissions involving the map class %s and permission %s at line %d of %s\n", map_args->class->datum.name, cmp->datum.name, map_args->node->line, map_args->node->path);
|
||||
map_args->rc = SEPOL_ERR;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return SEPOL_OK;
|
||||
}
|
||||
|
||||
|
@ -59,28 +59,29 @@ typedef struct avtab_key {
|
||||
#define AVTAB_MEMBER 0x0020
|
||||
#define AVTAB_CHANGE 0x0040
|
||||
#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
|
||||
#define AVTAB_OPNUM_ALLOWED 0x0100
|
||||
#define AVTAB_OPNUM_AUDITALLOW 0x0200
|
||||
#define AVTAB_OPNUM_DONTAUDIT 0x0400
|
||||
#define AVTAB_OPNUM (AVTAB_OPNUM_ALLOWED | AVTAB_OPNUM_AUDITALLOW | AVTAB_OPNUM_DONTAUDIT)
|
||||
#define AVTAB_OPTYPE_ALLOWED 0x1000
|
||||
#define AVTAB_OPTYPE_AUDITALLOW 0x2000
|
||||
#define AVTAB_OPTYPE_DONTAUDIT 0x4000
|
||||
#define AVTAB_OPTYPE (AVTAB_OPTYPE_ALLOWED | AVTAB_OPTYPE_AUDITALLOW | AVTAB_OPTYPE_DONTAUDIT)
|
||||
#define AVTAB_OP (AVTAB_OPNUM | AVTAB_OPTYPE)
|
||||
#define AVTAB_XPERMS_ALLOWED 0x0100
|
||||
#define AVTAB_XPERMS_AUDITALLOW 0x0200
|
||||
#define AVTAB_XPERMS_DONTAUDIT 0x0400
|
||||
#define AVTAB_XPERMS_NEVERALLOW 0x0800
|
||||
#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | AVTAB_XPERMS_DONTAUDIT)
|
||||
#define AVTAB_ENABLED_OLD 0x80000000
|
||||
#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
|
||||
uint16_t specified; /* what fields are specified */
|
||||
} avtab_key_t;
|
||||
|
||||
typedef struct avtab_operations {
|
||||
uint8_t type;
|
||||
typedef struct avtab_extended_perms {
|
||||
|
||||
#define AVTAB_XPERMS_IOCTLFUNCTION 0x01
|
||||
#define AVTAB_XPERMS_IOCTLDRIVER 0x02
|
||||
/* extension of the avtab_key specified */
|
||||
uint8_t specified;
|
||||
uint8_t driver;
|
||||
uint32_t perms[8];
|
||||
} avtab_operations_t;
|
||||
} avtab_extended_perms_t;
|
||||
|
||||
typedef struct avtab_datum {
|
||||
uint32_t data; /* access vector or type */
|
||||
avtab_operations_t *ops;
|
||||
avtab_extended_perms_t *xperms;
|
||||
} avtab_datum_t;
|
||||
|
||||
typedef struct avtab_node *avtab_ptr_t;
|
||||
|
@ -86,6 +86,7 @@ extern unsigned int ebitmap_cardinality(ebitmap_t *e1);
|
||||
extern int ebitmap_hamming_distance(ebitmap_t * e1, ebitmap_t * e2);
|
||||
extern int ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src);
|
||||
extern int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2);
|
||||
extern int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2);
|
||||
extern int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit);
|
||||
extern int ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value);
|
||||
extern void ebitmap_destroy(ebitmap_t * e);
|
||||
|
@ -25,11 +25,22 @@
|
||||
#ifndef _SEPOL_POLICYDB_HIERARCHY_H_
|
||||
#define _SEPOL_POLICYDB_HIERARCHY_H_
|
||||
|
||||
#include <sepol/policydb/avtab.h>
|
||||
#include <sepol/policydb/policydb.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern int hierarchy_add_bounds(sepol_handle_t *handle, policydb_t *p);
|
||||
|
||||
extern void bounds_destroy_bad(avtab_ptr_t cur);
|
||||
extern int bounds_check_type(sepol_handle_t *handle, policydb_t *p, uint32_t child,
|
||||
uint32_t parent, avtab_ptr_t *bad, int *numbad);
|
||||
|
||||
extern int bounds_check_users(sepol_handle_t *handle, policydb_t *p);
|
||||
extern int bounds_check_roles(sepol_handle_t *handle, policydb_t *p);
|
||||
extern int bounds_check_types(sepol_handle_t *handle, policydb_t *p);
|
||||
|
||||
extern int hierarchy_check_constraints(sepol_handle_t * handle, policydb_t * p);
|
||||
|
||||
__END_DECLS
|
||||
|
@ -241,11 +241,19 @@ typedef struct class_perm_node {
|
||||
struct class_perm_node *next;
|
||||
} class_perm_node_t;
|
||||
|
||||
typedef struct av_operations {
|
||||
uint8_t type;
|
||||
/* 256 bits of ioctl number permissions */
|
||||
uint32_t perms[8];
|
||||
} av_operations_t;
|
||||
#define xperm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
|
||||
#define xperm_set(x, p) (p[x >> 5] |= (1 << (x & 0x1f)))
|
||||
#define xperm_clear(x, p) (p[x >> 5] &= ~(1 << (x & 0x1f)))
|
||||
#define EXTENDED_PERMS_LEN 8
|
||||
|
||||
typedef struct av_extended_perms {
|
||||
#define AVRULE_XPERMS_IOCTLFUNCTION 0x01
|
||||
#define AVRULE_XPERMS_IOCTLDRIVER 0x02
|
||||
uint8_t specified;
|
||||
uint8_t driver;
|
||||
/* 256 bits of permissions */
|
||||
uint32_t perms[EXTENDED_PERMS_LEN];
|
||||
} av_extended_perms_t;
|
||||
|
||||
typedef struct avrule {
|
||||
/* these typedefs are almost exactly the same as those in avtab.h - they are
|
||||
@ -260,24 +268,19 @@ typedef struct avrule {
|
||||
#define AVRULE_MEMBER 0x0020
|
||||
#define AVRULE_CHANGE 0x0040
|
||||
#define AVRULE_TYPE (AVRULE_TRANSITION | AVRULE_MEMBER | AVRULE_CHANGE)
|
||||
#define AVRULE_OPNUM_ALLOWED 0x0100
|
||||
#define AVRULE_OPNUM_AUDITALLOW 0x0200
|
||||
#define AVRULE_OPNUM_DONTAUDIT 0x0400
|
||||
#define AVRULE_OPNUM (AVRULE_OPNUM_ALLOWED | AVRULE_OPNUM_AUDITALLOW | \
|
||||
AVRULE_OPNUM_DONTAUDIT)
|
||||
#define AVRULE_OPTYPE_ALLOWED 0x1000
|
||||
#define AVRULE_OPTYPE_AUDITALLOW 0x2000
|
||||
#define AVRULE_OPTYPE_DONTAUDIT 0x4000
|
||||
#define AVRULE_OPTYPE (AVRULE_OPTYPE_ALLOWED | AVRULE_OPTYPE_AUDITALLOW | \
|
||||
AVRULE_OPTYPE_DONTAUDIT)
|
||||
#define AVRULE_OP (AVRULE_OPNUM | AVRULE_OPTYPE)
|
||||
#define AVRULE_XPERMS_ALLOWED 0x0100
|
||||
#define AVRULE_XPERMS_AUDITALLOW 0x0200
|
||||
#define AVRULE_XPERMS_DONTAUDIT 0x0400
|
||||
#define AVRULE_XPERMS_NEVERALLOW 0x0800
|
||||
#define AVRULE_XPERMS (AVRULE_XPERMS_ALLOWED | AVRULE_XPERMS_AUDITALLOW | \
|
||||
AVRULE_XPERMS_DONTAUDIT | AVRULE_XPERMS_NEVERALLOW)
|
||||
uint32_t specified;
|
||||
#define RULE_SELF 1
|
||||
uint32_t flags;
|
||||
type_set_t stypes;
|
||||
type_set_t ttypes;
|
||||
class_perm_node_t *perms;
|
||||
av_operations_t * ops;
|
||||
av_extended_perms_t *xperms;
|
||||
unsigned long line; /* line number from policy.conf where
|
||||
* this rule originated */
|
||||
/* source file name and line number (e.g. .te file) */
|
||||
@ -652,7 +655,7 @@ extern void level_datum_init(level_datum_t * x);
|
||||
extern void level_datum_destroy(level_datum_t * x);
|
||||
extern void cat_datum_init(cat_datum_t * x);
|
||||
extern void cat_datum_destroy(cat_datum_t * x);
|
||||
|
||||
extern int check_assertion(policydb_t *p, avrule_t *avrule);
|
||||
extern int check_assertions(sepol_handle_t * handle,
|
||||
policydb_t * p, avrule_t * avrules);
|
||||
|
||||
@ -709,11 +712,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
|
||||
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
||||
#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
|
||||
#define POLICYDB_VERSION_XEN_DEVICETREE 30 /* Xen-specific */
|
||||
#define POLICYDB_VERSION_IOCTL_OPERATIONS 30 /* Linux-specific */
|
||||
#define POLICYDB_VERSION_XPERMS_IOCTL 30 /* Linux-specific */
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_IOCTL_OPERATIONS
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL
|
||||
|
||||
/* Module versions and specific changes*/
|
||||
#define MOD_POLICYDB_VERSION_BASE 4
|
||||
|
@ -32,5 +32,13 @@ extern int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a);
|
||||
extern char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
||||
sepol_access_vector_t av);
|
||||
|
||||
char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms);
|
||||
|
||||
/*
|
||||
* The tokenize function may be used to
|
||||
* replace sscanf
|
||||
*/
|
||||
extern int tokenize(char *line_buf, char delim, int num_args, ...);
|
||||
|
||||
__END_DECLS
|
||||
#endif
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Authors: Joshua Brindle <jbrindle@tresys.com>
|
||||
*
|
||||
* Assertion checker for avtab entries, taken from
|
||||
*
|
||||
* Assertion checker for avtab entries, taken from
|
||||
* checkpolicy.c by Stephen Smalley <sds@tycho.nsa.gov>
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2005 Tresys Technology, LLC
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -25,13 +25,20 @@
|
||||
#include <sepol/policydb/expand.h>
|
||||
#include <sepol/policydb/util.h>
|
||||
|
||||
#include "private.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void report_failure(sepol_handle_t *handle, policydb_t *p,
|
||||
const avrule_t * avrule,
|
||||
struct avtab_match_args {
|
||||
sepol_handle_t *handle;
|
||||
policydb_t *p;
|
||||
avrule_t *avrule;
|
||||
avtab_t *avtab;
|
||||
unsigned long errors;
|
||||
};
|
||||
|
||||
static void report_failure(sepol_handle_t *handle, policydb_t *p, const avrule_t *avrule,
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const class_perm_node_t *curperm,
|
||||
const avtab_ptr_t node)
|
||||
const class_perm_node_t *curperm, uint32_t perms)
|
||||
{
|
||||
if (avrule->source_filename) {
|
||||
ERR(handle, "neverallow on line %lu of %s (or line %lu of policy.conf) violated by allow %s %s:%s {%s };",
|
||||
@ -39,69 +46,386 @@ static void report_failure(sepol_handle_t *handle, policydb_t *p,
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
} else if (avrule->line) {
|
||||
ERR(handle, "neverallow on line %lu violated by allow %s %s:%s {%s };",
|
||||
avrule->line, p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
} else {
|
||||
ERR(handle, "neverallow violated by allow %s %s:%s {%s };",
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass,
|
||||
node->datum.data & curperm->data));
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long check_assertion_helper(sepol_handle_t * handle,
|
||||
policydb_t * p,
|
||||
avtab_t * te_avtab, avtab_t * te_cond_avtab,
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const avrule_t * avrule)
|
||||
static int match_any_class_permissions(class_perm_node_t *cp, uint32_t class, uint32_t data)
|
||||
{
|
||||
avtab_key_t avkey;
|
||||
avtab_ptr_t node;
|
||||
class_perm_node_t *curperm;
|
||||
unsigned long errors = 0;
|
||||
|
||||
for (curperm = avrule->perms; curperm != NULL; curperm = curperm->next) {
|
||||
avkey.source_type = stype + 1;
|
||||
avkey.target_type = ttype + 1;
|
||||
avkey.target_class = curperm->tclass;
|
||||
avkey.specified = AVTAB_ALLOWED;
|
||||
for (node = avtab_search_node(te_avtab, &avkey);
|
||||
node != NULL;
|
||||
node = avtab_search_node_next(node, avkey.specified)) {
|
||||
if (node->datum.data & curperm->data) {
|
||||
report_failure(handle, p, avrule, stype, ttype, curperm, node);
|
||||
errors++;
|
||||
}
|
||||
for (; cp; cp = cp->next) {
|
||||
if ((cp->tclass == class) && (cp->data & data)) {
|
||||
break;
|
||||
}
|
||||
for (node = avtab_search_node(te_cond_avtab, &avkey);
|
||||
node != NULL;
|
||||
node = avtab_search_node_next(node, avkey.specified)) {
|
||||
if (node->datum.data & curperm->data) {
|
||||
report_failure(handle, p, avrule, stype, ttype, curperm, node);
|
||||
errors++;
|
||||
}
|
||||
if (!cp)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int extended_permissions_and(uint32_t *perms1, uint32_t *perms2) {
|
||||
size_t i;
|
||||
for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
|
||||
if (perms1[i] & perms2[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_extended_permissions(av_extended_perms_t *neverallow, avtab_extended_perms_t *allow)
|
||||
{
|
||||
int rc = 0;
|
||||
if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
|
||||
if (neverallow->driver == allow->driver)
|
||||
rc = extended_permissions_and(neverallow->perms, allow->perms);
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
|
||||
rc = xperm_test(neverallow->driver, allow->perms);
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
|
||||
rc = xperm_test(allow->driver, neverallow->perms);
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
|
||||
rc = extended_permissions_and(neverallow->perms, allow->perms);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Compute which allowed extended permissions violate the neverallow rule */
|
||||
static void extended_permissions_violated(avtab_extended_perms_t *result,
|
||||
av_extended_perms_t *neverallow,
|
||||
avtab_extended_perms_t *allow)
|
||||
{
|
||||
size_t i;
|
||||
if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
|
||||
result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
|
||||
result->driver = allow->driver;
|
||||
for (i = 0; i < EXTENDED_PERMS_LEN; i++)
|
||||
result->perms[i] = neverallow->perms[i] & allow->perms[i];
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLFUNCTION)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
|
||||
result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
|
||||
result->driver = neverallow->driver;
|
||||
memcpy(result->perms, neverallow->perms, sizeof(result->perms));
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLFUNCTION)) {
|
||||
result->specified = AVTAB_XPERMS_IOCTLFUNCTION;
|
||||
result->driver = allow->driver;
|
||||
memcpy(result->perms, allow->perms, sizeof(result->perms));
|
||||
} else if ((neverallow->specified == AVRULE_XPERMS_IOCTLDRIVER)
|
||||
&& (allow->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
|
||||
result->specified = AVTAB_XPERMS_IOCTLDRIVER;
|
||||
for (i = 0; i < EXTENDED_PERMS_LEN; i++)
|
||||
result->perms[i] = neverallow->perms[i] & allow->perms[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Same scenarios of interest as check_assertion_extended_permissions */
|
||||
static int report_assertion_extended_permissions(sepol_handle_t *handle,
|
||||
policydb_t *p, const avrule_t *avrule,
|
||||
unsigned int stype, unsigned int ttype,
|
||||
const class_perm_node_t *curperm, uint32_t perms,
|
||||
avtab_key_t *k, avtab_t *avtab)
|
||||
{
|
||||
avtab_ptr_t node;
|
||||
avtab_key_t tmp_key;
|
||||
avtab_extended_perms_t *xperms;
|
||||
avtab_extended_perms_t error;
|
||||
int rc = 1;
|
||||
int ret = 0;
|
||||
|
||||
memcpy(&tmp_key, k, sizeof(avtab_key_t));
|
||||
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
|
||||
|
||||
for (node = avtab_search_node(avtab, &tmp_key);
|
||||
node;
|
||||
node = avtab_search_node_next(node, tmp_key.specified)) {
|
||||
xperms = node->datum.xperms;
|
||||
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
|
||||
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
|
||||
continue;
|
||||
|
||||
rc = check_extended_permissions(avrule->xperms, xperms);
|
||||
/* failure on the extended permission check_extended_permissionss */
|
||||
if (rc) {
|
||||
extended_permissions_violated(&error, avrule->xperms, xperms);
|
||||
ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
|
||||
"allowxperm %s %s:%s %s;",
|
||||
avrule->source_line, avrule->source_filename, avrule->line,
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_extended_perms_to_string(&error));
|
||||
|
||||
rc = 0;
|
||||
ret++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* failure on the regular permissions */
|
||||
if (rc) {
|
||||
ERR(handle, "neverallowxperm on line %lu of %s (or line %lu of policy.conf) violated by\n"
|
||||
"allow %s %s:%s {%s };",
|
||||
avrule->source_line, avrule->source_filename, avrule->line,
|
||||
p->p_type_val_to_name[stype],
|
||||
p->p_type_val_to_name[ttype],
|
||||
p->p_class_val_to_name[curperm->tclass - 1],
|
||||
sepol_av_to_string(p, curperm->tclass, perms));
|
||||
ret++;
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int report_assertion_avtab_matches(avtab_key_t *k, avtab_datum_t *d, void *args)
|
||||
{
|
||||
int rc = 0;
|
||||
struct avtab_match_args *a = (struct avtab_match_args *)args;
|
||||
sepol_handle_t *handle = a->handle;
|
||||
policydb_t *p = a->p;
|
||||
avtab_t *avtab = a->avtab;
|
||||
avrule_t *avrule = a->avrule;
|
||||
class_perm_node_t *cp;
|
||||
uint32_t perms;
|
||||
ebitmap_t src_matches, tgt_matches, matches;
|
||||
ebitmap_node_t *snode, *tnode;
|
||||
unsigned int i, j;
|
||||
|
||||
if (k->specified != AVTAB_ALLOWED)
|
||||
return 0;
|
||||
|
||||
if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
|
||||
return 0;
|
||||
|
||||
ebitmap_init(&src_matches);
|
||||
ebitmap_init(&tgt_matches);
|
||||
ebitmap_init(&matches);
|
||||
|
||||
rc = ebitmap_and(&src_matches, &avrule->stypes.types,
|
||||
&p->attr_type_map[k->source_type - 1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
if (ebitmap_length(&src_matches) == 0)
|
||||
goto exit;
|
||||
|
||||
if (avrule->flags == RULE_SELF) {
|
||||
rc = ebitmap_and(&matches, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
rc = ebitmap_and(&tgt_matches, &avrule->stypes.types, &matches);
|
||||
if (rc)
|
||||
goto oom;
|
||||
} else {
|
||||
rc = ebitmap_and(&tgt_matches, &avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
|
||||
if (rc)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
if (ebitmap_length(&tgt_matches) == 0)
|
||||
goto exit;
|
||||
|
||||
for (cp = avrule->perms; cp; cp = cp->next) {
|
||||
|
||||
perms = cp->data & d->data;
|
||||
if ((cp->tclass != k->target_class) || !perms) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ebitmap_for_each_bit(&src_matches, snode, i) {
|
||||
if (!ebitmap_node_get_bit(snode, i))
|
||||
continue;
|
||||
ebitmap_for_each_bit(&tgt_matches, tnode, j) {
|
||||
if (!ebitmap_node_get_bit(tnode, j))
|
||||
continue;
|
||||
|
||||
if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
|
||||
a->errors += report_assertion_extended_permissions(handle,p, avrule,
|
||||
i, j, cp, perms, k, avtab);
|
||||
} else {
|
||||
a->errors++;
|
||||
report_failure(handle, p, avrule, i, j, cp, perms);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
goto exit;
|
||||
|
||||
return errors;
|
||||
oom:
|
||||
ERR(NULL, "Out of memory - unable to check neverallows");
|
||||
|
||||
exit:
|
||||
ebitmap_destroy(&src_matches);
|
||||
ebitmap_destroy(&tgt_matches);
|
||||
ebitmap_destroy(&matches);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int report_assertion_failures(sepol_handle_t *handle, policydb_t *p, avrule_t *avrule)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args args;
|
||||
|
||||
args.handle = handle;
|
||||
args.p = p;
|
||||
args.avrule = avrule;
|
||||
args.errors = 0;
|
||||
|
||||
rc = avtab_map(&p->te_avtab, report_assertion_avtab_matches, &args);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
rc = avtab_map(&p->te_cond_avtab, report_assertion_avtab_matches, &args);
|
||||
if (rc)
|
||||
goto oom;
|
||||
|
||||
return args.errors;
|
||||
|
||||
oom:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the ioctl permission is granted in check_assertion_avtab_match for the
|
||||
* source/target/class matching the current avrule neverallow, a lookup is
|
||||
* performed to determine if extended permissions exist for the source/target/class.
|
||||
*
|
||||
* Four scenarios of interest:
|
||||
* 1. PASS - the ioctl permission is not granted for this source/target/class
|
||||
* This case is handled in check_assertion_avtab_match
|
||||
* 2. PASS - The ioctl permission is granted AND the extended permission
|
||||
* is NOT granted
|
||||
* 3. FAIL - The ioctl permission is granted AND no extended permissions
|
||||
* exist
|
||||
* 4. FAIL - The ioctl permission is granted AND the extended permission is
|
||||
* granted
|
||||
*/
|
||||
static int check_assertion_extended_permissions(avrule_t *avrule, avtab_t *avtab,
|
||||
avtab_key_t *k)
|
||||
{
|
||||
avtab_ptr_t node;
|
||||
avtab_key_t tmp_key;
|
||||
avtab_extended_perms_t *xperms;
|
||||
av_extended_perms_t *neverallow_xperms = avrule->xperms;
|
||||
int rc = 1;
|
||||
|
||||
memcpy(&tmp_key, k, sizeof(avtab_key_t));
|
||||
tmp_key.specified = AVTAB_XPERMS_ALLOWED;
|
||||
|
||||
for (node = avtab_search_node(avtab, &tmp_key);
|
||||
node;
|
||||
node = avtab_search_node_next(node, tmp_key.specified)) {
|
||||
xperms = node->datum.xperms;
|
||||
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
|
||||
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
|
||||
continue;
|
||||
|
||||
rc = check_extended_permissions(neverallow_xperms, xperms);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int check_assertion_avtab_match(avtab_key_t *k, avtab_datum_t *d, void *args)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args *a = (struct avtab_match_args *)args;
|
||||
policydb_t *p = a->p;
|
||||
avrule_t *avrule = a->avrule;
|
||||
avtab_t *avtab = a->avtab;
|
||||
|
||||
if (k->specified != AVTAB_ALLOWED)
|
||||
goto exit;
|
||||
|
||||
if (!match_any_class_permissions(avrule->perms, k->target_class, d->data))
|
||||
goto exit;
|
||||
|
||||
rc = ebitmap_match_any(&avrule->stypes.types, &p->attr_type_map[k->source_type - 1]);
|
||||
if (rc == 0)
|
||||
goto exit;
|
||||
|
||||
if (avrule->flags == RULE_SELF) {
|
||||
/* If the neverallow uses SELF, then it is not enough that the
|
||||
* neverallow's source matches the src and tgt of the rule being checked.
|
||||
* It must match the same thing in the src and tgt, so AND the source
|
||||
* and target together and check for a match on the result.
|
||||
*/
|
||||
ebitmap_t match;
|
||||
rc = ebitmap_and(&match, &p->attr_type_map[k->source_type - 1], &p->attr_type_map[k->target_type - 1] );
|
||||
if (rc) {
|
||||
ebitmap_destroy(&match);
|
||||
goto oom;
|
||||
}
|
||||
rc = ebitmap_match_any(&avrule->stypes.types, &match);
|
||||
ebitmap_destroy(&match);
|
||||
} else {
|
||||
rc = ebitmap_match_any(&avrule->ttypes.types, &p->attr_type_map[k->target_type -1]);
|
||||
}
|
||||
if (rc == 0)
|
||||
goto exit;
|
||||
|
||||
if (avrule->specified == AVRULE_XPERMS_NEVERALLOW) {
|
||||
rc = check_assertion_extended_permissions(avrule, avtab, k);
|
||||
if (rc == 0)
|
||||
goto exit;
|
||||
}
|
||||
return 1;
|
||||
|
||||
exit:
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
ERR(NULL, "Out of memory - unable to check neverallows");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_assertion(policydb_t *p, avrule_t *avrule)
|
||||
{
|
||||
int rc;
|
||||
struct avtab_match_args args;
|
||||
|
||||
args.handle = NULL;
|
||||
args.p = p;
|
||||
args.avrule = avrule;
|
||||
args.errors = 0;
|
||||
args.avtab = &p->te_avtab;
|
||||
|
||||
rc = avtab_map(&p->te_avtab, check_assertion_avtab_match, &args);
|
||||
|
||||
if (rc == 0) {
|
||||
args.avtab = &p->te_cond_avtab;
|
||||
rc = avtab_map(&p->te_cond_avtab, check_assertion_avtab_match, &args);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int check_assertions(sepol_handle_t * handle, policydb_t * p,
|
||||
avrule_t * avrules)
|
||||
{
|
||||
int rc;
|
||||
avrule_t *a;
|
||||
avtab_t te_avtab, te_cond_avtab;
|
||||
ebitmap_node_t *snode, *tnode;
|
||||
unsigned int i, j;
|
||||
unsigned long errors = 0;
|
||||
|
||||
if (!avrules) {
|
||||
@ -111,54 +435,22 @@ int check_assertions(sepol_handle_t * handle, policydb_t * p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (avrules) {
|
||||
if (avtab_init(&te_avtab))
|
||||
goto oom;
|
||||
if (avtab_init(&te_cond_avtab)) {
|
||||
avtab_destroy(&te_avtab);
|
||||
goto oom;
|
||||
}
|
||||
if (expand_avtab(p, &p->te_avtab, &te_avtab) ||
|
||||
expand_avtab(p, &p->te_cond_avtab, &te_cond_avtab)) {
|
||||
avtab_destroy(&te_avtab);
|
||||
avtab_destroy(&te_cond_avtab);
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = avrules; a != NULL; a = a->next) {
|
||||
ebitmap_t *stypes = &a->stypes.types;
|
||||
ebitmap_t *ttypes = &a->ttypes.types;
|
||||
|
||||
if (!(a->specified & AVRULE_NEVERALLOW))
|
||||
if (!(a->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)))
|
||||
continue;
|
||||
|
||||
ebitmap_for_each_bit(stypes, snode, i) {
|
||||
if (!ebitmap_node_get_bit(snode, i))
|
||||
continue;
|
||||
if (a->flags & RULE_SELF) {
|
||||
errors += check_assertion_helper
|
||||
(handle, p, &te_avtab, &te_cond_avtab, i, i,
|
||||
a);
|
||||
}
|
||||
ebitmap_for_each_bit(ttypes, tnode, j) {
|
||||
if (!ebitmap_node_get_bit(tnode, j))
|
||||
continue;
|
||||
errors += check_assertion_helper
|
||||
(handle, p, &te_avtab, &te_cond_avtab, i, j,
|
||||
a);
|
||||
rc = check_assertion(p, a);
|
||||
if (rc) {
|
||||
rc = report_assertion_failures(handle, p, a);
|
||||
if (rc < 0) {
|
||||
ERR(handle, "Error occurred while checking neverallows");
|
||||
return -1;
|
||||
}
|
||||
errors += rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors)
|
||||
ERR(handle, "%lu neverallow failures occurred", errors);
|
||||
|
||||
avtab_destroy(&te_avtab);
|
||||
avtab_destroy(&te_cond_avtab);
|
||||
return errors ? -1 : 0;
|
||||
|
||||
oom:
|
||||
ERR(handle, "Out of memory - unable to check neverallows");
|
||||
return -1;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
|
||||
avtab_datum_t * datum)
|
||||
{
|
||||
avtab_ptr_t newnode;
|
||||
avtab_operations_t *ops;
|
||||
avtab_extended_perms_t *xperms;
|
||||
|
||||
newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node));
|
||||
if (newnode == NULL)
|
||||
@ -101,16 +101,16 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key,
|
||||
memset(newnode, 0, sizeof(struct avtab_node));
|
||||
newnode->key = *key;
|
||||
|
||||
if (key->specified & AVTAB_OP) {
|
||||
ops = calloc(1, sizeof(avtab_operations_t));
|
||||
if (ops == NULL) {
|
||||
if (key->specified & AVTAB_XPERMS) {
|
||||
xperms = calloc(1, sizeof(avtab_extended_perms_t));
|
||||
if (xperms == NULL) {
|
||||
free(newnode);
|
||||
return NULL;
|
||||
}
|
||||
if (datum->ops) /* else caller populates ops*/
|
||||
*ops = *(datum->ops);
|
||||
if (datum->xperms) /* else caller populates xperms */
|
||||
*xperms = *(datum->xperms);
|
||||
|
||||
newnode->datum.ops = ops;
|
||||
newnode->datum.xperms = xperms;
|
||||
} else {
|
||||
newnode->datum = *datum;
|
||||
}
|
||||
@ -144,7 +144,8 @@ int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
|
||||
key->target_type == cur->key.target_type &&
|
||||
key->target_class == cur->key.target_class &&
|
||||
(specified & cur->key.specified)) {
|
||||
if (specified & AVTAB_OPNUM)
|
||||
/* Extended permissions are not necessarily unique */
|
||||
if (specified & AVTAB_XPERMS)
|
||||
break;
|
||||
return SEPOL_EEXIST;
|
||||
}
|
||||
@ -308,6 +309,9 @@ void avtab_destroy(avtab_t * h)
|
||||
for (i = 0; i < h->nslot; i++) {
|
||||
cur = h->htable[i];
|
||||
while (cur != NULL) {
|
||||
if (cur->key.specified & AVTAB_XPERMS) {
|
||||
free(cur->datum.xperms);
|
||||
}
|
||||
temp = cur;
|
||||
cur = cur->next;
|
||||
free(temp);
|
||||
@ -416,12 +420,9 @@ static uint16_t spec_order[] = {
|
||||
AVTAB_TRANSITION,
|
||||
AVTAB_CHANGE,
|
||||
AVTAB_MEMBER,
|
||||
AVTAB_OPNUM_ALLOWED,
|
||||
AVTAB_OPNUM_AUDITALLOW,
|
||||
AVTAB_OPNUM_DONTAUDIT,
|
||||
AVTAB_OPTYPE_ALLOWED,
|
||||
AVTAB_OPTYPE_AUDITALLOW,
|
||||
AVTAB_OPTYPE_DONTAUDIT
|
||||
AVTAB_XPERMS_ALLOWED,
|
||||
AVTAB_XPERMS_AUDITALLOW,
|
||||
AVTAB_XPERMS_DONTAUDIT
|
||||
};
|
||||
|
||||
int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
|
||||
@ -433,14 +434,14 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
|
||||
uint32_t buf32[8], items, items2, val;
|
||||
avtab_key_t key;
|
||||
avtab_datum_t datum;
|
||||
avtab_operations_t ops;
|
||||
avtab_extended_perms_t xperms;
|
||||
unsigned set;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
memset(&key, 0, sizeof(avtab_key_t));
|
||||
memset(&datum, 0, sizeof(avtab_datum_t));
|
||||
memset(&ops, 0, sizeof(avtab_operations_t));
|
||||
memset(&xperms, 0, sizeof(avtab_extended_perms_t));
|
||||
|
||||
if (vers < POLICYDB_VERSION_AVTAB) {
|
||||
rc = next_entry(buf32, fp, sizeof(uint32_t));
|
||||
@ -533,26 +534,32 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) &&
|
||||
(key.specified & AVTAB_OP)) {
|
||||
ERR(fp->handle, "policy version %u does not support ioctl "
|
||||
"operation rules and one was specified\n", vers);
|
||||
if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
|
||||
(key.specified & AVTAB_XPERMS)) {
|
||||
ERR(fp->handle, "policy version %u does not support extended "
|
||||
"permissions rules and one was specified\n", vers);
|
||||
return -1;
|
||||
} else if (key.specified & AVTAB_OP) {
|
||||
} else if (key.specified & AVTAB_XPERMS) {
|
||||
rc = next_entry(&buf8, fp, sizeof(uint8_t));
|
||||
if (rc < 0) {
|
||||
ERR(fp->handle, "truncated entry");
|
||||
return -1;
|
||||
}
|
||||
ops.type = buf8;
|
||||
xperms.specified = buf8;
|
||||
rc = next_entry(&buf8, fp, sizeof(uint8_t));
|
||||
if (rc < 0) {
|
||||
ERR(fp->handle, "truncated entry");
|
||||
return -1;
|
||||
}
|
||||
xperms.driver = buf8;
|
||||
rc = next_entry(buf32, fp, sizeof(uint32_t)*8);
|
||||
if (rc < 0) {
|
||||
ERR(fp->handle, "truncated entry");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(ops.perms); i++)
|
||||
ops.perms[i] = le32_to_cpu(buf32[i]);
|
||||
datum.ops = &ops;
|
||||
for (i = 0; i < ARRAY_SIZE(xperms.perms); i++)
|
||||
xperms.perms[i] = le32_to_cpu(buf32[i]);
|
||||
datum.xperms = &xperms;
|
||||
} else {
|
||||
rc = next_entry(buf32, fp, sizeof(uint32_t));
|
||||
if (rc < 0) {
|
||||
|
@ -224,6 +224,28 @@ int ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2)
|
||||
{
|
||||
ebitmap_node_t *n1 = e1->node;
|
||||
ebitmap_node_t *n2 = e2->node;
|
||||
|
||||
while (n1 && n2) {
|
||||
if (n1->startbit < n2->startbit) {
|
||||
n1 = n1->next;
|
||||
} else if (n2->startbit < n1->startbit) {
|
||||
n2 = n2->next;
|
||||
} else {
|
||||
if (n1->map & n2->map) {
|
||||
return 1;
|
||||
}
|
||||
n1 = n1->next;
|
||||
n2 = n2->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
|
||||
{
|
||||
ebitmap_node_t *n;
|
||||
|
@ -1604,24 +1604,25 @@ static int expand_range_trans(expand_state_t * state,
|
||||
static avtab_ptr_t find_avtab_node(sepol_handle_t * handle,
|
||||
avtab_t * avtab, avtab_key_t * key,
|
||||
cond_av_list_t ** cond,
|
||||
av_operations_t *operations)
|
||||
av_extended_perms_t *xperms)
|
||||
{
|
||||
avtab_ptr_t node;
|
||||
avtab_datum_t avdatum;
|
||||
cond_av_list_t *nl;
|
||||
int type_match = 0;
|
||||
int match = 0;
|
||||
|
||||
/* AVTAB_OPNUM entries are not necessarily unique */
|
||||
if (key->specified & AVTAB_OPNUM) {
|
||||
/* AVTAB_XPERMS entries are not necessarily unique */
|
||||
if (key->specified & AVTAB_XPERMS) {
|
||||
node = avtab_search_node(avtab, key);
|
||||
while (node) {
|
||||
if (node->datum.ops->type == operations->type) {
|
||||
type_match = 1;
|
||||
if ((node->datum.xperms->specified == xperms->specified) &&
|
||||
(node->datum.xperms->driver == xperms->driver)) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
node = avtab_search_node_next(node, key->specified);
|
||||
}
|
||||
if (!type_match)
|
||||
if (!match)
|
||||
node = NULL;
|
||||
} else {
|
||||
node = avtab_search_node(avtab, key);
|
||||
@ -1780,11 +1781,11 @@ static int expand_avrule_helper(sepol_handle_t * handle,
|
||||
cond_av_list_t ** cond,
|
||||
uint32_t stype, uint32_t ttype,
|
||||
class_perm_node_t * perms, avtab_t * avtab,
|
||||
int enabled, av_operations_t *operations)
|
||||
int enabled, av_extended_perms_t *extended_perms)
|
||||
{
|
||||
avtab_key_t avkey;
|
||||
avtab_datum_t *avdatump;
|
||||
avtab_operations_t *ops;
|
||||
avtab_extended_perms_t *xperms;
|
||||
avtab_ptr_t node;
|
||||
class_perm_node_t *cur;
|
||||
uint32_t spec = 0;
|
||||
@ -1802,22 +1803,14 @@ static int expand_avrule_helper(sepol_handle_t * handle,
|
||||
spec = AVTAB_AUDITDENY;
|
||||
} else if (specified & AVRULE_NEVERALLOW) {
|
||||
spec = AVTAB_NEVERALLOW;
|
||||
} else if (specified & AVRULE_OPNUM_ALLOWED) {
|
||||
spec = AVTAB_OPNUM_ALLOWED;
|
||||
} else if (specified & AVRULE_OPNUM_AUDITALLOW) {
|
||||
spec = AVTAB_OPNUM_AUDITALLOW;
|
||||
} else if (specified & AVRULE_OPNUM_DONTAUDIT) {
|
||||
} else if (specified & AVRULE_XPERMS_ALLOWED) {
|
||||
spec = AVTAB_XPERMS_ALLOWED;
|
||||
} else if (specified & AVRULE_XPERMS_AUDITALLOW) {
|
||||
spec = AVTAB_XPERMS_AUDITALLOW;
|
||||
} else if (specified & AVRULE_XPERMS_DONTAUDIT) {
|
||||
if (handle && handle->disable_dontaudit)
|
||||
return EXPAND_RULE_SUCCESS;
|
||||
spec = AVTAB_OPNUM_DONTAUDIT;
|
||||
} else if (specified & AVRULE_OPTYPE_ALLOWED) {
|
||||
spec = AVTAB_OPTYPE_ALLOWED;
|
||||
} else if (specified & AVRULE_OPTYPE_AUDITALLOW) {
|
||||
spec = AVTAB_OPTYPE_AUDITALLOW;
|
||||
} else if (specified & AVRULE_OPTYPE_DONTAUDIT) {
|
||||
if (handle && handle->disable_dontaudit)
|
||||
return EXPAND_RULE_SUCCESS;
|
||||
spec = AVTAB_OPTYPE_DONTAUDIT;
|
||||
spec = AVTAB_XPERMS_DONTAUDIT;
|
||||
} else {
|
||||
assert(0); /* unreachable */
|
||||
}
|
||||
@ -1829,7 +1822,7 @@ static int expand_avrule_helper(sepol_handle_t * handle,
|
||||
avkey.target_class = cur->tclass;
|
||||
avkey.specified = spec;
|
||||
|
||||
node = find_avtab_node(handle, avtab, &avkey, cond, operations);
|
||||
node = find_avtab_node(handle, avtab, &avkey, cond, extended_perms);
|
||||
if (!node)
|
||||
return EXPAND_RULE_ERROR;
|
||||
if (enabled) {
|
||||
@ -1859,20 +1852,21 @@ static int expand_avrule_helper(sepol_handle_t * handle,
|
||||
avdatump->data &= ~cur->data;
|
||||
else
|
||||
avdatump->data = ~cur->data;
|
||||
} else if (specified & AVRULE_OP) {
|
||||
if (!avdatump->ops) {
|
||||
ops = (avtab_operations_t *)
|
||||
calloc(1, sizeof(avtab_operations_t));
|
||||
if (!ops) {
|
||||
} else if (specified & AVRULE_XPERMS) {
|
||||
if (!avdatump->xperms) {
|
||||
xperms = (avtab_extended_perms_t *)
|
||||
calloc(1, sizeof(avtab_extended_perms_t));
|
||||
if (!xperms) {
|
||||
ERR(handle, "Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
node->datum.ops = ops;
|
||||
}
|
||||
node->datum.ops->type = operations->type;
|
||||
for (i = 0; i < ARRAY_SIZE(operations->perms); i++) {
|
||||
node->datum.ops->perms[i] |= operations->perms[i];
|
||||
node->datum.xperms = xperms;
|
||||
}
|
||||
node->datum.xperms->specified = extended_perms->specified;
|
||||
node->datum.xperms->driver = extended_perms->driver;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
|
||||
node->datum.xperms->perms[i] |= extended_perms->perms[i];
|
||||
} else {
|
||||
assert(0); /* should never occur */
|
||||
}
|
||||
@ -1897,10 +1891,10 @@ static int expand_rule_helper(sepol_handle_t * handle,
|
||||
if (!ebitmap_node_get_bit(snode, i))
|
||||
continue;
|
||||
if (source_rule->flags & RULE_SELF) {
|
||||
if (source_rule->specified & (AVRULE_AV | AVRULE_OP)) {
|
||||
if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
|
||||
retval = expand_avrule_helper(handle, source_rule->specified,
|
||||
cond, i, i, source_rule->perms,
|
||||
dest_avtab, enabled, source_rule->ops);
|
||||
dest_avtab, enabled, source_rule->xperms);
|
||||
if (retval != EXPAND_RULE_SUCCESS)
|
||||
return retval;
|
||||
} else {
|
||||
@ -1915,10 +1909,10 @@ static int expand_rule_helper(sepol_handle_t * handle,
|
||||
ebitmap_for_each_bit(ttypes, tnode, j) {
|
||||
if (!ebitmap_node_get_bit(tnode, j))
|
||||
continue;
|
||||
if (source_rule->specified & (AVRULE_AV | AVRULE_OP)) {
|
||||
if (source_rule->specified & (AVRULE_AV | AVRULE_XPERMS)) {
|
||||
retval = expand_avrule_helper(handle, source_rule->specified,
|
||||
cond, i, j, source_rule->perms,
|
||||
dest_avtab, enabled, source_rule->ops);
|
||||
dest_avtab, enabled, source_rule->xperms);
|
||||
if (retval != EXPAND_RULE_SUCCESS)
|
||||
return retval;
|
||||
} else {
|
||||
@ -1954,6 +1948,8 @@ static int convert_and_expand_rule(sepol_handle_t * handle,
|
||||
|
||||
if (!do_neverallow && source_rule->specified & AVRULE_NEVERALLOW)
|
||||
return EXPAND_RULE_SUCCESS;
|
||||
if (source_rule->specified & AVRULE_XPERMS_NEVERALLOW)
|
||||
return EXPAND_RULE_SUCCESS;
|
||||
|
||||
ebitmap_init(&stypes);
|
||||
ebitmap_init(&ttypes);
|
||||
@ -2317,25 +2313,33 @@ static int type_attr_map(hashtab_key_t key
|
||||
policydb_t *p = state->out;
|
||||
unsigned int i;
|
||||
ebitmap_node_t *tnode;
|
||||
int value;
|
||||
|
||||
type = (type_datum_t *) datum;
|
||||
value = type->s.value;
|
||||
|
||||
if (type->flavor == TYPE_ATTRIB) {
|
||||
if (ebitmap_cpy(&p->attr_type_map[type->s.value - 1],
|
||||
&type->types)) {
|
||||
ERR(state->handle, "Out of memory!");
|
||||
return -1;
|
||||
if (ebitmap_cpy(&p->attr_type_map[value - 1], &type->types)) {
|
||||
goto oom;
|
||||
}
|
||||
ebitmap_for_each_bit(&type->types, tnode, i) {
|
||||
if (!ebitmap_node_get_bit(tnode, i))
|
||||
continue;
|
||||
if (ebitmap_set_bit(&p->type_attr_map[i],
|
||||
type->s.value - 1, 1)) {
|
||||
ERR(state->handle, "Out of memory!");
|
||||
return -1;
|
||||
if (ebitmap_set_bit(&p->type_attr_map[i], value - 1, 1)) {
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ebitmap_set_bit(&p->attr_type_map[value - 1], value - 1, 1)) {
|
||||
goto oom;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
oom:
|
||||
ERR(state->handle, "Out of memory!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy.
|
||||
@ -2376,7 +2380,8 @@ int expand_rule(sepol_handle_t * handle,
|
||||
int retval;
|
||||
ebitmap_t stypes, ttypes;
|
||||
|
||||
if (source_rule->specified & AVRULE_NEVERALLOW)
|
||||
if ((source_rule->specified & AVRULE_NEVERALLOW)
|
||||
|| (source_rule->specified & AVRULE_XPERMS_NEVERALLOW))
|
||||
return 1;
|
||||
|
||||
ebitmap_init(&stypes);
|
||||
@ -2590,6 +2595,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
|
||||
ebitmap_t stypes, ttypes;
|
||||
avrule_t *avrule;
|
||||
class_perm_node_t *cur_perm, *new_perm, *tail_perm;
|
||||
av_extended_perms_t *xperms = NULL;
|
||||
|
||||
ebitmap_init(&stypes);
|
||||
ebitmap_init(&ttypes);
|
||||
@ -2606,7 +2612,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
|
||||
return -1;
|
||||
|
||||
avrule_init(avrule);
|
||||
avrule->specified = AVRULE_NEVERALLOW;
|
||||
avrule->specified = source_rule->specified;
|
||||
avrule->line = source_rule->line;
|
||||
avrule->flags = source_rule->flags;
|
||||
avrule->source_line = source_rule->source_line;
|
||||
@ -2645,6 +2651,15 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
|
||||
cur_perm = cur_perm->next;
|
||||
}
|
||||
|
||||
/* copy over extended permissions */
|
||||
if (source_rule->xperms) {
|
||||
xperms = calloc(1, sizeof(av_extended_perms_t));
|
||||
if (!xperms)
|
||||
goto err;
|
||||
memcpy(xperms, source_rule->xperms, sizeof(av_extended_perms_t));
|
||||
avrule->xperms = xperms;
|
||||
}
|
||||
|
||||
/* just prepend the avrule to the first branch; it'll never be
|
||||
written to disk */
|
||||
if (!dest_pol->global->branch_list->avrules)
|
||||
@ -2670,6 +2685,7 @@ static int copy_neverallow(policydb_t * dest_pol, uint32_t * typemap,
|
||||
free(cur_perm);
|
||||
cur_perm = tail_perm;
|
||||
}
|
||||
free(xperms);
|
||||
free(avrule);
|
||||
return -1;
|
||||
}
|
||||
@ -2722,16 +2738,15 @@ static int copy_and_expand_avrule_block(expand_state_t * state)
|
||||
cur_avrule = decl->avrules;
|
||||
while (cur_avrule != NULL) {
|
||||
if (!(state->expand_neverallow)
|
||||
&& cur_avrule->specified & AVRULE_NEVERALLOW) {
|
||||
&& cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW)) {
|
||||
/* copy this over directly so that assertions are checked later */
|
||||
if (copy_neverallow
|
||||
(state->out, state->typemap, cur_avrule))
|
||||
ERR(state->handle,
|
||||
"Error while copying neverallow.");
|
||||
} else {
|
||||
if (cur_avrule->specified & AVRULE_NEVERALLOW) {
|
||||
if (cur_avrule->specified & (AVRULE_NEVERALLOW | AVRULE_XPERMS_NEVERALLOW))
|
||||
state->out->unsupported_format = 1;
|
||||
}
|
||||
if (convert_and_expand_rule
|
||||
(state->handle, state->out, state->typemap,
|
||||
cur_avrule, &state->out->te_avtab, NULL,
|
||||
@ -3155,24 +3170,25 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
|
||||
{
|
||||
avtab_ptr_t node;
|
||||
avtab_datum_t *avd;
|
||||
avtab_operations_t *ops;
|
||||
avtab_extended_perms_t *xperms;
|
||||
unsigned int i;
|
||||
unsigned int type_match = 0;
|
||||
unsigned int match = 0;
|
||||
|
||||
if (k->specified & AVTAB_OPNUM) {
|
||||
if (k->specified & AVTAB_XPERMS) {
|
||||
/*
|
||||
* AVTAB_OPNUM entries are not necessarily unique.
|
||||
* find node with matching ops->type
|
||||
* AVTAB_XPERMS entries are not necessarily unique.
|
||||
* find node with matching xperms
|
||||
*/
|
||||
node = avtab_search_node(a, k);
|
||||
while (node) {
|
||||
if (node->datum.ops->type == d->ops->type) {
|
||||
type_match = 1;
|
||||
if ((node->datum.xperms->specified == d->xperms->specified) &&
|
||||
(node->datum.xperms->driver == d->xperms->driver)) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
node = avtab_search_node_next(node, k->specified);
|
||||
}
|
||||
if (!type_match)
|
||||
if (!match)
|
||||
node = NULL;
|
||||
} else {
|
||||
node = avtab_search_node(a, k);
|
||||
@ -3189,7 +3205,7 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
|
||||
}
|
||||
|
||||
avd = &node->datum;
|
||||
ops = node->datum.ops;
|
||||
xperms = node->datum.xperms;
|
||||
switch (k->specified & ~AVTAB_ENABLED) {
|
||||
case AVTAB_ALLOWED:
|
||||
case AVTAB_AUDITALLOW:
|
||||
@ -3198,14 +3214,11 @@ static int expand_avtab_insert(avtab_t * a, avtab_key_t * k, avtab_datum_t * d)
|
||||
case AVTAB_AUDITDENY:
|
||||
avd->data &= d->data;
|
||||
break;
|
||||
case AVTAB_OPNUM_ALLOWED:
|
||||
case AVTAB_OPNUM_AUDITALLOW:
|
||||
case AVTAB_OPNUM_DONTAUDIT:
|
||||
case AVTAB_OPTYPE_ALLOWED:
|
||||
case AVTAB_OPTYPE_AUDITALLOW:
|
||||
case AVTAB_OPTYPE_DONTAUDIT:
|
||||
for (i = 0; i < ARRAY_SIZE(ops->perms); i++)
|
||||
ops->perms[i] |= d->ops->perms[i];
|
||||
case AVTAB_XPERMS_ALLOWED:
|
||||
case AVTAB_XPERMS_AUDITALLOW:
|
||||
case AVTAB_XPERMS_DONTAUDIT:
|
||||
for (i = 0; i < ARRAY_SIZE(xperms->perms); i++)
|
||||
xperms->perms[i] |= d->xperms->perms[i];
|
||||
break;
|
||||
default:
|
||||
ERR(NULL, "Type conflict!");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2859,7 +2859,7 @@ static int level_string_to_cil(char *levelstr)
|
||||
char *token = NULL;
|
||||
char *ranged = NULL;
|
||||
|
||||
matched = sscanf(levelstr, "%m[^:]:%ms", &sens, &cats);
|
||||
matched = tokenize(levelstr, ':', 2, &sens, &cats);
|
||||
if (matched < 1 || matched > 2) {
|
||||
log_err("Invalid level: %s", levelstr);
|
||||
rc = -1;
|
||||
@ -2924,7 +2924,7 @@ static int context_string_to_cil(char *contextstr)
|
||||
char *type = NULL;
|
||||
char *level = NULL;
|
||||
|
||||
matched = sscanf(contextstr, "%m[^:]:%m[^:]:%m[^:]:%ms", &user, &role, &type, &level);
|
||||
matched = tokenize(contextstr, ':', 4, &user, &role, &type, &level);
|
||||
if (matched < 3 || matched > 4) {
|
||||
log_err("Invalid context: %s", contextstr);
|
||||
rc = -1;
|
||||
@ -2965,6 +2965,7 @@ static int seusers_to_cil(struct sepol_module_package *mod_pkg)
|
||||
char *user = NULL;
|
||||
char *seuser = NULL;
|
||||
char *level = NULL;
|
||||
char *tmp = NULL;
|
||||
int matched;
|
||||
|
||||
if (seusers_len == 0) {
|
||||
@ -2972,11 +2973,18 @@ static int seusers_to_cil(struct sepol_module_package *mod_pkg)
|
||||
}
|
||||
|
||||
while ((rc = get_line(&cur, end, &line)) > 0) {
|
||||
if (line[0] == '#') {
|
||||
tmp = line;
|
||||
while (isspace(*tmp)) {
|
||||
tmp++;
|
||||
}
|
||||
|
||||
if (tmp[0] == '#' || tmp[0] == '\0') {
|
||||
free(line);
|
||||
line = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = sscanf(line, "%m[^:]:%m[^:]:%ms", &user, &seuser, &level);
|
||||
matched = tokenize(tmp, ':', 3, &user, &seuser, &level);
|
||||
|
||||
if (matched < 2 || matched > 3) {
|
||||
log_err("Invalid seuser line: %s", line);
|
||||
@ -3045,28 +3053,51 @@ static int user_extra_to_cil(struct sepol_module_package *mod_pkg)
|
||||
int matched;
|
||||
char *user = NULL;
|
||||
char *prefix = NULL;
|
||||
int prefix_len = 0;
|
||||
char *user_str = NULL;
|
||||
char *prefix_str = NULL;
|
||||
char *eol = NULL;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (userx_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((rc = get_line(&cur, end, &line)) > 0) {
|
||||
if (line[0] == '#') {
|
||||
tmp = line;
|
||||
while (isspace(*tmp)) {
|
||||
tmp++;
|
||||
}
|
||||
|
||||
if (tmp[0] == '#' || tmp[0] == '\0') {
|
||||
free(line);
|
||||
line = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = sscanf(line, "user %ms prefix %m[^;];", &user, &prefix);
|
||||
if (matched != 2) {
|
||||
matched = tokenize(tmp, ' ', 4, &user_str, &user, &prefix_str, &prefix);
|
||||
if (matched != 4) {
|
||||
rc = -1;
|
||||
log_err("Invalid file context line: %s", line);
|
||||
log_err("Invalid user extra line: %s", line);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
prefix_len = strlen(prefix);
|
||||
eol = prefix + prefix_len - 1;
|
||||
if (*eol != ';' || strcmp(user_str, "user") || strcmp(prefix_str, "prefix")) {
|
||||
rc = -1;
|
||||
log_err("Invalid user extra line: %s", line);
|
||||
goto exit;
|
||||
}
|
||||
*eol = '\0';
|
||||
|
||||
cil_println(0, "(userprefix %s %s)", user, prefix);
|
||||
free(user);
|
||||
free(prefix);
|
||||
free(line);
|
||||
user = prefix = line = NULL;
|
||||
free(user_str);
|
||||
free(prefix_str);
|
||||
user = prefix = line = user_str = prefix_str = NULL;
|
||||
}
|
||||
|
||||
if (rc == -1) {
|
||||
@ -3096,17 +3127,25 @@ static int file_contexts_to_cil(struct sepol_module_package *mod_pkg)
|
||||
char *mode = NULL;
|
||||
char *context = NULL;
|
||||
const char *cilmode;
|
||||
char *tmp = NULL;
|
||||
|
||||
if (fc_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((rc = get_line(&cur, end, &line)) > 0) {
|
||||
if (line[0] == '#') {
|
||||
tmp = line;
|
||||
while (isspace(*tmp)) {
|
||||
tmp++;
|
||||
}
|
||||
|
||||
if (tmp[0] == '#' || tmp[0] == '\0') {
|
||||
free(line);
|
||||
line = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
matched = sscanf(line, "%ms %ms %ms", ®ex, &mode, &context);
|
||||
matched = tokenize(tmp, ' ', 3, ®ex, &mode, &context);
|
||||
if (matched < 2 || matched > 3) {
|
||||
rc = -1;
|
||||
log_err("Invalid file context line: %s", line);
|
||||
|
@ -180,7 +180,7 @@ static struct policydb_compat_info policydb_compat[] = {
|
||||
},
|
||||
{
|
||||
.type = POLICY_KERN,
|
||||
.version = POLICYDB_VERSION_IOCTL_OPERATIONS,
|
||||
.version = POLICYDB_VERSION_XPERMS_IOCTL,
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NODE6 + 1,
|
||||
.target_platform = SEPOL_TARGET_SELINUX,
|
||||
@ -3936,6 +3936,10 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
|
||||
/* add the type itself as the degenerate case */
|
||||
if (ebitmap_set_bit(&p->type_attr_map[i], i, 1))
|
||||
goto bad;
|
||||
if (p->type_val_to_struct[i] && p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
|
||||
if (ebitmap_set_bit(&p->attr_type_map[i], i, 1))
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,15 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sepol/policydb/flask_types.h>
|
||||
#include <sepol/policydb/policydb.h>
|
||||
#include <sepol/policydb/util.h>
|
||||
#include <dso.h>
|
||||
|
||||
struct val_to_name {
|
||||
unsigned int val;
|
||||
@ -114,3 +118,169 @@ char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
|
||||
|
||||
return avbuf;
|
||||
}
|
||||
|
||||
#define next_bit_in_range(i, p) ((i + 1 < sizeof(p)*8) && xperm_test((i + 1), p))
|
||||
|
||||
char *sepol_extended_perms_to_string(avtab_extended_perms_t *xperms)
|
||||
{
|
||||
uint16_t value;
|
||||
uint16_t low_bit;
|
||||
uint16_t low_value;
|
||||
unsigned int bit;
|
||||
unsigned int in_range = 0;
|
||||
static char xpermsbuf[2048];
|
||||
xpermsbuf[0] = '\0';
|
||||
char *p;
|
||||
int len, xpermslen = 0;
|
||||
p = xpermsbuf;
|
||||
|
||||
if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
|
||||
&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER))
|
||||
return NULL;
|
||||
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "ioctl { ");
|
||||
p += len;
|
||||
xpermslen += len;
|
||||
|
||||
for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
|
||||
if (!xperm_test(bit, xperms->perms))
|
||||
continue;
|
||||
|
||||
if (in_range && next_bit_in_range(bit, xperms->perms)) {
|
||||
/* continue until high value found */
|
||||
continue;
|
||||
} else if (next_bit_in_range(bit, xperms->perms)) {
|
||||
/* low value */
|
||||
low_bit = bit;
|
||||
in_range = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
|
||||
value = xperms->driver<<8 | bit;
|
||||
low_value = xperms->driver<<8 | low_bit;
|
||||
if (in_range) {
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, value);
|
||||
} else {
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx ", value);
|
||||
}
|
||||
} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
|
||||
value = bit << 8;
|
||||
low_value = low_bit << 8;
|
||||
if (in_range) {
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
|
||||
} else {
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
|
||||
return NULL;
|
||||
|
||||
p += len;
|
||||
xpermslen += len;
|
||||
if (in_range)
|
||||
in_range = 0;
|
||||
}
|
||||
|
||||
len = snprintf(p, sizeof(xpermsbuf) - xpermslen, "}");
|
||||
if (len < 0 || (size_t) len >= (sizeof(xpermsbuf) - xpermslen))
|
||||
return NULL;
|
||||
|
||||
return xpermsbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* The tokenize and tokenize_str functions may be used to
|
||||
* replace sscanf to read tokens from buffers.
|
||||
*/
|
||||
|
||||
/* Read a token from a buffer */
|
||||
static inline int tokenize_str(char delim, char **str, char **ptr, size_t *len)
|
||||
{
|
||||
char *tmp_buf = *ptr;
|
||||
*str = NULL;
|
||||
|
||||
while (**ptr != '\0') {
|
||||
if (isspace(delim) && isspace(**ptr)) {
|
||||
(*ptr)++;
|
||||
break;
|
||||
} else if (!isspace(delim) && **ptr == delim) {
|
||||
(*ptr)++;
|
||||
break;
|
||||
}
|
||||
|
||||
(*ptr)++;
|
||||
}
|
||||
|
||||
*len = *ptr - tmp_buf;
|
||||
/* If the end of the string has not been reached, this will ensure the
|
||||
* delimiter is not included when returning the token.
|
||||
*/
|
||||
if (**ptr != '\0') {
|
||||
(*len)--;
|
||||
}
|
||||
|
||||
*str = strndup(tmp_buf, *len);
|
||||
if (!*str) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Squash spaces if the delimiter is a whitespace character */
|
||||
while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
|
||||
(*ptr)++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* line_buf - Buffer containing string to tokenize.
|
||||
* delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
|
||||
* be tokenized using isspace().
|
||||
* num_args - The number of parameter entries to process.
|
||||
* ... - A 'char **' for each parameter.
|
||||
* returns - The number of items processed.
|
||||
*
|
||||
* This function calls tokenize_str() to do the actual string processing. The
|
||||
* caller is responsible for calling free() on each additional argument. The
|
||||
* function will not tokenize more than num_args and the last argument will
|
||||
* contain the remaining content of line_buf. If the delimiter is any whitespace
|
||||
* character, then all whitespace will be squashed.
|
||||
*/
|
||||
int hidden tokenize(char *line_buf, char delim, int num_args, ...)
|
||||
{
|
||||
char **arg, *buf_p;
|
||||
int rc, items;
|
||||
size_t arg_len = 0;
|
||||
va_list ap;
|
||||
|
||||
buf_p = line_buf;
|
||||
|
||||
/* Process the arguments */
|
||||
va_start(ap, num_args);
|
||||
|
||||
for (items = 0; items < num_args && *buf_p != '\0'; items++) {
|
||||
arg = va_arg(ap, char **);
|
||||
|
||||
/* Save the remainder of the string in arg */
|
||||
if (items == num_args - 1) {
|
||||
*arg = strdup(buf_p);
|
||||
if (*arg == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = tokenize_str(delim, arg, &buf_p, &arg_len);
|
||||
if (rc < 0) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
va_end(ap);
|
||||
return items;
|
||||
}
|
||||
|
@ -221,28 +221,32 @@ static int avtab_write_item(policydb_t * p,
|
||||
items = put_entry(buf16, sizeof(uint16_t), 4, fp);
|
||||
if (items != 4)
|
||||
return POLICYDB_ERROR;
|
||||
if ((p->policyvers < POLICYDB_VERSION_IOCTL_OPERATIONS) &&
|
||||
(cur->key.specified & AVTAB_OP)) {
|
||||
ERR(fp->handle, "policy version %u does not support ioctl operation"
|
||||
" rules and one was specified", p->policyvers);
|
||||
if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) &&
|
||||
(cur->key.specified & AVTAB_XPERMS)) {
|
||||
ERR(fp->handle, "policy version %u does not support ioctl extended"
|
||||
"permissions rules and one was specified", p->policyvers);
|
||||
return POLICYDB_ERROR;
|
||||
}
|
||||
|
||||
if (p->target_platform != SEPOL_TARGET_SELINUX &&
|
||||
(cur->key.specified & AVTAB_OP)) {
|
||||
(cur->key.specified & AVTAB_XPERMS)) {
|
||||
ERR(fp->handle, "Target platform %s does not support ioctl "
|
||||
"operation rules and one was specified",
|
||||
"extended permissions rules and one was specified",
|
||||
policydb_target_strings[p->target_platform]);
|
||||
return POLICYDB_ERROR;
|
||||
}
|
||||
|
||||
if (cur->key.specified & AVTAB_OP) {
|
||||
buf8 = cur->datum.ops->type;
|
||||
if (cur->key.specified & AVTAB_XPERMS) {
|
||||
buf8 = cur->datum.xperms->specified;
|
||||
items = put_entry(&buf8, sizeof(uint8_t),1,fp);
|
||||
if (items != 1)
|
||||
return POLICYDB_ERROR;
|
||||
for (i = 0; i < ARRAY_SIZE(cur->datum.ops->perms); i++)
|
||||
buf32[i] = cpu_to_le32(cur->datum.ops->perms[i]);
|
||||
buf8 = cur->datum.xperms->driver;
|
||||
items = put_entry(&buf8, sizeof(uint8_t),1,fp);
|
||||
if (items != 1)
|
||||
return POLICYDB_ERROR;
|
||||
for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++)
|
||||
buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]);
|
||||
items = put_entry(buf32, sizeof(uint32_t),8,fp);
|
||||
if (items != 8)
|
||||
return POLICYDB_ERROR;
|
||||
@ -1546,9 +1550,9 @@ static int avrule_write(avrule_t * avrule, struct policy_file *fp)
|
||||
uint32_t buf[32], len;
|
||||
class_perm_node_t *cur;
|
||||
|
||||
if (avrule->specified & AVRULE_OP) {
|
||||
ERR(fp->handle, "module policy does not support ioctl operation"
|
||||
" rules and one was specified");
|
||||
if (avrule->specified & AVRULE_XPERMS) {
|
||||
ERR(fp->handle, "module policy does not support extended"
|
||||
" permissions rules and one was specified");
|
||||
return POLICYDB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
* audit2allow/why: ignore setlocale errors, from Petr Lautrbach.
|
||||
* semodule: Add --extract/-E, --cil/-c, and --hll/-H to extract modules, from Yuli Khodorkovskiy.
|
||||
* audit2allow: Comment constraint rules in output, from Miroslav Grepl via Petr Lautrbach.
|
||||
* Fix PEP8 issues, from Jason Zaman.
|
||||
* semanage: fix moduleRecords deleteall method, from Stephen Smalley.
|
||||
* Improve compatibility with Python 3, from Michal Srb.
|
||||
* semanage: Set self.sename to sename after calling semanage_seuser_set_sename(), from Laurent Bigonville.
|
||||
* semanage: Fix typo in semanage args for minimium policy store, from Petr Lautrbach.
|
||||
* sepolicy: Only invoke RPM on RPM-enabled Linux distributions, from Sven Vermeulen.
|
||||
* mcstransd: don't reinvent getpeercon, from Stephen Smalley.
|
||||
* setfiles/restorecon: fix -r/-R option, from Petr Lautrbach.
|
||||
|
@ -19,7 +19,8 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys, os
|
||||
import sys
|
||||
import os
|
||||
|
||||
import sepolgen.audit as audit
|
||||
import sepolgen.policygen as policygen
|
||||
@ -31,7 +32,11 @@ import sepolgen.module as module
|
||||
from sepolgen.sepolgeni18n import _
|
||||
import selinux.audit2why as audit2why
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class AuditToPolicy:
|
||||
VERSION = "%prog .1"
|
||||
@ -65,8 +70,8 @@ class AuditToPolicy:
|
||||
help="generate a module package - conflicts with -o and -m")
|
||||
parser.add_option("-o", "--output", dest="output",
|
||||
help="append output to <filename>, conflicts with -M")
|
||||
parser.add_option("-D", "--dontaudit", action="store_true",
|
||||
dest="dontaudit", default=False,
|
||||
parser.add_option("-D", "--dontaudit", action="store_true",
|
||||
dest="dontaudit", default=False,
|
||||
help="generate policy with dontaudit rules")
|
||||
parser.add_option("-R", "--reference", action="store_true", dest="refpolicy",
|
||||
default=True, help="generate refpolicy style output")
|
||||
@ -83,7 +88,7 @@ class AuditToPolicy:
|
||||
parser.add_option("--interface-info", dest="interface_info", help="file name of interface information")
|
||||
parser.add_option("--debug", dest="debug", action="store_true", default=False,
|
||||
help="leave generated modules for -M")
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0])=="audit2why"),
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0]) == "audit2why"),
|
||||
help="Translates SELinux audit messages into a description of why the access was denied")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
@ -135,13 +140,13 @@ class AuditToPolicy:
|
||||
elif self.__options.audit:
|
||||
try:
|
||||
messages = audit.get_audit_msgs()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
elif self.__options.boot:
|
||||
try:
|
||||
messages = audit.get_audit_boot_msgs()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
else:
|
||||
@ -152,7 +157,7 @@ class AuditToPolicy:
|
||||
if filename is not None:
|
||||
try:
|
||||
f = open(filename)
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write('could not open file %s - "%s"\n' % (filename, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
@ -214,7 +219,7 @@ class AuditToPolicy:
|
||||
|
||||
try:
|
||||
fd = open(filename, "w")
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write("could not write output file: %s\n" % str(e))
|
||||
sys.exit(1)
|
||||
|
||||
@ -225,71 +230,71 @@ class AuditToPolicy:
|
||||
|
||||
try:
|
||||
mc.create_module_package(filename, self.__options.refpolicy)
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
sys.stdout.write(_("******************** IMPORTANT ***********************\n"))
|
||||
sys.stdout.write((_("To make this policy package active, execute:" +\
|
||||
"\n\nsemodule -i %s\n\n") % packagename))
|
||||
sys.stdout.write((_("To make this policy package active, execute:" +
|
||||
"\n\nsemodule -i %s\n\n") % packagename))
|
||||
|
||||
def __output_audit2why(self):
|
||||
import selinux
|
||||
import seobject
|
||||
for i in self.__parser.avc_msgs:
|
||||
rc = i.type
|
||||
data = i.data
|
||||
if rc >= 0:
|
||||
print "%s\n\tWas caused by:" % i.message
|
||||
if rc == audit2why.ALLOW:
|
||||
print "\t\tUnknown - would be allowed by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.DONTAUDIT:
|
||||
print "\t\tUnknown - should be dontaudit'd by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.BOOLEAN:
|
||||
if len(data) > 1:
|
||||
print "\tOne of the following booleans was set incorrectly."
|
||||
for b in data:
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(b[0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (b[0], b[1])
|
||||
else:
|
||||
print "\tThe boolean %s was set incorrectly. " % (data[0][0])
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(data[0][0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1])
|
||||
continue
|
||||
import selinux
|
||||
import seobject
|
||||
for i in self.__parser.avc_msgs:
|
||||
rc = i.type
|
||||
data = i.data
|
||||
if rc >= 0:
|
||||
print("%s\n\tWas caused by:" % i.message)
|
||||
if rc == audit2why.ALLOW:
|
||||
print("\t\tUnknown - would be allowed by active policy")
|
||||
print("\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n")
|
||||
print("\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n")
|
||||
continue
|
||||
if rc == audit2why.DONTAUDIT:
|
||||
print("\t\tUnknown - should be dontaudit'd by active policy")
|
||||
print("\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n")
|
||||
print("\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n")
|
||||
continue
|
||||
if rc == audit2why.BOOLEAN:
|
||||
if len(data) > 1:
|
||||
print("\tOne of the following booleans was set incorrectly.")
|
||||
for b in data:
|
||||
print("\tDescription:\n\t%s\n" % seobject.boolean_desc(b[0]))
|
||||
print("\tAllow access by executing:\n\t# setsebool -P %s %d" % (b[0], b[1]))
|
||||
else:
|
||||
print("\tThe boolean %s was set incorrectly. " % (data[0][0]))
|
||||
print("\tDescription:\n\t%s\n" % seobject.boolean_desc(data[0][0]))
|
||||
print("\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1]))
|
||||
continue
|
||||
|
||||
if rc == audit2why.TERULE:
|
||||
print "\t\tMissing type enforcement (TE) allow rule.\n"
|
||||
print "\t\tYou can use audit2allow to generate a loadable module to allow this access.\n"
|
||||
continue
|
||||
if rc == audit2why.TERULE:
|
||||
print("\t\tMissing type enforcement (TE) allow rule.\n")
|
||||
print("\t\tYou can use audit2allow to generate a loadable module to allow this access.\n")
|
||||
continue
|
||||
|
||||
if rc == audit2why.CONSTRAINT:
|
||||
print #!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access.\n"
|
||||
print "#Constraint rule:"
|
||||
print "\n\t" + data[0]
|
||||
for reason in data[1:]:
|
||||
print "#\tPossible cause is the source %s and target %s are different.\n" % reason
|
||||
if rc == audit2why.CONSTRAINT:
|
||||
print() # !!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access.\n"
|
||||
print("#Constraint rule:")
|
||||
print("\n#\t" + data[0])
|
||||
for reason in data[1:]:
|
||||
print("#\tPossible cause is the source %s and target %s are different.\n" % reason)
|
||||
|
||||
if rc == audit2why.RBAC:
|
||||
print "\t\tMissing role allow rule.\n"
|
||||
print "\t\tAdd an allow rule for the role pair.\n"
|
||||
continue
|
||||
if rc == audit2why.RBAC:
|
||||
print("\t\tMissing role allow rule.\n")
|
||||
print("\t\tAdd an allow rule for the role pair.\n")
|
||||
continue
|
||||
|
||||
audit2why.finish()
|
||||
return
|
||||
audit2why.finish()
|
||||
return
|
||||
|
||||
def __output(self):
|
||||
|
||||
|
||||
if self.__options.audit2why:
|
||||
try:
|
||||
return self.__output_audit2why()
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
g = policygen.PolicyGenerator()
|
||||
@ -348,11 +353,11 @@ class AuditToPolicy:
|
||||
self.__output()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
except ValueError, e:
|
||||
print e
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
except IOError, e:
|
||||
print e
|
||||
except IOError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -19,7 +19,8 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
import sys, os
|
||||
import sys
|
||||
import os
|
||||
|
||||
import sepolgen.audit as audit
|
||||
import sepolgen.policygen as policygen
|
||||
@ -31,7 +32,11 @@ import sepolgen.module as module
|
||||
from sepolgen.sepolgeni18n import _
|
||||
import selinux.audit2why as audit2why
|
||||
import locale
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class AuditToPolicy:
|
||||
VERSION = "%prog .1"
|
||||
@ -83,7 +88,7 @@ class AuditToPolicy:
|
||||
parser.add_option("--interface-info", dest="interface_info", help="file name of interface information")
|
||||
parser.add_option("--debug", dest="debug", action="store_true", default=False,
|
||||
help="leave generated modules for -M")
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0])=="audit2why"),
|
||||
parser.add_option("-w", "--why", dest="audit2why", action="store_true", default=(os.path.basename(sys.argv[0]) == "audit2why"),
|
||||
help="Translates SELinux audit messages into a description of why the access was denied")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
@ -135,13 +140,13 @@ class AuditToPolicy:
|
||||
elif self.__options.audit:
|
||||
try:
|
||||
messages = audit.get_audit_msgs()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
elif self.__options.boot:
|
||||
try:
|
||||
messages = audit.get_audit_boot_msgs()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
sys.stderr.write('could not run ausearch - "%s"\n' % str(e))
|
||||
sys.exit(1)
|
||||
else:
|
||||
@ -152,7 +157,7 @@ class AuditToPolicy:
|
||||
if filename is not None:
|
||||
try:
|
||||
f = open(filename)
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write('could not open file %s - "%s"\n' % (filename, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
@ -214,7 +219,7 @@ class AuditToPolicy:
|
||||
|
||||
try:
|
||||
fd = open(filename, "w")
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write("could not write output file: %s\n" % str(e))
|
||||
sys.exit(1)
|
||||
|
||||
@ -225,70 +230,70 @@ class AuditToPolicy:
|
||||
|
||||
try:
|
||||
mc.create_module_package(filename, self.__options.refpolicy)
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
sys.stdout.write(_("******************** IMPORTANT ***********************\n"))
|
||||
sys.stdout.write((_("To make this policy package active, execute:" +\
|
||||
"\n\nsemodule -i %s\n\n") % packagename))
|
||||
sys.stdout.write((_("To make this policy package active, execute:" +
|
||||
"\n\nsemodule -i %s\n\n") % packagename))
|
||||
|
||||
def __output_audit2why(self):
|
||||
import selinux
|
||||
import seobject
|
||||
for i in self.__parser.avc_msgs:
|
||||
rc = i.type
|
||||
data = i.data
|
||||
if rc >= 0:
|
||||
print "%s\n\tWas caused by:" % i.message
|
||||
if rc == audit2why.ALLOW:
|
||||
print "\t\tUnknown - would be allowed by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.DONTAUDIT:
|
||||
print "\t\tUnknown - should be dontaudit'd by active policy\n",
|
||||
print "\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n"
|
||||
print "\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n"
|
||||
continue
|
||||
if rc == audit2why.BOOLEAN:
|
||||
if len(data) > 1:
|
||||
print "\tOne of the following booleans was set incorrectly."
|
||||
for b in data:
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(b[0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (b[0], b[1])
|
||||
else:
|
||||
print "\tThe boolean %s was set incorrectly. " % (data[0][0])
|
||||
print "\tDescription:\n\t%s\n" % seobject.boolean_desc(data[0][0])
|
||||
print "\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1])
|
||||
continue
|
||||
import selinux
|
||||
import seobject
|
||||
for i in self.__parser.avc_msgs:
|
||||
rc = i.type
|
||||
data = i.data
|
||||
if rc >= 0:
|
||||
print("%s\n\tWas caused by:" % i.message)
|
||||
if rc == audit2why.ALLOW:
|
||||
print("\t\tUnknown - would be allowed by active policy")
|
||||
print("\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n")
|
||||
print("\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n")
|
||||
continue
|
||||
if rc == audit2why.DONTAUDIT:
|
||||
print("\t\tUnknown - should be dontaudit'd by active policy")
|
||||
print("\t\tPossible mismatch between this policy and the one under which the audit message was generated.\n")
|
||||
print("\t\tPossible mismatch between current in-memory boolean settings vs. permanent ones.\n")
|
||||
continue
|
||||
if rc == audit2why.BOOLEAN:
|
||||
if len(data) > 1:
|
||||
print("\tOne of the following booleans was set incorrectly.")
|
||||
for b in data:
|
||||
print("\tDescription:\n\t%s\n" % seobject.boolean_desc(b[0]))
|
||||
print("\tAllow access by executing:\n\t# setsebool -P %s %d" % (b[0], b[1]))
|
||||
else:
|
||||
print("\tThe boolean %s was set incorrectly. " % (data[0][0]))
|
||||
print("\tDescription:\n\t%s\n" % seobject.boolean_desc(data[0][0]))
|
||||
print("\tAllow access by executing:\n\t# setsebool -P %s %d" % (data[0][0], data[0][1]))
|
||||
continue
|
||||
|
||||
if rc == audit2why.TERULE:
|
||||
print "\t\tMissing type enforcement (TE) allow rule.\n"
|
||||
print "\t\tYou can use audit2allow to generate a loadable module to allow this access.\n"
|
||||
continue
|
||||
if rc == audit2why.TERULE:
|
||||
print("\t\tMissing type enforcement (TE) allow rule.\n")
|
||||
print("\t\tYou can use audit2allow to generate a loadable module to allow this access.\n")
|
||||
continue
|
||||
|
||||
if rc == audit2why.CONSTRAINT:
|
||||
print #!!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access.\n"
|
||||
print "#Constraint rule: \n\t" + data[0]
|
||||
for reason in data[1:]:
|
||||
print "#\tPossible cause is the source %s and target %s are different.\n\b" % reason
|
||||
if rc == audit2why.CONSTRAINT:
|
||||
print() # !!!! This avc is a constraint violation. You would need to modify the attributes of either the source or target types to allow this access.\n"
|
||||
print("#Constraint rule: \n\t" + data[0])
|
||||
for reason in data[1:]:
|
||||
print("#\tPossible cause is the source %s and target %s are different.\n\b" % reason)
|
||||
|
||||
if rc == audit2why.RBAC:
|
||||
print "\t\tMissing role allow rule.\n"
|
||||
print "\t\tAdd an allow rule for the role pair.\n"
|
||||
continue
|
||||
if rc == audit2why.RBAC:
|
||||
print("\t\tMissing role allow rule.\n")
|
||||
print("\t\tAdd an allow rule for the role pair.\n")
|
||||
continue
|
||||
|
||||
audit2why.finish()
|
||||
return
|
||||
audit2why.finish()
|
||||
return
|
||||
|
||||
def __output(self):
|
||||
|
||||
if self.__options.audit2why:
|
||||
try:
|
||||
return self.__output_audit2why()
|
||||
except RuntimeError, e:
|
||||
print e
|
||||
except RuntimeError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
g = policygen.PolicyGenerator()
|
||||
@ -347,11 +352,11 @@ class AuditToPolicy:
|
||||
self.__output()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
except ValueError, e:
|
||||
print e
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
except IOError, e:
|
||||
print e
|
||||
except IOError as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||
#
|
||||
# Copyright (C) 2006 Red Hat
|
||||
# Copyright (C) 2006 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
@ -41,6 +41,7 @@ import sepolgen.interfaces as interfaces
|
||||
VERSION = "%prog .1"
|
||||
ATTR_HELPER = "/usr/bin/sepolgen-ifgen-attr-helper"
|
||||
|
||||
|
||||
def parse_options():
|
||||
from optparse import OptionParser
|
||||
|
||||
@ -54,13 +55,14 @@ def parse_options():
|
||||
parser.add_option("-v", "--verbose", action="store_true", default=False,
|
||||
help="print debuging output")
|
||||
parser.add_option("-d", "--debug", action="store_true", default=False,
|
||||
help="extra debugging output")
|
||||
help="extra debugging output")
|
||||
parser.add_option("--no_attrs", action="store_true", default=False,
|
||||
help="do not retrieve attribute access from kernel policy")
|
||||
options, args = parser.parse_args()
|
||||
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def get_policy():
|
||||
p = selinux.selinux_current_policy_path()
|
||||
if p and os.path.exists(p):
|
||||
@ -74,6 +76,7 @@ def get_policy():
|
||||
return p
|
||||
return None
|
||||
|
||||
|
||||
def get_attrs(policy_path):
|
||||
try:
|
||||
if not policy_path:
|
||||
@ -82,14 +85,14 @@ def get_attrs(policy_path):
|
||||
sys.stderr.write("No installed policy to check\n")
|
||||
return None
|
||||
outfile = tempfile.NamedTemporaryFile()
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write("could not open attribute output file\n")
|
||||
return None
|
||||
except OSError:
|
||||
# SELinux Disabled Machine
|
||||
return None
|
||||
|
||||
fd = open("/dev/null","w")
|
||||
fd = open("/dev/null", "w")
|
||||
ret = subprocess.Popen([ATTR_HELPER, policy_path, outfile.name], stdout=fd).wait()
|
||||
fd.close()
|
||||
if ret != 0:
|
||||
@ -100,18 +103,19 @@ def get_attrs(policy_path):
|
||||
try:
|
||||
attrs.from_file(outfile)
|
||||
except:
|
||||
print "error parsing attribute info"
|
||||
print("error parsing attribute info")
|
||||
return None
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
def main():
|
||||
options = parse_options()
|
||||
|
||||
# Open the output first to generate errors before parsing
|
||||
try:
|
||||
f = open(options.output, "w")
|
||||
except IOError, e:
|
||||
except IOError as e:
|
||||
sys.stderr.write("could not open output file [%s]\n" % options.output)
|
||||
return 1
|
||||
|
||||
@ -130,9 +134,9 @@ def main():
|
||||
# Parse the headers
|
||||
try:
|
||||
headers = refparser.parse_headers(options.headers, output=log, debug=options.debug)
|
||||
except ValueError, e:
|
||||
print "error parsing headers"
|
||||
print str(e)
|
||||
except ValueError as e:
|
||||
print("error parsing headers")
|
||||
print(str(e))
|
||||
return 1
|
||||
|
||||
if_set = interfaces.InterfaceSet(output=log)
|
||||
@ -144,6 +148,6 @@ def main():
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
@ -1,26 +1,31 @@
|
||||
import unittest, os, shutil
|
||||
import unittest
|
||||
import os
|
||||
import shutil
|
||||
from tempfile import mkdtemp
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
|
||||
class Audit2allowTests(unittest.TestCase):
|
||||
|
||||
def assertDenied(self, err):
|
||||
self.assert_('Permission denied' in err,
|
||||
'"Permission denied" not found in %r' % err)
|
||||
self.assertTrue('Permission denied' in err,
|
||||
'"Permission denied" not found in %r' % err)
|
||||
|
||||
def assertNotFound(self, err):
|
||||
self.assert_('not found' in err,
|
||||
'"not found" not found in %r' % err)
|
||||
self.assertTrue('not found' in err,
|
||||
'"not found" not found in %r' % err)
|
||||
|
||||
def assertFailure(self, status):
|
||||
self.assert_(status != 0,
|
||||
'"Succeeded when it should have failed')
|
||||
self.assertTrue(status != 0,
|
||||
'"Succeeded when it should have failed')
|
||||
|
||||
def assertSuccess(self, cmd, status, err):
|
||||
self.assert_(status == 0,
|
||||
'"%s should have succeeded for this test %r' % (cmd, err))
|
||||
self.assertTrue(status == 0,
|
||||
'"%s should have succeeded for this test %r' % (cmd, err))
|
||||
|
||||
def test_sepolgen_ifgen(self):
|
||||
"Verify sepolgen-ifgen works"
|
||||
p = Popen(['sudo', 'sepolgen-ifgen'], stdout = PIPE)
|
||||
p = Popen(['sudo', 'sepolgen-ifgen'], stdout=PIPE)
|
||||
out, err = p.communicate()
|
||||
if err:
|
||||
print(out, err)
|
||||
@ -28,7 +33,7 @@ class Audit2allowTests(unittest.TestCase):
|
||||
|
||||
def test_audit2allow(self):
|
||||
"Verify audit2allow works"
|
||||
p = Popen(['audit2allow',"-i","test.log"], stdout = PIPE)
|
||||
p = Popen(['audit2allow', "-i", "test.log"], stdout=PIPE)
|
||||
out, err = p.communicate()
|
||||
if err:
|
||||
print(out, err)
|
||||
@ -36,7 +41,7 @@ class Audit2allowTests(unittest.TestCase):
|
||||
|
||||
def test_audit2why(self):
|
||||
"Verify audit2why works"
|
||||
p = Popen(['audit2why',"-i","test.log"], stdout = PIPE)
|
||||
p = Popen(['audit2why', "-i", "test.log"], stdout=PIPE)
|
||||
out, err = p.communicate()
|
||||
if err:
|
||||
print(out, err)
|
||||
|
@ -28,18 +28,18 @@ import tempfile
|
||||
import seobject
|
||||
import semanagePage
|
||||
|
||||
INSTALLPATH='/usr/share/system-config-selinux'
|
||||
INSTALLPATH = '/usr/share/system-config-selinux'
|
||||
sys.path.append(INSTALLPATH)
|
||||
|
||||
import commands
|
||||
ENFORCING=0
|
||||
PERMISSIVE=1
|
||||
DISABLED=2
|
||||
ENFORCING = 0
|
||||
PERMISSIVE = 1
|
||||
DISABLED = 2
|
||||
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
@ -48,41 +48,47 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
from glob import fnmatch
|
||||
|
||||
class Modifier:
|
||||
def __init__(self,name, on, save):
|
||||
self.on=on
|
||||
self.name=name
|
||||
self.save=save
|
||||
|
||||
def set(self,value):
|
||||
self.on=value
|
||||
self.save=True
|
||||
class Modifier:
|
||||
|
||||
def __init__(self, name, on, save):
|
||||
self.on = on
|
||||
self.name = name
|
||||
self.save = save
|
||||
|
||||
def set(self, value):
|
||||
self.on = value
|
||||
self.save = True
|
||||
|
||||
def isOn(self):
|
||||
return self.on
|
||||
|
||||
|
||||
class Boolean(Modifier):
|
||||
def __init__(self,name, val, save=False):
|
||||
Modifier.__init__(self,name, val, save)
|
||||
|
||||
def __init__(self, name, val, save=False):
|
||||
Modifier.__init__(self, name, val, save)
|
||||
|
||||
ACTIVE = 0
|
||||
MODULE = 1
|
||||
DESC = 2
|
||||
BOOLEAN = 3
|
||||
|
||||
|
||||
class booleansPage:
|
||||
|
||||
def __init__(self, xml, doDebug=None):
|
||||
self.xml = xml
|
||||
self.window = self.xml.get_widget("mainWindow").get_root_window()
|
||||
self.local = False
|
||||
self.types=[]
|
||||
self.types = []
|
||||
self.selinuxsupport = True
|
||||
self.typechanged = False
|
||||
self.doDebug = doDebug
|
||||
@ -112,7 +118,7 @@ class booleansPage:
|
||||
|
||||
checkbox = gtk.CellRendererToggle()
|
||||
checkbox.connect("toggled", self.boolean_toggled)
|
||||
col = gtk.TreeViewColumn('Active', checkbox, active = ACTIVE)
|
||||
col = gtk.TreeViewColumn('Active', checkbox, active=ACTIVE)
|
||||
col.set_clickable(True)
|
||||
col.set_sort_column_id(ACTIVE)
|
||||
self.booleansView.append_column(col)
|
||||
@ -123,7 +129,7 @@ class booleansPage:
|
||||
self.booleansView.append_column(col)
|
||||
|
||||
col = gtk.TreeViewColumn("Description", gtk.CellRendererText(), text=DESC)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_fixed_width(400)
|
||||
col.set_sort_column_id(DESC)
|
||||
col.set_resizable(True)
|
||||
@ -134,7 +140,7 @@ class booleansPage:
|
||||
col.set_resizable(True)
|
||||
self.booleansView.set_search_equal_func(self.__search)
|
||||
self.booleansView.append_column(col)
|
||||
self.filter=""
|
||||
self.filter = ""
|
||||
self.load(self.filter)
|
||||
|
||||
def error(self, message):
|
||||
@ -182,10 +188,10 @@ class booleansPage:
|
||||
self.error(e.args[0])
|
||||
|
||||
def filter_changed(self, *arg):
|
||||
filter = arg[0].get_text()
|
||||
filter = arg[0].get_text()
|
||||
if filter != self.filter:
|
||||
self.load(filter)
|
||||
self.filter=filter
|
||||
self.filter = filter
|
||||
|
||||
def use_menus(self):
|
||||
return False
|
||||
@ -193,17 +199,16 @@ class booleansPage:
|
||||
def get_description(self):
|
||||
return _("Boolean")
|
||||
|
||||
def match(self,key, filter=""):
|
||||
def match(self, key, filter=""):
|
||||
try:
|
||||
f=filter.lower()
|
||||
cat=self.booleans.get_category(key).lower()
|
||||
val=self.booleans.get_desc(key).lower()
|
||||
k=key.lower()
|
||||
f = filter.lower()
|
||||
cat = self.booleans.get_category(key).lower()
|
||||
val = self.booleans.get_desc(key).lower()
|
||||
k = key.lower()
|
||||
return val.find(f) >= 0 or k.find(f) >= 0 or cat.find(f) >= 0
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def load(self, filter=None):
|
||||
self.store.clear()
|
||||
self.booleans = seobject.booleanRecords()
|
||||
@ -211,7 +216,7 @@ class booleansPage:
|
||||
for name in booleansList:
|
||||
rec = booleansList[name]
|
||||
if self.match(name, filter):
|
||||
iter=self.store.append()
|
||||
iter = self.store.append()
|
||||
self.store.set_value(iter, ACTIVE, rec[2] == 1)
|
||||
self.store.set_value(iter, MODULE, self.booleans.get_category(name))
|
||||
self.store.set_value(iter, DESC, self.booleans.get_desc(name))
|
||||
@ -221,10 +226,10 @@ class booleansPage:
|
||||
iter = self.store.get_iter(row)
|
||||
val = self.store.get_value(iter, ACTIVE)
|
||||
key = self.store.get_value(iter, BOOLEAN)
|
||||
self.store.set_value(iter, ACTIVE , not val)
|
||||
self.store.set_value(iter, ACTIVE, not val)
|
||||
self.wait()
|
||||
setsebool="/usr/sbin/setsebool -P %s %d" % (key, not val)
|
||||
rc,out = commands.getstatusoutput(setsebool)
|
||||
setsebool = "/usr/sbin/setsebool -P %s %d" % (key, not val)
|
||||
rc, out = commands.getstatusoutput(setsebool)
|
||||
if rc != 0:
|
||||
self.error(out)
|
||||
self.load(self.filter)
|
||||
@ -232,7 +237,7 @@ class booleansPage:
|
||||
|
||||
def on_revert_clicked(self, button):
|
||||
self.wait()
|
||||
setsebool="semanage boolean --deleteall"
|
||||
setsebool = "semanage boolean --deleteall"
|
||||
commands.getstatusoutput(setsebool)
|
||||
self.load(self.filter)
|
||||
self.ready()
|
||||
|
@ -25,13 +25,13 @@ import gobject
|
||||
import sys
|
||||
import seobject
|
||||
import selinux
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
from sepolicy import get_all_entrypoint_domains
|
||||
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -39,12 +39,14 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class domainsPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
semanagePage.__init__(self, xml, "domains", _("Process Domain"))
|
||||
self.domain_filter = xml.get_widget("domainsFilterEntry")
|
||||
@ -54,12 +56,12 @@ class domainsPage(semanagePage):
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
self.view.set_model(self.store)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Domain Name"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Domain Name"), gtk.CellRendererText(), text=0)
|
||||
col.set_sort_column_id(0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Mode"), gtk.CellRendererText(), text = 1)
|
||||
col = gtk.TreeViewColumn(_("Mode"), gtk.CellRendererText(), text=1)
|
||||
col.set_sort_column_id(1)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
@ -68,12 +70,12 @@ class domainsPage(semanagePage):
|
||||
self.permissive_button = xml.get_widget("permissiveButton")
|
||||
self.enforcing_button = xml.get_widget("enforcingButton")
|
||||
|
||||
self.domains=get_all_entrypoint_domains()
|
||||
self.domains = get_all_entrypoint_domains()
|
||||
self.load()
|
||||
|
||||
def get_modules(self):
|
||||
modules=[]
|
||||
fd=os.popen("semodule -l")
|
||||
modules = []
|
||||
fd = os.popen("semodule -l")
|
||||
mods = fd.readlines()
|
||||
fd.close()
|
||||
for l in mods:
|
||||
@ -81,10 +83,10 @@ class domainsPage(semanagePage):
|
||||
return modules
|
||||
|
||||
def load(self, filter=""):
|
||||
self.filter=filter
|
||||
self.filter = filter
|
||||
self.store.clear()
|
||||
try:
|
||||
modules=self.get_modules()
|
||||
modules = self.get_modules()
|
||||
for domain in self.domains:
|
||||
if not self.match(domain, filter):
|
||||
continue
|
||||
@ -97,7 +99,7 @@ class domainsPage(semanagePage):
|
||||
self.store.set_value(iter, 1, "")
|
||||
except:
|
||||
pass
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def itemSelected(self, selection):
|
||||
store, iter = selection.get_selected()
|
||||
|
@ -22,16 +22,18 @@ import os
|
||||
import gobject
|
||||
import seobject
|
||||
import commands
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
|
||||
SPEC_COL = 0
|
||||
TYPE_COL = 1
|
||||
FTYPE_COL = 2
|
||||
|
||||
|
||||
class context:
|
||||
|
||||
def __init__(self, scontext):
|
||||
self.scontext = scontext
|
||||
con=scontext.split(":")
|
||||
con = scontext.split(":")
|
||||
self.type = con[0]
|
||||
if len(con) > 1:
|
||||
self.mls = con[1]
|
||||
@ -44,7 +46,7 @@ class context:
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
@ -53,13 +55,14 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class fcontextPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
semanagePage.__init__(self, xml, "fcontext", _("File Labeling"))
|
||||
self.fcontextFilter = xml.get_widget("fcontextFilterEntry")
|
||||
@ -72,16 +75,16 @@ class fcontextPage(semanagePage):
|
||||
self.view.set_search_equal_func(self.search)
|
||||
|
||||
col = gtk.TreeViewColumn(_("File\nSpecification"), gtk.CellRendererText(), text=SPEC_COL)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_fixed_width(250)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_fixed_width(250)
|
||||
|
||||
col.set_sort_column_id(SPEC_COL)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
col = gtk.TreeViewColumn(_("Selinux\nFile Type"), gtk.CellRendererText(), text=TYPE_COL)
|
||||
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_fixed_width(250)
|
||||
col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
|
||||
col.set_fixed_width(250)
|
||||
col.set_sort_column_id(TYPE_COL)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
@ -94,10 +97,10 @@ class fcontextPage(semanagePage):
|
||||
self.load()
|
||||
self.fcontextEntry = xml.get_widget("fcontextEntry")
|
||||
self.fcontextFileTypeCombo = xml.get_widget("fcontextFileTypeCombo")
|
||||
liststore=self.fcontextFileTypeCombo.get_model()
|
||||
liststore = self.fcontextFileTypeCombo.get_model()
|
||||
for k in seobject.file_types:
|
||||
if len(k) > 0 and k[0] != '-':
|
||||
iter=liststore.append()
|
||||
if len(k) > 0 and k[0] != '-':
|
||||
iter = liststore.append()
|
||||
liststore.set_value(iter, 0, k)
|
||||
iter = liststore.get_iter_first()
|
||||
self.fcontextFileTypeCombo.set_active_iter(iter)
|
||||
@ -106,13 +109,13 @@ class fcontextPage(semanagePage):
|
||||
|
||||
def match(self, fcon_dict, k, filter):
|
||||
try:
|
||||
f=filter.lower()
|
||||
f = filter.lower()
|
||||
for con in k:
|
||||
k=con.lower()
|
||||
k = con.lower()
|
||||
if k.find(f) >= 0:
|
||||
return True
|
||||
for con in fcon_dict[k]:
|
||||
k=con.lower()
|
||||
k = con.lower()
|
||||
if k.find(f) >= 0:
|
||||
return True
|
||||
except:
|
||||
@ -120,27 +123,27 @@ class fcontextPage(semanagePage):
|
||||
return False
|
||||
|
||||
def load(self, filter=""):
|
||||
self.filter=filter
|
||||
self.fcontext=seobject.fcontextRecords()
|
||||
self.filter = filter
|
||||
self.fcontext = seobject.fcontextRecords()
|
||||
self.store.clear()
|
||||
fcon_dict=self.fcontext.get_all(self.local)
|
||||
fcon_dict = self.fcontext.get_all(self.local)
|
||||
keys = fcon_dict.keys()
|
||||
keys.sort()
|
||||
for k in keys:
|
||||
if not self.match(fcon_dict, k, filter):
|
||||
continue
|
||||
iter=self.store.append()
|
||||
iter = self.store.append()
|
||||
self.store.set_value(iter, SPEC_COL, k[0])
|
||||
self.store.set_value(iter, FTYPE_COL, k[1])
|
||||
if fcon_dict[k]:
|
||||
rec="%s:%s" % (fcon_dict[k][2], seobject.translate(fcon_dict[k][3],False))
|
||||
rec = "%s:%s" % (fcon_dict[k][2], seobject.translate(fcon_dict[k][3], False))
|
||||
else:
|
||||
rec="<<None>>"
|
||||
rec = "<<None>>"
|
||||
self.store.set_value(iter, TYPE_COL, rec)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def filter_changed(self, *arg):
|
||||
filter = arg[0].get_text()
|
||||
filter = arg[0].get_text()
|
||||
if filter != self.filter:
|
||||
self.load(filter)
|
||||
|
||||
@ -149,13 +152,13 @@ class fcontextPage(semanagePage):
|
||||
self.fcontextEntry.set_text(store.get_value(iter, SPEC_COL))
|
||||
self.fcontextEntry.set_sensitive(False)
|
||||
scontext = store.get_value(iter, TYPE_COL)
|
||||
scon=context(scontext)
|
||||
scon = context(scontext)
|
||||
self.fcontextTypeEntry.set_text(scon.type)
|
||||
self.fcontextMLSEntry.set_text(scon.mls)
|
||||
type=store.get_value(iter, FTYPE_COL)
|
||||
liststore=self.fcontextFileTypeCombo.get_model()
|
||||
type = store.get_value(iter, FTYPE_COL)
|
||||
liststore = self.fcontextFileTypeCombo.get_model()
|
||||
iter = liststore.get_iter_first()
|
||||
while iter != None and liststore.get_value(iter,0) != type:
|
||||
while iter != None and liststore.get_value(iter, 0) != type:
|
||||
iter = liststore.iter_next(iter)
|
||||
if iter != None:
|
||||
self.fcontextFileTypeCombo.set_active_iter(iter)
|
||||
@ -171,8 +174,8 @@ class fcontextPage(semanagePage):
|
||||
def delete(self):
|
||||
store, iter = self.view.get_selection().get_selected()
|
||||
try:
|
||||
fspec=store.get_value(iter, SPEC_COL)
|
||||
ftype=store.get_value(iter, FTYPE_COL)
|
||||
fspec = store.get_value(iter, SPEC_COL)
|
||||
ftype = store.get_value(iter, FTYPE_COL)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage fcontext -d -f '%s' '%s'" % (ftype, fspec))
|
||||
self.ready()
|
||||
@ -180,16 +183,16 @@ class fcontextPage(semanagePage):
|
||||
if rc != 0:
|
||||
return self.error(out)
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
|
||||
def add(self):
|
||||
ftype=["", "--", "-d", "-c", "-b", "-s", "-l", "-p" ]
|
||||
fspec=self.fcontextEntry.get_text().strip()
|
||||
type=self.fcontextTypeEntry.get_text().strip()
|
||||
mls=self.fcontextMLSEntry.get_text().strip()
|
||||
list_model=self.fcontextFileTypeCombo.get_model()
|
||||
ftype = ["", "--", "-d", "-c", "-b", "-s", "-l", "-p"]
|
||||
fspec = self.fcontextEntry.get_text().strip()
|
||||
type = self.fcontextTypeEntry.get_text().strip()
|
||||
mls = self.fcontextMLSEntry.get_text().strip()
|
||||
list_model = self.fcontextFileTypeCombo.get_model()
|
||||
active = self.fcontextFileTypeCombo.get_active()
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage fcontext -a -t %s -r %s -f '%s' '%s'" % (type, mls, ftype[active], fspec))
|
||||
@ -198,18 +201,18 @@ class fcontextPage(semanagePage):
|
||||
self.error(out)
|
||||
return False
|
||||
|
||||
iter=self.store.append()
|
||||
iter = self.store.append()
|
||||
self.store.set_value(iter, SPEC_COL, fspec)
|
||||
self.store.set_value(iter, FTYPE_COL, ftype)
|
||||
self.store.set_value(iter, TYPE_COL, "%s:%s" % (type, mls))
|
||||
|
||||
def modify(self):
|
||||
fspec=self.fcontextEntry.get_text().strip()
|
||||
type=self.fcontextTypeEntry.get_text().strip()
|
||||
mls=self.fcontextMLSEntry.get_text().strip()
|
||||
list_model=self.fcontextFileTypeCombo.get_model()
|
||||
fspec = self.fcontextEntry.get_text().strip()
|
||||
type = self.fcontextTypeEntry.get_text().strip()
|
||||
mls = self.fcontextMLSEntry.get_text().strip()
|
||||
list_model = self.fcontextFileTypeCombo.get_model()
|
||||
iter = self.fcontextFileTypeCombo.get_active_iter()
|
||||
ftype=list_model.get_value(iter,0)
|
||||
ftype = list_model.get_value(iter, 0)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage fcontext -m -t %s -r %s -f '%s' '%s'" % (type, mls, ftype, fspec))
|
||||
self.ready()
|
||||
|
@ -34,7 +34,9 @@ import StringIO
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TextWriter(Formatter.DumbWriter):
|
||||
|
||||
def __init__(self, file=None, maxcol=80, indent_width=4):
|
||||
Formatter.DumbWriter.__init__(self, file, maxcol)
|
||||
self.indent_level = 0
|
||||
@ -58,7 +60,8 @@ class TextWriter(Formatter.DumbWriter):
|
||||
self.send_literal_data(' ' * offset + data)
|
||||
|
||||
def send_flowing_data(self, data):
|
||||
if not data: return
|
||||
if not data:
|
||||
return
|
||||
atbreak = self.atbreak or data[0] in string.whitespace
|
||||
col = self.col
|
||||
maxcol = self.maxcol
|
||||
@ -81,6 +84,7 @@ class TextWriter(Formatter.DumbWriter):
|
||||
self.col = col
|
||||
self.atbreak = data[-1] in string.whitespace
|
||||
|
||||
|
||||
class HTMLParserAnchor(htmllib.HTMLParser):
|
||||
|
||||
def __init__(self, formatter, verbose=0):
|
||||
@ -96,9 +100,11 @@ class HTMLParserAnchor(htmllib.HTMLParser):
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def escape_html(s):
|
||||
if s is None: return None
|
||||
s = s.replace("&", "&") # Must be done first!
|
||||
if s is None:
|
||||
return None
|
||||
s = s.replace("&", "&") # Must be done first!
|
||||
s = s.replace("<", "<")
|
||||
s = s.replace(">", ">")
|
||||
s = s.replace("'", "'")
|
||||
@ -107,16 +113,18 @@ def escape_html(s):
|
||||
|
||||
|
||||
def unescape_html(s):
|
||||
if s is None: return None
|
||||
if s is None:
|
||||
return None
|
||||
if '&' not in s:
|
||||
return s
|
||||
s = s.replace("<", "<")
|
||||
s = s.replace(">", ">")
|
||||
s = s.replace("'", "'")
|
||||
s = s.replace(""", '"')
|
||||
s = s.replace("&", "&") # Must be last
|
||||
s = s.replace("&", "&") # Must be last
|
||||
return s
|
||||
|
||||
|
||||
def html_to_text(html, maxcol=80):
|
||||
try:
|
||||
buffer = StringIO.StringIO()
|
||||
@ -131,6 +139,7 @@ def html_to_text(html, maxcol=80):
|
||||
log_program.error('cannot convert html to text: %s' % e)
|
||||
return None
|
||||
|
||||
|
||||
def html_document(*body_components):
|
||||
'''Wrap the body components in a HTML document structure with a valid header.
|
||||
Accepts a variable number of arguments of of which canb be:
|
||||
|
@ -24,12 +24,12 @@ import gobject
|
||||
import sys
|
||||
import commands
|
||||
import seobject
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -37,26 +37,28 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class loginsPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
self.firstTime = False
|
||||
semanagePage.__init__(self, xml, "logins", _("User Mapping"))
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
self.view.set_model(self.store)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Login\nName"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Login\nName"), gtk.CellRendererText(), text=0)
|
||||
col.set_sort_column_id(0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
col = gtk.TreeViewColumn(_("SELinux\nUser"), gtk.CellRendererText(), text = 1)
|
||||
col = gtk.TreeViewColumn(_("SELinux\nUser"), gtk.CellRendererText(), text=1)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
col = gtk.TreeViewColumn(_("MLS/\nMCS Range"), gtk.CellRendererText(), text = 2)
|
||||
col = gtk.TreeViewColumn(_("MLS/\nMCS Range"), gtk.CellRendererText(), text=2)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.load()
|
||||
@ -64,8 +66,8 @@ class loginsPage(semanagePage):
|
||||
self.loginsSelinuxUserCombo = xml.get_widget("loginsSelinuxUserCombo")
|
||||
self.loginsMLSEntry = xml.get_widget("loginsMLSEntry")
|
||||
|
||||
def load(self, filter = ""):
|
||||
self.filter=filter
|
||||
def load(self, filter=""):
|
||||
self.filter = filter
|
||||
self.login = seobject.loginRecords()
|
||||
dict = self.login.get_all(0)
|
||||
keys = dict.keys()
|
||||
@ -79,7 +81,7 @@ class loginsPage(semanagePage):
|
||||
self.store.set_value(iter, 0, k)
|
||||
self.store.set_value(iter, 1, dict[k][0])
|
||||
self.store.set_value(iter, 2, range)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def __dialogSetup(self):
|
||||
if self.firstTime == True:
|
||||
@ -99,7 +101,7 @@ class loginsPage(semanagePage):
|
||||
self.loginsSelinuxUserCombo.append_text(k)
|
||||
|
||||
iter = liststore.get_iter_first()
|
||||
while liststore.get_value(iter,0) != "user_u":
|
||||
while liststore.get_value(iter, 0) != "user_u":
|
||||
iter = liststore.iter_next(iter)
|
||||
self.loginsSelinuxUserCombo.set_active_iter(iter)
|
||||
|
||||
@ -113,12 +115,11 @@ class loginsPage(semanagePage):
|
||||
seuser = store.get_value(iter, 1)
|
||||
liststore = self.loginsSelinuxUserCombo.get_model()
|
||||
iter = liststore.get_iter_first()
|
||||
while iter != None and liststore.get_value(iter,0) != seuser:
|
||||
while iter != None and liststore.get_value(iter, 0) != seuser:
|
||||
iter = liststore.iter_next(iter)
|
||||
if iter != None:
|
||||
self.loginsSelinuxUserCombo.set_active_iter(iter)
|
||||
|
||||
|
||||
def dialogClear(self):
|
||||
self.__dialogSetup()
|
||||
self.loginsNameEntry.set_text("")
|
||||
@ -128,7 +129,7 @@ class loginsPage(semanagePage):
|
||||
def delete(self):
|
||||
store, iter = self.view.get_selection().get_selected()
|
||||
try:
|
||||
login=store.get_value(iter, 0)
|
||||
login = store.get_value(iter, 0)
|
||||
if login == "root" or login == "__default__":
|
||||
raise ValueError(_("Login '%s' is required") % login)
|
||||
|
||||
@ -139,18 +140,18 @@ class loginsPage(semanagePage):
|
||||
self.error(out)
|
||||
return False
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
|
||||
def add(self):
|
||||
target=self.loginsNameEntry.get_text().strip()
|
||||
serange=self.loginsMLSEntry.get_text().strip()
|
||||
target = self.loginsNameEntry.get_text().strip()
|
||||
serange = self.loginsMLSEntry.get_text().strip()
|
||||
if serange == "":
|
||||
serange="s0"
|
||||
list_model=self.loginsSelinuxUserCombo.get_model()
|
||||
serange = "s0"
|
||||
list_model = self.loginsSelinuxUserCombo.get_model()
|
||||
iter = self.loginsSelinuxUserCombo.get_active_iter()
|
||||
seuser = list_model.get_value(iter,0)
|
||||
seuser = list_model.get_value(iter, 0)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage login -a -s %s -r %s %s" % (seuser, serange, target))
|
||||
self.ready()
|
||||
@ -164,13 +165,13 @@ class loginsPage(semanagePage):
|
||||
self.store.set_value(iter, 2, seobject.translate(serange))
|
||||
|
||||
def modify(self):
|
||||
target=self.loginsNameEntry.get_text().strip()
|
||||
serange=self.loginsMLSEntry.get_text().strip()
|
||||
target = self.loginsNameEntry.get_text().strip()
|
||||
serange = self.loginsMLSEntry.get_text().strip()
|
||||
if serange == "":
|
||||
serange = "s0"
|
||||
list_model = self.loginsSelinuxUserCombo.get_model()
|
||||
iter = self.loginsSelinuxUserCombo.get_active_iter()
|
||||
seuser=list_model.get_value(iter,0)
|
||||
seuser = list_model.get_value(iter, 0)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage login -m -s %s -r %s %s" % (seuser, serange, target))
|
||||
self.ready()
|
||||
|
@ -27,7 +27,7 @@ import seobject
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -35,12 +35,14 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class loginsPage:
|
||||
|
||||
def __init__(self, xml):
|
||||
self.xml = xml
|
||||
self.view = xml.get_widget("mappingsView")
|
||||
|
@ -25,13 +25,13 @@ import gobject
|
||||
import sys
|
||||
import seobject
|
||||
import selinux
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -39,12 +39,14 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class modulesPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
semanagePage.__init__(self, xml, "modules", _("Policy Module"))
|
||||
self.module_filter = xml.get_widget("modulesFilterEntry")
|
||||
@ -55,12 +57,12 @@ class modulesPage(semanagePage):
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
self.view.set_model(self.store)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Module Name"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Module Name"), gtk.CellRendererText(), text=0)
|
||||
col.set_sort_column_id(0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Version"), gtk.CellRendererText(), text = 1)
|
||||
col = gtk.TreeViewColumn(_("Version"), gtk.CellRendererText(), text=1)
|
||||
self.enable_audit_button = xml.get_widget("enableAuditButton")
|
||||
self.enable_audit_button.connect("clicked", self.enable_audit)
|
||||
self.new_button = xml.get_widget("newModuleButton")
|
||||
@ -68,15 +70,15 @@ class modulesPage(semanagePage):
|
||||
col.set_sort_column_id(1)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.store.set_sort_func(1,self.sort_int, "")
|
||||
self.store.set_sort_func(1, self.sort_int, "")
|
||||
status, self.policy_type = selinux.selinux_getpolicytype()
|
||||
|
||||
self.load()
|
||||
|
||||
def sort_int(self, treemodel, iter1, iter2, user_data):
|
||||
try:
|
||||
p1 = int(treemodel.get_value(iter1,1))
|
||||
p2 = int(treemodel.get_value(iter1,1))
|
||||
p1 = int(treemodel.get_value(iter1, 1))
|
||||
p2 = int(treemodel.get_value(iter1, 1))
|
||||
if p1 > p2:
|
||||
return 1
|
||||
if p1 == p2:
|
||||
@ -86,7 +88,7 @@ class modulesPage(semanagePage):
|
||||
return 0
|
||||
|
||||
def load(self, filter=""):
|
||||
self.filter=filter
|
||||
self.filter = filter
|
||||
self.store.clear()
|
||||
try:
|
||||
fd = Popen("semodule -l", shell=True, stdout=PIPE).stdout
|
||||
@ -101,8 +103,7 @@ class modulesPage(semanagePage):
|
||||
self.store.set_value(iter, 1, ver.strip())
|
||||
except:
|
||||
pass
|
||||
self.view.get_selection().select_path ((0,))
|
||||
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def new_module(self, args):
|
||||
try:
|
||||
@ -121,7 +122,7 @@ class modulesPage(semanagePage):
|
||||
self.error(output)
|
||||
else:
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
@ -131,10 +132,10 @@ class modulesPage(semanagePage):
|
||||
try:
|
||||
self.wait()
|
||||
if self.audit_enabled:
|
||||
status, output =commands.getstatusoutput("semodule -DB")
|
||||
status, output = commands.getstatusoutput("semodule -DB")
|
||||
button.set_label(_("Disable Audit"))
|
||||
else:
|
||||
status, output =commands.getstatusoutput("semodule -B")
|
||||
status, output = commands.getstatusoutput("semodule -B")
|
||||
button.set_label(_("Enable Audit"))
|
||||
self.ready()
|
||||
|
||||
@ -147,7 +148,7 @@ class modulesPage(semanagePage):
|
||||
def disable_audit(self, button):
|
||||
try:
|
||||
self.wait()
|
||||
status, output =commands.getstatusoutput("semodule -B")
|
||||
status, output = commands.getstatusoutput("semodule -B")
|
||||
self.ready()
|
||||
if status != 0:
|
||||
self.error(output)
|
||||
@ -180,7 +181,7 @@ class modulesPage(semanagePage):
|
||||
def add(self, file):
|
||||
try:
|
||||
self.wait()
|
||||
status, output =commands.getstatusoutput("semodule -i %s" % file)
|
||||
status, output = commands.getstatusoutput("semodule -i %s" % file)
|
||||
self.ready()
|
||||
if status != 0:
|
||||
self.error(output)
|
||||
|
@ -30,7 +30,7 @@ import gnome
|
||||
import sys
|
||||
try:
|
||||
from sepolicy import generate
|
||||
except ValueError,e:
|
||||
except ValueError, e:
|
||||
sys.stderr.write("%s: %s\n" % (e.__class__.__name__, str(e)))
|
||||
sys.exit(1)
|
||||
|
||||
@ -39,10 +39,11 @@ import commands
|
||||
|
||||
import re
|
||||
|
||||
|
||||
def get_all_modules():
|
||||
try:
|
||||
all_modules = []
|
||||
rc, output=commands.getstatusoutput("semodule -l 2>/dev/null")
|
||||
rc, output = commands.getstatusoutput("semodule -l 2>/dev/null")
|
||||
if rc == 0:
|
||||
l = output.split("\n")
|
||||
for i in l:
|
||||
@ -56,7 +57,7 @@ def get_all_modules():
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
@ -65,7 +66,7 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
@ -78,6 +79,8 @@ sys.path.append('/usr/share/system-config-selinux')
|
||||
sys.path.append('.')
|
||||
|
||||
# From John Hunter http://www.daa.com.au/pipermail/pygtk/2003-February/004454.html
|
||||
|
||||
|
||||
def foreach(model, path, iter, selected):
|
||||
selected.append(model.get_value(iter, 0))
|
||||
|
||||
@ -85,13 +88,14 @@ def foreach(model, path, iter, selected):
|
||||
## Pull in the Glade file
|
||||
##
|
||||
if os.access("polgen.glade", os.F_OK):
|
||||
xml = gtk.glade.XML ("polgen.glade", domain=PROGNAME)
|
||||
xml = gtk.glade.XML("polgen.glade", domain=PROGNAME)
|
||||
else:
|
||||
xml = gtk.glade.XML ("/usr/share/system-config-selinux/polgen.glade", domain=PROGNAME)
|
||||
xml = gtk.glade.XML("/usr/share/system-config-selinux/polgen.glade", domain=PROGNAME)
|
||||
|
||||
FILE = 1
|
||||
DIR = 2
|
||||
|
||||
|
||||
class childWindow:
|
||||
START_PAGE = 0
|
||||
SELECT_TYPE_PAGE = 0
|
||||
@ -111,82 +115,82 @@ class childWindow:
|
||||
|
||||
def __init__(self):
|
||||
self.xml = xml
|
||||
self.notebook = xml.get_widget ("notebook")
|
||||
self.notebook = xml.get_widget("notebook")
|
||||
self.label_dict = {}
|
||||
self.tooltip_dict = {}
|
||||
label = xml.get_widget ("select_label")
|
||||
label = xml.get_widget("select_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_user_roles_label")
|
||||
label = xml.get_widget("select_user_roles_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_dir_label")
|
||||
label = xml.get_widget("select_dir_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_domain_admin_label")
|
||||
label = xml.get_widget("select_domain_admin_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_in_label")
|
||||
label = xml.get_widget("select_in_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_out_label")
|
||||
label = xml.get_widget("select_out_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_common_label")
|
||||
label = xml.get_widget("select_common_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_manages_label")
|
||||
label = xml.get_widget("select_manages_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("select_booleans_label")
|
||||
label = xml.get_widget("select_booleans_label")
|
||||
self.label_dict[label] = label.get_text()
|
||||
|
||||
label = xml.get_widget ("existing_user_treeview")
|
||||
label = xml.get_widget("existing_user_treeview")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("transition_treeview")
|
||||
label = xml.get_widget("transition_treeview")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_tcp_all_checkbutton")
|
||||
label = xml.get_widget("in_tcp_all_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_tcp_reserved_checkbutton")
|
||||
label = xml.get_widget("in_tcp_reserved_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_tcp_unreserved_checkbutton")
|
||||
label = xml.get_widget("in_tcp_unreserved_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_tcp_entry")
|
||||
label = xml.get_widget("in_tcp_entry")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_udp_all_checkbutton")
|
||||
label = xml.get_widget("in_udp_all_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_udp_reserved_checkbutton")
|
||||
label = xml.get_widget("in_udp_reserved_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_udp_unreserved_checkbutton")
|
||||
label = xml.get_widget("in_udp_unreserved_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("in_udp_entry")
|
||||
label = xml.get_widget("in_udp_entry")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("out_tcp_entry")
|
||||
label = xml.get_widget("out_tcp_entry")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("out_udp_entry")
|
||||
label = xml.get_widget("out_udp_entry")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("out_tcp_all_checkbutton")
|
||||
label = xml.get_widget("out_tcp_all_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("out_udp_all_checkbutton")
|
||||
label = xml.get_widget("out_udp_all_checkbutton")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("boolean_treeview")
|
||||
label = xml.get_widget("boolean_treeview")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
label = xml.get_widget ("write_treeview")
|
||||
label = xml.get_widget("write_treeview")
|
||||
self.tooltip_dict[label] = label.get_tooltip_text()
|
||||
|
||||
try:
|
||||
@ -201,7 +205,7 @@ class childWindow:
|
||||
self.all_users = []
|
||||
self.error(str(e))
|
||||
|
||||
self.name=""
|
||||
self.name = ""
|
||||
xml.signal_connect("on_delete_clicked", self.delete)
|
||||
xml.signal_connect("on_delete_boolean_clicked", self.delete_boolean)
|
||||
xml.signal_connect("on_exec_select_clicked", self.exec_select)
|
||||
@ -210,68 +214,67 @@ class childWindow:
|
||||
xml.signal_connect("on_add_boolean_clicked", self.add_boolean)
|
||||
xml.signal_connect("on_add_dir_clicked", self.add_dir)
|
||||
xml.signal_connect("on_about_clicked", self.on_about_clicked)
|
||||
xml.get_widget ("cancel_button").connect("clicked",self.quit)
|
||||
self.forward_button = xml.get_widget ("forward_button")
|
||||
self.forward_button.connect("clicked",self.forward)
|
||||
self.back_button = xml.get_widget ("back_button")
|
||||
self.back_button.connect("clicked",self.back)
|
||||
xml.get_widget("cancel_button").connect("clicked", self.quit)
|
||||
self.forward_button = xml.get_widget("forward_button")
|
||||
self.forward_button.connect("clicked", self.forward)
|
||||
self.back_button = xml.get_widget("back_button")
|
||||
self.back_button.connect("clicked", self.back)
|
||||
|
||||
self.boolean_dialog = xml.get_widget ("boolean_dialog")
|
||||
self.boolean_name_entry = xml.get_widget ("boolean_name_entry")
|
||||
self.boolean_description_entry = xml.get_widget ("boolean_description_entry")
|
||||
self.boolean_dialog = xml.get_widget("boolean_dialog")
|
||||
self.boolean_name_entry = xml.get_widget("boolean_name_entry")
|
||||
self.boolean_description_entry = xml.get_widget("boolean_description_entry")
|
||||
|
||||
self.pages={}
|
||||
self.pages = {}
|
||||
for i in generate.USERS:
|
||||
self.pages[i] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.TRANSITION_PAGE, self.ROLE_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE ]
|
||||
self.pages[generate.RUSER] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.ADMIN_PAGE, self.USER_TRANSITION_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE ]
|
||||
self.pages[generate.LUSER] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.TRANSITION_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE ]
|
||||
self.pages[generate.SANDBOX] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.EUSER] = [ self.SELECT_TYPE_PAGE, self.EXISTING_USER_PAGE, self.TRANSITION_PAGE, self.ROLE_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE ]
|
||||
self.pages[i] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.TRANSITION_PAGE, self.ROLE_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.RUSER] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.ADMIN_PAGE, self.USER_TRANSITION_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.LUSER] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.TRANSITION_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.SANDBOX] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.EUSER] = [self.SELECT_TYPE_PAGE, self.EXISTING_USER_PAGE, self.TRANSITION_PAGE, self.ROLE_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
|
||||
for i in generate.APPLICATIONS:
|
||||
self.pages[i] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.COMMON_APPS_PAGE, self.FILES_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.USER] = [ self.SELECT_TYPE_PAGE, self.APP_PAGE, self.USER_TRANSITION_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.COMMON_APPS_PAGE, self.FILES_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE ]
|
||||
self.pages[i] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.COMMON_APPS_PAGE, self.FILES_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
self.pages[generate.USER] = [self.SELECT_TYPE_PAGE, self.APP_PAGE, self.USER_TRANSITION_PAGE, self.IN_NET_PAGE, self.OUT_NET_PAGE, self.COMMON_APPS_PAGE, self.FILES_PAGE, self.BOOLEAN_PAGE, self.SELECT_DIR_PAGE]
|
||||
|
||||
self.current_page = 0
|
||||
self.back_button.set_sensitive(0)
|
||||
|
||||
self.network_buttons = {}
|
||||
|
||||
self.in_tcp_all_checkbutton = xml.get_widget ("in_tcp_all_checkbutton")
|
||||
self.in_tcp_reserved_checkbutton = xml.get_widget ("in_tcp_reserved_checkbutton")
|
||||
self.in_tcp_unreserved_checkbutton = xml.get_widget ("in_tcp_unreserved_checkbutton")
|
||||
self.in_tcp_all_checkbutton = xml.get_widget("in_tcp_all_checkbutton")
|
||||
self.in_tcp_reserved_checkbutton = xml.get_widget("in_tcp_reserved_checkbutton")
|
||||
self.in_tcp_unreserved_checkbutton = xml.get_widget("in_tcp_unreserved_checkbutton")
|
||||
self.in_tcp_entry = self.xml.get_widget("in_tcp_entry")
|
||||
self.network_buttons[self.in_tcp_all_checkbutton] = [ self.in_tcp_reserved_checkbutton, self.in_tcp_unreserved_checkbutton, self.in_tcp_entry ]
|
||||
self.network_buttons[self.in_tcp_all_checkbutton] = [self.in_tcp_reserved_checkbutton, self.in_tcp_unreserved_checkbutton, self.in_tcp_entry]
|
||||
|
||||
|
||||
self.out_tcp_all_checkbutton = xml.get_widget ("out_tcp_all_checkbutton")
|
||||
self.out_tcp_reserved_checkbutton = xml.get_widget ("out_tcp_reserved_checkbutton")
|
||||
self.out_tcp_unreserved_checkbutton = xml.get_widget ("out_tcp_unreserved_checkbutton")
|
||||
self.out_tcp_all_checkbutton = xml.get_widget("out_tcp_all_checkbutton")
|
||||
self.out_tcp_reserved_checkbutton = xml.get_widget("out_tcp_reserved_checkbutton")
|
||||
self.out_tcp_unreserved_checkbutton = xml.get_widget("out_tcp_unreserved_checkbutton")
|
||||
self.out_tcp_entry = self.xml.get_widget("out_tcp_entry")
|
||||
|
||||
self.network_buttons[self.out_tcp_all_checkbutton] = [ self.out_tcp_entry ]
|
||||
self.network_buttons[self.out_tcp_all_checkbutton] = [self.out_tcp_entry]
|
||||
|
||||
self.in_udp_all_checkbutton = xml.get_widget ("in_udp_all_checkbutton")
|
||||
self.in_udp_reserved_checkbutton = xml.get_widget ("in_udp_reserved_checkbutton")
|
||||
self.in_udp_unreserved_checkbutton = xml.get_widget ("in_udp_unreserved_checkbutton")
|
||||
self.in_udp_all_checkbutton = xml.get_widget("in_udp_all_checkbutton")
|
||||
self.in_udp_reserved_checkbutton = xml.get_widget("in_udp_reserved_checkbutton")
|
||||
self.in_udp_unreserved_checkbutton = xml.get_widget("in_udp_unreserved_checkbutton")
|
||||
self.in_udp_entry = self.xml.get_widget("in_udp_entry")
|
||||
|
||||
self.network_buttons[self.in_udp_all_checkbutton] = [ self.in_udp_reserved_checkbutton, self.in_udp_unreserved_checkbutton, self.in_udp_entry ]
|
||||
self.network_buttons[self.in_udp_all_checkbutton] = [self.in_udp_reserved_checkbutton, self.in_udp_unreserved_checkbutton, self.in_udp_entry]
|
||||
|
||||
self.out_udp_all_checkbutton = xml.get_widget ("out_udp_all_checkbutton")
|
||||
self.out_udp_all_checkbutton = xml.get_widget("out_udp_all_checkbutton")
|
||||
self.out_udp_entry = self.xml.get_widget("out_udp_entry")
|
||||
self.network_buttons[self.out_udp_all_checkbutton] = [ self.out_udp_entry ]
|
||||
self.network_buttons[self.out_udp_all_checkbutton] = [self.out_udp_entry]
|
||||
|
||||
for b in self.network_buttons.keys():
|
||||
b.connect("clicked",self.network_all_clicked)
|
||||
b.connect("clicked", self.network_all_clicked)
|
||||
|
||||
self.boolean_treeview = self.xml.get_widget("boolean_treeview")
|
||||
self.boolean_store = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_STRING)
|
||||
self.boolean_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
self.boolean_treeview.set_model(self.boolean_store)
|
||||
self.boolean_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Name"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Name"), gtk.CellRendererText(), text=0)
|
||||
self.boolean_treeview.append_column(col)
|
||||
col = gtk.TreeViewColumn(_("Description"), gtk.CellRendererText(), text = 1)
|
||||
col = gtk.TreeViewColumn(_("Description"), gtk.CellRendererText(), text=1)
|
||||
self.boolean_treeview.append_column(col)
|
||||
|
||||
self.role_treeview = self.xml.get_widget("role_treeview")
|
||||
@ -279,28 +282,28 @@ class childWindow:
|
||||
self.role_treeview.set_model(self.role_store)
|
||||
self.role_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
self.role_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Role"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Role"), gtk.CellRendererText(), text=0)
|
||||
self.role_treeview.append_column(col)
|
||||
|
||||
self.existing_user_treeview = self.xml.get_widget("existing_user_treeview")
|
||||
self.existing_user_store = gtk.ListStore(gobject.TYPE_STRING)
|
||||
self.existing_user_treeview.set_model(self.existing_user_store)
|
||||
self.existing_user_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Existing_User"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Existing_User"), gtk.CellRendererText(), text=0)
|
||||
self.existing_user_treeview.append_column(col)
|
||||
|
||||
for i in self.all_roles:
|
||||
iter = self.role_store.append()
|
||||
self.role_store.set_value(iter, 0, i[:-2])
|
||||
|
||||
self.in_tcp_reserved_checkbutton = xml.get_widget ("in_tcp_reserved_checkbutton")
|
||||
self.in_tcp_reserved_checkbutton = xml.get_widget("in_tcp_reserved_checkbutton")
|
||||
|
||||
self.transition_treeview = self.xml.get_widget("transition_treeview")
|
||||
self.transition_store = gtk.ListStore(gobject.TYPE_STRING)
|
||||
self.transition_treeview.set_model(self.transition_store)
|
||||
self.transition_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
self.transition_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text=0)
|
||||
self.transition_treeview.append_column(col)
|
||||
|
||||
self.user_transition_treeview = self.xml.get_widget("user_transition_treeview")
|
||||
@ -308,7 +311,7 @@ class childWindow:
|
||||
self.user_transition_treeview.set_model(self.user_transition_store)
|
||||
self.user_transition_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
self.user_transition_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text=0)
|
||||
self.user_transition_treeview.append_column(col)
|
||||
|
||||
for i in self.all_users:
|
||||
@ -322,7 +325,7 @@ class childWindow:
|
||||
self.admin_treeview.set_model(self.admin_store)
|
||||
self.admin_treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
|
||||
self.admin_store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("Application"), gtk.CellRendererText(), text=0)
|
||||
self.admin_treeview.append_column(col)
|
||||
|
||||
try:
|
||||
@ -333,7 +336,7 @@ class childWindow:
|
||||
for a in sepolicy.interface.get_admin():
|
||||
iter = self.admin_store.append()
|
||||
self.admin_store.set_value(iter, 0, a)
|
||||
except ValueError,e:
|
||||
except ValueError, e:
|
||||
self.error(e.message)
|
||||
|
||||
def confine_application(self):
|
||||
@ -367,19 +370,19 @@ class childWindow:
|
||||
if self.pages[type][self.current_page] == self.SELECT_DIR_PAGE:
|
||||
outputdir = self.output_entry.get_text()
|
||||
if not os.path.isdir(outputdir):
|
||||
self.error(_("%s must be a directory") % outputdir )
|
||||
self.error(_("%s must be a directory") % outputdir)
|
||||
return False
|
||||
|
||||
if self.pages[type][self.current_page] == self.FINISH_PAGE:
|
||||
self.generate_policy()
|
||||
self.xml.get_widget ("cancel_button").set_label(gtk.STOCK_CLOSE)
|
||||
self.xml.get_widget("cancel_button").set_label(gtk.STOCK_CLOSE)
|
||||
else:
|
||||
self.current_page = self.current_page + 1
|
||||
self.notebook.set_current_page(self.pages[type][self.current_page])
|
||||
if self.pages[type][self.current_page] == self.FINISH_PAGE:
|
||||
self.forward_button.set_label(gtk.STOCK_APPLY)
|
||||
|
||||
def back(self,arg):
|
||||
def back(self, arg):
|
||||
type = self.get_type()
|
||||
if self.pages[type][self.current_page] == self.FINISH_PAGE:
|
||||
self.forward_button.set_label(gtk.STOCK_GO_FORWARD)
|
||||
@ -394,7 +397,7 @@ class childWindow:
|
||||
for b in self.network_buttons[button]:
|
||||
b.set_sensitive(not active)
|
||||
|
||||
def verify(self, message, title="" ):
|
||||
def verify(self, message, title=""):
|
||||
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO,
|
||||
gtk.BUTTONS_YES_NO,
|
||||
message)
|
||||
@ -461,12 +464,12 @@ class childWindow:
|
||||
def generate_policy(self, *args):
|
||||
outputdir = self.output_entry.get_text()
|
||||
try:
|
||||
my_policy=generate.policy(self.get_name(), self.get_type())
|
||||
my_policy = generate.policy(self.get_name(), self.get_type())
|
||||
|
||||
iter= self.boolean_store.get_iter_first()
|
||||
iter = self.boolean_store.get_iter_first()
|
||||
while(iter):
|
||||
my_policy.add_boolean(self.boolean_store.get_value(iter, 0), self.boolean_store.get_value(iter, 1))
|
||||
iter= self.boolean_store.iter_next(iter)
|
||||
iter = self.boolean_store.iter_next(iter)
|
||||
|
||||
if self.get_type() in generate.APPLICATIONS:
|
||||
my_policy.set_program(self.exec_entry.get_text())
|
||||
@ -509,13 +512,13 @@ class childWindow:
|
||||
my_policy.set_out_tcp(self.out_tcp_all_checkbutton.get_active(), self.out_tcp_entry.get_text())
|
||||
my_policy.set_out_udp(self.out_udp_all_checkbutton.get_active(), self.out_udp_entry.get_text())
|
||||
|
||||
iter= self.store.get_iter_first()
|
||||
iter = self.store.get_iter_first()
|
||||
while(iter):
|
||||
if self.store.get_value(iter, 1) == FILE:
|
||||
my_policy.add_file(self.store.get_value(iter, 0))
|
||||
else:
|
||||
my_policy.add_dir(self.store.get_value(iter, 0))
|
||||
iter= self.store.iter_next(iter)
|
||||
iter = self.store.iter_next(iter)
|
||||
|
||||
self.info(my_policy.generate(outputdir))
|
||||
return False
|
||||
@ -526,15 +529,15 @@ class childWindow:
|
||||
store, iter = self.view.get_selection().get_selected()
|
||||
if iter != None:
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def delete_boolean(self, args):
|
||||
store, iter = self.boolean_treeview.get_selection().get_selected()
|
||||
if iter != None:
|
||||
store.remove(iter)
|
||||
self.boolean_treeview.get_selection().select_path ((0,))
|
||||
self.boolean_treeview.get_selection().select_path((0,))
|
||||
|
||||
def add_boolean(self,type):
|
||||
def add_boolean(self, type):
|
||||
self.boolean_name_entry.set_text("")
|
||||
self.boolean_description_entry.set_text("")
|
||||
rc = self.boolean_dialog.run()
|
||||
@ -545,7 +548,7 @@ class childWindow:
|
||||
self.boolean_store.set_value(iter, 0, self.boolean_name_entry.get_text())
|
||||
self.boolean_store.set_value(iter, 1, self.boolean_description_entry.get_text())
|
||||
|
||||
def __add(self,type):
|
||||
def __add(self, type):
|
||||
rc = self.file_dialog.run()
|
||||
self.file_dialog.hide()
|
||||
if rc == gtk.RESPONSE_CANCEL:
|
||||
@ -592,9 +595,9 @@ class childWindow:
|
||||
self.__add(DIR)
|
||||
|
||||
def on_about_clicked(self, args):
|
||||
dlg = xml.get_widget ("about_dialog")
|
||||
dlg.run ()
|
||||
dlg.hide ()
|
||||
dlg = xml.get_widget("about_dialog")
|
||||
dlg.run()
|
||||
dlg.hide()
|
||||
|
||||
def quit(self, args):
|
||||
gtk.main_quit()
|
||||
@ -605,15 +608,15 @@ class childWindow:
|
||||
self.druid = self.xml.get_widget("druid")
|
||||
self.type = 0
|
||||
self.name_entry = self.xml.get_widget("name_entry")
|
||||
self.name_entry.connect("insert_text",self.on_name_entry_changed)
|
||||
self.name_entry.connect("focus_out_event",self.on_focus_out_event)
|
||||
self.name_entry.connect("insert_text", self.on_name_entry_changed)
|
||||
self.name_entry.connect("focus_out_event", self.on_focus_out_event)
|
||||
self.exec_entry = self.xml.get_widget("exec_entry")
|
||||
self.exec_button = self.xml.get_widget("exec_button")
|
||||
self.init_script_entry = self.xml.get_widget("init_script_entry")
|
||||
self.init_script_button = self.xml.get_widget("init_script_button")
|
||||
self.output_entry = self.xml.get_widget("output_entry")
|
||||
self.output_entry.set_text(os.getcwd())
|
||||
self.xml.get_widget("output_button").connect("clicked",self.output_button_clicked)
|
||||
self.xml.get_widget("output_button").connect("clicked", self.output_button_clicked)
|
||||
|
||||
self.xwindows_user_radiobutton = self.xml.get_widget("xwindows_user_radiobutton")
|
||||
self.terminal_user_radiobutton = self.xml.get_widget("terminal_user_radiobutton")
|
||||
@ -641,10 +644,10 @@ class childWindow:
|
||||
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT)
|
||||
self.view.set_model(self.store)
|
||||
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text=0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def output_button_clicked(self, *args):
|
||||
self.file_dialog.set_title(_("Select directory to generate policy files in"))
|
||||
@ -712,7 +715,7 @@ class childWindow:
|
||||
return True
|
||||
|
||||
def on_name_page_next(self, *args):
|
||||
name=self.name_entry.get_text()
|
||||
name = self.name_entry.get_text()
|
||||
if not name.isalnum():
|
||||
self.error(_("You must add a name made up of letters and numbers and containing no spaces."))
|
||||
return True
|
||||
@ -730,7 +733,7 @@ class childWindow:
|
||||
if exe == "":
|
||||
self.error(_("You must enter a executable"))
|
||||
return True
|
||||
policy=generate.policy(name, self.get_type())
|
||||
policy = generate.policy(name, self.get_type())
|
||||
policy.set_program(exe)
|
||||
policy.gen_writeable()
|
||||
policy.gen_symbols()
|
||||
@ -762,7 +765,7 @@ class childWindow:
|
||||
gtk.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal (signal.SIGINT, signal.SIG_DFL)
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
app = childWindow()
|
||||
app.stand_alone()
|
||||
|
@ -24,7 +24,7 @@ import gobject
|
||||
import sys
|
||||
import seobject
|
||||
import commands
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
|
||||
##
|
||||
## I18N
|
||||
@ -41,12 +41,14 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class portsPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
semanagePage.__init__(self, xml, "ports", _("Network Port"))
|
||||
xml.signal_connect("on_group_clicked", self.on_group_clicked)
|
||||
@ -69,7 +71,7 @@ class portsPage(semanagePage):
|
||||
self.load()
|
||||
|
||||
def filter_changed(self, *arg):
|
||||
filter = arg[0].get_text()
|
||||
filter = arg[0].get_text()
|
||||
if filter != self.filter:
|
||||
if self.edit:
|
||||
self.load(filter)
|
||||
@ -77,37 +79,37 @@ class portsPage(semanagePage):
|
||||
self.group_load(filter)
|
||||
|
||||
def init_store(self):
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING , gobject.TYPE_STRING)
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
|
||||
self.view.set_model(self.store)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
|
||||
self.view.set_search_equal_func(self.search)
|
||||
col = gtk.TreeViewColumn(_("SELinux Port\nType"), gtk.CellRendererText(), text = TYPE_COL)
|
||||
col = gtk.TreeViewColumn(_("SELinux Port\nType"), gtk.CellRendererText(), text=TYPE_COL)
|
||||
col.set_sort_column_id(TYPE_COL)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.store.set_sort_column_id(TYPE_COL, gtk.SORT_ASCENDING)
|
||||
|
||||
col = gtk.TreeViewColumn(_("Protocol"), gtk.CellRendererText(), text = PROTOCOL_COL)
|
||||
col = gtk.TreeViewColumn(_("Protocol"), gtk.CellRendererText(), text=PROTOCOL_COL)
|
||||
col.set_sort_column_id(PROTOCOL_COL)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
|
||||
self.mls_col = gtk.TreeViewColumn(_("MLS/MCS\nLevel"), gtk.CellRendererText(), text = MLS_COL)
|
||||
self.mls_col = gtk.TreeViewColumn(_("MLS/MCS\nLevel"), gtk.CellRendererText(), text=MLS_COL)
|
||||
self.mls_col.set_resizable(True)
|
||||
self.mls_col.set_sort_column_id(MLS_COL)
|
||||
self.view.append_column(self.mls_col)
|
||||
|
||||
col = gtk.TreeViewColumn(_("Port"), gtk.CellRendererText(), text = PORT_COL)
|
||||
col = gtk.TreeViewColumn(_("Port"), gtk.CellRendererText(), text=PORT_COL)
|
||||
col.set_sort_column_id(PORT_COL)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
self.store.set_sort_func(PORT_COL,self.sort_int, "")
|
||||
self.store.set_sort_func(PORT_COL, self.sort_int, "")
|
||||
|
||||
def sort_int(self, treemodel, iter1, iter2, user_data):
|
||||
try:
|
||||
p1 = int(treemodel.get_value(iter1,PORT_COL).split('-')[0])
|
||||
p2 = int(treemodel.get_value(iter2,PORT_COL).split('-')[0])
|
||||
p1 = int(treemodel.get_value(iter1, PORT_COL).split('-')[0])
|
||||
p2 = int(treemodel.get_value(iter2, PORT_COL).split('-')[0])
|
||||
if p1 > p2:
|
||||
return 1
|
||||
if p1 == p2:
|
||||
@ -116,8 +118,8 @@ class portsPage(semanagePage):
|
||||
except:
|
||||
return 0
|
||||
|
||||
def load(self,filter = ""):
|
||||
self.filter=filter
|
||||
def load(self, filter=""):
|
||||
self.filter = filter
|
||||
self.port = seobject.portRecords()
|
||||
dict = self.port.get_all(self.local)
|
||||
keys = dict.keys()
|
||||
@ -135,10 +137,10 @@ class portsPage(semanagePage):
|
||||
self.store.set_value(iter, TYPE_COL, dict[k][0])
|
||||
self.store.set_value(iter, PROTOCOL_COL, k[2])
|
||||
self.store.set_value(iter, MLS_COL, dict[k][1])
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def group_load(self, filter = ""):
|
||||
self.filter=filter
|
||||
def group_load(self, filter=""):
|
||||
self.filter = filter
|
||||
self.port = seobject.portRecords()
|
||||
dict = self.port.get_all_by_type(self.local)
|
||||
keys = dict.keys()
|
||||
@ -146,14 +148,14 @@ class portsPage(semanagePage):
|
||||
self.store.clear()
|
||||
for k in keys:
|
||||
ports_string = ", ".join(dict[k])
|
||||
if not (self.match(ports_string, filter) or self.match(k[0], filter) or self.match(k[1], filter) ):
|
||||
if not (self.match(ports_string, filter) or self.match(k[0], filter) or self.match(k[1], filter)):
|
||||
continue
|
||||
iter = self.store.append()
|
||||
self.store.set_value(iter, TYPE_COL, k[0])
|
||||
self.store.set_value(iter, PROTOCOL_COL, k[1])
|
||||
self.store.set_value(iter, PORT_COL, ports_string)
|
||||
self.store.set_value(iter, MLS_COL, "")
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def propertiesDialog(self):
|
||||
if self.edit:
|
||||
@ -169,7 +171,7 @@ class portsPage(semanagePage):
|
||||
protocol = store.get_value(iter, PROTOCOL_COL)
|
||||
liststore = self.ports_protocol_combo.get_model()
|
||||
iter = liststore.get_iter_first()
|
||||
while iter != None and liststore.get_value(iter,0) != protocol:
|
||||
while iter != None and liststore.get_value(iter, 0) != protocol:
|
||||
iter = liststore.iter_next(iter)
|
||||
if iter != None:
|
||||
self.ports_protocol_combo.set_active_iter(iter)
|
||||
@ -192,7 +194,7 @@ class portsPage(semanagePage):
|
||||
if rc != 0:
|
||||
return self.error(out)
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
|
||||
@ -204,11 +206,11 @@ class portsPage(semanagePage):
|
||||
port_number = "1"
|
||||
for i in port_number.split("-"):
|
||||
if not i.isdigit():
|
||||
self.error(_("Port number \"%s\" is not valid. 0 < PORT_NUMBER < 65536 ") % port_number )
|
||||
self.error(_("Port number \"%s\" is not valid. 0 < PORT_NUMBER < 65536 ") % port_number)
|
||||
return False
|
||||
list_model = self.ports_protocol_combo.get_model()
|
||||
iter = self.ports_protocol_combo.get_active_iter()
|
||||
protocol = list_model.get_value(iter,0)
|
||||
protocol = list_model.get_value(iter, 0)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage port -a -p %s -r %s -t %s %s" % (protocol, mls, target, port_number))
|
||||
self.ready()
|
||||
@ -228,7 +230,7 @@ class portsPage(semanagePage):
|
||||
port_number = self.ports_number_entry.get_text().strip()
|
||||
list_model = self.ports_protocol_combo.get_model()
|
||||
iter = self.ports_protocol_combo.get_active_iter()
|
||||
protocol = list_model.get_value(iter,0)
|
||||
protocol = list_model.get_value(iter, 0)
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage port -m -p %s -r %s -t %s %s" % (protocol, mls, target, port_number))
|
||||
self.ready()
|
||||
|
@ -27,7 +27,7 @@ import seobject
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -35,16 +35,19 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
def idle_func():
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration()
|
||||
|
||||
|
||||
class semanagePage:
|
||||
|
||||
def __init__(self, xml, name, description):
|
||||
self.xml = xml
|
||||
self.window = self.xml.get_widget("mainWindow").get_root_window()
|
||||
@ -54,13 +57,13 @@ class semanagePage:
|
||||
self.local = False
|
||||
self.view = xml.get_widget("%sView" % name)
|
||||
self.dialog = xml.get_widget("%sDialog" % name)
|
||||
self.filter_entry = xml.get_widget("%sFilterEntry" % name )
|
||||
self.filter_entry = xml.get_widget("%sFilterEntry" % name)
|
||||
self.filter_entry.connect("focus_out_event", self.filter_changed)
|
||||
self.filter_entry.connect("activate", self.filter_changed)
|
||||
|
||||
self.view.connect("row_activated", self.rowActivated)
|
||||
self.view.get_selection().connect("changed", self.itemSelected)
|
||||
self.description = description;
|
||||
self.description = description
|
||||
|
||||
def wait(self):
|
||||
self.window.set_cursor(self.busy_cursor)
|
||||
@ -77,21 +80,21 @@ class semanagePage:
|
||||
return
|
||||
|
||||
def filter_changed(self, *arg):
|
||||
filter = arg[0].get_text()
|
||||
filter = arg[0].get_text()
|
||||
if filter != self.filter:
|
||||
self.load(filter)
|
||||
|
||||
def search(self, model, col, key, i):
|
||||
sort_col = self.store.get_sort_column_id()[0]
|
||||
val = model.get_value(i,sort_col)
|
||||
val = model.get_value(i, sort_col)
|
||||
if val.lower().startswith(key.lower()):
|
||||
return False
|
||||
return True
|
||||
|
||||
def match(self, target, filter):
|
||||
try:
|
||||
f=filter.lower()
|
||||
t=target.lower()
|
||||
f = filter.lower()
|
||||
t = target.lower()
|
||||
if t.find(f) >= 0:
|
||||
return True
|
||||
except:
|
||||
@ -101,7 +104,7 @@ class semanagePage:
|
||||
def rowActivated(self, view, row, Column):
|
||||
self.propertiesDialog()
|
||||
|
||||
def verify(self, message, title="" ):
|
||||
def verify(self, message, title=""):
|
||||
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO,
|
||||
gtk.BUTTONS_YES_NO,
|
||||
message)
|
||||
@ -134,11 +137,11 @@ class semanagePage:
|
||||
self.dialog.set_title(_("Add %s" % self.description))
|
||||
self.dialog.set_position(gtk.WIN_POS_MOUSE)
|
||||
|
||||
while self.dialog.run() == gtk.RESPONSE_OK:
|
||||
while self.dialog.run() == gtk.RESPONSE_OK:
|
||||
try:
|
||||
if self.add() == False:
|
||||
continue
|
||||
break;
|
||||
break
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
self.dialog.hide()
|
||||
@ -147,11 +150,11 @@ class semanagePage:
|
||||
self.dialogInit()
|
||||
self.dialog.set_title(_("Modify %s" % self.description))
|
||||
self.dialog.set_position(gtk.WIN_POS_MOUSE)
|
||||
while self.dialog.run() == gtk.RESPONSE_OK:
|
||||
while self.dialog.run() == gtk.RESPONSE_OK:
|
||||
try:
|
||||
if self.modify() == False:
|
||||
continue
|
||||
break;
|
||||
break
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
self.dialog.hide()
|
||||
|
@ -31,7 +31,7 @@ import commands
|
||||
ENFORCING = 1
|
||||
PERMISSIVE = 0
|
||||
DISABLED = -1
|
||||
modearray = ( "disabled", "permissive", "enforcing" )
|
||||
modearray = ("disabled", "permissive", "enforcing")
|
||||
|
||||
SELINUXDIR = "/etc/selinux/"
|
||||
RELABELFILE = "/.autorelabel"
|
||||
@ -39,7 +39,7 @@ RELABELFILE = "/.autorelabel"
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -50,7 +50,9 @@ except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class statusPage:
|
||||
|
||||
def __init__(self, xml):
|
||||
self.xml = xml
|
||||
self.needRelabel = False
|
||||
@ -66,15 +68,15 @@ class statusPage:
|
||||
self.relabel_checkbutton.set_active(self.is_relabel())
|
||||
self.relabel_checkbutton.connect("toggled", self.on_relabel_toggle)
|
||||
if self.get_current_mode() == ENFORCING or self.get_current_mode() == PERMISSIVE:
|
||||
self.currentOptionMenu.append_text(_("Permissive"))
|
||||
self.currentOptionMenu.append_text(_("Enforcing"))
|
||||
self.currentOptionMenu.set_active(self.get_current_mode())
|
||||
self.currentOptionMenu.connect("changed", self.set_current_mode)
|
||||
self.currentOptionMenu.set_sensitive(True)
|
||||
self.currentOptionMenu.append_text(_("Permissive"))
|
||||
self.currentOptionMenu.append_text(_("Enforcing"))
|
||||
self.currentOptionMenu.set_active(self.get_current_mode())
|
||||
self.currentOptionMenu.connect("changed", self.set_current_mode)
|
||||
self.currentOptionMenu.set_sensitive(True)
|
||||
else:
|
||||
self.currentOptionMenu.append_text(_("Disabled"))
|
||||
self.currentOptionMenu.set_active(0)
|
||||
self.currentOptionMenu.set_sensitive(False)
|
||||
self.currentOptionMenu.append_text(_("Disabled"))
|
||||
self.currentOptionMenu.set_active(0)
|
||||
self.currentOptionMenu.set_sensitive(False)
|
||||
|
||||
if self.read_selinux_config() == None:
|
||||
self.selinuxsupport = False
|
||||
@ -102,15 +104,15 @@ class statusPage:
|
||||
else:
|
||||
return DISABLED
|
||||
|
||||
def set_current_mode(self,menu):
|
||||
def set_current_mode(self, menu):
|
||||
selinux.security_setenforce(menu.get_active() == 1)
|
||||
|
||||
def is_relabel(self):
|
||||
return os.access(RELABELFILE, os.F_OK) != 0
|
||||
|
||||
def on_relabel_toggle(self,button):
|
||||
def on_relabel_toggle(self, button):
|
||||
if button.get_active():
|
||||
fd = open(RELABELFILE,"w")
|
||||
fd = open(RELABELFILE, "w")
|
||||
fd.close()
|
||||
else:
|
||||
if os.access(RELABELFILE, os.F_OK) != 0:
|
||||
@ -136,7 +138,7 @@ class statusPage:
|
||||
|
||||
self.relabel_checkbutton.set_active(True)
|
||||
|
||||
self.write_selinux_config(modearray[enabled], type )
|
||||
self.write_selinux_config(modearray[enabled], type)
|
||||
self.typeHistory = menu.get_active()
|
||||
|
||||
def enabled_changed(self, combo):
|
||||
@ -154,11 +156,11 @@ class statusPage:
|
||||
return None
|
||||
self.relabel_checkbutton.set_active(True)
|
||||
|
||||
self.write_selinux_config(modearray[enabled], type )
|
||||
self.write_selinux_config(modearray[enabled], type)
|
||||
self.enabled = enabled
|
||||
|
||||
def write_selinux_config(self, enforcing, type):
|
||||
path = selinux.selinux_path() + "config"
|
||||
path = selinux.selinux_path() + "config"
|
||||
backup_path = path + ".bck"
|
||||
fd = open(path)
|
||||
lines = fd.readlines()
|
||||
@ -183,7 +185,7 @@ class statusPage:
|
||||
self.initEnabled = False
|
||||
pass
|
||||
self.enabled = self.initEnabled
|
||||
self.enabledOptionMenu.set_active(self.enabled + 1 )
|
||||
self.enabledOptionMenu.set_active(self.enabled + 1)
|
||||
|
||||
self.types = []
|
||||
|
||||
@ -191,12 +193,12 @@ class statusPage:
|
||||
current = n
|
||||
|
||||
for i in os.listdir(SELINUXDIR):
|
||||
if os.path.isdir(SELINUXDIR+i) and os.path.isdir(SELINUXDIR+i+"/policy"):
|
||||
if os.path.isdir(SELINUXDIR + i) and os.path.isdir(SELINUXDIR + i + "/policy"):
|
||||
self.types.append(i)
|
||||
self.selinuxTypeOptionMenu.append_text(i)
|
||||
if i == self.initialtype:
|
||||
current = n
|
||||
n = n+1
|
||||
n = n + 1
|
||||
self.selinuxTypeOptionMenu.set_active(current)
|
||||
self.typeHistory = current
|
||||
|
||||
|
@ -28,7 +28,7 @@ try:
|
||||
except RuntimeError, e:
|
||||
print "system-config-selinux:", e
|
||||
print "This is a graphical application and requires DISPLAY to be set."
|
||||
sys.exit (1)
|
||||
sys.exit(1)
|
||||
|
||||
import gtk.glade
|
||||
import os
|
||||
@ -46,7 +46,7 @@ import selinux
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
@ -55,7 +55,7 @@ try:
|
||||
gettext.install(PROGNAME,
|
||||
localedir="/usr/share/locale",
|
||||
unicode=False,
|
||||
codeset = 'utf-8')
|
||||
codeset='utf-8')
|
||||
except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
@ -67,18 +67,19 @@ version = "1.0"
|
||||
sys.path.append('/usr/share/system-config-selinux')
|
||||
|
||||
|
||||
|
||||
##
|
||||
## Pull in the Glade file
|
||||
##
|
||||
if os.access("system-config-selinux.glade", os.F_OK):
|
||||
xml = gtk.glade.XML ("system-config-selinux.glade", domain=PROGNAME)
|
||||
xml = gtk.glade.XML("system-config-selinux.glade", domain=PROGNAME)
|
||||
else:
|
||||
xml = gtk.glade.XML ("/usr/share/system-config-selinux/system-config-selinux.glade", domain=PROGNAME)
|
||||
xml = gtk.glade.XML("/usr/share/system-config-selinux/system-config-selinux.glade", domain=PROGNAME)
|
||||
|
||||
|
||||
class childWindow:
|
||||
|
||||
def __init__(self):
|
||||
self.tabs=[]
|
||||
self.tabs = []
|
||||
self.xml = xml
|
||||
xml.signal_connect("on_quit_activate", self.destroy)
|
||||
xml.signal_connect("on_delete_clicked", self.delete)
|
||||
@ -93,8 +94,8 @@ class childWindow:
|
||||
self.add_page(loginsPage.loginsPage(xml))
|
||||
self.add_page(usersPage.usersPage(xml))
|
||||
self.add_page(portsPage.portsPage(xml))
|
||||
self.add_page(modulesPage.modulesPage(xml)) # modules
|
||||
self.add_page(domainsPage.domainsPage(xml)) # domains
|
||||
self.add_page(modulesPage.modulesPage(xml)) # modules
|
||||
self.add_page(domainsPage.domainsPage(xml)) # domains
|
||||
except ValueError, e:
|
||||
self.error(e.message)
|
||||
|
||||
@ -121,6 +122,7 @@ class childWindow:
|
||||
|
||||
def policy(self, args):
|
||||
os.spawnl(os.P_NOWAIT, "/usr/share/system-config-selinux/semanagegui.py")
|
||||
|
||||
def logging(self, args):
|
||||
os.spawnl(os.P_NOWAIT, "/usr/bin/seaudit")
|
||||
|
||||
@ -137,9 +139,9 @@ class childWindow:
|
||||
self.tabs[self.notebook.get_current_page()].on_local_clicked(button)
|
||||
|
||||
def on_about_activate(self, args):
|
||||
dlg = xml.get_widget ("aboutWindow")
|
||||
dlg.run ()
|
||||
dlg.hide ()
|
||||
dlg = xml.get_widget("aboutWindow")
|
||||
dlg.run()
|
||||
dlg.hide()
|
||||
|
||||
def destroy(self, args):
|
||||
gtk.main_quit()
|
||||
@ -158,7 +160,6 @@ class childWindow:
|
||||
self.notebook.set_current_page(0)
|
||||
self.use_menus(self.tabs[0].use_menus())
|
||||
|
||||
|
||||
def setupScreen(self):
|
||||
# Bring in widgets from glade file.
|
||||
self.mainWindow = self.xml.get_widget("mainWindow")
|
||||
@ -167,14 +168,14 @@ class childWindow:
|
||||
self.view.get_selection().connect("changed", self.itemSelected)
|
||||
self.store = gtk.ListStore(gobject.TYPE_STRING)
|
||||
self.view.set_model(self.store)
|
||||
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn("", gtk.CellRendererText(), text=0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
|
||||
for page in self.tabs:
|
||||
iter = self.store.append()
|
||||
self.store.set_value(iter, 0, page.get_description())
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def stand_alone(self):
|
||||
desktopName = _("Configue SELinux")
|
||||
@ -187,7 +188,7 @@ class childWindow:
|
||||
gtk.main()
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal (signal.SIGINT, signal.SIG_DFL)
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
app = childWindow()
|
||||
app.stand_alone()
|
||||
|
@ -24,12 +24,12 @@ import gobject
|
||||
import sys
|
||||
import commands
|
||||
import seobject
|
||||
from semanagePage import *;
|
||||
from semanagePage import *
|
||||
|
||||
##
|
||||
## I18N
|
||||
##
|
||||
PROGNAME="policycoreutils"
|
||||
PROGNAME = "policycoreutils"
|
||||
import gettext
|
||||
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
|
||||
gettext.textdomain(PROGNAME)
|
||||
@ -39,7 +39,9 @@ except IOError:
|
||||
import __builtin__
|
||||
__builtin__.__dict__['_'] = unicode
|
||||
|
||||
|
||||
class usersPage(semanagePage):
|
||||
|
||||
def __init__(self, xml):
|
||||
semanagePage.__init__(self, xml, "users", _("SELinux User"))
|
||||
|
||||
@ -47,16 +49,16 @@ class usersPage(semanagePage):
|
||||
self.view.set_model(self.store)
|
||||
self.store.set_sort_column_id(0, gtk.SORT_ASCENDING)
|
||||
|
||||
col = gtk.TreeViewColumn(_("SELinux\nUser"), gtk.CellRendererText(), text = 0)
|
||||
col = gtk.TreeViewColumn(_("SELinux\nUser"), gtk.CellRendererText(), text=0)
|
||||
col.set_sort_column_id(0)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
|
||||
col = gtk.TreeViewColumn(_("MLS/\nMCS Range"), gtk.CellRendererText(), text = 1)
|
||||
col = gtk.TreeViewColumn(_("MLS/\nMCS Range"), gtk.CellRendererText(), text=1)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
|
||||
col = gtk.TreeViewColumn(_("SELinux Roles"), gtk.CellRendererText(), text = 2)
|
||||
col = gtk.TreeViewColumn(_("SELinux Roles"), gtk.CellRendererText(), text=2)
|
||||
col.set_resizable(True)
|
||||
self.view.append_column(col)
|
||||
|
||||
@ -65,8 +67,8 @@ class usersPage(semanagePage):
|
||||
self.mlsRangeEntry = xml.get_widget("mlsRangeEntry")
|
||||
self.selinuxRolesEntry = xml.get_widget("selinuxRolesEntry")
|
||||
|
||||
def load(self, filter = ""):
|
||||
self.filter=filter
|
||||
def load(self, filter=""):
|
||||
self.filter = filter
|
||||
self.user = seobject.seluserRecords()
|
||||
dict = self.user.get_all()
|
||||
keys = dict.keys()
|
||||
@ -81,11 +83,11 @@ class usersPage(semanagePage):
|
||||
self.store.set_value(iter, 0, k)
|
||||
self.store.set_value(iter, 1, range)
|
||||
self.store.set_value(iter, 2, dict[k][3])
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
|
||||
def delete(self):
|
||||
if semanagePage.delete(self) == gtk.RESPONSE_NO:
|
||||
return None
|
||||
return None
|
||||
|
||||
def dialogInit(self):
|
||||
store, iter = self.view.get_selection().get_selected()
|
||||
@ -106,7 +108,7 @@ class usersPage(semanagePage):
|
||||
roles = self.selinuxRolesEntry.get_text()
|
||||
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage user -a -R '%s' -r %s %s" % (roles, range, user))
|
||||
(rc, out) = commands.getstatusoutput("semanage user -a -R '%s' -r %s %s" % (roles, range, user))
|
||||
self.ready()
|
||||
if rc != 0:
|
||||
self.error(out)
|
||||
@ -122,7 +124,7 @@ class usersPage(semanagePage):
|
||||
roles = self.selinuxRolesEntry.get_text()
|
||||
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage user -m -R '%s' -r %s %s" % (roles, range, user))
|
||||
(rc, out) = commands.getstatusoutput("semanage user -m -R '%s' -r %s %s" % (roles, range, user))
|
||||
self.ready()
|
||||
|
||||
if rc != 0:
|
||||
@ -133,17 +135,17 @@ class usersPage(semanagePage):
|
||||
def delete(self):
|
||||
store, iter = self.view.get_selection().get_selected()
|
||||
try:
|
||||
user=store.get_value(iter, 0)
|
||||
user = store.get_value(iter, 0)
|
||||
if user == "root" or user == "user_u":
|
||||
raise ValueError(_("SELinux user '%s' is required") % user)
|
||||
|
||||
self.wait()
|
||||
(rc, out) = commands.getstatusoutput("semanage user -d %s" % user)
|
||||
(rc, out) = commands.getstatusoutput("semanage user -d %s" % user)
|
||||
self.ready()
|
||||
if rc != 0:
|
||||
self.error(out)
|
||||
return False
|
||||
store.remove(iter)
|
||||
self.view.get_selection().select_path ((0,))
|
||||
self.view.get_selection().select_path((0,))
|
||||
except ValueError, e:
|
||||
self.error(e.args[0])
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user