| #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; |
| } |