direct-io.hg

view tools/security/secpol_xml2bin.c @ 11330:3e54734e55f3

[IA64] Remove extraneous verbose output to clean up Fedora boot.

Signed-off-by: Aron Griffis <aron@hp.com>
author awilliam@xenbuild.aw
date Wed Aug 23 13:26:46 2006 -0600 (2006-08-23)
parents 0de8a4a023d0
children 7b99b8bdbc85
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 #define NULL_LABEL_NAME "__NULL_LABEL__"
49 /* primary / secondary policy component setting */
50 enum policycomponent { CHWALL, STE, NULLPOLICY }
51 primary = NULLPOLICY, secondary = NULLPOLICY;
53 /* general list element for ste and chwall type queues */
54 struct type_entry {
55 TAILQ_ENTRY(type_entry) entries;
56 char *name; /* name of type from xml file */
57 type_t mapping; /* type mapping into 16bit */
58 };
60 TAILQ_HEAD(tailhead, type_entry) ste_head, chwall_head;
62 /* general list element for all label queues */
63 enum label_type { VM, RES, ANY };
64 struct ssid_entry {
65 TAILQ_ENTRY(ssid_entry) entries;
66 char *name; /* label name */
67 enum label_type type; /* type: VM / RESOURCE LABEL */
68 u_int32_t num; /* ssid or referenced ssid */
69 int is_ref; /* if this entry references earlier ssid number */
70 unsigned char *row; /* index of types (if not a reference) */
71 };
73 TAILQ_HEAD(tailhead_ssid, ssid_entry) ste_ssid_head, chwall_ssid_head,
74 conflictsets_head;
75 struct ssid_entry *current_chwall_ssid_p = NULL;
76 struct ssid_entry *current_ste_ssid_p = NULL;
77 struct ssid_entry *current_conflictset_p = NULL;
79 /* which label to assign to dom0 during boot */
80 char *bootstrap_label;
82 u_int32_t max_ste_ssids = 0;
83 u_int32_t max_chwall_ssids = 0;
84 u_int32_t max_chwall_labels = 0;
85 u_int32_t max_ste_labels = 0;
86 u_int32_t max_conflictsets = 0;
88 char *current_ssid_name; /* store name until structure is allocated */
89 char *current_conflictset_name; /* store name until structure is allocated */
91 /* dynamic list of type mappings for STE */
92 u_int32_t max_ste_types = 0;
94 /* dynamic list of type mappings for CHWALL */
95 u_int32_t max_chwall_types = 0;
97 /* dynamic list of conflict sets */
98 int max_conflict_set = 0;
100 /* which policies are defined */
101 int have_ste = 0;
102 int have_chwall = 0;
104 /* input/output file names */
105 char *policy_filename = NULL,
106 *binary_filename = NULL,
107 *mapping_filename = NULL, *schema_filename = NULL;
109 char *policy_reference_name = NULL;
111 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state);
113 void usage(char *prg)
114 {
115 printf("Usage: %s [OPTIONS] POLICYNAME\n", prg);
116 printf
117 ("POLICYNAME is the directory name within the policy directory\n");
118 printf
119 ("that contains the policy files. The default policy directory\n");
120 printf("is '%s' (see the '-d' option below to change it)\n",
121 POLICY_DIR);
122 printf
123 ("The policy files contained in the POLICYNAME directory must be named:\n");
124 printf("\tPOLICYNAME-security_policy.xml\n");
125 printf("\tPOLICYNAME-security_label_template.xml\n\n");
126 printf("OPTIONS:\n");
127 printf("\t-d POLICYDIR\n");
128 printf
129 ("\t\tUse POLICYDIR as the policy directory. This directory must contain\n");
130 printf("\t\tthe policy schema file 'security_policy.xsd'\n");
131 exit(EXIT_FAILURE);
132 }
135 /***************** policy-related parsing *********************/
137 char *type_by_mapping(struct tailhead *head, u_int32_t mapping)
138 {
139 struct type_entry *np;
140 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
141 if (np->mapping == mapping)
142 return np->name;
143 return NULL;
144 }
147 struct type_entry *lookup(struct tailhead *head, char *name)
148 {
149 struct type_entry *np;
150 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next)
151 if (!(strcmp(np->name, name)))
152 return np;
153 return NULL;
154 }
156 /* enforces single-entry lists */
157 int add_entry(struct tailhead *head, char *name, type_t mapping)
158 {
159 struct type_entry *e;
160 if (lookup(head, name)) {
161 printf("Error: Type >%s< defined more than once.\n", name);
162 return -EFAULT; /* already in the list */
163 }
164 if (!(e = malloc(sizeof(struct type_entry))))
165 return -ENOMEM;
167 e->name = name;
168 e->mapping = mapping;
169 TAILQ_INSERT_TAIL(head, e, entries);
170 return 0;
171 }
173 int totoken(char *tok)
174 {
175 int i;
176 for (i = 0; token[i] != NULL; i++)
177 if (!strcmp(token[i], tok))
178 return i;
179 return -EFAULT;
180 }
182 /* conflictsets use the same data structure as ssids; since
183 * they are similar in structure (set of types)
184 */
185 int init_next_conflictset(void)
186 {
187 struct ssid_entry *conflictset = malloc(sizeof(struct ssid_entry));
189 if (!conflictset)
190 return -ENOMEM;
192 conflictset->name = current_conflictset_name;
193 conflictset->num = max_conflictsets++;
194 conflictset->is_ref = 0; /* n/a for conflictsets */
195 /**
196 * row: allocate one byte per type;
197 * [i] != 0 --> mapped type >i< is part of the conflictset
198 */
199 conflictset->row = malloc(max_chwall_types);
200 if (!conflictset->row)
201 return -ENOMEM;
203 memset(conflictset->row, 0, max_chwall_types);
204 TAILQ_INSERT_TAIL(&conflictsets_head, conflictset, entries);
205 current_conflictset_p = conflictset;
206 return 0;
207 }
209 int register_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
210 {
211 xmlChar *text;
212 struct type_entry *e;
215 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
216 if (!text) {
217 printf("Error reading type name!\n");
218 return -EFAULT;
219 }
221 switch (state) {
222 case XML2BIN_stetype_S:
223 if (add_entry(&ste_head, (char *) text, max_ste_types)) {
224 xmlFree(text);
225 return -EFAULT;
226 }
227 max_ste_types++;
228 break;
230 case XML2BIN_chwalltype_S:
231 if (add_entry(&chwall_head, (char *) text, max_chwall_types)) {
232 xmlFree(text);
233 return -EFAULT;
234 }
235 max_chwall_types++;
236 break;
238 case XML2BIN_conflictsettype_S:
239 /* a) search the type in the chwall_type list */
240 e = lookup(&chwall_head, (char *) text);
241 if (e == NULL) {
242 printf("CS type >%s< not a CHWALL type.\n", text);
243 xmlFree(text);
244 return -EFAULT;
245 }
246 /* b) add type entry to the current cs set */
247 if (current_conflictset_p->row[e->mapping]) {
248 printf
249 ("ERROR: Double entry of type >%s< in conflict set %d.\n",
250 text, current_conflictset_p->num);
251 xmlFree(text);
252 return -EFAULT;
253 }
254 current_conflictset_p->row[e->mapping] = 1;
255 break;
257 default:
258 printf("Incorrect type environment (state = %lx, text = %s).\n",
259 state, text);
260 xmlFree(text);
261 return -EFAULT;
262 }
263 return 0;
264 }
266 void set_component_type(xmlNode * cur_node, enum policycomponent pc)
267 {
268 xmlChar *order;
270 if ((order =
271 xmlGetProp(cur_node, (xmlChar *) PRIMARY_COMPONENT_ATTR_NAME))) {
272 if (strcmp((char *) order, PRIMARY_COMPONENT)) {
273 printf("ERROR: Illegal attribut value >order=%s<.\n",
274 (char *) order);
275 xmlFree(order);
276 exit(EXIT_FAILURE);
277 }
278 if (primary != NULLPOLICY) {
279 printf("ERROR: Primary Policy Component set twice!\n");
280 exit(EXIT_FAILURE);
281 }
282 primary = pc;
283 xmlFree(order);
284 }
285 }
287 void walk_policy(xmlNode * start, xmlDocPtr doc, unsigned long state)
288 {
289 xmlNode *cur_node = NULL;
290 int code;
292 for (cur_node = start; cur_node; cur_node = cur_node->next) {
293 if ((code = totoken((char *) cur_node->name)) < 0) {
294 printf("Unknown token: >%s<. Aborting.\n", cur_node->name);
295 exit(EXIT_FAILURE);
296 }
297 switch (code) { /* adjust state to new state */
298 case XML2BIN_SECPOL:
299 case XML2BIN_STETYPES:
300 case XML2BIN_CHWALLTYPES:
301 case XML2BIN_CONFLICTSETS:
302 case XML2BIN_POLICYHEADER:
303 walk_policy(cur_node->children, doc, state | (1 << code));
304 break;
306 case XML2BIN_POLICYNAME: /* get policy reference name .... */
307 if (state != XML2BIN_PN_S) {
308 printf("ERROR: >Url< >%s< out of context.\n",
309 (char *) xmlNodeListGetString(doc,
310 cur_node->
311 xmlChildrenNode, 1));
312 exit(EXIT_FAILURE);
313 }
314 policy_reference_name = (char *)
315 xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
316 if (!policy_reference_name) {
317 printf("ERROR: empty >policy reference name (Url)<!\n");
318 exit(EXIT_FAILURE);
319 } else
320 printf("Policy Reference name (Url): %s\n",
321 policy_reference_name);
322 break;
324 case XML2BIN_STE:
325 if (WRITTEN_AGAINST_ACM_STE_VERSION != ACM_STE_VERSION) {
326 printf
327 ("ERROR: This program was written against another STE version.\n");
328 exit(EXIT_FAILURE);
329 }
330 have_ste = 1;
331 set_component_type(cur_node, STE);
332 walk_policy(cur_node->children, doc, state | (1 << code));
333 break;
335 case XML2BIN_CHWALL:
336 if (WRITTEN_AGAINST_ACM_CHWALL_VERSION != ACM_CHWALL_VERSION) {
337 printf
338 ("ERROR: This program was written against another CHWALL version.\n");
339 exit(EXIT_FAILURE);
340 }
341 have_chwall = 1;
342 set_component_type(cur_node, CHWALL);
343 walk_policy(cur_node->children, doc, state | (1 << code));
344 break;
346 case XML2BIN_CSTYPE:
347 current_conflictset_name =
348 (char *) xmlGetProp(cur_node, (xmlChar *) "name");
349 if (!current_conflictset_name)
350 current_conflictset_name = "";
352 if (init_next_conflictset()) {
353 printf
354 ("ERROR: creating new conflictset structure failed.\n");
355 exit(EXIT_FAILURE);
356 }
357 walk_policy(cur_node->children, doc, state | (1 << code));
358 break;
360 case XML2BIN_TYPE:
361 if (register_type(cur_node, doc, state))
362 exit(EXIT_FAILURE);
363 /* type leaf */
364 break;
366 case XML2BIN_LABELTEMPLATE: /* handle in second pass */
367 case XML2BIN_TEXT:
368 case XML2BIN_COMMENT:
369 case XML2BIN_DATE:
370 case XML2BIN_REFERENCE:
371 case XML2BIN_NSURL: /* for future use: where to find global label / type name mappings */
372 case XML2BIN_URL: /* for future use: where to find policy */
373 /* leaf - nothing to do */
374 break;
376 default:
377 printf("Unkonwn token Error (%d) in Policy\n", code);
378 exit(EXIT_FAILURE);
379 }
381 }
382 return;
383 }
385 void init_type_mapping(void)
386 {
387 printf("Creating ssid mappings ...\n");
389 /* initialize the ste and chwall type lists */
390 TAILQ_INIT(&ste_head);
391 TAILQ_INIT(&chwall_head);
392 TAILQ_INIT(&conflictsets_head);
393 }
395 void post_type_mapping(void)
396 {
397 struct type_entry *te;
398 struct ssid_entry *se;
399 int i;
401 /* determine primary/secondary policy component orders */
402 if ((primary == NULLPOLICY) && have_chwall)
403 primary = CHWALL; /* default if not set */
404 else if ((primary == NULLPOLICY) && have_ste)
405 primary = STE;
407 switch (primary) {
409 case CHWALL:
410 if (have_ste)
411 secondary = STE;
412 /* else default = NULLPOLICY */
413 break;
415 case STE:
416 if (have_chwall)
417 secondary = CHWALL;
418 /* else default = NULLPOLICY */
419 break;
421 default:
422 /* NULL/NULL policy */
423 break;
424 }
426 if (!DEBUG)
427 return;
429 /* print queues */
430 if (have_ste) {
431 printf("STE-Type queue (%s):\n",
432 (primary == STE) ? "PRIMARY" : "SECONDARY");
433 for (te = ste_head.tqh_first; te != NULL;
434 te = te->entries.tqe_next)
435 printf("name=%22s, map=%x\n", te->name, te->mapping);
436 }
437 if (have_chwall) {
438 printf("CHWALL-Type queue (%s):\n",
439 (primary == CHWALL) ? "PRIMARY" : "SECONDARY");
440 for (te = chwall_head.tqh_first; te != NULL;
441 te = te->entries.tqe_next)
442 printf("name=%s, map=%x\n", te->name, te->mapping);
444 printf("Conflictset queue (max=%d):\n", max_conflictsets);
445 for (se = conflictsets_head.tqh_first; se != NULL;
446 se = se->entries.tqe_next) {
447 printf("conflictset name >%s<\n",
448 se->name ? se->name : "NONAME");
449 for (i = 0; i < max_chwall_types; i++)
450 if (se->row[i])
451 printf("#%x ", i);
452 printf("\n");
453 }
454 }
455 }
458 /***************** template-related parsing *********************/
460 /* add default ssid at head of ssid queues */
461 int init_ssid_queues(void)
462 {
463 struct ssid_entry *default_ssid_chwall, *default_ssid_ste;
465 default_ssid_chwall = malloc(sizeof(struct ssid_entry));
466 default_ssid_ste = malloc(sizeof(struct ssid_entry));
468 if ((!default_ssid_chwall) || (!default_ssid_ste))
469 return -ENOMEM;
471 /* default chwall ssid */
472 default_ssid_chwall->name = NULL_LABEL_NAME;
473 default_ssid_chwall->num = max_chwall_ssids++;
474 default_ssid_chwall->is_ref = 0;
475 default_ssid_chwall->type = ANY;
477 default_ssid_chwall->row = malloc(max_chwall_types);
479 if (!default_ssid_chwall->row)
480 return -ENOMEM;
482 memset(default_ssid_chwall->row, 0, max_chwall_types);
484 TAILQ_INSERT_TAIL(&chwall_ssid_head, default_ssid_chwall, entries);
485 current_chwall_ssid_p = default_ssid_chwall;
486 max_chwall_labels++;
488 /* default ste ssid */
489 default_ssid_ste->name = NULL_LABEL_NAME;
490 default_ssid_ste->num = max_ste_ssids++;
491 default_ssid_ste->is_ref = 0;
492 default_ssid_ste->type = ANY;
494 default_ssid_ste->row = malloc(max_ste_types);
496 if (!default_ssid_ste->row)
497 return -ENOMEM;
499 memset(default_ssid_ste->row, 0, max_ste_types);
501 TAILQ_INSERT_TAIL(&ste_ssid_head, default_ssid_ste, entries);
502 current_ste_ssid_p = default_ssid_ste;
503 max_ste_labels++;
504 return 0;
505 }
507 int init_next_chwall_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_chwall_ssids++;
516 ssid->is_ref = 0;
518 if (state & (1 << XML2BIN_VM))
519 ssid->type = VM;
520 else
521 ssid->type = RES;
522 /**
523 * row: allocate one byte per type;
524 * [i] != 0 --> mapped type >i< is part of the ssid
525 */
526 ssid->row = malloc(max_chwall_types);
527 if (!ssid->row)
528 return -ENOMEM;
530 memset(ssid->row, 0, max_chwall_types);
531 TAILQ_INSERT_TAIL(&chwall_ssid_head, ssid, entries);
532 current_chwall_ssid_p = ssid;
533 max_chwall_labels++;
534 return 0;
535 }
537 int init_next_ste_ssid(unsigned long state)
538 {
539 struct ssid_entry *ssid = malloc(sizeof(struct ssid_entry));
541 if (!ssid)
542 return -ENOMEM;
544 ssid->name = current_ssid_name;
545 ssid->num = max_ste_ssids++;
546 ssid->is_ref = 0;
548 if (state & (1 << XML2BIN_VM))
549 ssid->type = VM;
550 else
551 ssid->type = RES;
553 /**
554 * row: allocate one byte per type;
555 * [i] != 0 --> mapped type >i< is part of the ssid
556 */
557 ssid->row = malloc(max_ste_types);
558 if (!ssid->row)
559 return -ENOMEM;
561 memset(ssid->row, 0, max_ste_types);
562 TAILQ_INSERT_TAIL(&ste_ssid_head, ssid, entries);
563 current_ste_ssid_p = ssid;
564 max_ste_labels++;
566 return 0;
567 }
570 /* adds a type to the current ssid */
571 int add_type(xmlNode * cur_node, xmlDocPtr doc, unsigned long state)
572 {
573 xmlChar *text;
574 struct type_entry *e;
576 text = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
577 if (!text) {
578 printf("Error reading type name!\n");
579 return -EFAULT;
580 }
581 /* same for all: 1. lookup type mapping, 2. mark type in ssid */
582 switch (state) {
583 case XML2BIN_VM_STE_S:
584 case XML2BIN_RES_STE_S:
585 /* lookup the type mapping and include the type mapping into the array */
586 if (!(e = lookup(&ste_head, (char *) text))) {
587 printf("ERROR: unknown VM STE type >%s<.\n", text);
588 exit(EXIT_FAILURE);
589 }
590 if (current_ste_ssid_p->row[e->mapping])
591 printf("Warning: double entry of VM STE type >%s<.\n", text);
593 current_ste_ssid_p->row[e->mapping] = 1;
594 break;
596 case XML2BIN_VM_CHWALL_S:
597 /* lookup the type mapping and include the type mapping into the array */
598 if (!(e = lookup(&chwall_head, (char *) text))) {
599 printf("ERROR: unknown VM CHWALL type >%s<.\n", text);
600 exit(EXIT_FAILURE);
601 }
602 if (current_chwall_ssid_p->row[e->mapping])
603 printf("Warning: double entry of VM CHWALL type >%s<.\n",
604 text);
606 current_chwall_ssid_p->row[e->mapping] = 1;
607 break;
609 default:
610 printf("Incorrect type environment (state = %lx, text = %s).\n",
611 state, text);
612 xmlFree(text);
613 return -EFAULT;
614 }
615 return 0;
616 }
618 void set_bootstrap_label(xmlNode * cur_node)
619 {
620 xmlChar *order;
622 if ((order =
623 xmlGetProp(cur_node, (xmlChar *) BOOTSTRAP_LABEL_ATTR_NAME)))
624 bootstrap_label = (char *) order;
625 else {
626 printf("ERROR: No bootstrap label defined!\n");
627 exit(EXIT_FAILURE);
628 }
629 }
631 void walk_labels(xmlNode * start, xmlDocPtr doc, unsigned long state)
632 {
633 xmlNode *cur_node = NULL;
634 int code;
636 for (cur_node = start; cur_node; cur_node = cur_node->next) {
637 if ((code = totoken((char *) cur_node->name)) < 0) {
638 printf("Unkonwn token: >%s<. Aborting.\n", cur_node->name);
639 exit(EXIT_FAILURE);
640 }
641 switch (code) { /* adjust state to new state */
642 case XML2BIN_SUBJECTS:
643 set_bootstrap_label(cur_node);
644 /* fall through */
645 case XML2BIN_SECPOL:
646 case XML2BIN_LABELTEMPLATE:
647 case XML2BIN_VM:
648 case XML2BIN_RES:
649 case XML2BIN_OBJECTS:
650 walk_labels(cur_node->children, doc, state | (1 << code));
651 break;
653 case XML2BIN_STETYPES:
654 /* create new ssid entry to use and point current to it */
655 if (init_next_ste_ssid(state)) {
656 printf("ERROR: creating new ste ssid structure failed.\n");
657 exit(EXIT_FAILURE);
658 }
659 walk_labels(cur_node->children, doc, state | (1 << code));
660 break;
662 case XML2BIN_CHWALLTYPES:
663 /* create new ssid entry to use and point current to it */
664 if (init_next_chwall_ssid(state)) {
665 printf
666 ("ERROR: creating new chwall ssid structure failed.\n");
667 exit(EXIT_FAILURE);
668 }
669 walk_labels(cur_node->children, doc, state | (1 << code));
670 break;
672 case XML2BIN_TYPE:
673 /* add type to current ssid */
674 if (add_type(cur_node, doc, state))
675 exit(EXIT_FAILURE);
676 break;
678 case XML2BIN_NAME:
679 if ((state == XML2BIN_VM_S) || (state == XML2BIN_RES_S)) {
680 current_ssid_name = (char *)
681 xmlNodeListGetString(doc, cur_node->xmlChildrenNode,
682 1);
683 if (!current_ssid_name) {
684 printf("ERROR: empty >vm/res name<!\n");
685 exit(EXIT_FAILURE);
686 }
687 } else {
688 printf
689 ("ERROR: >name< >%s< out of context (state = 0x%lx.\n",
690 (char *) xmlNodeListGetString(doc,
691 cur_node->
692 xmlChildrenNode, 1),
693 state);
694 exit(EXIT_FAILURE);
695 }
696 break;
698 case XML2BIN_TEXT:
699 case XML2BIN_COMMENT:
700 case XML2BIN_POLICYHEADER:
701 case XML2BIN_STE:
702 case XML2BIN_CHWALL:
703 break;
705 default:
706 printf("Unkonwn token Error (%d) in Label Template\n", code);
707 exit(EXIT_FAILURE);
708 }
709 }
710 return;
711 }
713 /*
714 * will go away as soon as we have non-static bootstrap ssidref for dom0
715 */
716 void fixup_bootstrap_label(struct tailhead_ssid *head,
717 u_int32_t max_types, u_int32_t * max_ssids)
718 {
719 struct ssid_entry *np;
720 int i;
722 /* should not happen if xml / xsd checks work */
723 if (!bootstrap_label) {
724 printf("ERROR: No bootstrap label defined.\n");
725 exit(EXIT_FAILURE);
726 }
728 /* search bootstrap_label */
729 for (np = head->tqh_first; np != NULL; np = np->entries.tqe_next) {
730 if (!strcmp(np->name, bootstrap_label)) {
731 break;
732 }
733 }
735 if (!np) {
736 /* bootstrap label not found */
737 printf("ERROR: Bootstrap label >%s< not found.\n",
738 bootstrap_label);
739 exit(EXIT_FAILURE);
740 }
742 /* move this entry ahead in the list right after the default entry so it
743 * receives ssidref 1/1 */
744 TAILQ_REMOVE(head, np, entries);
745 TAILQ_INSERT_AFTER(head, head->tqh_first, np, entries);
747 /* renumber the ssids (we could also just switch places with 1st element) */
748 for (np = head->tqh_first, i = 0; np != NULL;
749 np = np->entries.tqe_next, i++)
750 np->num = i;
752 }
754 void init_label_mapping(void)
755 {
757 printf("Creating label mappings ...\n");
758 /* initialize the ste and chwall type lists */
759 TAILQ_INIT(&chwall_ssid_head);
760 TAILQ_INIT(&ste_ssid_head);
762 /* init with default ssids */
763 if (init_ssid_queues()) {
764 printf("ERROR adding default ssids.\n");
765 exit(EXIT_FAILURE);
766 }
767 }
769 void post_label_mapping(void)
770 {
771 struct ssid_entry *np;
772 int i;
774 /*
775 * now sort bootstrap label to the head of the list
776 * (for now), dom0 assumes its label in the first
777 * defined ssidref (1/1). 0/0 is the default non-Label
778 */
779 if (have_chwall)
780 fixup_bootstrap_label(&chwall_ssid_head, max_chwall_types,
781 &max_chwall_ssids);
782 if (have_ste)
783 fixup_bootstrap_label(&ste_ssid_head, max_ste_types,
784 &max_ste_ssids);
786 if (!DEBUG)
787 return;
789 /* print queues */
790 if (have_chwall) {
791 printf("CHWALL SSID queue (max ssidrefs=%d):\n", max_chwall_ssids);
792 np = NULL;
793 for (np = chwall_ssid_head.tqh_first; np != NULL;
794 np = np->entries.tqe_next) {
795 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
796 if (np->is_ref)
797 printf("REFERENCE");
798 else
799 for (i = 0; i < max_chwall_types; i++)
800 if (np->row[i])
801 printf("#%02d ", i);
802 printf("\n\n");
803 }
804 }
805 if (have_ste) {
806 printf("STE SSID queue (max ssidrefs=%d):\n", max_ste_ssids);
807 np = NULL;
808 for (np = ste_ssid_head.tqh_first; np != NULL;
809 np = np->entries.tqe_next) {
810 printf("SSID #%02u (Label=%s)\n", np->num, np->name);
811 if (np->is_ref)
812 printf("REFERENCE");
813 else
814 for (i = 0; i < max_ste_types; i++)
815 if (np->row[i])
816 printf("#%02d ", i);
817 printf("\n\n");
818 }
819 }
820 }
822 void create_mappings(xmlDocPtr doc)
823 {
824 xmlNode *doc_root_node = xmlDocGetRootElement(doc);
826 /* walk the XML policy tree and fill in types and labels */
827 init_type_mapping();
828 walk_policy(doc_root_node, doc, XML2BIN_NULL); /* first pass: types */
829 post_type_mapping();
830 init_label_mapping();
831 walk_labels(doc_root_node, doc, XML2BIN_NULL); /* second pass: labels */
832 post_label_mapping();
833 }
835 /***************** writing the binary policy *********************/
837 /*
838 * the mapping file is ascii-based since it will likely be used from
839 * within scripts (using awk, grep, etc.);
840 *
841 * We print from high-level to low-level information so that with one
842 * pass, any symbol can be resolved (e.g. Label -> types)
843 */
844 int write_mapping(char *filename)
845 {
847 struct ssid_entry *e;
848 struct type_entry *t;
849 int i;
850 FILE *file;
852 if ((file = fopen(filename, "w")) == NULL)
853 return -EIO;
855 fprintf(file, "POLICYREFERENCENAME %s\n", policy_reference_name);
856 fprintf(file, "MAGIC %08x\n", ACM_MAGIC);
857 fprintf(file, "POLICY FILE %s\n", policy_filename);
858 fprintf(file, "BINARY FILE %s\n", binary_filename);
859 if (have_chwall) {
860 fprintf(file, "MAX-CHWALL-TYPES %08x\n", max_chwall_types);
861 fprintf(file, "MAX-CHWALL-SSIDS %08x\n", max_chwall_ssids);
862 fprintf(file, "MAX-CHWALL-LABELS %08x\n", max_chwall_labels);
863 }
864 if (have_ste) {
865 fprintf(file, "MAX-STE-TYPES %08x\n", max_ste_types);
866 fprintf(file, "MAX-STE-SSIDS %08x\n", max_ste_ssids);
867 fprintf(file, "MAX-STE-LABELS %08x\n", max_ste_labels);
868 }
869 fprintf(file, "\n");
871 /* primary / secondary order for combined ssid synthesis/analysis
872 * if no primary is named, then chwall is primary */
873 switch (primary) {
874 case CHWALL:
875 fprintf(file, "PRIMARY CHWALL\n");
876 break;
878 case STE:
879 fprintf(file, "PRIMARY STE\n");
880 break;
882 default:
883 fprintf(file, "PRIMARY NULL\n");
884 break;
885 }
887 switch (secondary) {
888 case CHWALL:
889 fprintf(file, "SECONDARY CHWALL\n");
890 break;
892 case STE:
893 fprintf(file, "SECONDARY STE\n");
894 break;
896 default:
897 fprintf(file, "SECONDARY NULL\n");
898 break;
899 }
900 fprintf(file, "\n");
902 /* first labels to ssid mappings */
903 if (have_chwall) {
904 for (e = chwall_ssid_head.tqh_first; e != NULL;
905 e = e->entries.tqe_next) {
906 fprintf(file, "LABEL->SSID %s CHWALL %-25s %8x\n",
907 (e->type ==
908 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
909 e->name, e->num);
910 }
911 fprintf(file, "\n");
912 }
913 if (have_ste) {
914 for (e = ste_ssid_head.tqh_first; e != NULL;
915 e = e->entries.tqe_next) {
916 fprintf(file, "LABEL->SSID %s STE %-25s %8x\n",
917 (e->type ==
918 VM) ? "VM " : ((e->type == RES) ? "RES" : "ANY"),
919 e->name, e->num);
920 }
921 fprintf(file, "\n");
922 }
924 /* second ssid to type mappings */
925 if (have_chwall) {
926 for (e = chwall_ssid_head.tqh_first; e != NULL;
927 e = e->entries.tqe_next) {
928 if (e->is_ref)
929 continue;
931 fprintf(file, "SSID->TYPE CHWALL %08x", e->num);
933 for (i = 0; i < max_chwall_types; i++)
934 if (e->row[i])
935 fprintf(file, " %s", type_by_mapping(&chwall_head, i));
937 fprintf(file, "\n");
938 }
939 fprintf(file, "\n");
940 }
941 if (have_ste) {
942 for (e = ste_ssid_head.tqh_first; e != NULL;
943 e = e->entries.tqe_next) {
944 if (e->is_ref)
945 continue;
947 fprintf(file, "SSID->TYPE STE %08x", e->num);
949 for (i = 0; i < max_ste_types; i++)
950 if (e->row[i])
951 fprintf(file, " %s", type_by_mapping(&ste_head, i));
953 fprintf(file, "\n");
954 }
955 fprintf(file, "\n");
956 }
957 /* third type mappings */
958 if (have_chwall) {
959 for (t = chwall_head.tqh_first; t != NULL; t = t->entries.tqe_next) {
960 fprintf(file, "TYPE CHWALL %-25s %8x\n",
961 t->name, t->mapping);
962 }
963 fprintf(file, "\n");
964 }
965 if (have_ste) {
966 for (t = ste_head.tqh_first; t != NULL; t = t->entries.tqe_next) {
967 fprintf(file, "TYPE STE %-25s %8x\n",
968 t->name, t->mapping);
969 }
970 fprintf(file, "\n");
971 }
972 fclose(file);
973 return 0;
974 }
977 unsigned char *write_policy_reference_binary(u_int32_t * len_pr)
978 {
979 unsigned char *buf, *ptr;
980 struct acm_policy_reference_buffer *pr_header;
981 u_int32_t len;
983 if (policy_reference_name == NULL) {
984 printf("ERROR: No policy reference name found.\n");
985 exit(EXIT_FAILURE);
986 }
987 len = (sizeof(struct acm_policy_reference_buffer) +
988 strlen(policy_reference_name) + 1);
989 buf = malloc(len);
990 ptr = buf;
992 if (!buf) {
993 printf
994 ("ERROR: out of memory allocating label reference buffer.\n");
995 exit(EXIT_FAILURE);
996 }
997 pr_header = (struct acm_policy_reference_buffer *) buf;
998 pr_header->len =
999 htonl(strlen(policy_reference_name) + 1 /* strend \'0' */ );
1000 ptr += sizeof(struct acm_policy_reference_buffer);
1001 strcpy((char *) ptr, policy_reference_name);
1003 (*len_pr) = len;
1004 return buf;
1008 unsigned char *write_chwall_binary(u_int32_t * len_chwall)
1010 unsigned char *buf, *ptr;
1011 struct acm_chwall_policy_buffer *chwall_header;
1012 u_int32_t len;
1013 struct ssid_entry *e;
1014 int i;
1016 if (!have_chwall)
1017 return NULL;
1019 len = sizeof(struct acm_chwall_policy_buffer) +
1020 sizeof(type_t) * max_chwall_types * max_chwall_ssids +
1021 sizeof(type_t) * max_chwall_types * max_conflictsets;
1023 buf = malloc(len);
1024 ptr = buf;
1026 if (!buf) {
1027 printf("ERROR: out of memory allocating chwall buffer.\n");
1028 exit(EXIT_FAILURE);
1030 /* chwall has 3 parts : header, types, conflictsets */
1032 chwall_header = (struct acm_chwall_policy_buffer *) buf;
1033 chwall_header->chwall_max_types = htonl(max_chwall_types);
1034 chwall_header->chwall_max_ssidrefs = htonl(max_chwall_ssids);
1035 chwall_header->policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1036 chwall_header->policy_version = htonl(ACM_CHWALL_VERSION);
1037 chwall_header->chwall_ssid_offset =
1038 htonl(sizeof(struct acm_chwall_policy_buffer));
1039 chwall_header->chwall_max_conflictsets = htonl(max_conflictsets);
1040 chwall_header->chwall_conflict_sets_offset =
1041 htonl(ntohl(chwall_header->chwall_ssid_offset) +
1042 sizeof(domaintype_t) * max_chwall_ssids * max_chwall_types);
1043 chwall_header->chwall_running_types_offset = 0;
1044 chwall_header->chwall_conflict_aggregate_offset = 0;
1045 ptr += sizeof(struct acm_chwall_policy_buffer);
1047 /* types */
1048 for (e = chwall_ssid_head.tqh_first; e != NULL;
1049 e = e->entries.tqe_next) {
1050 if (e->is_ref)
1051 continue;
1053 for (i = 0; i < max_chwall_types; i++)
1054 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1056 ptr += sizeof(type_t) * max_chwall_types;
1059 /* conflictsets */
1060 for (e = conflictsets_head.tqh_first; e != NULL;
1061 e = e->entries.tqe_next) {
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 if ((ptr - buf) != len) {
1069 printf("ERROR: wrong lengths in %s.\n", __func__);
1070 exit(EXIT_FAILURE);
1073 (*len_chwall) = len;
1074 return buf;
1077 unsigned char *write_ste_binary(u_int32_t * len_ste)
1079 unsigned char *buf, *ptr;
1080 struct acm_ste_policy_buffer *ste_header;
1081 struct ssid_entry *e;
1082 u_int32_t len;
1083 int i;
1085 if (!have_ste)
1086 return NULL;
1088 len = sizeof(struct acm_ste_policy_buffer) +
1089 sizeof(type_t) * max_ste_types * max_ste_ssids;
1091 buf = malloc(len);
1092 ptr = buf;
1094 if (!buf) {
1095 printf("ERROR: out of memory allocating chwall buffer.\n");
1096 exit(EXIT_FAILURE);
1099 /* fill buffer */
1100 ste_header = (struct acm_ste_policy_buffer *) buf;
1101 ste_header->policy_version = htonl(ACM_STE_VERSION);
1102 ste_header->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1103 ste_header->ste_max_types = htonl(max_ste_types);
1104 ste_header->ste_max_ssidrefs = htonl(max_ste_ssids);
1105 ste_header->ste_ssid_offset =
1106 htonl(sizeof(struct acm_ste_policy_buffer));
1108 ptr += sizeof(struct acm_ste_policy_buffer);
1110 /* types */
1111 for (e = ste_ssid_head.tqh_first; e != NULL; e = e->entries.tqe_next) {
1112 if (e->is_ref)
1113 continue;
1115 for (i = 0; i < max_ste_types; i++)
1116 ((type_t *) ptr)[i] = htons((type_t) e->row[i]);
1118 ptr += sizeof(type_t) * max_ste_types;
1121 if ((ptr - buf) != len) {
1122 printf("ERROR: wrong lengths in %s.\n", __func__);
1123 exit(EXIT_FAILURE);
1125 (*len_ste) = len;
1126 return buf; /* for now */
1129 int write_binary(char *filename)
1131 struct acm_policy_buffer header;
1132 unsigned char *ste_buffer = NULL, *chwall_buffer =
1133 NULL, *policy_reference_buffer = NULL;
1134 u_int32_t len;
1135 int fd, ret = 0;
1137 u_int32_t len_ste = 0, len_chwall = 0, len_pr = 0; /* length of policy components */
1139 /* open binary file */
1140 if ((fd =
1141 open(filename, O_WRONLY | O_CREAT | O_TRUNC,
1142 S_IRUSR | S_IWUSR)) <= 0) {
1143 ret = -EIO;
1144 goto out1;
1146 policy_reference_buffer = write_policy_reference_binary(&len_pr);
1147 ste_buffer = write_ste_binary(&len_ste);
1148 chwall_buffer = write_chwall_binary(&len_chwall);
1150 /* determine primary component (default chwall) */
1151 header.policy_version = htonl(ACM_POLICY_VERSION);
1152 header.magic = htonl(ACM_MAGIC);
1154 len = sizeof(struct acm_policy_buffer);
1155 if (have_chwall)
1156 len += len_chwall;
1157 if (have_ste)
1158 len += len_ste;
1159 len += len_pr; /* policy reference is mandatory */
1160 header.len = htonl(len);
1162 header.policy_reference_offset =
1163 htonl(sizeof(struct acm_policy_buffer));
1165 header.primary_buffer_offset =
1166 htonl(sizeof(struct acm_policy_buffer) + len_pr);
1167 if (primary == CHWALL) {
1168 header.primary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1169 header.secondary_buffer_offset =
1170 htonl((sizeof(struct acm_policy_buffer)) + len_pr +
1171 len_chwall);
1172 } else if (primary == STE) {
1173 header.primary_policy_code =
1174 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1175 header.secondary_buffer_offset =
1176 htonl((sizeof(struct acm_policy_buffer)) + len_pr +
1177 len_ste);
1178 } else {
1179 /* null policy */
1180 header.primary_policy_code = htonl(ACM_NULL_POLICY);
1181 header.secondary_buffer_offset =
1182 htonl(header.primary_buffer_offset);
1185 if (secondary == CHWALL)
1186 header.secondary_policy_code = htonl(ACM_CHINESE_WALL_POLICY);
1187 else if (secondary == STE)
1188 header.secondary_policy_code =
1189 htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
1190 else
1191 header.secondary_policy_code = htonl(ACM_NULL_POLICY);
1193 if (write(fd, (void *) &header, sizeof(struct acm_policy_buffer))
1194 != sizeof(struct acm_policy_buffer)) {
1195 ret = -EIO;
1196 goto out1;
1199 /* write label reference name */
1200 if (write(fd, policy_reference_buffer, len_pr) != len_pr) {
1201 ret = -EIO;
1202 goto out1;
1204 /* write primary policy component */
1205 if (primary == CHWALL) {
1206 if (write(fd, chwall_buffer, len_chwall) != len_chwall) {
1207 ret = -EIO;
1208 goto out1;
1210 } else if (primary == STE) {
1211 if (write(fd, ste_buffer, len_ste) != len_ste) {
1212 ret = -EIO;
1213 goto out1;
1215 } else; /* NULL POLICY has no policy data */
1217 /* write secondary policy component */
1218 if (secondary == CHWALL) {
1219 if (write(fd, chwall_buffer, len_chwall) != len_chwall) {
1220 ret = -EIO;
1221 goto out1;
1223 } else if (secondary == STE) {
1224 if (write(fd, ste_buffer, len_ste) != len_ste) {
1225 ret = -EIO;
1226 goto out1;
1228 } else; /* NULL POLICY has no policy data */
1230 out1:
1231 /* cleanup */
1232 if (policy_reference_buffer)
1233 free(policy_reference_buffer);
1234 if (chwall_buffer)
1235 free(chwall_buffer);
1236 if (ste_buffer)
1237 free(ste_buffer);
1238 close(fd);
1239 return ret;
1242 int is_valid(xmlDocPtr doc)
1244 int err = 0;
1245 xmlSchemaPtr schema_ctxt = NULL;
1246 xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL;
1247 xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL;
1249 schemaparser_ctxt = xmlSchemaNewParserCtxt(schema_filename);
1250 schema_ctxt = xmlSchemaParse(schemaparser_ctxt);
1251 schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt);
1253 #ifdef VALIDATE_SCHEMA
1254 /* only tested to be available from libxml2-2.6.20 upwards */
1255 if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1) {
1256 printf("ERROR: Invalid schema file %s (err=%d)\n",
1257 schema_filename, err);
1258 err = -EIO;
1259 goto out;
1260 } else
1261 printf("XML Schema %s valid.\n", schema_filename);
1262 #endif
1263 if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc))) {
1264 err = -EIO;
1265 goto out;
1267 out:
1268 xmlSchemaFreeValidCtxt(schemavalid_ctxt);
1269 xmlSchemaFreeParserCtxt(schemaparser_ctxt);
1270 xmlSchemaFree(schema_ctxt);
1271 return (err != 0) ? 0 : 1;
1274 int main(int argc, char **argv)
1276 xmlDocPtr policydoc = NULL;
1278 int err = EXIT_FAILURE;
1280 char *file_prefix;
1281 int prefix_len;
1283 int opt_char;
1284 char *policy_dir = POLICY_DIR;
1286 if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION) {
1287 printf
1288 ("ERROR: This program was written against an older ACM version.\n");
1289 printf("ERROR: ACM_POLICY_VERSION=%d, WRITTEN AGAINST= %d.\n",
1290 ACM_POLICY_VERSION, WRITTEN_AGAINST_ACM_POLICY_VERSION);
1291 exit(EXIT_FAILURE);
1294 while ((opt_char = getopt(argc, argv, "d:")) != -1) {
1295 switch (opt_char) {
1296 case 'd':
1297 policy_dir = malloc(strlen(optarg) + 2); /* null terminator and possibly "/" */
1298 if (!policy_dir) {
1299 printf("ERROR allocating directory name memory.\n");
1300 exit(EXIT_FAILURE);
1302 strcpy(policy_dir, optarg);
1303 if (policy_dir[strlen(policy_dir) - 1] != '/')
1304 strcat(policy_dir, "/");
1305 break;
1307 default:
1308 usage(basename(argv[0]));
1312 if ((argc - optind) != 1)
1313 usage(basename(argv[0]));
1315 printf("arg=%s\n", argv[optind]);
1317 prefix_len =
1318 strlen(policy_dir) + strlen(argv[optind]) +
1319 1 /* null terminator */ ;
1321 file_prefix = malloc(prefix_len);
1322 policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION));
1323 binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION));
1324 mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION));
1325 schema_filename =
1326 malloc(strlen(policy_dir) + strlen(SCHEMA_FILENAME) + 1);
1328 if (!file_prefix || !policy_filename ||
1329 !binary_filename || !mapping_filename || !schema_filename) {
1330 printf("ERROR allocating file name memory.\n");
1331 goto out2;
1334 /* create input/output filenames out of prefix */
1335 strcpy(file_prefix, policy_dir);
1336 strcat(file_prefix, argv[optind]);
1338 strcpy(policy_filename, file_prefix);
1339 strcpy(binary_filename, file_prefix);
1340 strcpy(mapping_filename, file_prefix);
1342 strcat(policy_filename, POLICY_EXTENSION);
1343 strcat(binary_filename, BINARY_EXTENSION);
1344 strcat(mapping_filename, MAPPING_EXTENSION);
1346 strcpy(schema_filename, policy_dir);
1347 strcat(schema_filename, SCHEMA_FILENAME);
1349 policydoc = xmlParseFile(policy_filename);
1351 if (policydoc == NULL) {
1352 printf("Error: could not parse file %s.\n", argv[optind]);
1353 goto out;
1356 printf("Validating policy file %s...\n", policy_filename);
1358 if (!is_valid(policydoc)) {
1359 printf("ERROR: Failed schema-validation for file %s (err=%d)\n",
1360 policy_filename, err);
1361 goto out;
1364 /* create mappings */
1365 create_mappings(policydoc);
1367 /* write label mapping file */
1368 if (write_mapping(mapping_filename)) {
1369 printf("ERROR: writing mapping file %s.\n", mapping_filename);
1370 goto out;
1373 /* write binary file */
1374 if (write_binary(binary_filename)) {
1375 printf("ERROR: writing binary file %s.\n", binary_filename);
1376 goto out;
1378 err = EXIT_SUCCESS;
1379 /* write stats */
1380 if (have_chwall) {
1381 printf("Max chwall labels: %u\n", max_chwall_labels);
1382 printf("Max chwall-types: %u\n", max_chwall_types);
1383 printf("Max chwall-ssids: %u\n", max_chwall_ssids);
1386 if (have_ste) {
1387 printf("Max ste labels: %u\n", max_ste_labels);
1388 printf("Max ste-types: %u\n", max_ste_types);
1389 printf("Max ste-ssids: %u\n", max_ste_ssids);
1391 /* cleanup */
1392 out:
1393 xmlFreeDoc(policydoc);
1394 out2:
1395 xmlCleanupParser();
1396 return err;
1399 /*
1400 * Local variables:
1401 * mode: C
1402 * c-set-style: "BSD"
1403 * c-basic-offset: 4
1404 * tab-width: 4
1405 * indent-tabs-mode: nil
1406 * End:
1407 */