]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2009-2010 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | /* | |
25 | * policytree.c - rfc5280 section 6.1.2 and later policy_tree implementation. | |
26 | */ | |
27 | ||
28 | #include "policytree.h" | |
29 | #include <libDER/oids.h> | |
30 | ||
31 | #include <security_utilities/debugging.h> | |
32 | ||
33 | #include <stdlib.h> | |
34 | ||
35 | #define DUMP_POLICY_TREE 0 | |
36 | ||
37 | #if !defined(DUMP_POLICY_TREE) | |
38 | #include <stdio.h> | |
39 | #endif | |
40 | ||
41 | static policy_set_t policy_set_create(const oid_t *p_oid) { | |
42 | policy_set_t policy_set = | |
43 | (policy_set_t)malloc(sizeof(*policy_set)); | |
44 | policy_set->oid_next = NULL; | |
45 | policy_set->oid = *p_oid; | |
46 | secdebug("policy-set", "%p", policy_set); | |
47 | return policy_set; | |
48 | } | |
49 | ||
50 | void policy_set_add(policy_set_t *policy_set, const oid_t *p_oid) { | |
51 | policy_set_t node = (policy_set_t)malloc(sizeof(*node)); | |
52 | node->oid_next = *policy_set; | |
53 | node->oid = *p_oid; | |
54 | *policy_set = node; | |
55 | secdebug("policy-set", "%p -> %p", node, node->oid_next); | |
56 | } | |
57 | ||
58 | void policy_set_free(policy_set_t node) { | |
59 | while (node) { | |
60 | policy_set_t next = node->oid_next; | |
61 | secdebug("policy-set", "%p -> %p", node, next); | |
62 | free(node); | |
63 | node = next; | |
64 | } | |
65 | } | |
66 | ||
67 | bool policy_set_contains(policy_set_t node, const oid_t *oid) { | |
68 | for (; node; node = node->oid_next) { | |
69 | if (oid_equal(node->oid, *oid)) | |
70 | return true; | |
71 | } | |
72 | return false; | |
73 | } | |
74 | ||
75 | void policy_set_intersect(policy_set_t *policy_set, policy_set_t other_set) { | |
76 | bool other_has_any = policy_set_contains(other_set, &oidAnyPolicy); | |
77 | if (policy_set_contains(*policy_set, &oidAnyPolicy)) { | |
78 | policy_set_t node = other_set; | |
79 | if (other_has_any) { | |
80 | /* Both sets contain anyPolicy so the intersection is anyPolicy | |
81 | plus all oids in either set. */ | |
82 | while (node) { | |
83 | if (!policy_set_contains(*policy_set, &node->oid)) { | |
84 | policy_set_add(policy_set, &node->oid); | |
85 | } | |
86 | } | |
87 | } else { | |
88 | /* The result set contains anyPolicy and other_set doesn't. The | |
89 | result set should be a copy of other_set. */ | |
90 | policy_set_free(*policy_set); | |
91 | *policy_set = NULL; | |
92 | while (node) { | |
93 | policy_set_add(policy_set, &node->oid); | |
94 | } | |
95 | } | |
96 | } else if (!other_has_any) { | |
97 | /* Neither set contains any policy oid so remove any values from the | |
98 | result set that aren't in other_set. */ | |
99 | policy_set_t *pnode = policy_set; | |
100 | while (*pnode) { | |
101 | policy_set_t node = *pnode; | |
102 | if (policy_set_contains(other_set, &node->oid)) { | |
103 | pnode = &node->oid_next; | |
104 | } else { | |
105 | *pnode = node->oid_next; | |
106 | node->oid_next = NULL; | |
107 | policy_set_free(node); | |
108 | } | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | policy_tree_t policy_tree_create(const oid_t *p_oid, policy_qualifier_t p_q) { | |
114 | policy_tree_t node = malloc(sizeof(*node)); | |
115 | node->valid_policy = *p_oid; | |
116 | node->qualifier_set = p_q; | |
117 | node->expected_policy_set = policy_set_create(p_oid); | |
118 | node->children = NULL; | |
119 | node->siblings = NULL; | |
120 | secdebug("policy-node", "%p", node); | |
121 | return node; | |
122 | } | |
123 | ||
124 | /* Walk the nodes in a tree at depth and invoke callback for each one. */ | |
125 | bool policy_tree_walk_depth(policy_tree_t root, int depth, | |
126 | bool(*callback)(policy_tree_t, void *), void *ctx) { | |
127 | policy_tree_t stack[depth + 1]; | |
128 | int stack_ix = 0; | |
129 | stack[stack_ix] = root; | |
130 | policy_tree_t node; | |
131 | bool match = false; | |
132 | bool child_visited = false; | |
133 | while (stack_ix >= 0) { | |
134 | /* stack[stack_ix - 1] is the parent of the current node. */ | |
135 | node = stack[stack_ix]; | |
136 | policy_tree_t child = node->children; | |
137 | if (!child_visited && stack_ix < depth && child ) { | |
138 | /* If we have a child and we haven't reached the | |
139 | required depth yet, we go depth first and proccess it. */ | |
140 | stack[++stack_ix] = child; | |
141 | } else { | |
142 | if (stack_ix == depth) { | |
143 | /* Proccess node. */ | |
144 | match |= callback(node, ctx); | |
145 | } | |
146 | /* Move on to sibling of node. */ | |
147 | policy_tree_t sibling = node->siblings; | |
148 | if (sibling) { | |
149 | /* Replace current node with it's sibling. */ | |
150 | stack[stack_ix] = sibling; | |
151 | child_visited = false; | |
152 | } else { | |
153 | /* No more siblings left, so pop the stack and backtrack. */ | |
154 | stack_ix--; | |
155 | /* We've handled the top of the stack's child already so | |
156 | just look at it's siblings. */ | |
157 | child_visited = true; | |
158 | } | |
159 | } | |
160 | } | |
161 | return match; | |
162 | } | |
163 | ||
164 | static void policy_tree_free_node(policy_tree_t node) { | |
165 | secdebug("policy-node", "%p children: %p siblngs: %p", node, | |
166 | node->children, node->siblings); | |
167 | if (node->expected_policy_set) { | |
168 | policy_set_free(node->expected_policy_set); | |
169 | node->expected_policy_set = NULL; | |
170 | } | |
171 | free(node); | |
172 | } | |
173 | ||
174 | /* Prune nodes from node down. */ | |
175 | void policy_tree_prune(policy_tree_t *node) { | |
176 | /* Free all our children and siblings. */ | |
177 | policy_tree_t *child = &(*node)->children; | |
178 | if (*child) | |
179 | policy_tree_prune(child); | |
180 | policy_tree_t *sibling = &(*node)->siblings; | |
181 | if (*sibling) | |
182 | policy_tree_prune(sibling); | |
183 | policy_tree_free_node(*node); | |
184 | *node = NULL; | |
185 | } | |
186 | ||
187 | /* Prune childless nodes at depth. */ | |
188 | void policy_tree_prune_childless(policy_tree_t *root, int depth) { | |
189 | policy_tree_t *stack[depth + 1]; | |
190 | int stack_ix = 0; | |
191 | stack[stack_ix] = root; | |
192 | bool child_visited = false; | |
193 | while (stack_ix >= 0) { | |
194 | policy_tree_t *node; | |
195 | node = stack[stack_ix]; | |
196 | policy_tree_t *child = &(*node)->children; | |
197 | if (!child_visited && stack_ix < depth && *child) { | |
198 | /* If we have a child and we haven't reached the | |
199 | required depth yet, we go depth first and proccess it. */ | |
200 | stack[++stack_ix] = child; | |
201 | } else if (!*child) { | |
202 | /* Childless node found, nuke it. */ | |
203 | #if !defined(DUMP_POLICY_TREE) | |
204 | printf("# prune /<%.08lx<\\ |%.08lx| >%.08lx> :%s: depth %d\n", | |
205 | (intptr_t)node, (intptr_t)*node, (intptr_t)(*node)->siblings, | |
206 | (child_visited ? "v" : " "), stack_ix); | |
207 | #endif | |
208 | ||
209 | policy_tree_t next = (*node)->siblings; | |
210 | (*node)->siblings = NULL; | |
211 | policy_tree_free_node(*node); | |
212 | *node = next; | |
213 | if (next) { | |
214 | /* stack[stack_ix] (node) already points to next now. */ | |
215 | child_visited = false; | |
216 | } else { | |
217 | /* No more siblings left, so pop the stack and backtrack. */ | |
218 | stack_ix--; | |
219 | child_visited = true; | |
220 | } | |
221 | } else { | |
222 | policy_tree_t *sibling = &(*node)->siblings; | |
223 | if (*sibling) { | |
224 | /* Replace current node with it's sibling. */ | |
225 | stack[stack_ix] = sibling; | |
226 | child_visited = false; | |
227 | } else { | |
228 | /* No more siblings left, so pop the stack and backtrack. */ | |
229 | stack_ix--; | |
230 | child_visited = true; | |
231 | } | |
232 | } | |
233 | } | |
234 | } | |
235 | ||
236 | /* Add a new child to the tree. */ | |
237 | static void policy_tree_add_child_explicit(policy_tree_t parent, | |
238 | const oid_t *p_oid, policy_qualifier_t p_q, policy_set_t p_expected) { | |
239 | policy_tree_t child = malloc(sizeof(*child)); | |
240 | child->valid_policy = *p_oid; | |
241 | child->qualifier_set = p_q; | |
242 | child->expected_policy_set = p_expected; | |
243 | child->children = NULL; | |
244 | ||
245 | #if 0 | |
246 | printf("# /%.08lx\\ |%.08lx| \\%.08lx/ >%.08lx> \\>%.08lx>/\n", | |
247 | (intptr_t)parent, (intptr_t)child, (intptr_t)parent->children, | |
248 | (intptr_t)parent->siblings, | |
249 | (intptr_t)(parent->children ? parent->children->siblings : NULL)); | |
250 | #endif | |
251 | ||
252 | /* Previous child becomes new child's first sibling. */ | |
253 | child->siblings = parent->children; | |
254 | /* New child becomes parent's first child. */ | |
255 | parent->children = child; | |
256 | ||
257 | secdebug("policy-node", "%p siblngs: %p", child, child->siblings); | |
258 | } | |
259 | ||
260 | /* Add a new child to the tree parent setting valid_policy to p_oid, | |
261 | qualifier_set to p_q and expected_policy_set to a set containing | |
262 | just p_oid. */ | |
263 | void policy_tree_add_child(policy_tree_t parent, | |
264 | const oid_t *p_oid, policy_qualifier_t p_q) { | |
265 | policy_set_t policy_set = policy_set_create(p_oid); | |
266 | policy_tree_add_child_explicit(parent, p_oid, p_q, policy_set); | |
267 | } | |
268 | ||
269 | void policy_tree_set_expected_policy(policy_tree_t node, | |
270 | policy_set_t p_expected) { | |
271 | if (node->expected_policy_set) | |
272 | policy_set_free(node->expected_policy_set); | |
273 | node->expected_policy_set = p_expected; | |
274 | } | |
275 | ||
276 | #if !defined(DUMP_POLICY_TREE) | |
277 | /* Dump a policy tree. */ | |
278 | static void policy_tree_dump4(policy_tree_t node, policy_tree_t parent, | |
279 | policy_tree_t prev_sibling, int depth) { | |
280 | policy_tree_t child = node->children; | |
281 | policy_tree_t sibling = node->siblings; | |
282 | static const char *spaces = " "; | |
283 | printf("# %.*s/%.08lx\\ |%.08lx| <%.08lx< >%.08lx> depth %d\n", | |
284 | depth * 11, spaces, | |
285 | (intptr_t)parent, (intptr_t)node, (intptr_t)prev_sibling, | |
286 | (intptr_t)sibling, depth); | |
287 | if (child) | |
288 | policy_tree_dump4(child, node, NULL, depth + 1); | |
289 | if (sibling) | |
290 | policy_tree_dump4(sibling, parent, node, depth); | |
291 | } | |
292 | #endif /* !defined(DUMP_POLICY_TREE) */ | |
293 | ||
294 | void policy_tree_dump(policy_tree_t node) { | |
295 | #if !defined(DUMP_POLICY_TREE) | |
296 | policy_tree_dump4(node, NULL, NULL, 0); | |
297 | #endif /* !defined(DUMP_POLICY_TREE) */ | |
298 | } |