9 #include <IOKit/IOKitLib.h>
10 #include <Kernel/IOKit/crypto/AppleKeyStoreDefs.h>
11 #include <Kernel/sys/content_protection.h>
13 /* Note that this test (due to the need to lock/unlock the device on demand, and the
14 need to manipulate the passcode) has the unfortunate effect of link xnu_quick_test
15 to the IOKit Framework. */
17 /* TODO: Change the test to use a single cleanup label. */
19 #define CPT_IO_SIZE 4096
20 #define CPT_AKS_BUF_SIZE 256
21 #define CPT_MAX_PASS_LEN 64
23 #define GET_PROT_CLASS(fd) fcntl((fd), F_GETPROTECTIONCLASS)
24 #define SET_PROT_CLASS(fd, prot_class) fcntl((fd), F_SETPROTECTIONCLASS, (prot_class))
26 #define PRINT_LOCK_FAIL printf("%s, line %d: failed to lock the device.\n", cpt_fail_header, __LINE__);
27 #define PRINT_UNLOCK_FAIL printf("%s, line %d: failed to unlock the device.\n", cpt_fail_header, __LINE__);
29 extern char g_target_path
[PATH_MAX
];
31 char * cpt_fail_header
= "Content protection test failed";
32 char * keystorectl_path
= "/usr/local/bin/keystorectl";
34 /* Shamelessly ripped from keystorectl routines; a wrapper for invoking the AKS user client. */
35 int apple_key_store(uint32_t command
,
39 size_t input_struct_count
,
41 uint32_t * output_count
)
44 io_connect_t connection
= IO_OBJECT_NULL
;
45 io_registry_entry_t apple_key_bag_service
= IO_OBJECT_NULL
;
46 kern_return_t k_result
= KERN_FAILURE
;
47 IOReturn io_result
= IO_OBJECT_NULL
;
49 apple_key_bag_service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching(kAppleKeyStoreServiceName
));
51 if (apple_key_bag_service
== IO_OBJECT_NULL
)
53 printf("FAILURE: failed to match kAppleKeyStoreServiceName.\n");
57 k_result
= IOServiceOpen(apple_key_bag_service
, mach_task_self(), 0, &connection
);
59 if (k_result
!= KERN_SUCCESS
)
61 printf("FAILURE: failed to open AppleKeyStore.\n");
65 k_result
= IOConnectCallMethod(connection
, kAppleKeyStoreUserClientOpen
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
, NULL
);
67 if (k_result
!= KERN_SUCCESS
)
69 printf("FAILURE: call to AppleKeyStore method kAppleKeyStoreUserClientOpen failed.\n");
73 io_result
= IOConnectCallMethod(connection
, command
, inputs
, input_count
, input_structs
, input_struct_count
, outputs
, output_count
, NULL
, NULL
);
75 if (io_result
!= kIOReturnSuccess
)
77 printf("FAILURE: call to AppleKeyStore method %d failed.\n", command
);
84 IOServiceClose(apple_key_bag_service
);
90 #ifndef KEYBAG_ENTITLEMENTS
91 /* Just a wrapper around forking to exec keystorectl for commands requiring entitlements. */
92 int keystorectl(char * const command
[])
94 int child_result
= -1;
102 printf("FAILURE: failed to fork.\n");
107 /* TODO: This keeps keystorectl from bombarding us with key state changes, but
108 there must be a better way of doing this; killing stderr is a bit nasty,
109 and if keystorectl fails, we want all the information we can get. */
112 execv(keystorectl_path
, command
);
113 printf("FAILURE: child failed to execv keystorectl, errno = %s.\n",
118 if ((waitpid(child
, &child_result
, 0) != child
) || WEXITSTATUS(child_result
))
120 printf("FAILURE: keystorectl failed.\n");
131 #endif /* KEYBAG_ENTITLEMENTS */
133 /* Code based on Mobile Key Bag; specifically MKBDeviceSupportsContentProtection
134 and MKBDeviceFormattedForContentProtection. */
135 /* We want to verify that we support content protection, and that
136 we are formatted for it. */
137 int supports_content_prot()
139 int local_result
= -1;
141 uint32_t buffer_size
= 1;
142 char buffer
[buffer_size
];
143 io_registry_entry_t defaults
= IO_OBJECT_NULL
;
144 kern_return_t k_result
= KERN_FAILURE
;
145 struct statfs statfs_results
;
147 defaults
= IORegistryEntryFromPath(kIOMasterPortDefault
, kIODeviceTreePlane
":/defaults");
149 if (defaults
== IO_OBJECT_NULL
)
151 printf("FAILURE: failed to find defaults registry entry.\n");
155 k_result
= IORegistryEntryGetProperty(defaults
, "content-protect", buffer
, &buffer_size
);
157 if (k_result
!= KERN_SUCCESS
)
158 { /* This isn't a failure; it means the entry doesn't exist, so we assume CP
164 /* At this point, we SUPPORT content protection... but are we formatted for it? */
165 /* This is ugly; we should be testing the file system we'll be testing in, not
167 local_result
= statfs(g_target_path
, &statfs_results
);
169 if (local_result
== -1)
171 printf("FAILURE: failed to statfs the test directory, errno = %s.\n",
174 else if (statfs_results
.f_flags
& MNT_CPROTECT
)
179 { /* This isn't a failure, it means the filesystem isn't formatted for CP. */
188 int device_lock_state()
190 /* TODO: Actually implement this. */
191 /* We fail if a passcode already exists, and the methods being used to lock/unlock
192 the device in this test appear to be synchronous... do we need this function? */
203 #ifdef KEYBAG_ENTITLEMENTS
204 /* If we're entitled, we can lock the device ourselves. */
205 uint64_t inputs
[] = {device_keybag_handle
};
206 uint32_t input_count
= (sizeof(inputs
) / sizeof(*inputs
));
207 result
= apple_key_store(kAppleKeyStoreKeyBagLock
, inputs
, input_count
, NULL
, 0, NULL
, NULL
);
209 /* If we aren't entitled, we'll need to use keystorectl to lock the device. */
210 /* keystorectl seems to have a bus error (though it locks successfully) unless
211 lock is passed an argument, so we'll also pass it the empty string. */
212 char * const keystorectl_args
[] = {keystorectl_path
, "lock", "", NULL
};
213 result
= keystorectl(keystorectl_args
);
214 #endif /* KEYBAG_ENTITLEMENTS */
219 int unlock_device(char * passcode
)
223 #ifdef KEYBAG_ENTITLEMENTS
224 /* If we're entitled, we can unlock the device ourselves. */
225 uint64_t inputs
[] = {device_keybag_handle
};
226 uint32_t input_count
= (sizeof(inputs
) / sizeof(*inputs
));
227 size_t input_struct_count
= 0;
229 if ((passcode
== NULL
) || ((input_struct_count
= strnlen(passcode
, CPT_MAX_PASS_LEN
)) == CPT_MAX_PASS_LEN
))
232 input_struct_count
= 0;
235 result
= apple_key_store(kAppleKeyStoreKeyBagUnlock
, inputs
, input_count
, passcode
, input_struct_count
, NULL
, NULL
);
237 /* If we aren't entitled, we'll need to use keystorectl to unlock the device. */
238 if ((passcode
== NULL
) || (strnlen(passcode
, CPT_MAX_PASS_LEN
) == CPT_MAX_PASS_LEN
))
243 char * const keystorectl_args
[] = {keystorectl_path
, "unlock", passcode
, NULL
};
244 result
= keystorectl(keystorectl_args
);
245 #endif /* KEYBAG_ENTITLEMENTS */
250 int set_passcode(char * new_passcode
, char * old_passcode
)
254 #ifdef KEYBAG_ENTITLEMENTS
255 /* If we're entitled, we can set the passcode ourselves. */
256 uint64_t inputs
[] = {device_keybag_handle
};
257 uint32_t input_count
= (sizeof(inputs
) / sizeof(*inputs
));
258 void * input_structs
= NULL
;
259 size_t input_struct_count
= 0;
260 char buffer
[CPT_AKS_BUF_SIZE
];
261 char * buffer_ptr
= buffer
;
262 uint32_t old_passcode_len
= 0;
263 uint32_t new_passcode_len
= 0;
265 if ((old_passcode
== NULL
) || ((old_passcode_len
= strnlen(old_passcode
, CPT_MAX_PASS_LEN
)) == CPT_MAX_PASS_LEN
))
268 old_passcode_len
= 0;
271 if ((new_passcode
== NULL
) || ((new_passcode_len
= strnlen(new_passcode
, CPT_MAX_PASS_LEN
)) == CPT_MAX_PASS_LEN
))
274 new_passcode_len
= 0;
277 *((uint32_t *) buffer_ptr
) = ((uint32_t) 2);
278 buffer_ptr
+= sizeof(uint32_t);
279 *((uint32_t *) buffer_ptr
) = old_passcode_len
;
280 buffer_ptr
+= sizeof(uint32_t);
281 memcpy(buffer_ptr
, old_passcode
, old_passcode_len
);
282 buffer_ptr
+= ((old_passcode_len
+ sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1));
283 *((uint32_t *) buffer_ptr
) = new_passcode_len
;
284 buffer_ptr
+= sizeof(uint32_t);
285 memcpy(buffer_ptr
, new_passcode
, new_passcode_len
);
286 buffer_ptr
+= ((new_passcode_len
+ sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1));
287 input_structs
= buffer
;
288 input_struct_count
= (buffer_ptr
- buffer
);
290 result
= apple_key_store(kAppleKeyStoreKeyBagSetPasscode
, inputs
, input_count
, input_structs
, input_struct_count
, NULL
, NULL
);
292 /* If we aren't entitled, we'll need to use keystorectl to set the passcode. */
293 if ((old_passcode
== NULL
) || (strnlen(old_passcode
, CPT_MAX_PASS_LEN
) == CPT_MAX_PASS_LEN
))
298 if ((new_passcode
== NULL
) || (strnlen(new_passcode
, CPT_MAX_PASS_LEN
) == CPT_MAX_PASS_LEN
))
303 char * const keystorectl_args
[] = {keystorectl_path
, "change-password", old_passcode
, new_passcode
, NULL
};
304 result
= keystorectl(keystorectl_args
);
305 #endif /* KEYBAG_ENTITLEMENTS */
310 int clear_passcode(char * passcode
)
312 /* For the moment, this will set the passcode to the empty string (a known value);
313 this will most likely need to change, or running this test may ruin everything(tm). */
316 result
= set_passcode(NULL
, passcode
);
322 /* Determines if we will try to test class C semanatics. */
323 int unlocked_since_boot()
325 /* TODO: Actually implement this. */
326 /* The actual semantics for CP mean that even with this primative, we would need
327 set a passcode and then reboot the device in order to test this; this function
328 will probably be rather worthless as a result. */
335 /* If the device has a passcode when we want to test it, things are going to go wrong.
336 As such, we'll assume the device never has a passcode.
338 Or we could just try "" to ""; it works. */
343 result
= set_passcode(NULL
, NULL
);
348 int content_protection_test(void * argp
)
350 #pragma unused (argp)
352 int local_result
= -1;
353 int test_result
= -1;
357 int new_prot_class
= -1;
358 int old_prot_class
= -1;
359 int current_byte
= 0;
360 char filepath
[PATH_MAX
];
361 char dirpath
[PATH_MAX
];
362 char subdirpath
[PATH_MAX
];
363 char rd_buffer
[CPT_IO_SIZE
];
364 char wr_buffer
[CPT_IO_SIZE
];
365 char * passcode
= "IAmASecurePassword";
367 /* Do some initial setup (names). */
368 bzero(filepath
, PATH_MAX
);
369 bzero(dirpath
, PATH_MAX
);
370 bzero(subdirpath
, PATH_MAX
);
372 /* This is just easier than checking each result individually. */
373 init_result
|= (strlcat(filepath
, g_target_path
, PATH_MAX
) == PATH_MAX
);
374 init_result
|= (strlcat(filepath
, "/", PATH_MAX
) == PATH_MAX
);
375 init_result
|= (strlcpy(dirpath
, filepath
, PATH_MAX
) == PATH_MAX
);
376 init_result
|= (strlcat(filepath
, "cpt_test_file", PATH_MAX
) == PATH_MAX
);
377 init_result
|= (strlcat(dirpath
, "cpt_test_dir/", PATH_MAX
) == PATH_MAX
);
378 init_result
|= (strlcpy(subdirpath
, dirpath
, PATH_MAX
) == PATH_MAX
);
379 init_result
|= (strlcat(subdirpath
, "cpt_test_subdir/", PATH_MAX
) == PATH_MAX
);
382 { /* If any of the initialization failed, we're just going to fail now. */
383 printf("%s, line %d: failed to initialize test strings.\n",
384 cpt_fail_header
, __LINE__
);
388 local_result
= supports_content_prot();
390 if (local_result
== -1)
392 printf("%s, line %d: failed to determine if content protection is supported.\n",
393 cpt_fail_header
, __LINE__
);
396 else if (local_result
== 0)
397 { /* If we don't support content protection at the moment, pass the test. */
398 printf("This device does not support or is not formatted for content protection.\n");
403 /* If we support content protection, we'll need to be able to set the passcode. */
404 local_result
= has_passcode();
406 if (local_result
== -1)
408 printf("%s, line %d: the device appears to have a passcode.\n",
409 cpt_fail_header
, __LINE__
);
413 if (set_passcode(passcode
, NULL
))
415 printf("%s, line %d: failed to set a new passcode.\n",
416 cpt_fail_header
, __LINE__
);
420 fd
= open(filepath
, O_CREAT
| O_EXCL
| O_RDWR
| O_CLOEXEC
);
424 printf("%s, line %d: failed to create the test file, errno = %s.\n",
425 cpt_fail_header
, __LINE__
, strerror(errno
));
426 goto remove_passcode
;
429 /* Ensure we can freely read and change protection classes when unlocked. */
430 for (new_prot_class
= PROTECTION_CLASS_A
; new_prot_class
<= PROTECTION_CLASS_F
; new_prot_class
++)
432 old_prot_class
= GET_PROT_CLASS(fd
);
434 if (old_prot_class
== -1)
436 printf("%s, line %d: failed to get protection class when unlocked, errno = %s.\n",
437 cpt_fail_header
, __LINE__
, strerror(errno
));
441 if (SET_PROT_CLASS(fd
, new_prot_class
))
443 printf("%s, line %d: failed to change protection class from %d to %d during unlock, errno = %s.\n",
444 cpt_fail_header
, __LINE__
, old_prot_class
, new_prot_class
, strerror(errno
));
449 if (SET_PROT_CLASS(fd
, PROTECTION_CLASS_D
))
451 printf("%s, line %d: failed to change protection class from F to D when unlocked, errno = %s.\n",
452 cpt_fail_header
, __LINE__
, strerror(errno
));
456 /* Try making a class A file while locked. */
463 if (!SET_PROT_CLASS(fd
, PROTECTION_CLASS_A
))
465 printf("%s, line %d: was able to change protection class from D to A when locked.\n",
466 cpt_fail_header
, __LINE__
);
470 if (unlock_device(passcode
))
476 /* Attempt opening/IO to a class A file while unlocked. */
477 if (SET_PROT_CLASS(fd
, PROTECTION_CLASS_A
))
479 printf("%s, line %d: failed to change protection class from D to A when unlocked, errno = %s.\n",
480 cpt_fail_header
, __LINE__
, strerror(errno
));
485 fd
= open(filepath
, O_RDWR
| O_CLOEXEC
);
489 printf("%s, line %d: failed to open a class A file when unlocked, errno = %s.\n",
490 cpt_fail_header
, __LINE__
, strerror(errno
));
494 /* TODO: Write specific data we can check for.
495 If we're going to do that, the write scheme should be deliberately ugly. */
498 while (current_byte
< CPT_IO_SIZE
)
500 local_result
= pwrite(fd
, &wr_buffer
[current_byte
], CPT_IO_SIZE
- current_byte
, current_byte
);
502 if (local_result
== -1)
504 printf("%s, line %d: failed to write to class A file when unlocked, errno = %s.\n",
505 cpt_fail_header
, __LINE__
, strerror(errno
));
509 current_byte
+= local_result
;
514 while (current_byte
< CPT_IO_SIZE
)
516 local_result
= pread(fd
, &rd_buffer
[current_byte
], CPT_IO_SIZE
- current_byte
, current_byte
);
518 if (local_result
== -1)
520 printf("%s, line %d: failed to read from class A file when unlocked, errno = %s.\n",
521 cpt_fail_header
, __LINE__
, strerror(errno
));
525 current_byte
+= local_result
;
528 /* Again, but now while locked; and try to change the file class as well. */
535 if (pread(fd
, rd_buffer
, CPT_IO_SIZE
, 0) > 0)
537 printf("%s, line %d: was able to read from a class A file when locked.\n",
538 cpt_fail_header
, __LINE__
);
542 if (pwrite(fd
, wr_buffer
, CPT_IO_SIZE
, 0) > 0)
544 printf("%s, line %d: was able to write to a class A file when locked.\n",
545 cpt_fail_header
, __LINE__
);
549 if (!SET_PROT_CLASS(fd
, PROTECTION_CLASS_D
))
551 printf("%s, line %d: was able to change protection class from A to D when locked.\n",
552 cpt_fail_header
, __LINE__
);
556 /* Try to open and truncate the file. */
558 fd
= open(filepath
, O_RDWR
| O_TRUNC
| O_CLOEXEC
);
562 printf("%s, line %d: was able to open and truncate a class A file when locked.\n",
563 cpt_fail_header
, __LINE__
);
567 /* Try to open the file */
568 fd
= open(filepath
, O_RDWR
| O_CLOEXEC
);
572 printf("%s, line %d: was able to open a class A file when locked.\n",
573 cpt_fail_header
, __LINE__
);
577 /* What about class B files? */
578 if (unlock_device(passcode
))
584 fd
= open(filepath
, O_RDWR
| O_CLOEXEC
);
588 printf("%s, line %d: was unable to open a class A file when unlocked.\n",
589 cpt_fail_header
, __LINE__
);
593 if (SET_PROT_CLASS(fd
, PROTECTION_CLASS_D
))
595 printf("%s, line %d: failed to change protection class from A to D when unlocked, errno = %s.\n",
596 cpt_fail_header
, __LINE__
, strerror(errno
));
606 /* Can we create a class B file while locked? */
607 if (SET_PROT_CLASS(fd
, PROTECTION_CLASS_B
))
609 printf("%s, line %d: failed to change protection class from D to B when locked, errno = %s.\n",
610 cpt_fail_header
, __LINE__
, strerror(errno
));
614 /* We should also be able to read/write to the file descriptor while it is open. */
617 while (current_byte
< CPT_IO_SIZE
)
619 local_result
= pwrite(fd
, &wr_buffer
[current_byte
], CPT_IO_SIZE
- current_byte
, current_byte
);
621 if (local_result
== -1)
623 printf("%s, line %d: failed to write to new class B file when locked, errno = %s.\n",
624 cpt_fail_header
, __LINE__
, strerror(errno
));
628 current_byte
+= local_result
;
633 while (current_byte
< CPT_IO_SIZE
)
635 local_result
= pread(fd
, &rd_buffer
[current_byte
], CPT_IO_SIZE
- current_byte
, current_byte
);
637 if (local_result
== -1)
639 printf("%s, line %d: failed to read from new class B file when locked, errno = %s.\n",
640 cpt_fail_header
, __LINE__
, strerror(errno
));
644 current_byte
+= local_result
;
647 /* We should not be able to open a class B file under lock. */
649 fd
= open(filepath
, O_RDWR
| O_CLOEXEC
);
653 printf("%s, line %d: was able to open a class B file when locked.\n",
654 cpt_fail_header
, __LINE__
);
660 /* We still need to test directory semantics. */
661 if (mkdir(dirpath
, 0x0777) == -1)
663 printf("%s, line %d: failed to create a new directory when locked, errno = %s.\n",
664 cpt_fail_header
, __LINE__
, strerror(errno
));
665 goto remove_passcode
;
668 /* The newly created directory should not have a protection class. */
669 dir_fd
= open(dirpath
, O_RDONLY
| O_CLOEXEC
);
673 printf("%s, line %d: failed to open an unclassed directory when locked, errno = %s.\n",
674 cpt_fail_header
, __LINE__
, strerror(errno
));
678 if (GET_PROT_CLASS(dir_fd
) != PROTECTION_CLASS_D
)
680 printf("%s, line %d: newly created directory had a non-D protection class.\n",
681 cpt_fail_header
, __LINE__
);
685 if (SET_PROT_CLASS(dir_fd
, PROTECTION_CLASS_A
))
687 printf("%s, line %d: was unable to change a directory from class D to class A during lock.\n",
688 cpt_fail_header
, __LINE__
);
692 if (SET_PROT_CLASS(dir_fd
, PROTECTION_CLASS_D
))
694 printf("%s, line %d: failed to change a directory from class A to class D during lock, errno = %s.\n",
695 cpt_fail_header
, __LINE__
, strerror(errno
));
699 /* Do all files created in the directory properly inherit the directory's protection class? */
700 if ((strlcpy(filepath
, dirpath
, PATH_MAX
) == PATH_MAX
) || (strlcat(filepath
, "cpt_test_file", PATH_MAX
) == PATH_MAX
))
702 printf("%s, line %d: failed to construct the path for a file in the directory.\n",
703 cpt_fail_header
, __LINE__
);
707 if (unlock_device(passcode
))
713 for (new_prot_class
= PROTECTION_CLASS_A
; new_prot_class
<= PROTECTION_CLASS_E
; new_prot_class
++)
715 old_prot_class
= GET_PROT_CLASS(dir_fd
);
717 if (old_prot_class
== -1)
719 printf("%s, line %d: failed to get the protection class for the directory, errno = %s.\n",
720 cpt_fail_header
, __LINE__
, strerror(errno
));
724 if (SET_PROT_CLASS(dir_fd
, new_prot_class
))
726 printf("%s, line %d: failed to change the protection class for the directory from %d to %d, errno = %s.\n",
727 cpt_fail_header
, __LINE__
, old_prot_class
, new_prot_class
, strerror(errno
));
731 fd
= open(filepath
, O_CREAT
| O_EXCL
| O_CLOEXEC
);
735 printf("%s, line %d: failed to create a file in a class %d directory when unlocked, errno = %s.\n",
736 cpt_fail_header
, __LINE__
, new_prot_class
, strerror(errno
));
740 local_result
= GET_PROT_CLASS(fd
);
742 if (local_result
== -1)
744 printf("%s, line %d: failed to get the new file's protection class, errno = %s.\n",
745 cpt_fail_header
, __LINE__
, strerror(errno
));
748 else if (local_result
!= new_prot_class
)
750 printf("%s, line %d: new file did not inherit the directory's protection class.\n",
751 cpt_fail_header
, __LINE__
, strerror(errno
));
759 /* Do we disallow creation of a class F directory? */
760 if (!SET_PROT_CLASS(dir_fd
, PROTECTION_CLASS_F
))
762 printf("%s, line %d: creation of a class F directory did not fail as expected.\n",
763 cpt_fail_header
, __LINE__
);
767 /* And are class A and class B semantics followed for when we create these files during lock? */
768 if (SET_PROT_CLASS(dir_fd
, PROTECTION_CLASS_A
))
770 printf("%s, line %d: failed to change directory class from F to A when unlocked, errno = %s.\n",
771 cpt_fail_header
, __LINE__
, strerror(errno
));
781 fd
= open(filepath
, O_CREAT
| O_EXCL
| O_CLOEXEC
);
785 printf("%s, line %d: was able to create a new file in a class A directory when locked.\n",
786 cpt_fail_header
, __LINE__
, strerror(errno
));
790 if (unlock_device(passcode
))
796 if (SET_PROT_CLASS(dir_fd
, PROTECTION_CLASS_B
))
798 printf("%s, line %d: failed to change directory class from A to B when unlocked, errno = %s.\n",
799 cpt_fail_header
, __LINE__
, strerror(errno
));
809 fd
= open(filepath
, O_CREAT
| O_EXCL
| O_RDWR
| O_CLOEXEC
);
813 printf("%s, line %d: failed to create new file in class B directory when locked, errno = %s.\n",
814 cpt_fail_header
, __LINE__
, strerror(errno
));
818 local_result
= GET_PROT_CLASS(fd
);
820 if (local_result
== -1)
822 printf("%s, line %d: failed to get protection class for a new file when locked, errno = %s.\n",
823 cpt_fail_header
, __LINE__
, strerror(errno
));
826 else if (local_result
!= PROTECTION_CLASS_B
)
828 printf("%s, line %d: new file in class B directory did not inherit protection class.\n",
829 cpt_fail_header
, __LINE__
, strerror(errno
));
833 /* What happens when we try to create new subdirectories? */
834 if (unlock_device(passcode
))
840 for (new_prot_class
= PROTECTION_CLASS_A
; new_prot_class
<= PROTECTION_CLASS_E
; new_prot_class
++)
842 if (SET_PROT_CLASS(dir_fd
, new_prot_class
))
844 printf("%s, line %d: failed to change directory to class %d, errno = %s.\n",
845 cpt_fail_header
, __LINE__
, new_prot_class
, strerror(errno
));
849 local_result
= mkdir(subdirpath
, 0x0777);
851 if (local_result
== -1)
853 printf("%s, line %d: failed to create subdirectory in class %d directory, errno = %s.\n",
854 cpt_fail_header
, __LINE__
, new_prot_class
, strerror(errno
));
858 subdir_fd
= open(subdirpath
, O_RDONLY
| O_CLOEXEC
);
862 printf("%s, line %d: failed to open subdirectory in class %d directory, errno = %s.\n",
863 cpt_fail_header
, __LINE__
, new_prot_class
, strerror(errno
));
867 local_result
= GET_PROT_CLASS(subdir_fd
);
869 if (local_result
== -1)
871 printf("%s, line %d: failed to get class of new subdirectory of class %d directory, errno = %s.\n",
872 cpt_fail_header
, __LINE__
, new_prot_class
, strerror(errno
));
875 else if (local_result
!= new_prot_class
)
877 printf("%s, line %d: new subdirectory had different class than class %d parent.\n",
878 cpt_fail_header
, __LINE__
, new_prot_class
);
886 /* If we've made it this far, the test was successful. */
908 /* Try to unlock the device (no ramifications if it isn't locked when we try) and remove the passcode. */
909 if (unlock_device(passcode
))
911 printf("WARNING: failed to unlock the device.\n");
914 if (clear_passcode(passcode
))
916 printf("WARNING: failed to clear the passcode.\n");