APIs for syncing password between profiles

Bug: 16233206.
Change-Id: I7941707ca66ac25bd122fd22e5e0f639e7af697e
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 727e746..40fbe0e 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -579,6 +579,65 @@
         }
         return ret;
     }
+
+    virtual int32_t reset_uid(int32_t uid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        status_t status = remote()->transact(BnKeystoreService::RESET_UID, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("reset_uid() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("reset_uid() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+
+    }
+
+    virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(sourceUid);
+        data.writeInt32(targetUid);
+        status_t status = remote()->transact(BnKeystoreService::SYNC_UID, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("sync_uid() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("sync_uid() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t password_uid(const String16& password, int32_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeString16(password);
+        data.writeInt32(uid);
+        status_t status = remote()->transact(BnKeystoreService::PASSWORD_UID, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("password_uid() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("password_uid() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
@@ -875,6 +934,32 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         }
+        case RESET_UID: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t uid = data.readInt32();
+            int32_t ret = reset_uid(uid);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case SYNC_UID: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t sourceUid = data.readInt32();
+            int32_t targetUid = data.readInt32();
+            int32_t ret = sync_uid(sourceUid, targetUid);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
+        case PASSWORD_UID: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            String16 password = data.readString16();
+            int32_t uid = data.readInt32();
+            int32_t ret = password_uid(password, uid);
+            reply->writeNoException();
+            reply->writeInt32(ret);
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index d7281e3..afdff8d 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -65,6 +65,9 @@
         DUPLICATE = IBinder::FIRST_CALL_TRANSACTION + 20,
         IS_HARDWARE_BACKED = IBinder::FIRST_CALL_TRANSACTION + 21,
         CLEAR_UID = IBinder::FIRST_CALL_TRANSACTION + 22,
+        RESET_UID = IBinder::FIRST_CALL_TRANSACTION + 23,
+        SYNC_UID = IBinder::FIRST_CALL_TRANSACTION + 24,
+        PASSWORD_UID = IBinder::FIRST_CALL_TRANSACTION + 25,
     };
 
     DECLARE_META_INTERFACE(KeystoreService);
@@ -120,6 +123,12 @@
     virtual int32_t is_hardware_backed(const String16& keyType) = 0;
 
     virtual int32_t clear_uid(int64_t uid) = 0;
+
+    virtual int32_t reset_uid(int32_t uid) = 0;
+
+    virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) = 0;
+
+    virtual int32_t password_uid(const String16& password, int32_t uid) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index bda6948..9e460d7 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -136,22 +136,25 @@
 
 /* Here are the permissions, actions, users, and the main function. */
 typedef enum {
-    P_TEST      = 1 << 0,
-    P_GET       = 1 << 1,
-    P_INSERT    = 1 << 2,
-    P_DELETE    = 1 << 3,
-    P_EXIST     = 1 << 4,
-    P_SAW       = 1 << 5,
-    P_RESET     = 1 << 6,
-    P_PASSWORD  = 1 << 7,
-    P_LOCK      = 1 << 8,
-    P_UNLOCK    = 1 << 9,
-    P_ZERO      = 1 << 10,
-    P_SIGN      = 1 << 11,
-    P_VERIFY    = 1 << 12,
-    P_GRANT     = 1 << 13,
-    P_DUPLICATE = 1 << 14,
-    P_CLEAR_UID = 1 << 15,
+    P_TEST          = 1 << 0,
+    P_GET           = 1 << 1,
+    P_INSERT        = 1 << 2,
+    P_DELETE        = 1 << 3,
+    P_EXIST         = 1 << 4,
+    P_SAW           = 1 << 5,
+    P_RESET         = 1 << 6,
+    P_PASSWORD      = 1 << 7,
+    P_LOCK          = 1 << 8,
+    P_UNLOCK        = 1 << 9,
+    P_ZERO          = 1 << 10,
+    P_SIGN          = 1 << 11,
+    P_VERIFY        = 1 << 12,
+    P_GRANT         = 1 << 13,
+    P_DUPLICATE     = 1 << 14,
+    P_CLEAR_UID     = 1 << 15,
+    P_RESET_UID     = 1 << 16,
+    P_SYNC_UID      = 1 << 17,
+    P_PASSWORD_UID  = 1 << 18,
 } perm_t;
 
 static struct user_euid {
@@ -180,7 +183,10 @@
     "verify",
     "grant",
     "duplicate",
-    "clear_uid"
+    "clear_uid",
+    "reset_uid",
+    "sync_uid",
+    "password_uid",
 };
 
 static struct user_perm {
@@ -761,6 +767,18 @@
         return ::NO_ERROR;
     }
 
+    ResponseCode copyMasterKey(UserState* src) {
+        if (mState != STATE_UNINITIALIZED) {
+            return ::SYSTEM_ERROR;
+        }
+        if (src->getState() != STATE_NO_ERROR) {
+            return ::SYSTEM_ERROR;
+        }
+        memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
+        setupMasterKeys();
+        return ::NO_ERROR;
+    }
+
     ResponseCode writeMasterKey(const android::String8& pw, Entropy* entropy) {
         uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
         generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
@@ -969,11 +987,18 @@
         return userState->initialize(pw, mEntropy);
     }
 
+    ResponseCode copyMasterKey(uid_t src, uid_t uid) {
+        UserState *userState = getUserState(uid);
+        UserState *initState = getUserState(src);
+        return userState->copyMasterKey(initState);
+    }
+
     ResponseCode writeMasterKey(const android::String8& pw, uid_t uid) {
         UserState* userState = getUserState(uid);
         return userState->writeMasterKey(pw, mEntropy);
     }
 
+
     ResponseCode readMasterKey(const android::String8& pw, uid_t uid) {
         UserState* userState = getUserState(uid);
         return userState->readMasterKey(pw, mEntropy);
@@ -2381,6 +2406,71 @@
         return rc;
     }
 
+    int32_t reset_uid(int32_t uid) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        pid_t spid = IPCThreadState::self()->getCallingPid();
+        if (!has_permission(callingUid, P_RESET_UID, spid)) {
+            ALOGW("permission denied for %d: reset_uid %d", callingUid, uid);
+            return ::PERMISSION_DENIED;
+        }
+        if (callingUid != AID_SYSTEM) {
+            ALOGW("permission denied for %d: reset_uid %d", callingUid, uid);
+            return ::PERMISSION_DENIED;
+        }
+
+        return mKeyStore->reset(uid) ? ::NO_ERROR : ::SYSTEM_ERROR;
+    }
+
+    int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        pid_t spid = IPCThreadState::self()->getCallingPid();
+        if (!has_permission(callingUid, P_SYNC_UID, spid)) {
+            ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
+            return ::PERMISSION_DENIED;
+        }
+        if (callingUid != AID_SYSTEM) {
+            ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
+            return ::PERMISSION_DENIED;
+        }
+        if (sourceUid == targetUid) {
+            return ::SYSTEM_ERROR;
+        }
+
+        // Initialise user keystore with existing master key held in-memory
+        return mKeyStore->copyMasterKey(sourceUid, targetUid);
+    }
+
+    int32_t password_uid(const String16& pw, int32_t targetUid) {
+        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        pid_t spid = IPCThreadState::self()->getCallingPid();
+        if (!has_permission(callingUid, P_PASSWORD_UID, spid)) {
+            ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
+            return ::PERMISSION_DENIED;
+        }
+        if (callingUid != AID_SYSTEM) {
+            ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
+            return ::PERMISSION_DENIED;
+        }
+
+        const String8 password8(pw);
+
+        switch (mKeyStore->getState(targetUid)) {
+            case ::STATE_UNINITIALIZED: {
+                // generate master key, encrypt with password, write to file, initialize mMasterKey*.
+                return mKeyStore->initializeUser(password8, targetUid);
+            }
+            case ::STATE_NO_ERROR: {
+                // rewrite master key with new password.
+                return mKeyStore->writeMasterKey(password8, targetUid);
+            }
+            case ::STATE_LOCKED: {
+                // read master key, decrypt with password, initialize mMasterKey*.
+                return mKeyStore->readMasterKey(password8, targetUid);
+            }
+        }
+        return ::SYSTEM_ERROR;
+    }
+
 private:
     inline bool isKeystoreUnlocked(State state) {
         switch (state) {