| #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" | 
 | #include "private.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 (!role || !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; | 
 |  | 
 | 	if (zero_or_saturated(con_str_len)) { | 
 | 		ERR(handle, "Invalid context length"); | 
 | 		goto err; | 
 | 	} | 
 |  | 
 | 	/* sepol_context_from_string expects a NULL-terminated string */ | 
 | 	con_cpy = malloc(con_str_len + 1); | 
 | 	if (!con_cpy) { | 
 | 		ERR(handle, "out of memory"); | 
 | 		goto err; | 
 | 	} | 
 |  | 
 | 	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; | 
 |  | 
 |       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; | 
 | } |