ia64/xen-unstable

view tools/security/secpol_xml2bin.c @ 9832:ad30019015a2

This patch adds support in the hypervisor for the policy name attribute
introduced into security policies. It also fixes a minor problem related
to handling unsupported boot policies.

Signed-off by: Reiner Sailer <sailer@us.ibm.com>
author smh22@firebug.cl.cam.ac.uk
date Mon Apr 24 10:51:50 2006 +0100 (2006-04-24)
parents 8aac8746047b
children 0de8a4a023d0
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 *binary_filename = NULL,
105 *mapping_filename = NULL, *schema_filename = NULL;
107 char *policy_reference_name = NULL;
109 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state);
111 void usage(char *prg)
112 {
113 printf("Usage: %s [OPTIONS] POLICYNAME\n", prg);
114 printf
115 ("POLICYNAME is the directory name within the policy directory\n");
116 printf
117 ("that contains the policy files. The default policy directory\n");
118 printf("is '%s' (see the '-d' option below to change it)\n",
119 POLICY_DIR);
120 printf
121 ("The policy files contained in the POLICYNAME directory must be named:\n");
122 printf("\tPOLICYNAME-security_policy.xml\n");
123 printf("\tPOLICYNAME-security_label_template.xml\n\n");
124 printf("OPTIONS:\n");
125 printf("\t-d POLICYDIR\n");
126 printf
127 ("\t\tUse POLICYDIR as the policy directory. This directory must contain\n");
128 printf("\t\tthe policy schema file 'security_policy.xsd'\n");
129 exit(EXIT_FAILURE);
130 }
133 /***************** policy-related parsing *********************/
135 char *type_by_mapping(struct tailhead *head, u_int32_t mapping)
136 {
137 struct type_entry *np;
138 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
139 if (np->mapping == mapping)
140 return np->name;
141 return NULL;
142 }
145 struct type_entry *lookup(struct tailhead *head, char *name)
146 {
147 struct type_entry *np;
148 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
149 if (!(strcmp(np->name, name)))
150 return np;
151 return NULL;
152 }
154 /* enforces single-entry lists */
155 int add_entry(struct tailhead *head, char *name, type_t mapping)
156 {
157 struct type_entry *e;
158 if (lookup(head, name)) {
159 printf("Error: Type >%s< defined more than once.\n", name);
160 return -EFAULT; /* already in the list */
161 }
162 if (!(e = malloc(sizeof(struct type_entry))))
163 return -ENOMEM;
165 e->name = name;
166 e->mapping = mapping;
167 TAILQ_INSERT_TAIL(head, e, entries);
168 return 0;
169 }
171 int totoken(char *tok)
172 {
173 int i;
174 for (i = 0; token[i] != NULL; i++)
175 if (!strcmp(token[i], tok))
176 return i;
177 return -EFAULT;
178 }
180 /* conflictsets use the same data structure as ssids; since
181 * they are similar in structure (set of types)
182 */
183 int init_next_conflictset(void)
184 {
185 struct ssid_entry *conflictset = malloc(sizeof(struct ssid_entry));
187 if (!conflictset)
188 return -ENOMEM;
190 conflictset->name = current_conflictset_name;
191 conflictset->num = max_conflictsets++;
192 conflictset->is_ref = 0; /* n/a for conflictsets */
193 /**
194 * row: allocate one byte per type;
195 * [i] != 0 --> mapped type >i< is part of the conflictset
196 */
197 conflictset->row = malloc(max_chwall_types);
198 if (!conflictset->row)
199 return -ENOMEM;
201 memset(conflictset->row, 0, max_chwall_types);
202 TAILQ_INSERT_TAIL(&conflictsets_head, conflictset, entries);
203 current_conflictset_p = conflictset;
204 return 0;
205 }
207 int register_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
208 {
209 xmlChar *text;
210 struct type_entry *e;
213 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
214 if (!text) {
215 printf("Error reading type name!\n");
216 return -EFAULT;
217 }
219 switch (state) {
220 case XML2BIN_stetype_S:
221 if (add_entry(&ste_head, (char *) text, max_ste_types)) {
222 xmlFree(text);
223 return -EFAULT;
224 }
225 max_ste_types++;
226 break;
228 case XML2BIN_chwalltype_S:
229 if (add_entry(&chwall_head, (char *) text, max_chwall_types)) {
230 xmlFree(text);
231 return -EFAULT;
232 }
233 max_chwall_types++;
234 break;
236 case XML2BIN_conflictsettype_S:
237 /* a) search the type in the chwall_type list */
238 e = lookup(&chwall_head, (char *) text);
239 if (e == NULL) {
240 printf("CS type >%s< not a CHWALL type.\n", text);
241 xmlFree(text);
242 return -EFAULT;
243 }
244 /* b) add type entry to the current cs set */
245 if (current_conflictset_p->row[e->mapping]) {
246 printf
247 ("ERROR: Double entry of type >%s< in conflict set %d.\n",
248 text, current_conflictset_p->num);
249 xmlFree(text);
250 return -EFAULT;
251 }
252 current_conflictset_p->row[e->mapping] = 1;
253 break;
255 default:
256 printf("Incorrect type environment (state = %lx, text = %s).\n",
257 state, text);
258 xmlFree(text);
259 return -EFAULT;
260 }
261 return 0;
262 }
264 void set_component_type(xmlNode * cur_node, enum policycomponent pc)
265 {
266 xmlChar *order;
268 if ((order =
269 xmlGetProp(cur_node, (xmlChar *) PRIMARY_COMPONENT_ATTR_NAME))) {
270 if (strcmp((char *) order, PRIMARY_COMPONENT)) {
271 printf("ERROR: Illegal attribut value >order=%s<.\n",
272 (char *) order);
273 xmlFree(order);
274 exit(EXIT_FAILURE);
275 }
276 if (primary != NULLPOLICY) {
277 printf("ERROR: Primary Policy Component set twice!\n");
278 exit(EXIT_FAILURE);
279 }
280 primary = pc;
281 xmlFree(order);
282 }
283 }
285 void walk_policy(xmlNode * start, xmlDocPtr doc, unsigned long state)
286 {
287 xmlNode *cur_node = NULL;
288 int code;
290 for (cur_node = start; cur_node; cur_node = cur_node->next) {
291 if ((code = totoken((char *) cur_node->name)) < 0) {
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 case XML2BIN_POLICYHEADER:
301 walk_policy(cur_node->children, doc, state | (1 << code));
302 break;
304 case XML2BIN_POLICYNAME: /* get policy reference name .... */
305 if (state != XML2BIN_PN_S) {
306 printf("ERROR: >Url< >%s< out of context.\n",
307 (char *) xmlNodeListGetString(doc,
308 cur_node->
309 xmlChildrenNode, 1));
310 exit(EXIT_FAILURE);
311 }
312 policy_reference_name = (char *)
313 xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
314 if (!policy_reference_name) {
315 printf("ERROR: empty >policy reference name (Url)<!\n");
316 exit(EXIT_FAILURE);
317 } else
318 printf("Policy Reference name (Url): %s\n",
319 policy_reference_name);
320 break;
322 case XML2BIN_STE:
323 if (WRITTEN_AGAINST_ACM_STE_VERSION != ACM_STE_VERSION) {
324 printf
325 ("ERROR: This program was written against another STE version.\n");
326 exit(EXIT_FAILURE);
327 }
328 have_ste = 1;
329 set_component_type(cur_node, STE);
330 walk_policy(cur_node->children, doc, state | (1 << code));
331 break;
333 case XML2BIN_CHWALL:
334 if (WRITTEN_AGAINST_ACM_CHWALL_VERSION != ACM_CHWALL_VERSION) {
335 printf
336 ("ERROR: This program was written against another CHWALL version.\n");
337 exit(EXIT_FAILURE);
338 }
339 have_chwall = 1;
340 set_component_type(cur_node, CHWALL);
341 walk_policy(cur_node->children, doc, state | (1 << code));
342 break;
344 case XML2BIN_CSTYPE:
345 current_conflictset_name =
346 (char *) xmlGetProp(cur_node, (xmlChar *) "name");
347 if (!current_conflictset_name)
348 current_conflictset_name = "";
350 if (init_next_conflictset()) {
351 printf
352 ("ERROR: creating new conflictset structure failed.\n");
353 exit(EXIT_FAILURE);
354 }
355 walk_policy(cur_node->children, doc, state | (1 << code));
356 break;
358 case XML2BIN_TYPE:
359 if (register_type(cur_node, doc, state))
360 exit(EXIT_FAILURE);
361 /* type leaf */
362 break;
364 case XML2BIN_LABELTEMPLATE: /* handle in second pass */
365 case XML2BIN_TEXT:
366 case XML2BIN_COMMENT:
367 case XML2BIN_DATE:
368 case XML2BIN_REFERENCE:
369 case XML2BIN_NSURL: /* for future use: where to find global label / type name mappings */
370 case XML2BIN_URL: /* for future use: where to find policy */
371 /* leaf - nothing to do */
372 break;
374 default:
375 printf("Unkonwn token Error (%d) in Policy\n", code);
376 exit(EXIT_FAILURE);
377 }
379 }
380 return;
381 }
383 void init_type_mapping(void)
384 {
385 printf("Creating ssid mappings ...\n");
387 /* initialize the ste and chwall type lists */
388 TAILQ_INIT(&ste_head);
389 TAILQ_INIT(&chwall_head);
390 TAILQ_INIT(&conflictsets_head);
391 }
393 void post_type_mapping(void)
394 {
395 struct type_entry *te;
396 struct ssid_entry *se;
397 int i;
399 /* determine primary/secondary policy component orders */
400 if ((primary == NULLPOLICY) && have_chwall)
401 primary = CHWALL; /* default if not set */
402 else if ((primary == NULLPOLICY) && have_ste)
403 primary = STE;
405 switch (primary) {
407 case CHWALL:
408 if (have_ste)
409 secondary = STE;
410 /* else default = NULLPOLICY */
411 break;
413 case STE:
414 if (have_chwall)
415 secondary = CHWALL;
416 /* else default = NULLPOLICY */
417 break;
419 default:
420 /* NULL/NULL policy */
421 break;
422 }
424 if (!DEBUG)
425 return;
427 /* print queues */
428 if (have_ste) {
429 printf("STE-Type queue (%s):\n",
430 (primary == STE) ? "PRIMARY" : "SECONDARY");
431 for (te = ste_head.tqh_first; te != NULL;
432 te = te->entries.tqe_next)
433 printf("name=%22s, map=%x\n", te->name, te->mapping);
434 }
435 if (have_chwall) {
436 printf("CHWALL-Type queue (%s):\n",
437 (primary == CHWALL) ? "PRIMARY" : "SECONDARY");
438 for (te = chwall_head.tqh_first; te != NULL;
439 te = te->entries.tqe_next)
440 printf("name=%s, map=%x\n", te->name, te->mapping);
442 printf("Conflictset queue (max=%d):\n", max_conflictsets);
443 for (se = conflictsets_head.tqh_first; se != NULL;
444 se = se->entries.tqe_next) {
445 printf("conflictset name >%s<\n",
446 se->name ? se->name : "NONAME");
447 for (i = 0; i < max_chwall_types; i++)
448 if (se->row[i])
449 printf("#%x ", i);
450 printf("\n");
451 }
452 }
453 }
456 /***************** template-related parsing *********************/
458 /* add default ssid at head of ssid queues */
459 int init_ssid_queues(void)
460 {
461 struct ssid_entry *default_ssid_chwall, *default_ssid_ste;
463 default_ssid_chwall = malloc(sizeof(struct ssid_entry));
464 default_ssid_ste = malloc(sizeof(struct ssid_entry));
466 if ((!default_ssid_chwall) || (!default_ssid_ste))
467 return -ENOMEM;
469 /* default chwall ssid */
470 default_ssid_chwall->name = "DEFAULT";
471 default_ssid_chwall->num = max_chwall_ssids++;
472 default_ssid_chwall->is_ref = 0;
473 default_ssid_chwall->type = ANY;
475 default_ssid_chwall->row = malloc(max_chwall_types);
477 if (!default_ssid_chwall->row)
478 return -ENOMEM;
480 memset(default_ssid_chwall->row, 0, max_chwall_types);
482 TAILQ_INSERT_TAIL(&chwall_ssid_head, default_ssid_chwall, entries);
483 current_chwall_ssid_p = default_ssid_chwall;
484 max_chwall_labels++;
486 /* default ste ssid */
487 default_ssid_ste->name = "DEFAULT";
488 default_ssid_ste->num = max_ste_ssids++;
489 default_ssid_ste->is_ref = 0;
490 default_ssid_ste->type = ANY;
492 default_ssid_ste->row = malloc(max_ste_types);
494 if (!default_ssid_ste->row)
495 return -ENOMEM;
497 memset(default_ssid_ste->row, 0, max_ste_types);
499 TAILQ_INSERT_TAIL(&ste_ssid_head, default_ssid_ste, entries);
500 current_ste_ssid_p = default_ssid_ste;
501 max_ste_labels++;
502 return 0;
503 }
505 int init_next_chwall_ssid(unsigned long state)
506 {
507 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
509 if (!ssid)
510 return -ENOMEM;
512 ssid->name = current_ssid_name;
513 ssid->num = max_chwall_ssids++;
514 ssid->is_ref = 0;
516 if (state & (1 << XML2BIN_VM))
517 ssid->type = VM;
518 else
519 ssid->type = RES;
520 /**
521 * row: allocate one byte per type;
522 * [i] != 0 --> mapped type >i< is part of the ssid
523 */
524 ssid->row = malloc(max_chwall_types);
525 if (!ssid->row)
526 return -ENOMEM;
528 memset(ssid->row, 0, max_chwall_types);
529 TAILQ_INSERT_TAIL(&chwall_ssid_head, ssid, entries);
530 current_chwall_ssid_p = ssid;
531 max_chwall_labels++;
532 return 0;
533 }
535 int init_next_ste_ssid(unsigned long state)
536 {
537 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
539 if (!ssid)
540 return -ENOMEM;
542 ssid->name = current_ssid_name;
543 ssid->num = max_ste_ssids++;
544 ssid->is_ref = 0;
546 if (state & (1 << XML2BIN_VM))
547 ssid->type = VM;
548 else
549 ssid->type = RES;
551 /**
552 * row: allocate one byte per type;
553 * [i] != 0 --> mapped type >i< is part of the ssid
554 */
555 ssid->row = malloc(max_ste_types);
556 if (!ssid->row)
557 return -ENOMEM;
559 memset(ssid->row, 0, max_ste_types);
560 TAILQ_INSERT_TAIL(&ste_ssid_head, ssid, entries);
561 current_ste_ssid_p = ssid;
562 max_ste_labels++;
564 return 0;
565 }
568 /* adds a type to the current ssid */
569 int add_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
570 {
571 xmlChar *text;
572 struct type_entry *e;
574 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
575 if (!text) {
576 printf("Error reading type name!\n");
577 return -EFAULT;
578 }
579 /* same for all: 1. lookup type mapping, 2. mark type in ssid */
580 switch (state) {
581 case XML2BIN_VM_STE_S:
582 case XML2BIN_RES_STE_S:
583 /* lookup the type mapping and include the type mapping into the array */
584 if (!(e = lookup(&ste_head, (char *) text))) {
585 printf("ERROR: unknown VM STE type >%s<.\n", text);
586 exit(EXIT_FAILURE);
587 }
588 if (current_ste_ssid_p->row[e->mapping])
589 printf("Warning: double entry of VM STE type >%s<.\n", text);
591 current_ste_ssid_p->row[e->mapping] = 1;
592 break;
594 case XML2BIN_VM_CHWALL_S:
595 /* lookup the type mapping and include the type mapping into the array */
596 if (!(e = lookup(&chwall_head, (char *) text))) {
597 printf("ERROR: unknown VM CHWALL type >%s<.\n", text);
598 exit(EXIT_FAILURE);
599 }
600 if (current_chwall_ssid_p->row[e->mapping])
601 printf("Warning: double entry of VM CHWALL type >%s<.\n",
602 text);
604 current_chwall_ssid_p->row[e->mapping] = 1;
605 break;
607 default:
608 printf("Incorrect type environment (state = %lx, text = %s).\n",
609 state, text);
610 xmlFree(text);
611 return -EFAULT;
612 }
613 return 0;
614 }
616 void set_bootstrap_label(xmlNode * cur_node)
617 {
618 xmlChar *order;
620 if ((order =
621 xmlGetProp(cur_node, (xmlChar *) BOOTSTRAP_LABEL_ATTR_NAME)))
622 bootstrap_label = (char *) order;
623 else {
624 printf("ERROR: No bootstrap label defined!\n");
625 exit(EXIT_FAILURE);
626 }
627 }
629 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state)
630 {
631 xmlNode *cur_node = NULL;
632 int code;
634 for (cur_node = start; cur_node; cur_node = cur_node->next) {
635 if ((code = totoken((char *) cur_node->name)) < 0) {
636 printf("Unkonwn token: >%s<. Aborting.\n", cur_node->name);
637 exit(EXIT_FAILURE);
638 }
639 switch (code) { /* adjust state to new state */
640 case XML2BIN_SUBJECTS:
641 set_bootstrap_label(cur_node);
642 /* fall through */
643 case XML2BIN_SECPOL:
644 case XML2BIN_LABELTEMPLATE:
645 case XML2BIN_VM:
646 case XML2BIN_RES:
647 case XML2BIN_OBJECTS:
648 walk_labels(cur_node->children, doc, state | (1 << code));
649 break;
651 case XML2BIN_STETYPES:
652 /* create new ssid entry to use and point current to it */
653 if (init_next_ste_ssid(state)) {
654 printf("ERROR: creating new ste ssid structure failed.\n");
655 exit(EXIT_FAILURE);
656 }
657 walk_labels(cur_node->children, doc, state | (1 << code));
658 break;
660 case XML2BIN_CHWALLTYPES:
661 /* create new ssid entry to use and point current to it */
662 if (init_next_chwall_ssid(state)) {
663 printf
664 ("ERROR: creating new chwall ssid structure failed.\n");
665 exit(EXIT_FAILURE);
666 }
667 walk_labels(cur_node->children, doc, state | (1 << code));
668 break;
670 case XML2BIN_TYPE:
671 /* add type to current ssid */
672 if (add_type(cur_node, doc, state))
673 exit(EXIT_FAILURE);
674 break;
676 case XML2BIN_NAME:
677 if ((state == XML2BIN_VM_S) || (state == XML2BIN_RES_S)) {
678 current_ssid_name = (char *)
679 xmlNodeListGetString(doc, cur_node->xmlChildrenNode,
680 1);
681 if (!current_ssid_name) {
682 printf("ERROR: empty >vm/res name<!\n");
683 exit(EXIT_FAILURE);
684 }
685 } else {
686 printf
687 ("ERROR: >name< >%s< out of context (state = 0x%lx.\n",
688 (char *) xmlNodeListGetString(doc,
689 cur_node->
690 xmlChildrenNode, 1),
691 state);
692 exit(EXIT_FAILURE);
693 }
694 break;
696 case XML2BIN_TEXT:
697 case XML2BIN_COMMENT:
698 case XML2BIN_POLICYHEADER:
699 case XML2BIN_STE:
700 case XML2BIN_CHWALL:
701 break;
703 default:
704 printf("Unkonwn token Error (%d) in Label Template\n", code);
705 exit(EXIT_FAILURE);
706 }
707 }
708 return;
709 }
711 /*
712 * will go away as soon as we have non-static bootstrap ssidref for dom0
713 */
714 void fixup_bootstrap_label(struct tailhead_ssid *head,
715 u_int32_t max_types, u_int32_t * max_ssids)
716 {
717 struct ssid_entry *np;
718 int i;
720 /* should not happen if xml / xsd checks work */
721 if (!bootstrap_label) {
722 printf("ERROR: No bootstrap label defined.\n");
723 exit(EXIT_FAILURE);
724 }
726 /* search bootstrap_label */
727 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) {
728 if (!strcmp(np->name, bootstrap_label)) {
729 break;
730 }
731 }
733 if (!np) {
734 /* bootstrap label not found */
735 printf("ERROR: Bootstrap label >%s< not found.\n",
736 bootstrap_label);
737 exit(EXIT_FAILURE);
738 }
740 /* move this entry ahead in the list right after the default entry so it
741 * receives ssidref 1/1 */
742 TAILQ_REMOVE(head, np, entries);
743 TAILQ_INSERT_AFTER(head, head->tqh_first, np, entries);
745 /* renumber the ssids (we could also just switch places with 1st element) */
746 for (np = head->tqh_first, i = 0; np != NULL;
747 np = np->entries.tqe_next, i++)
748 np->num = i;
750 }
752 void init_label_mapping(void)
753 {
755 printf("Creating label mappings ...\n");
756 /* initialize the ste and chwall type lists */
757 TAILQ_INIT(&chwall_ssid_head);
758 TAILQ_INIT(&ste_ssid_head);
760 /* init with default ssids */
761 if (init_ssid_queues()) {
762 printf("ERROR adding default ssids.\n");
763 exit(EXIT_FAILURE);
764 }
765 }
767 void post_label_mapping(void)
768 {
769 struct ssid_entry *np;
770 int i;
772 /*
773 * now sort bootstrap label to the head of the list
774 * (for now), dom0 assumes its label in the first
775 * defined ssidref (1/1). 0/0 is the default non-Label
776 */
777 if (have_chwall)
778 fixup_bootstrap_label(&chwall_ssid_head, max_chwall_types,
779 &max_chwall_ssids);
780 if (have_ste)
781 fixup_bootstrap_label(&ste_ssid_head, max_ste_types,
782 &max_ste_ssids);
784 if (!DEBUG)
785 return;
787 /* print queues */
788 if (have_chwall) {
789 printf("CHWALL SSID queue (max ssidrefs=%d):\n", max_chwall_ssids);
790 np = NULL;
791 for (np = chwall_ssid_head.tqh_first; np != NULL;
792 np = np->entries.tqe_next) {
793 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
794 if (np->is_ref)
795 printf("REFERENCE");
796 else
797 for (i = 0; i < max_chwall_types; i++)
798 if (np->row[i])
799 printf("#%02d ", i);
800 printf("\n\n");
801 }
802 }
803 if (have_ste) {
804 printf("STE SSID queue (max ssidrefs=%d):\n", max_ste_ssids);
805 np = NULL;
806 for (np = ste_ssid_head.tqh_first; np != NULL;
807 np = np->entries.tqe_next) {
808 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
809 if (np->is_ref)
810 printf("REFERENCE");
811 else
812 for (i = 0; i < max_ste_types; i++)
813 if (np->row[i])
814 printf("#%02d ", i);
815 printf("\n\n");
816 }
817 }
818 }
820 void create_mappings(xmlDocPtr doc)
821 {
822 xmlNode *doc_root_node = xmlDocGetRootElement(doc);
824 /* walk the XML policy tree and fill in types and labels */
825 init_type_mapping();
826 walk_policy(doc_root_node, doc, XML2BIN_NULL); /* first pass: types */
827 post_type_mapping();
828 init_label_mapping();
829 walk_labels(doc_root_node, doc, XML2BIN_NULL); /* second pass: labels */
830 post_label_mapping();
831 }
833 /***************** writing the binary policy *********************/
835 /*
836 * the mapping file is ascii-based since it will likely be used from
837 * within scripts (using awk, grep, etc.);
838 *
839 * We print from high-level to low-level information so that with one
840 * pass, any symbol can be resolved (e.g. Label -> types)
841 */
842 int write_mapping(char *filename)
843 {
845 struct ssid_entry *e;
846 struct type_entry *t;
847 int i;
848 FILE *file;
850 if ((file = fopen(filename, "w")) == NULL)
851 return -EIO;
853 fprintf(file, "POLICYREFERENCENAME %s\n", policy_reference_name);
854 fprintf(file, "MAGIC %08x\n", ACM_MAGIC);
855 fprintf(file, "POLICY FILE %s\n", policy_filename);
856 fprintf(file, "BINARY FILE %s\n", binary_filename);
857 if (have_chwall) {
858 fprintf(file, "MAX-CHWALL-TYPES %08x\n", max_chwall_types);
859 fprintf(file, "MAX-CHWALL-SSIDS %08x\n", max_chwall_ssids);
860 fprintf(file, "MAX-CHWALL-LABELS %08x\n", max_chwall_labels);
861 }
862 if (have_ste) {
863 fprintf(file, "MAX-STE-TYPES %08x\n", max_ste_types);
864 fprintf(file, "MAX-STE-SSIDS %08x\n", max_ste_ssids);
865 fprintf(file, "MAX-STE-LABELS %08x\n", max_ste_labels);
866 }
867 fprintf(file, "\n");
869 /* primary / secondary order for combined ssid synthesis/analysis
870 * if no primary is named, then chwall is primary */
871 switch (primary) {
872 case CHWALL:
873 fprintf(file, "PRIMARY CHWALL\n");
874 break;
876 case STE:
877 fprintf(file, "PRIMARY STE\n");
878 break;
880 default:
881 fprintf(file, "PRIMARY NULL\n");
882 break;
883 }
885 switch (secondary) {
886 case CHWALL:
887 fprintf(file, "SECONDARY CHWALL\n");
888 break;
890 case STE:
891 fprintf(file, "SECONDARY STE\n");
892 break;
894 default:
895 fprintf(file, "SECONDARY NULL\n");
896 break;
897 }
898 fprintf(file, "\n");
900 /* first labels to ssid mappings */
901 if (have_chwall) {
902 for (e = chwall_ssid_head.tqh_first; e != NULL;
903 e = e->entries.tqe_next) {
904 fprintf(file, "LABEL->SSID %s CHWALL %-25s %8x\n",
905 (e->type ==
906 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
907 e->name, e->num);
908 }
909 fprintf(file, "\n");
910 }
911 if (have_ste) {
912 for (e = ste_ssid_head.tqh_first; e != NULL;
913 e = e->entries.tqe_next) {
914 fprintf(file, "LABEL->SSID %s STE %-25s %8x\n",
915 (e->type ==
916 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
917 e->name, e->num);
918 }
919 fprintf(file, "\n");
920 }
922 /* second ssid to type mappings */
923 if (have_chwall) {
924 for (e = chwall_ssid_head.tqh_first; e != NULL;
925 e = e->entries.tqe_next) {
926 if (e->is_ref)
927 continue;
929 fprintf(file, "SSID->TYPE CHWALL %08x", e->num);
931 for (i = 0; i < max_chwall_types; i++)
932 if (e->row[i])
933 fprintf(file, " %s", type_by_mapping(&chwall_head, i));
935 fprintf(file, "\n");
936 }
937 fprintf(file, "\n");
938 }
939 if (have_ste) {
940 for (e = ste_ssid_head.tqh_first; e != NULL;
941 e = e->entries.tqe_next) {
942 if (e->is_ref)
943 continue;
945 fprintf(file, "SSID->TYPE STE %08x", e->num);
947 for (i = 0; i < max_ste_types; i++)
948 if (e->row[i])
949 fprintf(file, " %s", type_by_mapping(&ste_head, i));
951 fprintf(file, "\n");
952 }
953 fprintf(file, "\n");
954 }
955 /* third type mappings */
956 if (have_chwall) {
957 for (t = chwall_head.tqh_first; t != NULL; t = t->entries.tqe_next) {
958 fprintf(file, "TYPE CHWALL %-25s %8x\n",
959 t->name, t->mapping);
960 }
961 fprintf(file, "\n");
962 }
963 if (have_ste) {
964 for (t = ste_head.tqh_first; t != NULL; t = t->entries.tqe_next) {
965 fprintf(file, "TYPE STE %-25s %8x\n",
966 t->name, t->mapping);
967 }
968 fprintf(file, "\n");
969 }
970 fclose(file);
971 return 0;
972 }
975 unsigned char *write_policy_reference_binary(u_int32_t * len_pr)
976 {
977 unsigned char *buf, *ptr;
978 struct acm_policy_reference_buffer *pr_header;
979 u_int32_t len;
981 if (policy_reference_name == NULL) {
982 printf("ERROR: No policy reference name found.\n");
983 exit(EXIT_FAILURE);
984 }
985 len = (sizeof(struct acm_policy_reference_buffer) +
986 strlen(policy_reference_name) + 1);
987 buf = malloc(len);
988 ptr = buf;
990 if (!buf) {
991 printf
992 ("ERROR: out of memory allocating label reference buffer.\n");
993 exit(EXIT_FAILURE);
994 }
995 pr_header = (struct acm_policy_reference_buffer *) buf;
996 pr_header->len =
997 htonl(strlen(policy_reference_name) + 1 /* strend \'0' */ );
998 ptr += sizeof(struct acm_policy_reference_buffer);
999 strcpy((char *) ptr, policy_reference_name);
1001 (*len_pr) = len;
1002 return buf;
1006 unsigned char *write_chwall_binary(u_int32_t * len_chwall)
1008 unsigned char *buf, *ptr;
1009 struct acm_chwall_policy_buffer *chwall_header;
1010 u_int32_t len;
1011 struct ssid_entry *e;
1012 int i;
1014 if (!have_chwall)
1015 return NULL;
1017 len = sizeof(struct acm_chwall_policy_buffer) +
1018 sizeof(type_t) * max_chwall_types * max_chwall_ssids +
1019 sizeof(type_t) * max_chwall_types * max_conflictsets;
1021 buf = malloc(len);
1022 ptr = buf;
1024 if (!buf) {
1025 printf("ERROR: out of memory allocating chwall buffer.\n");
1026 exit(EXIT_FAILURE);
1028 /* chwall has 3 parts : header, types, conflictsets */
1030 chwall_header = (struct acm_chwall_policy_buffer *) buf;
1031 chwall_header->chwall_max_types = htonl(max_chwall_types);
1032 chwall_header->chwall_max_ssidrefs = htonl(max_chwall_ssids);
1033 chwall_header->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1034 chwall_header->policy_version = htonl(ACM_CHWALL_VERSION);
1035 chwall_header->chwall_ssid_offset =
1036 htonl(sizeof(struct acm_chwall_policy_buffer));
1037 chwall_header->chwall_max_conflictsets = htonl(max_conflictsets);
1038 chwall_header->chwall_conflict_sets_offset =
1039 htonl(ntohl(chwall_header->chwall_ssid_offset) +
1040 sizeof(domaintype_t) * max_chwall_ssids * max_chwall_types);
1041 chwall_header->chwall_running_types_offset = 0;
1042 chwall_header->chwall_conflict_aggregate_offset = 0;
1043 ptr += sizeof(struct acm_chwall_policy_buffer);
1045 /* types */
1046 for (e = chwall_ssid_head.tqh_first; e != NULL;
1047 e = e->entries.tqe_next) {
1048 if (e->is_ref)
1049 continue;
1051 for (i = 0; i < max_chwall_types; i++)
1052 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1054 ptr += sizeof(type_t) * max_chwall_types;
1057 /* conflictsets */
1058 for (e = conflictsets_head.tqh_first; e != NULL;
1059 e = e->entries.tqe_next) {
1060 for (i = 0; i < max_chwall_types; i++)
1061 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1063 ptr += sizeof(type_t) * max_chwall_types;
1066 if ((ptr - buf) != len) {
1067 printf("ERROR: wrong lengths in %s.\n", __func__);
1068 exit(EXIT_FAILURE);
1071 (*len_chwall) = len;
1072 return buf;
1075 unsigned char *write_ste_binary(u_int32_t * len_ste)
1077 unsigned char *buf, *ptr;
1078 struct acm_ste_policy_buffer *ste_header;
1079 struct ssid_entry *e;
1080 u_int32_t len;
1081 int i;
1083 if (!have_ste)
1084 return NULL;
1086 len = sizeof(struct acm_ste_policy_buffer) +
1087 sizeof(type_t) * max_ste_types * max_ste_ssids;
1089 buf = malloc(len);
1090 ptr = buf;
1092 if (!buf) {
1093 printf("ERROR: out of memory allocating chwall buffer.\n");
1094 exit(EXIT_FAILURE);
1097 /* fill buffer */
1098 ste_header = (struct acm_ste_policy_buffer *) buf;
1099 ste_header->policy_version = htonl(ACM_STE_VERSION);
1100 ste_header->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1101 ste_header->ste_max_types = htonl(max_ste_types);
1102 ste_header->ste_max_ssidrefs = htonl(max_ste_ssids);
1103 ste_header->ste_ssid_offset =
1104 htonl(sizeof(struct acm_ste_policy_buffer));
1106 ptr += sizeof(struct acm_ste_policy_buffer);
1108 /* types */
1109 for (e = ste_ssid_head.tqh_first; e != NULL; e = e->entries.tqe_next) {
1110 if (e->is_ref)
1111 continue;
1113 for (i = 0; i < max_ste_types; i++)
1114 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1116 ptr += sizeof(type_t) * max_ste_types;
1119 if ((ptr - buf) != len) {
1120 printf("ERROR: wrong lengths in %s.\n", __func__);
1121 exit(EXIT_FAILURE);
1123 (*len_ste) = len;
1124 return buf; /* for now */
1127 int write_binary(char *filename)
1129 struct acm_policy_buffer header;
1130 unsigned char *ste_buffer = NULL, *chwall_buffer =
1131 NULL, *policy_reference_buffer = NULL;
1132 u_int32_t len;
1133 int fd, ret = 0;
1135 u_int32_t len_ste = 0, len_chwall = 0, len_pr = 0; /* length of policy components */
1137 /* open binary file */
1138 if ((fd =
1139 open(filename, O_WRONLY | O_CREAT | O_TRUNC,
1140 S_IRUSR | S_IWUSR)) <= 0) {
1141 ret = -EIO;
1142 goto out1;
1144 policy_reference_buffer = write_policy_reference_binary(&len_pr);
1145 ste_buffer = write_ste_binary(&len_ste);
1146 chwall_buffer = write_chwall_binary(&len_chwall);
1148 /* determine primary component (default chwall) */
1149 header.policy_version = htonl(ACM_POLICY_VERSION);
1150 header.magic = htonl(ACM_MAGIC);
1152 len = sizeof(struct acm_policy_buffer);
1153 if (have_chwall)
1154 len += len_chwall;
1155 if (have_ste)
1156 len += len_ste;
1157 len += len_pr; /* policy reference is mandatory */
1158 header.len = htonl(len);
1160 header.policy_reference_offset =
1161 htonl(sizeof(struct acm_policy_buffer));
1163 header.primary_buffer_offset =
1164 htonl(sizeof(struct acm_policy_buffer) + len_pr);
1165 if (primary == CHWALL) {
1166 header.primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1167 header.secondary_buffer_offset =
1168 htonl((sizeof(struct acm_policy_buffer)) + len_pr +
1169 len_chwall);
1170 } else if (primary == STE) {
1171 header.primary_policy_code =
1172 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1173 header.secondary_buffer_offset =
1174 htonl((sizeof(struct acm_policy_buffer)) + len_pr +
1175 len_ste);
1176 } else {
1177 /* null policy */
1178 header.primary_policy_code = htonl(ACM_NULL_POLICY);
1179 header.secondary_buffer_offset =
1180 htonl(header.primary_buffer_offset);
1183 if (secondary == CHWALL)
1184 header.secondary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1185 else if (secondary == STE)
1186 header.secondary_policy_code =
1187 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1188 else
1189 header.secondary_policy_code = htonl(ACM_NULL_POLICY);
1191 if (write(fd, (void *) &header, sizeof(struct acm_policy_buffer))
1192 != sizeof(struct acm_policy_buffer)) {
1193 ret = -EIO;
1194 goto out1;
1197 /* write label reference name */
1198 if (write(fd, policy_reference_buffer, len_pr) != len_pr) {
1199 ret = -EIO;
1200 goto out1;
1202 /* write primary policy component */
1203 if (primary == CHWALL) {
1204 if (write(fd, chwall_buffer, len_chwall) != len_chwall) {
1205 ret = -EIO;
1206 goto out1;
1208 } else if (primary == STE) {
1209 if (write(fd, ste_buffer, len_ste) != len_ste) {
1210 ret = -EIO;
1211 goto out1;
1213 } else; /* NULL POLICY has no policy data */
1215 /* write secondary policy component */
1216 if (secondary == CHWALL) {
1217 if (write(fd, chwall_buffer, len_chwall) != len_chwall) {
1218 ret = -EIO;
1219 goto out1;
1221 } else if (secondary == STE) {
1222 if (write(fd, ste_buffer, len_ste) != len_ste) {
1223 ret = -EIO;
1224 goto out1;
1226 } else; /* NULL POLICY has no policy data */
1228 out1:
1229 /* cleanup */
1230 if (policy_reference_buffer)
1231 free(policy_reference_buffer);
1232 if (chwall_buffer)
1233 free(chwall_buffer);
1234 if (ste_buffer)
1235 free(ste_buffer);
1236 close(fd);
1237 return ret;
1240 int is_valid(xmlDocPtr doc)
1242 int err = 0;
1243 xmlSchemaPtr schema_ctxt = NULL;
1244 xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL;
1245 xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL;
1247 schemaparser_ctxt = xmlSchemaNewParserCtxt(schema_filename);
1248 schema_ctxt = xmlSchemaParse(schemaparser_ctxt);
1249 schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt);
1251 #ifdef VALIDATE_SCHEMA
1252 /* only tested to be available from libxml2-2.6.20 upwards */
1253 if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1) {
1254 printf("ERROR: Invalid schema file %s (err=%d)\n",
1255 schema_filename, err);
1256 err = -EIO;
1257 goto out;
1258 } else
1259 printf("XML Schema %s valid.\n", schema_filename);
1260 #endif
1261 if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc))) {
1262 err = -EIO;
1263 goto out;
1265 out:
1266 xmlSchemaFreeValidCtxt(schemavalid_ctxt);
1267 xmlSchemaFreeParserCtxt(schemaparser_ctxt);
1268 xmlSchemaFree(schema_ctxt);
1269 return (err != 0) ? 0 : 1;
1272 int main(int argc, char **argv)
1274 xmlDocPtr policydoc = NULL;
1276 int err = EXIT_FAILURE;
1278 char *file_prefix;
1279 int prefix_len;
1281 int opt_char;
1282 char *policy_dir = POLICY_DIR;
1284 if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION) {
1285 printf
1286 ("ERROR: This program was written against an older ACM version.\n");
1287 printf("ERROR: ACM_POLICY_VERSION=%d, WRITTEN AGAINST= %d.\n",
1288 ACM_POLICY_VERSION, WRITTEN_AGAINST_ACM_POLICY_VERSION);
1289 exit(EXIT_FAILURE);
1292 while ((opt_char = getopt(argc, argv, "d:")) != -1) {
1293 switch (opt_char) {
1294 case 'd':
1295 policy_dir = malloc(strlen(optarg) + 2); /* null terminator and possibly "/" */
1296 if (!policy_dir) {
1297 printf("ERROR allocating directory name memory.\n");
1298 exit(EXIT_FAILURE);
1300 strcpy(policy_dir, optarg);
1301 if (policy_dir[strlen(policy_dir) - 1] != '/')
1302 strcat(policy_dir, "/");
1303 break;
1305 default:
1306 usage(basename(argv[0]));
1310 if ((argc - optind) != 1)
1311 usage(basename(argv[0]));
1313 printf("arg=%s\n", argv[optind]);
1315 prefix_len =
1316 strlen(policy_dir) + strlen(argv[optind]) +
1317 1 /* null terminator */ ;
1319 file_prefix = malloc(prefix_len);
1320 policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION));
1321 binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION));
1322 mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION));
1323 schema_filename =
1324 malloc(strlen(policy_dir) + strlen(SCHEMA_FILENAME) + 1);
1326 if (!file_prefix || !policy_filename ||
1327 !binary_filename || !mapping_filename || !schema_filename) {
1328 printf("ERROR allocating file name memory.\n");
1329 goto out2;
1332 /* create input/output filenames out of prefix */
1333 strcpy(file_prefix, policy_dir);
1334 strcat(file_prefix, argv[optind]);
1336 strcpy(policy_filename, file_prefix);
1337 strcpy(binary_filename, file_prefix);
1338 strcpy(mapping_filename, file_prefix);
1340 strcat(policy_filename, POLICY_EXTENSION);
1341 strcat(binary_filename, BINARY_EXTENSION);
1342 strcat(mapping_filename, MAPPING_EXTENSION);
1344 strcpy(schema_filename, policy_dir);
1345 strcat(schema_filename, SCHEMA_FILENAME);
1347 policydoc = xmlParseFile(policy_filename);
1349 if (policydoc == NULL) {
1350 printf("Error: could not parse file %s.\n", argv[optind]);
1351 goto out;
1354 printf("Validating policy file %s...\n", policy_filename);
1356 if (!is_valid(policydoc)) {
1357 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1358 policy_filename, err);
1359 goto out;
1362 /* create mappings */
1363 create_mappings(policydoc);
1365 /* write label mapping file */
1366 if (write_mapping(mapping_filename)) {
1367 printf("ERROR: writing mapping file %s.\n", mapping_filename);
1368 goto out;
1371 /* write binary file */
1372 if (write_binary(binary_filename)) {
1373 printf("ERROR: writing binary file %s.\n", binary_filename);
1374 goto out;
1376 err = EXIT_SUCCESS;
1377 /* write stats */
1378 if (have_chwall) {
1379 printf("Max chwall labels: %u\n", max_chwall_labels);
1380 printf("Max chwall-types: %u\n", max_chwall_types);
1381 printf("Max chwall-ssids: %u\n", max_chwall_ssids);
1384 if (have_ste) {
1385 printf("Max ste labels: %u\n", max_ste_labels);
1386 printf("Max ste-types: %u\n", max_ste_types);
1387 printf("Max ste-ssids: %u\n", max_ste_ssids);
1389 /* cleanup */
1390 out:
1391 xmlFreeDoc(policydoc);
1392 out2:
1393 xmlCleanupParser();
1394 return err;
1397 /*
1398 * Local variables:
1399 * mode: C
1400 * c-set-style: "BSD"
1401 * c-basic-offset: 4
1402 * tab-width: 4
1403 * indent-tabs-mode: nil
1404 * End:
1405 */