16cd6a6acSopenharmony_ci#include <stdlib.h> 26cd6a6acSopenharmony_ci#include <string.h> 36cd6a6acSopenharmony_ci#include <errno.h> 46cd6a6acSopenharmony_ci 56cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h> 66cd6a6acSopenharmony_ci#include <sepol/policydb/services.h> 76cd6a6acSopenharmony_ci#include "context_internal.h" 86cd6a6acSopenharmony_ci 96cd6a6acSopenharmony_ci#include "debug.h" 106cd6a6acSopenharmony_ci#include "context.h" 116cd6a6acSopenharmony_ci#include "handle.h" 126cd6a6acSopenharmony_ci#include "mls.h" 136cd6a6acSopenharmony_ci#include "private.h" 146cd6a6acSopenharmony_ci 156cd6a6acSopenharmony_ci/* ----- Compatibility ---- */ 166cd6a6acSopenharmony_ciint policydb_context_isvalid(const policydb_t * p, const context_struct_t * c) 176cd6a6acSopenharmony_ci{ 186cd6a6acSopenharmony_ci 196cd6a6acSopenharmony_ci return context_is_valid(p, c); 206cd6a6acSopenharmony_ci} 216cd6a6acSopenharmony_ci 226cd6a6acSopenharmony_ciint sepol_check_context(const char *context) 236cd6a6acSopenharmony_ci{ 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_ci return sepol_context_to_sid(context, 266cd6a6acSopenharmony_ci strlen(context) + 1, NULL); 276cd6a6acSopenharmony_ci} 286cd6a6acSopenharmony_ci 296cd6a6acSopenharmony_ci/* ---- End compatibility --- */ 306cd6a6acSopenharmony_ci 316cd6a6acSopenharmony_ci/* 326cd6a6acSopenharmony_ci * Return 1 if the fields in the security context 336cd6a6acSopenharmony_ci * structure `c' are valid. Return 0 otherwise. 346cd6a6acSopenharmony_ci */ 356cd6a6acSopenharmony_ciint context_is_valid(const policydb_t * p, const context_struct_t * c) 366cd6a6acSopenharmony_ci{ 376cd6a6acSopenharmony_ci 386cd6a6acSopenharmony_ci role_datum_t *role; 396cd6a6acSopenharmony_ci user_datum_t *usrdatum; 406cd6a6acSopenharmony_ci ebitmap_t types, roles; 416cd6a6acSopenharmony_ci 426cd6a6acSopenharmony_ci ebitmap_init(&types); 436cd6a6acSopenharmony_ci ebitmap_init(&roles); 446cd6a6acSopenharmony_ci if (!c->role || c->role > p->p_roles.nprim) 456cd6a6acSopenharmony_ci return 0; 466cd6a6acSopenharmony_ci 476cd6a6acSopenharmony_ci if (!c->user || c->user > p->p_users.nprim) 486cd6a6acSopenharmony_ci return 0; 496cd6a6acSopenharmony_ci 506cd6a6acSopenharmony_ci if (!c->type || c->type > p->p_types.nprim) 516cd6a6acSopenharmony_ci return 0; 526cd6a6acSopenharmony_ci 536cd6a6acSopenharmony_ci if (c->role != OBJECT_R_VAL) { 546cd6a6acSopenharmony_ci /* 556cd6a6acSopenharmony_ci * Role must be authorized for the type. 566cd6a6acSopenharmony_ci */ 576cd6a6acSopenharmony_ci role = p->role_val_to_struct[c->role - 1]; 586cd6a6acSopenharmony_ci if (!role || !ebitmap_get_bit(&role->cache, c->type - 1)) 596cd6a6acSopenharmony_ci /* role may not be associated with type */ 606cd6a6acSopenharmony_ci return 0; 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_ci /* 636cd6a6acSopenharmony_ci * User must be authorized for the role. 646cd6a6acSopenharmony_ci */ 656cd6a6acSopenharmony_ci usrdatum = p->user_val_to_struct[c->user - 1]; 666cd6a6acSopenharmony_ci if (!usrdatum) 676cd6a6acSopenharmony_ci return 0; 686cd6a6acSopenharmony_ci 696cd6a6acSopenharmony_ci if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1)) 706cd6a6acSopenharmony_ci /* user may not be associated with role */ 716cd6a6acSopenharmony_ci return 0; 726cd6a6acSopenharmony_ci } 736cd6a6acSopenharmony_ci 746cd6a6acSopenharmony_ci if (!mls_context_isvalid(p, c)) 756cd6a6acSopenharmony_ci return 0; 766cd6a6acSopenharmony_ci 776cd6a6acSopenharmony_ci return 1; 786cd6a6acSopenharmony_ci} 796cd6a6acSopenharmony_ci 806cd6a6acSopenharmony_ci/* 816cd6a6acSopenharmony_ci * Write the security context string representation of 826cd6a6acSopenharmony_ci * the context structure `context' into a dynamically 836cd6a6acSopenharmony_ci * allocated string of the correct size. Set `*scontext' 846cd6a6acSopenharmony_ci * to point to this string and set `*scontext_len' to 856cd6a6acSopenharmony_ci * the length of the string. 866cd6a6acSopenharmony_ci */ 876cd6a6acSopenharmony_ciint context_to_string(sepol_handle_t * handle, 886cd6a6acSopenharmony_ci const policydb_t * policydb, 896cd6a6acSopenharmony_ci const context_struct_t * context, 906cd6a6acSopenharmony_ci char **result, size_t * result_len) 916cd6a6acSopenharmony_ci{ 926cd6a6acSopenharmony_ci 936cd6a6acSopenharmony_ci char *scontext = NULL; 946cd6a6acSopenharmony_ci size_t scontext_len = 0; 956cd6a6acSopenharmony_ci char *ptr; 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_ci /* Compute the size of the context. */ 986cd6a6acSopenharmony_ci scontext_len += 996cd6a6acSopenharmony_ci strlen(policydb->p_user_val_to_name[context->user - 1]) + 1; 1006cd6a6acSopenharmony_ci scontext_len += 1016cd6a6acSopenharmony_ci strlen(policydb->p_role_val_to_name[context->role - 1]) + 1; 1026cd6a6acSopenharmony_ci scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]); 1036cd6a6acSopenharmony_ci scontext_len += mls_compute_context_len(policydb, context); 1046cd6a6acSopenharmony_ci 1056cd6a6acSopenharmony_ci /* We must null terminate the string */ 1066cd6a6acSopenharmony_ci scontext_len += 1; 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci /* Allocate space for the context; caller must free this space. */ 1096cd6a6acSopenharmony_ci scontext = malloc(scontext_len); 1106cd6a6acSopenharmony_ci if (!scontext) 1116cd6a6acSopenharmony_ci goto omem; 1126cd6a6acSopenharmony_ci scontext[scontext_len - 1] = '\0'; 1136cd6a6acSopenharmony_ci 1146cd6a6acSopenharmony_ci /* 1156cd6a6acSopenharmony_ci * Copy the user name, role name and type name into the context. 1166cd6a6acSopenharmony_ci */ 1176cd6a6acSopenharmony_ci ptr = scontext; 1186cd6a6acSopenharmony_ci sprintf(ptr, "%s:%s:%s", 1196cd6a6acSopenharmony_ci policydb->p_user_val_to_name[context->user - 1], 1206cd6a6acSopenharmony_ci policydb->p_role_val_to_name[context->role - 1], 1216cd6a6acSopenharmony_ci policydb->p_type_val_to_name[context->type - 1]); 1226cd6a6acSopenharmony_ci 1236cd6a6acSopenharmony_ci ptr += 1246cd6a6acSopenharmony_ci strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 + 1256cd6a6acSopenharmony_ci strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 + 1266cd6a6acSopenharmony_ci strlen(policydb->p_type_val_to_name[context->type - 1]); 1276cd6a6acSopenharmony_ci 1286cd6a6acSopenharmony_ci mls_sid_to_context(policydb, context, &ptr); 1296cd6a6acSopenharmony_ci 1306cd6a6acSopenharmony_ci *result = scontext; 1316cd6a6acSopenharmony_ci *result_len = scontext_len; 1326cd6a6acSopenharmony_ci return STATUS_SUCCESS; 1336cd6a6acSopenharmony_ci 1346cd6a6acSopenharmony_ci omem: 1356cd6a6acSopenharmony_ci ERR(handle, "out of memory, could not convert " "context to string"); 1366cd6a6acSopenharmony_ci free(scontext); 1376cd6a6acSopenharmony_ci return STATUS_ERR; 1386cd6a6acSopenharmony_ci} 1396cd6a6acSopenharmony_ci 1406cd6a6acSopenharmony_ci/* 1416cd6a6acSopenharmony_ci * Create a context structure from the given record 1426cd6a6acSopenharmony_ci */ 1436cd6a6acSopenharmony_ciint context_from_record(sepol_handle_t * handle, 1446cd6a6acSopenharmony_ci const policydb_t * policydb, 1456cd6a6acSopenharmony_ci context_struct_t ** cptr, 1466cd6a6acSopenharmony_ci const sepol_context_t * record) 1476cd6a6acSopenharmony_ci{ 1486cd6a6acSopenharmony_ci 1496cd6a6acSopenharmony_ci context_struct_t *scontext = NULL; 1506cd6a6acSopenharmony_ci user_datum_t *usrdatum; 1516cd6a6acSopenharmony_ci role_datum_t *roldatum; 1526cd6a6acSopenharmony_ci type_datum_t *typdatum; 1536cd6a6acSopenharmony_ci 1546cd6a6acSopenharmony_ci /* Hashtab keys are not constant - suppress warnings */ 1556cd6a6acSopenharmony_ci char *user = strdup(sepol_context_get_user(record)); 1566cd6a6acSopenharmony_ci char *role = strdup(sepol_context_get_role(record)); 1576cd6a6acSopenharmony_ci char *type = strdup(sepol_context_get_type(record)); 1586cd6a6acSopenharmony_ci const char *mls = sepol_context_get_mls(record); 1596cd6a6acSopenharmony_ci 1606cd6a6acSopenharmony_ci scontext = (context_struct_t *) malloc(sizeof(context_struct_t)); 1616cd6a6acSopenharmony_ci if (!user || !role || !type || !scontext) { 1626cd6a6acSopenharmony_ci ERR(handle, "out of memory"); 1636cd6a6acSopenharmony_ci goto err; 1646cd6a6acSopenharmony_ci } 1656cd6a6acSopenharmony_ci context_init(scontext); 1666cd6a6acSopenharmony_ci 1676cd6a6acSopenharmony_ci /* User */ 1686cd6a6acSopenharmony_ci usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table, 1696cd6a6acSopenharmony_ci (hashtab_key_t) user); 1706cd6a6acSopenharmony_ci if (!usrdatum) { 1716cd6a6acSopenharmony_ci ERR(handle, "user %s is not defined", user); 1726cd6a6acSopenharmony_ci goto err_destroy; 1736cd6a6acSopenharmony_ci } 1746cd6a6acSopenharmony_ci scontext->user = usrdatum->s.value; 1756cd6a6acSopenharmony_ci 1766cd6a6acSopenharmony_ci /* Role */ 1776cd6a6acSopenharmony_ci roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table, 1786cd6a6acSopenharmony_ci (hashtab_key_t) role); 1796cd6a6acSopenharmony_ci if (!roldatum) { 1806cd6a6acSopenharmony_ci ERR(handle, "role %s is not defined", role); 1816cd6a6acSopenharmony_ci goto err_destroy; 1826cd6a6acSopenharmony_ci } 1836cd6a6acSopenharmony_ci scontext->role = roldatum->s.value; 1846cd6a6acSopenharmony_ci 1856cd6a6acSopenharmony_ci /* Type */ 1866cd6a6acSopenharmony_ci typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table, 1876cd6a6acSopenharmony_ci (hashtab_key_t) type); 1886cd6a6acSopenharmony_ci if (!typdatum || typdatum->flavor == TYPE_ATTRIB) { 1896cd6a6acSopenharmony_ci ERR(handle, "type %s is not defined", type); 1906cd6a6acSopenharmony_ci goto err_destroy; 1916cd6a6acSopenharmony_ci } 1926cd6a6acSopenharmony_ci scontext->type = typdatum->s.value; 1936cd6a6acSopenharmony_ci 1946cd6a6acSopenharmony_ci /* MLS */ 1956cd6a6acSopenharmony_ci if (mls && !policydb->mls) { 1966cd6a6acSopenharmony_ci ERR(handle, "MLS is disabled, but MLS context \"%s\" found", 1976cd6a6acSopenharmony_ci mls); 1986cd6a6acSopenharmony_ci goto err_destroy; 1996cd6a6acSopenharmony_ci } else if (!mls && policydb->mls) { 2006cd6a6acSopenharmony_ci ERR(handle, "MLS is enabled, but no MLS context found"); 2016cd6a6acSopenharmony_ci goto err_destroy; 2026cd6a6acSopenharmony_ci } 2036cd6a6acSopenharmony_ci if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0)) 2046cd6a6acSopenharmony_ci goto err_destroy; 2056cd6a6acSopenharmony_ci 2066cd6a6acSopenharmony_ci /* Validity check */ 2076cd6a6acSopenharmony_ci if (!context_is_valid(policydb, scontext)) { 2086cd6a6acSopenharmony_ci if (mls) { 2096cd6a6acSopenharmony_ci ERR(handle, 2106cd6a6acSopenharmony_ci "invalid security context: \"%s:%s:%s:%s\"", 2116cd6a6acSopenharmony_ci user, role, type, mls); 2126cd6a6acSopenharmony_ci } else { 2136cd6a6acSopenharmony_ci ERR(handle, 2146cd6a6acSopenharmony_ci "invalid security context: \"%s:%s:%s\"", 2156cd6a6acSopenharmony_ci user, role, type); 2166cd6a6acSopenharmony_ci } 2176cd6a6acSopenharmony_ci goto err_destroy; 2186cd6a6acSopenharmony_ci } 2196cd6a6acSopenharmony_ci 2206cd6a6acSopenharmony_ci *cptr = scontext; 2216cd6a6acSopenharmony_ci free(user); 2226cd6a6acSopenharmony_ci free(type); 2236cd6a6acSopenharmony_ci free(role); 2246cd6a6acSopenharmony_ci return STATUS_SUCCESS; 2256cd6a6acSopenharmony_ci 2266cd6a6acSopenharmony_ci err_destroy: 2276cd6a6acSopenharmony_ci errno = EINVAL; 2286cd6a6acSopenharmony_ci context_destroy(scontext); 2296cd6a6acSopenharmony_ci 2306cd6a6acSopenharmony_ci err: 2316cd6a6acSopenharmony_ci free(scontext); 2326cd6a6acSopenharmony_ci free(user); 2336cd6a6acSopenharmony_ci free(type); 2346cd6a6acSopenharmony_ci free(role); 2356cd6a6acSopenharmony_ci ERR(handle, "could not create context structure"); 2366cd6a6acSopenharmony_ci return STATUS_ERR; 2376cd6a6acSopenharmony_ci} 2386cd6a6acSopenharmony_ci 2396cd6a6acSopenharmony_ci/* 2406cd6a6acSopenharmony_ci * Create a record from the given context structure 2416cd6a6acSopenharmony_ci */ 2426cd6a6acSopenharmony_ciint context_to_record(sepol_handle_t * handle, 2436cd6a6acSopenharmony_ci const policydb_t * policydb, 2446cd6a6acSopenharmony_ci const context_struct_t * context, 2456cd6a6acSopenharmony_ci sepol_context_t ** record) 2466cd6a6acSopenharmony_ci{ 2476cd6a6acSopenharmony_ci 2486cd6a6acSopenharmony_ci sepol_context_t *tmp_record = NULL; 2496cd6a6acSopenharmony_ci char *mls = NULL; 2506cd6a6acSopenharmony_ci 2516cd6a6acSopenharmony_ci if (sepol_context_create(handle, &tmp_record) < 0) 2526cd6a6acSopenharmony_ci goto err; 2536cd6a6acSopenharmony_ci 2546cd6a6acSopenharmony_ci if (sepol_context_set_user(handle, tmp_record, 2556cd6a6acSopenharmony_ci policydb->p_user_val_to_name[context->user - 2566cd6a6acSopenharmony_ci 1]) < 0) 2576cd6a6acSopenharmony_ci goto err; 2586cd6a6acSopenharmony_ci 2596cd6a6acSopenharmony_ci if (sepol_context_set_role(handle, tmp_record, 2606cd6a6acSopenharmony_ci policydb->p_role_val_to_name[context->role - 2616cd6a6acSopenharmony_ci 1]) < 0) 2626cd6a6acSopenharmony_ci goto err; 2636cd6a6acSopenharmony_ci 2646cd6a6acSopenharmony_ci if (sepol_context_set_type(handle, tmp_record, 2656cd6a6acSopenharmony_ci policydb->p_type_val_to_name[context->type - 2666cd6a6acSopenharmony_ci 1]) < 0) 2676cd6a6acSopenharmony_ci goto err; 2686cd6a6acSopenharmony_ci 2696cd6a6acSopenharmony_ci if (policydb->mls) { 2706cd6a6acSopenharmony_ci if (mls_to_string(handle, policydb, context, &mls) < 0) 2716cd6a6acSopenharmony_ci goto err; 2726cd6a6acSopenharmony_ci 2736cd6a6acSopenharmony_ci if (sepol_context_set_mls(handle, tmp_record, mls) < 0) 2746cd6a6acSopenharmony_ci goto err; 2756cd6a6acSopenharmony_ci } 2766cd6a6acSopenharmony_ci 2776cd6a6acSopenharmony_ci free(mls); 2786cd6a6acSopenharmony_ci *record = tmp_record; 2796cd6a6acSopenharmony_ci return STATUS_SUCCESS; 2806cd6a6acSopenharmony_ci 2816cd6a6acSopenharmony_ci err: 2826cd6a6acSopenharmony_ci ERR(handle, "could not create context record"); 2836cd6a6acSopenharmony_ci sepol_context_free(tmp_record); 2846cd6a6acSopenharmony_ci free(mls); 2856cd6a6acSopenharmony_ci return STATUS_ERR; 2866cd6a6acSopenharmony_ci} 2876cd6a6acSopenharmony_ci 2886cd6a6acSopenharmony_ci/* 2896cd6a6acSopenharmony_ci * Create a context structure from the provided string. 2906cd6a6acSopenharmony_ci */ 2916cd6a6acSopenharmony_ciint context_from_string(sepol_handle_t * handle, 2926cd6a6acSopenharmony_ci const policydb_t * policydb, 2936cd6a6acSopenharmony_ci context_struct_t ** cptr, 2946cd6a6acSopenharmony_ci const char *con_str, size_t con_str_len) 2956cd6a6acSopenharmony_ci{ 2966cd6a6acSopenharmony_ci 2976cd6a6acSopenharmony_ci char *con_cpy = NULL; 2986cd6a6acSopenharmony_ci sepol_context_t *ctx_record = NULL; 2996cd6a6acSopenharmony_ci 3006cd6a6acSopenharmony_ci if (zero_or_saturated(con_str_len)) { 3016cd6a6acSopenharmony_ci ERR(handle, "Invalid context length"); 3026cd6a6acSopenharmony_ci goto err; 3036cd6a6acSopenharmony_ci } 3046cd6a6acSopenharmony_ci 3056cd6a6acSopenharmony_ci /* sepol_context_from_string expects a NULL-terminated string */ 3066cd6a6acSopenharmony_ci con_cpy = malloc(con_str_len + 1); 3076cd6a6acSopenharmony_ci if (!con_cpy) { 3086cd6a6acSopenharmony_ci ERR(handle, "out of memory"); 3096cd6a6acSopenharmony_ci goto err; 3106cd6a6acSopenharmony_ci } 3116cd6a6acSopenharmony_ci 3126cd6a6acSopenharmony_ci memcpy(con_cpy, con_str, con_str_len); 3136cd6a6acSopenharmony_ci con_cpy[con_str_len] = '\0'; 3146cd6a6acSopenharmony_ci 3156cd6a6acSopenharmony_ci if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0) 3166cd6a6acSopenharmony_ci goto err; 3176cd6a6acSopenharmony_ci 3186cd6a6acSopenharmony_ci /* Now create from the data structure */ 3196cd6a6acSopenharmony_ci if (context_from_record(handle, policydb, cptr, ctx_record) < 0) 3206cd6a6acSopenharmony_ci goto err; 3216cd6a6acSopenharmony_ci 3226cd6a6acSopenharmony_ci free(con_cpy); 3236cd6a6acSopenharmony_ci sepol_context_free(ctx_record); 3246cd6a6acSopenharmony_ci return STATUS_SUCCESS; 3256cd6a6acSopenharmony_ci 3266cd6a6acSopenharmony_ci err: 3276cd6a6acSopenharmony_ci ERR(handle, "could not create context structure"); 3286cd6a6acSopenharmony_ci free(con_cpy); 3296cd6a6acSopenharmony_ci sepol_context_free(ctx_record); 3306cd6a6acSopenharmony_ci return STATUS_ERR; 3316cd6a6acSopenharmony_ci} 3326cd6a6acSopenharmony_ci 3336cd6a6acSopenharmony_ciint sepol_context_check(sepol_handle_t * handle, 3346cd6a6acSopenharmony_ci const sepol_policydb_t * policydb, 3356cd6a6acSopenharmony_ci const sepol_context_t * context) 3366cd6a6acSopenharmony_ci{ 3376cd6a6acSopenharmony_ci 3386cd6a6acSopenharmony_ci context_struct_t *con = NULL; 3396cd6a6acSopenharmony_ci int ret = context_from_record(handle, &policydb->p, &con, context); 3406cd6a6acSopenharmony_ci context_destroy(con); 3416cd6a6acSopenharmony_ci free(con); 3426cd6a6acSopenharmony_ci return ret; 3436cd6a6acSopenharmony_ci} 344