+
+int e4crypt_policy_get(const char *directory, char *policy, size_t policy_length) {
+ if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return -1;
+ }
+
+ if (access(directory, W_OK)) {
+ PLOG(ERROR) << "Failed to access directory " << directory;
+ return -1;
+ }
+
+ int fd = open(directory, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open directory " << directory;
+ return -1;
+ }
+
+ ext4_encryption_policy eep;
+ memset(&eep, 0, sizeof(ext4_encryption_policy));
+
+ if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &eep)) {
+ PLOG(WARNING) << "Failed to get encryption policy for " << directory;
+ close(fd);
+ return -1;
+ } else {
+ close(fd);
+ }
+
+ if ((eep.version == 0)
+ && (eep.contents_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_XTS)
+ && (eep.filenames_encryption_mode == EXT4_ENCRYPTION_MODE_AES_256_CTS)
+ && (eep.flags == 0)) {
+ memcpy(policy, eep.master_key_descriptor, EXT4_KEY_DESCRIPTOR_SIZE);
+ return 0;
+ }
+
+ LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
+ return -1;
+}
+
+int e4crypt_policy_ensure(const char *directory, const char *policy, size_t policy_length) {
+ if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
+ LOG(ERROR) << "Policy wrong length: " << policy_length;
+ return -1;
+ }
+
+ char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE];
+ if (e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) == 0) {
+ char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+ char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
+
+ policy_to_hex(policy, policy_hex);
+ policy_to_hex(existing_policy, existing_policy_hex);
+
+ if (memcmp(policy, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE) == 0) {
+ LOG(INFO) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which matches expected value";
+ return 0;
+ } else {
+ LOG(ERROR) << "Found policy " << existing_policy_hex << " at " << directory
+ << " which doesn't match expected value " << policy_hex;
+ return -1;
+ }
+ }
+
+ return e4crypt_policy_set(directory, policy, policy_length);
+}