ia64/xen-unstable

view tools/security/secpol_xml2bin.c @ 6812:26cf3cfd3bed

Switch vcpu hotplugging to use xstransact.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 17:31:13 2005 +0000 (2005-09-13)
parents dd668f7527cb
children b2f4823b6ff0 b35215021b32 9af349b055e5 3233e7ecfa9f
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;