am 4d2eec14: am df5a6611: Merge "Revert "Revert "Permissions: GET_ACCOUNTS permission cleanup""" into mnc-dev
* commit '4d2eec1434f08667999b9cc51e6cf6f7146003e5': Revert "Revert "Permissions: GET_ACCOUNTS permission cleanup""
This commit is contained in:
@@ -138,7 +138,9 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
new AccountAuthenticatorResponse(response),
|
new AccountAuthenticatorResponse(response),
|
||||||
accountType, authTokenType, features, options);
|
accountType, authTokenType, features, options);
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
result.keySet(); // force it to be unparcelled
|
if (result != null) {
|
||||||
|
result.keySet(); // force it to be unparcelled
|
||||||
|
}
|
||||||
Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
|
Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -160,7 +162,9 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
|
final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
|
||||||
new AccountAuthenticatorResponse(response), account, options);
|
new AccountAuthenticatorResponse(response), account, options);
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
result.keySet(); // force it to be unparcelled
|
if (result != null) {
|
||||||
|
result.keySet(); // force it to be unparcelled
|
||||||
|
}
|
||||||
Log.v(TAG, "confirmCredentials: result "
|
Log.v(TAG, "confirmCredentials: result "
|
||||||
+ AccountManager.sanitizeResult(result));
|
+ AccountManager.sanitizeResult(result));
|
||||||
}
|
}
|
||||||
@@ -185,7 +189,9 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
|
result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
|
||||||
AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
|
AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
result.keySet(); // force it to be unparcelled
|
if (result != null) {
|
||||||
|
result.keySet(); // force it to be unparcelled
|
||||||
|
}
|
||||||
Log.v(TAG, "getAuthTokenLabel: result "
|
Log.v(TAG, "getAuthTokenLabel: result "
|
||||||
+ AccountManager.sanitizeResult(result));
|
+ AccountManager.sanitizeResult(result));
|
||||||
}
|
}
|
||||||
@@ -209,7 +215,9 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
new AccountAuthenticatorResponse(response), account,
|
new AccountAuthenticatorResponse(response), account,
|
||||||
authTokenType, loginOptions);
|
authTokenType, loginOptions);
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
result.keySet(); // force it to be unparcelled
|
if (result != null) {
|
||||||
|
result.keySet(); // force it to be unparcelled
|
||||||
|
}
|
||||||
Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
|
Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
|
||||||
}
|
}
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -234,7 +242,10 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
new AccountAuthenticatorResponse(response), account,
|
new AccountAuthenticatorResponse(response), account,
|
||||||
authTokenType, loginOptions);
|
authTokenType, loginOptions);
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
result.keySet(); // force it to be unparcelled
|
// Result may be null.
|
||||||
|
if (result != null) {
|
||||||
|
result.keySet(); // force it to be unparcelled
|
||||||
|
}
|
||||||
Log.v(TAG, "updateCredentials: result "
|
Log.v(TAG, "updateCredentials: result "
|
||||||
+ AccountManager.sanitizeResult(result));
|
+ AccountManager.sanitizeResult(result));
|
||||||
}
|
}
|
||||||
@@ -490,7 +501,7 @@ public abstract class AbstractAccountAuthenticator {
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li> {@link AccountManager#KEY_INTENT}, or
|
* <li> {@link AccountManager#KEY_INTENT}, or
|
||||||
* <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
|
* <li> {@link AccountManager#KEY_ACCOUNT_NAME} and {@link AccountManager#KEY_ACCOUNT_TYPE} of
|
||||||
* the account that was added, or
|
* the account whose credentials were updated, or
|
||||||
* <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
|
* <li> {@link AccountManager#KEY_ERROR_CODE} and {@link AccountManager#KEY_ERROR_MESSAGE} to
|
||||||
* indicate an error
|
* indicate an error
|
||||||
* </ul>
|
* </ul>
|
||||||
|
|||||||
@@ -333,7 +333,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.getPassword(account);
|
return mService.getPassword(account);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// will never happen
|
// won't ever happen
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -362,7 +362,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.getUserData(account, key);
|
return mService.getUserData(account, key);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// will never happen
|
// won't ever happen
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,8 +415,10 @@ public class AccountManager {
|
|||||||
*
|
*
|
||||||
* <p>It is safe to call this method from the main thread.
|
* <p>It is safe to call this method from the main thread.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>Clients of this method that have not been granted the
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS}.
|
* {@link android.Manifest.permission#GET_ACCOUNTS} permission,
|
||||||
|
* will only see those accounts managed by AbstractAccountAuthenticators whose
|
||||||
|
* signature matches the client.
|
||||||
*
|
*
|
||||||
* @return An array of {@link Account}, one for each account. Empty
|
* @return An array of {@link Account}, one for each account. Empty
|
||||||
* (never null) if no accounts have been added.
|
* (never null) if no accounts have been added.
|
||||||
@@ -438,8 +440,10 @@ public class AccountManager {
|
|||||||
*
|
*
|
||||||
* <p>It is safe to call this method from the main thread.
|
* <p>It is safe to call this method from the main thread.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>Clients of this method that have not been granted the
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS}.
|
* {@link android.Manifest.permission#GET_ACCOUNTS} permission,
|
||||||
|
* will only see those accounts managed by AbstractAccountAuthenticators whose
|
||||||
|
* signature matches the client.
|
||||||
*
|
*
|
||||||
* @return An array of {@link Account}, one for each account. Empty
|
* @return An array of {@link Account}, one for each account. Empty
|
||||||
* (never null) if no accounts have been added.
|
* (never null) if no accounts have been added.
|
||||||
@@ -466,7 +470,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.getAccountsForPackage(packageName, uid);
|
return mService.getAccountsForPackage(packageName, uid);
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
// possible security exception
|
// won't ever happen
|
||||||
throw new RuntimeException(re);
|
throw new RuntimeException(re);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -483,7 +487,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.getAccountsByTypeForPackage(type, packageName);
|
return mService.getAccountsByTypeForPackage(type, packageName);
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
// possible security exception
|
// won't ever happen
|
||||||
throw new RuntimeException(re);
|
throw new RuntimeException(re);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,9 +501,10 @@ public class AccountManager {
|
|||||||
*
|
*
|
||||||
* <p>It is safe to call this method from the main thread.
|
* <p>It is safe to call this method from the main thread.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>Clients of this method that have not been granted the
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
|
* {@link android.Manifest.permission#GET_ACCOUNTS} permission,
|
||||||
* authenticator that owns the account type.
|
* will only see those accounts managed by AbstractAccountAuthenticators whose
|
||||||
|
* signature matches the client.
|
||||||
*
|
*
|
||||||
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
|
* <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
|
||||||
* GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
|
* GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
|
||||||
@@ -585,7 +590,8 @@ public class AccountManager {
|
|||||||
* {@link AccountManagerFuture} must not be used on the main thread.
|
* {@link AccountManagerFuture} must not be used on the main thread.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>This method requires the caller to hold the permission
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS}.
|
* {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
|
||||||
|
* match with the AbstractAccountAuthenticator that manages the account.
|
||||||
*
|
*
|
||||||
* @param account The {@link Account} to test
|
* @param account The {@link Account} to test
|
||||||
* @param features An array of the account features to check
|
* @param features An array of the account features to check
|
||||||
@@ -628,9 +634,10 @@ public class AccountManager {
|
|||||||
* <p>This method may be called from any thread, but the returned
|
* <p>This method may be called from any thread, but the returned
|
||||||
* {@link AccountManagerFuture} must not be used on the main thread.
|
* {@link AccountManagerFuture} must not be used on the main thread.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>Clients of this method that have not been granted the
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS} or share a uid with the
|
* {@link android.Manifest.permission#GET_ACCOUNTS} permission,
|
||||||
* authenticator that owns the account type.
|
* will only see those accounts managed by AbstractAccountAuthenticators whose
|
||||||
|
* signature matches the client.
|
||||||
*
|
*
|
||||||
* @param type The type of accounts to return, must not be null
|
* @param type The type of accounts to return, must not be null
|
||||||
* @param features An array of the account features to require,
|
* @param features An array of the account features to require,
|
||||||
@@ -701,7 +708,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.addAccountExplicitly(account, password, userdata);
|
return mService.addAccountExplicitly(account, password, userdata);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// won't ever happen
|
// Can happen if there was a SecurityException was thrown.
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -966,7 +973,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
return mService.removeAccountExplicitly(account);
|
return mService.removeAccountExplicitly(account);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// won't ever happen
|
// May happen if the caller doesn't match the signature of the authenticator.
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1114,7 +1121,7 @@ public class AccountManager {
|
|||||||
try {
|
try {
|
||||||
mService.setUserData(account, key, value);
|
mService.setUserData(account, key, value);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
// won't ever happen
|
// Will happen if there is not signature match.
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1733,7 +1740,7 @@ public class AccountManager {
|
|||||||
* with these fields if an activity was supplied and the account
|
* with these fields if an activity was supplied and the account
|
||||||
* credentials were successfully updated:
|
* credentials were successfully updated:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
|
* <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
|
||||||
* <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
|
* <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@@ -2501,10 +2508,12 @@ public class AccountManager {
|
|||||||
* listeners are added in an Activity or Service's {@link Activity#onCreate}
|
* listeners are added in an Activity or Service's {@link Activity#onCreate}
|
||||||
* and removed in {@link Activity#onDestroy}.
|
* and removed in {@link Activity#onDestroy}.
|
||||||
*
|
*
|
||||||
* <p>It is safe to call this method from the main thread.
|
* <p>The listener will only be informed of accounts that would be returned
|
||||||
|
* to the caller via {@link #getAccounts()}. Typically this means that to
|
||||||
|
* get any accounts, the caller will need to be grated the GET_ACCOUNTS
|
||||||
|
* permission.
|
||||||
*
|
*
|
||||||
* <p>This method requires the caller to hold the permission
|
* <p>It is safe to call this method from the main thread.
|
||||||
* {@link android.Manifest.permission#GET_ACCOUNTS}.
|
|
||||||
*
|
*
|
||||||
* @param listener The listener to send notifications to
|
* @param listener The listener to send notifications to
|
||||||
* @param handler {@link Handler} identifying the thread to use
|
* @param handler {@link Handler} identifying the thread to use
|
||||||
|
|||||||
@@ -527,14 +527,14 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot get secrets for accounts of type: %s",
|
"uid %s cannot get secrets for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -627,14 +627,14 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (key == null) throw new IllegalArgumentException("key is null");
|
if (key == null) throw new IllegalArgumentException("key is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot get user data for accounts of type: %s",
|
"uid %s cannot get user data for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -664,22 +664,32 @@ public class AccountManagerService
|
|||||||
|
|
||||||
final long identityToken = clearCallingIdentity();
|
final long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
|
return getAuthenticatorTypesInternal(userId);
|
||||||
authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
|
|
||||||
AuthenticatorDescription[] types =
|
|
||||||
new AuthenticatorDescription[authenticatorCollection.size()];
|
|
||||||
int i = 0;
|
|
||||||
for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
|
|
||||||
: authenticatorCollection) {
|
|
||||||
types[i] = authenticator.type;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return types;
|
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should only be called inside of a clearCallingIdentity block.
|
||||||
|
*/
|
||||||
|
private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId) {
|
||||||
|
Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
|
||||||
|
authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
|
||||||
|
AuthenticatorDescription[] types =
|
||||||
|
new AuthenticatorDescription[authenticatorCollection.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
|
||||||
|
: authenticatorCollection) {
|
||||||
|
types[i] = authenticator.type;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private boolean isCrossUser(int callingUid, int userId) {
|
private boolean isCrossUser(int callingUid, int userId) {
|
||||||
return (userId != UserHandle.getCallingUserId()
|
return (userId != UserHandle.getCallingUserId()
|
||||||
&& callingUid != Process.myUid()
|
&& callingUid != Process.myUid()
|
||||||
@@ -697,7 +707,8 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot explicitly add accounts of type: %s",
|
"uid %s cannot explicitly add accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
@@ -713,12 +724,10 @@ public class AccountManagerService
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// fails if the account already exists
|
// fails if the account already exists
|
||||||
int uid = getCallingUid();
|
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
return addAccountInternal(accounts, account, password, extras, false, uid);
|
return addAccountInternal(accounts, account, password, extras, false, callingUid);
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
}
|
}
|
||||||
@@ -794,25 +803,26 @@ public class AccountManagerService
|
|||||||
if (account == null) {
|
if (account == null) {
|
||||||
throw new IllegalArgumentException("account is null");
|
throw new IllegalArgumentException("account is null");
|
||||||
}
|
}
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot notify authentication for accounts of type: %s",
|
"uid %s cannot notify authentication for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = Binder.getCallingUserHandle().getIdentifier();
|
|
||||||
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
|
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int user = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(user);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
|
return updateLastAuthenticatedTime(account);
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
}
|
}
|
||||||
return updateLastAuthenticatedTime(account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateLastAuthenticatedTime(Account account) {
|
private boolean updateLastAuthenticatedTime(Account account) {
|
||||||
@@ -985,8 +995,9 @@ public class AccountManagerService
|
|||||||
if (response == null) throw new IllegalArgumentException("response is null");
|
if (response == null) throw new IllegalArgumentException("response is null");
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (features == null) throw new IllegalArgumentException("features is null");
|
if (features == null) throw new IllegalArgumentException("features is null");
|
||||||
checkReadAccountsPermitted(callingUid, account.type);
|
|
||||||
int userId = UserHandle.getCallingUserId();
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
checkReadAccountsPermitted(callingUid, account.type, userId);
|
||||||
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1062,14 +1073,14 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (accountToRename == null) throw new IllegalArgumentException("account is null");
|
if (accountToRename == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(accountToRename.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot rename accounts of type: %s",
|
"uid %s cannot rename accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
accountToRename.type);
|
accountToRename.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1211,14 +1222,15 @@ public class AccountManagerService
|
|||||||
* authenticator. This will let users remove accounts (via Settings in the system) but not
|
* authenticator. This will let users remove accounts (via Settings in the system) but not
|
||||||
* arbitrary applications (like competing authenticators).
|
* arbitrary applications (like competing authenticators).
|
||||||
*/
|
*/
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid) && !isSystemUid(callingUid)) {
|
UserHandle user = new UserHandle(userId);
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier())
|
||||||
|
&& !isSystemUid(callingUid)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot remove accounts of type: %s",
|
"uid %s cannot remove accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canUserModifyAccounts(userId)) {
|
if (!canUserModifyAccounts(userId)) {
|
||||||
try {
|
try {
|
||||||
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
|
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
|
||||||
@@ -1235,10 +1247,7 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserHandle user = new UserHandle(userId);
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
|
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
|
cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
|
||||||
synchronized(accounts.credentialsPermissionNotificationIds) {
|
synchronized(accounts.credentialsPermissionNotificationIds) {
|
||||||
@@ -1268,6 +1277,7 @@ public class AccountManagerService
|
|||||||
+ ", caller's uid " + callingUid
|
+ ", caller's uid " + callingUid
|
||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
|
int userId = Binder.getCallingUserHandle().getIdentifier();
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
/*
|
/*
|
||||||
* Null accounts should result in returning false, as per
|
* Null accounts should result in returning false, as per
|
||||||
@@ -1275,22 +1285,18 @@ public class AccountManagerService
|
|||||||
*/
|
*/
|
||||||
Log.e(TAG, "account is null");
|
Log.e(TAG, "account is null");
|
||||||
return false;
|
return false;
|
||||||
} else if (!isAccountManagedByCaller(account.type, callingUid)) {
|
} else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot explicitly add accounts of type: %s",
|
"uid %s cannot explicitly add accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserAccounts accounts = getUserAccountsForCaller();
|
UserAccounts accounts = getUserAccountsForCaller();
|
||||||
int userId = Binder.getCallingUserHandle().getIdentifier();
|
|
||||||
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
|
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
|
logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
|
||||||
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
return removeAccountInternal(accounts, account);
|
return removeAccountInternal(accounts, account);
|
||||||
@@ -1524,14 +1530,14 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
|
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot peek the authtokens associated with accounts of type: %s",
|
"uid %s cannot peek the authtokens associated with accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1552,14 +1558,14 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
|
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot set auth tokens associated with accounts of type: %s",
|
"uid %s cannot set auth tokens associated with accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1578,14 +1584,14 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot set secrets for accounts of type: %s",
|
"uid %s cannot set secrets for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1642,14 +1648,14 @@ public class AccountManagerService
|
|||||||
+ ", pid " + Binder.getCallingPid());
|
+ ", pid " + Binder.getCallingPid());
|
||||||
}
|
}
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot clear passwords for accounts of type: %s",
|
"uid %s cannot clear passwords for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1670,14 +1676,14 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (key == null) throw new IllegalArgumentException("key is null");
|
if (key == null) throw new IllegalArgumentException("key is null");
|
||||||
if (account == null) throw new IllegalArgumentException("account is null");
|
if (account == null) throw new IllegalArgumentException("account is null");
|
||||||
if (!isAccountManagedByCaller(account.type, callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot set user data for accounts of type: %s",
|
"uid %s cannot set user data for accounts of type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
account.type);
|
account.type);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -1840,8 +1846,8 @@ public class AccountManagerService
|
|||||||
|
|
||||||
// skip the check if customTokens
|
// skip the check if customTokens
|
||||||
final int callerUid = Binder.getCallingUid();
|
final int callerUid = Binder.getCallingUid();
|
||||||
final boolean permissionGranted = customTokens ||
|
final boolean permissionGranted =
|
||||||
permissionIsGranted(account, authTokenType, callerUid);
|
customTokens || permissionIsGranted(account, authTokenType, callerUid, userId);
|
||||||
|
|
||||||
// Get the calling package. We will use it for the purpose of caching.
|
// Get the calling package. We will use it for the purpose of caching.
|
||||||
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
|
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
|
||||||
@@ -2363,14 +2369,14 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (response == null) throw new IllegalArgumentException("response is null");
|
if (response == null) throw new IllegalArgumentException("response is null");
|
||||||
if (accountType == null) throw new IllegalArgumentException("accountType is null");
|
if (accountType == null) throw new IllegalArgumentException("accountType is null");
|
||||||
if (!isAccountManagedByCaller(accountType, callingUid) && !isSystemUid(callingUid)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
if (!isAccountManagedByCaller(accountType, callingUid, userId) && !isSystemUid(callingUid)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"uid %s cannot edit authenticator properites for account type: %s",
|
"uid %s cannot edit authenticator properites for account type: %s",
|
||||||
callingUid,
|
callingUid,
|
||||||
accountType);
|
accountType);
|
||||||
throw new SecurityException(msg);
|
throw new SecurityException(msg);
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
@@ -2493,20 +2499,22 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the accounts for a specific user
|
* Returns the accounts visible to the client within the context of a specific user
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public Account[] getAccounts(int userId) {
|
public Account[] getAccounts(int userId) {
|
||||||
int callingUid = Binder.getCallingUid();
|
int callingUid = Binder.getCallingUid();
|
||||||
if (!isReadAccountsPermitted(callingUid, null)) {
|
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
|
||||||
|
if (visibleAccountTypes.isEmpty()) {
|
||||||
return new Account[0];
|
return new Account[0];
|
||||||
}
|
}
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
return getAccountsInternal(
|
||||||
synchronized (accounts.cacheLock) {
|
userId,
|
||||||
return getAccountsFromCacheLocked(accounts, null, callingUid, null);
|
callingUid,
|
||||||
}
|
null, // packageName
|
||||||
|
visibleAccountTypes);
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
}
|
}
|
||||||
@@ -2588,22 +2596,52 @@ public class AccountManagerService
|
|||||||
callingUid = packageUid;
|
callingUid = packageUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authenticators should be able to see their own accounts regardless of permissions.
|
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
|
||||||
if (TextUtils.isEmpty(type) && !isReadAccountsPermitted(callingUid, type)) {
|
if (visibleAccountTypes.isEmpty()
|
||||||
|
|| (type != null && !visibleAccountTypes.contains(type))) {
|
||||||
return new Account[0];
|
return new Account[0];
|
||||||
}
|
} else if (visibleAccountTypes.contains(type)) {
|
||||||
|
// Prune the list down to just the requested type.
|
||||||
|
visibleAccountTypes = new ArrayList<>();
|
||||||
|
visibleAccountTypes.add(type);
|
||||||
|
} // else aggregate all the visible accounts (it won't matter if the list is empty).
|
||||||
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts accounts = getUserAccounts(userId);
|
return getAccountsInternal(
|
||||||
synchronized (accounts.cacheLock) {
|
userId,
|
||||||
return getAccountsFromCacheLocked(accounts, type, callingUid, callingPackage);
|
callingUid,
|
||||||
}
|
callingPackage,
|
||||||
|
visibleAccountTypes);
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Account[] getAccountsInternal(
|
||||||
|
int userId,
|
||||||
|
int callingUid,
|
||||||
|
String callingPackage,
|
||||||
|
List<String> visibleAccountTypes) {
|
||||||
|
UserAccounts accounts = getUserAccounts(userId);
|
||||||
|
synchronized (accounts.cacheLock) {
|
||||||
|
UserAccounts userAccounts = getUserAccounts(userId);
|
||||||
|
ArrayList<Account> visibleAccounts = new ArrayList<>();
|
||||||
|
for (String visibleType : visibleAccountTypes) {
|
||||||
|
Account[] accountsForType = getAccountsFromCacheLocked(
|
||||||
|
userAccounts, visibleType, callingUid, callingPackage);
|
||||||
|
if (accountsForType != null) {
|
||||||
|
visibleAccounts.addAll(Arrays.asList(accountsForType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Account[] result = new Account[visibleAccounts.size()];
|
||||||
|
for (int i = 0; i < visibleAccounts.size(); i++) {
|
||||||
|
result[i] = visibleAccounts.get(i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean addSharedAccountAsUser(Account account, int userId) {
|
public boolean addSharedAccountAsUser(Account account, int userId) {
|
||||||
userId = handleIncomingUser(userId);
|
userId = handleIncomingUser(userId);
|
||||||
@@ -2739,8 +2777,12 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
if (response == null) throw new IllegalArgumentException("response is null");
|
if (response == null) throw new IllegalArgumentException("response is null");
|
||||||
if (type == null) throw new IllegalArgumentException("accountType is null");
|
if (type == null) throw new IllegalArgumentException("accountType is null");
|
||||||
if (!isReadAccountsPermitted(callingUid, type)) {
|
int userId = UserHandle.getCallingUserId();
|
||||||
|
|
||||||
|
List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
|
||||||
|
if (!visibleAccountTypes.contains(type)) {
|
||||||
Bundle result = new Bundle();
|
Bundle result = new Bundle();
|
||||||
|
// Need to return just the accounts that are from matching signatures.
|
||||||
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
|
result.putParcelableArray(AccountManager.KEY_ACCOUNTS, new Account[0]);
|
||||||
try {
|
try {
|
||||||
response.onResult(result);
|
response.onResult(result);
|
||||||
@@ -2749,7 +2791,6 @@ public class AccountManagerService
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int userId = UserHandle.getCallingUserId();
|
|
||||||
long identityToken = clearCallingIdentity();
|
long identityToken = clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
UserAccounts userAccounts = getUserAccounts(userId);
|
UserAccounts userAccounts = getUserAccounts(userId);
|
||||||
@@ -2763,7 +2804,11 @@ public class AccountManagerService
|
|||||||
onResult(response, result);
|
onResult(response, result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features,
|
new GetAccountsByTypeAndFeatureSession(
|
||||||
|
userAccounts,
|
||||||
|
response,
|
||||||
|
type,
|
||||||
|
features,
|
||||||
callingUid).bind();
|
callingUid).bind();
|
||||||
} finally {
|
} finally {
|
||||||
restoreCallingIdentity(identityToken);
|
restoreCallingIdentity(identityToken);
|
||||||
@@ -3696,10 +3741,11 @@ public class AccountManagerService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
|
private boolean permissionIsGranted(
|
||||||
|
Account account, String authTokenType, int callerUid, int userId) {
|
||||||
final boolean isPrivileged = isPrivileged(callerUid);
|
final boolean isPrivileged = isPrivileged(callerUid);
|
||||||
final boolean fromAuthenticator = account != null
|
final boolean fromAuthenticator = account != null
|
||||||
&& isAccountManagedByCaller(account.type, callerUid);
|
&& isAccountManagedByCaller(account.type, callerUid, userId);
|
||||||
final boolean hasExplicitGrants = account != null
|
final boolean hasExplicitGrants = account != null
|
||||||
&& hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
|
&& hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
@@ -3711,23 +3757,45 @@ public class AccountManagerService
|
|||||||
return fromAuthenticator || hasExplicitGrants || isPrivileged;
|
return fromAuthenticator || hasExplicitGrants || isPrivileged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAccountManagedByCaller(String accountType, int callingUid) {
|
private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId) {
|
||||||
if (accountType == null) {
|
if (accountType == null) {
|
||||||
return false;
|
return false;
|
||||||
|
} else {
|
||||||
|
return getTypesVisibleToCaller(callingUid, userId).contains(accountType);
|
||||||
}
|
}
|
||||||
final int callingUserId = UserHandle.getUserId(callingUid);
|
}
|
||||||
|
|
||||||
|
private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) {
|
||||||
|
if (accountType == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return getTypesManagedByCaller(callingUid, userId).contains(accountType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getTypesVisibleToCaller(int callingUid, int userId) {
|
||||||
|
boolean isPermitted =
|
||||||
|
isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
|
||||||
|
Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
|
||||||
|
Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
|
||||||
|
return getTypesForCaller(callingUid, userId, isPermitted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getTypesManagedByCaller(int callingUid, int userId) {
|
||||||
|
return getTypesForCaller(callingUid, userId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getTypesForCaller(
|
||||||
|
int callingUid, int userId, boolean isOtherwisePermitted) {
|
||||||
|
List<String> managedAccountTypes = new ArrayList<>();
|
||||||
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
|
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
|
||||||
mAuthenticatorCache.getAllServices(callingUserId)) {
|
mAuthenticatorCache.getAllServices(userId)) {
|
||||||
if (serviceInfo.type.type.equals(accountType)) {
|
final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
|
||||||
/*
|
if (isOtherwisePermitted || sigChk == PackageManager.SIGNATURE_MATCH) {
|
||||||
* We can't simply compare uids because uids can be recycled before the
|
managedAccountTypes.add(serviceInfo.type.type);
|
||||||
* authenticator cache is updated.
|
|
||||||
*/
|
|
||||||
final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
|
|
||||||
return sigChk == PackageManager.SIGNATURE_MATCH;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return managedAccountTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAccountPresentForCaller(String accountName, String accountType) {
|
private boolean isAccountPresentForCaller(String accountName, String accountType) {
|
||||||
@@ -3792,28 +3860,12 @@ public class AccountManagerService
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isReadAccountsPermitted(int callingUid, String accountType) {
|
|
||||||
/*
|
|
||||||
* Settings app (which is in the same uid as AcocuntManagerService), apps with the
|
|
||||||
* GET_ACCOUNTS permission or authenticators that own the account type should be able to
|
|
||||||
* access accounts of the specified account.
|
|
||||||
*/
|
|
||||||
boolean isPermitted =
|
|
||||||
isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
|
|
||||||
Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
|
|
||||||
boolean isAccountManagedByCaller = isAccountManagedByCaller(accountType, callingUid);
|
|
||||||
Log.w(TAG, String.format(
|
|
||||||
"isReadAccountPermitted: isPermitted: %s, isAM: %s",
|
|
||||||
isPermitted,
|
|
||||||
isAccountManagedByCaller));
|
|
||||||
return isPermitted || isAccountManagedByCaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Succeeds if any of the specified permissions are granted. */
|
/** Succeeds if any of the specified permissions are granted. */
|
||||||
private void checkReadAccountsPermitted(
|
private void checkReadAccountsPermitted(
|
||||||
int callingUid,
|
int callingUid,
|
||||||
String accountType) {
|
String accountType,
|
||||||
if (!isReadAccountsPermitted(callingUid, accountType)) {
|
int userId) {
|
||||||
|
if (!isAccountVisibleToCaller(accountType, callingUid, userId)) {
|
||||||
String msg = String.format(
|
String msg = String.format(
|
||||||
"caller uid %s cannot access %s accounts",
|
"caller uid %s cannot access %s accounts",
|
||||||
callingUid,
|
callingUid,
|
||||||
|
|||||||
Reference in New Issue
Block a user