ia64/xen-unstable

view tools/security/secpol_xml2bin.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children b3a255e88810
line source
1 /****************************************************************
2 * secpol_xml2bin.c
3 *
4 * Copyright (C) 2005 IBM Corporation
5 *
6 * Author: Reiner Sailer <sailer@us.ibm.com>
7 *
8 * Maintained:
9 * Reiner Sailer <sailer@us.ibm.com>
10 * Ray Valdez <rvaldez@us.ibm.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation, version 2 of the
15 * License.
16 *
17 * sHype policy translation tool. This tool takes an XML
18 * policy specification as input and produces a binary
19 * policy file that can be loaded into Xen through the
20 * ACM operations (secpol_tool loadpolicy) interface or at
21 * boot time (grub module parameter)
22 *
23 * indent -i4 -kr -nut
24 */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <libgen.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/queue.h>
35 #include <netinet/in.h>
36 #include <libxml/xmlschemas.h>
37 #include <libxml/parser.h>
38 #include <libxml/tree.h>
39 #include <libxml/xmlreader.h>
40 #include "secpol_compat.h"
41 #include <xen/acm.h>
43 #include "secpol_xml2bin.h"
45 #define DEBUG 0
47 /* primary / secondary policy component setting */
48 enum policycomponent { CHWALL, STE, NULLPOLICY }
49 primary = NULLPOLICY, secondary = NULLPOLICY;
51 /* general list element for ste and chwall type queues */
52 struct type_entry {
53 TAILQ_ENTRY(type_entry) entries;
54 char *name; /* name of type from xml file */
55 type_t mapping; /* type mapping into 16bit */
56 };
58 TAILQ_HEAD(tailhead, type_entry) ste_head, chwall_head;
60 /* general list element for all label queues */
61 enum label_type { VM, RES, ANY };
62 struct ssid_entry {
63 TAILQ_ENTRY(ssid_entry) entries;
64 char *name; /* label name */
65 enum label_type type; /* type: VM / RESOURCE LABEL */
66 u_int32_t num; /* ssid or referenced ssid */
67 int is_ref; /* if this entry references earlier ssid number */
68 unsigned char *row; /* index of types (if not a reference) */
69 };
71 TAILQ_HEAD(tailhead_ssid, ssid_entry) ste_ssid_head, chwall_ssid_head,
72 conflictsets_head;
73 struct ssid_entry *current_chwall_ssid_p = NULL;
74 struct ssid_entry *current_ste_ssid_p = NULL;
75 struct ssid_entry *current_conflictset_p = NULL;
77 /* which label to assign to dom0 during boot */
78 char *bootstrap_label;
80 u_int32_t max_ste_ssids = 0;
81 u_int32_t max_chwall_ssids = 0;
82 u_int32_t max_chwall_labels = 0;
83 u_int32_t max_ste_labels = 0;
84 u_int32_t max_conflictsets = 0;
86 char *current_ssid_name; /* store name until structure is allocated */
87 char *current_conflictset_name; /* store name until structure is allocated */
89 /* dynamic list of type mappings for STE */
90 u_int32_t max_ste_types = 0;
92 /* dynamic list of type mappings for CHWALL */
93 u_int32_t max_chwall_types = 0;
95 /* dynamic list of conflict sets */
96 int max_conflict_set = 0;
98 /* which policies are defined */
99 int have_ste = 0;
100 int have_chwall = 0;
102 /* input/output file names */
103 char *policy_filename = NULL,
104 *label_filename = NULL,
105 *binary_filename = NULL, *mapping_filename = NULL;
107 void usage(char *prg)
108 {
109 printf("usage:\n%s policyname[-policy.xml/-security_label_template.xml]\n",
110 prg);
111 exit(EXIT_FAILURE);
112 }
115 /***************** policy-related parsing *********************/
117 char *type_by_mapping(struct tailhead *head, u_int32_t mapping)
118 {
119 struct type_entry *np;
120 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
121 if (np->mapping == mapping)
122 return np->name;
123 return NULL;
124 }
127 struct type_entry *lookup(struct tailhead *head, char *name)
128 {
129 struct type_entry *np;
130 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
131 if (!(strcmp(np->name, name)))
132 return np;
133 return NULL;
134 }
136 /* enforces single-entry lists */
137 int add_entry(struct tailhead *head, char *name, type_t mapping)
138 {
139 struct type_entry *e;
140 if (lookup(head, name))
141 {
142 printf("Error: Type >%s< defined more than once.\n", name);
143 return -EFAULT; /* already in the list */
144 }
145 if (!(e = malloc(sizeof(struct type_entry))))
146 return -ENOMEM;
148 e->name = name;
149 e->mapping = mapping;
150 TAILQ_INSERT_TAIL(head, e, entries);
151 return 0;
152 }
154 int totoken(char *tok)
155 {
156 int i;
157 for (i = 0; token[i] != NULL; i++)
158 if (!strcmp(token[i], tok))
159 return i;
160 return -EFAULT;
161 }
163 /* conflictsets use the same data structure as ssids; since
164 * they are similar in structure (set of types)
165 */
166 int init_next_conflictset(void)
167 {
168 struct ssid_entry *conflictset = malloc(sizeof(struct ssid_entry));
170 if (!conflictset)
171 return -ENOMEM;
173 conflictset->name = current_conflictset_name;
174 conflictset->num = max_conflictsets++;
175 conflictset->is_ref = 0; /* n/a for conflictsets */
176 /**
177 * row: allocate one byte per type;
178 * [i] != 0 --> mapped type >i< is part of the conflictset
179 */
180 conflictset->row = malloc(max_chwall_types);
181 if (!conflictset->row)
182 return -ENOMEM;
184 memset(conflictset->row, 0, max_chwall_types);
185 TAILQ_INSERT_TAIL(&conflictsets_head, conflictset, entries);
186 current_conflictset_p = conflictset;
187 return 0;
188 }
190 int register_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
191 {
192 xmlChar *text;
193 struct type_entry *e;
196 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
197 if (!text)
198 {
199 printf("Error reading type name!\n");
200 return -EFAULT;
201 }
203 switch (state) {
204 case XML2BIN_stetype_S:
205 if (add_entry(&ste_head, (char *) text, max_ste_types))
206 {
207 xmlFree(text);
208 return -EFAULT;
209 }
210 max_ste_types++;
211 break;
213 case XML2BIN_chwalltype_S:
214 if (add_entry(&chwall_head, (char *) text, max_chwall_types))
215 {
216 xmlFree(text);
217 return -EFAULT;
218 }
219 max_chwall_types++;
220 break;
222 case XML2BIN_conflictsettype_S:
223 /* a) search the type in the chwall_type list */
224 e = lookup(&chwall_head, (char *) text);
225 if (e == NULL)
226 {
227 printf("CS type >%s< not a CHWALL type.\n", text);
228 xmlFree(text);
229 return -EFAULT;
230 }
231 /* b) add type entry to the current cs set */
232 if (current_conflictset_p->row[e->mapping])
233 {
234 printf("ERROR: Double entry of type >%s< in conflict set %d.\n",
235 text, current_conflictset_p->num);
236 xmlFree(text);
237 return -EFAULT;
238 }
239 current_conflictset_p->row[e->mapping] = 1;
240 break;
242 default:
243 printf("Incorrect type environment (state = %lx, text = %s).\n",
244 state, text);
245 xmlFree(text);
246 return -EFAULT;
247 }
248 return 0;
249 }
251 void set_component_type(xmlNode * cur_node, enum policycomponent pc)
252 {
253 xmlChar *order;
255 if ((order = xmlGetProp(cur_node, (xmlChar *) PRIMARY_COMPONENT_ATTR_NAME))) {
256 if (strcmp((char *) order, PRIMARY_COMPONENT))
257 {
258 printf("ERROR: Illegal attribut value >order=%s<.\n",
259 (char *) order);
260 xmlFree(order);
261 exit(EXIT_FAILURE);
262 }
263 if (primary != NULLPOLICY)
264 {
265 printf("ERROR: Primary Policy Component set twice!\n");
266 exit(EXIT_FAILURE);
267 }
268 primary = pc;
269 xmlFree(order);
270 }
271 }
273 void walk_policy(xmlNode * start, xmlDocPtr doc, unsigned long state)
274 {
275 xmlNode *cur_node = NULL;
276 int code;
278 for (cur_node = start; cur_node; cur_node = cur_node->next)
279 {
280 if ((code = totoken((char *) cur_node->name)) < 0)
281 {
282 printf("Unknown token: >%s<. Aborting.\n", cur_node->name);
283 exit(EXIT_FAILURE);
284 }
285 switch (code) { /* adjust state to new state */
286 case XML2BIN_SECPOL:
287 case XML2BIN_STETYPES:
288 case XML2BIN_CHWALLTYPES:
289 case XML2BIN_CONFLICTSETS:
290 walk_policy(cur_node->children, doc, state | (1 << code));
291 break;
293 case XML2BIN_STE:
294 if (WRITTEN_AGAINST_ACM_STE_VERSION != ACM_STE_VERSION)
295 {
296 printf("ERROR: This program was written against another STE version.\n");
297 exit(EXIT_FAILURE);
298 }
299 have_ste = 1;
300 set_component_type(cur_node, STE);
301 walk_policy(cur_node->children, doc, state | (1 << code));
302 break;
304 case XML2BIN_CHWALL:
305 if (WRITTEN_AGAINST_ACM_CHWALL_VERSION != ACM_CHWALL_VERSION)
306 {
307 printf("ERROR: This program was written against another CHWALL version.\n");
308 exit(EXIT_FAILURE);
309 }
310 have_chwall = 1;
311 set_component_type(cur_node, CHWALL);
312 walk_policy(cur_node->children, doc, state | (1 << code));
313 break;
315 case XML2BIN_CSTYPE:
316 current_conflictset_name =
317 (char *) xmlGetProp(cur_node, (xmlChar *) "name");
318 if (!current_conflictset_name)
319 current_conflictset_name = "";
321 if (init_next_conflictset())
322 {
323 printf
324 ("ERROR: creating new conflictset structure failed.\n");
325 exit(EXIT_FAILURE);
326 }
327 walk_policy(cur_node->children, doc, state | (1 << code));
328 break;
330 case XML2BIN_TYPE:
331 if (register_type(cur_node, doc, state))
332 exit(EXIT_FAILURE);
333 /* type leaf */
334 break;
336 case XML2BIN_TEXT:
337 case XML2BIN_COMMENT:
338 case XML2BIN_POLICYHEADER:
339 /* leaf - nothing to do */
340 break;
342 default:
343 printf("Unkonwn token Error (%d)\n", code);
344 exit(EXIT_FAILURE);
345 }
347 }
348 return;
349 }
351 int create_type_mapping(xmlDocPtr doc)
352 {
353 xmlNode *root_element = xmlDocGetRootElement(doc);
354 struct type_entry *te;
355 struct ssid_entry *se;
356 int i;
358 printf("Creating ssid mappings ...\n");
360 /* initialize the ste and chwall type lists */
361 TAILQ_INIT(&ste_head);
362 TAILQ_INIT(&chwall_head);
363 TAILQ_INIT(&conflictsets_head);
365 walk_policy(root_element, doc, XML2BIN_NULL);
367 /* determine primary/secondary policy component orders */
368 if ((primary == NULLPOLICY) && have_chwall)
369 primary = CHWALL; /* default if not set */
370 else if ((primary == NULLPOLICY) && have_ste)
371 primary = STE;
373 switch (primary) {
375 case CHWALL:
376 if (have_ste)
377 secondary = STE;
378 /* else default = NULLPOLICY */
379 break;
381 case STE:
382 if (have_chwall)
383 secondary = CHWALL;
384 /* else default = NULLPOLICY */
385 break;
387 default:
388 /* NULL/NULL policy */
389 break;
390 }
392 if (!DEBUG)
393 return 0;
395 /* print queues */
396 if (have_ste)
397 {
398 printf("STE-Type queue (%s):\n",
399 (primary == STE) ? "PRIMARY" : "SECONDARY");
400 for (te = ste_head.tqh_first; te != NULL;
401 te = te->entries.tqe_next)
402 printf("name=%22s, map=%x\n", te->name, te->mapping);
403 }
404 if (have_chwall)
405 {
406 printf("CHWALL-Type queue (%s):\n",
407 (primary == CHWALL) ? "PRIMARY" : "SECONDARY");
408 for (te = chwall_head.tqh_first; te != NULL;
409 te = te->entries.tqe_next)
410 printf("name=%s, map=%x\n", te->name, te->mapping);
412 printf("Conflictset queue (max=%d):\n", max_conflictsets);
413 for (se = conflictsets_head.tqh_first; se != NULL;
414 se = se->entries.tqe_next)
415 {
416 printf("conflictset name >%s<\n",
417 se->name ? se->name : "NONAME");
418 for (i = 0; i < max_chwall_types; i++)
419 if (se->row[i])
420 printf("#%x ", i);
421 printf("\n");
422 }
423 }
424 return 0;
425 }
428 /***************** template-related parsing *********************/
430 /* add default ssid at head of ssid queues */
431 int init_ssid_queues(void)
432 {
433 struct ssid_entry *default_ssid_chwall, *default_ssid_ste;
435 default_ssid_chwall = malloc(sizeof(struct ssid_entry));
436 default_ssid_ste = malloc(sizeof(struct ssid_entry));
438 if ((!default_ssid_chwall) || (!default_ssid_ste))
439 return -ENOMEM;
441 /* default chwall ssid */
442 default_ssid_chwall->name = "DEFAULT";
443 default_ssid_chwall->num = max_chwall_ssids++;
444 default_ssid_chwall->is_ref = 0;
445 default_ssid_chwall->type = ANY;
447 default_ssid_chwall->row = malloc(max_chwall_types);
449 if (!default_ssid_chwall->row)
450 return -ENOMEM;
452 memset(default_ssid_chwall->row, 0, max_chwall_types);
454 TAILQ_INSERT_TAIL(&chwall_ssid_head, default_ssid_chwall, entries);
455 current_chwall_ssid_p = default_ssid_chwall;
456 max_chwall_labels++;
458 /* default ste ssid */
459 default_ssid_ste->name = "DEFAULT";
460 default_ssid_ste->num = max_ste_ssids++;
461 default_ssid_ste->is_ref = 0;
462 default_ssid_ste->type = ANY;
464 default_ssid_ste->row = malloc(max_ste_types);
466 if (!default_ssid_ste->row)
467 return -ENOMEM;
469 memset(default_ssid_ste->row, 0, max_ste_types);
471 TAILQ_INSERT_TAIL(&ste_ssid_head, default_ssid_ste, entries);
472 current_ste_ssid_p = default_ssid_ste;
473 max_ste_labels++;
474 return 0;
475 }
477 int init_next_chwall_ssid(unsigned long state)
478 {
479 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
481 if (!ssid)
482 return -ENOMEM;
484 ssid->name = current_ssid_name;
485 ssid->num = max_chwall_ssids++;
486 ssid->is_ref = 0;
488 if (state & (1 << XML2BIN_VM))
489 ssid->type = VM;
490 else
491 ssid->type = RES;
492 /**
493 * row: allocate one byte per type;
494 * [i] != 0 --> mapped type >i< is part of the ssid
495 */
496 ssid->row = malloc(max_chwall_types);
497 if (!ssid->row)
498 return -ENOMEM;
500 memset(ssid->row, 0, max_chwall_types);
501 TAILQ_INSERT_TAIL(&chwall_ssid_head, ssid, entries);
502 current_chwall_ssid_p = ssid;
503 max_chwall_labels++;
504 return 0;
505 }
507 int init_next_ste_ssid(unsigned long state)
508 {
509 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
511 if (!ssid)
512 return -ENOMEM;
514 ssid->name = current_ssid_name;
515 ssid->num = max_ste_ssids++;
516 ssid->is_ref = 0;
518 if (state & (1 << XML2BIN_VM))
519 ssid->type = VM;
520 else
521 ssid->type = RES;
523 /**
524 * row: allocate one byte per type;
525 * [i] != 0 --> mapped type >i< is part of the ssid
526 */
527 ssid->row = malloc(max_ste_types);
528 if (!ssid->row)
529 return -ENOMEM;
531 memset(ssid->row, 0, max_ste_types);
532 TAILQ_INSERT_TAIL(&ste_ssid_head, ssid, entries);
533 current_ste_ssid_p = ssid;
534 max_ste_labels++;
536 return 0;
537 }
540 /* adds a type to the current ssid */
541 int add_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
542 {
543 xmlChar *text;
544 struct type_entry *e;
546 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
547 if (!text)
548 {
549 printf("Error reading type name!\n");
550 return -EFAULT;
551 }
552 /* same for all: 1. lookup type mapping, 2. mark type in ssid */
553 switch (state) {
554 case XML2BIN_VM_STE_S:
555 case XML2BIN_RES_STE_S:
556 /* lookup the type mapping and include the type mapping into the array */
557 if (!(e = lookup(&ste_head, (char *) text)))
558 {
559 printf("ERROR: unknown VM STE type >%s<.\n", text);
560 exit(EXIT_FAILURE);
561 }
562 if (current_ste_ssid_p->row[e->mapping])
563 printf("Warning: double entry of VM STE type >%s<.\n", text);
565 current_ste_ssid_p->row[e->mapping] = 1;
566 break;
568 case XML2BIN_VM_CHWALL_S:
569 /* lookup the type mapping and include the type mapping into the array */
570 if (!(e = lookup(&chwall_head, (char *) text)))
571 {
572 printf("ERROR: unknown VM CHWALL type >%s<.\n", text);
573 exit(EXIT_FAILURE);
574 }
575 if (current_chwall_ssid_p->row[e->mapping])
576 printf("Warning: double entry of VM CHWALL type >%s<.\n",
577 text);
579 current_chwall_ssid_p->row[e->mapping] = 1;
580 break;
582 default:
583 printf("Incorrect type environment (state = %lx, text = %s).\n",
584 state, text);
585 xmlFree(text);
586 return -EFAULT;
587 }
588 return 0;
589 }
591 void set_bootstrap_label(xmlNode * cur_node)
592 {
593 xmlChar *order;
595 if ((order = xmlGetProp(cur_node, (xmlChar *) BOOTSTRAP_LABEL_ATTR_NAME)))
596 bootstrap_label = (char *)order;
597 else {
598 printf("ERROR: No bootstrap label defined!\n");
599 exit(EXIT_FAILURE);
600 }
601 }
603 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state)
604 {
605 xmlNode *cur_node = NULL;
606 int code;
608 for (cur_node = start; cur_node; cur_node = cur_node->next)
609 {
610 if ((code = totoken((char *) cur_node->name)) < 0)
611 {
612 printf("Unkonwn token: >%s<. Aborting.\n", cur_node->name);
613 exit(EXIT_FAILURE);
614 }
615 switch (code) { /* adjust state to new state */
617 case XML2BIN_SUBJECTS:
618 set_bootstrap_label(cur_node);
619 /* fall through */
620 case XML2BIN_VM:
621 case XML2BIN_RES:
622 case XML2BIN_SECTEMPLATE:
623 case XML2BIN_OBJECTS:
624 walk_labels(cur_node->children, doc, state | (1 << code));
625 break;
627 case XML2BIN_STETYPES:
628 /* create new ssid entry to use and point current to it */
629 if (init_next_ste_ssid(state))
630 {
631 printf("ERROR: creating new ste ssid structure failed.\n");
632 exit(EXIT_FAILURE);
633 }
634 walk_labels(cur_node->children, doc, state | (1 << code));
636 break;
638 case XML2BIN_CHWALLTYPES:
639 /* create new ssid entry to use and point current to it */
640 if (init_next_chwall_ssid(state))
641 {
642 printf("ERROR: creating new chwall ssid structure failed.\n");
643 exit(EXIT_FAILURE);
644 }
645 walk_labels(cur_node->children, doc, state | (1 << code));
647 break;
649 case XML2BIN_TYPE:
650 /* add type to current ssid */
651 if (add_type(cur_node, doc, state))
652 exit(EXIT_FAILURE);
653 break;
655 case XML2BIN_NAME:
656 if ((state != XML2BIN_VM_S) && (state != XML2BIN_RES_S))
657 {
658 printf("ERROR: >name< out of VM/RES context.\n");
659 exit(EXIT_FAILURE);
660 }
661 current_ssid_name = (char *)
662 xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
664 if (!current_ssid_name)
665 {
666 printf("ERROR: empty >name<!\n");
667 exit(EXIT_FAILURE);
668 }
669 break;
671 case XML2BIN_TEXT:
672 case XML2BIN_COMMENT:
673 case XML2BIN_LABELHEADER:
674 break;
676 default:
677 printf("Unkonwn token Error (%d)\n", code);
678 exit(EXIT_FAILURE);
679 }
681 }
682 return;
683 }
685 /* this function walks through a ssid queue
686 * and transforms double entries into references
687 * of the first definition (we need to keep the
688 * entry to map labels but we don't want double
689 * ssids in the binary policy
690 */
691 void
692 remove_doubles(struct tailhead_ssid *head,
693 u_int32_t max_types, u_int32_t * max_ssids)
694 {
695 struct ssid_entry *np, *ni;
697 /* walk once through the list */
698 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
699 {
700 /* now search from the start until np for the same entry */
701 for (ni = head->tqh_first; ni != np; ni = ni->entries.tqe_next)
702 {
703 if (ni->is_ref)
704 continue;
705 if (memcmp(np->row, ni->row, max_types))
706 continue;
707 /* found one, set np reference to ni */
708 np->is_ref = 1;
709 np->num = ni->num;
710 (*max_ssids)--;
711 }
712 }
714 /* now minimize the ssid numbers used (doubles introduce holes) */
715 (*max_ssids) = 0; /* reset */
717 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
718 {
719 if (np->is_ref)
720 continue;
722 if (np->num != (*max_ssids)) {
723 /* first reset all later references to the new max_ssid */
724 for (ni = np->entries.tqe_next; ni != NULL; ni = ni->entries.tqe_next)
725 {
726 if (ni->num == np->num)
727 ni->num = (*max_ssids);
728 }
729 /* now reset num */
730 np->num = (*max_ssids)++;
731 }
732 else
733 (*max_ssids)++;
734 }
735 }
737 /*
738 * will go away as soon as we have non-static bootstrap ssidref for dom0
739 */
740 void fixup_bootstrap_label(struct tailhead_ssid *head,
741 u_int32_t max_types, u_int32_t * max_ssids)
742 {
743 struct ssid_entry *np;
744 int i;
746 /* should not happen if xml / xsd checks work */
747 if (!bootstrap_label)
748 {
749 printf("ERROR: No bootstrap label defined.\n");
750 exit(EXIT_FAILURE);
751 }
753 /* search bootstrap_label */
754 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
755 {
756 if (!strcmp(np->name, bootstrap_label))
757 {
758 break;
759 }
760 }
762 if (!np) {
763 /* bootstrap label not found */
764 printf("ERROR: Bootstrap label >%s< not found.\n", bootstrap_label);
765 exit(EXIT_FAILURE);
766 }
768 /* move this entry ahead in the list right after the default entry so it
769 * receives ssidref 1/1 */
770 TAILQ_REMOVE(head, np, entries);
771 TAILQ_INSERT_AFTER(head, head->tqh_first, np, entries);
773 /* renumber the ssids (we could also just switch places with 1st element) */
774 for (np = head->tqh_first, i=0; np != NULL; np = np->entries.tqe_next, i++)
775 np->num = i;
777 }
779 int create_ssid_mapping(xmlDocPtr doc)
780 {
781 xmlNode *root_element = xmlDocGetRootElement(doc);
782 struct ssid_entry *np;
783 int i;
785 printf("Creating label mappings ...\n");
786 /* initialize the ste and chwall type lists */
787 TAILQ_INIT(&chwall_ssid_head);
788 TAILQ_INIT(&ste_ssid_head);
790 /* init with default ssids */
791 if (init_ssid_queues())
792 {
793 printf("ERROR adding default ssids.\n");
794 exit(EXIT_FAILURE);
795 }
797 /* now walk the template DOM tree and fill in ssids */
798 walk_labels(root_element, doc, XML2BIN_NULL);
800 /*
801 * now sort bootstrap label to the head of the list
802 * (for now), dom0 assumes its label in the first
803 * defined ssidref (1/1). 0/0 is the default non-Label
804 */
805 if (have_chwall)
806 fixup_bootstrap_label(&chwall_ssid_head, max_chwall_types,
807 &max_chwall_ssids);
808 if (have_ste)
809 fixup_bootstrap_label(&ste_ssid_head, max_ste_types,
810 &max_ste_ssids);
812 /* remove any double entries (insert reference instead) */
813 if (have_chwall)
814 remove_doubles(&chwall_ssid_head, max_chwall_types,
815 &max_chwall_ssids);
816 if (have_ste)
817 remove_doubles(&ste_ssid_head, max_ste_types,
818 &max_ste_ssids);
820 if (!DEBUG)
821 return 0;
823 /* print queues */
824 if (have_chwall)
825 {
826 printf("CHWALL SSID queue (max ssidrefs=%d):\n", max_chwall_ssids);
827 np = NULL;
828 for (np = chwall_ssid_head.tqh_first; np != NULL;
829 np = np->entries.tqe_next)
830 {
831 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
832 if (np->is_ref)
833 printf("REFERENCE");
834 else
835 for (i = 0; i < max_chwall_types; i++)
836 if (np->row[i])
837 printf("#%02d ", i);
838 printf("\n\n");
839 }
840 }
841 if (have_ste)
842 {
843 printf("STE SSID queue (max ssidrefs=%d):\n", max_ste_ssids);
844 np = NULL;
845 for (np = ste_ssid_head.tqh_first; np != NULL;
846 np = np->entries.tqe_next)
847 {
848 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
849 if (np->is_ref)
850 printf("REFERENCE");
851 else
852 for (i = 0; i < max_ste_types; i++)
853 if (np->row[i])
854 printf("#%02d ", i);
855 printf("\n\n");
856 }
857 }
858 return 0;
859 }
861 /***************** writing the binary policy *********************/
863 /*
864 * the mapping file is ascii-based since it will likely be used from
865 * within scripts (using awk, grep, etc.);
866 *
867 * We print from high-level to low-level information so that with one
868 * pass, any symbol can be resolved (e.g. Label -> types)
869 */
870 int write_mapping(char *filename)
871 {
873 struct ssid_entry *e;
874 struct type_entry *t;
875 int i;
876 FILE *file;
878 if ((file = fopen(filename, "w")) == NULL)
879 return -EIO;
881 fprintf(file, "MAGIC %08x\n", ACM_MAGIC);
882 fprintf(file, "POLICY %s\n",
883 basename(policy_filename));
884 fprintf(file, "BINARY %s\n",
885 basename(binary_filename));
886 if (have_chwall)
887 {
888 fprintf(file, "MAX-CHWALL-TYPES %08x\n", max_chwall_types);
889 fprintf(file, "MAX-CHWALL-SSIDS %08x\n", max_chwall_ssids);
890 fprintf(file, "MAX-CHWALL-LABELS %08x\n", max_chwall_labels);
891 }
892 if (have_ste)
893 {
894 fprintf(file, "MAX-STE-TYPES %08x\n", max_ste_types);
895 fprintf(file, "MAX-STE-SSIDS %08x\n", max_ste_ssids);
896 fprintf(file, "MAX-STE-LABELS %08x\n", max_ste_labels);
897 }
898 fprintf(file, "\n");
900 /* primary / secondary order for combined ssid synthesis/analysis
901 * if no primary is named, then chwall is primary */
902 switch (primary) {
903 case CHWALL:
904 fprintf(file, "PRIMARY CHWALL\n");
905 break;
907 case STE:
908 fprintf(file, "PRIMARY STE\n");
909 break;
911 default:
912 fprintf(file, "PRIMARY NULL\n");
913 break;
914 }
916 switch (secondary) {
917 case CHWALL:
918 fprintf(file, "SECONDARY CHWALL\n");
919 break;
921 case STE:
922 fprintf(file, "SECONDARY STE\n");
923 break;
925 default:
926 fprintf(file, "SECONDARY NULL\n");
927 break;
928 }
929 fprintf(file, "\n");
931 /* first labels to ssid mappings */
932 if (have_chwall)
933 {
934 for (e = chwall_ssid_head.tqh_first; e != NULL;
935 e = e->entries.tqe_next)
936 {
937 fprintf(file, "LABEL->SSID %s CHWALL %-25s %8x\n",
938 (e->type ==
939 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
940 e->name, e->num);
941 }
942 fprintf(file, "\n");
943 }
944 if (have_ste)
945 {
946 for (e = ste_ssid_head.tqh_first; e != NULL;
947 e = e->entries.tqe_next)
948 {
949 fprintf(file, "LABEL->SSID %s STE %-25s %8x\n",
950 (e->type ==
951 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
952 e->name, e->num);
953 }
954 fprintf(file, "\n");
955 }
957 /* second ssid to type mappings */
958 if (have_chwall)
959 {
960 for (e = chwall_ssid_head.tqh_first; e != NULL;
961 e = e->entries.tqe_next)
962 {
963 if (e->is_ref)
964 continue;
966 fprintf(file, "SSID->TYPE CHWALL %08x", e->num);
968 for (i = 0; i < max_chwall_types; i++)
969 if (e->row[i])
970 fprintf(file, " %s", type_by_mapping(&chwall_head, i));
972 fprintf(file, "\n");
973 }
974 fprintf(file, "\n");
975 }
976 if (have_ste) {
977 for (e = ste_ssid_head.tqh_first; e != NULL;
978 e = e->entries.tqe_next)
979 {
980 if (e->is_ref)
981 continue;
983 fprintf(file, "SSID->TYPE STE %08x", e->num);
985 for (i = 0; i < max_ste_types; i++)
986 if (e->row[i])
987 fprintf(file, " %s", type_by_mapping(&ste_head, i));
989 fprintf(file, "\n");
990 }
991 fprintf(file, "\n");
992 }
993 /* third type mappings */
994 if (have_chwall)
995 {
996 for (t = chwall_head.tqh_first; t != NULL; t = t->entries.tqe_next)
997 {
998 fprintf(file, "TYPE CHWALL %-25s %8x\n",
999 t->name, t->mapping);
1001 fprintf(file, "\n");
1003 if (have_ste) {
1004 for (t = ste_head.tqh_first; t != NULL; t = t->entries.tqe_next)
1006 fprintf(file, "TYPE STE %-25s %8x\n",
1007 t->name, t->mapping);
1009 fprintf(file, "\n");
1011 fclose(file);
1012 return 0;
1015 unsigned char *write_chwall_binary(u_int32_t * len_chwall)
1017 unsigned char *buf, *ptr;
1018 struct acm_chwall_policy_buffer *chwall_header;
1019 u_int32_t len;
1020 struct ssid_entry *e;
1021 int i;
1023 if (!have_chwall)
1024 return NULL;
1026 len = sizeof(struct acm_chwall_policy_buffer) +
1027 sizeof(type_t) * max_chwall_types * max_chwall_ssids +
1028 sizeof(type_t) * max_chwall_types * max_conflictsets;
1030 buf = malloc(len);
1031 ptr = buf;
1033 if (!buf)
1035 printf("ERROR: out of memory allocating chwall buffer.\n");
1036 exit(EXIT_FAILURE);
1038 /* chwall has 3 parts : header, types, conflictsets */
1040 chwall_header = (struct acm_chwall_policy_buffer *) buf;
1041 chwall_header->chwall_max_types = htonl(max_chwall_types);
1042 chwall_header->chwall_max_ssidrefs = htonl(max_chwall_ssids);
1043 chwall_header->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1044 chwall_header->policy_version = htonl(ACM_CHWALL_VERSION);
1045 chwall_header->chwall_ssid_offset =
1046 htonl(sizeof(struct acm_chwall_policy_buffer));
1047 chwall_header->chwall_max_conflictsets = htonl(max_conflictsets);
1048 chwall_header->chwall_conflict_sets_offset =
1049 htonl(ntohl(chwall_header->chwall_ssid_offset) +
1050 sizeof(domaintype_t) * max_chwall_ssids * max_chwall_types);
1051 chwall_header->chwall_running_types_offset = 0; /* not set, only retrieved */
1052 chwall_header->chwall_conflict_aggregate_offset = 0; /* not set, only retrieved */
1053 ptr += sizeof(struct acm_chwall_policy_buffer);
1055 /* types */
1056 for (e = chwall_ssid_head.tqh_first; e != NULL;
1057 e = e->entries.tqe_next)
1059 if (e->is_ref)
1060 continue;
1062 for (i = 0; i < max_chwall_types; i++)
1063 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1065 ptr += sizeof(type_t) * max_chwall_types;
1068 /* conflictsets */
1069 for (e = conflictsets_head.tqh_first; e != NULL;
1070 e = e->entries.tqe_next)
1072 for (i = 0; i < max_chwall_types; i++)
1073 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1075 ptr += sizeof(type_t) * max_chwall_types;
1078 if ((ptr - buf) != len)
1080 printf("ERROR: wrong lengths in %s.\n", __func__);
1081 exit(EXIT_FAILURE);
1084 (*len_chwall) = len;
1085 return buf;
1088 unsigned char *write_ste_binary(u_int32_t * len_ste)
1090 unsigned char *buf, *ptr;
1091 struct acm_ste_policy_buffer *ste_header;
1092 struct ssid_entry *e;
1093 u_int32_t len;
1094 int i;
1096 if (!have_ste)
1097 return NULL;
1099 len = sizeof(struct acm_ste_policy_buffer) +
1100 sizeof(type_t) * max_ste_types * max_ste_ssids;
1102 buf = malloc(len);
1103 ptr = buf;
1105 if (!buf)
1107 printf("ERROR: out of memory allocating chwall buffer.\n");
1108 exit(EXIT_FAILURE);
1111 /* fill buffer */
1112 ste_header = (struct acm_ste_policy_buffer *) buf;
1113 ste_header->policy_version = htonl(ACM_STE_VERSION);
1114 ste_header->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1115 ste_header->ste_max_types = htonl(max_ste_types);
1116 ste_header->ste_max_ssidrefs = htonl(max_ste_ssids);
1117 ste_header->ste_ssid_offset =
1118 htonl(sizeof(struct acm_ste_policy_buffer));
1120 ptr += sizeof(struct acm_ste_policy_buffer);
1122 /* types */
1123 for (e = ste_ssid_head.tqh_first; e != NULL; e = e->entries.tqe_next)
1125 if (e->is_ref)
1126 continue;
1128 for (i = 0; i < max_ste_types; i++)
1129 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1131 ptr += sizeof(type_t) * max_ste_types;
1134 if ((ptr - buf) != len)
1136 printf("ERROR: wrong lengths in %s.\n", __func__);
1137 exit(EXIT_FAILURE);
1139 (*len_ste) = len;
1140 return buf; /* for now */
1143 int write_binary(char *filename)
1145 struct acm_policy_buffer header;
1146 unsigned char *ste_buffer = NULL, *chwall_buffer = NULL;
1147 u_int32_t len;
1148 int fd;
1150 u_int32_t len_ste = 0, len_chwall = 0; /* length of policy components */
1152 /* open binary file */
1153 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) <= 0)
1154 return -EIO;
1156 ste_buffer = write_ste_binary(&len_ste);
1157 chwall_buffer = write_chwall_binary(&len_chwall);
1159 /* determine primary component (default chwall) */
1160 header.policy_version = htonl(ACM_POLICY_VERSION);
1161 header.magic = htonl(ACM_MAGIC);
1163 len = sizeof(struct acm_policy_buffer);
1164 if (have_chwall)
1165 len += len_chwall;
1166 if (have_ste)
1167 len += len_ste;
1168 header.len = htonl(len);
1170 header.primary_buffer_offset = htonl(sizeof(struct acm_policy_buffer));
1171 if (primary == CHWALL)
1173 header.primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1174 header.secondary_buffer_offset =
1175 htonl((sizeof(struct acm_policy_buffer)) + len_chwall);
1177 else if (primary == STE)
1179 header.primary_policy_code =
1180 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1181 header.secondary_buffer_offset =
1182 htonl((sizeof(struct acm_policy_buffer)) + len_ste);
1184 else
1186 /* null policy */
1187 header.primary_policy_code = htonl(ACM_NULL_POLICY);
1188 header.secondary_buffer_offset =
1189 htonl(header.primary_buffer_offset);
1192 if (secondary == CHWALL)
1193 header.secondary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1194 else if (secondary == STE)
1195 header.secondary_policy_code =
1196 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1197 else
1198 header.secondary_policy_code = htonl(ACM_NULL_POLICY);
1200 if (write(fd, (void *) &header, sizeof(struct acm_policy_buffer))
1201 != sizeof(struct acm_policy_buffer))
1202 return -EIO;
1204 /* write primary policy component */
1205 if (primary == CHWALL)
1207 if (write(fd, chwall_buffer, len_chwall) != len_chwall)
1208 return -EIO;
1210 else if (primary == STE)
1212 if (write(fd, ste_buffer, len_ste) != len_ste)
1213 return -EIO;
1214 } else
1215 ; /* NULL POLICY has no policy data */
1217 /* write secondary policy component */
1218 if (secondary == CHWALL)
1220 if (write(fd, chwall_buffer, len_chwall) != len_chwall)
1221 return -EIO;
1223 else if (secondary == STE)
1225 if (write(fd, ste_buffer, len_ste) != len_ste)
1226 return -EIO;
1227 } else; /* NULL POLICY has no policy data */
1229 close(fd);
1230 return 0;
1233 int is_valid(xmlDocPtr doc)
1235 int err = 0;
1236 xmlSchemaPtr schema_ctxt = NULL;
1237 xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL;
1238 xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL;
1240 schemaparser_ctxt = xmlSchemaNewParserCtxt(SCHEMA_FILENAME);
1241 schema_ctxt = xmlSchemaParse(schemaparser_ctxt);
1242 schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt);
1244 #ifdef VALIDATE_SCHEMA
1245 /* only tested to be available from libxml2-2.6.20 upwards */
1246 if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1)
1248 printf("ERROR: Invalid schema file %s (err=%d)\n",
1249 SCHEMA_FILENAME, err);
1250 err = -EIO;
1251 goto out;
1253 else
1254 printf("XML Schema %s valid.\n", SCHEMA_FILENAME);
1255 #endif
1256 if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc)))
1258 err = -EIO;
1259 goto out;
1261 out:
1262 xmlSchemaFreeValidCtxt(schemavalid_ctxt);
1263 xmlSchemaFreeParserCtxt(schemaparser_ctxt);
1264 xmlSchemaFree(schema_ctxt);
1265 return (err != 0) ? 0 : 1;
1268 int main(int argc, char **argv)
1270 xmlDocPtr labeldoc = NULL;
1271 xmlDocPtr policydoc = NULL;
1273 int err = EXIT_SUCCESS;
1275 char *file_prefix;
1276 int prefix_len;
1278 if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION)
1280 printf("ERROR: This program was written against an older ACM version.\n");
1281 exit(EXIT_FAILURE);
1284 if (argc != 2)
1285 usage(basename(argv[0]));
1287 prefix_len = strlen(POLICY_SUBDIR) +
1288 strlen(argv[1]) + 1 /* "/" */ +
1289 strlen(argv[1]) + 1 /* "/" */ ;
1291 file_prefix = malloc(prefix_len);
1292 policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION));
1293 label_filename = malloc(prefix_len + strlen(LABEL_EXTENSION));
1294 binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION));
1295 mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION));
1297 if (!file_prefix || !policy_filename || !label_filename ||
1298 !binary_filename || !mapping_filename)
1300 printf("ERROR allocating file name memory.\n");
1301 goto out2;
1304 /* create input/output filenames out of prefix */
1305 strcat(file_prefix, POLICY_SUBDIR);
1306 strcat(file_prefix, argv[1]);
1307 strcat(file_prefix, "/");
1308 strcat(file_prefix, argv[1]);
1310 strcpy(policy_filename, file_prefix);
1311 strcpy(label_filename, file_prefix);
1312 strcpy(binary_filename, file_prefix);
1313 strcpy(mapping_filename, file_prefix);
1315 strcat(policy_filename, POLICY_EXTENSION);
1316 strcat(label_filename, LABEL_EXTENSION);
1317 strcat(binary_filename, BINARY_EXTENSION);
1318 strcat(mapping_filename, MAPPING_EXTENSION);
1320 labeldoc = xmlParseFile(label_filename);
1322 if (labeldoc == NULL)
1324 printf("Error: could not parse file %s.\n", argv[1]);
1325 goto out2;
1328 printf("Validating label file %s...\n", label_filename);
1329 if (!is_valid(labeldoc))
1331 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1332 label_filename, err);
1333 goto out1;
1336 policydoc = xmlParseFile(policy_filename);
1338 if (policydoc == NULL)
1340 printf("Error: could not parse file %s.\n", argv[1]);
1341 goto out1;
1344 printf("Validating policy file %s...\n", policy_filename);
1346 if (!is_valid(policydoc))
1348 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1349 policy_filename, err);
1350 goto out;
1353 /* Init queues and parse policy */
1354 create_type_mapping(policydoc);
1356 /* create ssids */
1357 create_ssid_mapping(labeldoc);
1359 /* write label mapping file */
1360 if (write_mapping(mapping_filename))
1362 printf("ERROR: writing mapping file %s.\n", mapping_filename);
1363 goto out;
1366 /* write binary file */
1367 if (write_binary(binary_filename))
1369 printf("ERROR: writing binary file %s.\n", binary_filename);
1370 goto out;
1373 /* write stats */
1374 if (have_chwall)
1376 printf("Max chwall labels: %u\n", max_chwall_labels);
1377 printf("Max chwall-types: %u\n", max_chwall_types);
1378 printf("Max chwall-ssids: %u\n", max_chwall_ssids);
1381 if (have_ste)
1383 printf("Max ste labels: %u\n", max_ste_labels);
1384 printf("Max ste-types: %u\n", max_ste_types);
1385 printf("Max ste-ssids: %u\n", max_ste_ssids);
1387 /* cleanup */
1388 out:
1389 xmlFreeDoc(policydoc);
1390 out1:
1391 xmlFreeDoc(labeldoc);
1392 out2:
1393 xmlCleanupParser();
1394 return err;