diff options
author | Carlos Valdivia <carlosvaldivia@google.com> | 2015-06-11 20:04:31 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-11 20:04:44 +0000 |
commit | d0041e5f474f4e795d6bc9e5eeaec4098949897c (patch) | |
tree | 253f82ccd582d44409c73074ca5eff89523f14e2 | |
parent | c8488e99e85ae5252e6078c00d123f1364aef25d (diff) | |
parent | dcddc476651deb72a27798de56eef584e5be5d32 (diff) | |
download | frameworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.zip frameworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.tar.gz frameworks_base-d0041e5f474f4e795d6bc9e5eeaec4098949897c.tar.bz2 |
Merge "Revert "Permissions: Fix account related permissions."" into mnc-dev
-rw-r--r-- | api/current.txt | 3 | ||||
-rw-r--r-- | api/system-current.txt | 3 | ||||
-rw-r--r-- | core/java/android/accounts/AccountManager.java | 155 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 24 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 21 | ||||
-rw-r--r-- | docs/html/training/sync-adapters/creating-sync-adapter.jd | 7 | ||||
-rw-r--r-- | services/core/java/com/android/server/accounts/AccountManagerService.java | 301 |
7 files changed, 284 insertions, 230 deletions
diff --git a/api/current.txt b/api/current.txt index ec56ce0..cfb9398 100644 --- a/api/current.txt +++ b/api/current.txt @@ -17,6 +17,7 @@ package android { field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE"; field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER"; field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"; + field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS"; field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; @@ -85,6 +86,7 @@ package android { field public static final java.lang.String INTERNET = "android.permission.INTERNET"; field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; + field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS"; field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; @@ -143,6 +145,7 @@ package android { field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR"; field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT"; field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; + field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS"; field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; field public static final java.lang.String VIBRATE = "android.permission.VIBRATE"; diff --git a/api/system-current.txt b/api/system-current.txt index 5ec8a62..6035ef2 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24,6 +24,7 @@ package android { field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER"; field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"; field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"; + field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS"; field public static final java.lang.String BACKUP = "android.permission.BACKUP"; field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; @@ -116,6 +117,7 @@ package android { field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS"; field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO"; + field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS"; field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS"; field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS"; field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES"; @@ -215,6 +217,7 @@ package android { field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK"; field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY"; + field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS"; field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; field public static final java.lang.String VIBRATE = "android.permission.VIBRATE"; diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 993b53d..31e129b 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -51,7 +51,10 @@ import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static android.Manifest.permission.AUTHENTICATE_ACCOUNTS; import static android.Manifest.permission.GET_ACCOUNTS; +import static android.Manifest.permission.MANAGE_ACCOUNTS; +import static android.Manifest.permission.USE_CREDENTIALS; /** * This class provides access to a centralized registry of the user's @@ -316,12 +319,14 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that owns the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the account's authenticator. * - * @param account The account to query for a password. Must not be {@code null}. + * @param account The account to query for a password * @return The account's password, null if none or if the account doesn't exist */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String getPassword(final Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -340,12 +345,14 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that owns the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the account's authenticator. * * @param account The account to query for user data * @return The user data, null if the account or key doesn't exist */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String getUserData(final Account account, final String key) { if (account == null) throw new IllegalArgumentException("account is null"); if (key == null) throw new IllegalArgumentException("key is null"); @@ -655,8 +662,10 @@ public class AccountManager { * wizards associated with authenticators, not directly by applications. * * <p>It is safe to call this method from the main thread. - * <p>This method requires the caller to have a signature match with the - * authenticator that owns the specified account. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the added account's authenticator. * * @param account The {@link Account} to add * @param password The password to associate with the account, null for none @@ -664,6 +673,7 @@ public class AccountManager { * @return True if the account was successfully added, false if the account * already exists, the account is null, or another error occurs. */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean addAccountExplicitly(Account account, String password, Bundle userdata) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -682,13 +692,14 @@ public class AccountManager { * <p> * It is not safe to call this method from the main thread. As such, call it * from another thread. - * <p>This method requires the caller to have a signature match with the - * authenticator that owns the specified account. + * <p> + * This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be + * called from the account's authenticator. * * @param account The {@link Account} to be updated. - * @return boolean {@code true} if the authentication of the account has been successfully - * acknowledged. Otherwise {@code false}. */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean notifyAccountAuthenticated(Account account) { if (account == null) throw new IllegalArgumentException("account is null"); @@ -706,8 +717,9 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and have the same UID as the account's authenticator. * * @param account The {@link Account} to rename * @param newName String name to be associated with the account. @@ -719,6 +731,7 @@ public class AccountManager { * after the name change. If successful the account's name will be the * specified new name. */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public AccountManagerFuture<Account> renameAccount( final Account account, @Size(min = 1) final String newName, @@ -770,8 +783,11 @@ public class AccountManager { * The authenticator may have its own policies preventing account * deletion, in which case the account will not be deleted. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method may be called from any thread, but the returned + * {@link AccountManagerFuture} must not be used on the main thread. + * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. * * @param account The {@link Account} to remove * @param callback Callback to invoke when the request completes, @@ -784,16 +800,15 @@ public class AccountManager { * {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)} * instead */ + @RequiresPermission(MANAGE_ACCOUNTS) @Deprecated public AccountManagerFuture<Boolean> removeAccount(final Account account, AccountManagerCallback<Boolean> callback, Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); return new Future2Task<Boolean>(handler, callback) { - @Override public void doWork() throws RemoteException { mService.removeAccount(mResponse, account, false); } - @Override public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { throw new AuthenticatorException("no result in response"); @@ -812,8 +827,8 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. * * @param account The {@link Account} to remove * @param activity The {@link Activity} context to use for launching a new @@ -840,11 +855,11 @@ public class AccountManager { * adding accounts (of this type) has been disabled by policy * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> removeAccount(final Account account, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { if (account == null) throw new IllegalArgumentException("account is null"); return new AmsTask(activity, handler, callback) { - @Override public void doWork() throws RemoteException { mService.removeAccount(mResponse, account, activity != null); } @@ -865,11 +880,9 @@ public class AccountManager { if (account == null) throw new IllegalArgumentException("account is null"); if (userHandle == null) throw new IllegalArgumentException("userHandle is null"); return new Future2Task<Boolean>(handler, callback) { - @Override public void doWork() throws RemoteException { mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier()); } - @Override public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { throw new AuthenticatorException("no result in response"); @@ -905,14 +918,17 @@ public class AccountManager { * in which case the account will not be deleted. * <p> * It is safe to call this method from the main thread. - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p> + * This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the + * same UID or signature as the account's authenticator. * * @param account The {@link Account} to delete. * @return True if the account was successfully deleted, false if the * account did not exist, the account is null, or another error * occurs. */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public boolean removeAccountExplicitly(Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -932,9 +948,14 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or + * {@link android.Manifest.permission#USE_CREDENTIALS} + * * @param accountType The account type of the auth token to invalidate, must not be null * @param authToken The auth token to invalidate, may be null */ + @RequiresPermission(anyOf = {MANAGE_ACCOUNTS, USE_CREDENTIALS}) public void invalidateAuthToken(final String accountType, final String authToken) { if (accountType == null) throw new IllegalArgumentException("accountType is null"); try { @@ -955,15 +976,16 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the account's authenticator. * - * @param account The account for which an auth token is to be fetched. Cannot be {@code null}. - * @param authTokenType The type of auth token to fetch. Cannot be {@code null}. + * @param account The account to fetch an auth token for + * @param authTokenType The type of auth token to fetch, see {#getAuthToken} * @return The cached auth token for this account and type, or null if * no auth token is cached or the account does not exist. - * @see #getAuthToken */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public String peekAuthToken(final Account account, final String authTokenType) { if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); @@ -983,12 +1005,14 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and have the same UID as the account's authenticator. * - * @param account The account whose password is to be set. Cannot be {@code null}. + * @param account The account to set a password for * @param password The password to set, null to clear the password */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setPassword(final Account account, final String password) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -1006,14 +1030,14 @@ public class AccountManager { * permissions, and may be used by applications or management interfaces * to "sign out" from an account. * - * <p>This method only successfully clear the account's password when the - * caller has the same signature as the authenticator that owns the - * specified account. Otherwise, this method will silently fail. - * * <p>It is safe to call this method from the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS} + * * @param account The account whose password to clear */ + @RequiresPermission(MANAGE_ACCOUNTS) public void clearPassword(final Account account) { if (account == null) throw new IllegalArgumentException("account is null"); try { @@ -1031,13 +1055,15 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the account's authenticator. * - * @param account Account whose user data is to be set. Must not be {@code null}. - * @param key String user data key to set. Must not be null - * @param value String value to set, {@code null} to clear this user data key + * @param account The account to set the userdata for + * @param key The userdata key to set. Must not be null + * @param value The value to set, null to clear this userdata key */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setUserData(final Account account, final String key, final String value) { if (account == null) throw new IllegalArgumentException("account is null"); if (key == null) throw new IllegalArgumentException("key is null"); @@ -1057,13 +1083,15 @@ public class AccountManager { * * <p>It is safe to call this method from the main thread. * - * <p>This method requires the caller to have a signature match with the - * authenticator that manages the specified account. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} + * and to have the same UID as the account's authenticator. * * @param account The account to set an auth token for * @param authTokenType The type of the auth token, see {#getAuthToken} * @param authToken The auth token to add to the cache */ + @RequiresPermission(AUTHENTICATE_ACCOUNTS) public void setAuthToken(Account account, final String authTokenType, final String authToken) { if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); @@ -1082,6 +1110,9 @@ public class AccountManager { * <p>This method may block while a network request completes, and must * never be made from the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()} * @param notifyAuthFailure If true, display a notification and return null @@ -1095,6 +1126,7 @@ public class AccountManager { * @throws java.io.IOException if the authenticator experienced an I/O problem * creating a new auth token, usually because of network trouble */ + @RequiresPermission(USE_CREDENTIALS) public String blockingGetAuthToken(Account account, String authTokenType, boolean notifyAuthFailure) throws OperationCanceledException, IOException, AuthenticatorException { @@ -1133,6 +1165,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1166,6 +1201,7 @@ public class AccountManager { * authenticator-dependent. The caller should verify the validity of the * account before requesting an auth token. */ + @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle options, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { @@ -1217,6 +1253,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1253,6 +1292,7 @@ public class AccountManager { * boolean, AccountManagerCallback, android.os.Handler)} instead */ @Deprecated + @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final boolean notifyAuthFailure, @@ -1293,6 +1333,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#USE_CREDENTIALS}. + * * @param account The account to fetch an auth token for * @param authTokenType The auth token type, an authenticator-dependent * string token, must not be null @@ -1328,6 +1371,7 @@ public class AccountManager { * authenticator-dependent. The caller should verify the validity of the * account before requesting an auth token. */ + @RequiresPermission(USE_CREDENTIALS) public AccountManagerFuture<Bundle> getAuthToken( final Account account, final String authTokenType, final Bundle options, final boolean notifyAuthFailure, @@ -1357,6 +1401,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * * @param accountType The type of account to add; must not be null * @param authTokenType The type of auth token (see {@link #getAuthToken}) * this account will need to be able to generate, null for none @@ -1394,6 +1441,7 @@ public class AccountManager { * creating a new account, usually because of network trouble * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, @@ -1538,6 +1586,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * * @param account The account to confirm password knowledge for * @param options Authenticator-specific options for the request; * if the {@link #KEY_PASSWORD} string field is present, the @@ -1564,11 +1615,11 @@ public class AccountManager { * If no activity or password was specified, the returned Bundle contains * {@link #KEY_INTENT} with the {@link Intent} needed to launch the * password prompt. - * + * * <p>Also the returning Bundle may contain {@link * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the * credential was validated/created. - * + * * If an error occurred,{@link AccountManagerFuture#getResult()} throws: * <ul> * <li> {@link AuthenticatorException} if the authenticator failed to respond @@ -1578,6 +1629,7 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> confirmCredentials(final Account account, final Bundle options, final Activity activity, @@ -1616,6 +1668,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * * @param account The account to update credentials for * @param authTokenType The credentials entered must allow an auth token * of this type to be created (but no actual auth token is returned); @@ -1651,6 +1706,7 @@ public class AccountManager { * verifying the password, usually because of network trouble * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> updateCredentials(final Account account, final String authTokenType, final Bundle options, final Activity activity, @@ -1673,8 +1729,8 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * - * <p>This method requires the caller to have the same signature as the - * authenticator associated with the specified account type. + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. * * @param accountType The account type associated with the authenticator * to adjust @@ -1702,6 +1758,7 @@ public class AccountManager { * updating settings, usually because of network trouble * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> editProperties(final String accountType, final Activity activity, final AccountManagerCallback<Bundle> callback, final Handler handler) { @@ -2196,6 +2253,9 @@ public class AccountManager { * <p>This method may be called from any thread, but the returned * {@link AccountManagerFuture} must not be used on the main thread. * + * <p>This method requires the caller to hold the permission + * {@link android.Manifest.permission#MANAGE_ACCOUNTS}. + * * @param accountType The account type required * (see {@link #getAccountsByType}), must not be null * @param authTokenType The desired auth token type @@ -2232,6 +2292,7 @@ public class AccountManager { * updating settings, usually because of network trouble * </ul> */ + @RequiresPermission(MANAGE_ACCOUNTS) public AccountManagerFuture<Bundle> getAuthTokenByFeatures( final String accountType, final String authTokenType, final String[] features, final Activity activity, final Bundle addAccountOptions, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a16a2f4..54123f5 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -980,11 +980,33 @@ <!-- Allows access to the list of accounts in the Accounts Service --> <permission android:name="android.permission.GET_ACCOUNTS" - android:permissionGroup="android.permission-group.CONTACTS" + android:permissionGroup="android.permission-group.ACCOUNTS" android:protectionLevel="normal" android:description="@string/permdesc_getAccounts" android:label="@string/permlab_getAccounts" /> + <!-- Allows an application to act as an AccountAuthenticator for + the AccountManager --> + <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" + android:permissionGroup="android.permission-group.ACCOUNTS" + android:protectionLevel="dangerous" + android:label="@string/permlab_authenticateAccounts" + android:description="@string/permdesc_authenticateAccounts" /> + + <!-- Allows an application to request authtokens from the AccountManager --> + <permission android:name="android.permission.USE_CREDENTIALS" + android:permissionGroup="android.permission-group.ACCOUNTS" + android:protectionLevel="dangerous" + android:label="@string/permlab_useCredentials" + android:description="@string/permdesc_useCredentials" /> + + <!-- Allows an application to manage the list of accounts in the AccountManager --> + <permission android:name="android.permission.MANAGE_ACCOUNTS" + android:permissionGroup="android.permission-group.ACCOUNTS" + android:protectionLevel="dangerous" + android:label="@string/permlab_manageAccounts" + android:description="@string/permdesc_manageAccounts" /> + <!-- @SystemApi Allows applications to call into AccountAuthenticators. <p>Not for use by third-party applications. --> <permission android:name="android.permission.ACCOUNT_MANAGER" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f6af19c..675d3e2 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1113,6 +1113,27 @@ the list of accounts known by the phone. This may include any accounts created by applications you have installed.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_authenticateAccounts">create accounts and set passwords</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_authenticateAccounts">Allows the app + to use the account authenticator capabilities of the + AccountManager, including creating accounts and getting and + setting their passwords.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_manageAccounts">add or remove accounts</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_manageAccounts">Allows the app to + perform operations like adding and removing accounts, and deleting + their password.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_useCredentials">use accounts on the device</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_useCredentials">Allows the app to request authentication tokens.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_accessNetworkState">view network connections</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd index 9bd17ba..b13ce07 100644 --- a/docs/html/training/sync-adapters/creating-sync-adapter.jd +++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd @@ -583,6 +583,13 @@ public class MainActivity extends FragmentActivity { running the sync adapter, see <a href="running-sync-adapter.html" >Running A Sync Adapter</a>. </dd> + <dt> +{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS} + </dt> + <dd> + Allows you to use the authenticator component you created in the lesson + <a href="creating-authenticator.html">Creating a Stub Authenticator</a>. + </dd> </dl> <p> The following snippet shows how to add the permissions: diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 49d9988..21f96c9 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -87,8 +87,11 @@ import java.io.File; import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; @@ -97,6 +100,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @@ -522,20 +526,14 @@ public class AccountManagerService @Override public String getPassword(Account account) { - int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "getPassword: " + account + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot get secrets for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); + UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -619,21 +617,15 @@ public class AccountManagerService @Override public String getUserData(Account account, String key) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { - String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s", - account, key, callingUid, Binder.getCallingPid()); - Log.v(TAG, msg); + Log.v(TAG, "getUserData: " + account + + ", key " + key + + ", caller's uid " + Binder.getCallingUid() + + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); if (key == null) throw new IllegalArgumentException("key is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot get user data for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -684,20 +676,13 @@ public class AccountManagerService @Override public boolean addAccountExplicitly(Account account, String password, Bundle extras) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "addAccountExplicitly: " + account - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot explicitly add accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); /* * Child users are not allowed to add accounts. Only the accounts that are * shared by the parent profile can be added to child profile. @@ -773,24 +758,10 @@ public class AccountManagerService @Override public boolean accountAuthenticated(final Account account) { - final int callingUid = Binder.getCallingUid(); - if (Log.isLoggable(TAG, Log.VERBOSE)) { - String msg = String.format( - "accountAuthenticated( account: %s, callerUid: %s)", - account, - callingUid); - Log.v(TAG, msg); - } if (account == null) { throw new IllegalArgumentException("account is null"); } - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot notify authentication for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); int userId = Binder.getCallingUserHandle().getIdentifier(); if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) { return false; @@ -1036,21 +1007,16 @@ public class AccountManagerService @Override public void renameAccount( IAccountManagerResponse response, Account accountToRename, String newName) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (accountToRename == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(accountToRename.type, callingUid)) { - String msg = String.format( - "uid %s cannot rename accounts of type: %s", - callingUid, - accountToRename.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(accountToRename); UserAccounts accounts = getUserAccountsForCaller(); + + int callingUid = getCallingUid(); long identityToken = clearCallingIdentity(); try { Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName, @@ -1159,21 +1125,65 @@ public class AccountManagerService @Override public void removeAccount(IAccountManagerResponse response, Account account, boolean expectActivityLaunch) { - removeAccountAsUser( - response, - account, - expectActivityLaunch, - UserHandle.getCallingUserId()); + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "removeAccount: " + account + + ", response " + response + + ", caller's uid " + Binder.getCallingUid() + + ", pid " + Binder.getCallingPid()); + } + if (response == null) throw new IllegalArgumentException("response is null"); + if (account == null) throw new IllegalArgumentException("account is null"); + checkManageAccountsPermission(); + UserHandle user = Binder.getCallingUserHandle(); + UserAccounts accounts = getUserAccountsForCaller(); + int userId = Binder.getCallingUserHandle().getIdentifier(); + if (!canUserModifyAccounts(userId)) { + try { + // TODO: This should be ERROR_CODE_USER_RESTRICTED instead. See http://b/16322768 + response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, + "User cannot modify accounts"); + } catch (RemoteException re) { + } + return; + } + if (!canUserModifyAccountsForType(userId, account.type)) { + try { + response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, + "User cannot modify accounts of this type (policy)."); + } catch (RemoteException re) { + } + return; + } + + long identityToken = clearCallingIdentity(); + + cancelNotification(getSigninRequiredNotificationId(accounts, account), user); + synchronized (accounts.credentialsPermissionNotificationIds) { + for (Pair<Pair<Account, String>, Integer> pair: + accounts.credentialsPermissionNotificationIds.keySet()) { + if (account.equals(pair.first.first)) { + int id = accounts.credentialsPermissionNotificationIds.get(pair); + cancelNotification(id, user); + } + } + } + + logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS); + + try { + new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind(); + } finally { + restoreCallingIdentity(identityToken); + } } @Override public void removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "removeAccount: " + account + ", response " + response - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid() + ", for user id " + userId); } @@ -1183,18 +1193,7 @@ public class AccountManagerService // Only allow the system process to modify accounts of other users enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId() + " trying to remove account for " + userId); - /* - * Only the system or authenticator should be allowed to remove accounts for that - * authenticator. This will let users remove accounts (via Settings in the system) but not - * arbitrary applications (like competing authenticators). - */ - if (!isAccountOwnedByCallingUid(account.type, callingUid) && !isSystemUid(callingUid)) { - String msg = String.format( - "uid %s cannot remove accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkManageAccountsPermission(); UserAccounts accounts = getUserAccounts(userId); if (!canUserModifyAccounts(userId)) { @@ -1239,26 +1238,13 @@ public class AccountManagerService @Override public boolean removeAccountExplicitly(Account account) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "removeAccountExplicitly: " + account - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } - if (account == null) { - /* - * Null accounts should result in returning false, as per - * AccountManage.addAccountExplicitly(...) java doc. - */ - Log.e(TAG, "account is null"); - return false; - } else if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot explicitly add accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + if (account == null) throw new IllegalArgumentException("account is null"); + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); int userId = Binder.getCallingUserHandle().getIdentifier(); @@ -1371,6 +1357,7 @@ public class AccountManagerService } if (accountType == null) throw new IllegalArgumentException("accountType is null"); if (authToken == null) throw new IllegalArgumentException("authToken is null"); + checkManageAccountsOrUseCredentialsPermissions(); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -1503,22 +1490,15 @@ public class AccountManagerService @Override public String peekAuthToken(Account account, String authTokenType) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "peekAuthToken: " + account + ", authTokenType " + authTokenType - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot peek the authtokens associated with accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -1530,22 +1510,15 @@ public class AccountManagerService @Override public void setAuthToken(Account account, String authTokenType, String authToken) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "setAuthToken: " + account + ", authTokenType " + authTokenType - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot set auth tokens associated with accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -1557,21 +1530,15 @@ public class AccountManagerService @Override public void setPassword(Account account, String password) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "setAuthToken: " + account - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot set secrets for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); + int callingUid = getCallingUid(); long identityToken = clearCallingIdentity(); try { setPasswordInternal(accounts, account, password, callingUid); @@ -1627,21 +1594,16 @@ public class AccountManagerService @Override public void clearPassword(Account account) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "clearPassword: " + account - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (account == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot clear passwords for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkManageAccountsPermission(); UserAccounts accounts = getUserAccountsForCaller(); + + int callingUid = getCallingUid(); long identityToken = clearCallingIdentity(); try { setPasswordInternal(accounts, account, null, callingUid); @@ -1652,22 +1614,15 @@ public class AccountManagerService @Override public void setUserData(Account account, String key, String value) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "setUserData: " + account + ", key " + key - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (key == null) throw new IllegalArgumentException("key is null"); if (account == null) throw new IllegalArgumentException("account is null"); - if (!isAccountOwnedByCallingUid(account.type, callingUid)) { - String msg = String.format( - "uid %s cannot set user data for accounts of type: %s", - callingUid, - account.type); - throw new SecurityException(msg); - } + checkAuthenticateAccountsPermission(account); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -1814,6 +1769,7 @@ public class AccountManagerService return; } + checkBinderPermission(Manifest.permission.USE_CREDENTIALS); final UserAccounts accounts = getUserAccountsForCaller(); final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo; authenticatorInfo = mAuthenticatorCache.getServiceInfo( @@ -2091,6 +2047,7 @@ public class AccountManagerService } if (response == null) throw new IllegalArgumentException("response is null"); if (accountType == null) throw new IllegalArgumentException("accountType is null"); + checkManageAccountsPermission(); // Is user disallowed from modifying accounts? int userId = Binder.getCallingUserHandle().getIdentifier(); @@ -2165,6 +2122,7 @@ public class AccountManagerService } if (response == null) throw new IllegalArgumentException("response is null"); if (accountType == null) throw new IllegalArgumentException("accountType is null"); + checkManageAccountsPermission(); // Only allow the system process to add accounts of other users enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId() @@ -2255,6 +2213,7 @@ public class AccountManagerService } if (response == null) throw new IllegalArgumentException("response is null"); if (account == null) throw new IllegalArgumentException("account is null"); + checkManageAccountsPermission(); UserAccounts accounts = getUserAccounts(userId); long identityToken = clearCallingIdentity(); try { @@ -2291,6 +2250,7 @@ public class AccountManagerService if (response == null) throw new IllegalArgumentException("response is null"); if (account == null) throw new IllegalArgumentException("account is null"); if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null"); + checkManageAccountsPermission(); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -2318,23 +2278,16 @@ public class AccountManagerService @Override public void editProperties(IAccountManagerResponse response, final String accountType, final boolean expectActivityLaunch) { - final int callingUid = Binder.getCallingUid(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "editProperties: accountType " + accountType + ", response " + response + ", expectActivityLaunch " + expectActivityLaunch - + ", caller's uid " + callingUid + + ", caller's uid " + Binder.getCallingUid() + ", pid " + Binder.getCallingPid()); } if (response == null) throw new IllegalArgumentException("response is null"); if (accountType == null) throw new IllegalArgumentException("accountType is null"); - if (!isAccountOwnedByCallingUid(accountType, callingUid) && !isSystemUid(callingUid)) { - String msg = String.format( - "uid %s cannot edit authenticator properites for account type: %s", - callingUid, - accountType); - throw new SecurityException(msg); - } + checkManageAccountsPermission(); UserAccounts accounts = getUserAccountsForCaller(); long identityToken = clearCallingIdentity(); try { @@ -3635,7 +3588,7 @@ public class AccountManagerService private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) { final boolean isPrivileged = isPrivileged(callerUid); final boolean fromAuthenticator = account != null - && isAccountManagedByCaller(account.type, callerUid); + && hasAuthenticatorUid(account.type, callerUid); final boolean hasExplicitGrants = account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid); if (Log.isLoggable(TAG, Log.VERBOSE)) { @@ -3647,17 +3600,14 @@ public class AccountManagerService return fromAuthenticator || hasExplicitGrants || isPrivileged; } - private boolean isAccountManagedByCaller(String accountType, int callingUid) { + private boolean hasAuthenticatorUid(String accountType, int callingUid) { final int callingUserId = UserHandle.getUserId(callingUid); for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo : mAuthenticatorCache.getAllServices(callingUserId)) { if (serviceInfo.type.type.equals(accountType)) { - /* - * We can't simply compare uids because uids can be recycled before the - * authenticator cache is updated. - */ - final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid); - return sigChk == PackageManager.SIGNATURE_MATCH; + return (serviceInfo.uid == callingUid) || + (mPackageManager.checkSignatures(serviceInfo.uid, callingUid) + == PackageManager.SIGNATURE_MATCH); } } return false; @@ -3698,49 +3648,36 @@ public class AccountManagerService } } - private boolean isSystemUid(int callingUid) { - String[] packages = null; - long ident = Binder.clearCallingIdentity(); - try { - packages = mPackageManager.getPackagesForUid(callingUid); - } finally { - Binder.restoreCallingIdentity(ident); - } - if (packages != null) { - for (String name : packages) { - try { - PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */); - if (packageInfo != null - && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) - != 0) { - return true; - } - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, String.format("Could not find package [%s]", name), e); - } - } - } else { - Log.w(TAG, "No known packages with uid " + callingUid); - } - return false; - } - - private boolean isAccountOwnedByCallingUid(String accountType, int callingUid) { - if (!isAccountManagedByCaller(accountType, callingUid)) { - String msg = "caller uid " + callingUid + " is different than the authenticator's uid"; + private void checkCallingUidAgainstAuthenticator(Account account) { + final int uid = Binder.getCallingUid(); + if (account == null || !hasAuthenticatorUid(account.type, uid)) { + String msg = "caller uid " + uid + " is different than the authenticator's uid"; Log.w(TAG, msg); - return false; + throw new SecurityException(msg); } if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.v(TAG, "caller uid " + callingUid + " is the same as the authenticator's uid"); + Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid"); } - return true; + } + + private void checkAuthenticateAccountsPermission(Account account) { + checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS); + checkCallingUidAgainstAuthenticator(account); } private void checkReadAccountsPermission() { checkBinderPermission(Manifest.permission.GET_ACCOUNTS); } + private void checkManageAccountsPermission() { + checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS); + } + + private void checkManageAccountsOrUseCredentialsPermissions() { + checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS, + Manifest.permission.USE_CREDENTIALS); + } + private boolean canUserModifyAccounts(int userId) { if (getUserManager().getUserRestrictions(new UserHandle(userId)) .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { |