• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
2 /*
3  * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
4  *
5  *	Support for enhanced MLS infrastructure.
6  *
7  * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2.1 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23 
24 /* FLASK */
25 
26 /*
27  * Implementation of the multi-level security (MLS) policy.
28  */
29 
30 #include <sepol/context.h>
31 #include <sepol/policydb/policydb.h>
32 #include <sepol/policydb/services.h>
33 #include <sepol/policydb/context.h>
34 
35 #include <stdlib.h>
36 
37 #include "handle.h"
38 #include "debug.h"
39 #include "private.h"
40 #include "mls.h"
41 
mls_to_string(sepol_handle_t * handle,const policydb_t * policydb,const context_struct_t * mls,char ** str)42 int mls_to_string(sepol_handle_t * handle,
43 		  const policydb_t * policydb,
44 		  const context_struct_t * mls, char **str)
45 {
46 
47 	char *ptr = NULL, *ptr2 = NULL;
48 
49 	/* Temporary buffer - length + NULL terminator */
50 	int len = mls_compute_context_len(policydb, mls) + 1;
51 
52 	ptr = (char *)malloc(len);
53 	if (ptr == NULL)
54 		goto omem;
55 
56 	/* Final string w/ ':' cut off */
57 	ptr2 = (char *)malloc(len - 1);
58 	if (ptr2 == NULL)
59 		goto omem;
60 
61 	mls_sid_to_context(policydb, mls, &ptr);
62 	ptr -= len - 1;
63 	strcpy(ptr2, ptr + 1);
64 
65 	free(ptr);
66 	*str = ptr2;
67 	return STATUS_SUCCESS;
68 
69       omem:
70 	ERR(handle, "out of memory, could not convert mls context to string");
71 
72 	free(ptr);
73 	free(ptr2);
74 	return STATUS_ERR;
75 
76 }
77 
mls_from_string(sepol_handle_t * handle,const policydb_t * policydb,const char * str,context_struct_t * mls)78 int mls_from_string(sepol_handle_t * handle,
79 		    const policydb_t * policydb,
80 		    const char *str, context_struct_t * mls)
81 {
82 
83 	char *tmp = strdup(str);
84 	char *tmp_cp = tmp;
85 	if (!tmp)
86 		goto omem;
87 
88 	if (mls_context_to_sid(policydb, '$', &tmp_cp, mls) < 0) {
89 		ERR(handle, "invalid MLS context %s", str);
90 		free(tmp);
91 		goto err;
92 	}
93 
94 	free(tmp);
95 	return STATUS_SUCCESS;
96 
97       omem:
98 	ERR(handle, "out of memory");
99 
100       err:
101 	ERR(handle, "could not construct mls context structure");
102 	return STATUS_ERR;
103 }
104 
105 /*
106  * Return the length in bytes for the MLS fields of the
107  * security context string representation of `context'.
108  */
mls_compute_context_len(const policydb_t * policydb,const context_struct_t * context)109 int mls_compute_context_len(const policydb_t * policydb,
110 			    const context_struct_t * context)
111 {
112 
113 	unsigned int i, l, len, range;
114 	ebitmap_node_t *cnode;
115 
116 	if (!policydb->mls)
117 		return 0;
118 
119 	len = 1;		/* for the beginning ":" */
120 	for (l = 0; l < 2; l++) {
121 		range = 0;
122 		len +=
123 		    strlen(policydb->
124 			   p_sens_val_to_name[context->range.level[l].sens -
125 					      1]);
126 
127 		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
128 			if (ebitmap_node_get_bit(cnode, i)) {
129 				if (range) {
130 					range++;
131 					continue;
132 				}
133 
134 				len +=
135 				    strlen(policydb->p_cat_val_to_name[i]) + 1;
136 				range++;
137 			} else {
138 				if (range > 1)
139 					len +=
140 					    strlen(policydb->
141 						   p_cat_val_to_name[i - 1]) +
142 					    1;
143 				range = 0;
144 			}
145 		}
146 		/* Handle case where last category is the end of range */
147 		if (range > 1)
148 			len += strlen(policydb->p_cat_val_to_name[i - 1]) + 1;
149 
150 		if (l == 0) {
151 			if (mls_level_eq(&context->range.level[0],
152 					 &context->range.level[1]))
153 				break;
154 			else
155 				len++;
156 		}
157 	}
158 
159 	return len;
160 }
161 
162 /*
163  * Write the security context string representation of
164  * the MLS fields of `context' into the string `*scontext'.
165  * Update `*scontext' to point to the end of the MLS fields.
166  */
mls_sid_to_context(const policydb_t * policydb,const context_struct_t * context,char ** scontext)167 void mls_sid_to_context(const policydb_t * policydb,
168 			const context_struct_t * context, char **scontext)
169 {
170 
171 	char *scontextp;
172 	unsigned int i, l, range, wrote_sep;
173 	ebitmap_node_t *cnode;
174 
175 	if (!policydb->mls)
176 		return;
177 
178 	scontextp = *scontext;
179 
180 	*scontextp = ':';
181 	scontextp++;
182 
183 	for (l = 0; l < 2; l++) {
184 		range = 0;
185 		wrote_sep = 0;
186 		strcpy(scontextp,
187 		       policydb->p_sens_val_to_name[context->range.level[l].
188 						    sens - 1]);
189 		scontextp +=
190 		    strlen(policydb->
191 			   p_sens_val_to_name[context->range.level[l].sens -
192 					      1]);
193 		/* categories */
194 		ebitmap_for_each_bit(&context->range.level[l].cat, cnode, i) {
195 			if (ebitmap_node_get_bit(cnode, i)) {
196 				if (range) {
197 					range++;
198 					continue;
199 				}
200 
201 				if (!wrote_sep) {
202 					*scontextp++ = ':';
203 					wrote_sep = 1;
204 				} else
205 					*scontextp++ = ',';
206 				strcpy(scontextp,
207 				       policydb->p_cat_val_to_name[i]);
208 				scontextp +=
209 				    strlen(policydb->p_cat_val_to_name[i]);
210 				range++;
211 			} else {
212 				if (range > 1) {
213 					if (range > 2)
214 						*scontextp++ = '.';
215 					else
216 						*scontextp++ = ',';
217 
218 					strcpy(scontextp,
219 					       policydb->p_cat_val_to_name[i -
220 									   1]);
221 					scontextp +=
222 					    strlen(policydb->
223 						   p_cat_val_to_name[i - 1]);
224 				}
225 				range = 0;
226 			}
227 		}
228 		/* Handle case where last category is the end of range */
229 		if (range > 1) {
230 			if (range > 2)
231 				*scontextp++ = '.';
232 			else
233 				*scontextp++ = ',';
234 
235 			strcpy(scontextp, policydb->p_cat_val_to_name[i - 1]);
236 			scontextp += strlen(policydb->p_cat_val_to_name[i - 1]);
237 		}
238 
239 		if (l == 0) {
240 			if (mls_level_eq(&context->range.level[0],
241 					 &context->range.level[1]))
242 				break;
243 			else {
244 				*scontextp = '-';
245 				scontextp++;
246 			}
247 		}
248 	}
249 
250 	*scontext = scontextp;
251 	return;
252 }
253 
254 /*
255  * Return 1 if the MLS fields in the security context
256  * structure `c' are valid.  Return 0 otherwise.
257  */
mls_context_isvalid(const policydb_t * p,const context_struct_t * c)258 int mls_context_isvalid(const policydb_t * p, const context_struct_t * c)
259 {
260 
261 	level_datum_t *levdatum;
262 	user_datum_t *usrdatum;
263 	unsigned int i, l;
264 	ebitmap_node_t *cnode;
265 	hashtab_key_t key;
266 
267 	if (!p->mls)
268 		return 1;
269 
270 	/*
271 	 * MLS range validity checks: high must dominate low, low level must
272 	 * be valid (category set <-> sensitivity check), and high level must
273 	 * be valid (category set <-> sensitivity check)
274 	 */
275 	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
276 		/* High does not dominate low. */
277 		return 0;
278 
279 	for (l = 0; l < 2; l++) {
280 		if (!c->range.level[l].sens
281 		    || c->range.level[l].sens > p->p_levels.nprim)
282 			return 0;
283 
284 		key = p->p_sens_val_to_name[c->range.level[l].sens - 1];
285 		if (!key)
286 			return 0;
287 
288 		levdatum = (level_datum_t *) hashtab_search(p->p_levels.table, key);
289 		if (!levdatum)
290 			return 0;
291 
292 		ebitmap_for_each_positive_bit(&c->range.level[l].cat, cnode, i) {
293 			if (i > p->p_cats.nprim)
294 				return 0;
295 			if (!ebitmap_get_bit(&levdatum->level->cat, i))
296 				/*
297 				 * Category may not be associated with
298 				 * sensitivity in low level.
299 				 */
300 				return 0;
301 		}
302 	}
303 
304 	if (c->role == OBJECT_R_VAL)
305 		return 1;
306 
307 	/*
308 	 * User must be authorized for the MLS range.
309 	 */
310 	if (!c->user || c->user > p->p_users.nprim)
311 		return 0;
312 	usrdatum = p->user_val_to_struct[c->user - 1];
313 	if (!usrdatum || !mls_range_contains(usrdatum->exp_range, c->range))
314 		return 0;	/* user may not be associated with range */
315 
316 	return 1;
317 }
318 
319 /*
320  * Set the MLS fields in the security context structure
321  * `context' based on the string representation in
322  * the string `*scontext'.  Update `*scontext' to
323  * point to the end of the string representation of
324  * the MLS fields.
325  *
326  * This function modifies the string in place, inserting
327  * NULL characters to terminate the MLS fields.
328  */
mls_context_to_sid(const policydb_t * policydb,char oldc,char ** scontext,context_struct_t * context)329 int mls_context_to_sid(const policydb_t * policydb,
330 		       char oldc, char **scontext, context_struct_t * context)
331 {
332 
333 	char delim;
334 	char *scontextp, *p, *rngptr;
335 	level_datum_t *levdatum;
336 	cat_datum_t *catdatum, *rngdatum;
337 	unsigned int l;
338 
339 	if (!policydb->mls)
340 		return 0;
341 
342 	/* No MLS component to the security context */
343 	if (!oldc)
344 		goto err;
345 
346 	/* Extract low sensitivity. */
347 	scontextp = p = *scontext;
348 	while (*p && *p != ':' && *p != '-')
349 		p++;
350 
351 	delim = *p;
352 	if (delim != 0)
353 		*p++ = 0;
354 
355 	for (l = 0; l < 2; l++) {
356 		levdatum =
357 		    (level_datum_t *) hashtab_search(policydb->p_levels.table,
358 						     (hashtab_key_t) scontextp);
359 
360 		if (!levdatum)
361 			goto err;
362 
363 		context->range.level[l].sens = levdatum->level->sens;
364 
365 		if (delim == ':') {
366 			/* Extract category set. */
367 			while (1) {
368 				scontextp = p;
369 				while (*p && *p != ',' && *p != '-')
370 					p++;
371 				delim = *p;
372 				if (delim != 0)
373 					*p++ = 0;
374 
375 				/* Separate into range if exists */
376 				if ((rngptr = strchr(scontextp, '.')) != NULL) {
377 					/* Remove '.' */
378 					*rngptr++ = 0;
379 				}
380 
381 				catdatum =
382 				    (cat_datum_t *) hashtab_search(policydb->
383 								   p_cats.table,
384 								   (hashtab_key_t)
385 								   scontextp);
386 				if (!catdatum)
387 					goto err;
388 
389 				if (ebitmap_set_bit
390 				    (&context->range.level[l].cat,
391 				     catdatum->s.value - 1, 1))
392 					goto err;
393 
394 				/* If range, set all categories in range */
395 				if (rngptr) {
396 					unsigned int i;
397 
398 					rngdatum = (cat_datum_t *)
399 					    hashtab_search(policydb->p_cats.
400 							   table,
401 							   (hashtab_key_t)
402 							   rngptr);
403 					if (!rngdatum)
404 						goto err;
405 
406 					if (catdatum->s.value >=
407 					    rngdatum->s.value)
408 						goto err;
409 
410 					for (i = catdatum->s.value;
411 					     i < rngdatum->s.value; i++) {
412 						if (ebitmap_set_bit
413 						    (&context->range.level[l].
414 						     cat, i, 1))
415 							goto err;
416 					}
417 				}
418 
419 				if (delim != ',')
420 					break;
421 			}
422 		}
423 		if (delim == '-') {
424 			/* Extract high sensitivity. */
425 			scontextp = p;
426 			while (*p && *p != ':')
427 				p++;
428 
429 			delim = *p;
430 			if (delim != 0)
431 				*p++ = 0;
432 		} else
433 			break;
434 	}
435 
436 	/* High level is missing, copy low level */
437 	if (l == 0) {
438 		if (mls_level_cpy(&context->range.level[1],
439 				  &context->range.level[0]) < 0)
440 			goto err;
441 	}
442 	*scontext = ++p;
443 
444 	return STATUS_SUCCESS;
445 
446       err:
447 	return STATUS_ERR;
448 }
449 
450 /*
451  * Copies the MLS range from `src' into `dst'.
452  */
mls_copy_context(context_struct_t * dst,const context_struct_t * src)453 static inline int mls_copy_context(context_struct_t * dst,
454 				   const context_struct_t * src)
455 {
456 	int l, rc = 0;
457 
458 	/* Copy the MLS range from the source context */
459 	for (l = 0; l < 2; l++) {
460 		dst->range.level[l].sens = src->range.level[l].sens;
461 		rc = ebitmap_cpy(&dst->range.level[l].cat,
462 				 &src->range.level[l].cat);
463 		if (rc)
464 			break;
465 	}
466 
467 	return rc;
468 }
469 
470 /*
471  * Copies the effective MLS range from `src' into `dst'.
472  */
mls_scopy_context(context_struct_t * dst,const context_struct_t * src)473 static inline int mls_scopy_context(context_struct_t * dst,
474 				    const context_struct_t * src)
475 {
476 	int l, rc = 0;
477 
478 	/* Copy the MLS range from the source context */
479 	for (l = 0; l < 2; l++) {
480 		dst->range.level[l].sens = src->range.level[0].sens;
481 		rc = ebitmap_cpy(&dst->range.level[l].cat,
482 				 &src->range.level[0].cat);
483 		if (rc)
484 			break;
485 	}
486 
487 	return rc;
488 }
489 
490 /*
491  * Copies the MLS range `range' into `context'.
492  */
mls_range_set(context_struct_t * context,const mls_range_t * range)493 static inline int mls_range_set(context_struct_t * context, const mls_range_t * range)
494 {
495 	int l, rc = 0;
496 
497 	/* Copy the MLS range into the  context */
498 	for (l = 0; l < 2; l++) {
499 		context->range.level[l].sens = range->level[l].sens;
500 		rc = ebitmap_cpy(&context->range.level[l].cat,
501 				 &range->level[l].cat);
502 		if (rc)
503 			break;
504 	}
505 
506 	return rc;
507 }
508 
mls_setup_user_range(context_struct_t * fromcon,user_datum_t * user,context_struct_t * usercon,int mls)509 int mls_setup_user_range(context_struct_t * fromcon, user_datum_t * user,
510 			 context_struct_t * usercon, int mls)
511 {
512 	if (mls) {
513 		mls_level_t *fromcon_sen = &(fromcon->range.level[0]);
514 		mls_level_t *fromcon_clr = &(fromcon->range.level[1]);
515 		mls_level_t *user_low = &(user->exp_range.level[0]);
516 		mls_level_t *user_clr = &(user->exp_range.level[1]);
517 		mls_level_t *user_def = &(user->exp_dfltlevel);
518 		mls_level_t *usercon_sen = &(usercon->range.level[0]);
519 		mls_level_t *usercon_clr = &(usercon->range.level[1]);
520 
521 		/* Honor the user's default level if we can */
522 		if (mls_level_between(user_def, fromcon_sen, fromcon_clr)) {
523 			*usercon_sen = *user_def;
524 		} else if (mls_level_between(fromcon_sen, user_def, user_clr)) {
525 			*usercon_sen = *fromcon_sen;
526 		} else if (mls_level_between(fromcon_clr, user_low, user_def)) {
527 			*usercon_sen = *user_low;
528 		} else
529 			return -EINVAL;
530 
531 		/* Lower the clearance of available contexts
532 		   if the clearance of "fromcon" is lower than
533 		   that of the user's default clearance (but
534 		   only if the "fromcon" clearance dominates
535 		   the user's computed sensitivity level) */
536 		if (mls_level_dom(user_clr, fromcon_clr)) {
537 			*usercon_clr = *fromcon_clr;
538 		} else if (mls_level_dom(fromcon_clr, user_clr)) {
539 			*usercon_clr = *user_clr;
540 		} else
541 			return -EINVAL;
542 	}
543 
544 	return 0;
545 }
546 
547 /*
548  * Convert the MLS fields in the security context
549  * structure `c' from the values specified in the
550  * policy `oldp' to the values specified in the policy `newp'.
551  */
mls_convert_context(policydb_t * oldp,policydb_t * newp,context_struct_t * c)552 int mls_convert_context(policydb_t * oldp,
553 			policydb_t * newp, context_struct_t * c)
554 {
555 	level_datum_t *levdatum;
556 	cat_datum_t *catdatum;
557 	ebitmap_t bitmap;
558 	unsigned int l, i;
559 	ebitmap_node_t *cnode;
560 
561 	if (!oldp->mls)
562 		return 0;
563 
564 	for (l = 0; l < 2; l++) {
565 		levdatum =
566 		    (level_datum_t *) hashtab_search(newp->p_levels.table,
567 						     oldp->
568 						     p_sens_val_to_name[c->
569 									range.
570 									level
571 									[l].
572 									sens -
573 									1]);
574 
575 		if (!levdatum)
576 			return -EINVAL;
577 		c->range.level[l].sens = levdatum->level->sens;
578 
579 		ebitmap_init(&bitmap);
580 		ebitmap_for_each_positive_bit(&c->range.level[l].cat, cnode, i) {
581 			int rc;
582 
583 			catdatum =
584 			    (cat_datum_t *) hashtab_search(newp->p_cats.
585 							   table,
586 							   oldp->
587 							   p_cat_val_to_name
588 							   [i]);
589 			if (!catdatum)
590 				return -EINVAL;
591 			rc = ebitmap_set_bit(&bitmap,
592 					     catdatum->s.value - 1, 1);
593 			if (rc)
594 				return rc;
595 		}
596 		ebitmap_destroy(&c->range.level[l].cat);
597 		c->range.level[l].cat = bitmap;
598 	}
599 
600 	return 0;
601 }
602 
mls_compute_sid(policydb_t * policydb,const context_struct_t * scontext,const context_struct_t * tcontext,sepol_security_class_t tclass,uint32_t specified,context_struct_t * newcontext)603 int mls_compute_sid(policydb_t * policydb,
604 		    const context_struct_t * scontext,
605 		    const context_struct_t * tcontext,
606 		    sepol_security_class_t tclass,
607 		    uint32_t specified, context_struct_t * newcontext)
608 {
609 	range_trans_t rtr;
610 	struct mls_range *r;
611 	struct class_datum *cladatum;
612 	int default_range = 0;
613 
614 	if (!policydb->mls)
615 		return 0;
616 
617 	switch (specified) {
618 	case AVTAB_TRANSITION:
619 		/* Look for a range transition rule. */
620 		rtr.source_type = scontext->type;
621 		rtr.target_type = tcontext->type;
622 		rtr.target_class = tclass;
623 		r = hashtab_search(policydb->range_tr, (hashtab_key_t) &rtr);
624 		if (r)
625 			return mls_range_set(newcontext, r);
626 
627 		if (tclass && tclass <= policydb->p_classes.nprim) {
628 			cladatum = policydb->class_val_to_struct[tclass - 1];
629 			if (cladatum)
630 				default_range = cladatum->default_range;
631 		}
632 
633 		switch (default_range) {
634 		case DEFAULT_SOURCE_LOW:
635 			return mls_context_cpy_low(newcontext, scontext);
636 		case DEFAULT_SOURCE_HIGH:
637 			return mls_context_cpy_high(newcontext, scontext);
638 		case DEFAULT_SOURCE_LOW_HIGH:
639 			return mls_context_cpy(newcontext, scontext);
640 		case DEFAULT_TARGET_LOW:
641 			return mls_context_cpy_low(newcontext, tcontext);
642 		case DEFAULT_TARGET_HIGH:
643 			return mls_context_cpy_high(newcontext, tcontext);
644 		case DEFAULT_TARGET_LOW_HIGH:
645 			return mls_context_cpy(newcontext, tcontext);
646 		case DEFAULT_GLBLUB:
647 			return mls_context_glblub(newcontext, scontext, tcontext);
648 		}
649 
650 		/* Fallthrough */
651 	case AVTAB_CHANGE:
652 		if (tclass == policydb->process_class)
653 			/* Use the process MLS attributes. */
654 			return mls_copy_context(newcontext, scontext);
655 		else
656 			/* Use the process effective MLS attributes. */
657 			return mls_scopy_context(newcontext, scontext);
658 	case AVTAB_MEMBER:
659 		/* Use the process effective MLS attributes. */
660 		return mls_context_cpy_low(newcontext, scontext);
661 	default:
662 		return -EINVAL;
663 	}
664 	return -EINVAL;
665 }
666 
sepol_mls_contains(sepol_handle_t * handle,const sepol_policydb_t * policydb,const char * mls1,const char * mls2,int * response)667 int sepol_mls_contains(sepol_handle_t * handle,
668 		       const sepol_policydb_t * policydb,
669 		       const char *mls1, const char *mls2, int *response)
670 {
671 
672 	context_struct_t *ctx1 = NULL, *ctx2 = NULL;
673 	ctx1 = malloc(sizeof(context_struct_t));
674 	ctx2 = malloc(sizeof(context_struct_t));
675 	if (ctx1 == NULL || ctx2 == NULL)
676 		goto omem;
677 	context_init(ctx1);
678 	context_init(ctx2);
679 
680 	if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
681 		goto err;
682 
683 	if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
684 		goto err;
685 
686 	*response = mls_range_contains(ctx1->range, ctx2->range);
687 	context_destroy(ctx1);
688 	context_destroy(ctx2);
689 	free(ctx1);
690 	free(ctx2);
691 	return STATUS_SUCCESS;
692 
693       omem:
694 	ERR(handle, "out of memory");
695 
696       err:
697 	ERR(handle, "could not check if mls context %s contains %s",
698 	    mls1, mls2);
699 	context_destroy(ctx1);
700 	context_destroy(ctx2);
701 	free(ctx1);
702 	free(ctx2);
703 	return STATUS_ERR;
704 }
705 
sepol_mls_check(sepol_handle_t * handle,const sepol_policydb_t * policydb,const char * mls)706 int sepol_mls_check(sepol_handle_t * handle,
707 		    const sepol_policydb_t * policydb, const char *mls)
708 {
709 
710 	int ret;
711 	context_struct_t *con = malloc(sizeof(context_struct_t));
712 	if (!con) {
713 		ERR(handle, "out of memory, could not check if "
714 		    "mls context %s is valid", mls);
715 		return STATUS_ERR;
716 	}
717 	context_init(con);
718 
719 	ret = mls_from_string(handle, &policydb->p, mls, con);
720 	context_destroy(con);
721 	free(con);
722 	return ret;
723 }
724 
mls_semantic_cat_init(mls_semantic_cat_t * c)725 void mls_semantic_cat_init(mls_semantic_cat_t * c)
726 {
727 	memset(c, 0, sizeof(mls_semantic_cat_t));
728 }
729 
mls_semantic_cat_destroy(mls_semantic_cat_t * c)730 void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
731 {
732 	/* it's currently a simple struct - really nothing to destroy */
733 	return;
734 }
735 
mls_semantic_level_init(mls_semantic_level_t * l)736 void mls_semantic_level_init(mls_semantic_level_t * l)
737 {
738 	memset(l, 0, sizeof(mls_semantic_level_t));
739 }
740 
mls_semantic_level_destroy(mls_semantic_level_t * l)741 void mls_semantic_level_destroy(mls_semantic_level_t * l)
742 {
743 	mls_semantic_cat_t *cur, *next;
744 
745 	if (l == NULL)
746 		return;
747 
748 	next = l->cat;
749 	while (next) {
750 		cur = next;
751 		next = cur->next;
752 		mls_semantic_cat_destroy(cur);
753 		free(cur);
754 	}
755 }
756 
mls_semantic_level_cpy(mls_semantic_level_t * dst,const mls_semantic_level_t * src)757 int mls_semantic_level_cpy(mls_semantic_level_t * dst,
758 			   const mls_semantic_level_t * src)
759 {
760 	const mls_semantic_cat_t *cat;
761 	mls_semantic_cat_t *newcat, *lnewcat = NULL;
762 
763 	mls_semantic_level_init(dst);
764 	dst->sens = src->sens;
765 	cat = src->cat;
766 	while (cat) {
767 		newcat =
768 		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
769 		if (!newcat)
770 			goto err;
771 
772 		mls_semantic_cat_init(newcat);
773 		if (lnewcat)
774 			lnewcat->next = newcat;
775 		else
776 			dst->cat = newcat;
777 
778 		newcat->low = cat->low;
779 		newcat->high = cat->high;
780 
781 		lnewcat = newcat;
782 		cat = cat->next;
783 	}
784 	return 0;
785 
786       err:
787 	mls_semantic_level_destroy(dst);
788 	return -1;
789 }
790 
mls_semantic_range_init(mls_semantic_range_t * r)791 void mls_semantic_range_init(mls_semantic_range_t * r)
792 {
793 	mls_semantic_level_init(&r->level[0]);
794 	mls_semantic_level_init(&r->level[1]);
795 }
796 
mls_semantic_range_destroy(mls_semantic_range_t * r)797 void mls_semantic_range_destroy(mls_semantic_range_t * r)
798 {
799 	mls_semantic_level_destroy(&r->level[0]);
800 	mls_semantic_level_destroy(&r->level[1]);
801 }
802 
mls_semantic_range_cpy(mls_semantic_range_t * dst,const mls_semantic_range_t * src)803 int mls_semantic_range_cpy(mls_semantic_range_t * dst,
804 			   const mls_semantic_range_t * src)
805 {
806 	if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
807 		return -1;
808 
809 	if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
810 		mls_semantic_level_destroy(&dst->level[0]);
811 		return -1;
812 	}
813 
814 	return 0;
815 }
816