Merge "There's a missing translaton in the Greek language file." into android-8.1
diff --git a/crypto/ext4crypt/Android.mk b/crypto/ext4crypt/Android.mk
index af5ab3a..693b675 100644
--- a/crypto/ext4crypt/Android.mk
+++ b/crypto/ext4crypt/Android.mk
@@ -28,6 +28,7 @@
         LOCAL_CFLAGS += -DHAVE_LIBKEYUTILS
         LOCAL_SHARED_LIBRARIES += libkeyutils
     endif
+    LOCAL_ADDITIONAL_DEPENDENCIES := keystore_auth
 else
     LOCAL_SRC_FILES += Keymaster.cpp KeyStorage.cpp
 endif
@@ -58,4 +59,15 @@
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := keystore_auth
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_SRC_FILES := keystore_auth.cpp
+LOCAL_SHARED_LIBRARIES := libc libkeystore_binder libutils libbinder liblog
+LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64
+
+include $(BUILD_EXECUTABLE)
+
 endif
diff --git a/crypto/ext4crypt/Decrypt.cpp b/crypto/ext4crypt/Decrypt.cpp
index 2dab166..4a8494e 100644
--- a/crypto/ext4crypt/Decrypt.cpp
+++ b/crypto/ext4crypt/Decrypt.cpp
@@ -287,10 +287,27 @@
 			return false;
 		}
 		memcpy(pwd->salt, intptr + 1, pwd->salt_len);
+		intptr++;
+		byteptr = (const unsigned char*)intptr;
+		byteptr += pwd->salt_len;
 	} else {
 		printf("Get_Password_Data salt_len is 0\n");
 		return false;
 	}
+	intptr = (const int*)byteptr;
+	pwd->handle_len = *intptr;
+	endianswap(&pwd->handle_len);
+	if (pwd->handle_len != 0) {
+		pwd->password_handle = malloc(pwd->handle_len);
+		if (!pwd->password_handle) {
+			printf("Get_Password_Data malloc password_handle\n");
+			return false;
+		}
+		memcpy(pwd->password_handle, intptr + 1, pwd->handle_len);
+	} else {
+		printf("Get_Password_Data handle_len is 0\n");
+		// Not an error if using weaver
+	}
 	return true;
 }
 
@@ -496,7 +513,7 @@
 /* C++ replacement for function of the same name
  * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#867
  * returning an empty string indicates an error */
-std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const std::string& handle_str, const userid_t user_id, const void* application_id, const size_t application_id_size) {
+std::string unwrapSyntheticPasswordBlob(const std::string& spblob_path, const std::string& handle_str, const userid_t user_id, const void* application_id, const size_t application_id_size, uint32_t auth_token_len) {
 	std::string disk_decryption_secret_key = "";
 
 	std::string keystore_alias_subid;
@@ -513,6 +530,11 @@
 		return disk_decryption_secret_key;
 	}
 
+	if (auth_token_len > 0) {
+		printf("Starting keystore_auth service...\n");
+		property_set("ctl.start", "keystore_auth");
+	}
+
 	// Read the data from the .spblob file per: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#869
 	std::string spblob_file = spblob_path + handle_str + ".spblob";
 	std::string spblob_data;
@@ -579,6 +601,36 @@
     intermediate_key.resize(actual_size + final_size - 16, '\0');// not sure why we have to trim the size by 16 as I don't see where this is done in Java side
     //printf("intermediate key: "); output_hex((const unsigned char*)intermediate_key.data(), intermediate_key.size()); printf("\n");
 
+	// When using secdis (aka not weaver) you must supply an auth token to the keystore prior to the begin operation
+	if (auth_token_len > 0) {
+		/*::keystore::KeyStoreServiceReturnCode auth_result = service->addAuthToken(auth_token, auth_token_len);
+		if (!auth_result.isOk()) {
+			// The keystore checks the uid of the calling process and will return a permission denied on this operation for user 0
+			printf("keystore error adding auth token\n");
+			return disk_decryption_secret_key;
+		}*/
+		// The keystore refuses to allow the root user to supply auth tokens, so we write the auth token to a file earlier and
+		// run a separate service that runs user the system user to add the auth token. We wait for the auth token file to be
+		// deleted by the keymaster_auth service and check for a /auth_error file in case of errors. We quit after after a while if
+		// the /auth_token file never gets deleted.
+		int auth_wait_count = 20;
+		while (access("/auth_token", F_OK) == 0 && auth_wait_count-- > 0)
+			usleep(5000);
+		if (auth_wait_count == 0 || access("/auth_error", F_OK) == 0) {
+			printf("error during keymaster_auth service\n");
+			/* If you are getting this error, make sure that you have the keymaster_auth service defined in your init scripts, preferrably in init.recovery.{ro.hardware}.rc
+			 * service keystore_auth /sbin/keystore_auth
+			 *     disabled
+			 *     oneshot
+			 *     user system
+			 *     group root
+			 *     seclabel u:r:recovery:s0
+			 *
+			 * And check dmesg for error codes regarding this service if needed. */
+			return disk_decryption_secret_key;
+		}
+	}
+
 	int32_t ret;
 
 	/* We only need a keyAlias which is USRSKEY_synthetic_password_b6f71045af7bd042 which we find and a uid which is -1 or 1000, I forget which
@@ -677,11 +729,40 @@
 
 #define PASSWORD_TOKEN_SIZE 32
 
-bool Free_Return(bool retval, void* weaver_key, void* pwd_salt) {
+/* C++ replacement for
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#992
+ * called here
+ * https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#813 */
+bool Get_Secdis(const std::string& spblob_path, const std::string& handle_str, std::string& secdis_data) {
+	std::string secdis_file = spblob_path + handle_str + ".secdis";
+	if (!android::base::ReadFileToString(secdis_file, &secdis_data)) {
+		printf("Failed to read '%s'\n", secdis_file.c_str());
+		return false;
+	}
+	//output_hex(secdis_data.data(), secdis_data.size());printf("\n");
+	return true;
+}
+
+// C++ replacement for https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#1033
+userid_t fakeUid(const userid_t uid) {
+    return 100000 + uid;
+}
+
+bool Is_Weaver(const std::string& spblob_path, const std::string& handle_str) {
+	std::string weaver_file = spblob_path + handle_str + ".weaver";
+	struct stat st;
+	if (stat(weaver_file.c_str(), &st) == 0)
+		return true;
+	return false;
+}
+
+bool Free_Return(bool retval, void* weaver_key, password_data_struct* pwd) {
 	if (weaver_key)
 		free(weaver_key);
-	if (pwd_salt)
-		free(pwd_salt);
+	if (pwd->salt)
+		free(pwd->salt);
+	if (pwd->password_handle)
+		free(pwd->password_handle);
 	return retval;
 }
 
@@ -692,6 +773,12 @@
 	void* weaver_key = NULL;
 	password_data_struct pwd;
 	pwd.salt = NULL;
+	pwd.salt_len = 0;
+	pwd.password_handle = NULL;
+	pwd.handle_len = 0;
+	char application_id[PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH];
+
+    uint32_t auth_token_len = 0;
 
 	std::string secret; // this will be the disk decryption key that is sent to vold
 	std::string token = "!"; // there is no token used for this kind of decrypt, key escrow is handled by weaver
@@ -708,14 +795,14 @@
 	// Get the handle: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/LockSettingsService.java#2017
 	if (!Find_Handle(spblob_path, handle_str)) {
 		printf("Error getting handle\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	printf("Handle is '%s'\n", handle_str.c_str());
 	// Now we begin driving unwrapPasswordBasedSyntheticPassword from: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#758
 	// First we read the password data which contains scrypt parameters
 	if (!Get_Password_Data(spblob_path, handle_str, &pwd)) {
 		printf("Failed to Get_Password_Data\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	//printf("pwd N %i R %i P %i salt ", pwd.scryptN, pwd.scryptR, pwd.scryptP); output_hex((char*)pwd.salt, pwd.salt_len); printf("\n");
 	unsigned char password_token[PASSWORD_TOKEN_SIZE];
@@ -723,81 +810,152 @@
 	// The password token is the password scrypted with the parameters from the password data file
 	if (!Get_Password_Token(&pwd, Password, &password_token[0])) {
 		printf("Failed to Get_Password_Token\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	//output_hex(&password_token[0], PASSWORD_TOKEN_SIZE);printf("\n");
-	// BEGIN PIXEL 2 WEAVER
-	// Get the weaver data from the .weaver file which tells us which slot to use when we ask weaver for the escrowed key
-	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#768
-	weaver_data_struct wd;
-	if (!Get_Weaver_Data(spblob_path, handle_str, &wd)) {
-		printf("Failed to get weaver data\n");
-		// Fail over to gatekeeper path for Pixel 1???
-		return Free_Return(retval, weaver_key, pwd.salt);
-	}
-	// The weaver key is the the password token prefixed with "weaver-key" padded to 128 with nulls with the password token appended then SHA512
-	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#1059
-	weaver_key = PersonalizedHashBinary(PERSONALISATION_WEAVER_KEY, (char*)&password_token[0], PASSWORD_TOKEN_SIZE);
-	if (!weaver_key) {
-		printf("malloc error getting weaver_key\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
-	}
-	// Now we start driving weaverVerify: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#343
-	// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#776
-	android::vold::Weaver weaver;
-    if (!weaver) {
-		printf("Failed to get weaver service\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
-	}
-	// Get the key size from weaver service
-	uint32_t weaver_key_size = 0;
-	if (!weaver.GetKeySize(&weaver_key_size)) {
-		printf("Failed to get weaver key size\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+	if (Is_Weaver(spblob_path, handle_str)) {
+		printf("using weaver\n");
+		// BEGIN PIXEL 2 WEAVER
+		// Get the weaver data from the .weaver file which tells us which slot to use when we ask weaver for the escrowed key
+		// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#768
+		weaver_data_struct wd;
+		if (!Get_Weaver_Data(spblob_path, handle_str, &wd)) {
+			printf("Failed to get weaver data\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		// The weaver key is the the password token prefixed with "weaver-key" padded to 128 with nulls with the password token appended then SHA512
+		// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#1059
+		weaver_key = PersonalizedHashBinary(PERSONALISATION_WEAVER_KEY, (char*)&password_token[0], PASSWORD_TOKEN_SIZE);
+		if (!weaver_key) {
+			printf("malloc error getting weaver_key\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		// Now we start driving weaverVerify: https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#343
+		// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#776
+		android::vold::Weaver weaver;
+		if (!weaver) {
+			printf("Failed to get weaver service\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		// Get the key size from weaver service
+		uint32_t weaver_key_size = 0;
+		if (!weaver.GetKeySize(&weaver_key_size)) {
+			printf("Failed to get weaver key size\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		} else {
+			//printf("weaver key size is %u\n", weaver_key_size);
+		}
+		//printf("weaver key: "); output_hex((unsigned char*)weaver_key, weaver_key_size); printf("\n");
+		// Send the slot from the .weaver file, the computed weaver key, and get the escrowed key data
+		std::vector<uint8_t> weaver_payload;
+		// TODO: we should return more information about the status including time delays before the next retry
+		if (!weaver.WeaverVerify(wd.slot, weaver_key, &weaver_payload)) {
+			printf("failed to weaver verify\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		//printf("weaver payload: "); output_hex(&weaver_payload); printf("\n");
+		// Done with weaverVerify
+		// Now we will compute the application ID
+		// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#964
+		// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#780
+		// The escrowed weaver key data is prefixed with "weaver-pwd" padded to 128 with nulls with the weaver payload appended then SHA512
+		void* weaver_secret = PersonalizedHashBinary(PERSONALISATION_WEAVER_PASSWORD, (const char*)weaver_payload.data(), weaver_payload.size());
+		//printf("weaver secret: "); output_hex((unsigned char*)weaver_secret, SHA512_DIGEST_LENGTH); printf("\n");
+		// The application ID is the password token and weaver secret appended to each other
+		memcpy((void*)&application_id[0], (void*)&password_token[0], PASSWORD_TOKEN_SIZE);
+		memcpy((void*)&application_id[PASSWORD_TOKEN_SIZE], weaver_secret, SHA512_DIGEST_LENGTH);
+		//printf("application ID: "); output_hex((unsigned char*)application_id, PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH); printf("\n");
+		// END PIXEL 2 WEAVER
 	} else {
-		//printf("weaver key size is %u\n", weaver_key_size);
+		printf("using secdis\n");
+		std::string secdis_data;
+		if (!Get_Secdis(spblob_path, handle_str, secdis_data)) {
+			printf("Failed to get secdis data\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		void* secdiscardable = PersonalizedHashBinary(PERSONALISATION_SECDISCARDABLE, (char*)secdis_data.data(), secdis_data.size());
+		if (!secdiscardable) {
+			printf("malloc error getting secdiscardable\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		memcpy((void*)&application_id[0], (void*)&password_token[0], PASSWORD_TOKEN_SIZE);
+		memcpy((void*)&application_id[PASSWORD_TOKEN_SIZE], secdiscardable, SHA512_DIGEST_LENGTH);
+
+		int ret = -1;
+		bool request_reenroll = false;
+		android::sp<android::hardware::gatekeeper::V1_0::IGatekeeper> gk_device;
+		gk_device = ::android::hardware::gatekeeper::V1_0::IGatekeeper::getService();
+		if (gk_device == nullptr) {
+			printf("failed to get gatekeeper service\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		if (pwd.handle_len <= 0) {
+			printf("no password handle supplied\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		android::hardware::hidl_vec<uint8_t> pwd_handle_hidl;
+		pwd_handle_hidl.setToExternal(const_cast<uint8_t *>((const uint8_t *)pwd.password_handle), pwd.handle_len);
+		void* gk_pwd_token = PersonalizedHashBinary(PERSONALIZATION_USER_GK_AUTH, (char*)&password_token[0], PASSWORD_TOKEN_SIZE);
+		if (!gk_pwd_token) {
+			printf("malloc error getting gatekeeper_key\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
+		android::hardware::hidl_vec<uint8_t> gk_pwd_token_hidl;
+		gk_pwd_token_hidl.setToExternal(const_cast<uint8_t *>((const uint8_t *)gk_pwd_token), SHA512_DIGEST_LENGTH);
+		android::hardware::Return<void> hwRet =
+			gk_device->verify(fakeUid(user_id), 0 /* challange */,
+							  pwd_handle_hidl,
+							  gk_pwd_token_hidl,
+							  [&ret, &request_reenroll, &auth_token_len]
+								(const android::hardware::gatekeeper::V1_0::GatekeeperResponse &rsp) {
+									ret = static_cast<int>(rsp.code); // propagate errors
+									if (rsp.code >= android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::STATUS_OK) {
+										auth_token_len = rsp.data.size();
+										request_reenroll = (rsp.code == android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::STATUS_REENROLL);
+										ret = 0; // all success states are reported as 0
+										// The keystore refuses to allow the root user to supply auth tokens, so we write the auth token to a file here and later
+										// run a separate service that runs as the system user to add the auth token. We wait for the auth token file to be
+										// deleted by the keymaster_auth service and check for a /auth_error file in case of errors. We quit after a while seconds if
+										// the /auth_token file never gets deleted.
+										unlink("/auth_token");
+										FILE* auth_file = fopen("/auth_token","wb");
+										if (auth_file != NULL) {
+											fwrite(rsp.data.data(), sizeof(uint8_t), rsp.data.size(), auth_file);
+											fclose(auth_file);
+										} else {
+											printf("failed to open /auth_token for writing\n");
+											ret = -2;
+										}
+									} else if (rsp.code == android::hardware::gatekeeper::V1_0::GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) {
+										ret = rsp.timeout;
+									}
+								}
+							 );
+		free(gk_pwd_token);
+		if (!hwRet.isOk() || ret != 0) {
+			printf("gatekeeper verification failed\n");
+			return Free_Return(retval, weaver_key, &pwd);
+		}
 	}
-	//printf("weaver key: "); output_hex((unsigned char*)weaver_key, weaver_key_size); printf("\n");
-	// Send the slot from the .weaver file, the computed weaver key, and get the escrowed key data
-	std::vector<uint8_t> weaver_payload;
-	// TODO: we should return more information about the status including time delays before the next retry
-	if (!weaver.WeaverVerify(wd.slot, weaver_key, &weaver_payload)) {
-		printf("failed to weaver verify\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
-	}
-	//printf("weaver payload: "); output_hex(&weaver_payload); printf("\n");
-	// Done with weaverVerify
-	// Now we will compute the application ID
-	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#964
-	// Called from https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#780
-	// The escrowed weaver key data is prefixed with "weaver-pwd" padded to 128 with nulls with the weaver payload appended then SHA512
-	void* weaver_secret = PersonalizedHashBinary(PERSONALISATION_WEAVER_PASSWORD, (const char*)weaver_payload.data(), weaver_payload.size());
-	//printf("weaver secret: "); output_hex((unsigned char*)weaver_secret, SHA512_DIGEST_LENGTH); printf("\n");
-	// The application ID is the password token and weaver secret appended to each other
-	char application_id[PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH];
-	memcpy((void*)&application_id[0], (void*)&password_token[0], PASSWORD_TOKEN_SIZE);
-	memcpy((void*)&application_id[PASSWORD_TOKEN_SIZE], weaver_secret, SHA512_DIGEST_LENGTH);
-	//printf("application ID: "); output_hex((unsigned char*)application_id, PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH); printf("\n");
-	// END PIXEL 2 WEAVER
 	// Now we will handle https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#816
 	// Plus we will include the last bit that computes the disk decrypt key found in:
 	// https://android.googlesource.com/platform/frameworks/base/+/android-8.0.0_r23/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java#153
-	secret = android::keystore::unwrapSyntheticPasswordBlob(spblob_path, handle_str, user_id, (const void*)&application_id[0], PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH);
+	secret = android::keystore::unwrapSyntheticPasswordBlob(spblob_path, handle_str, user_id, (const void*)&application_id[0], PASSWORD_TOKEN_SIZE + SHA512_DIGEST_LENGTH, auth_token_len);
 	if (!secret.size()) {
 		printf("failed to unwrapSyntheticPasswordBlob\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	if (!e4crypt_unlock_user_key(user_id, 0, token.c_str(), secret.c_str())) {
 		printf("e4crypt_unlock_user_key returned fail\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	if (!e4crypt_prepare_user_storage(nullptr, user_id, 0, flags)) {
 		printf("failed to e4crypt_prepare_user_storage\n");
-		return Free_Return(retval, weaver_key, pwd.salt);
+		return Free_Return(retval, weaver_key, &pwd);
 	}
 	printf("Decrypted Successfully!\n");
 	retval = true;
-	return Free_Return(retval, weaver_key, pwd.salt);
+	return Free_Return(retval, weaver_key, &pwd);
 }
 #endif //HAVE_SYNTH_PWD_SUPPORT
 
diff --git a/crypto/ext4crypt/HashPassword.h b/crypto/ext4crypt/HashPassword.h
index 8abd0de..4be107b 100644
--- a/crypto/ext4crypt/HashPassword.h
+++ b/crypto/ext4crypt/HashPassword.h
@@ -24,6 +24,8 @@
 #define PERSONALISATION_WEAVER_PASSWORD "weaver-pwd"
 #define PERSONALISATION_APPLICATION_ID "application-id"
 #define PERSONALIZATION_FBE_KEY "fbe-key"
+#define PERSONALIZATION_USER_GK_AUTH "user-gk-authentication"
+#define PERSONALISATION_SECDISCARDABLE "secdiscardable-transform"
 
 void* PersonalizedHashBinary(const char* prefix, const char* key, const size_t key_size);
 
diff --git a/crypto/ext4crypt/keystore_auth.cpp b/crypto/ext4crypt/keystore_auth.cpp
new file mode 100644
index 0000000..7d6eb24
--- /dev/null
+++ b/crypto/ext4crypt/keystore_auth.cpp
@@ -0,0 +1,90 @@
+/*
+	Copyright 2018 bigbiff/Dees_Troy TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* The keystore refuses to allow the root user to supply auth tokens, so
+ * we write the auth token to a file in TWRP and run a separate service
+ * (this) that runs as the system user to add the auth token. TWRP waits
+ * for /auth_token to be deleted and also looks for /auth_error to check
+ * for errors. TWRP will error out after a while if /auth_token does not
+ * get deleted. */
+
+#include <stdio.h>
+#include <string>
+
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/keystore.h>
+#include <keystore/authorization_set.h>
+
+#define LOG_TAG "keystore_auth"
+
+using namespace android;
+
+void create_error_file() {
+	FILE* error_file = fopen("/auth_error", "wb");
+	if (error_file == NULL) {
+		printf("Failed to open /auth_error\n");
+		ALOGE("Failed to open /auth_error\n");
+		return;
+	}
+	fwrite("1", 1, 1, error_file);
+	fclose(error_file);
+	unlink("/auth_token");
+}
+
+int main(int argc, char *argv[]) {
+	unlink("/auth_error");
+	FILE* auth_file = fopen("/auth_token", "rb");
+	if (auth_file == NULL) {
+		printf("Failed to open /auth_token\n");
+		ALOGE("Failed to open /auth_token\n");
+		create_error_file();
+		return -1;
+	}
+	// Get the file size
+	fseek(auth_file, 0, SEEK_END);
+	int size = ftell(auth_file);
+	fseek(auth_file, 0, SEEK_SET);
+	uint8_t auth_token[size];
+	fread(auth_token , sizeof(uint8_t), size, auth_file);
+	fclose(auth_file);
+	// First get the keystore service
+	sp<IServiceManager> sm = defaultServiceManager();
+	sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+	sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+	if (service == NULL) {
+		printf("error: could not connect to keystore service\n");
+		ALOGE("error: could not connect to keystore service\n");
+		create_error_file();
+		return -2;
+	}
+	::keystore::KeyStoreServiceReturnCode auth_result = service->addAuthToken(auth_token, size);
+	if (!auth_result.isOk()) {
+		// The keystore checks the uid of the calling process and will return a permission denied on this operation for user 0
+		printf("keystore error adding auth token\n");
+		ALOGE("keystore error adding auth token\n");
+		create_error_file();
+		return -3;
+	}
+	printf("successfully added auth token to keystore\n");
+	ALOGD("successfully added auth token to keystore\n");
+	unlink("/auth_token");
+	return 0;
+}
diff --git a/data.cpp b/data.cpp
index 599b5c0..4dfbde2 100644
--- a/data.cpp
+++ b/data.cpp
@@ -230,7 +230,7 @@
 
 int DataManager::LoadValues(const string& filename)
 {
-	string str, dev_id;
+	string dev_id;
 
 	if (!mInitialized)
 		SetDefaultValues();
@@ -263,6 +263,44 @@
 	return 0;
 }
 
+int DataManager::LoadPersistValues(void)
+{
+	static bool loaded = false;
+	string dev_id;
+
+	// Only run this function once, and make sure normal settings file has not yet been read
+	if (loaded || !mBackingFile.empty() || !TWFunc::Path_Exists(PERSIST_SETTINGS_FILE))
+		return -1;
+
+	LOGINFO("Attempt to load settings from /persist settings file...\n");
+
+	if (!mInitialized)
+		SetDefaultValues();
+
+	GetValue("device_id", dev_id);
+	mPersist.SetFile(PERSIST_SETTINGS_FILE);
+	mPersist.SetFileVersion(FILE_VERSION);
+
+	// Read in the file, if possible
+	pthread_mutex_lock(&m_valuesLock);
+	mPersist.LoadValues();
+
+#ifndef TW_NO_SCREEN_TIMEOUT
+	blankTimer.setTime(mPersist.GetIntValue("tw_screen_timeout_secs"));
+#endif
+
+	update_tz_environment_variables();
+	TWFunc::Set_Brightness(GetStrValue("tw_brightness"));
+
+	pthread_mutex_unlock(&m_valuesLock);
+
+	/* Don't set storage nor backup paths this early */
+
+	loaded = true;
+
+	return 0;
+}
+
 int DataManager::Flush()
 {
 	return SaveValues();
@@ -271,6 +309,15 @@
 int DataManager::SaveValues()
 {
 #ifndef TW_OEM_BUILD
+	if (PartitionManager.Mount_By_Path("/persist", false)) {
+		mPersist.SetFile(PERSIST_SETTINGS_FILE);
+		mPersist.SetFileVersion(FILE_VERSION);
+		pthread_mutex_lock(&m_valuesLock);
+		mPersist.SaveValues();
+		pthread_mutex_unlock(&m_valuesLock);
+		LOGINFO("Saved settings file values to %s\n", PERSIST_SETTINGS_FILE);
+	}
+
 	if (mBackingFile.empty())
 		return -1;
 
@@ -284,7 +331,7 @@
 	pthread_mutex_unlock(&m_valuesLock);
 
 	tw_set_default_metadata(mBackingFile.c_str());
-	LOGINFO("Saved settings file values\n");
+	LOGINFO("Saved settings file values to '%s'\n", mBackingFile.c_str());
 #endif // ifdef TW_OEM_BUILD
 	return 0;
 }
@@ -353,7 +400,7 @@
 	return 0;
 }
 
-unsigned long long DataManager::GetValue(const string& varName, unsigned long long& value)
+int DataManager::GetValue(const string& varName, unsigned long long& value)
 {
 	string data;
 
diff --git a/data.hpp b/data.hpp
index 790efc9..d61fe8e 100644
--- a/data.hpp
+++ b/data.hpp
@@ -23,6 +23,8 @@
 #include <pthread.h>
 #include "infomanager.hpp"
 
+#define PERSIST_SETTINGS_FILE  "/persist/.twrps"
+
 using namespace std;
 
 class DataManager
@@ -30,13 +32,14 @@
 public:
 	static int ResetDefaults();
 	static int LoadValues(const string& filename);
+	static int LoadPersistValues(void);
 	static int Flush();
 
 	// Core get routines
 	static int GetValue(const string& varName, string& value);
 	static int GetValue(const string& varName, int& value);
 	static int GetValue(const string& varName, float& value);
-	static unsigned long long GetValue(const string& varName, unsigned long long& value);
+	static int GetValue(const string& varName, unsigned long long& value);
 
 	// Helper functions
 	static string GetStrValue(const string& varName);
diff --git a/minuitwrp/Android.mk b/minuitwrp/Android.mk
index 3f83c97..09bdb8d 100644
--- a/minuitwrp/Android.mk
+++ b/minuitwrp/Android.mk
@@ -48,7 +48,11 @@
 ifneq ($(wildcard external/libdrm/Android.mk),)
   LOCAL_CFLAGS += -DHAS_DRM
   LOCAL_SRC_FILES += graphics_drm.cpp
-  LOCAL_WHOLE_STATIC_LIBRARIES += libdrm
+  ifneq ($(wildcard external/libdrm/Android.common.mk),)
+    LOCAL_WHOLE_STATIC_LIBRARIES += libdrm_platform
+  else
+    LOCAL_WHOLE_STATIC_LIBRARIES += libdrm
+  endif
 endif
 
 LOCAL_C_INCLUDES += \
diff --git a/partition.cpp b/partition.cpp
index 3957c65..59bd168 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -581,6 +581,18 @@
 			Process_TW_Flags(flagptr, Display_Error, 1); // Forcing the fstab to ver 1 because this data is coming from the /etc/twrp.flags which should be using the TWRP v1 flags format
 		}
 	}
+
+	if (Mount_Point == "/persist" && Can_Be_Mounted) {
+		bool mounted = Is_Mounted();
+		if (mounted || Mount(false)) {
+			// Read the backup settings file
+			DataManager::LoadPersistValues();
+			TWFunc::Fixup_Time_On_Boot("/persist/time/");
+			if (!mounted)
+				UnMount(false);
+		}
+	}
+
 	return true;
 }
 
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 7b950fc..b54dda2 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -34,6 +34,9 @@
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/fsck.fat
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/fatlabel
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/mkfs.fat
+ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 27; echo $$?),0)
+    RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/adbd
+endif
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/e2fsck
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/mke2fs
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/tune2fs
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index 5df44c6..b7bcebe 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -881,9 +881,12 @@
 	}
 }
 
-void TWFunc::Fixup_Time_On_Boot()
+void TWFunc::Fixup_Time_On_Boot(const string& time_paths /* = "" */)
 {
 #ifdef QCOM_RTC_FIX
+	static bool fixed = false;
+	if (fixed)
+		return;
 
 	LOGINFO("TWFunc::Fixup_Time: Pre-fix date and time: %s\n", TWFunc::Get_Current_Date().c_str());
 
@@ -904,6 +907,7 @@
 		if (tv.tv_sec > 1405209403) { // Anything older then 12 Jul 2014 23:56:43 GMT will do nicely thank you ;)
 
 			LOGINFO("TWFunc::Fixup_Time: Date and time corrected: %s\n", TWFunc::Get_Current_Date().c_str());
+			fixed = true;
 			return;
 
 		}
@@ -925,22 +929,28 @@
 	// Like, ats_1 is for modem and ats_2 is for TOD (time of day?).
 	// Look at file time_genoff.h in CodeAurora, qcom-opensource/time-services
 
-	static const char *paths[] = { "/data/system/time/", "/data/time/"  };
+	std::vector<std::string> paths; // space separated list of paths
+	if (time_paths.empty()) {
+		paths = Split_String("/data/system/time/ /data/time/", " ");
+		if (!PartitionManager.Mount_By_Path("/data", false))
+			return;
+	} else {
+		// When specific path(s) are used, Fixup_Time needs those
+		// partitions to already be mounted!
+		paths = Split_String(time_paths, " ");
+	}
 
 	FILE *f;
 	offset = 0;
 	struct dirent *dt;
 	std::string ats_path;
 
-	if (!PartitionManager.Mount_By_Path("/data", false))
-		return;
-
 	// Prefer ats_2, it seems to be the one we want according to logcat on hammerhead
 	// - it is the one for ATS_TOD (time of day?).
 	// However, I never saw a device where the offset differs between ats files.
-	for (size_t i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i)
+	for (size_t i = 0; i < paths.size(); ++i)
 	{
-		DIR *d = opendir(paths[i]);
+		DIR *d = opendir(paths[i].c_str());
 		if (!d)
 			continue;
 
@@ -950,34 +960,38 @@
 				continue;
 
 			if (ats_path.empty() || strcmp(dt->d_name, "ats_2") == 0)
-				ats_path = std::string(paths[i]).append(dt->d_name);
+				ats_path = paths[i] + dt->d_name;
 		}
 
 		closedir(d);
 	}
 
-	if (ats_path.empty())
-	{
+	if (ats_path.empty()) {
 		LOGINFO("TWFunc::Fixup_Time: no ats files found, leaving untouched!\n");
-		return;
-	}
-
-	f = fopen(ats_path.c_str(), "r");
-	if (!f)
-	{
+	} else if ((f = fopen(ats_path.c_str(), "r")) == NULL) {
 		LOGINFO("TWFunc::Fixup_Time: failed to open file %s\n", ats_path.c_str());
-		return;
-	}
-
-	if (fread(&offset, sizeof(offset), 1, f) != 1)
-	{
+	} else if (fread(&offset, sizeof(offset), 1, f) != 1) {
 		LOGINFO("TWFunc::Fixup_Time: failed load uint64 from file %s\n", ats_path.c_str());
 		fclose(f);
-		return;
-	}
-	fclose(f);
+	} else {
+		fclose(f);
 
-	LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), offset);
+		LOGINFO("TWFunc::Fixup_Time: Setting time offset from file %s, offset %llu\n", ats_path.c_str(), (unsigned long long) offset);
+		DataManager::SetValue("tw_qcom_ats_offset", (unsigned long long) offset, 1);
+		fixed = true;
+	}
+
+	if (!fixed) {
+		// Failed to get offset from ats file, check twrp settings
+		unsigned long long value;
+		if (DataManager::GetValue("tw_qcom_ats_offset", value) < 0) {
+			return;
+		} else {
+			offset = (uint64_t) value;
+			LOGINFO("TWFunc::Fixup_Time: Setting time offset from twrp setting file, offset %llu\n", (unsigned long long) offset);
+			// Do not consider the settings file as a definitive answer, keep fixed=false so next run will try ats files again
+		}
+	}
 
 	gettimeofday(&tv, NULL);
 
@@ -993,7 +1007,6 @@
 	settimeofday(&tv, NULL);
 
 	LOGINFO("TWFunc::Fixup_Time: Date and time corrected: %s\n", TWFunc::Get_Current_Date().c_str());
-
 #endif
 }
 
diff --git a/twrp-functions.hpp b/twrp-functions.hpp
index 9c149ea..a1f67f2 100644
--- a/twrp-functions.hpp
+++ b/twrp-functions.hpp
@@ -88,7 +88,7 @@
 	static string System_Property_Get(string Prop_Name);                // Returns value of Prop_Name from reading /system/build.prop
 	static string Get_Current_Date(void);                               // Returns the current date in ccyy-m-dd--hh-nn-ss format
 	static void Auto_Generate_Backup_Name();                            // Populates TW_BACKUP_NAME with a backup name based on current date and ro.build.display.id from /system/build.prop
-	static void Fixup_Time_On_Boot(); // Fixes time on devices which need it
+	static void Fixup_Time_On_Boot(const string& time_paths = ""); // Fixes time on devices which need it (time_paths is a space separated list of paths to check for ats_* files)
 	static std::vector<std::string> Split_String(const std::string& str, const std::string& delimiter, bool removeEmpty = true); // Splits string by delimiter
 	static bool Create_Dir_Recursive(const std::string& path, mode_t mode = 0755, uid_t uid = -1, gid_t gid = -1);  // Create directory and it's parents, if they don't exist. mode, uid and gid are set to all _newly_ created folders. If whole path exists, do nothing.
 	static int Set_Brightness(std::string brightness_value); // Well, you can read, it does what it says, passing return int from TWFunc::Write_File ;)