Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0246a8a authored by Robin Lee's avatar Robin Lee
Browse files

Keep managed profile keystores in sync with owner

Fixes setting a keyguard password for keystore in a multi-user setup
while we're at it.

Bug: 16233206.
Change-Id: I7941707ca66ac25bd122fd22e5e0f639e7af697e
parent d627eac2
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -478,6 +478,59 @@ public interface IKeystoreService extends IInterface {
                }
                return _result;
            }

            public int reset_uid(int uid) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(uid);
                    mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            public int sync_uid(int srcUid, int dstUid) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(srcUid);
                    _data.writeInt(dstUid);
                    mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            public int password_uid(String password, int uid) throws RemoteException {
                Parcel _data = Parcel.obtain();
                Parcel _reply = Parcel.obtain();
                int _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(password);
                    _data.writeInt(uid);
                    mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        private static final String DESCRIPTOR = "android.security.keystore";
@@ -505,6 +558,9 @@ public interface IKeystoreService extends IInterface {
        static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20;
        static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21;
        static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22;
        static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23;
        static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24;
        static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25;

        /**
         * Cast an IBinder object into an IKeystoreService interface, generating
@@ -597,4 +653,10 @@ public interface IKeystoreService extends IInterface {
    public int is_hardware_backed(String string) throws RemoteException;

    public int clear_uid(long uid) throws RemoteException;

    public int reset_uid(int uid) throws RemoteException;

    public int sync_uid(int sourceUid, int targetUid) throws RemoteException;

    public int password_uid(String password, int uid) throws RemoteException;
}
+30 −0
Original line number Diff line number Diff line
@@ -331,6 +331,36 @@ public class KeyStore {
        }
    }

    public boolean resetUid(int uid) {
        try {
            mError = mBinder.reset_uid(uid);
            return mError == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean syncUid(int sourceUid, int targetUid) {
        try {
            mError = mBinder.sync_uid(sourceUid, targetUid);
            return mError == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public boolean passwordUid(String password, int uid) {
        try {
            mError = mBinder.password_uid(password, uid);
            return mError == NO_ERROR;
        } catch (RemoteException e) {
            Log.w(TAG, "Cannot connect to keystore", e);
            return false;
        }
    }

    public int getLastError() {
        return mError;
    }
+63 −10
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.server;

import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;

@@ -31,6 +34,7 @@ import android.database.sqlite.SQLiteStatement;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.storage.IMountService;
import android.os.ServiceManager;
@@ -41,11 +45,14 @@ import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;

import com.android.internal.os.BackgroundThread;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.ILockSettingsObserver;
import com.android.internal.widget.LockPatternUtils;
@@ -99,7 +106,29 @@ public class LockSettingsService extends ILockSettings.Stub {

        mLockPatternUtils = new LockPatternUtils(context);
        mFirstCallToVold = true;

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_USER_ADDED);
        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
    }

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            // Update keystore settings for profiles which use the same password as their parent
            if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
                final UserInfo parentInfo = um.getProfileParent(userHandle);
                if (parentInfo != null) {
                    final KeyStore ks = KeyStore.getInstance();
                    final int profileUid = UserHandle.getUid(userHandle, Process.SYSTEM_UID);
                    final int parentUid = UserHandle.getUid(parentInfo.id, Process.SYSTEM_UID);
                    ks.syncUid(parentUid, profileUid);
                }
            }
        }
    };

    public void systemReady() {
        migrateOldData();
@@ -275,6 +304,17 @@ public class LockSettingsService extends ILockSettings.Stub {
        }
    }

    private int getUserParentOrSelfId(int userId) {
        if (userId != 0) {
            final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
            final UserInfo pi = um.getProfileParent(userId);
            if (pi != null) {
                return pi.id;
            }
        }
        return userId;
    }

    private String getLockPatternFilename(int userId) {
        String dataSystemDirectory =
                android.os.Environment.getDataDirectory().getAbsolutePath() +
@@ -283,6 +323,7 @@ public class LockSettingsService extends ILockSettings.Stub {
            // Leave it in the same place for user 0
            return dataSystemDirectory + LOCK_PATTERN_FILE;
        } else {
            userId = getUserParentOrSelfId(userId);
            return  new File(Environment.getUserSystemDirectory(userId), LOCK_PATTERN_FILE)
                    .getAbsolutePath();
        }
@@ -296,6 +337,7 @@ public class LockSettingsService extends ILockSettings.Stub {
            // Leave it in the same place for user 0
            return dataSystemDirectory + LOCK_PASSWORD_FILE;
        } else {
            userId = getUserParentOrSelfId(userId);
            return new File(Environment.getUserSystemDirectory(userId), LOCK_PASSWORD_FILE)
                    .getAbsolutePath();
        }
@@ -315,16 +357,27 @@ public class LockSettingsService extends ILockSettings.Stub {
        return new File(getLockPatternFilename(userId)).length() > 0;
    }

    private void maybeUpdateKeystore(String password, int userId) {
        if (userId == UserHandle.USER_OWNER) {
            final KeyStore keyStore = KeyStore.getInstance();
            // Conditionally reset the keystore if empty. If non-empty, we are just
            // switching key guard type
            if (TextUtils.isEmpty(password) && keyStore.isEmpty()) {
                keyStore.reset();
    private void maybeUpdateKeystore(String password, int userHandle) {
        final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
        final KeyStore ks = KeyStore.getInstance();

        final List<UserInfo> profiles = um.getProfiles(userHandle);
        boolean shouldReset = TextUtils.isEmpty(password);

        // For historical reasons, don't wipe a non-empty keystore if we have a single user with a
        // single profile.
        if (userHandle == UserHandle.USER_OWNER && profiles.size() == 1) {
            if (!ks.isEmpty()) {
                shouldReset = false;
            }
        }

        for (UserInfo pi : profiles) {
            final int profileUid = UserHandle.getUid(pi.id, Process.SYSTEM_UID);
            if (shouldReset) {
                ks.resetUid(profileUid);
            } else {
                // Update the keystore password
                keyStore.password(password);
                ks.passwordUid(password, profileUid);
            }
        }
    }