diff options
Diffstat (limited to 'libsepol/src/context.c')
-rw-r--r-- | libsepol/src/context.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/libsepol/src/context.c b/libsepol/src/context.c new file mode 100644 index 00000000..84dad348 --- /dev/null +++ b/libsepol/src/context.c @@ -0,0 +1,338 @@ +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <sepol/policydb/policydb.h> +#include <sepol/policydb/services.h> +#include "context_internal.h" + +#include "debug.h" +#include "context.h" +#include "handle.h" +#include "mls.h" + +/* ----- Compatibility ---- */ +int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c) +{ + + return context_is_valid(p, c); +} + +int sepol_check_context(const char *context) +{ + + return sepol_context_to_sid((const sepol_security_context_t)context, + strlen(context) + 1, NULL); +} + +/* ---- End compatibility --- */ + +/* + * Return 1 if the fields in the security context + * structure `c' are valid. Return 0 otherwise. + */ +int context_is_valid(const policydb_t * p, const context_struct_t * c) +{ + + role_datum_t *role; + user_datum_t *usrdatum; + ebitmap_t types, roles; + int ret = 1; + + ebitmap_init(&types); + ebitmap_init(&roles); + if (!c->role || c->role > p->p_roles.nprim) + return 0; + + if (!c->user || c->user > p->p_users.nprim) + return 0; + + if (!c->type || c->type > p->p_types.nprim) + return 0; + + if (c->role != OBJECT_R_VAL) { + /* + * Role must be authorized for the type. + */ + role = p->role_val_to_struct[c->role - 1]; + if (!ebitmap_get_bit(&role->cache, c->type - 1)) + /* role may not be associated with type */ + return 0; + + /* + * User must be authorized for the role. + */ + usrdatum = p->user_val_to_struct[c->user - 1]; + if (!usrdatum) + return 0; + + if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1)) + /* user may not be associated with role */ + return 0; + } + + if (!mls_context_isvalid(p, c)) + return 0; + + return ret; +} + +/* + * Write the security context string representation of + * the context structure `context' into a dynamically + * allocated string of the correct size. Set `*scontext' + * to point to this string and set `*scontext_len' to + * the length of the string. + */ +int context_to_string(sepol_handle_t * handle, + const policydb_t * policydb, + const context_struct_t * context, + char **result, size_t * result_len) +{ + + char *scontext = NULL; + size_t scontext_len = 0; + char *ptr; + + /* Compute the size of the context. */ + scontext_len += + strlen(policydb->p_user_val_to_name[context->user - 1]) + 1; + scontext_len += + strlen(policydb->p_role_val_to_name[context->role - 1]) + 1; + scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]); + scontext_len += mls_compute_context_len(policydb, context); + + /* We must null terminate the string */ + scontext_len += 1; + + /* Allocate space for the context; caller must free this space. */ + scontext = malloc(scontext_len); + if (!scontext) + goto omem; + scontext[scontext_len - 1] = '\0'; + + /* + * Copy the user name, role name and type name into the context. + */ + ptr = scontext; + sprintf(ptr, "%s:%s:%s", + policydb->p_user_val_to_name[context->user - 1], + policydb->p_role_val_to_name[context->role - 1], + policydb->p_type_val_to_name[context->type - 1]); + + ptr += + strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 + + strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 + + strlen(policydb->p_type_val_to_name[context->type - 1]); + + mls_sid_to_context(policydb, context, &ptr); + + *result = scontext; + *result_len = scontext_len; + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory, could not convert " "context to string"); + free(scontext); + return STATUS_ERR; +} + +/* + * Create a context structure from the given record + */ +int context_from_record(sepol_handle_t * handle, + const policydb_t * policydb, + context_struct_t ** cptr, + const sepol_context_t * record) +{ + + context_struct_t *scontext = NULL; + user_datum_t *usrdatum; + role_datum_t *roldatum; + type_datum_t *typdatum; + + /* Hashtab keys are not constant - suppress warnings */ + char *user = strdup(sepol_context_get_user(record)); + char *role = strdup(sepol_context_get_role(record)); + char *type = strdup(sepol_context_get_type(record)); + const char *mls = sepol_context_get_mls(record); + + scontext = (context_struct_t *) malloc(sizeof(context_struct_t)); + if (!user || !role || !type || !scontext) { + ERR(handle, "out of memory"); + goto err; + } + context_init(scontext); + + /* User */ + usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table, + (hashtab_key_t) user); + if (!usrdatum) { + ERR(handle, "user %s is not defined", user); + goto err_destroy; + } + scontext->user = usrdatum->s.value; + + /* Role */ + roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table, + (hashtab_key_t) role); + if (!roldatum) { + ERR(handle, "role %s is not defined", role); + goto err_destroy; + } + scontext->role = roldatum->s.value; + + /* Type */ + typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table, + (hashtab_key_t) type); + if (!typdatum || typdatum->flavor == TYPE_ATTRIB) { + ERR(handle, "type %s is not defined", type); + goto err_destroy; + } + scontext->type = typdatum->s.value; + + /* MLS */ + if (mls && !policydb->mls) { + ERR(handle, "MLS is disabled, but MLS context \"%s\" found", + mls); + goto err_destroy; + } else if (!mls && policydb->mls) { + ERR(handle, "MLS is enabled, but no MLS context found"); + goto err_destroy; + } + if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0)) + goto err_destroy; + + /* Validity check */ + if (!context_is_valid(policydb, scontext)) { + if (mls) { + ERR(handle, + "invalid security context: \"%s:%s:%s:%s\"", + user, role, type, mls); + } else { + ERR(handle, + "invalid security context: \"%s:%s:%s\"", + user, role, type); + } + goto err_destroy; + } + + *cptr = scontext; + free(user); + free(type); + free(role); + return STATUS_SUCCESS; + + err_destroy: + errno = EINVAL; + context_destroy(scontext); + + err: + free(scontext); + free(user); + free(type); + free(role); + ERR(handle, "could not create context structure"); + return STATUS_ERR; +} + +/* + * Create a record from the given context structure + */ +int context_to_record(sepol_handle_t * handle, + const policydb_t * policydb, + const context_struct_t * context, + sepol_context_t ** record) +{ + + sepol_context_t *tmp_record = NULL; + char *mls = NULL; + + if (sepol_context_create(handle, &tmp_record) < 0) + goto err; + + if (sepol_context_set_user(handle, tmp_record, + policydb->p_user_val_to_name[context->user - + 1]) < 0) + goto err; + + if (sepol_context_set_role(handle, tmp_record, + policydb->p_role_val_to_name[context->role - + 1]) < 0) + goto err; + + if (sepol_context_set_type(handle, tmp_record, + policydb->p_type_val_to_name[context->type - + 1]) < 0) + goto err; + + if (policydb->mls) { + if (mls_to_string(handle, policydb, context, &mls) < 0) + goto err; + + if (sepol_context_set_mls(handle, tmp_record, mls) < 0) + goto err; + } + + free(mls); + *record = tmp_record; + return STATUS_SUCCESS; + + err: + ERR(handle, "could not create context record"); + sepol_context_free(tmp_record); + free(mls); + return STATUS_ERR; +} + +/* + * Create a context structure from the provided string. + */ +int context_from_string(sepol_handle_t * handle, + const policydb_t * policydb, + context_struct_t ** cptr, + const char *con_str, size_t con_str_len) +{ + + char *con_cpy = NULL; + sepol_context_t *ctx_record = NULL; + + /* sepol_context_from_string expects a NULL-terminated string */ + con_cpy = malloc(con_str_len + 1); + if (!con_cpy) + goto omem; + memcpy(con_cpy, con_str, con_str_len); + con_cpy[con_str_len] = '\0'; + + if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0) + goto err; + + /* Now create from the data structure */ + if (context_from_record(handle, policydb, cptr, ctx_record) < 0) + goto err; + + free(con_cpy); + sepol_context_free(ctx_record); + return STATUS_SUCCESS; + + omem: + ERR(handle, "out of memory"); + + err: + ERR(handle, "could not create context structure"); + free(con_cpy); + sepol_context_free(ctx_record); + return STATUS_ERR; +} + +int sepol_context_check(sepol_handle_t * handle, + const sepol_policydb_t * policydb, + const sepol_context_t * context) +{ + + context_struct_t *con = NULL; + int ret = context_from_record(handle, &policydb->p, &con, context); + context_destroy(con); + free(con); + return ret; +} |