Home | History | Annotate | Download | only in src
      1 #include <stdlib.h>
      2 #include <string.h>
      3 #include <errno.h>
      4 
      5 #include <sepol/policydb/policydb.h>
      6 #include <sepol/policydb/services.h>
      7 #include "context_internal.h"
      8 
      9 #include "debug.h"
     10 #include "context.h"
     11 #include "handle.h"
     12 #include "mls.h"
     13 
     14 /* ----- Compatibility ---- */
     15 int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c)
     16 {
     17 
     18 	return context_is_valid(p, c);
     19 }
     20 
     21 int sepol_check_context(const char *context)
     22 {
     23 
     24 	return sepol_context_to_sid((const sepol_security_context_t)context,
     25 				    strlen(context) + 1, NULL);
     26 }
     27 
     28 /* ---- End compatibility --- */
     29 
     30 /*
     31  * Return 1 if the fields in the security context
     32  * structure `c' are valid.  Return 0 otherwise.
     33  */
     34 int context_is_valid(const policydb_t * p, const context_struct_t * c)
     35 {
     36 
     37 	role_datum_t *role;
     38 	user_datum_t *usrdatum;
     39 	ebitmap_t types, roles;
     40 	int ret = 1;
     41 
     42 	ebitmap_init(&types);
     43 	ebitmap_init(&roles);
     44 	if (!c->role || c->role > p->p_roles.nprim)
     45 		return 0;
     46 
     47 	if (!c->user || c->user > p->p_users.nprim)
     48 		return 0;
     49 
     50 	if (!c->type || c->type > p->p_types.nprim)
     51 		return 0;
     52 
     53 	if (c->role != OBJECT_R_VAL) {
     54 		/*
     55 		 * Role must be authorized for the type.
     56 		 */
     57 		role = p->role_val_to_struct[c->role - 1];
     58 		if (!ebitmap_get_bit(&role->cache, c->type - 1))
     59 			/* role may not be associated with type */
     60 			return 0;
     61 
     62 		/*
     63 		 * User must be authorized for the role.
     64 		 */
     65 		usrdatum = p->user_val_to_struct[c->user - 1];
     66 		if (!usrdatum)
     67 			return 0;
     68 
     69 		if (!ebitmap_get_bit(&usrdatum->cache, c->role - 1))
     70 			/* user may not be associated with role */
     71 			return 0;
     72 	}
     73 
     74 	if (!mls_context_isvalid(p, c))
     75 		return 0;
     76 
     77 	return ret;
     78 }
     79 
     80 /*
     81  * Write the security context string representation of
     82  * the context structure `context' into a dynamically
     83  * allocated string of the correct size.  Set `*scontext'
     84  * to point to this string and set `*scontext_len' to
     85  * the length of the string.
     86  */
     87 int context_to_string(sepol_handle_t * handle,
     88 		      const policydb_t * policydb,
     89 		      const context_struct_t * context,
     90 		      char **result, size_t * result_len)
     91 {
     92 
     93 	char *scontext = NULL;
     94 	size_t scontext_len = 0;
     95 	char *ptr;
     96 
     97 	/* Compute the size of the context. */
     98 	scontext_len +=
     99 	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1;
    100 	scontext_len +=
    101 	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1;
    102 	scontext_len += strlen(policydb->p_type_val_to_name[context->type - 1]);
    103 	scontext_len += mls_compute_context_len(policydb, context);
    104 
    105 	/* We must null terminate the string */
    106 	scontext_len += 1;
    107 
    108 	/* Allocate space for the context; caller must free this space. */
    109 	scontext = malloc(scontext_len);
    110 	if (!scontext)
    111 		goto omem;
    112 	scontext[scontext_len - 1] = '\0';
    113 
    114 	/*
    115 	 * Copy the user name, role name and type name into the context.
    116 	 */
    117 	ptr = scontext;
    118 	sprintf(ptr, "%s:%s:%s",
    119 		policydb->p_user_val_to_name[context->user - 1],
    120 		policydb->p_role_val_to_name[context->role - 1],
    121 		policydb->p_type_val_to_name[context->type - 1]);
    122 
    123 	ptr +=
    124 	    strlen(policydb->p_user_val_to_name[context->user - 1]) + 1 +
    125 	    strlen(policydb->p_role_val_to_name[context->role - 1]) + 1 +
    126 	    strlen(policydb->p_type_val_to_name[context->type - 1]);
    127 
    128 	mls_sid_to_context(policydb, context, &ptr);
    129 
    130 	*result = scontext;
    131 	*result_len = scontext_len;
    132 	return STATUS_SUCCESS;
    133 
    134       omem:
    135 	ERR(handle, "out of memory, could not convert " "context to string");
    136 	free(scontext);
    137 	return STATUS_ERR;
    138 }
    139 
    140 /*
    141  * Create a context structure from the given record
    142  */
    143 int context_from_record(sepol_handle_t * handle,
    144 			const policydb_t * policydb,
    145 			context_struct_t ** cptr,
    146 			const sepol_context_t * record)
    147 {
    148 
    149 	context_struct_t *scontext = NULL;
    150 	user_datum_t *usrdatum;
    151 	role_datum_t *roldatum;
    152 	type_datum_t *typdatum;
    153 
    154 	/* Hashtab keys are not constant - suppress warnings */
    155 	char *user = strdup(sepol_context_get_user(record));
    156 	char *role = strdup(sepol_context_get_role(record));
    157 	char *type = strdup(sepol_context_get_type(record));
    158 	const char *mls = sepol_context_get_mls(record);
    159 
    160 	scontext = (context_struct_t *) malloc(sizeof(context_struct_t));
    161 	if (!user || !role || !type || !scontext) {
    162 		ERR(handle, "out of memory");
    163 		goto err;
    164 	}
    165 	context_init(scontext);
    166 
    167 	/* User */
    168 	usrdatum = (user_datum_t *) hashtab_search(policydb->p_users.table,
    169 						   (hashtab_key_t) user);
    170 	if (!usrdatum) {
    171 		ERR(handle, "user %s is not defined", user);
    172 		goto err_destroy;
    173 	}
    174 	scontext->user = usrdatum->s.value;
    175 
    176 	/* Role */
    177 	roldatum = (role_datum_t *) hashtab_search(policydb->p_roles.table,
    178 						   (hashtab_key_t) role);
    179 	if (!roldatum) {
    180 		ERR(handle, "role %s is not defined", role);
    181 		goto err_destroy;
    182 	}
    183 	scontext->role = roldatum->s.value;
    184 
    185 	/* Type */
    186 	typdatum = (type_datum_t *) hashtab_search(policydb->p_types.table,
    187 						   (hashtab_key_t) type);
    188 	if (!typdatum || typdatum->flavor == TYPE_ATTRIB) {
    189 		ERR(handle, "type %s is not defined", type);
    190 		goto err_destroy;
    191 	}
    192 	scontext->type = typdatum->s.value;
    193 
    194 	/* MLS */
    195 	if (mls && !policydb->mls) {
    196 		ERR(handle, "MLS is disabled, but MLS context \"%s\" found",
    197 		    mls);
    198 		goto err_destroy;
    199 	} else if (!mls && policydb->mls) {
    200 		ERR(handle, "MLS is enabled, but no MLS context found");
    201 		goto err_destroy;
    202 	}
    203 	if (mls && (mls_from_string(handle, policydb, mls, scontext) < 0))
    204 		goto err_destroy;
    205 
    206 	/* Validity check */
    207 	if (!context_is_valid(policydb, scontext)) {
    208 		if (mls) {
    209 			ERR(handle,
    210 			    "invalid security context: \"%s:%s:%s:%s\"",
    211 			    user, role, type, mls);
    212 		} else {
    213 			ERR(handle,
    214 			    "invalid security context: \"%s:%s:%s\"",
    215 			    user, role, type);
    216 		}
    217 		goto err_destroy;
    218 	}
    219 
    220 	*cptr = scontext;
    221 	free(user);
    222 	free(type);
    223 	free(role);
    224 	return STATUS_SUCCESS;
    225 
    226       err_destroy:
    227 	errno = EINVAL;
    228 	context_destroy(scontext);
    229 
    230       err:
    231 	free(scontext);
    232 	free(user);
    233 	free(type);
    234 	free(role);
    235 	ERR(handle, "could not create context structure");
    236 	return STATUS_ERR;
    237 }
    238 
    239 /*
    240  * Create a record from the given context structure
    241  */
    242 int context_to_record(sepol_handle_t * handle,
    243 		      const policydb_t * policydb,
    244 		      const context_struct_t * context,
    245 		      sepol_context_t ** record)
    246 {
    247 
    248 	sepol_context_t *tmp_record = NULL;
    249 	char *mls = NULL;
    250 
    251 	if (sepol_context_create(handle, &tmp_record) < 0)
    252 		goto err;
    253 
    254 	if (sepol_context_set_user(handle, tmp_record,
    255 				   policydb->p_user_val_to_name[context->user -
    256 								1]) < 0)
    257 		goto err;
    258 
    259 	if (sepol_context_set_role(handle, tmp_record,
    260 				   policydb->p_role_val_to_name[context->role -
    261 								1]) < 0)
    262 		goto err;
    263 
    264 	if (sepol_context_set_type(handle, tmp_record,
    265 				   policydb->p_type_val_to_name[context->type -
    266 								1]) < 0)
    267 		goto err;
    268 
    269 	if (policydb->mls) {
    270 		if (mls_to_string(handle, policydb, context, &mls) < 0)
    271 			goto err;
    272 
    273 		if (sepol_context_set_mls(handle, tmp_record, mls) < 0)
    274 			goto err;
    275 	}
    276 
    277 	free(mls);
    278 	*record = tmp_record;
    279 	return STATUS_SUCCESS;
    280 
    281       err:
    282 	ERR(handle, "could not create context record");
    283 	sepol_context_free(tmp_record);
    284 	free(mls);
    285 	return STATUS_ERR;
    286 }
    287 
    288 /*
    289  * Create a context structure from the provided string.
    290  */
    291 int context_from_string(sepol_handle_t * handle,
    292 			const policydb_t * policydb,
    293 			context_struct_t ** cptr,
    294 			const char *con_str, size_t con_str_len)
    295 {
    296 
    297 	char *con_cpy = NULL;
    298 	sepol_context_t *ctx_record = NULL;
    299 
    300 	/* sepol_context_from_string expects a NULL-terminated string */
    301 	con_cpy = malloc(con_str_len + 1);
    302 	if (!con_cpy)
    303 		goto omem;
    304 	memcpy(con_cpy, con_str, con_str_len);
    305 	con_cpy[con_str_len] = '\0';
    306 
    307 	if (sepol_context_from_string(handle, con_cpy, &ctx_record) < 0)
    308 		goto err;
    309 
    310 	/* Now create from the data structure */
    311 	if (context_from_record(handle, policydb, cptr, ctx_record) < 0)
    312 		goto err;
    313 
    314 	free(con_cpy);
    315 	sepol_context_free(ctx_record);
    316 	return STATUS_SUCCESS;
    317 
    318       omem:
    319 	ERR(handle, "out of memory");
    320 
    321       err:
    322 	ERR(handle, "could not create context structure");
    323 	free(con_cpy);
    324 	sepol_context_free(ctx_record);
    325 	return STATUS_ERR;
    326 }
    327 
    328 int sepol_context_check(sepol_handle_t * handle,
    329 			const sepol_policydb_t * policydb,
    330 			const sepol_context_t * context)
    331 {
    332 
    333 	context_struct_t *con = NULL;
    334 	int ret = context_from_record(handle, &policydb->p, &con, context);
    335 	context_destroy(con);
    336 	free(con);
    337 	return ret;
    338 }
    339