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