Merge "Set flags correctly for softkeymaster."
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index f920095..5331e32 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -554,20 +554,22 @@
         return ret;
     }
 
-    virtual int32_t password(const String16& password)
+    virtual int32_t onUserPasswordChanged(int32_t userId, const String16& password)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(userId);
         data.writeString16(password);
-        status_t status = remote()->transact(BnKeystoreService::PASSWORD, data, &reply);
+        status_t status = remote()->transact(BnKeystoreService::ON_USER_PASSWORD_CHANGED, data,
+                                             &reply);
         if (status != NO_ERROR) {
-            ALOGD("password() could not contact remote: %d\n", status);
+            ALOGD("onUserPasswordChanged() could not contact remote: %d\n", status);
             return -1;
         }
         int32_t err = reply.readExceptionCode();
         int32_t ret = reply.readInt32();
         if (err < 0) {
-            ALOGD("password() caught exception %d\n", err);
+            ALOGD("onUserPasswordChanged() caught exception %d\n", err);
             return -1;
         }
         return ret;
@@ -591,10 +593,11 @@
         return ret;
     }
 
-    virtual int32_t unlock(const String16& password)
+    virtual int32_t unlock(int32_t userId, const String16& password)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+        data.writeInt32(userId);
         data.writeString16(password);
         status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
         if (status != NO_ERROR) {
@@ -1379,10 +1382,11 @@
             reply->writeInt32(ret);
             return NO_ERROR;
         } break;
-        case PASSWORD: {
+        case ON_USER_PASSWORD_CHANGED: {
             CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t userId = data.readInt32();
             String16 pass = data.readString16();
-            int32_t ret = password(pass);
+            int32_t ret = onUserPasswordChanged(userId, pass);
             reply->writeNoException();
             reply->writeInt32(ret);
             return NO_ERROR;
@@ -1396,8 +1400,9 @@
         } break;
         case UNLOCK: {
             CHECK_INTERFACE(IKeystoreService, data, reply);
+            int32_t userId = data.readInt32();
             String16 pass = data.readString16();
-            int32_t ret = unlock(pass);
+            int32_t ret = unlock(userId, pass);
             reply->writeNoException();
             reply->writeInt32(ret);
             return NO_ERROR;
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index 8b5b5d3..d0cf6f5 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -105,7 +105,7 @@
         EXIST = IBinder::FIRST_CALL_TRANSACTION + 4,
         SAW = IBinder::FIRST_CALL_TRANSACTION + 5,
         RESET = IBinder::FIRST_CALL_TRANSACTION + 6,
-        PASSWORD = IBinder::FIRST_CALL_TRANSACTION + 7,
+        ON_USER_PASSWORD_CHANGED = IBinder::FIRST_CALL_TRANSACTION + 7,
         LOCK = IBinder::FIRST_CALL_TRANSACTION + 8,
         UNLOCK = IBinder::FIRST_CALL_TRANSACTION + 9,
         ZERO = IBinder::FIRST_CALL_TRANSACTION + 10,
@@ -154,11 +154,11 @@
 
     virtual int32_t reset() = 0;
 
-    virtual int32_t password(const String16& password) = 0;
+    virtual int32_t onUserPasswordChanged(int32_t userId, const String16& newPassword) = 0;
 
     virtual int32_t lock() = 0;
 
-    virtual int32_t unlock(const String16& password) = 0;
+    virtual int32_t unlock(int32_t userId, const String16& password) = 0;
 
     virtual int32_t zero() = 0;
 
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 13612b7..2ee7324 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -249,6 +249,10 @@
     return uid / AID_USER;
 }
 
+static uid_t get_uid(uid_t userId, uid_t appId) {
+    return userId * AID_USER + get_app_id(appId);
+}
+
 static bool keystore_selinux_check_access(uid_t /*uid*/, perm_t perm, pid_t spid) {
     if (!ks_is_selinux_enabled) {
         return true;
@@ -768,6 +772,12 @@
         memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
     }
 
+    bool deleteMasterKey() {
+        setState(STATE_UNINITIALIZED);
+        zeroizeMasterKeysInMemory();
+        return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
+    }
+
     ResponseCode initialize(const android::String8& pw, Entropy* entropy) {
         if (!generateMasterKey(entropy)) {
             return SYSTEM_ERROR;
@@ -870,19 +880,18 @@
     bool reset() {
         DIR* dir = opendir(getUserDirName());
         if (!dir) {
+            // If the directory doesn't exist then nothing to do.
+            if (errno == ENOENT) {
+                return true;
+            }
             ALOGW("couldn't open user directory: %s", strerror(errno));
             return false;
         }
 
         struct dirent* file;
         while ((file = readdir(dir)) != NULL) {
-            // We only care about files.
-            if (file->d_type != DT_REG) {
-                continue;
-            }
-
-            // Skip anything that starts with a "."
-            if (file->d_name[0] == '.' && strcmp(".masterkey", file->d_name)) {
+            // skip . and ..
+            if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
                 continue;
             }
 
@@ -1050,29 +1059,53 @@
                 encoded);
     }
 
-    bool reset(uid_t uid) {
+    /*
+     * Delete entries owned by userId. If keepUnencryptedEntries is true
+     * then only encrypted entries will be removed, otherwise all entries will
+     * be removed.
+     */
+    void resetUser(uid_t userId, bool keepUnenryptedEntries) {
         android::String8 prefix("");
         android::Vector<android::String16> aliases;
-        if (saw(prefix, &aliases, uid) != ::NO_ERROR) {
-            return ::SYSTEM_ERROR;
-        }
-
+        uid_t uid = get_uid(userId, AID_SYSTEM);
         UserState* userState = getUserState(uid);
+        if (saw(prefix, &aliases, uid) != ::NO_ERROR) {
+            return;
+        }
         for (uint32_t i = 0; i < aliases.size(); i++) {
             android::String8 filename(aliases[i]);
             filename = android::String8::format("%s/%s", userState->getUserDirName(),
-                    getKeyName(filename).string());
-            del(filename, ::TYPE_ANY, uid);
-        }
+                                                getKeyName(filename).string());
+            bool shouldDelete = true;
+            if (keepUnenryptedEntries) {
+                Blob blob;
+                ResponseCode rc = get(filename, &blob, ::TYPE_ANY, uid);
 
-        userState->zeroizeMasterKeysInMemory();
-        userState->setState(STATE_UNINITIALIZED);
-        return userState->reset();
+                /* get can fail if the blob is encrypted and the state is
+                 * not unlocked, only skip deleting blobs that were loaded and
+                 * who are not encrypted. If there are blobs we fail to read for
+                 * other reasons err on the safe side and delete them since we
+                 * can't tell if they're encrypted.
+                 */
+                shouldDelete = !(rc == ::NO_ERROR && !blob.isEncrypted());
+            }
+            if (shouldDelete) {
+                del(filename, ::TYPE_ANY, uid);
+            }
+        }
+        if (!userState->deleteMasterKey()) {
+            ALOGE("Failed to delete user %d's master key", userId);
+        }
+        if (!keepUnenryptedEntries) {
+            if(!userState->reset()) {
+                ALOGE("Failed to remove user %d's directory", userId);
+            }
+        }
     }
 
     bool isEmpty(uid_t uid) const {
         const UserState* userState = getUserState(uid);
-        if (userState == NULL || userState->getState() == STATE_UNINITIALIZED) {
+        if (userState == NULL) {
             return true;
         }
 
@@ -1729,39 +1762,46 @@
         }
 
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        return mKeyStore->reset(callingUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
+        mKeyStore->resetUser(get_user_id(callingUid), false);
+        return ::NO_ERROR;
     }
 
-    /*
-     * Here is the history. To improve the security, the parameters to generate the
-     * master key has been changed. To make a seamless transition, we update the
-     * file using the same password when the user unlock it for the first time. If
-     * any thing goes wrong during the transition, the new file will not overwrite
-     * the old one. This avoids permanent damages of the existing data.
-     */
-    int32_t password(const String16& password) {
+    int32_t onUserPasswordChanged(int32_t userId, const String16& password) {
         if (!checkBinderPermission(P_PASSWORD)) {
             return ::PERMISSION_DENIED;
         }
 
         const String8 password8(password);
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        uid_t uid = get_uid(userId, AID_SYSTEM);
 
-        switch (mKeyStore->getState(callingUid)) {
-            case ::STATE_UNINITIALIZED: {
-                // generate master key, encrypt with password, write to file, initialize mMasterKey*.
-                return mKeyStore->initializeUser(password8, callingUid);
+        // Flush the auth token table to prevent stale tokens from sticking
+        // around.
+        mAuthTokenTable.Clear();
+
+        if (password.size() == 0) {
+            ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId);
+            mKeyStore->resetUser(static_cast<uid_t>(userId), true);
+            return ::NO_ERROR;
+        } else {
+            switch (mKeyStore->getState(uid)) {
+                case ::STATE_UNINITIALIZED: {
+                    // generate master key, encrypt with password, write to file,
+                    // initialize mMasterKey*.
+                    return mKeyStore->initializeUser(password8, uid);
+                }
+                case ::STATE_NO_ERROR: {
+                    // rewrite master key with new password.
+                    return mKeyStore->writeMasterKey(password8, uid);
+                }
+                case ::STATE_LOCKED: {
+                    ALOGE("Changing user %d's password while locked, clearing old encryption",
+                          userId);
+                    mKeyStore->resetUser(static_cast<uid_t>(userId), true);
+                    return mKeyStore->initializeUser(password8, uid);
+                }
             }
-            case ::STATE_NO_ERROR: {
-                // rewrite master key with new password.
-                return mKeyStore->writeMasterKey(password8, callingUid);
-            }
-            case ::STATE_LOCKED: {
-                // read master key, decrypt with password, initialize mMasterKey*.
-                return mKeyStore->readMasterKey(password8, callingUid);
-            }
+            return ::SYSTEM_ERROR;
         }
-        return ::SYSTEM_ERROR;
     }
 
     int32_t lock() {
@@ -1780,20 +1820,21 @@
         return ::NO_ERROR;
     }
 
-    int32_t unlock(const String16& pw) {
+    int32_t unlock(int32_t userId, const String16& pw) {
         if (!checkBinderPermission(P_UNLOCK)) {
             return ::PERMISSION_DENIED;
         }
 
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        State state = mKeyStore->getState(callingUid);
+        uid_t uid = get_uid(userId, AID_SYSTEM);
+        State state = mKeyStore->getState(uid);
         if (state != ::STATE_LOCKED) {
-            ALOGD("calling unlock when not locked");
+            ALOGI("calling unlock when not locked, ignoring.");
             return state;
         }
 
         const String8 password8(pw);
-        return password(pw);
+        // read master key, decrypt with password, initialize mMasterKey*.
+        return mKeyStore->readMasterKey(password8, uid);
     }
 
     int32_t zero() {
@@ -2246,15 +2287,9 @@
     }
 
     int32_t reset_uid(int32_t targetUid) {
+        // TODO: Remove this method from the binder interface
         targetUid = getEffectiveUid(targetUid);
-        if (!checkBinderPermissionSelfOrSystem(P_RESET_UID, targetUid)) {
-            return ::PERMISSION_DENIED;
-        }
-        // Flush the auth token table to prevent stale tokens from sticking
-        // around.
-        mAuthTokenTable.Clear();
-
-        return mKeyStore->reset(targetUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
+        return onUserPasswordChanged(get_user_id(targetUid), String16(""));
     }
 
     int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index 1e19890..1391abf 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -200,11 +200,11 @@
 
     NO_ARG_INT_RETURN(reset);
 
-    SINGLE_ARG_INT_RETURN(password);
+    // TODO: notifyUserPasswordChanged
 
     NO_ARG_INT_RETURN(lock);
 
-    SINGLE_ARG_INT_RETURN(unlock);
+    // TODO: unlock
 
     NO_ARG_INT_RETURN(zero);