1 /* Author : Stephen Smalley, <sds@epoch.ncsc.mil> */
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/policydb/policydb.h>
31 #include <sepol/policydb/services.h>
32 #include <sepol/policydb/flask.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 
266 	if (!p->mls)
267 		return 1;
268 
269 	/*
270 	 * MLS range validity checks: high must dominate low, low level must
271 	 * be valid (category set <-> sensitivity check), and high level must
272 	 * be valid (category set <-> sensitivity check)
273 	 */
274 	if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
275 		/* High does not dominate low. */
276 		return 0;
277 
278 	for (l = 0; l < 2; l++) {
279 		if (!c->range.level[l].sens
280 		    || c->range.level[l].sens > p->p_levels.nprim)
281 			return 0;
282 		levdatum = (level_datum_t *) hashtab_search(p->p_levels.table,
283 							    p->
284 							    p_sens_val_to_name
285 							    [c->range.level[l].
286 							     sens - 1]);
287 		if (!levdatum)
288 			return 0;
289 
290 		ebitmap_for_each_bit(&c->range.level[l].cat, cnode, i) {
291 			if (ebitmap_node_get_bit(cnode, i)) {
292 				if (i > p->p_cats.nprim)
293 					return 0;
294 				if (!ebitmap_get_bit(&levdatum->level->cat, i))
295 					/*
296 					 * Category may not be associated with
297 					 * sensitivity in low level.
298 					 */
299 					return 0;
300 			}
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 (!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,context_struct_t * src)453 static inline int mls_copy_context(context_struct_t * dst,
454 				   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,context_struct_t * src)473 static inline int mls_scopy_context(context_struct_t * dst,
474 				    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,mls_range_t * range)493 static inline int mls_range_set(context_struct_t * context, 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_bit(&c->range.level[l].cat, cnode, i) {
581 			if (ebitmap_node_get_bit(cnode, i)) {
582 				int rc;
583 
584 				catdatum =
585 				    (cat_datum_t *) hashtab_search(newp->p_cats.
586 								   table,
587 								   oldp->
588 								   p_cat_val_to_name
589 								   [i]);
590 				if (!catdatum)
591 					return -EINVAL;
592 				rc = ebitmap_set_bit(&bitmap,
593 						     catdatum->s.value - 1, 1);
594 				if (rc)
595 					return rc;
596 			}
597 		}
598 		ebitmap_destroy(&c->range.level[l].cat);
599 		c->range.level[l].cat = bitmap;
600 	}
601 
602 	return 0;
603 }
604 
mls_compute_sid(policydb_t * policydb,context_struct_t * scontext,context_struct_t * tcontext,sepol_security_class_t tclass,uint32_t specified,context_struct_t * newcontext)605 int mls_compute_sid(policydb_t * policydb,
606 		    context_struct_t * scontext,
607 		    context_struct_t * tcontext,
608 		    sepol_security_class_t tclass,
609 		    uint32_t specified, context_struct_t * newcontext)
610 {
611 	range_trans_t *rtr;
612 	if (!policydb->mls)
613 		return 0;
614 
615 	switch (specified) {
616 	case AVTAB_TRANSITION:
617 		/* Look for a range transition rule. */
618 		for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
619 			if (rtr->source_type == scontext->type &&
620 			    rtr->target_type == tcontext->type &&
621 			    rtr->target_class == tclass) {
622 				/* Set the range from the rule */
623 				return mls_range_set(newcontext,
624 						     &rtr->target_range);
625 			}
626 		}
627 		/* Fallthrough */
628 	case AVTAB_CHANGE:
629 		if (tclass == SECCLASS_PROCESS)
630 			/* Use the process MLS attributes. */
631 			return mls_copy_context(newcontext, scontext);
632 		else
633 			/* Use the process effective MLS attributes. */
634 			return mls_scopy_context(newcontext, scontext);
635 	case AVTAB_MEMBER:
636 		/* Only polyinstantiate the MLS attributes if
637 		   the type is being polyinstantiated */
638 		if (newcontext->type != tcontext->type) {
639 			/* Use the process effective MLS attributes. */
640 			return mls_scopy_context(newcontext, scontext);
641 		} else {
642 			/* Use the related object MLS attributes. */
643 			return mls_copy_context(newcontext, tcontext);
644 		}
645 	default:
646 		return -EINVAL;
647 	}
648 	return -EINVAL;
649 }
650 
sepol_mls_contains(sepol_handle_t * handle,sepol_policydb_t * policydb,const char * mls1,const char * mls2,int * response)651 int sepol_mls_contains(sepol_handle_t * handle,
652 		       sepol_policydb_t * policydb,
653 		       const char *mls1, const char *mls2, int *response)
654 {
655 
656 	context_struct_t *ctx1 = NULL, *ctx2 = NULL;
657 	ctx1 = malloc(sizeof(context_struct_t));
658 	ctx2 = malloc(sizeof(context_struct_t));
659 	if (ctx1 == NULL || ctx2 == NULL)
660 		goto omem;
661 	context_init(ctx1);
662 	context_init(ctx2);
663 
664 	if (mls_from_string(handle, &policydb->p, mls1, ctx1) < 0)
665 		goto err;
666 
667 	if (mls_from_string(handle, &policydb->p, mls2, ctx2) < 0)
668 		goto err;
669 
670 	*response = mls_range_contains(ctx1->range, ctx2->range);
671 	context_destroy(ctx1);
672 	context_destroy(ctx2);
673 	free(ctx1);
674 	free(ctx2);
675 	return STATUS_SUCCESS;
676 
677       omem:
678 	ERR(handle, "out of memory");
679 
680       err:
681 	ERR(handle, "could not check if mls context %s contains %s",
682 	    mls1, mls2);
683 	context_destroy(ctx1);
684 	context_destroy(ctx2);
685 	free(ctx1);
686 	free(ctx2);
687 	return STATUS_ERR;
688 }
689 
sepol_mls_check(sepol_handle_t * handle,sepol_policydb_t * policydb,const char * mls)690 int sepol_mls_check(sepol_handle_t * handle,
691 		    sepol_policydb_t * policydb, const char *mls)
692 {
693 
694 	int ret;
695 	context_struct_t *con = malloc(sizeof(context_struct_t));
696 	if (!con) {
697 		ERR(handle, "out of memory, could not check if "
698 		    "mls context %s is valid", mls);
699 		return STATUS_ERR;
700 	}
701 	context_init(con);
702 
703 	ret = mls_from_string(handle, &policydb->p, mls, con);
704 	context_destroy(con);
705 	free(con);
706 	return ret;
707 }
708 
mls_semantic_cat_init(mls_semantic_cat_t * c)709 void mls_semantic_cat_init(mls_semantic_cat_t * c)
710 {
711 	memset(c, 0, sizeof(mls_semantic_cat_t));
712 }
713 
mls_semantic_cat_destroy(mls_semantic_cat_t * c)714 void mls_semantic_cat_destroy(mls_semantic_cat_t * c __attribute__ ((unused)))
715 {
716 	/* it's currently a simple struct - really nothing to destroy */
717 	return;
718 }
719 
mls_semantic_level_init(mls_semantic_level_t * l)720 void mls_semantic_level_init(mls_semantic_level_t * l)
721 {
722 	memset(l, 0, sizeof(mls_semantic_level_t));
723 }
724 
mls_semantic_level_destroy(mls_semantic_level_t * l)725 void mls_semantic_level_destroy(mls_semantic_level_t * l)
726 {
727 	mls_semantic_cat_t *cur, *next;
728 
729 	if (l == NULL)
730 		return;
731 
732 	next = l->cat;
733 	while (next) {
734 		cur = next;
735 		next = cur->next;
736 		mls_semantic_cat_destroy(cur);
737 		free(cur);
738 	}
739 }
740 
mls_semantic_level_cpy(mls_semantic_level_t * dst,mls_semantic_level_t * src)741 int mls_semantic_level_cpy(mls_semantic_level_t * dst,
742 			   mls_semantic_level_t * src)
743 {
744 	mls_semantic_cat_t *cat, *newcat, *lnewcat = NULL;
745 
746 	mls_semantic_level_init(dst);
747 	dst->sens = src->sens;
748 	cat = src->cat;
749 	while (cat) {
750 		newcat =
751 		    (mls_semantic_cat_t *) malloc(sizeof(mls_semantic_cat_t));
752 		if (!newcat)
753 			goto err;
754 
755 		mls_semantic_cat_init(newcat);
756 		if (lnewcat)
757 			lnewcat->next = newcat;
758 		else
759 			dst->cat = newcat;
760 
761 		newcat->low = cat->low;
762 		newcat->high = cat->high;
763 
764 		lnewcat = newcat;
765 		cat = cat->next;
766 	}
767 	return 0;
768 
769       err:
770 	mls_semantic_level_destroy(dst);
771 	return -1;
772 }
773 
mls_semantic_range_init(mls_semantic_range_t * r)774 void mls_semantic_range_init(mls_semantic_range_t * r)
775 {
776 	mls_semantic_level_init(&r->level[0]);
777 	mls_semantic_level_init(&r->level[1]);
778 }
779 
mls_semantic_range_destroy(mls_semantic_range_t * r)780 void mls_semantic_range_destroy(mls_semantic_range_t * r)
781 {
782 	mls_semantic_level_destroy(&r->level[0]);
783 	mls_semantic_level_destroy(&r->level[1]);
784 }
785 
mls_semantic_range_cpy(mls_semantic_range_t * dst,mls_semantic_range_t * src)786 int mls_semantic_range_cpy(mls_semantic_range_t * dst,
787 			   mls_semantic_range_t * src)
788 {
789 	if (mls_semantic_level_cpy(&dst->level[0], &src->level[0]) < 0)
790 		return -1;
791 
792 	if (mls_semantic_level_cpy(&dst->level[1], &src->level[1]) < 0) {
793 		mls_semantic_level_destroy(&dst->level[0]);
794 		return -1;
795 	}
796 
797 	return 0;
798 }
799