keystore: add "migrate" command
To support the WiFi service, we need to support migration from the
system UID to the wifi UID. This adds a command to achieve the
migration.
Bug: 8122243
Change-Id: I31e2ba3b3a92c582a6f8d71bbb139c408c06814f
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 09bcf33..0b26bc8 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -136,6 +136,7 @@
P_SIGN = 1 << 11,
P_VERIFY = 1 << 12,
P_GRANT = 1 << 13,
+ P_MIGRATE = 1 << 14,
} perm_t;
static struct user_euid {
@@ -1584,6 +1585,51 @@
return static_cast<int64_t>(s.st_mtime);
}
+ int32_t migrate(const String16& name, int32_t targetUid) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(callingUid, P_MIGRATE)) {
+ ALOGW("permission denied for %d: migrate", callingUid);
+ return -1L;
+ }
+
+ State state = mKeyStore->getState();
+ if (!isKeystoreUnlocked(state)) {
+ ALOGD("calling migrate in state: %d", state);
+ return state;
+ }
+
+ if (!is_granted_to(callingUid, targetUid)) {
+ ALOGD("migrate not granted: %d -> %d", callingUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+
+ String8 source8(name);
+ char source[NAME_MAX];
+
+ encode_key_for_uid(source, callingUid, source8);
+
+ if (access(source, W_OK) == -1) {
+ return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ }
+
+ String8 target8(name);
+ char target[NAME_MAX];
+
+ encode_key_for_uid(target, targetUid, target8);
+
+ // Make sure the target doesn't exist
+ if (access(target, R_OK) == 0 || errno != ENOENT) {
+ ALOGD("migrate target already exists: %s", strerror(errno));
+ return ::SYSTEM_ERROR;
+ }
+
+ if (rename(source, target)) {
+ ALOGD("migrate could not rename: %s", strerror(errno));
+ return ::SYSTEM_ERROR;
+ }
+ return ::NO_ERROR;
+ }
+
private:
inline bool isKeystoreUnlocked(State state) {
switch (state) {