Add onUserAdded/Removed methods

These will handle the logic of Android users being added/removed from
the device instead of the system calling the various reset/sync methods.

(cherry-picked from commit fd777e7111ce01c672706867302db08371e5afce)

Change-Id: Ic6be0de63cc1b0579a46e7101dcfeb1a9ffa4738
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 64530f5..ab31418 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -1291,6 +1291,46 @@
         }
         return ret;
     };
+
+    virtual int32_t onUserAdded(int32_t userId, int32_t parentId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(userId);
+        data.writeInt32(parentId);
+        status_t status = remote()->transact(BnKeystoreService::ON_USER_ADDED, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("onUserAdded() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("onUserAdded() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
+    virtual int32_t onUserRemoved(int32_t userId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(userId);
+        status_t status = remote()->transact(BnKeystoreService::ON_USER_REMOVED, data, &reply);
+        if (status != NO_ERROR) {
+            ALOGD("onUserRemoved() could not contact remote: %d\n", status);
+            return -1;
+        }
+        int32_t err = reply.readExceptionCode();
+        int32_t ret = reply.readInt32();
+        if (err < 0) {
+            ALOGD("onUserRemoved() caught exception %d\n", err);
+            return -1;
+        }
+        return ret;
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService");
@@ -1794,6 +1834,25 @@
 
             return NO_ERROR;
         }
+        case ON_USER_ADDED: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t userId = data.readInt32();
+            int32_t parentId = data.readInt32();
+            int32_t result = onUserAdded(userId, parentId);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            return NO_ERROR;
+        }
+        case ON_USER_REMOVED: {
+            CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t userId = data.readInt32();
+            int32_t result = onUserRemoved(userId);
+            reply->writeNoException();
+            reply->writeInt32(result);
+
+            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 d0cf6f5..7fdfe38 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -135,6 +135,8 @@
         ABORT = IBinder::FIRST_CALL_TRANSACTION + 34,
         IS_OPERATION_AUTHORIZED = IBinder::FIRST_CALL_TRANSACTION + 35,
         ADD_AUTH_TOKEN = IBinder::FIRST_CALL_TRANSACTION + 36,
+        ON_USER_ADDED = IBinder::FIRST_CALL_TRANSACTION + 37,
+        ON_USER_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 38,
     };
 
     DECLARE_META_INTERFACE(KeystoreService);
@@ -236,6 +238,10 @@
 
     virtual int32_t addAuthToken(const uint8_t* token, size_t length) = 0;
 
+    virtual int32_t onUserAdded(int32_t userId, int32_t parentId) = 0;
+
+    virtual int32_t onUserRemoved(int32_t userId) = 0;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index c321c45..3068756 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -172,6 +172,7 @@
     P_SYNC_UID      = 1 << 17,
     P_PASSWORD_UID  = 1 << 18,
     P_ADD_AUTH      = 1 << 19,
+    P_USER_CHANGED  = 1 << 20,
 } perm_t;
 
 static struct user_euid {
@@ -205,6 +206,7 @@
     "sync_uid",
     "password_uid",
     "add_auth",
+    "user_changed",
 };
 
 static struct user_perm {
@@ -1813,6 +1815,36 @@
         }
     }
 
+    int32_t onUserAdded(int32_t userId, int32_t parentId) {
+        if (!checkBinderPermission(P_USER_CHANGED)) {
+            return ::PERMISSION_DENIED;
+        }
+
+        // Sanity check that the new user has an empty keystore.
+        if (!mKeyStore->isEmpty(userId)) {
+            ALOGW("New user %d's keystore not empty. Clearing old entries.", userId);
+        }
+        // Unconditionally clear the keystore, just to be safe.
+        mKeyStore->resetUser(userId, false);
+
+        // If the user has a parent user then use the parent's
+        // masterkey/password, otherwise there's nothing to do.
+        if (parentId != -1) {
+            return mKeyStore->copyMasterKey(parentId, userId);
+        } else {
+            return ::NO_ERROR;
+        }
+    }
+
+    int32_t onUserRemoved(int32_t userId) {
+        if (!checkBinderPermission(P_USER_CHANGED)) {
+            return ::PERMISSION_DENIED;
+        }
+
+        mKeyStore->resetUser(userId, false);
+        return ::NO_ERROR;
+    }
+
     int32_t lock() {
         if (!checkBinderPermission(P_LOCK)) {
             return ::PERMISSION_DENIED;