]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2009-2010,2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
d8f41ccd | 5 | * |
b1ab9ed8 A |
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. | |
d8f41ccd | 12 | * |
b1ab9ed8 A |
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. | |
d8f41ccd | 20 | * |
b1ab9ed8 A |
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" | |
5c19dc3a | 29 | #include <libDER/oidsPriv.h> |
b1ab9ed8 | 30 | |
427c49bc | 31 | #include <utilities/debugging.h> |
b1ab9ed8 A |
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)); | |
6b200bc3 | 115 | memset(node, 0, sizeof(*node)); |
b1ab9ed8 A |
116 | node->valid_policy = *p_oid; |
117 | node->qualifier_set = p_q; | |
118 | node->expected_policy_set = policy_set_create(p_oid); | |
b1ab9ed8 A |
119 | secdebug("policy-node", "%p", node); |
120 | return node; | |
121 | } | |
122 | ||
123 | /* Walk the nodes in a tree at depth and invoke callback for each one. */ | |
124 | bool policy_tree_walk_depth(policy_tree_t root, int depth, | |
125 | bool(*callback)(policy_tree_t, void *), void *ctx) { | |
126 | policy_tree_t stack[depth + 1]; | |
127 | int stack_ix = 0; | |
128 | stack[stack_ix] = root; | |
129 | policy_tree_t node; | |
130 | bool match = false; | |
131 | bool child_visited = false; | |
132 | while (stack_ix >= 0) { | |
133 | /* stack[stack_ix - 1] is the parent of the current node. */ | |
134 | node = stack[stack_ix]; | |
135 | policy_tree_t child = node->children; | |
136 | if (!child_visited && stack_ix < depth && child ) { | |
137 | /* If we have a child and we haven't reached the | |
138 | required depth yet, we go depth first and proccess it. */ | |
139 | stack[++stack_ix] = child; | |
140 | } else { | |
141 | if (stack_ix == depth) { | |
142 | /* Proccess node. */ | |
143 | match |= callback(node, ctx); | |
144 | } | |
145 | /* Move on to sibling of node. */ | |
146 | policy_tree_t sibling = node->siblings; | |
147 | if (sibling) { | |
148 | /* Replace current node with it's sibling. */ | |
149 | stack[stack_ix] = sibling; | |
150 | child_visited = false; | |
151 | } else { | |
152 | /* No more siblings left, so pop the stack and backtrack. */ | |
153 | stack_ix--; | |
154 | /* We've handled the top of the stack's child already so | |
155 | just look at it's siblings. */ | |
156 | child_visited = true; | |
157 | } | |
158 | } | |
159 | } | |
160 | return match; | |
161 | } | |
162 | ||
163 | static void policy_tree_free_node(policy_tree_t node) { | |
164 | secdebug("policy-node", "%p children: %p siblngs: %p", node, | |
165 | node->children, node->siblings); | |
166 | if (node->expected_policy_set) { | |
167 | policy_set_free(node->expected_policy_set); | |
168 | node->expected_policy_set = NULL; | |
169 | } | |
170 | free(node); | |
171 | } | |
172 | ||
6b200bc3 A |
173 | void policy_tree_remove_node(policy_tree_t *node) { |
174 | /* Free node's children */ | |
175 | policy_tree_t *child = &(*node)->children; | |
176 | if (*child) | |
177 | policy_tree_prune(child); | |
178 | ||
179 | /* Remove node from parent */ | |
180 | policy_tree_t parent = (*node)->parent; | |
181 | parent->children = (*node)->siblings; | |
182 | ||
183 | /* Free node */ | |
184 | policy_tree_free_node(*node); | |
185 | *node = NULL; | |
186 | } | |
187 | ||
b1ab9ed8 A |
188 | /* Prune nodes from node down. */ |
189 | void policy_tree_prune(policy_tree_t *node) { | |
190 | /* Free all our children and siblings. */ | |
191 | policy_tree_t *child = &(*node)->children; | |
192 | if (*child) | |
193 | policy_tree_prune(child); | |
194 | policy_tree_t *sibling = &(*node)->siblings; | |
195 | if (*sibling) | |
196 | policy_tree_prune(sibling); | |
197 | policy_tree_free_node(*node); | |
198 | *node = NULL; | |
199 | } | |
200 | ||
201 | /* Prune childless nodes at depth. */ | |
202 | void policy_tree_prune_childless(policy_tree_t *root, int depth) { | |
203 | policy_tree_t *stack[depth + 1]; | |
204 | int stack_ix = 0; | |
205 | stack[stack_ix] = root; | |
206 | bool child_visited = false; | |
207 | while (stack_ix >= 0) { | |
208 | policy_tree_t *node; | |
209 | node = stack[stack_ix]; | |
210 | policy_tree_t *child = &(*node)->children; | |
211 | if (!child_visited && stack_ix < depth && *child) { | |
212 | /* If we have a child and we haven't reached the | |
213 | required depth yet, we go depth first and proccess it. */ | |
214 | stack[++stack_ix] = child; | |
215 | } else if (!*child) { | |
216 | /* Childless node found, nuke it. */ | |
217 | #if !defined(DUMP_POLICY_TREE) | |
218 | printf("# prune /<%.08lx<\\ |%.08lx| >%.08lx> :%s: depth %d\n", | |
219 | (intptr_t)node, (intptr_t)*node, (intptr_t)(*node)->siblings, | |
220 | (child_visited ? "v" : " "), stack_ix); | |
221 | #endif | |
222 | ||
223 | policy_tree_t next = (*node)->siblings; | |
224 | (*node)->siblings = NULL; | |
225 | policy_tree_free_node(*node); | |
226 | *node = next; | |
227 | if (next) { | |
228 | /* stack[stack_ix] (node) already points to next now. */ | |
229 | child_visited = false; | |
230 | } else { | |
231 | /* No more siblings left, so pop the stack and backtrack. */ | |
232 | stack_ix--; | |
233 | child_visited = true; | |
234 | } | |
235 | } else { | |
236 | policy_tree_t *sibling = &(*node)->siblings; | |
237 | if (*sibling) { | |
238 | /* Replace current node with it's sibling. */ | |
239 | stack[stack_ix] = sibling; | |
240 | child_visited = false; | |
241 | } else { | |
242 | /* No more siblings left, so pop the stack and backtrack. */ | |
243 | stack_ix--; | |
244 | child_visited = true; | |
245 | } | |
246 | } | |
247 | } | |
248 | } | |
249 | ||
250 | /* Add a new child to the tree. */ | |
251 | static void policy_tree_add_child_explicit(policy_tree_t parent, | |
252 | const oid_t *p_oid, policy_qualifier_t p_q, policy_set_t p_expected) { | |
253 | policy_tree_t child = malloc(sizeof(*child)); | |
6b200bc3 | 254 | memset(child, 0, sizeof(*child)); |
b1ab9ed8 A |
255 | child->valid_policy = *p_oid; |
256 | child->qualifier_set = p_q; | |
257 | child->expected_policy_set = p_expected; | |
6b200bc3 | 258 | child->parent = parent; |
b1ab9ed8 A |
259 | |
260 | #if 0 | |
261 | printf("# /%.08lx\\ |%.08lx| \\%.08lx/ >%.08lx> \\>%.08lx>/\n", | |
262 | (intptr_t)parent, (intptr_t)child, (intptr_t)parent->children, | |
263 | (intptr_t)parent->siblings, | |
264 | (intptr_t)(parent->children ? parent->children->siblings : NULL)); | |
265 | #endif | |
266 | ||
267 | /* Previous child becomes new child's first sibling. */ | |
268 | child->siblings = parent->children; | |
269 | /* New child becomes parent's first child. */ | |
270 | parent->children = child; | |
271 | ||
272 | secdebug("policy-node", "%p siblngs: %p", child, child->siblings); | |
273 | } | |
274 | ||
275 | /* Add a new child to the tree parent setting valid_policy to p_oid, | |
276 | qualifier_set to p_q and expected_policy_set to a set containing | |
277 | just p_oid. */ | |
278 | void policy_tree_add_child(policy_tree_t parent, | |
279 | const oid_t *p_oid, policy_qualifier_t p_q) { | |
280 | policy_set_t policy_set = policy_set_create(p_oid); | |
281 | policy_tree_add_child_explicit(parent, p_oid, p_q, policy_set); | |
282 | } | |
283 | ||
6b200bc3 A |
284 | /* Add a new sibling to the tree setting valid_policy to p_oid, |
285 | qualifier set to p_q and expected_policy_set to p_expected */ | |
286 | void policy_tree_add_sibling(policy_tree_t sibling, const oid_t *p_oid, | |
287 | policy_qualifier_t p_q, policy_set_t p_expected) { | |
288 | policy_tree_add_child_explicit(sibling->parent, p_oid, p_q, p_expected); | |
289 | } | |
290 | ||
b1ab9ed8 A |
291 | void policy_tree_set_expected_policy(policy_tree_t node, |
292 | policy_set_t p_expected) { | |
293 | if (node->expected_policy_set) | |
294 | policy_set_free(node->expected_policy_set); | |
295 | node->expected_policy_set = p_expected; | |
296 | } | |
297 | ||
298 | #if !defined(DUMP_POLICY_TREE) | |
299 | /* Dump a policy tree. */ | |
300 | static void policy_tree_dump4(policy_tree_t node, policy_tree_t parent, | |
301 | policy_tree_t prev_sibling, int depth) { | |
302 | policy_tree_t child = node->children; | |
303 | policy_tree_t sibling = node->siblings; | |
304 | static const char *spaces = " "; | |
305 | printf("# %.*s/%.08lx\\ |%.08lx| <%.08lx< >%.08lx> depth %d\n", | |
306 | depth * 11, spaces, | |
307 | (intptr_t)parent, (intptr_t)node, (intptr_t)prev_sibling, | |
308 | (intptr_t)sibling, depth); | |
309 | if (child) | |
310 | policy_tree_dump4(child, node, NULL, depth + 1); | |
311 | if (sibling) | |
312 | policy_tree_dump4(sibling, parent, node, depth); | |
313 | } | |
314 | #endif /* !defined(DUMP_POLICY_TREE) */ | |
315 | ||
316 | void policy_tree_dump(policy_tree_t node) { | |
317 | #if !defined(DUMP_POLICY_TREE) | |
318 | policy_tree_dump4(node, NULL, NULL, 0); | |
319 | #endif /* !defined(DUMP_POLICY_TREE) */ | |
320 | } |