xref: /third_party/selinux/libsepol/src/mls.c (revision 6cd6a6ac)
16cd6a6acSopenharmony_ci/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
26cd6a6acSopenharmony_ci/*
36cd6a6acSopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
46cd6a6acSopenharmony_ci *
56cd6a6acSopenharmony_ci *	Support for enhanced MLS infrastructure.
66cd6a6acSopenharmony_ci *
76cd6a6acSopenharmony_ci * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
86cd6a6acSopenharmony_ci *
96cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
106cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
116cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
126cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
136cd6a6acSopenharmony_ci *
146cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
156cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
166cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
176cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
186cd6a6acSopenharmony_ci *
196cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
206cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
216cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
226cd6a6acSopenharmony_ci */
236cd6a6acSopenharmony_ci
246cd6a6acSopenharmony_ci/* FLASK */
256cd6a6acSopenharmony_ci
266cd6a6acSopenharmony_ci/*
276cd6a6acSopenharmony_ci * Implementation of the multi-level security (MLS) policy.
286cd6a6acSopenharmony_ci */
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci#include <sepol/context.h>
316cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
326cd6a6acSopenharmony_ci#include <sepol/policydb/services.h>
336cd6a6acSopenharmony_ci#include <sepol/policydb/context.h>
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci#include <stdlib.h>
366cd6a6acSopenharmony_ci
376cd6a6acSopenharmony_ci#include "handle.h"
386cd6a6acSopenharmony_ci#include "debug.h"
396cd6a6acSopenharmony_ci#include "private.h"
406cd6a6acSopenharmony_ci#include "mls.h"
416cd6a6acSopenharmony_ci
426cd6a6acSopenharmony_ciint mls_to_string(sepol_handle_t * handle,
436cd6a6acSopenharmony_ci		  const policydb_t * policydb,
446cd6a6acSopenharmony_ci		  const context_struct_t * mls, char **str)
456cd6a6acSopenharmony_ci{
466cd6a6acSopenharmony_ci
476cd6a6acSopenharmony_ci	char *ptr = NULL, *ptr2 = NULL;
486cd6a6acSopenharmony_ci
496cd6a6acSopenharmony_ci	/* Temporary buffer - length + NULL terminator */
506cd6a6acSopenharmony_ci	int len = mls_compute_context_len(policydb, mls) + 1;
516cd6a6acSopenharmony_ci
526cd6a6acSopenharmony_ci	ptr = (char *)malloc(len);
536cd6a6acSopenharmony_ci	if (ptr == NULL)
546cd6a6acSopenharmony_ci		goto omem;
556cd6a6acSopenharmony_ci
566cd6a6acSopenharmony_ci	/* Final string w/ ':' cut off */
576cd6a6acSopenharmony_ci	ptr2 = (char *)malloc(len - 1);
586cd6a6acSopenharmony_ci	if (ptr2 == NULL)
596cd6a6acSopenharmony_ci		goto omem;
606cd6a6acSopenharmony_ci
616cd6a6acSopenharmony_ci	mls_sid_to_context(policydb, mls, &ptr);
626cd6a6acSopenharmony_ci	ptr -= len - 1;
636cd6a6acSopenharmony_ci	strcpy(ptr2, ptr + 1);
646cd6a6acSopenharmony_ci
656cd6a6acSopenharmony_ci	free(ptr);
666cd6a6acSopenharmony_ci	*str = ptr2;
676cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
686cd6a6acSopenharmony_ci
696cd6a6acSopenharmony_ci      omem:
706cd6a6acSopenharmony_ci	ERR(handle, "out of memory, could not convert mls context to string");
716cd6a6acSopenharmony_ci
726cd6a6acSopenharmony_ci	free(ptr);
736cd6a6acSopenharmony_ci	free(ptr2);
746cd6a6acSopenharmony_ci	return STATUS_ERR;
756cd6a6acSopenharmony_ci
766cd6a6acSopenharmony_ci}
776cd6a6acSopenharmony_ci
786cd6a6acSopenharmony_ciint mls_from_string(sepol_handle_t * handle,
796cd6a6acSopenharmony_ci		    const policydb_t * policydb,
806cd6a6acSopenharmony_ci		    const char *str, context_struct_t * mls)
816cd6a6acSopenharmony_ci{
826cd6a6acSopenharmony_ci
836cd6a6acSopenharmony_ci	char *tmp = strdup(str);
846cd6a6acSopenharmony_ci	char *tmp_cp = tmp;
856cd6a6acSopenharmony_ci	if (!tmp)
866cd6a6acSopenharmony_ci		goto omem;
876cd6a6acSopenharmony_ci
886cd6a6acSopenharmony_ci	if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
896cd6a6acSopenharmony_ci		ERR(handle, "invalid MLS context %s", str);
906cd6a6acSopenharmony_ci		free(tmp);
916cd6a6acSopenharmony_ci		goto err;
926cd6a6acSopenharmony_ci	}
936cd6a6acSopenharmony_ci
946cd6a6acSopenharmony_ci	free(tmp);
956cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
966cd6a6acSopenharmony_ci
976cd6a6acSopenharmony_ci      omem:
986cd6a6acSopenharmony_ci	ERR(handle, "out of memory");
996cd6a6acSopenharmony_ci
1006cd6a6acSopenharmony_ci      err:
1016cd6a6acSopenharmony_ci	ERR(handle, "could not construct mls context structure");
1026cd6a6acSopenharmony_ci	return STATUS_ERR;
1036cd6a6acSopenharmony_ci}
1046cd6a6acSopenharmony_ci
1056cd6a6acSopenharmony_ci/*
1066cd6a6acSopenharmony_ci * Return the length in bytes for the MLS fields of the
1076cd6a6acSopenharmony_ci * security context string representation of `context'.
1086cd6a6acSopenharmony_ci */
1096cd6a6acSopenharmony_ciint mls_compute_context_len(const policydb_t * policydb,
1106cd6a6acSopenharmony_ci			    const context_struct_t * context)
1116cd6a6acSopenharmony_ci{
1126cd6a6acSopenharmony_ci
1136cd6a6acSopenharmony_ci	unsigned int i, l, len, range;
1146cd6a6acSopenharmony_ci	ebitmap_node_t *cnode;
1156cd6a6acSopenharmony_ci
1166cd6a6acSopenharmony_ci	if (!policydb->mls)
1176cd6a6acSopenharmony_ci		return 0;
1186cd6a6acSopenharmony_ci
1196cd6a6acSopenharmony_ci	len = 1;		/* for the beginning ":" */
1206cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
1216cd6a6acSopenharmony_ci		range = 0;
1226cd6a6acSopenharmony_ci		len +=
1236cd6a6acSopenharmony_ci		    strlen(policydb->
1246cd6a6acSopenharmony_ci			   p_sens_val_to_name[context->range.level[l].sens -
1256cd6a6acSopenharmony_ci					      1]);
1266cd6a6acSopenharmony_ci
1276cd6a6acSopenharmony_ci		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
1286cd6a6acSopenharmony_ci			if (ebitmap_node_get_bit(cnode, i)) {
1296cd6a6acSopenharmony_ci				if (range) {
1306cd6a6acSopenharmony_ci					range++;
1316cd6a6acSopenharmony_ci					continue;
1326cd6a6acSopenharmony_ci				}
1336cd6a6acSopenharmony_ci
1346cd6a6acSopenharmony_ci				len +=
1356cd6a6acSopenharmony_ci				    strlen(policydb->p_cat_val_to_name[i]) + 1;
1366cd6a6acSopenharmony_ci				range++;
1376cd6a6acSopenharmony_ci			} else {
1386cd6a6acSopenharmony_ci				if (range > 1)
1396cd6a6acSopenharmony_ci					len +=
1406cd6a6acSopenharmony_ci					    strlen(policydb->
1416cd6a6acSopenharmony_ci						   p_cat_val_to_name[i - 1]) +
1426cd6a6acSopenharmony_ci					    1;
1436cd6a6acSopenharmony_ci				range = 0;
1446cd6a6acSopenharmony_ci			}
1456cd6a6acSopenharmony_ci		}
1466cd6a6acSopenharmony_ci		/* Handle case where last category is the end of range */
1476cd6a6acSopenharmony_ci		if (range > 1)
1486cd6a6acSopenharmony_ci			len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
1496cd6a6acSopenharmony_ci
1506cd6a6acSopenharmony_ci		if (l == 0) {
1516cd6a6acSopenharmony_ci			if (mls_level_eq(&context->range.level[0],
1526cd6a6acSopenharmony_ci					 &context->range.level[1]))
1536cd6a6acSopenharmony_ci				break;
1546cd6a6acSopenharmony_ci			else
1556cd6a6acSopenharmony_ci				len++;
1566cd6a6acSopenharmony_ci		}
1576cd6a6acSopenharmony_ci	}
1586cd6a6acSopenharmony_ci
1596cd6a6acSopenharmony_ci	return len;
1606cd6a6acSopenharmony_ci}
1616cd6a6acSopenharmony_ci
1626cd6a6acSopenharmony_ci/*
1636cd6a6acSopenharmony_ci * Write the security context string representation of
1646cd6a6acSopenharmony_ci * the MLS fields of `context' into the string `*scontext'.
1656cd6a6acSopenharmony_ci * Update `*scontext' to point to the end of the MLS fields.
1666cd6a6acSopenharmony_ci */
1676cd6a6acSopenharmony_civoid mls_sid_to_context(const policydb_t * policydb,
1686cd6a6acSopenharmony_ci			const context_struct_t * context, char **scontext)
1696cd6a6acSopenharmony_ci{
1706cd6a6acSopenharmony_ci
1716cd6a6acSopenharmony_ci	char *scontextp;
1726cd6a6acSopenharmony_ci	unsigned int i, l, range, wrote_sep;
1736cd6a6acSopenharmony_ci	ebitmap_node_t *cnode;
1746cd6a6acSopenharmony_ci
1756cd6a6acSopenharmony_ci	if (!policydb->mls)
1766cd6a6acSopenharmony_ci		return;
1776cd6a6acSopenharmony_ci
1786cd6a6acSopenharmony_ci	scontextp = *scontext;
1796cd6a6acSopenharmony_ci
1806cd6a6acSopenharmony_ci	*scontextp = ':';
1816cd6a6acSopenharmony_ci	scontextp++;
1826cd6a6acSopenharmony_ci
1836cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
1846cd6a6acSopenharmony_ci		range = 0;
1856cd6a6acSopenharmony_ci		wrote_sep = 0;
1866cd6a6acSopenharmony_ci		strcpy(scontextp,
1876cd6a6acSopenharmony_ci		       policydb->p_sens_val_to_name[context->range.level[l].
1886cd6a6acSopenharmony_ci						    sens - 1]);
1896cd6a6acSopenharmony_ci		scontextp +=
1906cd6a6acSopenharmony_ci		    strlen(policydb->
1916cd6a6acSopenharmony_ci			   p_sens_val_to_name[context->range.level[l].sens -
1926cd6a6acSopenharmony_ci					      1]);
1936cd6a6acSopenharmony_ci		/* categories */
1946cd6a6acSopenharmony_ci		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
1956cd6a6acSopenharmony_ci			if (ebitmap_node_get_bit(cnode, i)) {
1966cd6a6acSopenharmony_ci				if (range) {
1976cd6a6acSopenharmony_ci					range++;
1986cd6a6acSopenharmony_ci					continue;
1996cd6a6acSopenharmony_ci				}
2006cd6a6acSopenharmony_ci
2016cd6a6acSopenharmony_ci				if (!wrote_sep) {
2026cd6a6acSopenharmony_ci					*scontextp++ = ':';
2036cd6a6acSopenharmony_ci					wrote_sep = 1;
2046cd6a6acSopenharmony_ci				} else
2056cd6a6acSopenharmony_ci					*scontextp++ = ',';
2066cd6a6acSopenharmony_ci				strcpy(scontextp,
2076cd6a6acSopenharmony_ci				       policydb->p_cat_val_to_name[i]);
2086cd6a6acSopenharmony_ci				scontextp +=
2096cd6a6acSopenharmony_ci				    strlen(policydb->p_cat_val_to_name[i]);
2106cd6a6acSopenharmony_ci				range++;
2116cd6a6acSopenharmony_ci			} else {
2126cd6a6acSopenharmony_ci				if (range > 1) {
2136cd6a6acSopenharmony_ci					if (range > 2)
2146cd6a6acSopenharmony_ci						*scontextp++ = '.';
2156cd6a6acSopenharmony_ci					else
2166cd6a6acSopenharmony_ci						*scontextp++ = ',';
2176cd6a6acSopenharmony_ci
2186cd6a6acSopenharmony_ci					strcpy(scontextp,
2196cd6a6acSopenharmony_ci					       policydb->p_cat_val_to_name[i -
2206cd6a6acSopenharmony_ci									   1]);
2216cd6a6acSopenharmony_ci					scontextp +=
2226cd6a6acSopenharmony_ci					    strlen(policydb->
2236cd6a6acSopenharmony_ci						   p_cat_val_to_name[i - 1]);
2246cd6a6acSopenharmony_ci				}
2256cd6a6acSopenharmony_ci				range = 0;
2266cd6a6acSopenharmony_ci			}
2276cd6a6acSopenharmony_ci		}
2286cd6a6acSopenharmony_ci		/* Handle case where last category is the end of range */
2296cd6a6acSopenharmony_ci		if (range > 1) {
2306cd6a6acSopenharmony_ci			if (range > 2)
2316cd6a6acSopenharmony_ci				*scontextp++ = '.';
2326cd6a6acSopenharmony_ci			else
2336cd6a6acSopenharmony_ci				*scontextp++ = ',';
2346cd6a6acSopenharmony_ci
2356cd6a6acSopenharmony_ci			strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
2366cd6a6acSopenharmony_ci			scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
2376cd6a6acSopenharmony_ci		}
2386cd6a6acSopenharmony_ci
2396cd6a6acSopenharmony_ci		if (l == 0) {
2406cd6a6acSopenharmony_ci			if (mls_level_eq(&context->range.level[0],
2416cd6a6acSopenharmony_ci					 &context->range.level[1]))
2426cd6a6acSopenharmony_ci				break;
2436cd6a6acSopenharmony_ci			else {
2446cd6a6acSopenharmony_ci				*scontextp = '-';
2456cd6a6acSopenharmony_ci				scontextp++;
2466cd6a6acSopenharmony_ci			}
2476cd6a6acSopenharmony_ci		}
2486cd6a6acSopenharmony_ci	}
2496cd6a6acSopenharmony_ci
2506cd6a6acSopenharmony_ci	*scontext = scontextp;
2516cd6a6acSopenharmony_ci	return;
2526cd6a6acSopenharmony_ci}
2536cd6a6acSopenharmony_ci
2546cd6a6acSopenharmony_ci/*
2556cd6a6acSopenharmony_ci * Return 1 if the MLS fields in the security context
2566cd6a6acSopenharmony_ci * structure `c' are valid.  Return 0 otherwise.
2576cd6a6acSopenharmony_ci */
2586cd6a6acSopenharmony_ciint mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
2596cd6a6acSopenharmony_ci{
2606cd6a6acSopenharmony_ci
2616cd6a6acSopenharmony_ci	level_datum_t *levdatum;
2626cd6a6acSopenharmony_ci	user_datum_t *usrdatum;
2636cd6a6acSopenharmony_ci	unsigned int i, l;
2646cd6a6acSopenharmony_ci	ebitmap_node_t *cnode;
2656cd6a6acSopenharmony_ci	hashtab_key_t key;
2666cd6a6acSopenharmony_ci
2676cd6a6acSopenharmony_ci	if (!p->mls)
2686cd6a6acSopenharmony_ci		return 1;
2696cd6a6acSopenharmony_ci
2706cd6a6acSopenharmony_ci	/*
2716cd6a6acSopenharmony_ci	 * MLS range validity checks: high must dominate low, low level must
2726cd6a6acSopenharmony_ci	 * be valid (category set <-> sensitivity check), and high level must
2736cd6a6acSopenharmony_ci	 * be valid (category set <-> sensitivity check)
2746cd6a6acSopenharmony_ci	 */
2756cd6a6acSopenharmony_ci	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
2766cd6a6acSopenharmony_ci		/* High does not dominate low. */
2776cd6a6acSopenharmony_ci		return 0;
2786cd6a6acSopenharmony_ci
2796cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
2806cd6a6acSopenharmony_ci		if (!c->range.level[l].sens
2816cd6a6acSopenharmony_ci		    || c->range.level[l].sens > p->p_levels.nprim)
2826cd6a6acSopenharmony_ci			return 0;
2836cd6a6acSopenharmony_ci
2846cd6a6acSopenharmony_ci		key = p->p_sens_val_to_name[c->range.level[l].sens - 1];
2856cd6a6acSopenharmony_ci		if (!key)
2866cd6a6acSopenharmony_ci			return 0;
2876cd6a6acSopenharmony_ci
2886cd6a6acSopenharmony_ci		levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, key);
2896cd6a6acSopenharmony_ci		if (!levdatum)
2906cd6a6acSopenharmony_ci			return 0;
2916cd6a6acSopenharmony_ci
2926cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(&c->range.level[l].cat, cnode, i) {
2936cd6a6acSopenharmony_ci			if (i > p->p_cats.nprim)
2946cd6a6acSopenharmony_ci				return 0;
2956cd6a6acSopenharmony_ci			if (!ebitmap_get_bit(&levdatum->level->cat, i))
2966cd6a6acSopenharmony_ci				/*
2976cd6a6acSopenharmony_ci				 * Category may not be associated with
2986cd6a6acSopenharmony_ci				 * sensitivity in low level.
2996cd6a6acSopenharmony_ci				 */
3006cd6a6acSopenharmony_ci				return 0;
3016cd6a6acSopenharmony_ci		}
3026cd6a6acSopenharmony_ci	}
3036cd6a6acSopenharmony_ci
3046cd6a6acSopenharmony_ci	if (c->role == OBJECT_R_VAL)
3056cd6a6acSopenharmony_ci		return 1;
3066cd6a6acSopenharmony_ci
3076cd6a6acSopenharmony_ci	/*
3086cd6a6acSopenharmony_ci	 * User must be authorized for the MLS range.
3096cd6a6acSopenharmony_ci	 */
3106cd6a6acSopenharmony_ci	if (!c->user || c->user > p->p_users.nprim)
3116cd6a6acSopenharmony_ci		return 0;
3126cd6a6acSopenharmony_ci	usrdatum = p->user_val_to_struct[c->user - 1];
3136cd6a6acSopenharmony_ci	if (!usrdatum || !mls_range_contains(usrdatum->exp_range, c->range))
3146cd6a6acSopenharmony_ci		return 0;	/* user may not be associated with range */
3156cd6a6acSopenharmony_ci
3166cd6a6acSopenharmony_ci	return 1;
3176cd6a6acSopenharmony_ci}
3186cd6a6acSopenharmony_ci
3196cd6a6acSopenharmony_ci/*
3206cd6a6acSopenharmony_ci * Set the MLS fields in the security context structure
3216cd6a6acSopenharmony_ci * `context' based on the string representation in
3226cd6a6acSopenharmony_ci * the string `*scontext'.  Update `*scontext' to
3236cd6a6acSopenharmony_ci * point to the end of the string representation of
3246cd6a6acSopenharmony_ci * the MLS fields.
3256cd6a6acSopenharmony_ci *
3266cd6a6acSopenharmony_ci * This function modifies the string in place, inserting
3276cd6a6acSopenharmony_ci * NULL characters to terminate the MLS fields.
3286cd6a6acSopenharmony_ci */
3296cd6a6acSopenharmony_ciint mls_context_to_sid(const policydb_t * policydb,
3306cd6a6acSopenharmony_ci		       char oldc, char **scontext, context_struct_t * context)
3316cd6a6acSopenharmony_ci{
3326cd6a6acSopenharmony_ci
3336cd6a6acSopenharmony_ci	char delim;
3346cd6a6acSopenharmony_ci	char *scontextp, *p, *rngptr;
3356cd6a6acSopenharmony_ci	level_datum_t *levdatum;
3366cd6a6acSopenharmony_ci	cat_datum_t *catdatum, *rngdatum;
3376cd6a6acSopenharmony_ci	unsigned int l;
3386cd6a6acSopenharmony_ci
3396cd6a6acSopenharmony_ci	if (!policydb->mls)
3406cd6a6acSopenharmony_ci		return 0;
3416cd6a6acSopenharmony_ci
3426cd6a6acSopenharmony_ci	/* No MLS component to the security context */
3436cd6a6acSopenharmony_ci	if (!oldc)
3446cd6a6acSopenharmony_ci		goto err;
3456cd6a6acSopenharmony_ci
3466cd6a6acSopenharmony_ci	/* Extract low sensitivity. */
3476cd6a6acSopenharmony_ci	scontextp = p = *scontext;
3486cd6a6acSopenharmony_ci	while (*p && *p != ':' && *p != '-')
3496cd6a6acSopenharmony_ci		p++;
3506cd6a6acSopenharmony_ci
3516cd6a6acSopenharmony_ci	delim = *p;
3526cd6a6acSopenharmony_ci	if (delim != 0)
3536cd6a6acSopenharmony_ci		*p++ = 0;
3546cd6a6acSopenharmony_ci
3556cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
3566cd6a6acSopenharmony_ci		levdatum =
3576cd6a6acSopenharmony_ci		    (level_datum_t *) hashtab_search(policydb->p_levels.table,
3586cd6a6acSopenharmony_ci						     (hashtab_key_t) scontextp);
3596cd6a6acSopenharmony_ci
3606cd6a6acSopenharmony_ci		if (!levdatum)
3616cd6a6acSopenharmony_ci			goto err;
3626cd6a6acSopenharmony_ci
3636cd6a6acSopenharmony_ci		context->range.level[l].sens = levdatum->level->sens;
3646cd6a6acSopenharmony_ci
3656cd6a6acSopenharmony_ci		if (delim == ':') {
3666cd6a6acSopenharmony_ci			/* Extract category set. */
3676cd6a6acSopenharmony_ci			while (1) {
3686cd6a6acSopenharmony_ci				scontextp = p;
3696cd6a6acSopenharmony_ci				while (*p && *p != ',' && *p != '-')
3706cd6a6acSopenharmony_ci					p++;
3716cd6a6acSopenharmony_ci				delim = *p;
3726cd6a6acSopenharmony_ci				if (delim != 0)
3736cd6a6acSopenharmony_ci					*p++ = 0;
3746cd6a6acSopenharmony_ci
3756cd6a6acSopenharmony_ci				/* Separate into range if exists */
3766cd6a6acSopenharmony_ci				if ((rngptr = strchr(scontextp, '.')) != NULL) {
3776cd6a6acSopenharmony_ci					/* Remove '.' */
3786cd6a6acSopenharmony_ci					*rngptr++ = 0;
3796cd6a6acSopenharmony_ci				}
3806cd6a6acSopenharmony_ci
3816cd6a6acSopenharmony_ci				catdatum =
3826cd6a6acSopenharmony_ci				    (cat_datum_t *) hashtab_search(policydb->
3836cd6a6acSopenharmony_ci								   p_cats.table,
3846cd6a6acSopenharmony_ci								   (hashtab_key_t)
3856cd6a6acSopenharmony_ci								   scontextp);
3866cd6a6acSopenharmony_ci				if (!catdatum)
3876cd6a6acSopenharmony_ci					goto err;
3886cd6a6acSopenharmony_ci
3896cd6a6acSopenharmony_ci				if (ebitmap_set_bit
3906cd6a6acSopenharmony_ci				    (&context->range.level[l].cat,
3916cd6a6acSopenharmony_ci				     catdatum->s.value - 1, 1))
3926cd6a6acSopenharmony_ci					goto err;
3936cd6a6acSopenharmony_ci
3946cd6a6acSopenharmony_ci				/* If range, set all categories in range */
3956cd6a6acSopenharmony_ci				if (rngptr) {
3966cd6a6acSopenharmony_ci					unsigned int i;
3976cd6a6acSopenharmony_ci
3986cd6a6acSopenharmony_ci					rngdatum = (cat_datum_t *)
3996cd6a6acSopenharmony_ci					    hashtab_search(policydb->p_cats.
4006cd6a6acSopenharmony_ci							   table,
4016cd6a6acSopenharmony_ci							   (hashtab_key_t)
4026cd6a6acSopenharmony_ci							   rngptr);
4036cd6a6acSopenharmony_ci					if (!rngdatum)
4046cd6a6acSopenharmony_ci						goto err;
4056cd6a6acSopenharmony_ci
4066cd6a6acSopenharmony_ci					if (catdatum->s.value >=
4076cd6a6acSopenharmony_ci					    rngdatum->s.value)
4086cd6a6acSopenharmony_ci						goto err;
4096cd6a6acSopenharmony_ci
4106cd6a6acSopenharmony_ci					for (i = catdatum->s.value;
4116cd6a6acSopenharmony_ci					     i < rngdatum->s.value; i++) {
4126cd6a6acSopenharmony_ci						if (ebitmap_set_bit
4136cd6a6acSopenharmony_ci						    (&context->range.level[l].
4146cd6a6acSopenharmony_ci						     cat, i, 1))
4156cd6a6acSopenharmony_ci							goto err;
4166cd6a6acSopenharmony_ci					}
4176cd6a6acSopenharmony_ci				}
4186cd6a6acSopenharmony_ci
4196cd6a6acSopenharmony_ci				if (delim != ',')
4206cd6a6acSopenharmony_ci					break;
4216cd6a6acSopenharmony_ci			}
4226cd6a6acSopenharmony_ci		}
4236cd6a6acSopenharmony_ci		if (delim == '-') {
4246cd6a6acSopenharmony_ci			/* Extract high sensitivity. */
4256cd6a6acSopenharmony_ci			scontextp = p;
4266cd6a6acSopenharmony_ci			while (*p && *p != ':')
4276cd6a6acSopenharmony_ci				p++;
4286cd6a6acSopenharmony_ci
4296cd6a6acSopenharmony_ci			delim = *p;
4306cd6a6acSopenharmony_ci			if (delim != 0)
4316cd6a6acSopenharmony_ci				*p++ = 0;
4326cd6a6acSopenharmony_ci		} else
4336cd6a6acSopenharmony_ci			break;
4346cd6a6acSopenharmony_ci	}
4356cd6a6acSopenharmony_ci
4366cd6a6acSopenharmony_ci	/* High level is missing, copy low level */
4376cd6a6acSopenharmony_ci	if (l == 0) {
4386cd6a6acSopenharmony_ci		if (mls_level_cpy(&context->range.level[1],
4396cd6a6acSopenharmony_ci				  &context->range.level[0]) < 0)
4406cd6a6acSopenharmony_ci			goto err;
4416cd6a6acSopenharmony_ci	}
4426cd6a6acSopenharmony_ci	*scontext = ++p;
4436cd6a6acSopenharmony_ci
4446cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
4456cd6a6acSopenharmony_ci
4466cd6a6acSopenharmony_ci      err:
4476cd6a6acSopenharmony_ci	return STATUS_ERR;
4486cd6a6acSopenharmony_ci}
4496cd6a6acSopenharmony_ci
4506cd6a6acSopenharmony_ci/*
4516cd6a6acSopenharmony_ci * Copies the MLS range from `src' into `dst'.
4526cd6a6acSopenharmony_ci */
4536cd6a6acSopenharmony_cistatic inline int mls_copy_context(context_struct_t * dst,
4546cd6a6acSopenharmony_ci				   const context_struct_t * src)
4556cd6a6acSopenharmony_ci{
4566cd6a6acSopenharmony_ci	int l, rc = 0;
4576cd6a6acSopenharmony_ci
4586cd6a6acSopenharmony_ci	/* Copy the MLS range from the source context */
4596cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
4606cd6a6acSopenharmony_ci		dst->range.level[l].sens = src->range.level[l].sens;
4616cd6a6acSopenharmony_ci		rc = ebitmap_cpy(&dst->range.level[l].cat,
4626cd6a6acSopenharmony_ci				 &src->range.level[l].cat);
4636cd6a6acSopenharmony_ci		if (rc)
4646cd6a6acSopenharmony_ci			break;
4656cd6a6acSopenharmony_ci	}
4666cd6a6acSopenharmony_ci
4676cd6a6acSopenharmony_ci	return rc;
4686cd6a6acSopenharmony_ci}
4696cd6a6acSopenharmony_ci
4706cd6a6acSopenharmony_ci/*
4716cd6a6acSopenharmony_ci * Copies the effective MLS range from `src' into `dst'.
4726cd6a6acSopenharmony_ci */
4736cd6a6acSopenharmony_cistatic inline int mls_scopy_context(context_struct_t * dst,
4746cd6a6acSopenharmony_ci				    const context_struct_t * src)
4756cd6a6acSopenharmony_ci{
4766cd6a6acSopenharmony_ci	int l, rc = 0;
4776cd6a6acSopenharmony_ci
4786cd6a6acSopenharmony_ci	/* Copy the MLS range from the source context */
4796cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
4806cd6a6acSopenharmony_ci		dst->range.level[l].sens = src->range.level[0].sens;
4816cd6a6acSopenharmony_ci		rc = ebitmap_cpy(&dst->range.level[l].cat,
4826cd6a6acSopenharmony_ci				 &src->range.level[0].cat);
4836cd6a6acSopenharmony_ci		if (rc)
4846cd6a6acSopenharmony_ci			break;
4856cd6a6acSopenharmony_ci	}
4866cd6a6acSopenharmony_ci
4876cd6a6acSopenharmony_ci	return rc;
4886cd6a6acSopenharmony_ci}
4896cd6a6acSopenharmony_ci
4906cd6a6acSopenharmony_ci/*
4916cd6a6acSopenharmony_ci * Copies the MLS range `range' into `context'.
4926cd6a6acSopenharmony_ci */
4936cd6a6acSopenharmony_cistatic inline int mls_range_set(context_struct_t * context, const mls_range_t * range)
4946cd6a6acSopenharmony_ci{
4956cd6a6acSopenharmony_ci	int l, rc = 0;
4966cd6a6acSopenharmony_ci
4976cd6a6acSopenharmony_ci	/* Copy the MLS range into the  context */
4986cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
4996cd6a6acSopenharmony_ci		context->range.level[l].sens = range->level[l].sens;
5006cd6a6acSopenharmony_ci		rc = ebitmap_cpy(&context->range.level[l].cat,
5016cd6a6acSopenharmony_ci				 &range->level[l].cat);
5026cd6a6acSopenharmony_ci		if (rc)
5036cd6a6acSopenharmony_ci			break;
5046cd6a6acSopenharmony_ci	}
5056cd6a6acSopenharmony_ci
5066cd6a6acSopenharmony_ci	return rc;
5076cd6a6acSopenharmony_ci}
5086cd6a6acSopenharmony_ci
5096cd6a6acSopenharmony_ciint mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
5106cd6a6acSopenharmony_ci			 context_struct_t * usercon, int mls)
5116cd6a6acSopenharmony_ci{
5126cd6a6acSopenharmony_ci	if (mls) {
5136cd6a6acSopenharmony_ci		mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
5146cd6a6acSopenharmony_ci		mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
5156cd6a6acSopenharmony_ci		mls_level_t *user_low = &(user->exp_range.level[0]);
5166cd6a6acSopenharmony_ci		mls_level_t *user_clr = &(user->exp_range.level[1]);
5176cd6a6acSopenharmony_ci		mls_level_t *user_def = &(user->exp_dfltlevel);
5186cd6a6acSopenharmony_ci		mls_level_t *usercon_sen = &(usercon->range.level[0]);
5196cd6a6acSopenharmony_ci		mls_level_t *usercon_clr = &(usercon->range.level[1]);
5206cd6a6acSopenharmony_ci
5216cd6a6acSopenharmony_ci		/* Honor the user's default level if we can */
5226cd6a6acSopenharmony_ci		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
5236cd6a6acSopenharmony_ci			*usercon_sen = *user_def;
5246cd6a6acSopenharmony_ci		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
5256cd6a6acSopenharmony_ci			*usercon_sen = *fromcon_sen;
5266cd6a6acSopenharmony_ci		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
5276cd6a6acSopenharmony_ci			*usercon_sen = *user_low;
5286cd6a6acSopenharmony_ci		} else
5296cd6a6acSopenharmony_ci			return -EINVAL;
5306cd6a6acSopenharmony_ci
5316cd6a6acSopenharmony_ci		/* Lower the clearance of available contexts
5326cd6a6acSopenharmony_ci		   if the clearance of "fromcon" is lower than
5336cd6a6acSopenharmony_ci		   that of the user's default clearance (but
5346cd6a6acSopenharmony_ci		   only if the "fromcon" clearance dominates
5356cd6a6acSopenharmony_ci		   the user's computed sensitivity level) */
5366cd6a6acSopenharmony_ci		if (mls_level_dom(user_clr, fromcon_clr)) {
5376cd6a6acSopenharmony_ci			*usercon_clr = *fromcon_clr;
5386cd6a6acSopenharmony_ci		} else if (mls_level_dom(fromcon_clr, user_clr)) {
5396cd6a6acSopenharmony_ci			*usercon_clr = *user_clr;
5406cd6a6acSopenharmony_ci		} else
5416cd6a6acSopenharmony_ci			return -EINVAL;
5426cd6a6acSopenharmony_ci	}
5436cd6a6acSopenharmony_ci
5446cd6a6acSopenharmony_ci	return 0;
5456cd6a6acSopenharmony_ci}
5466cd6a6acSopenharmony_ci
5476cd6a6acSopenharmony_ci/*
5486cd6a6acSopenharmony_ci * Convert the MLS fields in the security context
5496cd6a6acSopenharmony_ci * structure `c' from the values specified in the
5506cd6a6acSopenharmony_ci * policy `oldp' to the values specified in the policy `newp'.
5516cd6a6acSopenharmony_ci */
5526cd6a6acSopenharmony_ciint mls_convert_context(policydb_t * oldp,
5536cd6a6acSopenharmony_ci			policydb_t * newp, context_struct_t * c)
5546cd6a6acSopenharmony_ci{
5556cd6a6acSopenharmony_ci	level_datum_t *levdatum;
5566cd6a6acSopenharmony_ci	cat_datum_t *catdatum;
5576cd6a6acSopenharmony_ci	ebitmap_t bitmap;
5586cd6a6acSopenharmony_ci	unsigned int l, i;
5596cd6a6acSopenharmony_ci	ebitmap_node_t *cnode;
5606cd6a6acSopenharmony_ci
5616cd6a6acSopenharmony_ci	if (!oldp->mls)
5626cd6a6acSopenharmony_ci		return 0;
5636cd6a6acSopenharmony_ci
5646cd6a6acSopenharmony_ci	for (l = 0; l < 2; l++) {
5656cd6a6acSopenharmony_ci		levdatum =
5666cd6a6acSopenharmony_ci		    (level_datum_t *) hashtab_search(newp->p_levels.table,
5676cd6a6acSopenharmony_ci						     oldp->
5686cd6a6acSopenharmony_ci						     p_sens_val_to_name[c->
5696cd6a6acSopenharmony_ci									range.
5706cd6a6acSopenharmony_ci									level
5716cd6a6acSopenharmony_ci									[l].
5726cd6a6acSopenharmony_ci									sens -
5736cd6a6acSopenharmony_ci									1]);
5746cd6a6acSopenharmony_ci
5756cd6a6acSopenharmony_ci		if (!levdatum)
5766cd6a6acSopenharmony_ci			return -EINVAL;
5776cd6a6acSopenharmony_ci		c->range.level[l].sens = levdatum->level->sens;
5786cd6a6acSopenharmony_ci
5796cd6a6acSopenharmony_ci		ebitmap_init(&bitmap);
5806cd6a6acSopenharmony_ci		ebitmap_for_each_positive_bit(&c->range.level[l].cat, cnode, i) {
5816cd6a6acSopenharmony_ci			int rc;
5826cd6a6acSopenharmony_ci
5836cd6a6acSopenharmony_ci			catdatum =
5846cd6a6acSopenharmony_ci			    (cat_datum_t *) hashtab_search(newp->p_cats.
5856cd6a6acSopenharmony_ci							   table,
5866cd6a6acSopenharmony_ci							   oldp->
5876cd6a6acSopenharmony_ci							   p_cat_val_to_name
5886cd6a6acSopenharmony_ci							   [i]);
5896cd6a6acSopenharmony_ci			if (!catdatum)
5906cd6a6acSopenharmony_ci				return -EINVAL;
5916cd6a6acSopenharmony_ci			rc = ebitmap_set_bit(&bitmap,
5926cd6a6acSopenharmony_ci					     catdatum->s.value - 1, 1);
5936cd6a6acSopenharmony_ci			if (rc)
5946cd6a6acSopenharmony_ci				return rc;
5956cd6a6acSopenharmony_ci		}
5966cd6a6acSopenharmony_ci		ebitmap_destroy(&c->range.level[l].cat);
5976cd6a6acSopenharmony_ci		c->range.level[l].cat = bitmap;
5986cd6a6acSopenharmony_ci	}
5996cd6a6acSopenharmony_ci
6006cd6a6acSopenharmony_ci	return 0;
6016cd6a6acSopenharmony_ci}
6026cd6a6acSopenharmony_ci
6036cd6a6acSopenharmony_ciint mls_compute_sid(policydb_t * policydb,
6046cd6a6acSopenharmony_ci		    const context_struct_t * scontext,
6056cd6a6acSopenharmony_ci		    const context_struct_t * tcontext,
6066cd6a6acSopenharmony_ci		    sepol_security_class_t tclass,
6076cd6a6acSopenharmony_ci		    uint32_t specified, context_struct_t * newcontext)
6086cd6a6acSopenharmony_ci{
6096cd6a6acSopenharmony_ci	range_trans_t rtr;
6106cd6a6acSopenharmony_ci	struct mls_range *r;
6116cd6a6acSopenharmony_ci	struct class_datum *cladatum;
6126cd6a6acSopenharmony_ci	int default_range = 0;
6136cd6a6acSopenharmony_ci
6146cd6a6acSopenharmony_ci	if (!policydb->mls)
6156cd6a6acSopenharmony_ci		return 0;
6166cd6a6acSopenharmony_ci
6176cd6a6acSopenharmony_ci	switch (specified) {
6186cd6a6acSopenharmony_ci	case AVTAB_TRANSITION:
6196cd6a6acSopenharmony_ci		/* Look for a range transition rule. */
6206cd6a6acSopenharmony_ci		rtr.source_type = scontext->type;
6216cd6a6acSopenharmony_ci		rtr.target_type = tcontext->type;
6226cd6a6acSopenharmony_ci		rtr.target_class = tclass;
6236cd6a6acSopenharmony_ci		r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr);
6246cd6a6acSopenharmony_ci		if (r)
6256cd6a6acSopenharmony_ci			return mls_range_set(newcontext, r);
6266cd6a6acSopenharmony_ci
6276cd6a6acSopenharmony_ci		if (tclass && tclass <= policydb->p_classes.nprim) {
6286cd6a6acSopenharmony_ci			cladatum = policydb->class_val_to_struct[tclass - 1];
6296cd6a6acSopenharmony_ci			if (cladatum)
6306cd6a6acSopenharmony_ci				default_range = cladatum->default_range;
6316cd6a6acSopenharmony_ci		}
6326cd6a6acSopenharmony_ci
6336cd6a6acSopenharmony_ci		switch (default_range) {
6346cd6a6acSopenharmony_ci		case DEFAULT_SOURCE_LOW:
6356cd6a6acSopenharmony_ci			return mls_context_cpy_low(newcontext, scontext);
6366cd6a6acSopenharmony_ci		case DEFAULT_SOURCE_HIGH:
6376cd6a6acSopenharmony_ci			return mls_context_cpy_high(newcontext, scontext);
6386cd6a6acSopenharmony_ci		case DEFAULT_SOURCE_LOW_HIGH:
6396cd6a6acSopenharmony_ci			return mls_context_cpy(newcontext, scontext);
6406cd6a6acSopenharmony_ci		case DEFAULT_TARGET_LOW:
6416cd6a6acSopenharmony_ci			return mls_context_cpy_low(newcontext, tcontext);
6426cd6a6acSopenharmony_ci		case DEFAULT_TARGET_HIGH:
6436cd6a6acSopenharmony_ci			return mls_context_cpy_high(newcontext, tcontext);
6446cd6a6acSopenharmony_ci		case DEFAULT_TARGET_LOW_HIGH:
6456cd6a6acSopenharmony_ci			return mls_context_cpy(newcontext, tcontext);
6466cd6a6acSopenharmony_ci		case DEFAULT_GLBLUB:
6476cd6a6acSopenharmony_ci			return mls_context_glblub(newcontext, scontext, tcontext);
6486cd6a6acSopenharmony_ci		}
6496cd6a6acSopenharmony_ci
6506cd6a6acSopenharmony_ci		/* Fallthrough */
6516cd6a6acSopenharmony_ci	case AVTAB_CHANGE:
6526cd6a6acSopenharmony_ci		if (tclass == policydb->process_class)
6536cd6a6acSopenharmony_ci			/* Use the process MLS attributes. */
6546cd6a6acSopenharmony_ci			return mls_copy_context(newcontext, scontext);
6556cd6a6acSopenharmony_ci		else
6566cd6a6acSopenharmony_ci			/* Use the process effective MLS attributes. */
6576cd6a6acSopenharmony_ci			return mls_scopy_context(newcontext, scontext);
6586cd6a6acSopenharmony_ci	case AVTAB_MEMBER:
6596cd6a6acSopenharmony_ci		/* Use the process effective MLS attributes. */
6606cd6a6acSopenharmony_ci		return mls_context_cpy_low(newcontext, scontext);
6616cd6a6acSopenharmony_ci	default:
6626cd6a6acSopenharmony_ci		return -EINVAL;
6636cd6a6acSopenharmony_ci	}
6646cd6a6acSopenharmony_ci	return -EINVAL;
6656cd6a6acSopenharmony_ci}
6666cd6a6acSopenharmony_ci
6676cd6a6acSopenharmony_ciint sepol_mls_contains(sepol_handle_t * handle,
6686cd6a6acSopenharmony_ci		       const sepol_policydb_t * policydb,
6696cd6a6acSopenharmony_ci		       const char *mls1, const char *mls2, int *response)
6706cd6a6acSopenharmony_ci{
6716cd6a6acSopenharmony_ci
6726cd6a6acSopenharmony_ci	context_struct_t *ctx1 = NULL, *ctx2 = NULL;
6736cd6a6acSopenharmony_ci	ctx1 = malloc(sizeof(context_struct_t));
6746cd6a6acSopenharmony_ci	ctx2 = malloc(sizeof(context_struct_t));
6756cd6a6acSopenharmony_ci	if (ctx1 == NULL || ctx2 == NULL)
6766cd6a6acSopenharmony_ci		goto omem;
6776cd6a6acSopenharmony_ci	context_init(ctx1);
6786cd6a6acSopenharmony_ci	context_init(ctx2);
6796cd6a6acSopenharmony_ci
6806cd6a6acSopenharmony_ci	if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
6816cd6a6acSopenharmony_ci		goto err;
6826cd6a6acSopenharmony_ci
6836cd6a6acSopenharmony_ci	if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
6846cd6a6acSopenharmony_ci		goto err;
6856cd6a6acSopenharmony_ci
6866cd6a6acSopenharmony_ci	*response = mls_range_contains(ctx1->range, ctx2->range);
6876cd6a6acSopenharmony_ci	context_destroy(ctx1);
6886cd6a6acSopenharmony_ci	context_destroy(ctx2);
6896cd6a6acSopenharmony_ci	free(ctx1);
6906cd6a6acSopenharmony_ci	free(ctx2);
6916cd6a6acSopenharmony_ci	return STATUS_SUCCESS;
6926cd6a6acSopenharmony_ci
6936cd6a6acSopenharmony_ci      omem:
6946cd6a6acSopenharmony_ci	ERR(handle, "out of memory");
6956cd6a6acSopenharmony_ci
6966cd6a6acSopenharmony_ci      err:
6976cd6a6acSopenharmony_ci	ERR(handle, "could not check if mls context %s contains %s",
6986cd6a6acSopenharmony_ci	    mls1, mls2);
6996cd6a6acSopenharmony_ci	context_destroy(ctx1);
7006cd6a6acSopenharmony_ci	context_destroy(ctx2);
7016cd6a6acSopenharmony_ci	free(ctx1);
7026cd6a6acSopenharmony_ci	free(ctx2);
7036cd6a6acSopenharmony_ci	return STATUS_ERR;
7046cd6a6acSopenharmony_ci}
7056cd6a6acSopenharmony_ci
7066cd6a6acSopenharmony_ciint sepol_mls_check(sepol_handle_t * handle,
7076cd6a6acSopenharmony_ci		    const sepol_policydb_t * policydb, const char *mls)
7086cd6a6acSopenharmony_ci{
7096cd6a6acSopenharmony_ci
7106cd6a6acSopenharmony_ci	int ret;
7116cd6a6acSopenharmony_ci	context_struct_t *con = malloc(sizeof(context_struct_t));
7126cd6a6acSopenharmony_ci	if (!con) {
7136cd6a6acSopenharmony_ci		ERR(handle, "out of memory, could not check if "
7146cd6a6acSopenharmony_ci		    "mls context %s is valid", mls);
7156cd6a6acSopenharmony_ci		return STATUS_ERR;
7166cd6a6acSopenharmony_ci	}
7176cd6a6acSopenharmony_ci	context_init(con);
7186cd6a6acSopenharmony_ci
7196cd6a6acSopenharmony_ci	ret = mls_from_string(handle, &policydb->p, mls, con);
7206cd6a6acSopenharmony_ci	context_destroy(con);
7216cd6a6acSopenharmony_ci	free(con);
7226cd6a6acSopenharmony_ci	return ret;
7236cd6a6acSopenharmony_ci}
7246cd6a6acSopenharmony_ci
7256cd6a6acSopenharmony_civoid mls_semantic_cat_init(mls_semantic_cat_t * c)
7266cd6a6acSopenharmony_ci{
7276cd6a6acSopenharmony_ci	memset(c, 0, sizeof(mls_semantic_cat_t));
7286cd6a6acSopenharmony_ci}
7296cd6a6acSopenharmony_ci
7306cd6a6acSopenharmony_civoid mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
7316cd6a6acSopenharmony_ci{
7326cd6a6acSopenharmony_ci	/* it's currently a simple struct - really nothing to destroy */
7336cd6a6acSopenharmony_ci	return;
7346cd6a6acSopenharmony_ci}
7356cd6a6acSopenharmony_ci
7366cd6a6acSopenharmony_civoid mls_semantic_level_init(mls_semantic_level_t * l)
7376cd6a6acSopenharmony_ci{
7386cd6a6acSopenharmony_ci	memset(l, 0, sizeof(mls_semantic_level_t));
7396cd6a6acSopenharmony_ci}
7406cd6a6acSopenharmony_ci
7416cd6a6acSopenharmony_civoid mls_semantic_level_destroy(mls_semantic_level_t * l)
7426cd6a6acSopenharmony_ci{
7436cd6a6acSopenharmony_ci	mls_semantic_cat_t *cur, *next;
7446cd6a6acSopenharmony_ci
7456cd6a6acSopenharmony_ci	if (l == NULL)
7466cd6a6acSopenharmony_ci		return;
7476cd6a6acSopenharmony_ci
7486cd6a6acSopenharmony_ci	next = l->cat;
7496cd6a6acSopenharmony_ci	while (next) {
7506cd6a6acSopenharmony_ci		cur = next;
7516cd6a6acSopenharmony_ci		next = cur->next;
7526cd6a6acSopenharmony_ci		mls_semantic_cat_destroy(cur);
7536cd6a6acSopenharmony_ci		free(cur);
7546cd6a6acSopenharmony_ci	}
7556cd6a6acSopenharmony_ci}
7566cd6a6acSopenharmony_ci
7576cd6a6acSopenharmony_ciint mls_semantic_level_cpy(mls_semantic_level_t * dst,
7586cd6a6acSopenharmony_ci			   const mls_semantic_level_t * src)
7596cd6a6acSopenharmony_ci{
7606cd6a6acSopenharmony_ci	const mls_semantic_cat_t *cat;
7616cd6a6acSopenharmony_ci	mls_semantic_cat_t *newcat, *lnewcat = NULL;
7626cd6a6acSopenharmony_ci
7636cd6a6acSopenharmony_ci	mls_semantic_level_init(dst);
7646cd6a6acSopenharmony_ci	dst->sens = src->sens;
7656cd6a6acSopenharmony_ci	cat = src->cat;
7666cd6a6acSopenharmony_ci	while (cat) {
7676cd6a6acSopenharmony_ci		newcat =
7686cd6a6acSopenharmony_ci		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
7696cd6a6acSopenharmony_ci		if (!newcat)
7706cd6a6acSopenharmony_ci			goto err;
7716cd6a6acSopenharmony_ci
7726cd6a6acSopenharmony_ci		mls_semantic_cat_init(newcat);
7736cd6a6acSopenharmony_ci		if (lnewcat)
7746cd6a6acSopenharmony_ci			lnewcat->next = newcat;
7756cd6a6acSopenharmony_ci		else
7766cd6a6acSopenharmony_ci			dst->cat = newcat;
7776cd6a6acSopenharmony_ci
7786cd6a6acSopenharmony_ci		newcat->low = cat->low;
7796cd6a6acSopenharmony_ci		newcat->high = cat->high;
7806cd6a6acSopenharmony_ci
7816cd6a6acSopenharmony_ci		lnewcat = newcat;
7826cd6a6acSopenharmony_ci		cat = cat->next;
7836cd6a6acSopenharmony_ci	}
7846cd6a6acSopenharmony_ci	return 0;
7856cd6a6acSopenharmony_ci
7866cd6a6acSopenharmony_ci      err:
7876cd6a6acSopenharmony_ci	mls_semantic_level_destroy(dst);
7886cd6a6acSopenharmony_ci	return -1;
7896cd6a6acSopenharmony_ci}
7906cd6a6acSopenharmony_ci
7916cd6a6acSopenharmony_civoid mls_semantic_range_init(mls_semantic_range_t * r)
7926cd6a6acSopenharmony_ci{
7936cd6a6acSopenharmony_ci	mls_semantic_level_init(&r->level[0]);
7946cd6a6acSopenharmony_ci	mls_semantic_level_init(&r->level[1]);
7956cd6a6acSopenharmony_ci}
7966cd6a6acSopenharmony_ci
7976cd6a6acSopenharmony_civoid mls_semantic_range_destroy(mls_semantic_range_t * r)
7986cd6a6acSopenharmony_ci{
7996cd6a6acSopenharmony_ci	mls_semantic_level_destroy(&r->level[0]);
8006cd6a6acSopenharmony_ci	mls_semantic_level_destroy(&r->level[1]);
8016cd6a6acSopenharmony_ci}
8026cd6a6acSopenharmony_ci
8036cd6a6acSopenharmony_ciint mls_semantic_range_cpy(mls_semantic_range_t * dst,
8046cd6a6acSopenharmony_ci			   const mls_semantic_range_t * src)
8056cd6a6acSopenharmony_ci{
8066cd6a6acSopenharmony_ci	if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
8076cd6a6acSopenharmony_ci		return -1;
8086cd6a6acSopenharmony_ci
8096cd6a6acSopenharmony_ci	if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
8106cd6a6acSopenharmony_ci		mls_semantic_level_destroy(&dst->level[0]);
8116cd6a6acSopenharmony_ci		return -1;
8126cd6a6acSopenharmony_ci	}
8136cd6a6acSopenharmony_ci
8146cd6a6acSopenharmony_ci	return 0;
8156cd6a6acSopenharmony_ci}
816