ia64/xen-unstable

view tools/security/secpol_xml2bin.c @ 8740:3d7ea7972b39

Update patches for linux 2.6.15.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Feb 02 17:16:00 2006 +0000 (2006-02-02)
parents 8aac8746047b
children ad30019015a2
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 (xensec_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 <stdint.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,
106 *schema_filename = NULL;
108 void usage(char *prg)
109 {
110 printf("Usage: %s [OPTIONS] POLICYNAME\n", prg);
111 printf("POLICYNAME is the directory name within the policy directory\n");
112 printf("that contains the policy files. The default policy directory\n");
113 printf("is '%s' (see the '-d' option below to change it)\n", POLICY_DIR);
114 printf("The policy files contained in the POLICYNAME directory must be named:\n");
115 printf("\tPOLICYNAME-security_policy.xml\n");
116 printf("\tPOLICYNAME-security_label_template.xml\n\n");
117 printf("OPTIONS:\n");
118 printf("\t-d POLICYDIR\n");
119 printf("\t\tUse POLICYDIR as the policy directory. This directory must contain\n");
120 printf("\t\tthe policy schema file 'security_policy.xsd'\n");
121 exit(EXIT_FAILURE);
122 }
125 /***************** policy-related parsing *********************/
127 char *type_by_mapping(struct tailhead *head, u_int32_t mapping)
128 {
129 struct type_entry *np;
130 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
131 if (np->mapping == mapping)
132 return np->name;
133 return NULL;
134 }
137 struct type_entry *lookup(struct tailhead *head, char *name)
138 {
139 struct type_entry *np;
140 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
141 if (!(strcmp(np->name, name)))
142 return np;
143 return NULL;
144 }
146 /* enforces single-entry lists */
147 int add_entry(struct tailhead *head, char *name, type_t mapping)
148 {
149 struct type_entry *e;
150 if (lookup(head, name))
151 {
152 printf("Error: Type >%s< defined more than once.\n", name);
153 return -EFAULT; /* already in the list */
154 }
155 if (!(e = malloc(sizeof(struct type_entry))))
156 return -ENOMEM;
158 e->name = name;
159 e->mapping = mapping;
160 TAILQ_INSERT_TAIL(head, e, entries);
161 return 0;
162 }
164 int totoken(char *tok)
165 {
166 int i;
167 for (i = 0; token[i] != NULL; i++)
168 if (!strcmp(token[i], tok))
169 return i;
170 return -EFAULT;
171 }
173 /* conflictsets use the same data structure as ssids; since
174 * they are similar in structure (set of types)
175 */
176 int init_next_conflictset(void)
177 {
178 struct ssid_entry *conflictset = malloc(sizeof(struct ssid_entry));
180 if (!conflictset)
181 return -ENOMEM;
183 conflictset->name = current_conflictset_name;
184 conflictset->num = max_conflictsets++;
185 conflictset->is_ref = 0; /* n/a for conflictsets */
186 /**
187 * row: allocate one byte per type;
188 * [i] != 0 --> mapped type >i< is part of the conflictset
189 */
190 conflictset->row = malloc(max_chwall_types);
191 if (!conflictset->row)
192 return -ENOMEM;
194 memset(conflictset->row, 0, max_chwall_types);
195 TAILQ_INSERT_TAIL(&conflictsets_head, conflictset, entries);
196 current_conflictset_p = conflictset;
197 return 0;
198 }
200 int register_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
201 {
202 xmlChar *text;
203 struct type_entry *e;
206 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
207 if (!text)
208 {
209 printf("Error reading type name!\n");
210 return -EFAULT;
211 }
213 switch (state) {
214 case XML2BIN_stetype_S:
215 if (add_entry(&ste_head, (char *) text, max_ste_types))
216 {
217 xmlFree(text);
218 return -EFAULT;
219 }
220 max_ste_types++;
221 break;
223 case XML2BIN_chwalltype_S:
224 if (add_entry(&chwall_head, (char *) text, max_chwall_types))
225 {
226 xmlFree(text);
227 return -EFAULT;
228 }
229 max_chwall_types++;
230 break;
232 case XML2BIN_conflictsettype_S:
233 /* a) search the type in the chwall_type list */
234 e = lookup(&chwall_head, (char *) text);
235 if (e == NULL)
236 {
237 printf("CS type >%s< not a CHWALL type.\n", text);
238 xmlFree(text);
239 return -EFAULT;
240 }
241 /* b) add type entry to the current cs set */
242 if (current_conflictset_p->row[e->mapping])
243 {
244 printf("ERROR: Double entry of type >%s< in conflict set %d.\n",
245 text, current_conflictset_p->num);
246 xmlFree(text);
247 return -EFAULT;
248 }
249 current_conflictset_p->row[e->mapping] = 1;
250 break;
252 default:
253 printf("Incorrect type environment (state = %lx, text = %s).\n",
254 state, text);
255 xmlFree(text);
256 return -EFAULT;
257 }
258 return 0;
259 }
261 void set_component_type(xmlNode * cur_node, enum policycomponent pc)
262 {
263 xmlChar *order;
265 if ((order = xmlGetProp(cur_node, (xmlChar *) PRIMARY_COMPONENT_ATTR_NAME))) {
266 if (strcmp((char *) order, PRIMARY_COMPONENT))
267 {
268 printf("ERROR: Illegal attribut value >order=%s<.\n",
269 (char *) order);
270 xmlFree(order);
271 exit(EXIT_FAILURE);
272 }
273 if (primary != NULLPOLICY)
274 {
275 printf("ERROR: Primary Policy Component set twice!\n");
276 exit(EXIT_FAILURE);
277 }
278 primary = pc;
279 xmlFree(order);
280 }
281 }
283 void walk_policy(xmlNode * start, xmlDocPtr doc, unsigned long state)
284 {
285 xmlNode *cur_node = NULL;
286 int code;
288 for (cur_node = start; cur_node; cur_node = cur_node->next)
289 {
290 if ((code = totoken((char *) cur_node->name)) < 0)
291 {
292 printf("Unknown token: >%s<. Aborting.\n", cur_node->name);
293 exit(EXIT_FAILURE);
294 }
295 switch (code) { /* adjust state to new state */
296 case XML2BIN_SECPOL:
297 case XML2BIN_STETYPES:
298 case XML2BIN_CHWALLTYPES:
299 case XML2BIN_CONFLICTSETS:
300 walk_policy(cur_node->children, doc, state | (1 << code));
301 break;
303 case XML2BIN_STE:
304 if (WRITTEN_AGAINST_ACM_STE_VERSION != ACM_STE_VERSION)
305 {
306 printf("ERROR: This program was written against another STE version.\n");
307 exit(EXIT_FAILURE);
308 }
309 have_ste = 1;
310 set_component_type(cur_node, STE);
311 walk_policy(cur_node->children, doc, state | (1 << code));
312 break;
314 case XML2BIN_CHWALL:
315 if (WRITTEN_AGAINST_ACM_CHWALL_VERSION != ACM_CHWALL_VERSION)
316 {
317 printf("ERROR: This program was written against another CHWALL version.\n");
318 exit(EXIT_FAILURE);
319 }
320 have_chwall = 1;
321 set_component_type(cur_node, CHWALL);
322 walk_policy(cur_node->children, doc, state | (1 << code));
323 break;
325 case XML2BIN_CSTYPE:
326 current_conflictset_name =
327 (char *) xmlGetProp(cur_node, (xmlChar *) "name");
328 if (!current_conflictset_name)
329 current_conflictset_name = "";
331 if (init_next_conflictset())
332 {
333 printf
334 ("ERROR: creating new conflictset structure failed.\n");
335 exit(EXIT_FAILURE);
336 }
337 walk_policy(cur_node->children, doc, state | (1 << code));
338 break;
340 case XML2BIN_TYPE:
341 if (register_type(cur_node, doc, state))
342 exit(EXIT_FAILURE);
343 /* type leaf */
344 break;
346 case XML2BIN_TEXT:
347 case XML2BIN_COMMENT:
348 case XML2BIN_POLICYHEADER:
349 /* leaf - nothing to do */
350 break;
352 default:
353 printf("Unkonwn token Error (%d)\n", code);
354 exit(EXIT_FAILURE);
355 }
357 }
358 return;
359 }
361 int create_type_mapping(xmlDocPtr doc)
362 {
363 xmlNode *root_element = xmlDocGetRootElement(doc);
364 struct type_entry *te;
365 struct ssid_entry *se;
366 int i;
368 printf("Creating ssid mappings ...\n");
370 /* initialize the ste and chwall type lists */
371 TAILQ_INIT(&ste_head);
372 TAILQ_INIT(&chwall_head);
373 TAILQ_INIT(&conflictsets_head);
375 walk_policy(root_element, doc, XML2BIN_NULL);
377 /* determine primary/secondary policy component orders */
378 if ((primary == NULLPOLICY) && have_chwall)
379 primary = CHWALL; /* default if not set */
380 else if ((primary == NULLPOLICY) && have_ste)
381 primary = STE;
383 switch (primary) {
385 case CHWALL:
386 if (have_ste)
387 secondary = STE;
388 /* else default = NULLPOLICY */
389 break;
391 case STE:
392 if (have_chwall)
393 secondary = CHWALL;
394 /* else default = NULLPOLICY */
395 break;
397 default:
398 /* NULL/NULL policy */
399 break;
400 }
402 if (!DEBUG)
403 return 0;
405 /* print queues */
406 if (have_ste)
407 {
408 printf("STE-Type queue (%s):\n",
409 (primary == STE) ? "PRIMARY" : "SECONDARY");
410 for (te = ste_head.tqh_first; te != NULL;
411 te = te->entries.tqe_next)
412 printf("name=%22s, map=%x\n", te->name, te->mapping);
413 }
414 if (have_chwall)
415 {
416 printf("CHWALL-Type queue (%s):\n",
417 (primary == CHWALL) ? "PRIMARY" : "SECONDARY");
418 for (te = chwall_head.tqh_first; te != NULL;
419 te = te->entries.tqe_next)
420 printf("name=%s, map=%x\n", te->name, te->mapping);
422 printf("Conflictset queue (max=%d):\n", max_conflictsets);
423 for (se = conflictsets_head.tqh_first; se != NULL;
424 se = se->entries.tqe_next)
425 {
426 printf("conflictset name >%s<\n",
427 se->name ? se->name : "NONAME");
428 for (i = 0; i < max_chwall_types; i++)
429 if (se->row[i])
430 printf("#%x ", i);
431 printf("\n");
432 }
433 }
434 return 0;
435 }
438 /***************** template-related parsing *********************/
440 /* add default ssid at head of ssid queues */
441 int init_ssid_queues(void)
442 {
443 struct ssid_entry *default_ssid_chwall, *default_ssid_ste;
445 default_ssid_chwall = malloc(sizeof(struct ssid_entry));
446 default_ssid_ste = malloc(sizeof(struct ssid_entry));
448 if ((!default_ssid_chwall) || (!default_ssid_ste))
449 return -ENOMEM;
451 /* default chwall ssid */
452 default_ssid_chwall->name = "DEFAULT";
453 default_ssid_chwall->num = max_chwall_ssids++;
454 default_ssid_chwall->is_ref = 0;
455 default_ssid_chwall->type = ANY;
457 default_ssid_chwall->row = malloc(max_chwall_types);
459 if (!default_ssid_chwall->row)
460 return -ENOMEM;
462 memset(default_ssid_chwall->row, 0, max_chwall_types);
464 TAILQ_INSERT_TAIL(&chwall_ssid_head, default_ssid_chwall, entries);
465 current_chwall_ssid_p = default_ssid_chwall;
466 max_chwall_labels++;
468 /* default ste ssid */
469 default_ssid_ste->name = "DEFAULT";
470 default_ssid_ste->num = max_ste_ssids++;
471 default_ssid_ste->is_ref = 0;
472 default_ssid_ste->type = ANY;
474 default_ssid_ste->row = malloc(max_ste_types);
476 if (!default_ssid_ste->row)
477 return -ENOMEM;
479 memset(default_ssid_ste->row, 0, max_ste_types);
481 TAILQ_INSERT_TAIL(&ste_ssid_head, default_ssid_ste, entries);
482 current_ste_ssid_p = default_ssid_ste;
483 max_ste_labels++;
484 return 0;
485 }
487 int init_next_chwall_ssid(unsigned long state)
488 {
489 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
491 if (!ssid)
492 return -ENOMEM;
494 ssid->name = current_ssid_name;
495 ssid->num = max_chwall_ssids++;
496 ssid->is_ref = 0;
498 if (state & (1 << XML2BIN_VM))
499 ssid->type = VM;
500 else
501 ssid->type = RES;
502 /**
503 * row: allocate one byte per type;
504 * [i] != 0 --> mapped type >i< is part of the ssid
505 */
506 ssid->row = malloc(max_chwall_types);
507 if (!ssid->row)
508 return -ENOMEM;
510 memset(ssid->row, 0, max_chwall_types);
511 TAILQ_INSERT_TAIL(&chwall_ssid_head, ssid, entries);
512 current_chwall_ssid_p = ssid;
513 max_chwall_labels++;
514 return 0;
515 }
517 int init_next_ste_ssid(unsigned long state)
518 {
519 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
521 if (!ssid)
522 return -ENOMEM;
524 ssid->name = current_ssid_name;
525 ssid->num = max_ste_ssids++;
526 ssid->is_ref = 0;
528 if (state & (1 << XML2BIN_VM))
529 ssid->type = VM;
530 else
531 ssid->type = RES;
533 /**
534 * row: allocate one byte per type;
535 * [i] != 0 --> mapped type >i< is part of the ssid
536 */
537 ssid->row = malloc(max_ste_types);
538 if (!ssid->row)
539 return -ENOMEM;
541 memset(ssid->row, 0, max_ste_types);
542 TAILQ_INSERT_TAIL(&ste_ssid_head, ssid, entries);
543 current_ste_ssid_p = ssid;
544 max_ste_labels++;
546 return 0;
547 }
550 /* adds a type to the current ssid */
551 int add_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
552 {
553 xmlChar *text;
554 struct type_entry *e;
556 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
557 if (!text)
558 {
559 printf("Error reading type name!\n");
560 return -EFAULT;
561 }
562 /* same for all: 1. lookup type mapping, 2. mark type in ssid */
563 switch (state) {
564 case XML2BIN_VM_STE_S:
565 case XML2BIN_RES_STE_S:
566 /* lookup the type mapping and include the type mapping into the array */
567 if (!(e = lookup(&ste_head, (char *) text)))
568 {
569 printf("ERROR: unknown VM STE type >%s<.\n", text);
570 exit(EXIT_FAILURE);
571 }
572 if (current_ste_ssid_p->row[e->mapping])
573 printf("Warning: double entry of VM STE type >%s<.\n", text);
575 current_ste_ssid_p->row[e->mapping] = 1;
576 break;
578 case XML2BIN_VM_CHWALL_S:
579 /* lookup the type mapping and include the type mapping into the array */
580 if (!(e = lookup(&chwall_head, (char *) text)))
581 {
582 printf("ERROR: unknown VM CHWALL type >%s<.\n", text);
583 exit(EXIT_FAILURE);
584 }
585 if (current_chwall_ssid_p->row[e->mapping])
586 printf("Warning: double entry of VM CHWALL type >%s<.\n",
587 text);
589 current_chwall_ssid_p->row[e->mapping] = 1;
590 break;
592 default:
593 printf("Incorrect type environment (state = %lx, text = %s).\n",
594 state, text);
595 xmlFree(text);
596 return -EFAULT;
597 }
598 return 0;
599 }
601 void set_bootstrap_label(xmlNode * cur_node)
602 {
603 xmlChar *order;
605 if ((order = xmlGetProp(cur_node, (xmlChar *) BOOTSTRAP_LABEL_ATTR_NAME)))
606 bootstrap_label = (char *)order;
607 else {
608 printf("ERROR: No bootstrap label defined!\n");
609 exit(EXIT_FAILURE);
610 }
611 }
613 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state)
614 {
615 xmlNode *cur_node = NULL;
616 int code;
618 for (cur_node = start; cur_node; cur_node = cur_node->next)
619 {
620 if ((code = totoken((char *) cur_node->name)) < 0)
621 {
622 printf("Unkonwn token: >%s<. Aborting.\n", cur_node->name);
623 exit(EXIT_FAILURE);
624 }
625 switch (code) { /* adjust state to new state */
627 case XML2BIN_SUBJECTS:
628 set_bootstrap_label(cur_node);
629 /* fall through */
630 case XML2BIN_VM:
631 case XML2BIN_RES:
632 case XML2BIN_SECTEMPLATE:
633 case XML2BIN_OBJECTS:
634 walk_labels(cur_node->children, doc, state | (1 << code));
635 break;
637 case XML2BIN_STETYPES:
638 /* create new ssid entry to use and point current to it */
639 if (init_next_ste_ssid(state))
640 {
641 printf("ERROR: creating new ste ssid structure failed.\n");
642 exit(EXIT_FAILURE);
643 }
644 walk_labels(cur_node->children, doc, state | (1 << code));
646 break;
648 case XML2BIN_CHWALLTYPES:
649 /* create new ssid entry to use and point current to it */
650 if (init_next_chwall_ssid(state))
651 {
652 printf("ERROR: creating new chwall ssid structure failed.\n");
653 exit(EXIT_FAILURE);
654 }
655 walk_labels(cur_node->children, doc, state | (1 << code));
657 break;
659 case XML2BIN_TYPE:
660 /* add type to current ssid */
661 if (add_type(cur_node, doc, state))
662 exit(EXIT_FAILURE);
663 break;
665 case XML2BIN_NAME:
666 if ((state != XML2BIN_VM_S) && (state != XML2BIN_RES_S))
667 {
668 printf("ERROR: >name< out of VM/RES context.\n");
669 exit(EXIT_FAILURE);
670 }
671 current_ssid_name = (char *)
672 xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
674 if (!current_ssid_name)
675 {
676 printf("ERROR: empty >name<!\n");
677 exit(EXIT_FAILURE);
678 }
679 break;
681 case XML2BIN_TEXT:
682 case XML2BIN_COMMENT:
683 case XML2BIN_LABELHEADER:
684 break;
686 default:
687 printf("Unkonwn token Error (%d)\n", code);
688 exit(EXIT_FAILURE);
689 }
691 }
692 return;
693 }
695 /* this function walks through a ssid queue
696 * and transforms double entries into references
697 * of the first definition (we need to keep the
698 * entry to map labels but we don't want double
699 * ssids in the binary policy
700 */
701 void
702 remove_doubles(struct tailhead_ssid *head,
703 u_int32_t max_types, u_int32_t * max_ssids)
704 {
705 struct ssid_entry *np, *ni;
707 /* walk once through the list */
708 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
709 {
710 /* now search from the start until np for the same entry */
711 for (ni = head->tqh_first; ni != np; ni = ni->entries.tqe_next)
712 {
713 if (ni->is_ref)
714 continue;
715 if (memcmp(np->row, ni->row, max_types))
716 continue;
717 /* found one, set np reference to ni */
718 np->is_ref = 1;
719 np->num = ni->num;
720 (*max_ssids)--;
721 }
722 }
724 /* now minimize the ssid numbers used (doubles introduce holes) */
725 (*max_ssids) = 0; /* reset */
727 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
728 {
729 if (np->is_ref)
730 continue;
732 if (np->num != (*max_ssids)) {
733 /* first reset all later references to the new max_ssid */
734 for (ni = np->entries.tqe_next; ni != NULL; ni = ni->entries.tqe_next)
735 {
736 if (ni->num == np->num)
737 ni->num = (*max_ssids);
738 }
739 /* now reset num */
740 np->num = (*max_ssids)++;
741 }
742 else
743 (*max_ssids)++;
744 }
745 }
747 /*
748 * will go away as soon as we have non-static bootstrap ssidref for dom0
749 */
750 void fixup_bootstrap_label(struct tailhead_ssid *head,
751 u_int32_t max_types, u_int32_t * max_ssids)
752 {
753 struct ssid_entry *np;
754 int i;
756 /* should not happen if xml / xsd checks work */
757 if (!bootstrap_label)
758 {
759 printf("ERROR: No bootstrap label defined.\n");
760 exit(EXIT_FAILURE);
761 }
763 /* search bootstrap_label */
764 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
765 {
766 if (!strcmp(np->name, bootstrap_label))
767 {
768 break;
769 }
770 }
772 if (!np) {
773 /* bootstrap label not found */
774 printf("ERROR: Bootstrap label >%s< not found.\n", bootstrap_label);
775 exit(EXIT_FAILURE);
776 }
778 /* move this entry ahead in the list right after the default entry so it
779 * receives ssidref 1/1 */
780 TAILQ_REMOVE(head, np, entries);
781 TAILQ_INSERT_AFTER(head, head->tqh_first, np, entries);
783 /* renumber the ssids (we could also just switch places with 1st element) */
784 for (np = head->tqh_first, i=0; np != NULL; np = np->entries.tqe_next, i++)
785 np->num = i;
787 }
789 int create_ssid_mapping(xmlDocPtr doc)
790 {
791 xmlNode *root_element = xmlDocGetRootElement(doc);
792 struct ssid_entry *np;
793 int i;
795 printf("Creating label mappings ...\n");
796 /* initialize the ste and chwall type lists */
797 TAILQ_INIT(&chwall_ssid_head);
798 TAILQ_INIT(&ste_ssid_head);
800 /* init with default ssids */
801 if (init_ssid_queues())
802 {
803 printf("ERROR adding default ssids.\n");
804 exit(EXIT_FAILURE);
805 }
807 /* now walk the template DOM tree and fill in ssids */
808 walk_labels(root_element, doc, XML2BIN_NULL);
810 /*
811 * now sort bootstrap label to the head of the list
812 * (for now), dom0 assumes its label in the first
813 * defined ssidref (1/1). 0/0 is the default non-Label
814 */
815 if (have_chwall)
816 fixup_bootstrap_label(&chwall_ssid_head, max_chwall_types,
817 &max_chwall_ssids);
818 if (have_ste)
819 fixup_bootstrap_label(&ste_ssid_head, max_ste_types,
820 &max_ste_ssids);
822 /* remove any double entries (insert reference instead) */
823 if (have_chwall)
824 remove_doubles(&chwall_ssid_head, max_chwall_types,
825 &max_chwall_ssids);
826 if (have_ste)
827 remove_doubles(&ste_ssid_head, max_ste_types,
828 &max_ste_ssids);
830 if (!DEBUG)
831 return 0;
833 /* print queues */
834 if (have_chwall)
835 {
836 printf("CHWALL SSID queue (max ssidrefs=%d):\n", max_chwall_ssids);
837 np = NULL;
838 for (np = chwall_ssid_head.tqh_first; np != NULL;
839 np = np->entries.tqe_next)
840 {
841 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
842 if (np->is_ref)
843 printf("REFERENCE");
844 else
845 for (i = 0; i < max_chwall_types; i++)
846 if (np->row[i])
847 printf("#%02d ", i);
848 printf("\n\n");
849 }
850 }
851 if (have_ste)
852 {
853 printf("STE SSID queue (max ssidrefs=%d):\n", max_ste_ssids);
854 np = NULL;
855 for (np = ste_ssid_head.tqh_first; np != NULL;
856 np = np->entries.tqe_next)
857 {
858 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
859 if (np->is_ref)
860 printf("REFERENCE");
861 else
862 for (i = 0; i < max_ste_types; i++)
863 if (np->row[i])
864 printf("#%02d ", i);
865 printf("\n\n");
866 }
867 }
868 return 0;
869 }
871 /***************** writing the binary policy *********************/
873 /*
874 * the mapping file is ascii-based since it will likely be used from
875 * within scripts (using awk, grep, etc.);
876 *
877 * We print from high-level to low-level information so that with one
878 * pass, any symbol can be resolved (e.g. Label -> types)
879 */
880 int write_mapping(char *filename)
881 {
883 struct ssid_entry *e;
884 struct type_entry *t;
885 int i;
886 FILE *file;
888 if ((file = fopen(filename, "w")) == NULL)
889 return -EIO;
891 fprintf(file, "MAGIC %08x\n", ACM_MAGIC);
892 fprintf(file, "POLICY %s\n",
893 basename(policy_filename));
894 fprintf(file, "BINARY %s\n",
895 basename(binary_filename));
896 if (have_chwall)
897 {
898 fprintf(file, "MAX-CHWALL-TYPES %08x\n", max_chwall_types);
899 fprintf(file, "MAX-CHWALL-SSIDS %08x\n", max_chwall_ssids);
900 fprintf(file, "MAX-CHWALL-LABELS %08x\n", max_chwall_labels);
901 }
902 if (have_ste)
903 {
904 fprintf(file, "MAX-STE-TYPES %08x\n", max_ste_types);
905 fprintf(file, "MAX-STE-SSIDS %08x\n", max_ste_ssids);
906 fprintf(file, "MAX-STE-LABELS %08x\n", max_ste_labels);
907 }
908 fprintf(file, "\n");
910 /* primary / secondary order for combined ssid synthesis/analysis
911 * if no primary is named, then chwall is primary */
912 switch (primary) {
913 case CHWALL:
914 fprintf(file, "PRIMARY CHWALL\n");
915 break;
917 case STE:
918 fprintf(file, "PRIMARY STE\n");
919 break;
921 default:
922 fprintf(file, "PRIMARY NULL\n");
923 break;
924 }
926 switch (secondary) {
927 case CHWALL:
928 fprintf(file, "SECONDARY CHWALL\n");
929 break;
931 case STE:
932 fprintf(file, "SECONDARY STE\n");
933 break;
935 default:
936 fprintf(file, "SECONDARY NULL\n");
937 break;
938 }
939 fprintf(file, "\n");
941 /* first labels to ssid mappings */
942 if (have_chwall)
943 {
944 for (e = chwall_ssid_head.tqh_first; e != NULL;
945 e = e->entries.tqe_next)
946 {
947 fprintf(file, "LABEL->SSID %s CHWALL %-25s %8x\n",
948 (e->type ==
949 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
950 e->name, e->num);
951 }
952 fprintf(file, "\n");
953 }
954 if (have_ste)
955 {
956 for (e = ste_ssid_head.tqh_first; e != NULL;
957 e = e->entries.tqe_next)
958 {
959 fprintf(file, "LABEL->SSID %s STE %-25s %8x\n",
960 (e->type ==
961 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
962 e->name, e->num);
963 }
964 fprintf(file, "\n");
965 }
967 /* second ssid to type mappings */
968 if (have_chwall)
969 {
970 for (e = chwall_ssid_head.tqh_first; e != NULL;
971 e = e->entries.tqe_next)
972 {
973 if (e->is_ref)
974 continue;
976 fprintf(file, "SSID->TYPE CHWALL %08x", e->num);
978 for (i = 0; i < max_chwall_types; i++)
979 if (e->row[i])
980 fprintf(file, " %s", type_by_mapping(&chwall_head, i));
982 fprintf(file, "\n");
983 }
984 fprintf(file, "\n");
985 }
986 if (have_ste) {
987 for (e = ste_ssid_head.tqh_first; e != NULL;
988 e = e->entries.tqe_next)
989 {
990 if (e->is_ref)
991 continue;
993 fprintf(file, "SSID->TYPE STE %08x", e->num);
995 for (i = 0; i < max_ste_types; i++)
996 if (e->row[i])
997 fprintf(file, " %s", type_by_mapping(&ste_head, i));
999 fprintf(file, "\n");
1001 fprintf(file, "\n");
1003 /* third type mappings */
1004 if (have_chwall)
1006 for (t = chwall_head.tqh_first; t != NULL; t = t->entries.tqe_next)
1008 fprintf(file, "TYPE CHWALL %-25s %8x\n",
1009 t->name, t->mapping);
1011 fprintf(file, "\n");
1013 if (have_ste) {
1014 for (t = ste_head.tqh_first; t != NULL; t = t->entries.tqe_next)
1016 fprintf(file, "TYPE STE %-25s %8x\n",
1017 t->name, t->mapping);
1019 fprintf(file, "\n");
1021 fclose(file);
1022 return 0;
1025 unsigned char *write_chwall_binary(u_int32_t * len_chwall)
1027 unsigned char *buf, *ptr;
1028 struct acm_chwall_policy_buffer *chwall_header;
1029 u_int32_t len;
1030 struct ssid_entry *e;
1031 int i;
1033 if (!have_chwall)
1034 return NULL;
1036 len = sizeof(struct acm_chwall_policy_buffer) +
1037 sizeof(type_t) * max_chwall_types * max_chwall_ssids +
1038 sizeof(type_t) * max_chwall_types * max_conflictsets;
1040 buf = malloc(len);
1041 ptr = buf;
1043 if (!buf)
1045 printf("ERROR: out of memory allocating chwall buffer.\n");
1046 exit(EXIT_FAILURE);
1048 /* chwall has 3 parts : header, types, conflictsets */
1050 chwall_header = (struct acm_chwall_policy_buffer *) buf;
1051 chwall_header->chwall_max_types = htonl(max_chwall_types);
1052 chwall_header->chwall_max_ssidrefs = htonl(max_chwall_ssids);
1053 chwall_header->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1054 chwall_header->policy_version = htonl(ACM_CHWALL_VERSION);
1055 chwall_header->chwall_ssid_offset =
1056 htonl(sizeof(struct acm_chwall_policy_buffer));
1057 chwall_header->chwall_max_conflictsets = htonl(max_conflictsets);
1058 chwall_header->chwall_conflict_sets_offset =
1059 htonl(ntohl(chwall_header->chwall_ssid_offset) +
1060 sizeof(domaintype_t) * max_chwall_ssids * max_chwall_types);
1061 chwall_header->chwall_running_types_offset = 0; /* not set, only retrieved */
1062 chwall_header->chwall_conflict_aggregate_offset = 0; /* not set, only retrieved */
1063 ptr += sizeof(struct acm_chwall_policy_buffer);
1065 /* types */
1066 for (e = chwall_ssid_head.tqh_first; e != NULL;
1067 e = e->entries.tqe_next)
1069 if (e->is_ref)
1070 continue;
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 /* conflictsets */
1079 for (e = conflictsets_head.tqh_first; e != NULL;
1080 e = e->entries.tqe_next)
1082 for (i = 0; i < max_chwall_types; i++)
1083 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1085 ptr += sizeof(type_t) * max_chwall_types;
1088 if ((ptr - buf) != len)
1090 printf("ERROR: wrong lengths in %s.\n", __func__);
1091 exit(EXIT_FAILURE);
1094 (*len_chwall) = len;
1095 return buf;
1098 unsigned char *write_ste_binary(u_int32_t * len_ste)
1100 unsigned char *buf, *ptr;
1101 struct acm_ste_policy_buffer *ste_header;
1102 struct ssid_entry *e;
1103 u_int32_t len;
1104 int i;
1106 if (!have_ste)
1107 return NULL;
1109 len = sizeof(struct acm_ste_policy_buffer) +
1110 sizeof(type_t) * max_ste_types * max_ste_ssids;
1112 buf = malloc(len);
1113 ptr = buf;
1115 if (!buf)
1117 printf("ERROR: out of memory allocating chwall buffer.\n");
1118 exit(EXIT_FAILURE);
1121 /* fill buffer */
1122 ste_header = (struct acm_ste_policy_buffer *) buf;
1123 ste_header->policy_version = htonl(ACM_STE_VERSION);
1124 ste_header->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1125 ste_header->ste_max_types = htonl(max_ste_types);
1126 ste_header->ste_max_ssidrefs = htonl(max_ste_ssids);
1127 ste_header->ste_ssid_offset =
1128 htonl(sizeof(struct acm_ste_policy_buffer));
1130 ptr += sizeof(struct acm_ste_policy_buffer);
1132 /* types */
1133 for (e = ste_ssid_head.tqh_first; e != NULL; e = e->entries.tqe_next)
1135 if (e->is_ref)
1136 continue;
1138 for (i = 0; i < max_ste_types; i++)
1139 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1141 ptr += sizeof(type_t) * max_ste_types;
1144 if ((ptr - buf) != len)
1146 printf("ERROR: wrong lengths in %s.\n", __func__);
1147 exit(EXIT_FAILURE);
1149 (*len_ste) = len;
1150 return buf; /* for now */
1153 int write_binary(char *filename)
1155 struct acm_policy_buffer header;
1156 unsigned char *ste_buffer = NULL, *chwall_buffer = NULL;
1157 u_int32_t len;
1158 int fd;
1160 u_int32_t len_ste = 0, len_chwall = 0; /* length of policy components */
1162 /* open binary file */
1163 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) <= 0)
1164 return -EIO;
1166 ste_buffer = write_ste_binary(&len_ste);
1167 chwall_buffer = write_chwall_binary(&len_chwall);
1169 /* determine primary component (default chwall) */
1170 header.policy_version = htonl(ACM_POLICY_VERSION);
1171 header.magic = htonl(ACM_MAGIC);
1173 len = sizeof(struct acm_policy_buffer);
1174 if (have_chwall)
1175 len += len_chwall;
1176 if (have_ste)
1177 len += len_ste;
1178 header.len = htonl(len);
1180 header.primary_buffer_offset = htonl(sizeof(struct acm_policy_buffer));
1181 if (primary == CHWALL)
1183 header.primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1184 header.secondary_buffer_offset =
1185 htonl((sizeof(struct acm_policy_buffer)) + len_chwall);
1187 else if (primary == STE)
1189 header.primary_policy_code =
1190 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1191 header.secondary_buffer_offset =
1192 htonl((sizeof(struct acm_policy_buffer)) + len_ste);
1194 else
1196 /* null policy */
1197 header.primary_policy_code = htonl(ACM_NULL_POLICY);
1198 header.secondary_buffer_offset =
1199 htonl(header.primary_buffer_offset);
1202 if (secondary == CHWALL)
1203 header.secondary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1204 else if (secondary == STE)
1205 header.secondary_policy_code =
1206 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1207 else
1208 header.secondary_policy_code = htonl(ACM_NULL_POLICY);
1210 if (write(fd, (void *) &header, sizeof(struct acm_policy_buffer))
1211 != sizeof(struct acm_policy_buffer))
1212 return -EIO;
1214 /* write primary policy component */
1215 if (primary == CHWALL)
1217 if (write(fd, chwall_buffer, len_chwall) != len_chwall)
1218 return -EIO;
1220 else if (primary == STE)
1222 if (write(fd, ste_buffer, len_ste) != len_ste)
1223 return -EIO;
1224 } else
1225 ; /* NULL POLICY has no policy data */
1227 /* write secondary policy component */
1228 if (secondary == CHWALL)
1230 if (write(fd, chwall_buffer, len_chwall) != len_chwall)
1231 return -EIO;
1233 else if (secondary == STE)
1235 if (write(fd, ste_buffer, len_ste) != len_ste)
1236 return -EIO;
1237 } else; /* NULL POLICY has no policy data */
1239 close(fd);
1240 return 0;
1243 int is_valid(xmlDocPtr doc)
1245 int err = 0;
1246 xmlSchemaPtr schema_ctxt = NULL;
1247 xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL;
1248 xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL;
1250 schemaparser_ctxt = xmlSchemaNewParserCtxt(schema_filename);
1251 schema_ctxt = xmlSchemaParse(schemaparser_ctxt);
1252 schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt);
1254 #ifdef VALIDATE_SCHEMA
1255 /* only tested to be available from libxml2-2.6.20 upwards */
1256 if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1)
1258 printf("ERROR: Invalid schema file %s (err=%d)\n",
1259 schema_filename, err);
1260 err = -EIO;
1261 goto out;
1263 else
1264 printf("XML Schema %s valid.\n", schema_filename);
1265 #endif
1266 if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc)))
1268 err = -EIO;
1269 goto out;
1271 out:
1272 xmlSchemaFreeValidCtxt(schemavalid_ctxt);
1273 xmlSchemaFreeParserCtxt(schemaparser_ctxt);
1274 xmlSchemaFree(schema_ctxt);
1275 return (err != 0) ? 0 : 1;
1278 int main(int argc, char **argv)
1280 xmlDocPtr labeldoc = NULL;
1281 xmlDocPtr policydoc = NULL;
1283 int err = EXIT_SUCCESS;
1285 char *file_prefix;
1286 int prefix_len;
1288 int opt_char;
1289 char *policy_dir = POLICY_DIR;
1291 if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION)
1293 printf("ERROR: This program was written against an older ACM version.\n");
1294 exit(EXIT_FAILURE);
1297 while ((opt_char = getopt(argc, argv, "d:")) != -1) {
1298 switch (opt_char) {
1299 case 'd':
1300 policy_dir = malloc(strlen(optarg) + 2); // null terminator and possibly "/"
1301 if (!policy_dir) {
1302 printf("ERROR allocating directory name memory.\n");
1303 exit(EXIT_FAILURE);
1305 strcpy(policy_dir, optarg);
1306 if (policy_dir[strlen(policy_dir) - 1] != '/')
1307 strcat(policy_dir, "/");
1308 break;
1310 default:
1311 usage(basename(argv[0]));
1315 if ((argc - optind) != 1)
1316 usage(basename(argv[0]));
1318 prefix_len = strlen(policy_dir) +
1319 strlen(argv[optind]) + 1 /* "/" */ +
1320 strlen(argv[optind]) + 1 /* null terminator */ ;
1322 file_prefix = malloc(prefix_len);
1323 policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION));
1324 label_filename = malloc(prefix_len + strlen(LABEL_EXTENSION));
1325 binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION));
1326 mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION));
1327 schema_filename = malloc(strlen(policy_dir) + strlen(SCHEMA_FILENAME) + 1);
1329 if (!file_prefix || !policy_filename || !label_filename ||
1330 !binary_filename || !mapping_filename || !schema_filename)
1332 printf("ERROR allocating file name memory.\n");
1333 goto out2;
1336 /* create input/output filenames out of prefix */
1337 strcpy(file_prefix, policy_dir);
1338 strcat(file_prefix, argv[optind]);
1339 strcat(file_prefix, "/");
1340 strcat(file_prefix, argv[optind]);
1342 strcpy(policy_filename, file_prefix);
1343 strcpy(label_filename, file_prefix);
1344 strcpy(binary_filename, file_prefix);
1345 strcpy(mapping_filename, file_prefix);
1347 strcat(policy_filename, POLICY_EXTENSION);
1348 strcat(label_filename, LABEL_EXTENSION);
1349 strcat(binary_filename, BINARY_EXTENSION);
1350 strcat(mapping_filename, MAPPING_EXTENSION);
1352 strcpy(schema_filename, policy_dir);
1353 strcat(schema_filename, SCHEMA_FILENAME);
1355 labeldoc = xmlParseFile(label_filename);
1357 if (labeldoc == NULL)
1359 printf("Error: could not parse file %s.\n", argv[optind]);
1360 goto out2;
1363 printf("Validating label file %s...\n", label_filename);
1364 if (!is_valid(labeldoc))
1366 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1367 label_filename, err);
1368 goto out1;
1371 policydoc = xmlParseFile(policy_filename);
1373 if (policydoc == NULL)
1375 printf("Error: could not parse file %s.\n", argv[optind]);
1376 goto out1;
1379 printf("Validating policy file %s...\n", policy_filename);
1381 if (!is_valid(policydoc))
1383 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1384 policy_filename, err);
1385 goto out;
1388 /* Init queues and parse policy */
1389 create_type_mapping(policydoc);
1391 /* create ssids */
1392 create_ssid_mapping(labeldoc);
1394 /* write label mapping file */
1395 if (write_mapping(mapping_filename))
1397 printf("ERROR: writing mapping file %s.\n", mapping_filename);
1398 goto out;
1401 /* write binary file */
1402 if (write_binary(binary_filename))
1404 printf("ERROR: writing binary file %s.\n", binary_filename);
1405 goto out;
1408 /* write stats */
1409 if (have_chwall)
1411 printf("Max chwall labels: %u\n", max_chwall_labels);
1412 printf("Max chwall-types: %u\n", max_chwall_types);
1413 printf("Max chwall-ssids: %u\n", max_chwall_ssids);
1416 if (have_ste)
1418 printf("Max ste labels: %u\n", max_ste_labels);
1419 printf("Max ste-types: %u\n", max_ste_types);
1420 printf("Max ste-ssids: %u\n", max_ste_ssids);
1422 /* cleanup */
1423 out:
1424 xmlFreeDoc(policydoc);
1425 out1:
1426 xmlFreeDoc(labeldoc);
1427 out2:
1428 xmlCleanupParser();
1429 return err;