]>
Commit | Line | Data |
---|---|---|
39037602 | 1 | /* |
a39ff7e2 | 2 | * Copyright (c) 2015-2018 Apple Inc. All rights reserved. |
39037602 A |
3 | * |
4 | * @APPLE_OSREFERENCE_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. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #include <sys/cprotect.h> | |
30 | #include <sys/malloc.h> | |
31 | #include <sys/mount_internal.h> | |
32 | #include <sys/filio.h> | |
33 | #include <sys/content_protection.h> | |
34 | #include <libkern/crypto/sha1.h> | |
35 | #include <libkern/libkern.h> | |
d9a64523 A |
36 | //for write protection |
37 | #include <vm/vm_kern.h> | |
38 | #include <vm/vm_map.h> | |
39037602 | 39 | |
0a7de745 | 40 | #define PTR_ADD(type, base, offset) (type)((uintptr_t)(base) + (offset)) |
39037602 A |
41 | |
42 | // -- struct cpx -- | |
43 | ||
44 | /* | |
45 | * This structure contains the unwrapped key and is passed to the lower layers. | |
46 | * It is private so users must use the accessors declared in sys/cprotect.h | |
47 | * to read/write it. | |
48 | */ | |
49 | ||
f427ee49 | 50 | // cpx_flags defined in cprotect.h |
39037602 | 51 | enum { |
0a7de745 A |
52 | CPX_SEP_WRAPPEDKEY = 0x01, |
53 | CPX_IV_AES_CTX_INITIALIZED = 0x02, | |
54 | CPX_USE_OFFSET_FOR_IV = 0x04, | |
39037602 A |
55 | |
56 | // Using AES IV context generated from key | |
0a7de745 | 57 | CPX_IV_AES_CTX_VFS = 0x08, |
813fb2f6 | 58 | CPX_SYNTHETIC_OFFSET_FOR_IV = 0x10, |
0a7de745 A |
59 | CPX_COMPOSITEKEY = 0x20, |
60 | ||
d9a64523 | 61 | //write page protection |
0a7de745 | 62 | CPX_WRITE_PROTECTABLE = 0x40 |
39037602 A |
63 | }; |
64 | ||
f427ee49 A |
65 | /* |
66 | * variable-length CPX structure. See fixed-length variant in cprotect.h | |
67 | */ | |
39037602 A |
68 | struct cpx { |
69 | #if DEBUG | |
0a7de745 | 70 | uint32_t cpx_magic1; |
39037602 | 71 | #endif |
f427ee49 | 72 | aes_encrypt_ctx *cpx_iv_aes_ctx_ptr;// Pointer to context used for generating the IV |
0a7de745 A |
73 | cpx_flags_t cpx_flags; |
74 | uint16_t cpx_max_key_len; | |
75 | uint16_t cpx_key_len; | |
f427ee49 | 76 | //fixed length up to here. cpx_cached_key is variable-length |
0a7de745 | 77 | uint8_t cpx_cached_key[]; |
813fb2f6 | 78 | }; |
39037602 | 79 | |
f427ee49 A |
80 | /* Allows us to switch between CPX types */ |
81 | typedef union cpxunion { | |
82 | struct cpx cpx_var; | |
83 | fcpx_t cpx_fixed; | |
84 | } cpxunion_t; | |
85 | ||
86 | ZONE_DECLARE(cpx_zone, "cpx", | |
87 | sizeof(struct fcpx), ZC_ZFREE_CLEARMEM); | |
88 | ZONE_DECLARE(aes_ctz_zone, "AES ctx", | |
89 | sizeof(aes_encrypt_ctx), ZC_ZFREE_CLEARMEM | ZC_NOENCRYPT); | |
90 | ||
91 | // Note: see struct fcpx defined in sys/cprotect.h | |
92 | ||
39037602 A |
93 | // -- cpx_t accessors -- |
94 | ||
0a7de745 | 95 | size_t |
f427ee49 | 96 | cpx_size(size_t key_len) |
39037602 | 97 | { |
f427ee49 A |
98 | // This should pick up the 'magic' word in DEBUG for free. |
99 | size_t size = sizeof(struct cpx) + key_len; | |
39037602 A |
100 | |
101 | return size; | |
102 | } | |
103 | ||
0a7de745 A |
104 | size_t |
105 | cpx_sizex(const struct cpx *cpx) | |
39037602 A |
106 | { |
107 | return cpx_size(cpx->cpx_max_key_len); | |
108 | } | |
109 | ||
0a7de745 | 110 | cpx_t |
f427ee49 | 111 | cpx_alloc(size_t key_len, bool needs_ctx) |
39037602 | 112 | { |
d9a64523 | 113 | cpx_t cpx = NULL; |
0a7de745 | 114 | |
d9a64523 | 115 | #if CONFIG_KEYPAGE_WP |
0a7de745 | 116 | /* |
a39ff7e2 A |
117 | * Macs only use 1 key per volume, so force it into its own page. |
118 | * This way, we can write-protect as needed. | |
119 | */ | |
0a7de745 | 120 | size_t cpsize = cpx_size(key_len); |
f427ee49 A |
121 | |
122 | // silence warning for needs_ctx | |
123 | (void) needs_ctx; | |
124 | ||
a39ff7e2 | 125 | if (cpsize < PAGE_SIZE) { |
0a7de745 A |
126 | /* |
127 | * Don't use MALLOC to allocate the page-sized structure. Instead, | |
d9a64523 | 128 | * use kmem_alloc to bypass KASAN since we are supplying our own |
0a7de745 | 129 | * unilateral write protection on this page. Note that kmem_alloc |
d9a64523 A |
130 | * can block. |
131 | */ | |
0a7de745 | 132 | if (kmem_alloc(kernel_map, (vm_offset_t *)&cpx, PAGE_SIZE, VM_KERN_MEMORY_FILE)) { |
d9a64523 | 133 | /* |
0a7de745 | 134 | * returning NULL at this point (due to failed allocation) would just |
d9a64523 A |
135 | * result in a panic. fall back to attempting a normal MALLOC, and don't |
136 | * let the cpx get marked PROTECTABLE. | |
137 | */ | |
138 | MALLOC(cpx, cpx_t, cpx_size(key_len), M_TEMP, M_WAITOK); | |
0a7de745 | 139 | } else { |
d9a64523 A |
140 | //mark the page as protectable, since kmem_alloc succeeded. |
141 | cpx->cpx_flags |= CPX_WRITE_PROTECTABLE; | |
142 | } | |
0a7de745 A |
143 | } else { |
144 | panic("cpx_size too large ! (%lu)", cpsize); | |
a39ff7e2 A |
145 | } |
146 | #else | |
f427ee49 A |
147 | /* If key page write protection disabled, just switch to zalloc */ |
148 | ||
149 | // error out if you try to request a key that's too big | |
150 | if (key_len > VFS_CP_MAX_CACHEBUFLEN) { | |
151 | return NULL; | |
152 | } | |
153 | ||
154 | // the actual key array is fixed-length, but the amount of usable content can vary, via 'key_len' | |
155 | cpx = zalloc_flags(cpx_zone, Z_WAITOK | Z_ZERO); | |
156 | ||
157 | // if our encryption type needs it, alloc the context | |
158 | if (needs_ctx) { | |
159 | cpx_alloc_ctx(cpx); | |
160 | } | |
161 | ||
a39ff7e2 | 162 | #endif |
39037602 A |
163 | cpx_init(cpx, key_len); |
164 | ||
165 | return cpx; | |
166 | } | |
167 | ||
f427ee49 A |
168 | int |
169 | cpx_alloc_ctx(cpx_t cpx) | |
170 | { | |
171 | #if CONFIG_KEYPAGE_WP | |
172 | (void) cpx; | |
173 | #else | |
174 | if (cpx->cpx_iv_aes_ctx_ptr) { | |
175 | // already allocated? | |
176 | return 0; | |
177 | } | |
178 | ||
179 | cpx->cpx_iv_aes_ctx_ptr = zalloc_flags(aes_ctz_zone, Z_WAITOK | Z_ZERO); | |
180 | #endif // CONFIG_KEYPAGE_WP | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | void | |
186 | cpx_free_ctx(cpx_t cpx) | |
187 | { | |
188 | #if CONFIG_KEYPAGE_WP | |
189 | (void) cpx; | |
190 | # else | |
191 | if (cpx->cpx_iv_aes_ctx_ptr) { | |
192 | zfree(aes_ctz_zone, cpx->cpx_iv_aes_ctx_ptr); | |
193 | } | |
194 | #endif // CONFIG_KEYPAGE_WP | |
195 | } | |
196 | ||
0a7de745 A |
197 | void |
198 | cpx_writeprotect(cpx_t cpx) | |
a39ff7e2 | 199 | { |
d9a64523 | 200 | #if CONFIG_KEYPAGE_WP |
a39ff7e2 A |
201 | void *cpxstart = (void*)cpx; |
202 | void *cpxend = (void*)((uint8_t*)cpx + PAGE_SIZE); | |
d9a64523 | 203 | if (cpx->cpx_flags & CPX_WRITE_PROTECTABLE) { |
0a7de745 | 204 | vm_map_protect(kernel_map, (vm_map_offset_t)cpxstart, (vm_map_offset_t)cpxend, (VM_PROT_READ), FALSE); |
d9a64523 | 205 | } |
a39ff7e2 A |
206 | #else |
207 | (void) cpx; | |
208 | #endif | |
209 | return; | |
210 | } | |
211 | ||
39037602 | 212 | #if DEBUG |
0a7de745 A |
213 | static const uint32_t cpx_magic1 = 0x7b787063; // cpx{ |
214 | static const uint32_t cpx_magic2 = 0x7870637d; // }cpx | |
39037602 A |
215 | #endif |
216 | ||
0a7de745 A |
217 | void |
218 | cpx_free(cpx_t cpx) | |
39037602 A |
219 | { |
220 | #if DEBUG | |
221 | assert(cpx->cpx_magic1 == cpx_magic1); | |
222 | assert(*PTR_ADD(uint32_t *, cpx, cpx_sizex(cpx) - 4) == cpx_magic2); | |
223 | #endif | |
0a7de745 | 224 | |
d9a64523 | 225 | #if CONFIG_KEYPAGE_WP |
a39ff7e2 A |
226 | /* unprotect the page before bzeroing */ |
227 | void *cpxstart = (void*)cpx; | |
0a7de745 | 228 | void *cpxend = (void*)((uint8_t*)cpx + PAGE_SIZE); |
d9a64523 | 229 | if (cpx->cpx_flags & CPX_WRITE_PROTECTABLE) { |
0a7de745 | 230 | vm_map_protect(kernel_map, (vm_map_offset_t)cpxstart, (vm_map_offset_t)cpxend, (VM_PROT_DEFAULT), FALSE); |
d9a64523 A |
231 | |
232 | //now zero the memory after un-protecting it | |
233 | bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len); | |
a39ff7e2 | 234 | |
d9a64523 A |
235 | //If we are here, then we used kmem_alloc to get the page. Must use kmem_free to drop it. |
236 | kmem_free(kernel_map, (vm_offset_t)cpx, PAGE_SIZE); | |
237 | return; | |
238 | } | |
0a7de745 | 239 | #else |
f427ee49 A |
240 | // free the context if it wasn't already freed |
241 | cpx_free_ctx(cpx); | |
242 | zfree(cpx_zone, cpx); | |
d9a64523 A |
243 | return; |
244 | #endif | |
39037602 A |
245 | } |
246 | ||
0a7de745 A |
247 | void |
248 | cpx_init(cpx_t cpx, size_t key_len) | |
39037602 A |
249 | { |
250 | #if DEBUG | |
251 | cpx->cpx_magic1 = cpx_magic1; | |
252 | *PTR_ADD(uint32_t *, cpx, cpx_size(key_len) - 4) = cpx_magic2; | |
253 | #endif | |
254 | cpx->cpx_flags = 0; | |
255 | cpx->cpx_key_len = 0; | |
f427ee49 A |
256 | assert(key_len <= UINT16_MAX); |
257 | cpx->cpx_max_key_len = (uint16_t)key_len; | |
39037602 A |
258 | } |
259 | ||
0a7de745 A |
260 | bool |
261 | cpx_is_sep_wrapped_key(const struct cpx *cpx) | |
39037602 A |
262 | { |
263 | return ISSET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
264 | } | |
265 | ||
0a7de745 A |
266 | void |
267 | cpx_set_is_sep_wrapped_key(struct cpx *cpx, bool v) | |
39037602 | 268 | { |
0a7de745 A |
269 | if (v) { |
270 | SET(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
271 | } else { | |
272 | CLR(cpx->cpx_flags, CPX_SEP_WRAPPEDKEY); | |
273 | } | |
39037602 A |
274 | } |
275 | ||
0a7de745 A |
276 | bool |
277 | cpx_is_composite_key(const struct cpx *cpx) | |
813fb2f6 | 278 | { |
0a7de745 | 279 | return ISSET(cpx->cpx_flags, CPX_COMPOSITEKEY); |
813fb2f6 A |
280 | } |
281 | ||
0a7de745 A |
282 | void |
283 | cpx_set_is_composite_key(struct cpx *cpx, bool v) | |
813fb2f6 | 284 | { |
0a7de745 A |
285 | if (v) { |
286 | SET(cpx->cpx_flags, CPX_COMPOSITEKEY); | |
287 | } else { | |
288 | CLR(cpx->cpx_flags, CPX_COMPOSITEKEY); | |
289 | } | |
813fb2f6 A |
290 | } |
291 | ||
0a7de745 A |
292 | bool |
293 | cpx_use_offset_for_iv(const struct cpx *cpx) | |
39037602 A |
294 | { |
295 | return ISSET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
296 | } | |
297 | ||
0a7de745 A |
298 | void |
299 | cpx_set_use_offset_for_iv(struct cpx *cpx, bool v) | |
39037602 | 300 | { |
0a7de745 A |
301 | if (v) { |
302 | SET(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
303 | } else { | |
304 | CLR(cpx->cpx_flags, CPX_USE_OFFSET_FOR_IV); | |
305 | } | |
39037602 A |
306 | } |
307 | ||
0a7de745 A |
308 | bool |
309 | cpx_synthetic_offset_for_iv(const struct cpx *cpx) | |
39037602 A |
310 | { |
311 | return ISSET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
312 | } | |
313 | ||
0a7de745 A |
314 | void |
315 | cpx_set_synthetic_offset_for_iv(struct cpx *cpx, bool v) | |
39037602 | 316 | { |
0a7de745 A |
317 | if (v) { |
318 | SET(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
319 | } else { | |
320 | CLR(cpx->cpx_flags, CPX_SYNTHETIC_OFFSET_FOR_IV); | |
321 | } | |
39037602 A |
322 | } |
323 | ||
0a7de745 A |
324 | uint16_t |
325 | cpx_max_key_len(const struct cpx *cpx) | |
39037602 A |
326 | { |
327 | return cpx->cpx_max_key_len; | |
328 | } | |
329 | ||
0a7de745 A |
330 | uint16_t |
331 | cpx_key_len(const struct cpx *cpx) | |
39037602 A |
332 | { |
333 | return cpx->cpx_key_len; | |
334 | } | |
335 | ||
0a7de745 A |
336 | void |
337 | cpx_set_key_len(struct cpx *cpx, uint16_t key_len) | |
39037602 A |
338 | { |
339 | cpx->cpx_key_len = key_len; | |
340 | ||
341 | if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS)) { | |
342 | /* | |
343 | * We assume that if the key length is being modified, the key | |
344 | * has changed. As a result, un-set any bits related to the | |
345 | * AES context, if needed. They should be re-generated | |
346 | * on-demand. | |
347 | */ | |
348 | CLR(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_IV_AES_CTX_VFS); | |
349 | } | |
350 | } | |
351 | ||
0a7de745 A |
352 | bool |
353 | cpx_has_key(const struct cpx *cpx) | |
39037602 A |
354 | { |
355 | return cpx->cpx_key_len > 0; | |
356 | } | |
357 | ||
358 | #pragma clang diagnostic push | |
359 | #pragma clang diagnostic ignored "-Wcast-qual" | |
0a7de745 A |
360 | void * |
361 | cpx_key(const struct cpx *cpx) | |
39037602 A |
362 | { |
363 | return (void *)cpx->cpx_cached_key; | |
364 | } | |
365 | #pragma clang diagnostic pop | |
366 | ||
0a7de745 A |
367 | void |
368 | cpx_set_aes_iv_key(struct cpx *cpx, void *iv_key) | |
39037602 | 369 | { |
f427ee49 A |
370 | if (cpx->cpx_iv_aes_ctx_ptr) { |
371 | aes_encrypt_key128(iv_key, cpx->cpx_iv_aes_ctx_ptr); | |
372 | SET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED | CPX_USE_OFFSET_FOR_IV); | |
373 | CLR(cpx->cpx_flags, CPX_IV_AES_CTX_VFS); | |
374 | } | |
39037602 A |
375 | } |
376 | ||
0a7de745 A |
377 | aes_encrypt_ctx * |
378 | cpx_iv_aes_ctx(struct cpx *cpx) | |
39037602 | 379 | { |
0a7de745 | 380 | if (ISSET(cpx->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) { |
f427ee49 | 381 | return cpx->cpx_iv_aes_ctx_ptr; |
0a7de745 | 382 | } |
39037602 A |
383 | |
384 | SHA1_CTX sha1ctxt; | |
385 | uint8_t digest[SHA_DIGEST_LENGTH]; /* Kiv */ | |
386 | ||
387 | /* First init the cp_cache_iv_key[] */ | |
388 | SHA1Init(&sha1ctxt); | |
389 | ||
390 | /* | |
391 | * We can only use this when the keys are generated in the AP; As a result | |
392 | * we only use the first 32 bytes of key length in the cache key | |
393 | */ | |
394 | SHA1Update(&sha1ctxt, cpx->cpx_cached_key, cpx->cpx_key_len); | |
395 | SHA1Final(digest, &sha1ctxt); | |
396 | ||
397 | cpx_set_aes_iv_key(cpx, digest); | |
398 | SET(cpx->cpx_flags, CPX_IV_AES_CTX_VFS); | |
399 | ||
f427ee49 | 400 | return cpx->cpx_iv_aes_ctx_ptr; |
39037602 A |
401 | } |
402 | ||
0a7de745 A |
403 | void |
404 | cpx_flush(cpx_t cpx) | |
39037602 A |
405 | { |
406 | bzero(cpx->cpx_cached_key, cpx->cpx_max_key_len); | |
f427ee49 A |
407 | if (cpx->cpx_iv_aes_ctx_ptr) { |
408 | bzero(cpx->cpx_iv_aes_ctx_ptr, sizeof(aes_encrypt_ctx)); | |
409 | } | |
39037602 A |
410 | cpx->cpx_flags = 0; |
411 | cpx->cpx_key_len = 0; | |
412 | } | |
413 | ||
0a7de745 A |
414 | bool |
415 | cpx_can_copy(const struct cpx *src, const struct cpx *dst) | |
39037602 A |
416 | { |
417 | return src->cpx_key_len <= dst->cpx_max_key_len; | |
418 | } | |
419 | ||
0a7de745 A |
420 | void |
421 | cpx_copy(const struct cpx *src, cpx_t dst) | |
39037602 A |
422 | { |
423 | uint16_t key_len = cpx_key_len(src); | |
424 | cpx_set_key_len(dst, key_len); | |
425 | memcpy(cpx_key(dst), cpx_key(src), key_len); | |
426 | dst->cpx_flags = src->cpx_flags; | |
0a7de745 | 427 | if (ISSET(dst->cpx_flags, CPX_IV_AES_CTX_INITIALIZED)) { |
f427ee49 | 428 | *(dst->cpx_iv_aes_ctx_ptr) = *(src->cpx_iv_aes_ctx_ptr); // deep copy |
0a7de745 | 429 | } |
39037602 A |
430 | } |
431 | ||
813fb2f6 A |
432 | typedef struct { |
433 | cp_lock_state_t state; | |
0a7de745 A |
434 | int valid_uuid; |
435 | uuid_t volume_uuid; | |
813fb2f6 | 436 | } cp_lock_vfs_callback_arg; |
39037602 A |
437 | |
438 | static int | |
439 | cp_lock_vfs_callback(mount_t mp, void *arg) | |
440 | { | |
813fb2f6 A |
441 | cp_lock_vfs_callback_arg *callback_arg = (cp_lock_vfs_callback_arg *)arg; |
442 | ||
0a7de745 | 443 | if (callback_arg->valid_uuid) { |
813fb2f6 A |
444 | struct vfs_attr va; |
445 | VFSATTR_INIT(&va); | |
446 | VFSATTR_WANTED(&va, f_uuid); | |
447 | ||
0a7de745 | 448 | if (vfs_getattr(mp, &va, vfs_context_current())) { |
813fb2f6 | 449 | return 0; |
0a7de745 | 450 | } |
813fb2f6 | 451 | |
0a7de745 | 452 | if (!VFSATTR_IS_SUPPORTED(&va, f_uuid)) { |
813fb2f6 | 453 | return 0; |
0a7de745 | 454 | } |
39037602 | 455 | |
0a7de745 | 456 | if (memcmp(va.f_uuid, callback_arg->volume_uuid, sizeof(uuid_t))) { |
813fb2f6 | 457 | return 0; |
0a7de745 | 458 | } |
813fb2f6 A |
459 | } |
460 | ||
461 | VFS_IOCTL(mp, FIODEVICELOCKED, (void *)(uintptr_t)callback_arg->state, 0, vfs_context_kernel()); | |
39037602 A |
462 | return 0; |
463 | } | |
464 | ||
465 | int | |
466 | cp_key_store_action(cp_key_store_action_t action) | |
467 | { | |
813fb2f6 A |
468 | cp_lock_vfs_callback_arg callback_arg; |
469 | ||
39037602 | 470 | switch (action) { |
0a7de745 A |
471 | case CP_ACTION_LOCKED: |
472 | case CP_ACTION_UNLOCKED: | |
473 | callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE); | |
474 | memset(callback_arg.volume_uuid, 0, sizeof(uuid_t)); | |
475 | callback_arg.valid_uuid = 0; | |
476 | return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg); | |
477 | default: | |
478 | return -1; | |
39037602 A |
479 | } |
480 | } | |
481 | ||
482 | int | |
813fb2f6 | 483 | cp_key_store_action_for_volume(uuid_t volume_uuid, cp_key_store_action_t action) |
39037602 | 484 | { |
813fb2f6 | 485 | cp_lock_vfs_callback_arg callback_arg; |
39037602 | 486 | |
813fb2f6 | 487 | switch (action) { |
0a7de745 A |
488 | case CP_ACTION_LOCKED: |
489 | case CP_ACTION_UNLOCKED: | |
490 | callback_arg.state = (action == CP_ACTION_LOCKED ? CP_LOCKED_STATE : CP_UNLOCKED_STATE); | |
491 | memcpy(callback_arg.volume_uuid, volume_uuid, sizeof(uuid_t)); | |
492 | callback_arg.valid_uuid = 1; | |
493 | return vfs_iterate(0, cp_lock_vfs_callback, (void *)&callback_arg); | |
494 | default: | |
495 | return -1; | |
813fb2f6 | 496 | } |
39037602 A |
497 | } |
498 | ||
499 | int | |
500 | cp_is_valid_class(int isdir, int32_t protectionclass) | |
501 | { | |
502 | /* | |
503 | * The valid protection classes are from 0 -> N | |
504 | * We use a signed argument to detect unassigned values from | |
505 | * directory entry creation time in HFS. | |
506 | */ | |
507 | if (isdir) { | |
508 | /* Directories are not allowed to have F, but they can have "NONE" */ | |
0a7de745 A |
509 | return (protectionclass >= PROTECTION_CLASS_DIR_NONE) && |
510 | (protectionclass <= PROTECTION_CLASS_D); | |
511 | } else { | |
512 | return (protectionclass >= PROTECTION_CLASS_A) && | |
513 | (protectionclass <= PROTECTION_CLASS_F); | |
39037602 A |
514 | } |
515 | } | |
516 | ||
517 | /* | |
518 | * Parses versions of the form 12A316, i.e. <major><minor><revision> and | |
519 | * returns a uint32_t in the form 0xaabbcccc where aa = <major>, | |
520 | * bb = <ASCII char>, cccc = <revision>. | |
521 | */ | |
522 | static cp_key_os_version_t | |
523 | parse_os_version(const char *vers) | |
524 | { | |
525 | const char *p = vers; | |
526 | ||
527 | int a = 0; | |
528 | while (*p >= '0' && *p <= '9') { | |
529 | a = a * 10 + *p - '0'; | |
530 | ++p; | |
531 | } | |
532 | ||
0a7de745 | 533 | if (!a) { |
39037602 | 534 | return 0; |
0a7de745 | 535 | } |
39037602 A |
536 | |
537 | int b = *p++; | |
0a7de745 | 538 | if (!b) { |
39037602 | 539 | return 0; |
0a7de745 | 540 | } |
39037602 A |
541 | |
542 | int c = 0; | |
543 | while (*p >= '0' && *p <= '9') { | |
544 | c = c * 10 + *p - '0'; | |
545 | ++p; | |
546 | } | |
547 | ||
0a7de745 | 548 | if (!c) { |
39037602 | 549 | return 0; |
0a7de745 | 550 | } |
39037602 A |
551 | |
552 | return (a & 0xff) << 24 | b << 16 | (c & 0xffff); | |
553 | } | |
554 | ||
555 | cp_key_os_version_t | |
556 | cp_os_version(void) | |
557 | { | |
558 | static cp_key_os_version_t cp_os_version; | |
559 | ||
0a7de745 | 560 | if (cp_os_version) { |
39037602 | 561 | return cp_os_version; |
0a7de745 | 562 | } |
39037602 | 563 | |
0a7de745 | 564 | if (!osversion[0]) { |
39037602 | 565 | return 0; |
0a7de745 | 566 | } |
39037602 A |
567 | |
568 | cp_os_version = parse_os_version(osversion); | |
569 | if (!cp_os_version) { | |
570 | printf("cp_os_version: unable to parse osversion `%s'\n", osversion); | |
571 | cp_os_version = 1; | |
572 | } | |
573 | ||
574 | return cp_os_version; | |
575 | } |