1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.accounts; 18 19 import android.Manifest; 20 import android.accounts.AbstractAccountAuthenticator; 21 import android.accounts.Account; 22 import android.accounts.AccountAndUser; 23 import android.accounts.AccountAuthenticatorResponse; 24 import android.accounts.AccountManager; 25 import android.accounts.AccountManagerInternal; 26 import android.accounts.AccountManagerResponse; 27 import android.accounts.AuthenticatorDescription; 28 import android.accounts.CantAddAccountActivity; 29 import android.accounts.ChooseAccountActivity; 30 import android.accounts.GrantCredentialsPermissionActivity; 31 import android.accounts.IAccountAuthenticator; 32 import android.accounts.IAccountAuthenticatorResponse; 33 import android.accounts.IAccountManager; 34 import android.accounts.IAccountManagerResponse; 35 import android.annotation.IntRange; 36 import android.annotation.NonNull; 37 import android.annotation.Nullable; 38 import android.app.ActivityManager; 39 import android.app.ActivityThread; 40 import android.app.AppOpsManager; 41 import android.app.BroadcastOptions; 42 import android.app.INotificationManager; 43 import android.app.Notification; 44 import android.app.NotificationManager; 45 import android.app.PendingIntent; 46 import android.app.admin.DevicePolicyEventLogger; 47 import android.app.admin.DevicePolicyManager; 48 import android.app.admin.DevicePolicyManagerInternal; 49 import android.app.compat.CompatChanges; 50 import android.compat.annotation.ChangeId; 51 import android.compat.annotation.EnabledAfter; 52 import android.content.BroadcastReceiver; 53 import android.content.ClipData; 54 import android.content.ComponentName; 55 import android.content.Context; 56 import android.content.Intent; 57 import android.content.IntentFilter; 58 import android.content.IntentSender; 59 import android.content.ServiceConnection; 60 import android.content.pm.ActivityInfo; 61 import android.content.pm.ApplicationInfo; 62 import android.content.pm.IPackageManager; 63 import android.content.pm.PackageInfo; 64 import android.content.pm.PackageManager; 65 import android.content.pm.PackageManager.NameNotFoundException; 66 import android.content.pm.PackageManagerInternal; 67 import android.content.pm.RegisteredServicesCache; 68 import android.content.pm.RegisteredServicesCacheListener; 69 import android.content.pm.ResolveInfo; 70 import android.content.pm.Signature; 71 import android.content.pm.SigningDetails.CertCapabilities; 72 import android.content.pm.UserInfo; 73 import android.database.Cursor; 74 import android.database.sqlite.SQLiteCantOpenDatabaseException; 75 import android.database.sqlite.SQLiteFullException; 76 import android.database.sqlite.SQLiteStatement; 77 import android.os.Binder; 78 import android.os.Build; 79 import android.os.Bundle; 80 import android.os.Environment; 81 import android.os.Handler; 82 import android.os.IBinder; 83 import android.os.Looper; 84 import android.os.Message; 85 import android.os.Parcel; 86 import android.os.Parcelable; 87 import android.os.Process; 88 import android.os.RemoteCallback; 89 import android.os.RemoteException; 90 import android.os.ResultReceiver; 91 import android.os.ShellCallback; 92 import android.os.StrictMode; 93 import android.os.SystemClock; 94 import android.os.UserHandle; 95 import android.os.UserManager; 96 import android.provider.Settings; 97 import android.stats.devicepolicy.DevicePolicyEnums; 98 import android.text.TextUtils; 99 import android.util.EventLog; 100 import android.util.Log; 101 import android.util.Pair; 102 import android.util.Slog; 103 import android.util.SparseArray; 104 import android.util.SparseBooleanArray; 105 106 import com.android.internal.R; 107 import com.android.internal.annotations.GuardedBy; 108 import com.android.internal.annotations.VisibleForTesting; 109 import com.android.internal.content.PackageMonitor; 110 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 111 import com.android.internal.notification.SystemNotificationChannels; 112 import com.android.internal.util.ArrayUtils; 113 import com.android.internal.util.DumpUtils; 114 import com.android.internal.util.IndentingPrintWriter; 115 import com.android.internal.util.Preconditions; 116 import com.android.modules.expresslog.Histogram; 117 import com.android.server.LocalServices; 118 import com.android.server.ServiceThread; 119 import com.android.server.SystemService; 120 121 import com.google.android.collect.Lists; 122 import com.google.android.collect.Sets; 123 124 import java.io.File; 125 import java.io.FileDescriptor; 126 import java.io.PrintWriter; 127 import java.security.GeneralSecurityException; 128 import java.security.MessageDigest; 129 import java.security.NoSuchAlgorithmException; 130 import java.text.SimpleDateFormat; 131 import java.util.ArrayList; 132 import java.util.Arrays; 133 import java.util.Collection; 134 import java.util.Collections; 135 import java.util.Date; 136 import java.util.HashMap; 137 import java.util.HashSet; 138 import java.util.LinkedHashMap; 139 import java.util.List; 140 import java.util.Map; 141 import java.util.Map.Entry; 142 import java.util.Objects; 143 import java.util.Set; 144 import java.util.UUID; 145 import java.util.concurrent.CopyOnWriteArrayList; 146 import java.util.concurrent.atomic.AtomicReference; 147 148 /** 149 * A system service that provides account, password, and authtoken management for all 150 * accounts on the device. Some of these calls are implemented with the help of the corresponding 151 * {@link IAccountAuthenticator} services. This service is not accessed by users directly, 152 * instead one uses an instance of {@link AccountManager}, which can be accessed as follows: 153 * AccountManager accountManager = AccountManager.get(context); 154 * @hide 155 */ 156 public class AccountManagerService 157 extends IAccountManager.Stub 158 implements RegisteredServicesCacheListener<AuthenticatorDescription> { 159 private static final String TAG = "AccountManagerService"; 160 161 public static class Lifecycle extends SystemService { 162 private AccountManagerService mService; 163 Lifecycle(Context context)164 public Lifecycle(Context context) { 165 super(context); 166 } 167 168 @Override onStart()169 public void onStart() { 170 mService = new AccountManagerService(new Injector(getContext())); 171 publishBinderService(Context.ACCOUNT_SERVICE, mService); 172 } 173 174 @Override onUserUnlocking(@onNull TargetUser user)175 public void onUserUnlocking(@NonNull TargetUser user) { 176 mService.onUnlockUser(user.getUserIdentifier()); 177 } 178 179 @Override onUserStopped(@onNull TargetUser user)180 public void onUserStopped(@NonNull TargetUser user) { 181 Slog.i(TAG, "onUserStopped " + user); 182 mService.purgeUserData(user.getUserIdentifier()); 183 } 184 } 185 186 final Context mContext; 187 188 private final PackageManager mPackageManager; 189 private final AppOpsManager mAppOpsManager; 190 private UserManager mUserManager; 191 private final Injector mInjector; 192 193 final MessageHandler mHandler; 194 195 private static final int TIMEOUT_DELAY_MS = 1000 * 60 * 15; 196 // Messages that can be sent on mHandler 197 private static final int MESSAGE_TIMED_OUT = 3; 198 private static final int MESSAGE_COPY_SHARED_ACCOUNT = 4; 199 200 private final IAccountAuthenticatorCache mAuthenticatorCache; 201 private static final String PRE_N_DATABASE_NAME = "accounts.db"; 202 private static final Intent ACCOUNTS_CHANGED_INTENT; 203 private static final Bundle ACCOUNTS_CHANGED_OPTIONS = new BroadcastOptions() 204 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 205 .toBundle(); 206 207 private static final int SIGNATURE_CHECK_MISMATCH = 0; 208 private static final int SIGNATURE_CHECK_MATCH = 1; 209 private static final int SIGNATURE_CHECK_UID_MATCH = 2; 210 211 /** 212 * Apps targeting Android U and above need to declare the package visibility needs in the 213 * manifest to access the AccountManager APIs. 214 */ 215 @ChangeId 216 @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 217 private static final long ENFORCE_PACKAGE_VISIBILITY_FILTERING = 154726397; 218 219 static { 220 ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION); 221 ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 222 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 223 } 224 225 private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>(); 226 227 static class UserAccounts { 228 private final int userId; 229 final AccountsDb accountsDb; 230 private final HashMap<Pair<Pair<Account, String>, Integer>, NotificationId> 231 credentialsPermissionNotificationIds = new HashMap<>(); 232 private final HashMap<Account, NotificationId> signinRequiredNotificationIds 233 = new HashMap<>(); 234 final Object cacheLock = new Object(); 235 final Object dbLock = new Object(); // if needed, dbLock must be obtained before cacheLock 236 /** protected by the {@link #cacheLock} */ 237 final HashMap<String, Account[]> accountCache = new LinkedHashMap<>(); 238 /** protected by the {@link #cacheLock} */ 239 private final Map<Account, Map<String, String>> userDataCache = new HashMap<>(); 240 /** protected by the {@link #cacheLock} */ 241 private final Map<Account, Map<String, String>> authTokenCache = new HashMap<>(); 242 /** protected by the {@link #cacheLock} */ 243 private final TokenCache accountTokenCaches = new TokenCache(); 244 /** protected by the {@link #cacheLock} */ 245 private final Map<Account, Map<String, Integer>> visibilityCache = new HashMap<>(); 246 247 /** protected by the {@link #mReceiversForType}, 248 * type -> (packageName -> number of active receivers) 249 * type == null is used to get notifications about all account types 250 */ 251 private final Map<String, Map<String, Integer>> mReceiversForType = new HashMap<>(); 252 253 /** 254 * protected by the {@link #cacheLock} 255 * 256 * Caches the previous names associated with an account. Previous names 257 * should be cached because we expect that when an Account is renamed, 258 * many clients will receive a LOGIN_ACCOUNTS_CHANGED broadcast and 259 * want to know if the accounts they care about have been renamed. 260 * 261 * The previous names are wrapped in an {@link AtomicReference} so that 262 * we can distinguish between those accounts with no previous names and 263 * those whose previous names haven't been cached (yet). 264 */ 265 private final HashMap<Account, AtomicReference<String>> previousNameCache = 266 new HashMap<Account, AtomicReference<String>>(); 267 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile)268 UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) { 269 this.userId = userId; 270 synchronized (dbLock) { 271 synchronized (cacheLock) { 272 accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile); 273 } 274 } 275 } 276 } 277 278 private final SparseArray<UserAccounts> mUsers = new SparseArray<>(); 279 private final SparseBooleanArray mLocalUnlockedUsers = new SparseBooleanArray(); 280 // Not thread-safe. Only use in synchronized context 281 private final SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 282 private CopyOnWriteArrayList<AccountManagerInternal.OnAppPermissionChangeListener> 283 mAppPermissionChangeListeners = new CopyOnWriteArrayList<>(); 284 285 private static AtomicReference<AccountManagerService> sThis = new AtomicReference<>(); 286 private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{}; 287 288 private static Histogram sResponseLatency = new Histogram( 289 "app.value_high_authenticator_response_latency", 290 new Histogram.ScaledRangeOptions(20, 10000, 10000, 1.5f) 291 ); 292 293 /** 294 * This should only be called by system code. One should only call this after the service 295 * has started. 296 * @return a reference to the AccountManagerService instance 297 * @hide 298 */ getSingleton()299 public static AccountManagerService getSingleton() { 300 return sThis.get(); 301 } 302 AccountManagerService(Injector injector)303 public AccountManagerService(Injector injector) { 304 mInjector = injector; 305 mContext = injector.getContext(); 306 mPackageManager = mContext.getPackageManager(); 307 mAppOpsManager = mContext.getSystemService(AppOpsManager.class); 308 mHandler = new MessageHandler(injector.getMessageHandlerLooper()); 309 mAuthenticatorCache = mInjector.getAccountAuthenticatorCache(); 310 mAuthenticatorCache.setListener(this, mHandler); 311 312 sThis.set(this); 313 314 IntentFilter intentFilter = new IntentFilter(); 315 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 316 intentFilter.addDataScheme("package"); 317 mContext.registerReceiver(new BroadcastReceiver() { 318 @Override 319 public void onReceive(Context context1, Intent intent) { 320 // Don't delete accounts when updating a authenticator's 321 // package. 322 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 323 /* Purging data requires file io, don't block the main thread. This is probably 324 * less than ideal because we are introducing a race condition where old grants 325 * could be exercised until they are purged. But that race condition existed 326 * anyway with the broadcast receiver. 327 * 328 * Ideally, we would completely clear the cache, purge data from the database, 329 * and then rebuild the cache. All under the cache lock. But that change is too 330 * large at this point. 331 */ 332 final String removedPackageName = intent.getData().getSchemeSpecificPart(); 333 Runnable purgingRunnable = new Runnable() { 334 @Override 335 public void run() { 336 purgeOldGrantsAll(); 337 // Notify authenticator about removed app? 338 removeVisibilityValuesForPackage(removedPackageName); 339 } 340 }; 341 mHandler.post(purgingRunnable); 342 } 343 } 344 }, intentFilter); 345 346 injector.addLocalService(new AccountManagerInternalImpl()); 347 348 IntentFilter userFilter = new IntentFilter(); 349 userFilter.addAction(Intent.ACTION_USER_REMOVED); 350 mContext.registerReceiverAsUser(new BroadcastReceiver() { 351 @Override 352 public void onReceive(Context context, Intent intent) { 353 String action = intent.getAction(); 354 if (Intent.ACTION_USER_REMOVED.equals(action)) { 355 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 356 if (userId < 1) return; 357 Slog.i(TAG, "User " + userId + " removed"); 358 purgeUserData(userId); 359 } 360 } 361 }, UserHandle.ALL, userFilter, null, null); 362 363 // Need to cancel account request notifications if the update/install can access the account 364 new PackageMonitor() { 365 @Override 366 public void onPackageAdded(String packageName, int uid) { 367 // Called on a handler, and running as the system 368 try { 369 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); 370 cancelAccountAccessRequestNotificationIfNeeded(uid, true, accounts); 371 } catch (SQLiteCantOpenDatabaseException e) { 372 Log.w(TAG, "Can't read accounts database", e); 373 return; 374 } 375 } 376 377 @Override 378 public void onPackageUpdateFinished(String packageName, int uid) { 379 // Called on a handler, and running as the system 380 try { 381 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); 382 cancelAccountAccessRequestNotificationIfNeeded(uid, true, accounts); 383 } catch (SQLiteCantOpenDatabaseException e) { 384 Log.w(TAG, "Can't read accounts database", e); 385 return; 386 } 387 } 388 }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); 389 390 // Cancel account request notification if an app op was preventing the account access 391 mAppOpsManager.startWatchingMode(AppOpsManager.OP_GET_ACCOUNTS, null, 392 new AppOpsManager.OnOpChangedInternalListener() { 393 @Override 394 public void onOpChanged(int op, String packageName) { 395 try { 396 final int userId = ActivityManager.getCurrentUser(); 397 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); 398 final int mode = mAppOpsManager.checkOpNoThrow( 399 AppOpsManager.OP_GET_ACCOUNTS, uid, packageName); 400 if (mode == AppOpsManager.MODE_ALLOWED) { 401 final long identity = Binder.clearCallingIdentity(); 402 try { 403 UserAccounts accounts = getUserAccounts(userId); 404 cancelAccountAccessRequestNotificationIfNeeded( 405 packageName, uid, true, accounts); 406 } finally { 407 Binder.restoreCallingIdentity(identity); 408 } 409 } 410 } catch (NameNotFoundException e) { 411 /* ignore */ 412 } catch (SQLiteCantOpenDatabaseException e) { 413 Log.w(TAG, "Can't read accounts database", e); 414 return; 415 } 416 } 417 }); 418 419 // Cancel account request notification if a permission was preventing the account access 420 mPackageManager.addOnPermissionsChangeListener( 421 (int uid) -> { 422 // Permission changes cause requires updating accounts cache. 423 AccountManager.invalidateLocalAccountsDataCaches(); 424 425 Account[] accounts = null; 426 String[] packageNames = mPackageManager.getPackagesForUid(uid); 427 if (packageNames != null) { 428 final int userId = UserHandle.getUserId(uid); 429 final long identity = Binder.clearCallingIdentity(); 430 try { 431 for (String packageName : packageNames) { 432 // if app asked for permission we need to cancel notification even 433 // for O+ applications. 434 if (mPackageManager.checkPermission( 435 Manifest.permission.GET_ACCOUNTS, 436 packageName) != PackageManager.PERMISSION_GRANTED) { 437 continue; 438 } 439 440 if (accounts == null) { 441 accounts = getAccountsOrEmptyArray(null, userId, "android"); 442 if (ArrayUtils.isEmpty(accounts)) { 443 return; 444 } 445 } 446 UserAccounts userAccounts = getUserAccounts(UserHandle.getUserId(uid)); 447 for (Account account : accounts) { 448 cancelAccountAccessRequestNotificationIfNeeded( 449 account, uid, packageName, true, userAccounts); 450 } 451 } 452 } finally { 453 Binder.restoreCallingIdentity(identity); 454 } 455 } 456 }); 457 } 458 459 getBindInstantServiceAllowed(int userId)460 boolean getBindInstantServiceAllowed(int userId) { 461 return mAuthenticatorCache.getBindInstantServiceAllowed(userId); 462 } 463 setBindInstantServiceAllowed(int userId, boolean allowed)464 void setBindInstantServiceAllowed(int userId, boolean allowed) { 465 mAuthenticatorCache.setBindInstantServiceAllowed(userId, allowed); 466 } 467 cancelAccountAccessRequestNotificationIfNeeded(int uid, boolean checkAccess, UserAccounts userAccounts)468 private void cancelAccountAccessRequestNotificationIfNeeded(int uid, 469 boolean checkAccess, UserAccounts userAccounts) { 470 Account[] accounts = getAccountsOrEmptyArray(null, UserHandle.getUserId(uid), "android"); 471 for (Account account : accounts) { 472 cancelAccountAccessRequestNotificationIfNeeded(account, uid, checkAccess, userAccounts); 473 } 474 } 475 cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid, boolean checkAccess, UserAccounts userAccounts)476 private void cancelAccountAccessRequestNotificationIfNeeded(String packageName, int uid, 477 boolean checkAccess, UserAccounts userAccounts) { 478 Account[] accounts = getAccountsOrEmptyArray(null, UserHandle.getUserId(uid), "android"); 479 for (Account account : accounts) { 480 cancelAccountAccessRequestNotificationIfNeeded(account, 481 uid, packageName, checkAccess, userAccounts); 482 } 483 } 484 cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid, boolean checkAccess, UserAccounts accounts)485 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid, 486 boolean checkAccess, UserAccounts accounts) { 487 String[] packageNames = mPackageManager.getPackagesForUid(uid); 488 if (packageNames != null) { 489 for (String packageName : packageNames) { 490 cancelAccountAccessRequestNotificationIfNeeded(account, uid, 491 packageName, checkAccess, accounts); 492 } 493 } 494 } 495 cancelAccountAccessRequestNotificationIfNeeded(Account account, int uid, String packageName, boolean checkAccess, UserAccounts accounts)496 private void cancelAccountAccessRequestNotificationIfNeeded(Account account, 497 int uid, String packageName, boolean checkAccess, UserAccounts accounts) { 498 if (!checkAccess || hasAccountAccess(account, packageName, 499 UserHandle.getUserHandleForUid(uid))) { 500 cancelNotification(getCredentialPermissionNotificationId(account, 501 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid, accounts), 502 accounts); 503 } 504 } 505 506 @Override addAccountExplicitlyWithVisibility(Account account, String password, Bundle extras, Map packageToVisibility, String opPackageName)507 public boolean addAccountExplicitlyWithVisibility(Account account, String password, 508 Bundle extras, Map packageToVisibility, String opPackageName) { 509 Bundle.setDefusable(extras, true); 510 int callingUid = Binder.getCallingUid(); 511 int userId = UserHandle.getCallingUserId(); 512 Objects.requireNonNull(account, "account cannot be null"); 513 Log.v(TAG, "addAccountExplicitly: caller's uid=" + callingUid + ", pid=" 514 + Binder.getCallingPid() + ", packageName=" + opPackageName + ", accountType=" 515 + account.type); 516 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 517 String msg = String.format("uid=%s, package=%s cannot explicitly add " 518 + "accounts of type: %s", callingUid, opPackageName, account.type); 519 throw new SecurityException(msg); 520 } 521 /* 522 * Child users are not allowed to add accounts. Only the accounts that are shared by the 523 * parent profile can be added to child profile. 524 * 525 * TODO: Only allow accounts that were shared to be added by a limited user. 526 */ 527 // fails if the account already exists 528 final long identityToken = clearCallingIdentity(); 529 try { 530 UserAccounts accounts = getUserAccounts(userId); 531 return addAccountInternal(accounts, account, password, extras, callingUid, 532 (Map<String, Integer>) packageToVisibility, opPackageName); 533 } finally { 534 restoreCallingIdentity(identityToken); 535 } 536 } 537 538 @Override getAccountsAndVisibilityForPackage(String packageName, String accountType)539 public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName, 540 String accountType) { 541 int callingUid = Binder.getCallingUid(); 542 int userId = UserHandle.getCallingUserId(); 543 boolean isSystemUid = UserHandle.isSameApp(callingUid, Process.SYSTEM_UID); 544 List<String> managedTypes = getTypesForCaller(callingUid, userId, isSystemUid); 545 546 if ((accountType != null && !managedTypes.contains(accountType)) 547 || (accountType == null && !isSystemUid)) { 548 throw new SecurityException( 549 "getAccountsAndVisibilityForPackage() called from unauthorized uid " 550 + callingUid + " with packageName=" + packageName); 551 } 552 if (accountType != null) { 553 managedTypes = new ArrayList<String>(); 554 managedTypes.add(accountType); 555 } 556 557 final long identityToken = clearCallingIdentity(); 558 try { 559 UserAccounts accounts = getUserAccounts(userId); 560 return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid, 561 accounts); 562 } finally { 563 restoreCallingIdentity(identityToken); 564 } 565 } 566 567 /* 568 * accountTypes may not be null 569 */ getAccountsAndVisibilityForPackage(String packageName, List<String> accountTypes, Integer callingUid, UserAccounts accounts)570 private Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName, 571 List<String> accountTypes, Integer callingUid, UserAccounts accounts) { 572 if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { 573 Log.w(TAG, "getAccountsAndVisibilityForPackage#Package not found " + packageName); 574 return new LinkedHashMap<>(); 575 } 576 577 Map<Account, Integer> result = new LinkedHashMap<>(); 578 for (String accountType : accountTypes) { 579 synchronized (accounts.dbLock) { 580 synchronized (accounts.cacheLock) { 581 final Account[] accountsOfType = accounts.accountCache.get(accountType); 582 if (accountsOfType != null) { 583 for (Account account : accountsOfType) { 584 result.put(account, 585 resolveAccountVisibility(account, packageName, accounts)); 586 } 587 } 588 } 589 } 590 } 591 return filterSharedAccounts(accounts, result, callingUid, packageName); 592 } 593 594 @Override getPackagesAndVisibilityForAccount(Account account)595 public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) { 596 Objects.requireNonNull(account, "account cannot be null"); 597 int callingUid = Binder.getCallingUid(); 598 int userId = UserHandle.getCallingUserId(); 599 if (!isAccountManagedByCaller(account.type, callingUid, userId) 600 && !isSystemUid(callingUid)) { 601 String msg = 602 String.format("uid %s cannot get secrets for account %s", callingUid, account); 603 throw new SecurityException(msg); 604 } 605 606 final long identityToken = clearCallingIdentity(); 607 try { 608 UserAccounts accounts = getUserAccounts(userId); 609 synchronized (accounts.dbLock) { 610 synchronized (accounts.cacheLock) { 611 return getPackagesAndVisibilityForAccountLocked(account, accounts); 612 } 613 } 614 } finally { 615 restoreCallingIdentity(identityToken); 616 } 617 618 } 619 620 /** 621 * Returns Map with all package names and visibility values for given account. 622 * The method and returned map must be guarded by accounts.cacheLock 623 * 624 * @param account Account to get visibility values. 625 * @param accounts UserAccount that currently hosts the account and application 626 * 627 * @return Map with cache for package names to visibility. 628 */ getPackagesAndVisibilityForAccountLocked(Account account, UserAccounts accounts)629 private @NonNull Map<String, Integer> getPackagesAndVisibilityForAccountLocked(Account account, 630 UserAccounts accounts) { 631 Map<String, Integer> accountVisibility = accounts.visibilityCache.get(account); 632 if (accountVisibility == null) { 633 Log.d(TAG, "Visibility was not initialized"); 634 accountVisibility = new HashMap<>(); 635 accounts.visibilityCache.put(account, accountVisibility); 636 AccountManager.invalidateLocalAccountsDataCaches(); 637 } 638 return accountVisibility; 639 } 640 641 @Override getAccountVisibility(Account account, String packageName)642 public int getAccountVisibility(Account account, String packageName) { 643 Objects.requireNonNull(account, "account cannot be null"); 644 Objects.requireNonNull(packageName, "packageName cannot be null"); 645 int callingUid = Binder.getCallingUid(); 646 int userId = UserHandle.getCallingUserId(); 647 if (!isAccountManagedByCaller(account.type, callingUid, userId) 648 && !isSystemUid(callingUid)) { 649 String msg = String.format( 650 "uid %s cannot get secrets for accounts of type: %s", 651 callingUid, 652 account.type); 653 throw new SecurityException(msg); 654 } 655 final long identityToken = clearCallingIdentity(); 656 try { 657 UserAccounts accounts = getUserAccounts(userId); 658 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) { 659 int visibility = getAccountVisibilityFromCache(account, packageName, accounts); 660 if (AccountManager.VISIBILITY_UNDEFINED != visibility) { 661 return visibility; 662 } else { 663 return AccountManager.VISIBILITY_USER_MANAGED_VISIBLE; 664 } 665 } 666 if (AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)) { 667 int visibility = getAccountVisibilityFromCache(account, packageName, accounts); 668 if (AccountManager.VISIBILITY_UNDEFINED != visibility) { 669 return visibility; 670 } else { 671 return AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE; 672 } 673 } 674 if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { 675 return AccountManager.VISIBILITY_NOT_VISIBLE; 676 } 677 return resolveAccountVisibility(account, packageName, accounts); 678 } finally { 679 restoreCallingIdentity(identityToken); 680 } 681 } 682 683 /** 684 * Method returns visibility for given account and package name. 685 * 686 * @param account The account to check visibility. 687 * @param packageName Package name to check visibility. 688 * @param accounts UserAccount that currently hosts the account and application 689 * 690 * @return Visibility value, AccountManager.VISIBILITY_UNDEFINED if no value was stored. 691 * 692 */ getAccountVisibilityFromCache(Account account, String packageName, UserAccounts accounts)693 private int getAccountVisibilityFromCache(Account account, String packageName, 694 UserAccounts accounts) { 695 synchronized (accounts.cacheLock) { 696 Map<String, Integer> accountVisibility = 697 getPackagesAndVisibilityForAccountLocked(account, accounts); 698 Integer visibility = accountVisibility.get(packageName); 699 return visibility != null ? visibility : AccountManager.VISIBILITY_UNDEFINED; 700 } 701 } 702 703 /** 704 * Method which handles default values for Account visibility. 705 * 706 * @param account The account to check visibility. 707 * @param packageName Package name to check visibility 708 * @param accounts UserAccount that currently hosts the account and application 709 * 710 * @return Visibility value, the method never returns AccountManager.VISIBILITY_UNDEFINED 711 * 712 */ resolveAccountVisibility(Account account, @NonNull String packageName, UserAccounts accounts)713 private Integer resolveAccountVisibility(Account account, @NonNull String packageName, 714 UserAccounts accounts) { 715 Objects.requireNonNull(packageName, "packageName cannot be null"); 716 int uid = -1; 717 try { 718 final long identityToken = clearCallingIdentity(); 719 try { 720 uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId); 721 } finally { 722 restoreCallingIdentity(identityToken); 723 } 724 } catch (NameNotFoundException e) { 725 Log.w(TAG, "resolveAccountVisibility#Package not found " + e.getMessage()); 726 return AccountManager.VISIBILITY_NOT_VISIBLE; 727 } 728 729 // System visibility can not be restricted. 730 if (UserHandle.isSameApp(uid, Process.SYSTEM_UID)) { 731 return AccountManager.VISIBILITY_VISIBLE; 732 } 733 734 int signatureCheckResult = 735 checkPackageSignature(account.type, uid, accounts.userId); 736 737 // Authenticator can not restrict visibility to itself. 738 if (signatureCheckResult == SIGNATURE_CHECK_UID_MATCH) { 739 return AccountManager.VISIBILITY_VISIBLE; // Authenticator can always see the account 740 } 741 742 // Return stored value if it was set. 743 int visibility = getAccountVisibilityFromCache(account, packageName, accounts); 744 745 if (AccountManager.VISIBILITY_UNDEFINED != visibility) { 746 return visibility; 747 } 748 749 boolean isPrivileged = isPermittedForPackage(packageName, accounts.userId, 750 Manifest.permission.GET_ACCOUNTS_PRIVILEGED); 751 752 // Device/Profile owner gets visibility by default. 753 if (isProfileOwner(uid)) { 754 return AccountManager.VISIBILITY_VISIBLE; 755 } 756 757 boolean preO = isPreOApplication(packageName); 758 if ((signatureCheckResult != SIGNATURE_CHECK_MISMATCH) 759 || (preO && checkGetAccountsPermission(packageName, accounts.userId)) 760 || (checkReadContactsPermission(packageName, accounts.userId) 761 && accountTypeManagesContacts(account.type, accounts.userId)) 762 || isPrivileged) { 763 // Use legacy for preO apps with GET_ACCOUNTS permission or pre/postO with signature 764 // match. 765 visibility = getAccountVisibilityFromCache(account, 766 AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE, accounts); 767 if (AccountManager.VISIBILITY_UNDEFINED == visibility) { 768 visibility = AccountManager.VISIBILITY_USER_MANAGED_VISIBLE; 769 } 770 } else { 771 visibility = getAccountVisibilityFromCache(account, 772 AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, accounts); 773 if (AccountManager.VISIBILITY_UNDEFINED == visibility) { 774 visibility = AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE; 775 } 776 } 777 return visibility; 778 } 779 780 /** 781 * Checks targetSdk for a package; 782 * 783 * @param packageName Package name 784 * 785 * @return True if package's target SDK is below {@link android.os.Build.VERSION_CODES#O}, or 786 * undefined 787 */ isPreOApplication(String packageName)788 private boolean isPreOApplication(String packageName) { 789 try { 790 final long identityToken = clearCallingIdentity(); 791 ApplicationInfo applicationInfo; 792 try { 793 applicationInfo = mPackageManager.getApplicationInfo(packageName, 0); 794 } finally { 795 restoreCallingIdentity(identityToken); 796 } 797 798 if (applicationInfo != null) { 799 int version = applicationInfo.targetSdkVersion; 800 return version < android.os.Build.VERSION_CODES.O; 801 } 802 return true; 803 } catch (NameNotFoundException e) { 804 Log.w(TAG, "isPreOApplication#Package not found " + e.getMessage()); 805 return true; 806 } 807 } 808 809 @Override setAccountVisibility(Account account, String packageName, int newVisibility)810 public boolean setAccountVisibility(Account account, String packageName, int newVisibility) { 811 Objects.requireNonNull(account, "account cannot be null"); 812 Objects.requireNonNull(packageName, "packageName cannot be null"); 813 int callingUid = Binder.getCallingUid(); 814 int userId = UserHandle.getCallingUserId(); 815 if (!isAccountManagedByCaller(account.type, callingUid, userId) 816 && !isSystemUid(callingUid)) { 817 String msg = String.format( 818 "uid %s cannot get secrets for accounts of type: %s", 819 callingUid, 820 account.type); 821 throw new SecurityException(msg); 822 } 823 final long identityToken = clearCallingIdentity(); 824 try { 825 UserAccounts accounts = getUserAccounts(userId); 826 return setAccountVisibility(account, packageName, newVisibility, true /* notify */, 827 accounts, callingUid); 828 } finally { 829 restoreCallingIdentity(identityToken); 830 } 831 } 832 isVisible(int visibility)833 private boolean isVisible(int visibility) { 834 return visibility == AccountManager.VISIBILITY_VISIBLE || 835 visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE; 836 } 837 838 /** 839 * Updates visibility for given account name and package. 840 * 841 * @param account Account to update visibility. 842 * @param packageName Package name for which visibility is updated. 843 * @param newVisibility New visibility calue 844 * @param notify if the flag is set applications will get notification about visibility change 845 * @param accounts UserAccount that currently hosts the account and application 846 * @param callingUid The caller's uid. 847 * 848 * @return True if account visibility was changed. 849 */ setAccountVisibility(Account account, String packageName, int newVisibility, boolean notify, UserAccounts accounts, int callingUid)850 private boolean setAccountVisibility(Account account, String packageName, int newVisibility, 851 boolean notify, UserAccounts accounts, int callingUid) { 852 synchronized (accounts.dbLock) { 853 synchronized (accounts.cacheLock) { 854 Map<String, Integer> packagesToVisibility; 855 List<String> accountRemovedReceivers; 856 if (notify) { 857 if (isSpecialPackageKey(packageName)) { 858 packagesToVisibility = 859 getRequestingPackages(account, accounts); 860 accountRemovedReceivers = getAccountRemovedReceivers(account, accounts); 861 } else { 862 if (!canCallerAccessPackage(packageName, callingUid, accounts.userId)) { 863 return false; // package is not installed or not visible. 864 } 865 packagesToVisibility = new HashMap<>(); 866 packagesToVisibility.put(packageName, 867 resolveAccountVisibility(account, packageName, accounts)); 868 accountRemovedReceivers = new ArrayList<>(); 869 if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) { 870 accountRemovedReceivers.add(packageName); 871 } 872 } 873 } else { 874 // Notifications will not be send - only used during add account. 875 if (!isSpecialPackageKey(packageName) 876 && !canCallerAccessPackage(packageName, callingUid, accounts.userId)) { 877 // package is not installed and not meta value. 878 return false; 879 } 880 packagesToVisibility = Collections.emptyMap(); 881 accountRemovedReceivers = Collections.emptyList(); 882 } 883 if (notify) { 884 Integer oldVisibility = 885 accounts.accountsDb.findAccountVisibility(account, packageName); 886 if (oldVisibility != null && oldVisibility == newVisibility) { 887 // Database will not be updated - skip LOGIN_ACCOUNTS_CHANGED broadcast. 888 notify = false; 889 } 890 } 891 892 if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) { 893 return false; 894 } 895 896 if (notify) { 897 Log.i(TAG, "Notifying visibility changed for package=" + packageName); 898 for (Entry<String, Integer> packageToVisibility : packagesToVisibility 899 .entrySet()) { 900 int oldVisibility = packageToVisibility.getValue(); 901 int currentVisibility = 902 resolveAccountVisibility(account, packageName, accounts); 903 if (isVisible(oldVisibility) != isVisible(currentVisibility)) { 904 notifyPackage(packageToVisibility.getKey(), accounts); 905 } 906 } 907 for (String packageNameToNotify : accountRemovedReceivers) { 908 int currentVisibility = 909 resolveAccountVisibility(account, packageNameToNotify, accounts); 910 if (isVisible(currentVisibility)) { 911 continue; 912 } 913 sendAccountRemovedBroadcast( 914 account, 915 packageNameToNotify, 916 accounts.userId, 917 /*useCase=*/"setAccountVisibility"); 918 } 919 sendAccountsChangedBroadcast( 920 accounts.userId, account.type, /*useCase=*/"setAccountVisibility"); 921 } 922 return true; 923 } 924 } 925 } 926 927 // Update account visibility in cache and database. updateAccountVisibilityLocked(Account account, String packageName, int newVisibility, UserAccounts accounts)928 private boolean updateAccountVisibilityLocked(Account account, String packageName, 929 int newVisibility, UserAccounts accounts) { 930 final long accountId = accounts.accountsDb.findDeAccountId(account); 931 if (accountId < 0) { 932 return false; 933 } 934 935 final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); 936 try { 937 if (!accounts.accountsDb.setAccountVisibility(accountId, packageName, 938 newVisibility)) { 939 return false; 940 } 941 } finally { 942 StrictMode.setThreadPolicy(oldPolicy); 943 } 944 Map<String, Integer> accountVisibility = 945 getPackagesAndVisibilityForAccountLocked(account, accounts); 946 accountVisibility.put(packageName, newVisibility); 947 AccountManager.invalidateLocalAccountsDataCaches(); 948 return true; 949 } 950 951 @Override registerAccountListener(String[] accountTypes, String opPackageName)952 public void registerAccountListener(String[] accountTypes, String opPackageName) { 953 int callingUid = Binder.getCallingUid(); 954 mAppOpsManager.checkPackage(callingUid, opPackageName); 955 956 int userId = UserHandle.getCallingUserId(); 957 final long identityToken = clearCallingIdentity(); 958 try { 959 UserAccounts accounts = getUserAccounts(userId); 960 registerAccountListener(accountTypes, opPackageName, accounts); 961 } finally { 962 restoreCallingIdentity(identityToken); 963 } 964 } 965 registerAccountListener(String[] accountTypes, String opPackageName, UserAccounts accounts)966 private void registerAccountListener(String[] accountTypes, String opPackageName, 967 UserAccounts accounts) { 968 synchronized (accounts.mReceiversForType) { 969 if (accountTypes == null) { 970 // null for any type 971 accountTypes = new String[] {null}; 972 } 973 for (String type : accountTypes) { 974 Map<String, Integer> receivers = accounts.mReceiversForType.get(type); 975 if (receivers == null) { 976 receivers = new HashMap<>(); 977 accounts.mReceiversForType.put(type, receivers); 978 } 979 Integer cnt = receivers.get(opPackageName); 980 receivers.put(opPackageName, cnt != null ? cnt + 1 : 1); 981 } 982 } 983 } 984 985 @Override unregisterAccountListener(String[] accountTypes, String opPackageName)986 public void unregisterAccountListener(String[] accountTypes, String opPackageName) { 987 int callingUid = Binder.getCallingUid(); 988 mAppOpsManager.checkPackage(callingUid, opPackageName); 989 int userId = UserHandle.getCallingUserId(); 990 final long identityToken = clearCallingIdentity(); 991 try { 992 UserAccounts accounts = getUserAccounts(userId); 993 unregisterAccountListener(accountTypes, opPackageName, accounts); 994 } finally { 995 restoreCallingIdentity(identityToken); 996 } 997 } 998 unregisterAccountListener(String[] accountTypes, String opPackageName, UserAccounts accounts)999 private void unregisterAccountListener(String[] accountTypes, String opPackageName, 1000 UserAccounts accounts) { 1001 synchronized (accounts.mReceiversForType) { 1002 if (accountTypes == null) { 1003 // null for any type 1004 accountTypes = new String[] {null}; 1005 } 1006 for (String type : accountTypes) { 1007 Map<String, Integer> receivers = accounts.mReceiversForType.get(type); 1008 if (receivers == null || receivers.get(opPackageName) == null) { 1009 throw new IllegalArgumentException("attempt to unregister wrong receiver"); 1010 } 1011 Integer cnt = receivers.get(opPackageName); 1012 if (cnt == 1) { 1013 receivers.remove(opPackageName); 1014 } else { 1015 receivers.put(opPackageName, cnt - 1); 1016 } 1017 } 1018 } 1019 } 1020 1021 // Send notification to all packages which can potentially see the account sendNotificationAccountUpdated(Account account, UserAccounts accounts)1022 private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) { 1023 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts); 1024 1025 for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) { 1026 if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) 1027 && (packageToVisibility.getValue() 1028 != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) { 1029 notifyPackage(packageToVisibility.getKey(), accounts); 1030 } 1031 } 1032 } 1033 1034 /** 1035 * Sends a direct intent to a package, notifying it of account visibility change. 1036 * 1037 * @param packageName to send Account to 1038 * @param accounts UserAccount that currently hosts the account 1039 */ notifyPackage(String packageName, UserAccounts accounts)1040 private void notifyPackage(String packageName, UserAccounts accounts) { 1041 Log.i(TAG, "notifying package=" + packageName + " for userId=" + accounts.userId 1042 +", sending broadcast of " + AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED); 1043 Intent intent = new Intent(AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED); 1044 intent.setPackage(packageName); 1045 intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1046 mContext.sendBroadcastAsUser(intent, new UserHandle(accounts.userId)); 1047 } 1048 1049 // Returns a map from package name to visibility, for packages subscribed 1050 // to notifications about any account type, or type of provided account 1051 // account type or all types. getRequestingPackages(Account account, UserAccounts accounts)1052 private Map<String, Integer> getRequestingPackages(Account account, UserAccounts accounts) { 1053 Set<String> packages = new HashSet<>(); 1054 synchronized (accounts.mReceiversForType) { 1055 for (String type : new String[] {account.type, null}) { 1056 Map<String, Integer> receivers = accounts.mReceiversForType.get(type); 1057 if (receivers != null) { 1058 packages.addAll(receivers.keySet()); 1059 } 1060 } 1061 } 1062 Map<String, Integer> result = new HashMap<>(); 1063 for (String packageName : packages) { 1064 result.put(packageName, resolveAccountVisibility(account, packageName, accounts)); 1065 } 1066 return result; 1067 } 1068 1069 // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account. getAccountRemovedReceivers(Account account, UserAccounts accounts)1070 private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) { 1071 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED); 1072 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1073 List<ResolveInfo> receivers = 1074 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId); 1075 List<String> result = new ArrayList<>(); 1076 if (receivers == null) { 1077 return result; 1078 } 1079 for (ResolveInfo resolveInfo: receivers) { 1080 String packageName = resolveInfo.activityInfo.applicationInfo.packageName; 1081 int visibility = resolveAccountVisibility(account, packageName, accounts); 1082 if (visibility == AccountManager.VISIBILITY_VISIBLE 1083 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) { 1084 result.add(packageName); 1085 } 1086 } 1087 return result; 1088 } 1089 1090 // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account. shouldNotifyPackageOnAccountRemoval(Account account, String packageName, UserAccounts accounts)1091 private boolean shouldNotifyPackageOnAccountRemoval(Account account, 1092 String packageName, UserAccounts accounts) { 1093 int visibility = resolveAccountVisibility(account, packageName, accounts); 1094 if (visibility != AccountManager.VISIBILITY_VISIBLE 1095 && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) { 1096 return false; 1097 } 1098 1099 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED); 1100 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1101 intent.setPackage(packageName); 1102 List<ResolveInfo> receivers = 1103 mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId); 1104 return (receivers != null && receivers.size() > 0); 1105 } 1106 1107 /** 1108 * Returns true if packageName is one of special values. 1109 */ isSpecialPackageKey(String packageName)1110 private boolean isSpecialPackageKey(String packageName) { 1111 return (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName) 1112 || AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE.equals(packageName)); 1113 } 1114 sendAccountsChangedBroadcast( int userId, String accountType, @NonNull String useCase)1115 private void sendAccountsChangedBroadcast( 1116 int userId, String accountType, @NonNull String useCase) { 1117 Objects.requireNonNull(useCase, "useCase can't be null"); 1118 Log.i(TAG, "the accountType= " + (accountType == null ? "" : accountType) 1119 + " changed with useCase=" + useCase + " for userId=" + userId 1120 + ", sending broadcast of " + ACCOUNTS_CHANGED_INTENT.getAction()); 1121 mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId), 1122 null /* receiverPermission */, ACCOUNTS_CHANGED_OPTIONS); 1123 } 1124 sendAccountRemovedBroadcast( Account account, String packageName, int userId, @NonNull String useCase)1125 private void sendAccountRemovedBroadcast( 1126 Account account, String packageName, int userId, @NonNull String useCase) { 1127 Objects.requireNonNull(useCase, "useCase can't be null"); 1128 Log.i(TAG, "the account with type=" + account.type + " removed while useCase=" 1129 + useCase + " for userId=" + userId + ", sending broadcast of " 1130 + AccountManager.ACTION_ACCOUNT_REMOVED); 1131 Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED); 1132 intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1133 intent.setPackage(packageName); 1134 intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name); 1135 intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type); 1136 mContext.sendBroadcastAsUser(intent, new UserHandle(userId)); 1137 } 1138 1139 @Override onTransact(int code, Parcel data, Parcel reply, int flags)1140 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 1141 throws RemoteException { 1142 try { 1143 return super.onTransact(code, data, reply, flags); 1144 } catch (RuntimeException e) { 1145 // The account manager only throws security exceptions, so let's 1146 // log all others. 1147 if (!(e instanceof SecurityException || e instanceof IllegalArgumentException)) { 1148 Slog.wtf(TAG, "Account Manager Crash", e); 1149 } 1150 throw e; 1151 } 1152 } 1153 getUserManager()1154 private UserManager getUserManager() { 1155 if (mUserManager == null) { 1156 mUserManager = UserManager.get(mContext); 1157 } 1158 return mUserManager; 1159 } 1160 1161 /** 1162 * Validate internal set of accounts against installed authenticators for 1163 * given user. Clears cached authenticators before validating. 1164 */ validateAccounts(int userId)1165 public void validateAccounts(int userId) { 1166 final UserAccounts accounts = getUserAccounts(userId); 1167 // Invalidate user-specific cache to make sure we catch any 1168 // removed authenticators. 1169 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */); 1170 } 1171 1172 /** 1173 * Validate internal set of accounts against installed authenticators for 1174 * given user. Clear cached authenticators before validating when requested. 1175 */ validateAccountsInternal( UserAccounts accounts, boolean invalidateAuthenticatorCache)1176 private void validateAccountsInternal( 1177 UserAccounts accounts, boolean invalidateAuthenticatorCache) { 1178 if (Log.isLoggable(TAG, Log.DEBUG)) { 1179 Log.d(TAG, "validateAccountsInternal " + accounts.userId 1180 + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached() 1181 + " userLocked=" + mLocalUnlockedUsers.get(accounts.userId)); 1182 } 1183 1184 if (invalidateAuthenticatorCache) { 1185 mAuthenticatorCache.invalidateCache(accounts.userId); 1186 } 1187 1188 final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser( 1189 mAuthenticatorCache, accounts.userId); 1190 boolean userUnlocked = isLocalUnlockedUser(accounts.userId); 1191 1192 synchronized (accounts.dbLock) { 1193 synchronized (accounts.cacheLock) { 1194 boolean accountDeleted = false; 1195 1196 // Get a map of stored authenticator types to UID 1197 final AccountsDb accountsDb = accounts.accountsDb; 1198 Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid(); 1199 // Create a list of authenticator type whose previous uid no longer exists 1200 HashSet<String> obsoleteAuthType = Sets.newHashSet(); 1201 SparseBooleanArray knownUids = null; 1202 for (Entry<String, Integer> authToUidEntry : metaAuthUid.entrySet()) { 1203 String type = authToUidEntry.getKey(); 1204 int uid = authToUidEntry.getValue(); 1205 Integer knownUid = knownAuth.get(type); 1206 if (knownUid != null && uid == knownUid) { 1207 // Remove it from the knownAuth list if it's unchanged. 1208 knownAuth.remove(type); 1209 } else { 1210 /* 1211 * The authenticator is presently not cached and should only be triggered 1212 * when we think an authenticator has been removed (or is being updated). 1213 * But we still want to check if any data with the associated uid is 1214 * around. This is an (imperfect) signal that the package may be updating. 1215 * 1216 * A side effect of this is that an authenticator sharing a uid with 1217 * multiple apps won't get its credentials wiped as long as some app with 1218 * that uid is still on the device. But I suspect that this is a rare case. 1219 * And it isn't clear to me how an attacker could really exploit that 1220 * feature. 1221 * 1222 * The upshot is that we don't have to worry about accounts getting 1223 * uninstalled while the authenticator's package is being updated. 1224 * 1225 */ 1226 if (knownUids == null) { 1227 knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId); 1228 } 1229 if (!knownUids.get(uid)) { 1230 // The authenticator is not presently available to the cache. And the 1231 // package no longer has a data directory (so we surmise it isn't 1232 // updating). So purge its data from the account databases. 1233 obsoleteAuthType.add(type); 1234 // And delete it from the TABLE_META 1235 accountsDb.deleteMetaByAuthTypeAndUid(type, uid); 1236 } 1237 } 1238 } 1239 1240 // Add the newly registered authenticator to TABLE_META. If old authenticators have 1241 // been re-enabled (after being updated for example), then we just overwrite the old 1242 // values. 1243 for (Entry<String, Integer> entry : knownAuth.entrySet()) { 1244 accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue()); 1245 } 1246 1247 final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts(); 1248 try { 1249 accounts.accountCache.clear(); 1250 final HashMap<String, ArrayList<String>> accountNamesByType 1251 = new LinkedHashMap<>(); 1252 for (Entry<Long, Account> accountEntry : accountsMap.entrySet()) { 1253 final long accountId = accountEntry.getKey(); 1254 final Account account = accountEntry.getValue(); 1255 if (obsoleteAuthType.contains(account.type)) { 1256 Slog.w(TAG, "deleting account " + account.toSafeString() 1257 + " because type " + account.type 1258 + "'s registered authenticator no longer exist."); 1259 Map<String, Integer> packagesToVisibility = 1260 getRequestingPackages(account, accounts); 1261 List<String> accountRemovedReceivers = 1262 getAccountRemovedReceivers(account, accounts); 1263 accountsDb.beginTransaction(); 1264 try { 1265 accountsDb.deleteDeAccount(accountId); 1266 // Also delete from CE table if user is unlocked; if user is 1267 // currently locked the account will be removed later by 1268 // syncDeCeAccountsLocked 1269 if (userUnlocked) { 1270 accountsDb.deleteCeAccount(accountId); 1271 } 1272 accountsDb.setTransactionSuccessful(); 1273 } finally { 1274 accountsDb.endTransaction(); 1275 } 1276 accountDeleted = true; 1277 Log.i(TAG, "validateAccountsInternal#Deleted UserId=" 1278 + accounts.userId + ", AccountId=" + accountId); 1279 1280 logRecord(AccountsDb.DEBUG_ACTION_AUTHENTICATOR_REMOVE, 1281 AccountsDb.TABLE_ACCOUNTS, accountId, accounts); 1282 1283 accounts.userDataCache.remove(account); 1284 accounts.authTokenCache.remove(account); 1285 accounts.accountTokenCaches.remove(account); 1286 accounts.visibilityCache.remove(account); 1287 1288 for (Entry<String, Integer> packageToVisibility : 1289 packagesToVisibility.entrySet()) { 1290 if (isVisible(packageToVisibility.getValue())) { 1291 notifyPackage(packageToVisibility.getKey(), accounts); 1292 } 1293 } 1294 for (String packageName : accountRemovedReceivers) { 1295 sendAccountRemovedBroadcast( 1296 account, 1297 packageName, 1298 accounts.userId, 1299 /*useCase=*/"validateAccounts"); 1300 } 1301 } else { 1302 ArrayList<String> accountNames = accountNamesByType.get(account.type); 1303 if (accountNames == null) { 1304 accountNames = new ArrayList<>(); 1305 accountNamesByType.put(account.type, accountNames); 1306 } 1307 accountNames.add(account.name); 1308 } 1309 } 1310 for (Map.Entry<String, ArrayList<String>> cur : accountNamesByType.entrySet()) { 1311 final String accountType = cur.getKey(); 1312 final ArrayList<String> accountNames = cur.getValue(); 1313 final Account[] accountsForType = new Account[accountNames.size()]; 1314 for (int i = 0; i < accountsForType.length; i++) { 1315 accountsForType[i] = new Account(accountNames.get(i), accountType, 1316 UUID.randomUUID().toString()); 1317 } 1318 accounts.accountCache.put(accountType, accountsForType); 1319 } 1320 accounts.visibilityCache.putAll(accountsDb.findAllVisibilityValues()); 1321 AccountManager.invalidateLocalAccountsDataCaches(); 1322 } finally { 1323 if (accountDeleted) { 1324 sendAccountsChangedBroadcast( 1325 accounts.userId, 1326 /*accountType=*/"ambiguous", 1327 /*useCase=*/"validateAccounts"); 1328 } 1329 } 1330 } 1331 } 1332 } 1333 getUidsOfInstalledOrUpdatedPackagesAsUser(int userId)1334 private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) { 1335 // Get the UIDs of all apps that might have data on the device. We want 1336 // to preserve user data if the app might otherwise be storing data. 1337 List<PackageInfo> pkgsWithData = 1338 mPackageManager.getInstalledPackagesAsUser( 1339 PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); 1340 SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size()); 1341 for (PackageInfo pkgInfo : pkgsWithData) { 1342 if (pkgInfo.applicationInfo != null 1343 && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { 1344 knownUids.put(pkgInfo.applicationInfo.uid, true); 1345 } 1346 } 1347 return knownUids; 1348 } 1349 getAuthenticatorTypeAndUIDForUser( Context context, int userId)1350 static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser( 1351 Context context, 1352 int userId) { 1353 AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context); 1354 return getAuthenticatorTypeAndUIDForUser(authCache, userId); 1355 } 1356 getAuthenticatorTypeAndUIDForUser( IAccountAuthenticatorCache authCache, int userId)1357 private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser( 1358 IAccountAuthenticatorCache authCache, 1359 int userId) { 1360 HashMap<String, Integer> knownAuth = new LinkedHashMap<>(); 1361 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache 1362 .getAllServices(userId)) { 1363 knownAuth.put(service.type.type, service.uid); 1364 } 1365 return knownAuth; 1366 } 1367 getUserAccountsForCaller()1368 private UserAccounts getUserAccountsForCaller() { 1369 return getUserAccounts(UserHandle.getCallingUserId()); 1370 } 1371 getUserAccounts(int userId)1372 protected UserAccounts getUserAccounts(int userId) { 1373 try { 1374 return getUserAccountsNotChecked(userId); 1375 } catch (RuntimeException e) { 1376 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { 1377 // Let it go... 1378 throw e; 1379 } 1380 // User accounts database is corrupted, we must wipe out the whole user, otherwise the 1381 // system will crash indefinitely 1382 Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its " 1383 + "account database"); 1384 if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) { 1385 Slog.i(TAG, "Switching to system user first"); 1386 try { 1387 ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM); 1388 } catch (RemoteException re) { 1389 Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re); 1390 } 1391 } 1392 if (!getUserManager().removeUserEvenWhenDisallowed(userId)) { 1393 Slog.e(TAG, "could not remove user " + userId); 1394 } 1395 throw e; 1396 } 1397 } 1398 getUserAccountsNotChecked(int userId)1399 private UserAccounts getUserAccountsNotChecked(int userId) { 1400 synchronized (mUsers) { 1401 UserAccounts accounts = mUsers.get(userId); 1402 boolean validateAccounts = false; 1403 if (accounts == null) { 1404 File preNDbFile = new File(mInjector.getPreNDatabaseName(userId)); 1405 File deDbFile = new File(mInjector.getDeDatabaseName(userId)); 1406 accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile); 1407 mUsers.append(userId, accounts); 1408 purgeOldGrants(accounts); 1409 AccountManager.invalidateLocalAccountsDataCaches(); 1410 validateAccounts = true; 1411 } 1412 // open CE database if necessary 1413 if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) { 1414 Log.i(TAG, "User " + userId + " is unlocked - opening CE database"); 1415 synchronized (accounts.dbLock) { 1416 synchronized (accounts.cacheLock) { 1417 File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId)); 1418 accounts.accountsDb.attachCeDatabase(ceDatabaseFile); 1419 } 1420 } 1421 syncDeCeAccountsLocked(accounts); 1422 } 1423 if (validateAccounts) { 1424 validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */); 1425 } 1426 return accounts; 1427 } 1428 } 1429 syncDeCeAccountsLocked(UserAccounts accounts)1430 private void syncDeCeAccountsLocked(UserAccounts accounts) { 1431 Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held"); 1432 List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe(); 1433 if (!accountsToRemove.isEmpty()) { 1434 Slog.i(TAG, accountsToRemove.size() 1435 + " accounts were previously deleted while user " 1436 + accounts.userId + " was locked. Removing accounts from CE tables"); 1437 logRecord(accounts, AccountsDb.DEBUG_ACTION_SYNC_DE_CE_ACCOUNTS, 1438 AccountsDb.TABLE_ACCOUNTS); 1439 1440 for (Account account : accountsToRemove) { 1441 removeAccountInternal(accounts, account, Process.SYSTEM_UID); 1442 } 1443 } 1444 } 1445 purgeOldGrantsAll()1446 private void purgeOldGrantsAll() { 1447 synchronized (mUsers) { 1448 for (int i = 0; i < mUsers.size(); i++) { 1449 purgeOldGrants(mUsers.valueAt(i)); 1450 } 1451 } 1452 } 1453 purgeOldGrants(UserAccounts accounts)1454 private void purgeOldGrants(UserAccounts accounts) { 1455 synchronized (accounts.dbLock) { 1456 synchronized (accounts.cacheLock) { 1457 List<Integer> uids; 1458 try { 1459 uids = accounts.accountsDb.findAllUidGrants(); 1460 } catch (SQLiteCantOpenDatabaseException e) { 1461 Log.w(TAG, "Could not delete grants for user = " + accounts.userId); 1462 return; 1463 } 1464 for (int uid : uids) { 1465 final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null; 1466 if (packageExists) { 1467 continue; 1468 } 1469 Log.d(TAG, "deleting grants for UID " + uid 1470 + " because its package is no longer installed"); 1471 accounts.accountsDb.deleteGrantsByUid(uid); 1472 } 1473 } 1474 } 1475 } 1476 removeVisibilityValuesForPackage(String packageName)1477 private void removeVisibilityValuesForPackage(String packageName) { 1478 if (isSpecialPackageKey(packageName)) { 1479 return; 1480 } 1481 synchronized (mUsers) { 1482 int numberOfUsers = mUsers.size(); 1483 for (int i = 0; i < numberOfUsers; i++) { 1484 UserAccounts accounts = mUsers.valueAt(i); 1485 try { 1486 mPackageManager.getPackageUidAsUser(packageName, accounts.userId); 1487 } catch (NameNotFoundException e) { 1488 // package does not exist - remove visibility values 1489 try { 1490 accounts.accountsDb.deleteAccountVisibilityForPackage(packageName); 1491 } catch (SQLiteCantOpenDatabaseException sqlException) { 1492 Log.w(TAG, "Could not delete account visibility for user = " 1493 + accounts.userId, sqlException); 1494 continue; 1495 } 1496 synchronized (accounts.dbLock) { 1497 synchronized (accounts.cacheLock) { 1498 for (Account account : accounts.visibilityCache.keySet()) { 1499 Map<String, Integer> accountVisibility = 1500 getPackagesAndVisibilityForAccountLocked(account, accounts); 1501 accountVisibility.remove(packageName); 1502 } 1503 AccountManager.invalidateLocalAccountsDataCaches(); 1504 } 1505 } 1506 } 1507 } 1508 } 1509 } 1510 purgeUserData(int userId)1511 private void purgeUserData(int userId) { 1512 UserAccounts accounts; 1513 synchronized (mUsers) { 1514 accounts = mUsers.get(userId); 1515 mUsers.remove(userId); 1516 mLocalUnlockedUsers.delete(userId); 1517 AccountManager.invalidateLocalAccountsDataCaches(); 1518 } 1519 if (accounts != null) { 1520 synchronized (accounts.dbLock) { 1521 synchronized (accounts.cacheLock) { 1522 accounts.accountsDb.closeDebugStatement(); 1523 accounts.accountsDb.close(); 1524 } 1525 } 1526 } 1527 } 1528 1529 @VisibleForTesting onUserUnlocked(Intent intent)1530 void onUserUnlocked(Intent intent) { 1531 onUnlockUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)); 1532 } 1533 onUnlockUser(int userId)1534 void onUnlockUser(int userId) { 1535 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1536 Log.v(TAG, "onUserUnlocked " + userId); 1537 } 1538 synchronized (mUsers) { 1539 mLocalUnlockedUsers.put(userId, true); 1540 } 1541 if (userId < 1) return; 1542 mHandler.post(() -> syncSharedAccounts(userId)); 1543 } 1544 syncSharedAccounts(int userId)1545 private void syncSharedAccounts(int userId) { 1546 // Check if there's a shared account that needs to be created as an account 1547 Account[] sharedAccounts = getSharedAccountsAsUser(userId); 1548 if (sharedAccounts == null || sharedAccounts.length == 0) return; 1549 Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName()); 1550 int parentUserId = UserHandle.USER_SYSTEM; 1551 for (Account sa : sharedAccounts) { 1552 if (ArrayUtils.contains(accounts, sa)) continue; 1553 // Account doesn't exist. Copy it now. 1554 copyAccountToUser(null /*no response*/, sa, parentUserId, userId); 1555 } 1556 } 1557 1558 @Override onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed)1559 public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) { 1560 UserInfo user = getUserManager().getUserInfo(userId); 1561 if (user == null) { 1562 Log.w(TAG, "onServiceChanged: ignore removed user " + userId); 1563 return; 1564 } 1565 validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */); 1566 } 1567 1568 @Override getPassword(Account account)1569 public String getPassword(Account account) { 1570 int callingUid = Binder.getCallingUid(); 1571 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1572 Log.v(TAG, "getPassword: " + account 1573 + ", caller's uid " + Binder.getCallingUid() 1574 + ", pid " + Binder.getCallingPid()); 1575 } 1576 if (account == null) throw new IllegalArgumentException("account is null"); 1577 int userId = UserHandle.getCallingUserId(); 1578 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 1579 String msg = String.format( 1580 "uid %s cannot get secrets for accounts of type: %s", 1581 callingUid, 1582 account.type); 1583 throw new SecurityException(msg); 1584 } 1585 final long identityToken = clearCallingIdentity(); 1586 try { 1587 UserAccounts accounts = getUserAccounts(userId); 1588 return readPasswordInternal(accounts, account); 1589 } finally { 1590 restoreCallingIdentity(identityToken); 1591 } 1592 } 1593 readPasswordInternal(UserAccounts accounts, Account account)1594 private String readPasswordInternal(UserAccounts accounts, Account account) { 1595 if (account == null) { 1596 return null; 1597 } 1598 if (!isLocalUnlockedUser(accounts.userId)) { 1599 Log.w(TAG, "Password is not available - user " + accounts.userId + " data is locked"); 1600 return null; 1601 } 1602 1603 synchronized (accounts.dbLock) { 1604 synchronized (accounts.cacheLock) { 1605 return accounts.accountsDb 1606 .findAccountPasswordByNameAndType(account.name, account.type); 1607 } 1608 } 1609 } 1610 1611 @Override getPreviousName(Account account)1612 public String getPreviousName(Account account) { 1613 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1614 Log.v(TAG, "getPreviousName: " + account 1615 + ", caller's uid " + Binder.getCallingUid() 1616 + ", pid " + Binder.getCallingPid()); 1617 } 1618 Objects.requireNonNull(account, "account cannot be null"); 1619 int userId = UserHandle.getCallingUserId(); 1620 final long identityToken = clearCallingIdentity(); 1621 try { 1622 UserAccounts accounts = getUserAccounts(userId); 1623 return readPreviousNameInternal(accounts, account); 1624 } finally { 1625 restoreCallingIdentity(identityToken); 1626 } 1627 } 1628 readPreviousNameInternal(UserAccounts accounts, Account account)1629 private String readPreviousNameInternal(UserAccounts accounts, Account account) { 1630 if (account == null) { 1631 return null; 1632 } 1633 synchronized (accounts.dbLock) { 1634 synchronized (accounts.cacheLock) { 1635 AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account); 1636 if (previousNameRef == null) { 1637 String previousName = accounts.accountsDb.findDeAccountPreviousName(account); 1638 previousNameRef = new AtomicReference<>(previousName); 1639 accounts.previousNameCache.put(account, previousNameRef); 1640 return previousName; 1641 } else { 1642 return previousNameRef.get(); 1643 } 1644 } 1645 } 1646 } 1647 1648 @Override getUserData(Account account, String key)1649 public String getUserData(Account account, String key) { 1650 final int callingUid = Binder.getCallingUid(); 1651 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1652 String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s", 1653 account, key, callingUid, Binder.getCallingPid()); 1654 Log.v(TAG, msg); 1655 } 1656 Objects.requireNonNull(account, "account cannot be null"); 1657 Objects.requireNonNull(key, "key cannot be null"); 1658 int userId = UserHandle.getCallingUserId(); 1659 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 1660 String msg = String.format( 1661 "uid %s cannot get user data for accounts of type: %s", 1662 callingUid, 1663 account.type); 1664 throw new SecurityException(msg); 1665 } 1666 if (!isLocalUnlockedUser(userId)) { 1667 Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid); 1668 return null; 1669 } 1670 final long identityToken = clearCallingIdentity(); 1671 try { 1672 UserAccounts accounts = getUserAccounts(userId); 1673 if (!accountExistsCache(accounts, account)) { 1674 return null; 1675 } 1676 return readUserDataInternal(accounts, account, key); 1677 } finally { 1678 restoreCallingIdentity(identityToken); 1679 } 1680 } 1681 1682 @Override getAuthenticatorTypes(int userId)1683 public AuthenticatorDescription[] getAuthenticatorTypes(int userId) { 1684 int callingUid = Binder.getCallingUid(); 1685 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1686 Log.v(TAG, "getAuthenticatorTypes: " 1687 + "for user id " + userId 1688 + " caller's uid " + callingUid 1689 + ", pid " + Binder.getCallingPid()); 1690 } 1691 // Only allow the system process to read accounts of other users 1692 if (isCrossUser(callingUid, userId)) { 1693 throw new SecurityException( 1694 String.format( 1695 "User %s tying to get authenticator types for %s" , 1696 UserHandle.getCallingUserId(), 1697 userId)); 1698 } 1699 1700 final long identityToken = clearCallingIdentity(); 1701 try { 1702 return getAuthenticatorTypesInternal(userId, callingUid); 1703 1704 } finally { 1705 restoreCallingIdentity(identityToken); 1706 } 1707 } 1708 1709 /** 1710 * Should only be called inside of a clearCallingIdentity block. 1711 */ getAuthenticatorTypesInternal(int userId, int callingUid)1712 private AuthenticatorDescription[] getAuthenticatorTypesInternal(int userId, int callingUid) { 1713 mAuthenticatorCache.updateServices(userId); 1714 Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>> 1715 authenticatorCollection = mAuthenticatorCache.getAllServices(userId); 1716 final List<AuthenticatorDescription> types = 1717 new ArrayList<>(authenticatorCollection.size()); 1718 for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator 1719 : authenticatorCollection) { 1720 if (canCallerAccessPackage(authenticator.type.packageName, callingUid, userId)) { 1721 types.add(authenticator.type); 1722 } 1723 } 1724 return types.toArray(new AuthenticatorDescription[types.size()]); 1725 } 1726 isCrossUser(int callingUid, int userId)1727 private boolean isCrossUser(int callingUid, int userId) { 1728 return (userId != UserHandle.getCallingUserId() 1729 && callingUid != Process.SYSTEM_UID 1730 && mContext.checkCallingOrSelfPermission( 1731 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) 1732 != PackageManager.PERMISSION_GRANTED); 1733 } 1734 1735 @Override addAccountExplicitly( Account account, String password, Bundle extras, String opPackageName)1736 public boolean addAccountExplicitly( 1737 Account account, String password, Bundle extras, String opPackageName) { 1738 return addAccountExplicitlyWithVisibility( 1739 account, password, extras, /* packageToVisibility= */ null, opPackageName); 1740 } 1741 1742 @Override copyAccountToUser(final IAccountManagerResponse response, final Account account, final int userFrom, int userTo)1743 public void copyAccountToUser(final IAccountManagerResponse response, final Account account, 1744 final int userFrom, int userTo) { 1745 int callingUid = Binder.getCallingUid(); 1746 if (isCrossUser(callingUid, UserHandle.USER_ALL)) { 1747 throw new SecurityException("Calling copyAccountToUser requires " 1748 + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL); 1749 } 1750 final UserAccounts fromAccounts = getUserAccounts(userFrom); 1751 final UserAccounts toAccounts = getUserAccounts(userTo); 1752 if (fromAccounts == null || toAccounts == null) { 1753 if (response != null) { 1754 Bundle result = new Bundle(); 1755 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false); 1756 try { 1757 response.onResult(result); 1758 } catch (RemoteException e) { 1759 Slog.w(TAG, "Failed to report error back to the client." + e); 1760 } 1761 } 1762 return; 1763 } 1764 1765 Slog.d(TAG, "Copying account " + account.toSafeString() 1766 + " from user " + userFrom + " to user " + userTo); 1767 final long identityToken = clearCallingIdentity(); 1768 try { 1769 new Session(fromAccounts, response, account.type, false, 1770 false /* stripAuthTokenFromResult */, account.name, 1771 false /* authDetailsRequired */) { 1772 @Override 1773 protected String toDebugString(long now) { 1774 return super.toDebugString(now) + ", getAccountCredentialsForClone" 1775 + ", " + account.type; 1776 } 1777 1778 @Override 1779 public void run() throws RemoteException { 1780 mAuthenticator.getAccountCredentialsForCloning(this, account); 1781 } 1782 1783 @Override 1784 public void onResult(Bundle result) { 1785 Bundle.setDefusable(result, true); 1786 if (result != null 1787 && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { 1788 // Create a Session for the target user and pass in the bundle 1789 completeCloningAccount(response, result, account, toAccounts, userFrom); 1790 } else { 1791 super.onResult(result); 1792 } 1793 } 1794 }.bind(); 1795 } finally { 1796 restoreCallingIdentity(identityToken); 1797 } 1798 } 1799 1800 @Override accountAuthenticated(final Account account)1801 public boolean accountAuthenticated(final Account account) { 1802 final int callingUid = Binder.getCallingUid(); 1803 if (Log.isLoggable(TAG, Log.VERBOSE)) { 1804 String msg = String.format( 1805 "accountAuthenticated( account: %s, callerUid: %s)", 1806 account, 1807 callingUid); 1808 Log.v(TAG, msg); 1809 } 1810 Objects.requireNonNull(account, "account cannot be null"); 1811 int userId = UserHandle.getCallingUserId(); 1812 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 1813 String msg = String.format( 1814 "uid %s cannot notify authentication for accounts of type: %s", 1815 callingUid, 1816 account.type); 1817 throw new SecurityException(msg); 1818 } 1819 1820 if (!canUserModifyAccounts(userId, callingUid) || 1821 !canUserModifyAccountsForType(userId, account.type, callingUid)) { 1822 return false; 1823 } 1824 1825 final long identityToken = clearCallingIdentity(); 1826 try { 1827 UserAccounts accounts = getUserAccounts(userId); 1828 return updateLastAuthenticatedTime(account); 1829 } finally { 1830 restoreCallingIdentity(identityToken); 1831 } 1832 } 1833 updateLastAuthenticatedTime(Account account)1834 private boolean updateLastAuthenticatedTime(Account account) { 1835 final UserAccounts accounts = getUserAccountsForCaller(); 1836 synchronized (accounts.dbLock) { 1837 synchronized (accounts.cacheLock) { 1838 return accounts.accountsDb.updateAccountLastAuthenticatedTime(account); 1839 } 1840 } 1841 } 1842 completeCloningAccount(IAccountManagerResponse response, final Bundle accountCredentials, final Account account, final UserAccounts targetUser, final int parentUserId)1843 private void completeCloningAccount(IAccountManagerResponse response, 1844 final Bundle accountCredentials, final Account account, final UserAccounts targetUser, 1845 final int parentUserId){ 1846 Bundle.setDefusable(accountCredentials, true); 1847 final long id = clearCallingIdentity(); 1848 try { 1849 new Session(targetUser, response, account.type, false, 1850 false /* stripAuthTokenFromResult */, account.name, 1851 false /* authDetailsRequired */) { 1852 @Override 1853 protected String toDebugString(long now) { 1854 return super.toDebugString(now) + ", getAccountCredentialsForClone" 1855 + ", " + account.type; 1856 } 1857 1858 @Override 1859 public void run() throws RemoteException { 1860 // Confirm that the owner's account still exists before this step. 1861 for (Account acc : getAccounts(parentUserId, mContext.getOpPackageName())) { 1862 if (acc.equals(account)) { 1863 mAuthenticator.addAccountFromCredentials( 1864 this, account, accountCredentials); 1865 break; 1866 } 1867 } 1868 } 1869 1870 @Override 1871 public void onResult(Bundle result) { 1872 Bundle.setDefusable(result, true); 1873 // TODO: Anything to do if if succedded? 1874 // TODO: If it failed: Show error notification? Should we remove the shadow 1875 // account to avoid retries? 1876 // TODO: what we do with the visibility? 1877 1878 super.onResult(result); 1879 } 1880 1881 @Override 1882 public void onError(int errorCode, String errorMessage) { 1883 super.onError(errorCode, errorMessage); 1884 // TODO: Show error notification to user 1885 // TODO: Should we remove the shadow account so that it doesn't keep trying? 1886 } 1887 1888 }.bind(); 1889 } finally { 1890 restoreCallingIdentity(id); 1891 } 1892 } 1893 addAccountInternal(UserAccounts accounts, Account account, String password, Bundle extras, int callingUid, Map<String, Integer> packageToVisibility, String opPackageName)1894 private boolean addAccountInternal(UserAccounts accounts, Account account, String password, 1895 Bundle extras, int callingUid, Map<String, Integer> packageToVisibility, 1896 String opPackageName) { 1897 Bundle.setDefusable(extras, true); 1898 if (account == null) { 1899 return false; 1900 } 1901 if (account.name != null && account.name.length() > 200) { 1902 Log.w(TAG, "Account cannot be added - Name longer than 200 chars"); 1903 return false; 1904 } 1905 if (account.type != null && account.type.length() > 200) { 1906 Log.w(TAG, "Account cannot be added - Name longer than 200 chars"); 1907 return false; 1908 } 1909 if (!isLocalUnlockedUser(accounts.userId)) { 1910 Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user " 1911 + accounts.userId + " is locked. callingUid=" + callingUid); 1912 return false; 1913 } 1914 synchronized (accounts.dbLock) { 1915 synchronized (accounts.cacheLock) { 1916 accounts.accountsDb.beginTransaction(); 1917 try { 1918 if (accounts.accountsDb.findCeAccountId(account) >= 0) { 1919 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() 1920 + ", skipping since the account already exists"); 1921 return false; 1922 } 1923 if (accounts.accountsDb.findAllDeAccounts().size() > 100) { 1924 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() 1925 + ", skipping since more than 100 accounts on device exist"); 1926 return false; 1927 } 1928 long accountId = accounts.accountsDb.insertCeAccount(account, password); 1929 if (accountId < 0) { 1930 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() 1931 + ", skipping the DB insert failed"); 1932 return false; 1933 } 1934 // Insert into DE table 1935 if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) { 1936 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() 1937 + ", skipping the DB insert failed"); 1938 return false; 1939 } 1940 if (extras != null) { 1941 for (String key : extras.keySet()) { 1942 final String value = extras.getString(key); 1943 if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) { 1944 Log.w(TAG, "insertAccountIntoDatabase: " 1945 + account.toSafeString() 1946 + ", skipping since insertExtra failed for key " + key); 1947 return false; 1948 } else { 1949 AccountManager.invalidateLocalAccountUserDataCaches(); 1950 } 1951 } 1952 } 1953 1954 if (packageToVisibility != null) { 1955 for (Entry<String, Integer> entry : packageToVisibility.entrySet()) { 1956 setAccountVisibility(account, entry.getKey() /* package */, 1957 entry.getValue() /* visibility */, false /* notify */, 1958 accounts, callingUid); 1959 } 1960 } 1961 accounts.accountsDb.setTransactionSuccessful(); 1962 1963 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, 1964 accountId, 1965 accounts, callingUid); 1966 1967 insertAccountIntoCacheLocked(accounts, account); 1968 } finally { 1969 accounts.accountsDb.endTransaction(); 1970 } 1971 } 1972 } 1973 if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) { 1974 addAccountToLinkedRestrictedUsers(account, accounts.userId); 1975 } 1976 1977 sendNotificationAccountUpdated(account, accounts); 1978 // Only send LOGIN_ACCOUNTS_CHANGED when the database changed. 1979 Log.i(TAG, "callingUid=" + callingUid + ", userId=" + accounts.userId 1980 + " added account"); 1981 sendAccountsChangedBroadcast(accounts.userId, account.type, /*useCase=*/"addAccount"); 1982 1983 logAddAccountExplicitlyMetrics(opPackageName, account.type, packageToVisibility); 1984 return true; 1985 } 1986 logAddAccountExplicitlyMetrics( String callerPackage, String accountType, @Nullable Map<String, Integer> accountVisibility)1987 private void logAddAccountExplicitlyMetrics( 1988 String callerPackage, String accountType, 1989 @Nullable Map<String, Integer> accountVisibility) { 1990 // Although this is not a 'device policy' API, enterprise is the current use case. 1991 DevicePolicyEventLogger 1992 .createEvent(DevicePolicyEnums.ADD_ACCOUNT_EXPLICITLY) 1993 .setStrings( 1994 TextUtils.emptyIfNull(accountType), 1995 TextUtils.emptyIfNull(callerPackage), 1996 findPackagesPerVisibility(accountVisibility)) 1997 .write(); 1998 } 1999 findPackagesPerVisibility(@ullable Map<String, Integer> accountVisibility)2000 private String[] findPackagesPerVisibility(@Nullable Map<String, Integer> accountVisibility) { 2001 Map<Integer, Set<String>> packagesPerVisibility = new HashMap<>(); 2002 if (accountVisibility != null) { 2003 for (Entry<String, Integer> entry : accountVisibility.entrySet()) { 2004 if (!packagesPerVisibility.containsKey(entry.getValue())) { 2005 packagesPerVisibility.put(entry.getValue(), new HashSet<>()); 2006 } 2007 packagesPerVisibility.get(entry.getValue()).add(entry.getKey()); 2008 } 2009 } 2010 2011 String[] packagesPerVisibilityStr = new String[5]; 2012 packagesPerVisibilityStr[AccountManager.VISIBILITY_UNDEFINED] = getPackagesForVisibilityStr( 2013 AccountManager.VISIBILITY_UNDEFINED, packagesPerVisibility); 2014 packagesPerVisibilityStr[AccountManager.VISIBILITY_VISIBLE] = getPackagesForVisibilityStr( 2015 AccountManager.VISIBILITY_VISIBLE, packagesPerVisibility); 2016 packagesPerVisibilityStr[AccountManager.VISIBILITY_USER_MANAGED_VISIBLE] = 2017 getPackagesForVisibilityStr( 2018 AccountManager.VISIBILITY_USER_MANAGED_VISIBLE, packagesPerVisibility); 2019 packagesPerVisibilityStr[AccountManager.VISIBILITY_NOT_VISIBLE] = 2020 getPackagesForVisibilityStr( 2021 AccountManager.VISIBILITY_NOT_VISIBLE, packagesPerVisibility); 2022 packagesPerVisibilityStr[AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE] = 2023 getPackagesForVisibilityStr( 2024 AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE, packagesPerVisibility); 2025 return packagesPerVisibilityStr; 2026 } 2027 getPackagesForVisibilityStr( int visibility, Map<Integer, Set<String>> packagesPerVisibility)2028 private String getPackagesForVisibilityStr( 2029 int visibility, Map<Integer, Set<String>> packagesPerVisibility) { 2030 return visibility + ":" 2031 + (packagesPerVisibility.containsKey(visibility) 2032 ? TextUtils.join(",", packagesPerVisibility.get(visibility)) 2033 : ""); 2034 } 2035 isLocalUnlockedUser(int userId)2036 private boolean isLocalUnlockedUser(int userId) { 2037 synchronized (mUsers) { 2038 return mLocalUnlockedUsers.get(userId); 2039 } 2040 } 2041 2042 /** 2043 * Adds the account to all linked restricted users as shared accounts. If the user is currently 2044 * running, then clone the account too. 2045 * @param account the account to share with limited users 2046 * 2047 */ addAccountToLinkedRestrictedUsers(Account account, int parentUserId)2048 private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) { 2049 List<UserInfo> users = getUserManager().getUsers(); 2050 for (UserInfo user : users) { 2051 if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) { 2052 addSharedAccountAsUser(account, user.id); 2053 if (isLocalUnlockedUser(user.id)) { 2054 mHandler.sendMessage(mHandler.obtainMessage( 2055 MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account)); 2056 } 2057 } 2058 } 2059 } 2060 2061 @Override hasFeatures(IAccountManagerResponse response, Account account, String[] features, int userId, String opPackageName)2062 public void hasFeatures(IAccountManagerResponse response, 2063 Account account, String[] features, int userId, String opPackageName) { 2064 int callingUid = Binder.getCallingUid(); 2065 mAppOpsManager.checkPackage(callingUid, opPackageName); 2066 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2067 Log.v(TAG, "hasFeatures: " + account 2068 + ", response " + response 2069 + ", features " + Arrays.toString(features) 2070 + ", caller's uid " + callingUid 2071 + ", userId " + userId 2072 + ", pid " + Binder.getCallingPid()); 2073 } 2074 Preconditions.checkArgument(account != null, "account cannot be null"); 2075 Preconditions.checkArgument(response != null, "response cannot be null"); 2076 Preconditions.checkArgument(features != null, "features cannot be null"); 2077 2078 if (userId != UserHandle.getCallingUserId() 2079 && callingUid != Process.SYSTEM_UID 2080 && mContext.checkCallingOrSelfPermission( 2081 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) 2082 != PackageManager.PERMISSION_GRANTED) { 2083 throw new SecurityException("User " + UserHandle.getCallingUserId() 2084 + " trying to check account features for " + userId); 2085 } 2086 2087 checkReadAccountsPermitted(callingUid, account.type, userId, 2088 opPackageName); 2089 2090 final long identityToken = clearCallingIdentity(); 2091 try { 2092 UserAccounts accounts = getUserAccounts(userId); 2093 new TestFeaturesSession(accounts, response, account, features).bind(); 2094 } finally { 2095 restoreCallingIdentity(identityToken); 2096 } 2097 } 2098 2099 private class TestFeaturesSession extends Session { 2100 private final String[] mFeatures; 2101 private final Account mAccount; 2102 TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response, Account account, String[] features)2103 public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response, 2104 Account account, String[] features) { 2105 super(accounts, response, account.type, false /* expectActivityLaunch */, 2106 true /* stripAuthTokenFromResult */, account.name, 2107 false /* authDetailsRequired */); 2108 mFeatures = features; 2109 mAccount = account; 2110 } 2111 2112 @Override run()2113 public void run() throws RemoteException { 2114 try { 2115 mAuthenticator.hasFeatures(this, mAccount, mFeatures); 2116 } catch (RemoteException e) { 2117 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception"); 2118 } 2119 } 2120 2121 @Override onResult(Bundle result)2122 public void onResult(Bundle result) { 2123 Bundle.setDefusable(result, true); 2124 IAccountManagerResponse response = getResponseAndClose(); 2125 if (response != null) { 2126 try { 2127 if (result == null) { 2128 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle"); 2129 return; 2130 } 2131 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2132 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response " 2133 + response); 2134 } 2135 final Bundle newResult = new Bundle(); 2136 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, 2137 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)); 2138 response.onResult(newResult); 2139 } catch (RemoteException e) { 2140 // if the caller is dead then there is no one to care about remote exceptions 2141 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2142 Log.v(TAG, "failure while notifying response", e); 2143 } 2144 } 2145 } 2146 } 2147 2148 @Override toDebugString(long now)2149 protected String toDebugString(long now) { 2150 return super.toDebugString(now) + ", hasFeatures" 2151 + ", " + mAccount 2152 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null); 2153 } 2154 } 2155 2156 @Override renameAccount( IAccountManagerResponse response, Account accountToRename, String newName)2157 public void renameAccount( 2158 IAccountManagerResponse response, Account accountToRename, String newName) { 2159 final int callingUid = Binder.getCallingUid(); 2160 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2161 Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName 2162 + ", caller's uid " + callingUid 2163 + ", pid " + Binder.getCallingPid()); 2164 } 2165 if (accountToRename == null) throw new IllegalArgumentException("account is null"); 2166 if (newName != null && newName.length() > 200) { 2167 Log.e(TAG, "renameAccount failed - account name longer than 200"); 2168 throw new IllegalArgumentException("account name longer than 200"); 2169 } 2170 int userId = UserHandle.getCallingUserId(); 2171 if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) { 2172 String msg = String.format( 2173 "uid %s cannot rename accounts of type: %s", 2174 callingUid, 2175 accountToRename.type); 2176 throw new SecurityException(msg); 2177 } 2178 final long identityToken = clearCallingIdentity(); 2179 try { 2180 UserAccounts accounts = getUserAccounts(userId); 2181 Log.i(TAG, "callingUid=" + callingUid + ", userId=" + accounts.userId 2182 + " performing rename account"); 2183 Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName); 2184 Bundle result = new Bundle(); 2185 result.putString(AccountManager.KEY_ACCOUNT_NAME, resultingAccount.name); 2186 result.putString(AccountManager.KEY_ACCOUNT_TYPE, resultingAccount.type); 2187 result.putString(AccountManager.KEY_ACCOUNT_ACCESS_ID, 2188 resultingAccount.getAccessId()); 2189 try { 2190 response.onResult(result); 2191 } catch (RemoteException e) { 2192 Log.w(TAG, e.getMessage()); 2193 } 2194 } finally { 2195 restoreCallingIdentity(identityToken); 2196 } 2197 } 2198 renameAccountInternal( UserAccounts accounts, Account accountToRename, String newName)2199 private Account renameAccountInternal( 2200 UserAccounts accounts, Account accountToRename, String newName) { 2201 Account resultAccount = null; 2202 /* 2203 * Cancel existing notifications. Let authenticators 2204 * re-post notifications as required. But we don't know if 2205 * the authenticators have bound their notifications to 2206 * now stale account name data. 2207 * 2208 * With a rename api, we might not need to do this anymore but it 2209 * shouldn't hurt. 2210 */ 2211 cancelNotification( 2212 getSigninRequiredNotificationId(accounts, accountToRename), 2213 accounts); 2214 synchronized(accounts.credentialsPermissionNotificationIds) { 2215 for (Pair<Pair<Account, String>, Integer> pair: 2216 accounts.credentialsPermissionNotificationIds.keySet()) { 2217 if (accountToRename.equals(pair.first.first)) { 2218 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair); 2219 cancelNotification(id, accounts); 2220 } 2221 } 2222 } 2223 synchronized (accounts.dbLock) { 2224 synchronized (accounts.cacheLock) { 2225 List<String> accountRemovedReceivers = 2226 getAccountRemovedReceivers(accountToRename, accounts); 2227 accounts.accountsDb.beginTransaction(); 2228 Account renamedAccount = new Account(newName, accountToRename.type); 2229 try { 2230 if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) { 2231 Log.e(TAG, "renameAccount failed - account with new name already exists"); 2232 return null; 2233 } 2234 final long accountId = accounts.accountsDb.findDeAccountId(accountToRename); 2235 if (accountId >= 0) { 2236 accounts.accountsDb.renameCeAccount(accountId, newName); 2237 if (accounts.accountsDb.renameDeAccount( 2238 accountId, newName, accountToRename.name)) { 2239 accounts.accountsDb.setTransactionSuccessful(); 2240 } else { 2241 Log.e(TAG, "renameAccount failed"); 2242 return null; 2243 } 2244 } else { 2245 Log.e(TAG, "renameAccount failed - old account does not exist"); 2246 return null; 2247 } 2248 } finally { 2249 accounts.accountsDb.endTransaction(); 2250 } 2251 /* 2252 * Database transaction was successful. Clean up cached 2253 * data associated with the account in the user profile. 2254 */ 2255 renamedAccount = insertAccountIntoCacheLocked(accounts, renamedAccount); 2256 /* 2257 * Extract the data and token caches before removing the 2258 * old account to preserve the user data associated with 2259 * the account. 2260 */ 2261 Map<String, String> tmpData = accounts.userDataCache.get(accountToRename); 2262 Map<String, String> tmpTokens = accounts.authTokenCache.get(accountToRename); 2263 Map<String, Integer> tmpVisibility = accounts.visibilityCache.get(accountToRename); 2264 removeAccountFromCacheLocked(accounts, accountToRename); 2265 /* 2266 * Update the cached data associated with the renamed 2267 * account. 2268 */ 2269 accounts.userDataCache.put(renamedAccount, tmpData); 2270 accounts.authTokenCache.put(renamedAccount, tmpTokens); 2271 accounts.visibilityCache.put(renamedAccount, tmpVisibility); 2272 accounts.previousNameCache.put( 2273 renamedAccount, 2274 new AtomicReference<>(accountToRename.name)); 2275 resultAccount = renamedAccount; 2276 2277 int parentUserId = accounts.userId; 2278 if (canHaveProfile(parentUserId)) { 2279 /* 2280 * Owner or system user account was renamed, rename the account for 2281 * those users with which the account was shared. 2282 */ 2283 List<UserInfo> users = getUserManager().getAliveUsers(); 2284 for (UserInfo user : users) { 2285 if (user.isRestricted() 2286 && (user.restrictedProfileParentId == parentUserId)) { 2287 renameSharedAccountAsUser(accountToRename, newName, user.id); 2288 } 2289 } 2290 } 2291 2292 sendNotificationAccountUpdated(resultAccount, accounts); 2293 sendAccountsChangedBroadcast( 2294 accounts.userId, accountToRename.type, /*useCase=*/"renameAccount"); 2295 for (String packageName : accountRemovedReceivers) { 2296 sendAccountRemovedBroadcast( 2297 accountToRename, 2298 packageName, 2299 accounts.userId, 2300 /*useCase=*/"renameAccount"); 2301 } 2302 2303 AccountManager.invalidateLocalAccountsDataCaches(); 2304 AccountManager.invalidateLocalAccountUserDataCaches(); 2305 } 2306 } 2307 return resultAccount; 2308 } 2309 canHaveProfile(final int parentUserId)2310 private boolean canHaveProfile(final int parentUserId) { 2311 final UserInfo userInfo = getUserManager().getUserInfo(parentUserId); 2312 return userInfo != null && userInfo.canHaveProfile(); 2313 } 2314 2315 @Override removeAccountAsUser(IAccountManagerResponse response, Account account, boolean expectActivityLaunch, int userId)2316 public void removeAccountAsUser(IAccountManagerResponse response, Account account, 2317 boolean expectActivityLaunch, int userId) { 2318 final int callingUid = Binder.getCallingUid(); 2319 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2320 Log.v(TAG, "removeAccount: " + account 2321 + ", response " + response 2322 + ", caller's uid " + callingUid 2323 + ", pid " + Binder.getCallingPid() 2324 + ", for user id " + userId); 2325 } 2326 Preconditions.checkArgument(account != null, "account cannot be null"); 2327 Preconditions.checkArgument(response != null, "response cannot be null"); 2328 2329 // Only allow the system process to modify accounts of other users 2330 if (isCrossUser(callingUid, userId)) { 2331 throw new SecurityException( 2332 String.format( 2333 "User %s tying remove account for %s" , 2334 UserHandle.getCallingUserId(), 2335 userId)); 2336 } 2337 /* 2338 * Only the system, authenticator or profile owner should be allowed to remove accounts for 2339 * that authenticator. This will let users remove accounts (via Settings in the system) but 2340 * not arbitrary applications (like competing authenticators). 2341 */ 2342 UserHandle user = UserHandle.of(userId); 2343 if (!isAccountManagedByCaller(account.type, callingUid, user.getIdentifier()) 2344 && !isSystemUid(callingUid) 2345 && !isProfileOwner(callingUid)) { 2346 String msg = String.format( 2347 "uid %s cannot remove accounts of type: %s", 2348 callingUid, 2349 account.type); 2350 throw new SecurityException(msg); 2351 } 2352 if (!canUserModifyAccounts(userId, callingUid)) { 2353 try { 2354 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED, 2355 "User cannot modify accounts"); 2356 } catch (RemoteException re) { 2357 } 2358 return; 2359 } 2360 if (!canUserModifyAccountsForType(userId, account.type, callingUid)) { 2361 try { 2362 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 2363 "User cannot modify accounts of this type (policy)."); 2364 } catch (RemoteException re) { 2365 Log.w(TAG, "RemoteException while removing account", re); 2366 } 2367 return; 2368 } 2369 if (isFirstAccountRemovalDisabled(account)) { 2370 try { 2371 response.onError( 2372 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 2373 "User cannot remove the first " 2374 + account.type 2375 + " account on the device."); 2376 } catch (RemoteException re) { 2377 Log.w(TAG, "RemoteException while removing account", re); 2378 } 2379 return; 2380 } 2381 final long identityToken = clearCallingIdentity(); 2382 UserAccounts accounts = getUserAccounts(userId); 2383 cancelNotification(getSigninRequiredNotificationId(accounts, account), accounts); 2384 synchronized(accounts.credentialsPermissionNotificationIds) { 2385 for (Pair<Pair<Account, String>, Integer> pair: 2386 accounts.credentialsPermissionNotificationIds.keySet()) { 2387 if (account.equals(pair.first.first)) { 2388 NotificationId id = accounts.credentialsPermissionNotificationIds.get(pair); 2389 cancelNotification(id, accounts); 2390 } 2391 } 2392 } 2393 final long accountId = accounts.accountsDb.findDeAccountId(account); 2394 logRecord( 2395 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE, 2396 AccountsDb.TABLE_ACCOUNTS, 2397 accountId, 2398 accounts, 2399 callingUid); 2400 try { 2401 new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind(); 2402 } finally { 2403 restoreCallingIdentity(identityToken); 2404 } 2405 } 2406 2407 @Override removeAccountExplicitly(Account account)2408 public boolean removeAccountExplicitly(Account account) { 2409 final int callingUid = Binder.getCallingUid(); 2410 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2411 Log.v(TAG, "removeAccountExplicitly: " + account 2412 + ", caller's uid " + callingUid 2413 + ", pid " + Binder.getCallingPid()); 2414 } 2415 int userId = Binder.getCallingUserHandle().getIdentifier(); 2416 if (account == null) { 2417 /* 2418 * Null accounts should result in returning false, as per 2419 * AccountManage.addAccountExplicitly(...) java doc. 2420 */ 2421 Log.e(TAG, "account is null"); 2422 return false; 2423 } else if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2424 String msg = String.format( 2425 "uid %s cannot explicitly remove accounts of type: %s", 2426 callingUid, 2427 account.type); 2428 throw new SecurityException(msg); 2429 } 2430 if (isFirstAccountRemovalDisabled(account)) { 2431 Log.e(TAG, "Cannot remove the first " + account.type + " account on the device."); 2432 return false; 2433 } 2434 UserAccounts accounts = getUserAccountsForCaller(); 2435 final long accountId = accounts.accountsDb.findDeAccountId(account); 2436 logRecord( 2437 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE, 2438 AccountsDb.TABLE_ACCOUNTS, 2439 accountId, 2440 accounts, 2441 callingUid); 2442 final long identityToken = clearCallingIdentity(); 2443 try { 2444 return removeAccountInternal(accounts, account, callingUid); 2445 } finally { 2446 restoreCallingIdentity(identityToken); 2447 } 2448 } 2449 2450 private class RemoveAccountSession extends Session { 2451 final Account mAccount; RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response, Account account, boolean expectActivityLaunch)2452 public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response, 2453 Account account, boolean expectActivityLaunch) { 2454 super(accounts, response, account.type, expectActivityLaunch, 2455 true /* stripAuthTokenFromResult */, account.name, 2456 false /* authDetailsRequired */); 2457 mAccount = account; 2458 } 2459 2460 @Override toDebugString(long now)2461 protected String toDebugString(long now) { 2462 return super.toDebugString(now) + ", removeAccount" 2463 + ", account " + mAccount; 2464 } 2465 2466 @Override run()2467 public void run() throws RemoteException { 2468 mAuthenticator.getAccountRemovalAllowed(this, mAccount); 2469 } 2470 2471 @Override onResult(Bundle result)2472 public void onResult(Bundle result) { 2473 Bundle.setDefusable(result, true); 2474 if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT) 2475 && !result.containsKey(AccountManager.KEY_INTENT)) { 2476 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT); 2477 if (removalAllowed) { 2478 removeAccountInternal(mAccounts, mAccount, getCallingUid()); 2479 } 2480 IAccountManagerResponse response = getResponseAndClose(); 2481 if (response != null) { 2482 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2483 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response " 2484 + response); 2485 } 2486 try { 2487 response.onResult(result); 2488 } catch (RemoteException e) { 2489 Slog.e(TAG, "Error calling onResult()", e); 2490 } 2491 } 2492 } 2493 super.onResult(result); 2494 } 2495 } 2496 2497 @VisibleForTesting removeAccountInternal(Account account)2498 protected void removeAccountInternal(Account account) { 2499 removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid()); 2500 } 2501 removeAccountInternal(UserAccounts accounts, Account account, int callingUid)2502 private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) { 2503 boolean isChanged = false; 2504 boolean userUnlocked = isLocalUnlockedUser(accounts.userId); 2505 if (!userUnlocked) { 2506 Slog.i(TAG, "Removing account " + account.toSafeString() 2507 + " while user " + accounts.userId 2508 + " is still locked. CE data will be removed later"); 2509 } 2510 synchronized (accounts.dbLock) { 2511 synchronized (accounts.cacheLock) { 2512 Map<String, Integer> packagesToVisibility = getRequestingPackages(account, 2513 accounts); 2514 List<String> accountRemovedReceivers = 2515 getAccountRemovedReceivers(account, accounts); 2516 accounts.accountsDb.beginTransaction(); 2517 // Set to a placeholder value, this will only be used if the database 2518 // transaction succeeds. 2519 long accountId = -1; 2520 try { 2521 accountId = accounts.accountsDb.findDeAccountId(account); 2522 if (accountId >= 0) { 2523 isChanged = accounts.accountsDb.deleteDeAccount(accountId); 2524 } 2525 // always delete from CE table if CE storage is available 2526 // DE account could be removed while CE was locked 2527 if (userUnlocked) { 2528 long ceAccountId = accounts.accountsDb.findCeAccountId(account); 2529 if (ceAccountId >= 0) { 2530 accounts.accountsDb.deleteCeAccount(ceAccountId); 2531 } 2532 } 2533 accounts.accountsDb.setTransactionSuccessful(); 2534 } finally { 2535 accounts.accountsDb.endTransaction(); 2536 } 2537 if (isChanged) { 2538 removeAccountFromCacheLocked(accounts, account); 2539 for (Entry<String, Integer> packageToVisibility : packagesToVisibility 2540 .entrySet()) { 2541 if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE) 2542 || (packageToVisibility.getValue() 2543 == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) { 2544 notifyPackage(packageToVisibility.getKey(), accounts); 2545 } 2546 } 2547 2548 // Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred. 2549 Log.i(TAG, "callingUid=" + callingUid + ", userId=" + accounts.userId 2550 + " removed account"); 2551 sendAccountsChangedBroadcast( 2552 accounts.userId, account.type, /*useCase=*/"removeAccount"); 2553 for (String packageName : accountRemovedReceivers) { 2554 sendAccountRemovedBroadcast( 2555 account, packageName, accounts.userId, /*useCase=*/"removeAccount"); 2556 } 2557 String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE 2558 : AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE; 2559 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts); 2560 } 2561 } 2562 } 2563 final long id = Binder.clearCallingIdentity(); 2564 try { 2565 int parentUserId = accounts.userId; 2566 if (canHaveProfile(parentUserId)) { 2567 // Remove from any restricted profiles that are sharing this account. 2568 List<UserInfo> users = getUserManager().getAliveUsers(); 2569 for (UserInfo user : users) { 2570 if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) { 2571 removeSharedAccountAsUser(account, user.id, callingUid); 2572 } 2573 } 2574 } 2575 } finally { 2576 Binder.restoreCallingIdentity(id); 2577 } 2578 2579 if (isChanged) { 2580 synchronized (accounts.credentialsPermissionNotificationIds) { 2581 for (Pair<Pair<Account, String>, Integer> key 2582 : accounts.credentialsPermissionNotificationIds.keySet()) { 2583 if (account.equals(key.first.first) 2584 && AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE.equals(key.first.second)) { 2585 final int uid = (Integer) key.second; 2586 mHandler.post(() -> cancelAccountAccessRequestNotificationIfNeeded( 2587 account, uid, false, accounts)); 2588 } 2589 } 2590 } 2591 } 2592 2593 AccountManager.invalidateLocalAccountUserDataCaches(); 2594 2595 return isChanged; 2596 } 2597 2598 @Override invalidateAuthToken(String accountType, String authToken)2599 public void invalidateAuthToken(String accountType, String authToken) { 2600 int callerUid = Binder.getCallingUid(); 2601 Objects.requireNonNull(accountType, "accountType cannot be null"); 2602 Objects.requireNonNull(authToken, "authToken cannot be null"); 2603 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2604 Log.v(TAG, "invalidateAuthToken: accountType " + accountType 2605 + ", caller's uid " + callerUid 2606 + ", pid " + Binder.getCallingPid()); 2607 } 2608 int userId = UserHandle.getCallingUserId(); 2609 final long identityToken = clearCallingIdentity(); 2610 try { 2611 UserAccounts accounts = getUserAccounts(userId); 2612 List<Pair<Account, String>> deletedTokens; 2613 synchronized (accounts.dbLock) { 2614 accounts.accountsDb.beginTransaction(); 2615 try { 2616 deletedTokens = invalidateAuthTokenLocked(accounts, accountType, authToken); 2617 accounts.accountsDb.setTransactionSuccessful(); 2618 } finally { 2619 accounts.accountsDb.endTransaction(); 2620 } 2621 synchronized (accounts.cacheLock) { 2622 for (Pair<Account, String> tokenInfo : deletedTokens) { 2623 Account act = tokenInfo.first; 2624 String tokenType = tokenInfo.second; 2625 writeAuthTokenIntoCacheLocked(accounts, act, tokenType, null); 2626 } 2627 // wipe out cached token in memory. 2628 accounts.accountTokenCaches.remove(accountType, authToken); 2629 } 2630 } 2631 } finally { 2632 restoreCallingIdentity(identityToken); 2633 } 2634 } 2635 invalidateAuthTokenLocked(UserAccounts accounts, String accountType, String authToken)2636 private List<Pair<Account, String>> invalidateAuthTokenLocked(UserAccounts accounts, String accountType, 2637 String authToken) { 2638 // TODO Move to AccountsDB 2639 List<Pair<Account, String>> results = new ArrayList<>(); 2640 Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken); 2641 2642 try { 2643 while (cursor.moveToNext()) { 2644 String authTokenId = cursor.getString(0); 2645 String accountName = cursor.getString(1); 2646 String authTokenType = cursor.getString(2); 2647 accounts.accountsDb.deleteAuthToken(authTokenId); 2648 results.add(Pair.create(new Account(accountName, accountType), authTokenType)); 2649 } 2650 } finally { 2651 cursor.close(); 2652 } 2653 return results; 2654 } 2655 saveCachedToken( UserAccounts accounts, Account account, String callerPkg, byte[] callerSigDigest, String tokenType, String token, long expiryMillis)2656 private void saveCachedToken( 2657 UserAccounts accounts, 2658 Account account, 2659 String callerPkg, 2660 byte[] callerSigDigest, 2661 String tokenType, 2662 String token, 2663 long expiryMillis) { 2664 2665 if (account == null || tokenType == null || callerPkg == null || callerSigDigest == null) { 2666 return; 2667 } 2668 cancelNotification(getSigninRequiredNotificationId(accounts, account), accounts); 2669 synchronized (accounts.cacheLock) { 2670 accounts.accountTokenCaches.put( 2671 account, token, tokenType, callerPkg, callerSigDigest, expiryMillis); 2672 } 2673 } 2674 saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type, String authToken)2675 private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type, 2676 String authToken) { 2677 if (account == null || type == null) { 2678 return false; 2679 } 2680 cancelNotification(getSigninRequiredNotificationId(accounts, account), accounts); 2681 synchronized (accounts.dbLock) { 2682 accounts.accountsDb.beginTransaction(); 2683 boolean updateCache = false; 2684 try { 2685 long accountId = accounts.accountsDb.findDeAccountId(account); 2686 if (accountId < 0) { 2687 return false; 2688 } 2689 accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type); 2690 if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) { 2691 accounts.accountsDb.setTransactionSuccessful(); 2692 updateCache = true; 2693 return true; 2694 } 2695 return false; 2696 } finally { 2697 accounts.accountsDb.endTransaction(); 2698 if (updateCache) { 2699 synchronized (accounts.cacheLock) { 2700 writeAuthTokenIntoCacheLocked(accounts, account, type, authToken); 2701 } 2702 } 2703 } 2704 } 2705 } 2706 2707 @Override peekAuthToken(Account account, String authTokenType)2708 public String peekAuthToken(Account account, String authTokenType) { 2709 final int callingUid = Binder.getCallingUid(); 2710 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2711 Log.v(TAG, "peekAuthToken: " + account 2712 + ", authTokenType " + authTokenType 2713 + ", caller's uid " + callingUid 2714 + ", pid " + Binder.getCallingPid()); 2715 } 2716 Objects.requireNonNull(account, "account cannot be null"); 2717 Objects.requireNonNull(authTokenType, "authTokenType cannot be null"); 2718 int userId = UserHandle.getCallingUserId(); 2719 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2720 String msg = String.format( 2721 "uid %s cannot peek the authtokens associated with accounts of type: %s", 2722 callingUid, 2723 account.type); 2724 throw new SecurityException(msg); 2725 } 2726 if (!isLocalUnlockedUser(userId)) { 2727 Log.w(TAG, "Authtoken not available - user " + userId + " data is locked. callingUid " 2728 + callingUid); 2729 return null; 2730 } 2731 final long identityToken = clearCallingIdentity(); 2732 try { 2733 UserAccounts accounts = getUserAccounts(userId); 2734 return readAuthTokenInternal(accounts, account, authTokenType); 2735 } finally { 2736 restoreCallingIdentity(identityToken); 2737 } 2738 } 2739 2740 @Override setAuthToken(Account account, String authTokenType, String authToken)2741 public void setAuthToken(Account account, String authTokenType, String authToken) { 2742 final int callingUid = Binder.getCallingUid(); 2743 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2744 Log.v(TAG, "setAuthToken: " + account 2745 + ", authTokenType " + authTokenType 2746 + ", caller's uid " + callingUid 2747 + ", pid " + Binder.getCallingPid()); 2748 } 2749 Objects.requireNonNull(account, "account cannot be null"); 2750 Objects.requireNonNull(authTokenType, "authTokenType cannot be null"); 2751 int userId = UserHandle.getCallingUserId(); 2752 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2753 String msg = String.format( 2754 "uid %s cannot set auth tokens associated with accounts of type: %s", 2755 callingUid, 2756 account.type); 2757 throw new SecurityException(msg); 2758 } 2759 final long identityToken = clearCallingIdentity(); 2760 try { 2761 UserAccounts accounts = getUserAccounts(userId); 2762 saveAuthTokenToDatabase(accounts, account, authTokenType, authToken); 2763 } finally { 2764 restoreCallingIdentity(identityToken); 2765 } 2766 } 2767 2768 @Override setPassword(Account account, String password)2769 public void setPassword(Account account, String password) { 2770 final int callingUid = Binder.getCallingUid(); 2771 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2772 Log.v(TAG, "setAuthToken: " + account 2773 + ", caller's uid " + callingUid 2774 + ", pid " + Binder.getCallingPid()); 2775 } 2776 Objects.requireNonNull(account, "account cannot be null"); 2777 int userId = UserHandle.getCallingUserId(); 2778 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2779 String msg = String.format( 2780 "uid %s cannot set secrets for accounts of type: %s", 2781 callingUid, 2782 account.type); 2783 throw new SecurityException(msg); 2784 } 2785 final long identityToken = clearCallingIdentity(); 2786 try { 2787 UserAccounts accounts = getUserAccounts(userId); 2788 setPasswordInternal(accounts, account, password, callingUid); 2789 } finally { 2790 restoreCallingIdentity(identityToken); 2791 } 2792 } 2793 setPasswordInternal(UserAccounts accounts, Account account, String password, int callingUid)2794 private void setPasswordInternal(UserAccounts accounts, Account account, String password, 2795 int callingUid) { 2796 if (account == null) { 2797 return; 2798 } 2799 boolean isChanged = false; 2800 synchronized (accounts.dbLock) { 2801 synchronized (accounts.cacheLock) { 2802 accounts.accountsDb.beginTransaction(); 2803 try { 2804 final long accountId = accounts.accountsDb.findDeAccountId(account); 2805 if (accountId >= 0) { 2806 accounts.accountsDb.updateCeAccountPassword(accountId, password); 2807 accounts.accountsDb.deleteAuthTokensByAccountId(accountId); 2808 accounts.authTokenCache.remove(account); 2809 accounts.accountTokenCaches.remove(account); 2810 accounts.accountsDb.setTransactionSuccessful(); 2811 // If there is an account whose password will be updated and the database 2812 // transactions succeed, then we say that a change has occured. Even if the 2813 // new password is the same as the old and there were no authtokens to 2814 // delete. 2815 isChanged = true; 2816 String action = (password == null || password.length() == 0) ? 2817 AccountsDb.DEBUG_ACTION_CLEAR_PASSWORD 2818 : AccountsDb.DEBUG_ACTION_SET_PASSWORD; 2819 logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, 2820 callingUid); 2821 } 2822 } finally { 2823 accounts.accountsDb.endTransaction(); 2824 if (isChanged) { 2825 // Send LOGIN_ACCOUNTS_CHANGED only if the something changed. 2826 sendNotificationAccountUpdated(account, accounts); 2827 Log.i(TAG, "callingUid=" + callingUid + " changed password"); 2828 sendAccountsChangedBroadcast( 2829 accounts.userId, account.type, /*useCase=*/"setPassword"); 2830 } 2831 } 2832 } 2833 } 2834 } 2835 2836 @Override clearPassword(Account account)2837 public void clearPassword(Account account) { 2838 final int callingUid = Binder.getCallingUid(); 2839 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2840 Log.v(TAG, "clearPassword: " + account 2841 + ", caller's uid " + callingUid 2842 + ", pid " + Binder.getCallingPid()); 2843 } 2844 Objects.requireNonNull(account, "account cannot be null"); 2845 int userId = UserHandle.getCallingUserId(); 2846 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2847 String msg = String.format( 2848 "uid %s cannot clear passwords for accounts of type: %s", 2849 callingUid, 2850 account.type); 2851 throw new SecurityException(msg); 2852 } 2853 final long identityToken = clearCallingIdentity(); 2854 try { 2855 UserAccounts accounts = getUserAccounts(userId); 2856 setPasswordInternal(accounts, account, null, callingUid); 2857 } finally { 2858 restoreCallingIdentity(identityToken); 2859 } 2860 } 2861 2862 @Override setUserData(Account account, String key, String value)2863 public void setUserData(Account account, String key, String value) { 2864 final int callingUid = Binder.getCallingUid(); 2865 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2866 Log.v(TAG, "setUserData: " + account 2867 + ", key " + key 2868 + ", caller's uid " + callingUid 2869 + ", pid " + Binder.getCallingPid()); 2870 } 2871 if (key == null) throw new IllegalArgumentException("key is null"); 2872 if (account == null) throw new IllegalArgumentException("account is null"); 2873 int userId = UserHandle.getCallingUserId(); 2874 if (!isAccountManagedByCaller(account.type, callingUid, userId)) { 2875 String msg = String.format( 2876 "uid %s cannot set user data for accounts of type: %s", 2877 callingUid, 2878 account.type); 2879 throw new SecurityException(msg); 2880 } 2881 final long identityToken = clearCallingIdentity(); 2882 try { 2883 UserAccounts accounts = getUserAccounts(userId); 2884 if (!accountExistsCache(accounts, account)) { 2885 return; 2886 } 2887 setUserdataInternal(accounts, account, key, value); 2888 } finally { 2889 restoreCallingIdentity(identityToken); 2890 } 2891 } 2892 accountExistsCache(UserAccounts accounts, Account account)2893 private boolean accountExistsCache(UserAccounts accounts, Account account) { 2894 synchronized (accounts.cacheLock) { 2895 if (accounts.accountCache.containsKey(account.type)) { 2896 for (Account acc : accounts.accountCache.get(account.type)) { 2897 if (acc.name.equals(account.name)) { 2898 return true; 2899 } 2900 } 2901 } 2902 } 2903 return false; 2904 } 2905 setUserdataInternal(UserAccounts accounts, Account account, String key, String value)2906 private void setUserdataInternal(UserAccounts accounts, Account account, String key, 2907 String value) { 2908 synchronized (accounts.dbLock) { 2909 accounts.accountsDb.beginTransaction(); 2910 try { 2911 long accountId = accounts.accountsDb.findDeAccountId(account); 2912 if (accountId < 0) { 2913 return; 2914 } 2915 long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key); 2916 if (extrasId < 0) { 2917 extrasId = accounts.accountsDb.insertExtra(accountId, key, value); 2918 if (extrasId < 0) { 2919 return; 2920 } 2921 } else if (!accounts.accountsDb.updateExtra(extrasId, value)) { 2922 return; 2923 } 2924 accounts.accountsDb.setTransactionSuccessful(); 2925 } finally { 2926 accounts.accountsDb.endTransaction(); 2927 } 2928 synchronized (accounts.cacheLock) { 2929 writeUserDataIntoCacheLocked(accounts, account, key, value); 2930 AccountManager.invalidateLocalAccountUserDataCaches(); 2931 } 2932 } 2933 } 2934 onResult(IAccountManagerResponse response, Bundle result)2935 private void onResult(IAccountManagerResponse response, Bundle result) { 2936 if (result == null) { 2937 Log.e(TAG, "the result is unexpectedly null", new Exception()); 2938 } 2939 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2940 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response " 2941 + response); 2942 } 2943 try { 2944 response.onResult(result); 2945 } catch (RemoteException e) { 2946 // if the caller is dead then there is no one to care about remote 2947 // exceptions 2948 if (Log.isLoggable(TAG, Log.VERBOSE)) { 2949 Log.v(TAG, "failure while notifying response", e); 2950 } 2951 } 2952 } 2953 2954 @Override getAuthTokenLabel(IAccountManagerResponse response, final String accountType, final String authTokenType)2955 public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType, 2956 final String authTokenType) 2957 throws RemoteException { 2958 Preconditions.checkArgument(accountType != null, "accountType cannot be null"); 2959 Preconditions.checkArgument(authTokenType != null, "authTokenType cannot be null"); 2960 2961 final int callingUid = getCallingUid(); 2962 clearCallingIdentity(); 2963 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) { 2964 throw new SecurityException("can only call from system"); 2965 } 2966 int userId = UserHandle.getUserId(callingUid); 2967 final long identityToken = clearCallingIdentity(); 2968 try { 2969 UserAccounts accounts = getUserAccounts(userId); 2970 new Session(accounts, response, accountType, false /* expectActivityLaunch */, 2971 false /* stripAuthTokenFromResult */, null /* accountName */, 2972 false /* authDetailsRequired */) { 2973 @Override 2974 protected String toDebugString(long now) { 2975 return super.toDebugString(now) + ", getAuthTokenLabel" 2976 + ", " + accountType 2977 + ", authTokenType " + authTokenType; 2978 } 2979 2980 @Override 2981 public void run() throws RemoteException { 2982 mAuthenticator.getAuthTokenLabel(this, authTokenType); 2983 } 2984 2985 @Override 2986 public void onResult(Bundle result) { 2987 Bundle.setDefusable(result, true); 2988 if (result != null) { 2989 String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL); 2990 Bundle bundle = new Bundle(); 2991 bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label); 2992 super.onResult(bundle); 2993 return; 2994 } else { 2995 super.onResult(result); 2996 } 2997 } 2998 }.bind(); 2999 } finally { 3000 restoreCallingIdentity(identityToken); 3001 } 3002 } 3003 3004 @Override getAuthToken( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean notifyOnAuthFailure, final boolean expectActivityLaunch, final Bundle loginOptions)3005 public void getAuthToken( 3006 IAccountManagerResponse response, 3007 final Account account, 3008 final String authTokenType, 3009 final boolean notifyOnAuthFailure, 3010 final boolean expectActivityLaunch, 3011 final Bundle loginOptions) { 3012 Bundle.setDefusable(loginOptions, true); 3013 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3014 Log.v(TAG, "getAuthToken: " + account 3015 + ", response " + response 3016 + ", authTokenType " + authTokenType 3017 + ", notifyOnAuthFailure " + notifyOnAuthFailure 3018 + ", expectActivityLaunch " + expectActivityLaunch 3019 + ", caller's uid " + Binder.getCallingUid() 3020 + ", pid " + Binder.getCallingPid()); 3021 } 3022 Preconditions.checkArgument(response != null, "response cannot be null"); 3023 try { 3024 if (account == null) { 3025 Slog.w(TAG, "getAuthToken called with null account"); 3026 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "account is null"); 3027 return; 3028 } 3029 if (authTokenType == null) { 3030 Slog.w(TAG, "getAuthToken called with null authTokenType"); 3031 response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS, "authTokenType is null"); 3032 return; 3033 } 3034 } catch (RemoteException e) { 3035 Slog.w(TAG, "Failed to report error back to the client." + e); 3036 return; 3037 } 3038 int userId = UserHandle.getCallingUserId(); 3039 final long ident = Binder.clearCallingIdentity(); 3040 final UserAccounts accounts; 3041 final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo; 3042 try { 3043 accounts = getUserAccounts(userId); 3044 authenticatorInfo = mAuthenticatorCache.getServiceInfo( 3045 AuthenticatorDescription.newKey(account.type), accounts.userId); 3046 } finally { 3047 Binder.restoreCallingIdentity(ident); 3048 } 3049 3050 final boolean customTokens = 3051 authenticatorInfo != null && authenticatorInfo.type.customTokens; 3052 3053 // skip the check if customTokens 3054 final int callerUid = Binder.getCallingUid(); 3055 final boolean permissionGranted = 3056 customTokens || permissionIsGranted(account, authTokenType, callerUid, userId); 3057 3058 // Get the calling package. We will use it for the purpose of caching. 3059 final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME); 3060 String[] callerOwnedPackageNames; 3061 final long ident2 = Binder.clearCallingIdentity(); 3062 try { 3063 callerOwnedPackageNames = mPackageManager.getPackagesForUid(callerUid); 3064 } finally { 3065 Binder.restoreCallingIdentity(ident2); 3066 } 3067 if (callerPkg == null || callerOwnedPackageNames == null 3068 || !ArrayUtils.contains(callerOwnedPackageNames, callerPkg)) { 3069 String msg = String.format( 3070 "Uid %s is attempting to illegally masquerade as package %s!", 3071 callerUid, 3072 callerPkg); 3073 throw new SecurityException(msg); 3074 } 3075 3076 // let authenticator know the identity of the caller 3077 loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid); 3078 loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid()); 3079 3080 if (notifyOnAuthFailure) { 3081 loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true); 3082 } 3083 3084 final long identityToken = clearCallingIdentity(); 3085 try { 3086 // Distill the caller's package signatures into a single digest. 3087 final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg, userId); 3088 3089 // if the caller has permission, do the peek. otherwise go the more expensive 3090 // route of starting a Session 3091 if (!customTokens && permissionGranted) { 3092 String authToken = readAuthTokenInternal(accounts, account, authTokenType); 3093 if (authToken != null) { 3094 logGetAuthTokenMetrics(callerPkg, account.type); 3095 Bundle result = new Bundle(); 3096 result.putString(AccountManager.KEY_AUTHTOKEN, authToken); 3097 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 3098 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); 3099 onResult(response, result); 3100 return; 3101 } 3102 } 3103 3104 if (customTokens) { 3105 /* 3106 * Look up tokens in the new cache only if the loginOptions don't have parameters 3107 * outside of those expected to be injected by the AccountManager, e.g. 3108 * ANDORID_PACKAGE_NAME. 3109 */ 3110 TokenCache.Value cachedToken = readCachedTokenInternal( 3111 accounts, 3112 account, 3113 authTokenType, 3114 callerPkg, 3115 callerPkgSigDigest); 3116 if (cachedToken != null) { 3117 logGetAuthTokenMetrics(callerPkg, account.type); 3118 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3119 Log.v(TAG, "getAuthToken: cache hit ofr custom token authenticator."); 3120 } 3121 Bundle result = new Bundle(); 3122 result.putString(AccountManager.KEY_AUTHTOKEN, cachedToken.token); 3123 result.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 3124 cachedToken.expiryEpochMillis); 3125 result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 3126 result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); 3127 onResult(response, result); 3128 return; 3129 } 3130 } 3131 3132 new Session( 3133 accounts, 3134 response, 3135 account.type, 3136 expectActivityLaunch, 3137 false /* stripAuthTokenFromResult */, 3138 account.name, 3139 false /* authDetailsRequired */) { 3140 @Override 3141 protected String toDebugString(long now) { 3142 if (loginOptions != null) loginOptions.keySet(); 3143 return super.toDebugString(now) + ", getAuthToken" 3144 + ", " + account.toSafeString() 3145 + ", authTokenType " + authTokenType 3146 + ", loginOptions " + loginOptions 3147 + ", notifyOnAuthFailure " + notifyOnAuthFailure; 3148 } 3149 3150 @Override 3151 public void run() throws RemoteException { 3152 // If the caller doesn't have permission then create and return the 3153 // "grant permission" intent instead of the "getAuthToken" intent. 3154 if (!permissionGranted) { 3155 mAuthenticator.getAuthTokenLabel(this, authTokenType); 3156 } else { 3157 mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions); 3158 logGetAuthTokenMetrics(callerPkg, account.type); 3159 } 3160 } 3161 3162 @Override 3163 public void onResult(Bundle result) { 3164 Bundle.setDefusable(result, true); 3165 if (result != null) { 3166 if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) { 3167 Intent intent = newGrantCredentialsPermissionIntent( 3168 account, 3169 null, 3170 callerUid, 3171 new AccountAuthenticatorResponse(this), 3172 authTokenType, 3173 true); 3174 mCanStartAccountManagerActivity = true; 3175 Bundle bundle = new Bundle(); 3176 bundle.putParcelable(AccountManager.KEY_INTENT, intent); 3177 onResult(bundle); 3178 return; 3179 } 3180 String authToken = result.getString(AccountManager.KEY_AUTHTOKEN); 3181 if (authToken != null) { 3182 String name = result.getString(AccountManager.KEY_ACCOUNT_NAME); 3183 String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE); 3184 if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) { 3185 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 3186 "the type and name should not be empty"); 3187 return; 3188 } 3189 Account resultAccount = new Account(name, type); 3190 if (!customTokens) { 3191 saveAuthTokenToDatabase( 3192 mAccounts, 3193 resultAccount, 3194 authTokenType, 3195 authToken); 3196 } 3197 long expiryMillis = result.getLong( 3198 AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0L); 3199 if (customTokens 3200 && expiryMillis > System.currentTimeMillis()) { 3201 saveCachedToken( 3202 mAccounts, 3203 account, 3204 callerPkg, 3205 callerPkgSigDigest, 3206 authTokenType, 3207 authToken, 3208 expiryMillis); 3209 } 3210 } 3211 3212 Intent intent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class); 3213 if (intent != null && notifyOnAuthFailure && !customTokens) { 3214 /* 3215 * Make sure that the supplied intent is owned by the authenticator 3216 * giving it to the system. Otherwise a malicious authenticator could 3217 * have users launching arbitrary activities by tricking users to 3218 * interact with malicious notifications. 3219 */ 3220 if (!checkKeyIntent( 3221 Binder.getCallingUid(), 3222 result)) { 3223 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 3224 "invalid intent in bundle returned"); 3225 return; 3226 } 3227 doNotification( 3228 mAccounts, 3229 account, 3230 result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE), 3231 intent, "android", accounts.userId); 3232 } 3233 } 3234 super.onResult(result); 3235 } 3236 }.bind(); 3237 } finally { 3238 restoreCallingIdentity(identityToken); 3239 } 3240 } 3241 logGetAuthTokenMetrics(final String callerPackage, String accountType)3242 private void logGetAuthTokenMetrics(final String callerPackage, String accountType) { 3243 // Although this is not a 'device policy' API, enterprise is the current use case. 3244 DevicePolicyEventLogger 3245 .createEvent(DevicePolicyEnums.GET_ACCOUNT_AUTH_TOKEN) 3246 .setStrings( 3247 TextUtils.emptyIfNull(callerPackage), 3248 TextUtils.emptyIfNull(accountType)) 3249 .write(); 3250 } 3251 calculatePackageSignatureDigest(String callerPkg, int userId)3252 private byte[] calculatePackageSignatureDigest(String callerPkg, int userId) { 3253 MessageDigest digester; 3254 try { 3255 digester = MessageDigest.getInstance("SHA-256"); 3256 PackageInfo pkgInfo = mPackageManager.getPackageInfoAsUser( 3257 callerPkg, PackageManager.GET_SIGNATURES, userId); 3258 for (Signature sig : pkgInfo.signatures) { 3259 digester.update(sig.toByteArray()); 3260 } 3261 } catch (NoSuchAlgorithmException x) { 3262 Log.wtf(TAG, "SHA-256 should be available", x); 3263 digester = null; 3264 } catch (NameNotFoundException e) { 3265 Log.w(TAG, "Could not find packageinfo for: " + callerPkg); 3266 digester = null; 3267 } 3268 return (digester == null) ? null : digester.digest(); 3269 } 3270 createNoCredentialsPermissionNotification(Account account, Intent intent, String packageName, UserAccounts accounts)3271 private void createNoCredentialsPermissionNotification(Account account, Intent intent, 3272 String packageName, UserAccounts accounts) { 3273 int userId = accounts.userId; 3274 int uid = intent.getIntExtra( 3275 GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1); 3276 String authTokenType = intent.getStringExtra( 3277 GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE); 3278 final String titleAndSubtitle = 3279 mContext.getString(R.string.permission_request_notification_for_app_with_subtitle, 3280 getApplicationLabel(packageName, userId), account.name); 3281 final int index = titleAndSubtitle.indexOf('\n'); 3282 String title = titleAndSubtitle; 3283 String subtitle = ""; 3284 if (index > 0) { 3285 title = titleAndSubtitle.substring(0, index); 3286 subtitle = titleAndSubtitle.substring(index + 1); 3287 } 3288 UserHandle user = UserHandle.of(userId); 3289 Context contextForUser = getContextForUser(user); 3290 Notification n = 3291 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT) 3292 .setSmallIcon(android.R.drawable.stat_sys_warning) 3293 .setWhen(0) 3294 .setColor(contextForUser.getColor( 3295 com.android.internal.R.color.system_notification_accent_color)) 3296 .setContentTitle(title) 3297 .setContentText(subtitle) 3298 .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent, 3299 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, 3300 null, user)) 3301 .build(); 3302 installNotification(getCredentialPermissionNotificationId( 3303 account, authTokenType, uid, accounts), n, "android", user.getIdentifier()); 3304 } 3305 getApplicationLabel(String packageName, int userId)3306 private String getApplicationLabel(String packageName, int userId) { 3307 try { 3308 return mPackageManager.getApplicationLabel( 3309 mPackageManager.getApplicationInfoAsUser(packageName, 0, userId)).toString(); 3310 } catch (PackageManager.NameNotFoundException e) { 3311 return packageName; 3312 } 3313 } 3314 newGrantCredentialsPermissionIntent(Account account, String packageName, int uid, AccountAuthenticatorResponse response, String authTokenType, boolean startInNewTask)3315 private Intent newGrantCredentialsPermissionIntent(Account account, String packageName, 3316 int uid, AccountAuthenticatorResponse response, String authTokenType, 3317 boolean startInNewTask) { 3318 3319 Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class); 3320 3321 if (startInNewTask) { 3322 // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag. 3323 // Since it was set in Eclair+ we can't change it without breaking apps using 3324 // the intent from a non-Activity context. This is the default behavior. 3325 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3326 } 3327 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); 3328 intent.addCategory(getCredentialPermissionNotificationId(account, 3329 authTokenType, uid, accounts).mTag + (packageName != null ? packageName : "")); 3330 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account); 3331 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType); 3332 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response); 3333 intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid); 3334 3335 return intent; 3336 } 3337 getCredentialPermissionNotificationId(Account account, String authTokenType, int uid, UserAccounts accounts)3338 private NotificationId getCredentialPermissionNotificationId(Account account, 3339 String authTokenType, int uid, UserAccounts accounts) { 3340 NotificationId nId; 3341 synchronized (accounts.credentialsPermissionNotificationIds) { 3342 final Pair<Pair<Account, String>, Integer> key = 3343 new Pair<Pair<Account, String>, Integer>( 3344 new Pair<Account, String>(account, authTokenType), uid); 3345 nId = accounts.credentialsPermissionNotificationIds.get(key); 3346 if (nId == null) { 3347 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION 3348 + ":" + account.hashCode() + ":" + authTokenType.hashCode() + ":" + uid; 3349 int id = SystemMessage.NOTE_ACCOUNT_CREDENTIAL_PERMISSION; 3350 nId = new NotificationId(tag, id); 3351 accounts.credentialsPermissionNotificationIds.put(key, nId); 3352 } 3353 } 3354 return nId; 3355 } 3356 getSigninRequiredNotificationId(UserAccounts accounts, Account account)3357 private NotificationId getSigninRequiredNotificationId(UserAccounts accounts, Account account) { 3358 NotificationId nId; 3359 synchronized (accounts.signinRequiredNotificationIds) { 3360 nId = accounts.signinRequiredNotificationIds.get(account); 3361 if (nId == null) { 3362 String tag = TAG + ":" + SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN 3363 + ":" + account.hashCode(); 3364 int id = SystemMessage.NOTE_ACCOUNT_REQUIRE_SIGNIN; 3365 nId = new NotificationId(tag, id); 3366 accounts.signinRequiredNotificationIds.put(account, nId); 3367 } 3368 } 3369 return nId; 3370 } 3371 3372 @Override addAccount(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3373 public void addAccount(final IAccountManagerResponse response, final String accountType, 3374 final String authTokenType, final String[] requiredFeatures, 3375 final boolean expectActivityLaunch, final Bundle optionsIn) { 3376 Bundle.setDefusable(optionsIn, true); 3377 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3378 Log.v(TAG, "addAccount: accountType " + accountType 3379 + ", response " + response 3380 + ", authTokenType " + authTokenType 3381 + ", requiredFeatures " + Arrays.toString(requiredFeatures) 3382 + ", expectActivityLaunch " + expectActivityLaunch 3383 + ", caller's uid " + Binder.getCallingUid() 3384 + ", pid " + Binder.getCallingPid()); 3385 } 3386 if (response == null) throw new IllegalArgumentException("response is null"); 3387 if (accountType == null) throw new IllegalArgumentException("accountType is null"); 3388 3389 // Is user disallowed from modifying accounts? 3390 final int uid = Binder.getCallingUid(); 3391 final int userId = UserHandle.getUserId(uid); 3392 if (!canUserModifyAccounts(userId, uid)) { 3393 try { 3394 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED, 3395 "User is not allowed to add an account!"); 3396 } catch (RemoteException re) { 3397 } 3398 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId); 3399 return; 3400 } 3401 if (!canUserModifyAccountsForType(userId, accountType, uid)) { 3402 try { 3403 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3404 "User cannot modify accounts of this type (policy)."); 3405 } catch (RemoteException re) { 3406 } 3407 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3408 userId); 3409 return; 3410 } 3411 addAccountAndLogMetrics(response, accountType, authTokenType, requiredFeatures, 3412 expectActivityLaunch, optionsIn, userId); 3413 } 3414 3415 @Override addAccountAsUser(final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn, int userId)3416 public void addAccountAsUser(final IAccountManagerResponse response, final String accountType, 3417 final String authTokenType, final String[] requiredFeatures, 3418 final boolean expectActivityLaunch, final Bundle optionsIn, int userId) { 3419 Bundle.setDefusable(optionsIn, true); 3420 int callingUid = Binder.getCallingUid(); 3421 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3422 Log.v(TAG, "addAccount: accountType " + accountType 3423 + ", response " + response 3424 + ", authTokenType " + authTokenType 3425 + ", requiredFeatures " + Arrays.toString(requiredFeatures) 3426 + ", expectActivityLaunch " + expectActivityLaunch 3427 + ", caller's uid " + Binder.getCallingUid() 3428 + ", pid " + Binder.getCallingPid() 3429 + ", for user id " + userId); 3430 } 3431 Preconditions.checkArgument(response != null, "response cannot be null"); 3432 Preconditions.checkArgument(accountType != null, "accountType cannot be null"); 3433 // Only allow the system process to add accounts of other users 3434 if (isCrossUser(callingUid, userId)) { 3435 throw new SecurityException( 3436 String.format( 3437 "User %s trying to add account for %s" , 3438 UserHandle.getCallingUserId(), 3439 userId)); 3440 } 3441 3442 // Is user disallowed from modifying accounts? 3443 if (!canUserModifyAccounts(userId, callingUid)) { 3444 try { 3445 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED, 3446 "User is not allowed to add an account!"); 3447 } catch (RemoteException re) { 3448 } 3449 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId); 3450 return; 3451 } 3452 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) { 3453 try { 3454 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3455 "User cannot modify accounts of this type (policy)."); 3456 } catch (RemoteException re) { 3457 } 3458 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3459 userId); 3460 return; 3461 } 3462 addAccountAndLogMetrics(response, accountType, authTokenType, requiredFeatures, 3463 expectActivityLaunch, optionsIn, userId); 3464 } 3465 addAccountAndLogMetrics( IAccountManagerResponse response, String accountType, String authTokenType, String[] requiredFeatures, boolean expectActivityLaunch, Bundle optionsIn, int userId)3466 private void addAccountAndLogMetrics( 3467 IAccountManagerResponse response, String accountType, 3468 String authTokenType, String[] requiredFeatures, 3469 boolean expectActivityLaunch, Bundle optionsIn, int userId) { 3470 final int pid = Binder.getCallingPid(); 3471 final int uid = Binder.getCallingUid(); 3472 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn; 3473 options.putInt(AccountManager.KEY_CALLER_UID, uid); 3474 options.putInt(AccountManager.KEY_CALLER_PID, pid); 3475 3476 final long identityToken = clearCallingIdentity(); 3477 try { 3478 UserAccounts accounts = getUserAccounts(userId); 3479 logRecordWithUid( 3480 accounts, AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS, 3481 uid); 3482 new Session(accounts, response, accountType, expectActivityLaunch, 3483 true /* stripAuthTokenFromResult */, null /* accountName */, 3484 false /* authDetailsRequired */, true /* updateLastAuthenticationTime */) { 3485 @Override 3486 public void run() throws RemoteException { 3487 mAuthenticator.addAccount( 3488 this, mAccountType, authTokenType, requiredFeatures, options); 3489 String callerPackage = options.getString( 3490 AccountManager.KEY_ANDROID_PACKAGE_NAME); 3491 logAddAccountMetrics( 3492 callerPackage, accountType, requiredFeatures, authTokenType); 3493 } 3494 3495 @Override 3496 protected String toDebugString(long now) { 3497 return super.toDebugString(now) + ", addAccount" 3498 + ", accountType " + accountType 3499 + ", requiredFeatures " 3500 + (requiredFeatures != null 3501 ? TextUtils.join(",", requiredFeatures) 3502 : null); 3503 } 3504 }.bind(); 3505 } finally { 3506 restoreCallingIdentity(identityToken); 3507 } 3508 } 3509 logAddAccountMetrics( String callerPackage, String accountType, String[] requiredFeatures, String authTokenType)3510 private void logAddAccountMetrics( 3511 String callerPackage, String accountType, String[] requiredFeatures, 3512 String authTokenType) { 3513 // Although this is not a 'device policy' API, enterprise is the current use case. 3514 DevicePolicyEventLogger 3515 .createEvent(DevicePolicyEnums.ADD_ACCOUNT) 3516 .setStrings( 3517 TextUtils.emptyIfNull(accountType), 3518 TextUtils.emptyIfNull(callerPackage), 3519 TextUtils.emptyIfNull(authTokenType), 3520 requiredFeatures == null 3521 ? "" 3522 : TextUtils.join(";", requiredFeatures)) 3523 .write(); 3524 } 3525 3526 @Override startAddAccountSession( final IAccountManagerResponse response, final String accountType, final String authTokenType, final String[] requiredFeatures, final boolean expectActivityLaunch, final Bundle optionsIn)3527 public void startAddAccountSession( 3528 final IAccountManagerResponse response, 3529 final String accountType, 3530 final String authTokenType, 3531 final String[] requiredFeatures, 3532 final boolean expectActivityLaunch, 3533 final Bundle optionsIn) { 3534 Bundle.setDefusable(optionsIn, true); 3535 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3536 Log.v(TAG, 3537 "startAddAccountSession: accountType " + accountType 3538 + ", response " + response 3539 + ", authTokenType " + authTokenType 3540 + ", requiredFeatures " + Arrays.toString(requiredFeatures) 3541 + ", expectActivityLaunch " + expectActivityLaunch 3542 + ", caller's uid " + Binder.getCallingUid() 3543 + ", pid " + Binder.getCallingPid()); 3544 } 3545 Preconditions.checkArgument(response != null, "response cannot be null"); 3546 Preconditions.checkArgument(accountType != null, "accountType cannot be null"); 3547 3548 final int uid = Binder.getCallingUid(); 3549 final int userId = UserHandle.getUserId(uid); 3550 if (!canUserModifyAccounts(userId, uid)) { 3551 try { 3552 response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED, 3553 "User is not allowed to add an account!"); 3554 } catch (RemoteException re) { 3555 } 3556 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId); 3557 return; 3558 } 3559 if (!canUserModifyAccountsForType(userId, accountType, uid)) { 3560 try { 3561 response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3562 "User cannot modify accounts of this type (policy)."); 3563 } catch (RemoteException re) { 3564 } 3565 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3566 userId); 3567 return; 3568 } 3569 final int pid = Binder.getCallingPid(); 3570 final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn; 3571 options.putInt(AccountManager.KEY_CALLER_UID, uid); 3572 options.putInt(AccountManager.KEY_CALLER_PID, pid); 3573 3574 // Check to see if the Password should be included to the caller. 3575 String callerPkg = options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME); 3576 boolean isPasswordForwardingAllowed = checkPermissionAndNote( 3577 callerPkg, uid, Manifest.permission.GET_PASSWORD); 3578 3579 final long identityToken = clearCallingIdentity(); 3580 try { 3581 UserAccounts accounts = getUserAccounts(userId); 3582 logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD, 3583 AccountsDb.TABLE_ACCOUNTS, uid); 3584 new StartAccountSession( 3585 accounts, 3586 response, 3587 accountType, 3588 expectActivityLaunch, 3589 null /* accountName */, 3590 false /* authDetailsRequired */, 3591 true /* updateLastAuthenticationTime */, 3592 isPasswordForwardingAllowed) { 3593 @Override 3594 public void run() throws RemoteException { 3595 mAuthenticator.startAddAccountSession(this, mAccountType, authTokenType, 3596 requiredFeatures, options); 3597 logAddAccountMetrics(callerPkg, accountType, requiredFeatures, authTokenType); 3598 } 3599 3600 @Override 3601 protected String toDebugString(long now) { 3602 return super.toDebugString(now) + ", startAddAccountSession" + ", accountType " 3603 + accountType + ", requiredFeatures " 3604 + (requiredFeatures != null 3605 ? TextUtils.join(",", requiredFeatures) : "null"); 3606 } 3607 }.bind(); 3608 } finally { 3609 restoreCallingIdentity(identityToken); 3610 } 3611 } 3612 3613 /** Session that will encrypt the KEY_ACCOUNT_SESSION_BUNDLE in result. */ 3614 private abstract class StartAccountSession extends Session { 3615 3616 private final boolean mIsPasswordForwardingAllowed; 3617 StartAccountSession( UserAccounts accounts, IAccountManagerResponse response, String accountType, boolean expectActivityLaunch, String accountName, boolean authDetailsRequired, boolean updateLastAuthenticationTime, boolean isPasswordForwardingAllowed)3618 public StartAccountSession( 3619 UserAccounts accounts, 3620 IAccountManagerResponse response, 3621 String accountType, 3622 boolean expectActivityLaunch, 3623 String accountName, 3624 boolean authDetailsRequired, 3625 boolean updateLastAuthenticationTime, 3626 boolean isPasswordForwardingAllowed) { 3627 super(accounts, response, accountType, expectActivityLaunch, 3628 true /* stripAuthTokenFromResult */, accountName, authDetailsRequired, 3629 updateLastAuthenticationTime); 3630 mIsPasswordForwardingAllowed = isPasswordForwardingAllowed; 3631 } 3632 3633 @Override onResult(Bundle result)3634 public void onResult(Bundle result) { 3635 Bundle.setDefusable(result, true); 3636 mNumResults++; 3637 Intent intent = null; 3638 if (result != null) { 3639 if (!checkKeyIntent( 3640 Binder.getCallingUid(), 3641 result)) { 3642 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 3643 "invalid intent in bundle returned"); 3644 return; 3645 } 3646 } 3647 IAccountManagerResponse response; 3648 if (mExpectActivityLaunch && result != null 3649 && result.containsKey(AccountManager.KEY_INTENT)) { 3650 response = mResponse; 3651 } else { 3652 response = getResponseAndClose(); 3653 } 3654 if (response == null) { 3655 return; 3656 } 3657 if (result == null) { 3658 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3659 Log.v(TAG, getClass().getSimpleName() + " calling onError() on response " 3660 + response); 3661 } 3662 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE, 3663 "null bundle returned"); 3664 return; 3665 } 3666 3667 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && (intent == null)) { 3668 // All AccountManager error codes are greater 3669 // than 0 3670 sendErrorResponse(response, result.getInt(AccountManager.KEY_ERROR_CODE), 3671 result.getString(AccountManager.KEY_ERROR_MESSAGE)); 3672 return; 3673 } 3674 3675 // Omit passwords if the caller isn't permitted to see them. 3676 if (!mIsPasswordForwardingAllowed) { 3677 result.remove(AccountManager.KEY_PASSWORD); 3678 } 3679 3680 // Strip auth token from result. 3681 result.remove(AccountManager.KEY_AUTHTOKEN); 3682 if (!checkKeyIntent(Binder.getCallingUid(), result)) { 3683 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 3684 "invalid intent in bundle returned"); 3685 return; 3686 } 3687 3688 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3689 Log.v(TAG, 3690 getClass().getSimpleName() + " calling onResult() on response " + response); 3691 } 3692 3693 // Get the session bundle created by authenticator. The 3694 // bundle contains data necessary for finishing the session 3695 // later. The session bundle will be encrypted here and 3696 // decrypted later when trying to finish the session. 3697 Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE); 3698 if (sessionBundle != null) { 3699 String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE); 3700 if (TextUtils.isEmpty(accountType) 3701 || !mAccountType.equalsIgnoreCase(accountType)) { 3702 Log.w(TAG, "Account type in session bundle doesn't match request."); 3703 } 3704 // Add accountType info to session bundle. This will 3705 // override any value set by authenticator. 3706 sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType); 3707 3708 // Encrypt session bundle before returning to caller. 3709 try { 3710 CryptoHelper cryptoHelper = CryptoHelper.getInstance(); 3711 Bundle encryptedBundle = cryptoHelper.encryptBundle(sessionBundle); 3712 result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, encryptedBundle); 3713 } catch (GeneralSecurityException e) { 3714 if (Log.isLoggable(TAG, Log.DEBUG)) { 3715 Log.v(TAG, "Failed to encrypt session bundle!", e); 3716 } 3717 sendErrorResponse(response, AccountManager.ERROR_CODE_INVALID_RESPONSE, 3718 "failed to encrypt session bundle"); 3719 return; 3720 } 3721 } 3722 3723 sendResponse(response, result); 3724 } 3725 } 3726 3727 @Override finishSessionAsUser(IAccountManagerResponse response, @NonNull Bundle sessionBundle, boolean expectActivityLaunch, Bundle appInfo, int userId)3728 public void finishSessionAsUser(IAccountManagerResponse response, 3729 @NonNull Bundle sessionBundle, 3730 boolean expectActivityLaunch, 3731 Bundle appInfo, 3732 int userId) { 3733 Bundle.setDefusable(sessionBundle, true); 3734 int callingUid = Binder.getCallingUid(); 3735 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3736 Log.v(TAG, 3737 "finishSession: response "+ response 3738 + ", expectActivityLaunch " + expectActivityLaunch 3739 + ", caller's uid " + callingUid 3740 + ", caller's user id " + UserHandle.getCallingUserId() 3741 + ", pid " + Binder.getCallingPid() 3742 + ", for user id " + userId); 3743 } 3744 Preconditions.checkArgument(response != null, "response cannot be null"); 3745 // Session bundle is the encrypted bundle of the original bundle created by authenticator. 3746 // Account type is added to it before encryption. 3747 if (sessionBundle == null || sessionBundle.size() == 0) { 3748 throw new IllegalArgumentException("sessionBundle is empty"); 3749 } 3750 3751 // Only allow the system process to finish session for other users. 3752 if (isCrossUser(callingUid, userId)) { 3753 throw new SecurityException( 3754 String.format( 3755 "User %s trying to finish session for %s without cross user permission", 3756 UserHandle.getCallingUserId(), 3757 userId)); 3758 } 3759 3760 if (!canUserModifyAccounts(userId, callingUid)) { 3761 sendErrorResponse(response, 3762 AccountManager.ERROR_CODE_USER_RESTRICTED, 3763 "User is not allowed to add an account!"); 3764 showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId); 3765 return; 3766 } 3767 3768 final int pid = Binder.getCallingPid(); 3769 final Bundle decryptedBundle; 3770 final String accountType; 3771 // First decrypt session bundle to get account type for checking permission. 3772 try { 3773 CryptoHelper cryptoHelper = CryptoHelper.getInstance(); 3774 decryptedBundle = cryptoHelper.decryptBundle(sessionBundle); 3775 if (decryptedBundle == null) { 3776 sendErrorResponse( 3777 response, 3778 AccountManager.ERROR_CODE_BAD_REQUEST, 3779 "failed to decrypt session bundle"); 3780 return; 3781 } 3782 accountType = decryptedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE); 3783 // Account type cannot be null. This should not happen if session bundle was created 3784 // properly by #StartAccountSession. 3785 if (TextUtils.isEmpty(accountType)) { 3786 sendErrorResponse( 3787 response, 3788 AccountManager.ERROR_CODE_BAD_ARGUMENTS, 3789 "accountType is empty"); 3790 return; 3791 } 3792 3793 // If by any chances, decryptedBundle contains colliding keys with 3794 // system info 3795 // such as AccountManager.KEY_ANDROID_PACKAGE_NAME required by the add account flow or 3796 // update credentials flow, we should replace with the new values of the current call. 3797 if (appInfo != null) { 3798 decryptedBundle.putAll(appInfo); 3799 } 3800 3801 // Add info that may be used by add account or update credentials flow. 3802 decryptedBundle.putInt(AccountManager.KEY_CALLER_UID, callingUid); 3803 decryptedBundle.putInt(AccountManager.KEY_CALLER_PID, pid); 3804 } catch (GeneralSecurityException e) { 3805 if (Log.isLoggable(TAG, Log.DEBUG)) { 3806 Log.v(TAG, "Failed to decrypt session bundle!", e); 3807 } 3808 sendErrorResponse( 3809 response, 3810 AccountManager.ERROR_CODE_BAD_REQUEST, 3811 "failed to decrypt session bundle"); 3812 return; 3813 } 3814 3815 if (!canUserModifyAccountsForType(userId, accountType, callingUid)) { 3816 sendErrorResponse( 3817 response, 3818 AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3819 "User cannot modify accounts of this type (policy)."); 3820 showCantAddAccount(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE, 3821 userId); 3822 return; 3823 } 3824 3825 final long identityToken = clearCallingIdentity(); 3826 try { 3827 UserAccounts accounts = getUserAccounts(userId); 3828 logRecordWithUid( 3829 accounts, 3830 AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_SESSION_FINISH, 3831 AccountsDb.TABLE_ACCOUNTS, 3832 callingUid); 3833 new Session( 3834 accounts, 3835 response, 3836 accountType, 3837 expectActivityLaunch, 3838 true /* stripAuthTokenFromResult */, 3839 null /* accountName */, 3840 false /* authDetailsRequired */, 3841 true /* updateLastAuthenticationTime */) { 3842 @Override 3843 public void run() throws RemoteException { 3844 mAuthenticator.finishSession(this, mAccountType, decryptedBundle); 3845 } 3846 3847 @Override 3848 protected String toDebugString(long now) { 3849 return super.toDebugString(now) 3850 + ", finishSession" 3851 + ", accountType " + accountType; 3852 } 3853 }.bind(); 3854 } finally { 3855 restoreCallingIdentity(identityToken); 3856 } 3857 } 3858 showCantAddAccount(int errorCode, int userId)3859 private void showCantAddAccount(int errorCode, int userId) { 3860 final DevicePolicyManagerInternal dpmi = 3861 LocalServices.getService(DevicePolicyManagerInternal.class); 3862 Intent intent = null; 3863 if (dpmi == null) { 3864 intent = getDefaultCantAddAccountIntent(errorCode); 3865 } else if (errorCode == AccountManager.ERROR_CODE_USER_RESTRICTED) { 3866 intent = dpmi.createUserRestrictionSupportIntent(userId, 3867 UserManager.DISALLOW_MODIFY_ACCOUNTS); 3868 } else if (errorCode == AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE) { 3869 intent = dpmi.createShowAdminSupportIntent(userId, false); 3870 } 3871 if (intent == null) { 3872 intent = getDefaultCantAddAccountIntent(errorCode); 3873 } 3874 final long identityToken = clearCallingIdentity(); 3875 try { 3876 mContext.startActivityAsUser(intent, new UserHandle(userId)); 3877 } finally { 3878 restoreCallingIdentity(identityToken); 3879 } 3880 } 3881 3882 /** 3883 * Called when we don't know precisely who is preventing us from adding an account. 3884 */ getDefaultCantAddAccountIntent(int errorCode)3885 private Intent getDefaultCantAddAccountIntent(int errorCode) { 3886 Intent cantAddAccount = new Intent(mContext, CantAddAccountActivity.class); 3887 cantAddAccount.putExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, errorCode); 3888 cantAddAccount.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 3889 return cantAddAccount; 3890 } 3891 3892 @Override confirmCredentialsAsUser( IAccountManagerResponse response, final Account account, final Bundle options, final boolean expectActivityLaunch, int userId)3893 public void confirmCredentialsAsUser( 3894 IAccountManagerResponse response, 3895 final Account account, 3896 final Bundle options, 3897 final boolean expectActivityLaunch, 3898 int userId) { 3899 Bundle.setDefusable(options, true); 3900 int callingUid = Binder.getCallingUid(); 3901 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3902 Log.v(TAG, "confirmCredentials: " + account 3903 + ", response " + response 3904 + ", expectActivityLaunch " + expectActivityLaunch 3905 + ", caller's uid " + callingUid 3906 + ", pid " + Binder.getCallingPid()); 3907 } 3908 // Only allow the system process to read accounts of other users 3909 if (isCrossUser(callingUid, userId)) { 3910 throw new SecurityException( 3911 String.format( 3912 "User %s trying to confirm account credentials for %s" , 3913 UserHandle.getCallingUserId(), 3914 userId)); 3915 } 3916 if (response == null) throw new IllegalArgumentException("response is null"); 3917 if (account == null) throw new IllegalArgumentException("account is null"); 3918 final long identityToken = clearCallingIdentity(); 3919 try { 3920 UserAccounts accounts = getUserAccounts(userId); 3921 new Session(accounts, response, account.type, expectActivityLaunch, 3922 true /* stripAuthTokenFromResult */, account.name, 3923 true /* authDetailsRequired */, true /* updateLastAuthenticatedTime */) { 3924 @Override 3925 public void run() throws RemoteException { 3926 mAuthenticator.confirmCredentials(this, account, options); 3927 } 3928 @Override 3929 protected String toDebugString(long now) { 3930 return super.toDebugString(now) + ", confirmCredentials" 3931 + ", " + account.toSafeString(); 3932 } 3933 }.bind(); 3934 } finally { 3935 restoreCallingIdentity(identityToken); 3936 } 3937 } 3938 3939 @Override updateCredentials(IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3940 public void updateCredentials(IAccountManagerResponse response, final Account account, 3941 final String authTokenType, final boolean expectActivityLaunch, 3942 final Bundle loginOptions) { 3943 Bundle.setDefusable(loginOptions, true); 3944 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3945 Log.v(TAG, "updateCredentials: " + account 3946 + ", response " + response 3947 + ", authTokenType " + authTokenType 3948 + ", expectActivityLaunch " + expectActivityLaunch 3949 + ", caller's uid " + Binder.getCallingUid() 3950 + ", pid " + Binder.getCallingPid()); 3951 } 3952 if (response == null) throw new IllegalArgumentException("response is null"); 3953 if (account == null) throw new IllegalArgumentException("account is null"); 3954 int userId = UserHandle.getCallingUserId(); 3955 final long identityToken = clearCallingIdentity(); 3956 try { 3957 UserAccounts accounts = getUserAccounts(userId); 3958 new Session(accounts, response, account.type, expectActivityLaunch, 3959 true /* stripAuthTokenFromResult */, account.name, 3960 false /* authDetailsRequired */, true /* updateLastCredentialTime */) { 3961 @Override 3962 public void run() throws RemoteException { 3963 mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions); 3964 } 3965 @Override 3966 protected String toDebugString(long now) { 3967 if (loginOptions != null) loginOptions.keySet(); 3968 return super.toDebugString(now) + ", updateCredentials" 3969 + ", " + account.toSafeString() 3970 + ", authTokenType " + authTokenType 3971 + ", loginOptions " + loginOptions; 3972 } 3973 }.bind(); 3974 } finally { 3975 restoreCallingIdentity(identityToken); 3976 } 3977 } 3978 3979 @Override startUpdateCredentialsSession( IAccountManagerResponse response, final Account account, final String authTokenType, final boolean expectActivityLaunch, final Bundle loginOptions)3980 public void startUpdateCredentialsSession( 3981 IAccountManagerResponse response, 3982 final Account account, 3983 final String authTokenType, 3984 final boolean expectActivityLaunch, 3985 final Bundle loginOptions) { 3986 Bundle.setDefusable(loginOptions, true); 3987 if (Log.isLoggable(TAG, Log.VERBOSE)) { 3988 Log.v(TAG, 3989 "startUpdateCredentialsSession: " + account + ", response " + response 3990 + ", authTokenType " + authTokenType + ", expectActivityLaunch " 3991 + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid() 3992 + ", pid " + Binder.getCallingPid()); 3993 } 3994 if (response == null) { 3995 throw new IllegalArgumentException("response is null"); 3996 } 3997 if (account == null) { 3998 throw new IllegalArgumentException("account is null"); 3999 } 4000 4001 final int uid = Binder.getCallingUid(); 4002 int userId = UserHandle.getCallingUserId(); 4003 4004 // Check to see if the Password should be included to the caller. 4005 String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME); 4006 boolean isPasswordForwardingAllowed = checkPermissionAndNote( 4007 callerPkg, uid, Manifest.permission.GET_PASSWORD); 4008 4009 final long identityToken = clearCallingIdentity(); 4010 try { 4011 UserAccounts accounts = getUserAccounts(userId); 4012 new StartAccountSession( 4013 accounts, 4014 response, 4015 account.type, 4016 expectActivityLaunch, 4017 account.name, 4018 false /* authDetailsRequired */, 4019 true /* updateLastCredentialTime */, 4020 isPasswordForwardingAllowed) { 4021 @Override 4022 public void run() throws RemoteException { 4023 mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType, 4024 loginOptions); 4025 } 4026 4027 @Override 4028 protected String toDebugString(long now) { 4029 if (loginOptions != null) 4030 loginOptions.keySet(); 4031 return super.toDebugString(now) 4032 + ", startUpdateCredentialsSession" 4033 + ", " + account.toSafeString() 4034 + ", authTokenType " + authTokenType 4035 + ", loginOptions " + loginOptions; 4036 } 4037 }.bind(); 4038 } finally { 4039 restoreCallingIdentity(identityToken); 4040 } 4041 } 4042 4043 @Override isCredentialsUpdateSuggested( IAccountManagerResponse response, final Account account, final String statusToken)4044 public void isCredentialsUpdateSuggested( 4045 IAccountManagerResponse response, 4046 final Account account, 4047 final String statusToken) { 4048 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4049 Log.v(TAG, 4050 "isCredentialsUpdateSuggested: " + account + ", response " + response 4051 + ", caller's uid " + Binder.getCallingUid() 4052 + ", pid " + Binder.getCallingPid()); 4053 } 4054 if (response == null) { 4055 throw new IllegalArgumentException("response is null"); 4056 } 4057 if (account == null) { 4058 throw new IllegalArgumentException("account is null"); 4059 } 4060 if (TextUtils.isEmpty(statusToken)) { 4061 throw new IllegalArgumentException("status token is empty"); 4062 } 4063 4064 int usrId = UserHandle.getCallingUserId(); 4065 final long identityToken = clearCallingIdentity(); 4066 try { 4067 UserAccounts accounts = getUserAccounts(usrId); 4068 new Session(accounts, response, account.type, false /* expectActivityLaunch */, 4069 false /* stripAuthTokenFromResult */, account.name, 4070 false /* authDetailsRequired */) { 4071 @Override 4072 protected String toDebugString(long now) { 4073 return super.toDebugString(now) + ", isCredentialsUpdateSuggested" 4074 + ", " + account.toSafeString(); 4075 } 4076 4077 @Override 4078 public void run() throws RemoteException { 4079 mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken); 4080 } 4081 4082 @Override 4083 public void onResult(Bundle result) { 4084 Bundle.setDefusable(result, true); 4085 IAccountManagerResponse response = getResponseAndClose(); 4086 if (response == null) { 4087 return; 4088 } 4089 4090 if (result == null) { 4091 sendErrorResponse( 4092 response, 4093 AccountManager.ERROR_CODE_INVALID_RESPONSE, 4094 "null bundle"); 4095 return; 4096 } 4097 4098 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4099 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response " 4100 + response); 4101 } 4102 // Check to see if an error occurred. We know if an error occurred because all 4103 // error codes are greater than 0. 4104 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) { 4105 sendErrorResponse(response, 4106 result.getInt(AccountManager.KEY_ERROR_CODE), 4107 result.getString(AccountManager.KEY_ERROR_MESSAGE)); 4108 return; 4109 } 4110 if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) { 4111 sendErrorResponse( 4112 response, 4113 AccountManager.ERROR_CODE_INVALID_RESPONSE, 4114 "no result in response"); 4115 return; 4116 } 4117 final Bundle newResult = new Bundle(); 4118 newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, 4119 result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)); 4120 sendResponse(response, newResult); 4121 } 4122 }.bind(); 4123 } finally { 4124 restoreCallingIdentity(identityToken); 4125 } 4126 } 4127 4128 @Override editProperties(IAccountManagerResponse response, final String accountType, final boolean expectActivityLaunch)4129 public void editProperties(IAccountManagerResponse response, final String accountType, 4130 final boolean expectActivityLaunch) { 4131 final int callingUid = Binder.getCallingUid(); 4132 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4133 Log.v(TAG, "editProperties: accountType " + accountType 4134 + ", response " + response 4135 + ", expectActivityLaunch " + expectActivityLaunch 4136 + ", caller's uid " + callingUid 4137 + ", pid " + Binder.getCallingPid()); 4138 } 4139 if (response == null) throw new IllegalArgumentException("response is null"); 4140 if (accountType == null) throw new IllegalArgumentException("accountType is null"); 4141 int userId = UserHandle.getCallingUserId(); 4142 if (!isAccountManagedByCaller(accountType, callingUid, userId) 4143 && !isSystemUid(callingUid)) { 4144 String msg = String.format( 4145 "uid %s cannot edit authenticator properites for account type: %s", 4146 callingUid, 4147 accountType); 4148 throw new SecurityException(msg); 4149 } 4150 final long identityToken = clearCallingIdentity(); 4151 try { 4152 UserAccounts accounts = getUserAccounts(userId); 4153 new Session(accounts, response, accountType, expectActivityLaunch, 4154 true /* stripAuthTokenFromResult */, null /* accountName */, 4155 false /* authDetailsRequired */) { 4156 @Override 4157 public void run() throws RemoteException { 4158 mAuthenticator.editProperties(this, mAccountType); 4159 } 4160 @Override 4161 protected String toDebugString(long now) { 4162 return super.toDebugString(now) + ", editProperties" 4163 + ", accountType " + accountType; 4164 } 4165 }.bind(); 4166 } finally { 4167 restoreCallingIdentity(identityToken); 4168 } 4169 } 4170 4171 @Override hasAccountAccess(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)4172 public boolean hasAccountAccess(@NonNull Account account, @NonNull String packageName, 4173 @NonNull UserHandle userHandle) { 4174 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 4175 throw new SecurityException("Can be called only by system UID"); 4176 } 4177 Objects.requireNonNull(account, "account cannot be null"); 4178 Objects.requireNonNull(packageName, "packageName cannot be null"); 4179 Objects.requireNonNull(userHandle, "userHandle cannot be null"); 4180 4181 final int userId = userHandle.getIdentifier(); 4182 4183 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete"); 4184 4185 try { 4186 int uid = mPackageManager.getPackageUidAsUser(packageName, userId); 4187 return hasAccountAccess(account, packageName, uid); 4188 } catch (NameNotFoundException e) { 4189 Log.w(TAG, "hasAccountAccess#Package not found " + e.getMessage()); 4190 return false; 4191 } 4192 } 4193 4194 // Returns package with oldest target SDK for given UID. getPackageNameForUid(int uid)4195 private String getPackageNameForUid(int uid) { 4196 String[] packageNames = mPackageManager.getPackagesForUid(uid); 4197 if (ArrayUtils.isEmpty(packageNames)) { 4198 return null; 4199 } 4200 String packageName = packageNames[0]; 4201 if (packageNames.length == 1) { 4202 return packageName; 4203 } 4204 // Due to visibility changes we want to use package with oldest target SDK 4205 int oldestVersion = Integer.MAX_VALUE; 4206 for (String name : packageNames) { 4207 try { 4208 ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(name, 0); 4209 if (applicationInfo != null) { 4210 int version = applicationInfo.targetSdkVersion; 4211 if (version < oldestVersion) { 4212 oldestVersion = version; 4213 packageName = name; 4214 } 4215 } 4216 } catch (NameNotFoundException e) { 4217 // skip 4218 } 4219 } 4220 return packageName; 4221 } 4222 hasAccountAccess(@onNull Account account, @Nullable String packageName, int uid)4223 private boolean hasAccountAccess(@NonNull Account account, @Nullable String packageName, 4224 int uid) { 4225 if (packageName == null) { 4226 packageName = getPackageNameForUid(uid); 4227 if (packageName == null) { 4228 return false; 4229 } 4230 } 4231 4232 // Use null token which means any token. Having a token means the package 4233 // is trusted by the authenticator, hence it is fine to access the account. 4234 if (permissionIsGranted(account, null, uid, UserHandle.getUserId(uid))) { 4235 return true; 4236 } 4237 // In addition to the permissions required to get an auth token we also allow 4238 // the account to be accessed by apps for which user or authenticator granted visibility. 4239 4240 int visibility = resolveAccountVisibility(account, packageName, 4241 getUserAccounts(UserHandle.getUserId(uid))); 4242 return (visibility == AccountManager.VISIBILITY_VISIBLE 4243 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE); 4244 } 4245 4246 @Override createRequestAccountAccessIntentSenderAsUser(@onNull Account account, @NonNull String packageName, @NonNull UserHandle userHandle)4247 public IntentSender createRequestAccountAccessIntentSenderAsUser(@NonNull Account account, 4248 @NonNull String packageName, @NonNull UserHandle userHandle) { 4249 if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { 4250 throw new SecurityException("Can be called only by system UID"); 4251 } 4252 4253 Objects.requireNonNull(account, "account cannot be null"); 4254 Objects.requireNonNull(packageName, "packageName cannot be null"); 4255 Objects.requireNonNull(userHandle, "userHandle cannot be null"); 4256 4257 final int userId = userHandle.getIdentifier(); 4258 4259 Preconditions.checkArgumentInRange(userId, 0, Integer.MAX_VALUE, "user must be concrete"); 4260 4261 final int uid; 4262 try { 4263 uid = mPackageManager.getPackageUidAsUser(packageName, userId); 4264 } catch (NameNotFoundException e) { 4265 Slog.e(TAG, "Unknown package " + packageName); 4266 return null; 4267 } 4268 4269 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, null); 4270 4271 final long identity = Binder.clearCallingIdentity(); 4272 try { 4273 return PendingIntent.getActivityAsUser( 4274 mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT 4275 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, 4276 null, new UserHandle(userId)).getIntentSender(); 4277 } finally { 4278 Binder.restoreCallingIdentity(identity); 4279 } 4280 } 4281 newRequestAccountAccessIntent(Account account, String packageName, int uid, RemoteCallback callback)4282 private Intent newRequestAccountAccessIntent(Account account, String packageName, 4283 int uid, RemoteCallback callback) { 4284 return newGrantCredentialsPermissionIntent(account, packageName, uid, 4285 new AccountAuthenticatorResponse(new IAccountAuthenticatorResponse.Stub() { 4286 @Override 4287 public void onResult(Bundle value) throws RemoteException { 4288 handleAuthenticatorResponse(true); 4289 } 4290 4291 @Override 4292 public void onRequestContinued() { 4293 /* ignore */ 4294 } 4295 4296 @Override 4297 public void onError(int errorCode, String errorMessage) throws RemoteException { 4298 handleAuthenticatorResponse(false); 4299 } 4300 4301 private void handleAuthenticatorResponse(boolean accessGranted) throws RemoteException { 4302 UserAccounts userAccounts = getUserAccounts(UserHandle.getUserId(uid)); 4303 cancelNotification(getCredentialPermissionNotificationId(account, 4304 AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid, userAccounts), userAccounts); 4305 if (callback != null) { 4306 Bundle result = new Bundle(); 4307 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, accessGranted); 4308 callback.sendResult(result); 4309 } 4310 } 4311 }), AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, false); 4312 } 4313 4314 @Override 4315 public boolean someUserHasAccount(@NonNull final Account account) { 4316 if (!UserHandle.isSameApp(Process.SYSTEM_UID, Binder.getCallingUid())) { 4317 throw new SecurityException("Only system can check for accounts across users"); 4318 } 4319 final long token = Binder.clearCallingIdentity(); 4320 try { 4321 AccountAndUser[] allAccounts = getAllAccountsForSystemProcess(); 4322 for (int i = allAccounts.length - 1; i >= 0; i--) { 4323 if (allAccounts[i].account.equals(account)) { 4324 return true; 4325 } 4326 } 4327 return false; 4328 } finally { 4329 Binder.restoreCallingIdentity(token); 4330 } 4331 } 4332 4333 private class GetAccountsByTypeAndFeatureSession extends Session { 4334 private final String[] mFeatures; 4335 private volatile Account[] mAccountsOfType = null; 4336 private volatile ArrayList<Account> mAccountsWithFeatures = null; 4337 private volatile int mCurrentAccount = 0; 4338 private final int mCallingUid; 4339 private final String mPackageName; 4340 private final boolean mIncludeManagedNotVisible; 4341 4342 public GetAccountsByTypeAndFeatureSession( 4343 UserAccounts accounts, 4344 IAccountManagerResponse response, 4345 String type, 4346 String[] features, 4347 int callingUid, 4348 String packageName, 4349 boolean includeManagedNotVisible) { 4350 super(accounts, response, type, false /* expectActivityLaunch */, 4351 true /* stripAuthTokenFromResult */, null /* accountName */, 4352 false /* authDetailsRequired */); 4353 mCallingUid = callingUid; 4354 mFeatures = features; 4355 mPackageName = packageName; 4356 mIncludeManagedNotVisible = includeManagedNotVisible; 4357 } 4358 4359 @Override 4360 public void run() throws RemoteException { 4361 mAccountsOfType = getAccountsFromCache(mAccounts, mAccountType, 4362 mCallingUid, mPackageName, mIncludeManagedNotVisible); 4363 // check whether each account matches the requested features 4364 mAccountsWithFeatures = new ArrayList<>(mAccountsOfType.length); 4365 mCurrentAccount = 0; 4366 4367 checkAccount(); 4368 } 4369 4370 public void checkAccount() { 4371 if (mCurrentAccount >= mAccountsOfType.length) { 4372 sendResult(); 4373 return; 4374 } 4375 4376 final IAccountAuthenticator accountAuthenticator = mAuthenticator; 4377 if (accountAuthenticator == null) { 4378 // It is possible that the authenticator has died, which is indicated by 4379 // mAuthenticator being set to null. If this happens then just abort. 4380 // There is no need to send back a result or error in this case since 4381 // that already happened when mAuthenticator was cleared. 4382 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4383 Log.v(TAG, "checkAccount: aborting session since we are no longer" 4384 + " connected to the authenticator, " + toDebugString()); 4385 } 4386 return; 4387 } 4388 try { 4389 accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures); 4390 } catch (RemoteException e) { 4391 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception"); 4392 } 4393 } 4394 4395 @Override 4396 public void onResult(Bundle result) { 4397 Bundle.setDefusable(result, true); 4398 mNumResults++; 4399 if (result == null) { 4400 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle"); 4401 return; 4402 } 4403 if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) { 4404 mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]); 4405 } 4406 mCurrentAccount++; 4407 checkAccount(); 4408 } 4409 4410 public void sendResult() { 4411 IAccountManagerResponse response = getResponseAndClose(); 4412 if (response != null) { 4413 try { 4414 Account[] accounts = new Account[mAccountsWithFeatures.size()]; 4415 for (int i = 0; i < accounts.length; i++) { 4416 accounts[i] = mAccountsWithFeatures.get(i); 4417 } 4418 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4419 Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response " 4420 + response); 4421 } 4422 Bundle result = new Bundle(); 4423 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts); 4424 response.onResult(result); 4425 } catch (RemoteException e) { 4426 // if the caller is dead then there is no one to care about remote exceptions 4427 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4428 Log.v(TAG, "failure while notifying response", e); 4429 } 4430 } 4431 } 4432 } 4433 4434 @Override 4435 protected String toDebugString(long now) { 4436 return super.toDebugString(now) + ", getAccountsByTypeAndFeatures" 4437 + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null); 4438 } 4439 } 4440 4441 /** 4442 * Returns the accounts visible to the client within the context of a specific user 4443 * @hide 4444 */ 4445 @NonNull 4446 public Account[] getAccounts(int userId, String opPackageName) { 4447 int callingUid = Binder.getCallingUid(); 4448 mAppOpsManager.checkPackage(callingUid, opPackageName); 4449 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId, 4450 opPackageName); 4451 if (visibleAccountTypes.isEmpty()) { 4452 return EMPTY_ACCOUNT_ARRAY; 4453 } 4454 final long identityToken = clearCallingIdentity(); 4455 try { 4456 UserAccounts accounts = getUserAccounts(userId); 4457 return getAccountsInternal( 4458 accounts, 4459 callingUid, 4460 opPackageName, 4461 visibleAccountTypes, 4462 false /* includeUserManagedNotVisible */); 4463 } finally { 4464 restoreCallingIdentity(identityToken); 4465 } 4466 } 4467 4468 /** 4469 * Returns accounts for all running users, ignores visibility values. 4470 * 4471 * Should only be called by System process. 4472 * @hide 4473 */ 4474 @NonNull 4475 public AccountAndUser[] getRunningAccountsForSystem() { 4476 final int[] runningUserIds; 4477 try { 4478 runningUserIds = ActivityManager.getService().getRunningUserIds(); 4479 } catch (RemoteException e) { 4480 // Running in system_server; should never happen 4481 throw new RuntimeException(e); 4482 } 4483 return getAccountsForSystem(runningUserIds); 4484 } 4485 4486 /** 4487 * Returns accounts for all users, ignores visibility values. 4488 * 4489 * Should only be called by system process 4490 * 4491 * @hide 4492 */ 4493 @NonNull 4494 public AccountAndUser[] getAllAccountsForSystemProcess() { 4495 final List<UserInfo> users = getUserManager().getAliveUsers(); 4496 final int[] userIds = new int[users.size()]; 4497 for (int i = 0; i < userIds.length; i++) { 4498 userIds[i] = users.get(i).id; 4499 } 4500 return getAccountsForSystem(userIds); 4501 } 4502 4503 /** 4504 * Returns all accounts for the given user, ignores all visibility checks. 4505 * This should only be called by system process. 4506 * 4507 * @hide 4508 */ 4509 @NonNull 4510 private AccountAndUser[] getAccountsForSystem(int[] userIds) { 4511 final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList(); 4512 for (int userId : userIds) { 4513 UserAccounts userAccounts = getUserAccounts(userId); 4514 if (userAccounts == null) continue; 4515 Account[] accounts = getAccountsFromCache( 4516 userAccounts, 4517 null /* type */, 4518 Binder.getCallingUid(), 4519 "android"/* packageName */, 4520 false /* include managed not visible*/); 4521 for (Account account : accounts) { 4522 runningAccounts.add(new AccountAndUser(account, userId)); 4523 } 4524 } 4525 4526 AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()]; 4527 return runningAccounts.toArray(accountsArray); 4528 } 4529 4530 @Override 4531 @NonNull 4532 public Account[] getAccountsAsUser(String type, int userId, String opPackageName) { 4533 int callingUid = Binder.getCallingUid(); 4534 mAppOpsManager.checkPackage(callingUid, opPackageName); 4535 try { 4536 return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1, 4537 opPackageName, false /* includeUserManagedNotVisible */); 4538 } catch (SQLiteCantOpenDatabaseException e) { 4539 Log.e(TAG, "Could not get accounts for user " + userId, e); 4540 return new Account[]{}; 4541 } 4542 } 4543 4544 @NonNull 4545 private Account[] getAccountsOrEmptyArray(String type, int userId, String opPackageName) { 4546 try { 4547 return getAccountsAsUser(type, userId, opPackageName); 4548 } catch (SQLiteCantOpenDatabaseException e) { 4549 Log.w(TAG, "Could not get accounts for user " + userId, e); 4550 return new Account[]{}; 4551 } 4552 } 4553 4554 @NonNull 4555 private Account[] getAccountsAsUserForPackage( 4556 String type, 4557 int userId, 4558 String callingPackage, 4559 int packageUid, 4560 String opPackageName, 4561 boolean includeUserManagedNotVisible) { 4562 int callingUid = Binder.getCallingUid(); 4563 // Only allow the system process to read accounts of other users 4564 if (userId != UserHandle.getCallingUserId() 4565 && callingUid != Process.SYSTEM_UID 4566 && mContext.checkCallingOrSelfPermission( 4567 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) 4568 != PackageManager.PERMISSION_GRANTED) { 4569 throw new SecurityException("User " + UserHandle.getCallingUserId() 4570 + " trying to get account for " + userId); 4571 } 4572 4573 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4574 Log.v(TAG, "getAccounts: accountType " + type 4575 + ", caller's uid " + Binder.getCallingUid() 4576 + ", pid " + Binder.getCallingPid()); 4577 } 4578 4579 // If the original calling app was using account choosing activity 4580 // provided by the framework or authenticator we'll passing in 4581 // the original caller's uid here, which is what should be used for filtering. 4582 List<String> managedTypes = 4583 getTypesManagedByCaller(callingUid, UserHandle.getUserId(callingUid)); 4584 if (packageUid != -1 && 4585 ((UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) 4586 || (type != null && managedTypes.contains(type))))) { 4587 callingUid = packageUid; 4588 opPackageName = callingPackage; 4589 } 4590 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId, 4591 opPackageName); 4592 if (visibleAccountTypes.isEmpty() 4593 || (type != null && !visibleAccountTypes.contains(type))) { 4594 return EMPTY_ACCOUNT_ARRAY; 4595 } else if (visibleAccountTypes.contains(type)) { 4596 // Prune the list down to just the requested type. 4597 visibleAccountTypes = new ArrayList<>(); 4598 visibleAccountTypes.add(type); 4599 } // else aggregate all the visible accounts (it won't matter if the 4600 // list is empty). 4601 4602 final long identityToken = clearCallingIdentity(); 4603 try { 4604 UserAccounts accounts = getUserAccounts(userId); 4605 return getAccountsInternal( 4606 accounts, 4607 callingUid, 4608 opPackageName, 4609 visibleAccountTypes, 4610 includeUserManagedNotVisible); 4611 } finally { 4612 restoreCallingIdentity(identityToken); 4613 } 4614 } 4615 4616 @NonNull 4617 private Account[] getAccountsInternal( 4618 UserAccounts userAccounts, 4619 int callingUid, 4620 String callingPackage, 4621 List<String> visibleAccountTypes, 4622 boolean includeUserManagedNotVisible) { 4623 ArrayList<Account> visibleAccounts = new ArrayList<>(); 4624 for (String visibleType : visibleAccountTypes) { 4625 Account[] accountsForType = getAccountsFromCache( 4626 userAccounts, visibleType, callingUid, callingPackage, 4627 includeUserManagedNotVisible); 4628 if (accountsForType != null) { 4629 visibleAccounts.addAll(Arrays.asList(accountsForType)); 4630 } 4631 } 4632 Account[] result = new Account[visibleAccounts.size()]; 4633 for (int i = 0; i < visibleAccounts.size(); i++) { 4634 result[i] = visibleAccounts.get(i); 4635 } 4636 return result; 4637 } 4638 4639 @Override 4640 public void addSharedAccountsFromParentUser(int parentUserId, int userId, 4641 String opPackageName) { 4642 checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser"); 4643 Account[] accounts = getAccountsOrEmptyArray(null, parentUserId, opPackageName); 4644 for (Account account : accounts) { 4645 addSharedAccountAsUser(account, userId); 4646 } 4647 } 4648 4649 private boolean addSharedAccountAsUser(Account account, int userId) { 4650 userId = handleIncomingUser(userId); 4651 UserAccounts accounts = getUserAccounts(userId); 4652 accounts.accountsDb.deleteSharedAccount(account); 4653 long accountId = accounts.accountsDb.insertSharedAccount(account); 4654 if (accountId < 0) { 4655 Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString() 4656 + ", skipping the DB insert failed"); 4657 return false; 4658 } 4659 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_SHARED_ACCOUNTS, accountId, 4660 accounts); 4661 return true; 4662 } 4663 4664 public boolean renameSharedAccountAsUser(Account account, String newName, int userId) { 4665 userId = handleIncomingUser(userId); 4666 UserAccounts accounts = getUserAccounts(userId); 4667 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account); 4668 int r = accounts.accountsDb.renameSharedAccount(account, newName); 4669 if (r > 0) { 4670 int callingUid = getCallingUid(); 4671 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS, 4672 sharedTableAccountId, accounts, callingUid); 4673 // Recursively rename the account. 4674 renameAccountInternal(accounts, account, newName); 4675 } 4676 return r > 0; 4677 } 4678 4679 public boolean removeSharedAccountAsUser(Account account, int userId) { 4680 return removeSharedAccountAsUser(account, userId, getCallingUid()); 4681 } 4682 4683 private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) { 4684 userId = handleIncomingUser(userId); 4685 UserAccounts accounts = getUserAccounts(userId); 4686 long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account); 4687 boolean deleted = accounts.accountsDb.deleteSharedAccount(account); 4688 if (deleted) { 4689 logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS, 4690 sharedTableAccountId, accounts, callingUid); 4691 removeAccountInternal(accounts, account, callingUid); 4692 } 4693 return deleted; 4694 } 4695 4696 public Account[] getSharedAccountsAsUser(int userId) { 4697 userId = handleIncomingUser(userId); 4698 UserAccounts accounts = getUserAccounts(userId); 4699 synchronized (accounts.dbLock) { 4700 List<Account> accountList = accounts.accountsDb.getSharedAccounts(); 4701 Account[] accountArray = new Account[accountList.size()]; 4702 accountList.toArray(accountArray); 4703 return accountArray; 4704 } 4705 } 4706 4707 @Override 4708 @NonNull 4709 public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) { 4710 int callingUid = Binder.getCallingUid(); 4711 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) { 4712 // Don't do opPackageName check - caller is system. 4713 throw new SecurityException("getAccountsForPackage() called from unauthorized uid " 4714 + callingUid + " with uid=" + uid); 4715 } 4716 return getAccountsAsUserForPackage(null, UserHandle.getCallingUserId(), packageName, uid, 4717 opPackageName, true /* includeUserManagedNotVisible */); 4718 } 4719 4720 @Override 4721 @NonNull 4722 public Account[] getAccountsByTypeForPackage(String type, String packageName, 4723 String opPackageName) { 4724 int callingUid = Binder.getCallingUid(); 4725 int userId = UserHandle.getCallingUserId(); 4726 mAppOpsManager.checkPackage(callingUid, opPackageName); 4727 int packageUid = -1; 4728 try { 4729 packageUid = mPackageManager.getPackageUidAsUser(packageName, userId); 4730 } catch (NameNotFoundException re) { 4731 Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re); 4732 return EMPTY_ACCOUNT_ARRAY; 4733 } 4734 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) 4735 && (type != null && !isAccountManagedByCaller(type, callingUid, userId))) { 4736 return EMPTY_ACCOUNT_ARRAY; 4737 } 4738 if (!UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) && type == null) { 4739 return getAccountsAsUserForPackage(type, userId, 4740 packageName, packageUid, opPackageName, false /* includeUserManagedNotVisible */); 4741 } 4742 return getAccountsAsUserForPackage(type, userId, 4743 packageName, packageUid, opPackageName, true /* includeUserManagedNotVisible */); 4744 } 4745 4746 private boolean needToStartChooseAccountActivity(Account[] accounts, String callingPackage) { 4747 if (accounts.length < 1) return false; 4748 if (accounts.length > 1) return true; 4749 Account account = accounts[0]; 4750 UserAccounts userAccounts = getUserAccounts(UserHandle.getCallingUserId()); 4751 int visibility = resolveAccountVisibility(account, callingPackage, userAccounts); 4752 if (visibility == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE) return true; 4753 return false; 4754 } 4755 4756 private void startChooseAccountActivityWithAccounts( 4757 IAccountManagerResponse response, Account[] accounts, String callingPackage) { 4758 Intent intent = new Intent(mContext, ChooseAccountActivity.class); 4759 intent.putExtra(AccountManager.KEY_ACCOUNTS, accounts); 4760 intent.putExtra(AccountManager.KEY_ACCOUNT_MANAGER_RESPONSE, 4761 new AccountManagerResponse(response)); 4762 intent.putExtra(AccountManager.KEY_ANDROID_PACKAGE_NAME, callingPackage); 4763 4764 mContext.startActivityAsUser(intent, UserHandle.of(UserHandle.getCallingUserId())); 4765 } 4766 4767 private void handleGetAccountsResult( 4768 IAccountManagerResponse response, 4769 Account[] accounts, 4770 String callingPackage) { 4771 4772 if (needToStartChooseAccountActivity(accounts, callingPackage)) { 4773 startChooseAccountActivityWithAccounts(response, accounts, callingPackage); 4774 return; 4775 } 4776 if (accounts.length == 1) { 4777 Bundle bundle = new Bundle(); 4778 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, accounts[0].name); 4779 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accounts[0].type); 4780 onResult(response, bundle); 4781 return; 4782 } 4783 // No qualified account exists, return an empty Bundle. 4784 onResult(response, new Bundle()); 4785 } 4786 4787 @Override 4788 public void getAccountByTypeAndFeatures( 4789 IAccountManagerResponse response, 4790 String accountType, 4791 String[] features, 4792 String opPackageName) { 4793 4794 int callingUid = Binder.getCallingUid(); 4795 mAppOpsManager.checkPackage(callingUid, opPackageName); 4796 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4797 Log.v(TAG, "getAccount: accountType " + accountType 4798 + ", response " + response 4799 + ", features " + Arrays.toString(features) 4800 + ", caller's uid " + callingUid 4801 + ", pid " + Binder.getCallingPid()); 4802 } 4803 if (response == null) throw new IllegalArgumentException("response is null"); 4804 if (accountType == null) throw new IllegalArgumentException("accountType is null"); 4805 4806 int userId = UserHandle.getCallingUserId(); 4807 4808 final long identityToken = clearCallingIdentity(); 4809 try { 4810 UserAccounts userAccounts = getUserAccounts(userId); 4811 if (ArrayUtils.isEmpty(features)) { 4812 Account[] accountsWithManagedNotVisible = getAccountsFromCache( 4813 userAccounts, accountType, callingUid, opPackageName, 4814 true /* include managed not visible */); 4815 handleGetAccountsResult( 4816 response, accountsWithManagedNotVisible, opPackageName); 4817 return; 4818 } 4819 4820 IAccountManagerResponse retrieveAccountsResponse = 4821 new IAccountManagerResponse.Stub() { 4822 @Override 4823 public void onResult(Bundle value) throws RemoteException { 4824 Parcelable[] parcelables = value.getParcelableArray( 4825 AccountManager.KEY_ACCOUNTS); 4826 Account[] accounts = new Account[parcelables.length]; 4827 for (int i = 0; i < parcelables.length; i++) { 4828 accounts[i] = (Account) parcelables[i]; 4829 } 4830 handleGetAccountsResult( 4831 response, accounts, opPackageName); 4832 } 4833 4834 @Override 4835 public void onError(int errorCode, String errorMessage) 4836 throws RemoteException { 4837 // Will not be called in this case. 4838 } 4839 }; 4840 new GetAccountsByTypeAndFeatureSession( 4841 userAccounts, 4842 retrieveAccountsResponse, 4843 accountType, 4844 features, 4845 callingUid, 4846 opPackageName, 4847 true /* include managed not visible */).bind(); 4848 } finally { 4849 restoreCallingIdentity(identityToken); 4850 } 4851 } 4852 4853 @Override 4854 public void getAccountsByFeatures( 4855 IAccountManagerResponse response, 4856 String type, 4857 String[] features, 4858 String opPackageName) { 4859 int callingUid = Binder.getCallingUid(); 4860 mAppOpsManager.checkPackage(callingUid, opPackageName); 4861 if (Log.isLoggable(TAG, Log.VERBOSE)) { 4862 Log.v(TAG, "getAccounts: accountType " + type 4863 + ", response " + response 4864 + ", features " + Arrays.toString(features) 4865 + ", caller's uid " + callingUid 4866 + ", pid " + Binder.getCallingPid()); 4867 } 4868 if (response == null) throw new IllegalArgumentException("response is null"); 4869 if (type == null) throw new IllegalArgumentException("accountType is null"); 4870 int userId = UserHandle.getCallingUserId(); 4871 4872 List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId, 4873 opPackageName); 4874 if (!visibleAccountTypes.contains(type)) { 4875 Bundle result = new Bundle(); 4876 // Need to return just the accounts that are from matching signatures. 4877 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, EMPTY_ACCOUNT_ARRAY); 4878 try { 4879 response.onResult(result); 4880 } catch (RemoteException e) { 4881 Log.e(TAG, "Cannot respond to caller do to exception." , e); 4882 } 4883 return; 4884 } 4885 4886 final long identityToken = clearCallingIdentity(); 4887 try { 4888 UserAccounts userAccounts = getUserAccounts(userId); 4889 if (features == null || features.length == 0) { 4890 Account[] accounts = getAccountsFromCache(userAccounts, type, callingUid, 4891 opPackageName, false); 4892 Bundle result = new Bundle(); 4893 result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts); 4894 onResult(response, result); 4895 return; 4896 } 4897 new GetAccountsByTypeAndFeatureSession( 4898 userAccounts, 4899 response, 4900 type, 4901 features, 4902 callingUid, 4903 opPackageName, 4904 false /* include managed not visible */).bind(); 4905 } finally { 4906 restoreCallingIdentity(identityToken); 4907 } 4908 } 4909 4910 @Override 4911 public void onAccountAccessed(String token) throws RemoteException { 4912 final int uid = Binder.getCallingUid(); 4913 if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { 4914 return; 4915 } 4916 final int userId = UserHandle.getCallingUserId(); 4917 final long identity = Binder.clearCallingIdentity(); 4918 try { 4919 for (Account account : getAccounts(userId, mContext.getOpPackageName())) { 4920 if (Objects.equals(account.getAccessId(), token)) { 4921 // An app just accessed the account. At this point it knows about 4922 // it and there is not need to hide this account from the app. 4923 // Do we need to update account visibility here? 4924 if (!hasAccountAccess(account, null, uid)) { 4925 updateAppPermission(account, AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, 4926 uid, true); 4927 } 4928 } 4929 } 4930 } finally { 4931 Binder.restoreCallingIdentity(identity); 4932 } 4933 } 4934 4935 @Override 4936 public void onShellCommand(FileDescriptor in, FileDescriptor out, 4937 FileDescriptor err, String[] args, ShellCallback callback, 4938 ResultReceiver resultReceiver) { 4939 new AccountManagerServiceShellCommand(this).exec(this, in, out, err, args, 4940 callback, resultReceiver); 4941 } 4942 4943 private abstract class Session extends IAccountAuthenticatorResponse.Stub 4944 implements IBinder.DeathRecipient, ServiceConnection { 4945 private final Object mSessionLock = new Object(); 4946 IAccountManagerResponse mResponse; 4947 final String mAccountType; 4948 final boolean mExpectActivityLaunch; 4949 final long mCreationTime; 4950 final String mAccountName; 4951 // Indicates if we need to add auth details(like last credential time) 4952 final boolean mAuthDetailsRequired; 4953 // If set, we need to update the last authenticated time. This is 4954 // currently 4955 // used on 4956 // successful confirming credentials. 4957 final boolean mUpdateLastAuthenticatedTime; 4958 4959 public int mNumResults = 0; 4960 private int mNumRequestContinued = 0; 4961 private int mNumErrors = 0; 4962 4963 IAccountAuthenticator mAuthenticator = null; 4964 4965 private final boolean mStripAuthTokenFromResult; 4966 protected boolean mCanStartAccountManagerActivity = false; 4967 protected final UserAccounts mAccounts; 4968 4969 private int mAuthenticatorUid; 4970 private long mBindingStartTime; 4971 4972 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, 4973 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, 4974 boolean authDetailsRequired) { 4975 this(accounts, response, accountType, expectActivityLaunch, stripAuthTokenFromResult, 4976 accountName, authDetailsRequired, false /* updateLastAuthenticatedTime */); 4977 } 4978 4979 public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, 4980 boolean expectActivityLaunch, boolean stripAuthTokenFromResult, String accountName, 4981 boolean authDetailsRequired, boolean updateLastAuthenticatedTime) { 4982 super(); 4983 //if (response == null) throw new IllegalArgumentException("response is null"); 4984 if (accountType == null) throw new IllegalArgumentException("accountType is null"); 4985 mAccounts = accounts; 4986 mStripAuthTokenFromResult = stripAuthTokenFromResult; 4987 mAccountType = accountType; 4988 mExpectActivityLaunch = expectActivityLaunch; 4989 mCreationTime = SystemClock.elapsedRealtime(); 4990 mAccountName = accountName; 4991 mAuthDetailsRequired = authDetailsRequired; 4992 mUpdateLastAuthenticatedTime = updateLastAuthenticatedTime; 4993 4994 synchronized (mSessions) { 4995 mSessions.put(toString(), this); 4996 } 4997 scheduleTimeout(); 4998 if (response != null) { 4999 try { 5000 response.asBinder().linkToDeath(this, 0 /* flags */); 5001 mResponse = response; 5002 } catch (RemoteException e) { 5003 binderDied(); 5004 } 5005 } 5006 } 5007 5008 IAccountManagerResponse getResponseAndClose() { 5009 if (mAuthenticatorUid != 0 && mBindingStartTime > 0) { 5010 sResponseLatency.logSampleWithUid(mAuthenticatorUid, 5011 SystemClock.uptimeMillis() - mBindingStartTime); 5012 } 5013 if (mResponse == null) { 5014 close(); 5015 return null; 5016 } 5017 IAccountManagerResponse response = mResponse; 5018 close(); // this clears mResponse so we need to save the response before this call 5019 return response; 5020 } 5021 5022 /** 5023 * Checks Intents, supplied via KEY_INTENT, to make sure that they don't violate our 5024 * security policy. 5025 * 5026 * In particular we want to make sure that the Authenticator doesn't try to trick users 5027 * into launching arbitrary intents on the device via by tricking to click authenticator 5028 * supplied entries in the system Settings app. 5029 */ 5030 protected boolean checkKeyIntent(int authUid, Bundle bundle) { 5031 if (!checkKeyIntentParceledCorrectly(bundle)) { 5032 EventLog.writeEvent(0x534e4554, "250588548", authUid, ""); 5033 return false; 5034 } 5035 Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class); 5036 if (intent == null) { 5037 return true; 5038 } 5039 // Explicitly set an empty ClipData to ensure that we don't offer to 5040 // promote any Uris contained inside for granting purposes 5041 if (intent.getClipData() == null) { 5042 intent.setClipData(ClipData.newPlainText(null, null)); 5043 } 5044 final long bid = Binder.clearCallingIdentity(); 5045 try { 5046 PackageManager pm = mContext.getPackageManager(); 5047 ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId); 5048 if (resolveInfo == null) { 5049 return false; 5050 } 5051 ActivityInfo targetActivityInfo = resolveInfo.activityInfo; 5052 int targetUid = targetActivityInfo.applicationInfo.uid; 5053 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 5054 if (!isExportedSystemActivity(targetActivityInfo) 5055 && !pmi.hasSignatureCapability(targetUid, authUid, CertCapabilities.AUTH)) { 5056 String pkgName = targetActivityInfo.packageName; 5057 String activityName = targetActivityInfo.name; 5058 String tmpl = "KEY_INTENT resolved to an Activity (%s) in a package (%s) that " 5059 + "does not share a signature with the supplying authenticator (%s)."; 5060 Log.e(TAG, String.format(tmpl, activityName, pkgName, mAccountType)); 5061 return false; 5062 } 5063 return true; 5064 } finally { 5065 Binder.restoreCallingIdentity(bid); 5066 } 5067 } 5068 5069 /** 5070 * Simulate the client side's deserialization of KEY_INTENT value, to make sure they don't 5071 * violate our security policy. 5072 * 5073 * In particular we want to make sure the Authenticator doesn't trick users 5074 * into launching arbitrary intents on the device via exploiting any other Parcel read/write 5075 * mismatch problems. 5076 */ 5077 private boolean checkKeyIntentParceledCorrectly(Bundle bundle) { 5078 Parcel p = Parcel.obtain(); 5079 p.writeBundle(bundle); 5080 p.setDataPosition(0); 5081 Bundle simulateBundle = p.readBundle(); 5082 p.recycle(); 5083 Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class); 5084 if (intent != null && intent.getClass() != Intent.class) { 5085 return false; 5086 } 5087 Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT, 5088 Intent.class); 5089 if (intent == null) { 5090 return (simulateIntent == null); 5091 } 5092 if (!intent.filterEquals(simulateIntent)) { 5093 return false; 5094 } 5095 5096 if (intent.getSelector() != simulateIntent.getSelector()) { 5097 return false; 5098 } 5099 5100 int prohibitedFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION 5101 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION 5102 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5103 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5104 return (simulateIntent.getFlags() & prohibitedFlags) == 0; 5105 } 5106 5107 private boolean isExportedSystemActivity(ActivityInfo activityInfo) { 5108 String className = activityInfo.name; 5109 if (!"android".equals(activityInfo.packageName)) { 5110 return false; 5111 5112 } 5113 return (mCanStartAccountManagerActivity 5114 && GrantCredentialsPermissionActivity.class.getName().equals(className)) 5115 || CantAddAccountActivity.class.getName().equals(className); 5116 } 5117 5118 private void close() { 5119 synchronized (mSessions) { 5120 if (mSessions.remove(toString()) == null) { 5121 // the session was already closed, so bail out now 5122 return; 5123 } 5124 } 5125 if (mResponse != null) { 5126 // stop listening for response deaths 5127 mResponse.asBinder().unlinkToDeath(this, 0 /* flags */); 5128 5129 // clear this so that we don't accidentally send any further results 5130 mResponse = null; 5131 } 5132 cancelTimeout(); 5133 unbind(); 5134 } 5135 5136 @Override 5137 public void binderDied() { 5138 mResponse = null; 5139 close(); 5140 } 5141 5142 protected String toDebugString() { 5143 return toDebugString(SystemClock.elapsedRealtime()); 5144 } 5145 5146 protected String toDebugString(long now) { 5147 return "Session: expectLaunch " + mExpectActivityLaunch 5148 + ", connected " + (mAuthenticator != null) 5149 + ", stats (" + mNumResults + "/" + mNumRequestContinued 5150 + "/" + mNumErrors + ")" 5151 + ", lifetime " + ((now - mCreationTime) / 1000.0); 5152 } 5153 5154 void bind() { 5155 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5156 Log.v(TAG, "initiating bind to authenticator type " + mAccountType); 5157 } 5158 if (!bindToAuthenticator(mAccountType)) { 5159 Log.w(TAG, "bind attempt failed for " + toDebugString()); 5160 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure"); 5161 } 5162 } 5163 5164 private void unbind() { 5165 synchronized (mSessionLock) { 5166 if (mAuthenticator != null) { 5167 mAuthenticator = null; 5168 mContext.unbindService(this); 5169 } 5170 } 5171 } 5172 5173 private void scheduleTimeout() { 5174 mHandler.sendMessageDelayed( 5175 mHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS); 5176 } 5177 5178 public void cancelTimeout() { 5179 mHandler.removeMessages(MESSAGE_TIMED_OUT, this); 5180 } 5181 5182 @Override 5183 public void onServiceConnected(ComponentName name, IBinder service) { 5184 synchronized (mSessionLock) { 5185 mAuthenticator = IAccountAuthenticator.Stub.asInterface(service); 5186 try { 5187 run(); 5188 } catch (RemoteException e) { 5189 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, 5190 "remote exception"); 5191 } 5192 } 5193 } 5194 5195 @Override 5196 public void onServiceDisconnected(ComponentName name) { 5197 IAccountManagerResponse response = getResponseAndClose(); 5198 if (response != null) { 5199 try { 5200 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, 5201 "disconnected"); 5202 } catch (RemoteException e) { 5203 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5204 Log.v(TAG, "Session.onServiceDisconnected: " 5205 + "caught RemoteException while responding", e); 5206 } 5207 } 5208 } 5209 } 5210 5211 public abstract void run() throws RemoteException; 5212 5213 public void onTimedOut() { 5214 IAccountManagerResponse response = getResponseAndClose(); 5215 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5216 Log.v(TAG, "Session.onTimedOut"); 5217 } 5218 if (response != null) { 5219 try { 5220 response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, 5221 "timeout"); 5222 } catch (RemoteException e) { 5223 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5224 Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding", 5225 e); 5226 } 5227 } 5228 } 5229 } 5230 5231 @Override 5232 public void onResult(Bundle result) { 5233 Bundle.setDefusable(result, true); 5234 mNumResults++; 5235 Intent intent = null; 5236 if (result != null) { 5237 boolean isSuccessfulConfirmCreds = result.getBoolean( 5238 AccountManager.KEY_BOOLEAN_RESULT, false); 5239 boolean isSuccessfulUpdateCredsOrAddAccount = 5240 result.containsKey(AccountManager.KEY_ACCOUNT_NAME) 5241 && result.containsKey(AccountManager.KEY_ACCOUNT_TYPE); 5242 // We should only update lastAuthenticated time, if 5243 // mUpdateLastAuthenticatedTime is true and the confirmRequest 5244 // or updateRequest was successful 5245 boolean needUpdate = mUpdateLastAuthenticatedTime 5246 && (isSuccessfulConfirmCreds || isSuccessfulUpdateCredsOrAddAccount); 5247 if (needUpdate || mAuthDetailsRequired) { 5248 boolean accountPresent = isAccountPresentForCaller(mAccountName, mAccountType); 5249 if (needUpdate && accountPresent) { 5250 updateLastAuthenticatedTime(new Account(mAccountName, mAccountType)); 5251 } 5252 if (mAuthDetailsRequired) { 5253 long lastAuthenticatedTime = -1; 5254 if (accountPresent) { 5255 lastAuthenticatedTime = mAccounts.accountsDb 5256 .findAccountLastAuthenticatedTime( 5257 new Account(mAccountName, mAccountType)); 5258 } 5259 result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME, 5260 lastAuthenticatedTime); 5261 } 5262 } 5263 } 5264 if (result != null) { 5265 if (!checkKeyIntent( 5266 Binder.getCallingUid(), 5267 result)) { 5268 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 5269 "invalid intent in bundle returned"); 5270 return; 5271 } 5272 } 5273 if (result != null 5274 && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) { 5275 String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME); 5276 String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE); 5277 if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { 5278 Account account = new Account(accountName, accountType); 5279 cancelNotification(getSigninRequiredNotificationId(mAccounts, account), 5280 mAccounts); 5281 } 5282 } 5283 IAccountManagerResponse response; 5284 if (mExpectActivityLaunch && result != null 5285 && result.containsKey(AccountManager.KEY_INTENT)) { 5286 response = mResponse; 5287 } else { 5288 response = getResponseAndClose(); 5289 } 5290 if (response != null) { 5291 try { 5292 if (result == null) { 5293 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5294 Log.v(TAG, getClass().getSimpleName() 5295 + " calling onError() on response " + response); 5296 } 5297 response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 5298 "null bundle returned"); 5299 } else { 5300 if (mStripAuthTokenFromResult) { 5301 result.remove(AccountManager.KEY_AUTHTOKEN); 5302 if (!checkKeyIntent(Binder.getCallingUid(), result)) { 5303 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, 5304 "invalid intent in bundle returned"); 5305 return; 5306 } 5307 } 5308 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5309 Log.v(TAG, getClass().getSimpleName() 5310 + " calling onResult() on response " + response); 5311 } 5312 if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0) && 5313 (intent == null)) { 5314 // All AccountManager error codes are greater than 0 5315 response.onError(result.getInt(AccountManager.KEY_ERROR_CODE), 5316 result.getString(AccountManager.KEY_ERROR_MESSAGE)); 5317 } else { 5318 response.onResult(result); 5319 } 5320 } 5321 } catch (RemoteException e) { 5322 // if the caller is dead then there is no one to care about remote exceptions 5323 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5324 Log.v(TAG, "failure while notifying response", e); 5325 } 5326 } 5327 } 5328 } 5329 5330 @Override 5331 public void onRequestContinued() { 5332 mNumRequestContinued++; 5333 } 5334 5335 @Override 5336 public void onError(int errorCode, String errorMessage) { 5337 mNumErrors++; 5338 IAccountManagerResponse response = getResponseAndClose(); 5339 if (response != null) { 5340 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5341 Log.v(TAG, getClass().getSimpleName() 5342 + " calling onError() on response " + response); 5343 } 5344 try { 5345 response.onError(errorCode, errorMessage); 5346 } catch (RemoteException e) { 5347 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5348 Log.v(TAG, "Session.onError: caught RemoteException while responding", e); 5349 } 5350 } 5351 } else { 5352 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5353 Log.v(TAG, "Session.onError: already closed"); 5354 } 5355 } 5356 } 5357 5358 /** 5359 * find the component name for the authenticator and initiate a bind 5360 * if no authenticator or the bind fails then return false, otherwise return true 5361 */ 5362 private boolean bindToAuthenticator(String authenticatorType) { 5363 final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo; 5364 authenticatorInfo = mAuthenticatorCache.getServiceInfo( 5365 AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId); 5366 if (authenticatorInfo == null) { 5367 Log.w(TAG, "there is no authenticator for " + authenticatorType 5368 + ", bailing out"); 5369 5370 return false; 5371 } 5372 5373 if (!isLocalUnlockedUser(mAccounts.userId) 5374 && !authenticatorInfo.componentInfo.directBootAware) { 5375 Slog.w(TAG, "Blocking binding to authenticator " + authenticatorInfo.componentName 5376 + " which isn't encryption aware"); 5377 return false; 5378 } 5379 5380 Intent intent = new Intent(); 5381 intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT); 5382 intent.setComponent(authenticatorInfo.componentName); 5383 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5384 Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName); 5385 } 5386 long flags = Context.BIND_AUTO_CREATE; 5387 if (mAuthenticatorCache.getBindInstantServiceAllowed(mAccounts.userId)) { 5388 flags |= Context.BIND_ALLOW_INSTANT; 5389 } 5390 if (!mContext.bindServiceAsUser(intent, this, Context.BindServiceFlags.of(flags), 5391 UserHandle.of(mAccounts.userId))) { 5392 Log.w(TAG, "bindService to " + authenticatorInfo.componentName + " failed"); 5393 // Perform unbind as per documentation at Context.bindServiceAsUser 5394 mContext.unbindService(this); 5395 return false; 5396 } 5397 mAuthenticatorUid = authenticatorInfo.uid; 5398 mBindingStartTime = SystemClock.uptimeMillis(); 5399 return true; 5400 } 5401 } 5402 5403 class MessageHandler extends Handler { 5404 MessageHandler(Looper looper) { 5405 super(looper); 5406 } 5407 5408 @Override 5409 public void handleMessage(Message msg) { 5410 switch (msg.what) { 5411 case MESSAGE_TIMED_OUT: 5412 Session session = (Session)msg.obj; 5413 session.onTimedOut(); 5414 break; 5415 5416 case MESSAGE_COPY_SHARED_ACCOUNT: 5417 copyAccountToUser(/*no response*/ null, (Account) msg.obj, msg.arg1, msg.arg2); 5418 break; 5419 5420 default: 5421 throw new IllegalStateException("unhandled message: " + msg.what); 5422 } 5423 } 5424 } 5425 5426 private void logRecord(UserAccounts accounts, String action, String tableName) { 5427 logRecord(action, tableName, -1, accounts); 5428 } 5429 5430 private void logRecordWithUid(UserAccounts accounts, String action, String tableName, int uid) { 5431 logRecord(action, tableName, -1, accounts, uid); 5432 } 5433 5434 /* 5435 * This function receives an opened writable database. 5436 */ 5437 private void logRecord(String action, String tableName, long accountId, 5438 UserAccounts userAccount) { 5439 logRecord(action, tableName, accountId, userAccount, getCallingUid()); 5440 } 5441 5442 /* 5443 * This function receives an opened writable database and writes to it in a separate thread. 5444 */ 5445 private void logRecord(String action, String tableName, long accountId, 5446 UserAccounts userAccount, int callingUid) { 5447 5448 class LogRecordTask implements Runnable { 5449 private final String action; 5450 private final String tableName; 5451 private final long accountId; 5452 private final UserAccounts userAccount; 5453 private final int callingUid; 5454 private final long userDebugDbInsertionPoint; 5455 5456 LogRecordTask(final String action, 5457 final String tableName, 5458 final long accountId, 5459 final UserAccounts userAccount, 5460 final int callingUid, 5461 final long userDebugDbInsertionPoint) { 5462 this.action = action; 5463 this.tableName = tableName; 5464 this.accountId = accountId; 5465 this.userAccount = userAccount; 5466 this.callingUid = callingUid; 5467 this.userDebugDbInsertionPoint = userDebugDbInsertionPoint; 5468 } 5469 5470 @Override 5471 public void run() { 5472 synchronized (userAccount.accountsDb.mDebugStatementLock) { 5473 SQLiteStatement logStatement = userAccount.accountsDb.getStatementForLogging(); 5474 if (logStatement == null) { 5475 return; // Can't log. 5476 } 5477 logStatement.bindLong(1, accountId); 5478 logStatement.bindString(2, action); 5479 logStatement.bindString(3, mDateFormat.format(new Date())); 5480 logStatement.bindLong(4, callingUid); 5481 logStatement.bindString(5, tableName); 5482 logStatement.bindLong(6, userDebugDbInsertionPoint); 5483 try { 5484 logStatement.execute(); 5485 } catch (IllegalStateException | SQLiteFullException e) { 5486 // Guard against crash, DB can already be closed 5487 // since this statement is executed on a handler thread 5488 Slog.w(TAG, "Failed to insert a log record. accountId=" + accountId 5489 + " action=" + action + " tableName=" + tableName + " Error: " + e); 5490 } finally { 5491 logStatement.clearBindings(); 5492 } 5493 } 5494 } 5495 } 5496 long insertionPoint = userAccount.accountsDb.reserveDebugDbInsertionPoint(); 5497 if (insertionPoint != -1) { 5498 LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount, 5499 callingUid, insertionPoint); 5500 mHandler.post(logTask); 5501 } 5502 } 5503 5504 public IBinder onBind(@SuppressWarnings("unused") Intent intent) { 5505 return asBinder(); 5506 } 5507 5508 /** 5509 * Searches array of arguments for the specified string 5510 * @param args array of argument strings 5511 * @param value value to search for 5512 * @return true if the value is contained in the array 5513 */ 5514 private static boolean scanArgs(String[] args, String value) { 5515 if (args != null) { 5516 for (String arg : args) { 5517 if (value.equals(arg)) { 5518 return true; 5519 } 5520 } 5521 } 5522 return false; 5523 } 5524 5525 @Override 5526 protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 5527 if (!DumpUtils.checkDumpPermission(mContext, TAG, fout)) return; 5528 final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c"); 5529 final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, " "); 5530 5531 final List<UserInfo> users = getUserManager().getUsers(); 5532 for (UserInfo user : users) { 5533 ipw.println("User " + user + ":"); 5534 ipw.increaseIndent(); 5535 dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest); 5536 ipw.println(); 5537 ipw.decreaseIndent(); 5538 } 5539 } 5540 5541 private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout, 5542 String[] args, boolean isCheckinRequest) { 5543 if (isCheckinRequest) { 5544 // This is a checkin request. *Only* upload the account types and the count of 5545 // each. 5546 synchronized (userAccounts.dbLock) { 5547 userAccounts.accountsDb.dumpDeAccountsTable(fout); 5548 } 5549 } else { 5550 Account[] accounts = getAccountsFromCache(userAccounts, null /* type */, 5551 Process.SYSTEM_UID, "android" /* packageName */, false); 5552 fout.println("Accounts: " + accounts.length); 5553 for (Account account : accounts) { 5554 fout.println(" " + account.toString()); 5555 } 5556 5557 // Add debug information. 5558 fout.println(); 5559 synchronized (userAccounts.dbLock) { 5560 userAccounts.accountsDb.dumpDebugTable(fout); 5561 } 5562 fout.println(); 5563 synchronized (mSessions) { 5564 final long now = SystemClock.elapsedRealtime(); 5565 fout.println("Active Sessions: " + mSessions.size()); 5566 for (Session session : mSessions.values()) { 5567 fout.println(" " + session.toDebugString(now)); 5568 } 5569 } 5570 5571 fout.println(); 5572 mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId); 5573 5574 boolean isUserUnlocked; 5575 synchronized (mUsers) { 5576 isUserUnlocked = isLocalUnlockedUser(userAccounts.userId); 5577 } 5578 // Following logs are printed only when user is unlocked. 5579 if (!isUserUnlocked) { 5580 return; 5581 } 5582 fout.println(); 5583 synchronized (userAccounts.dbLock) { 5584 Map<Account, Map<String, Integer>> allVisibilityValues = 5585 userAccounts.accountsDb.findAllVisibilityValues(); 5586 fout.println("Account visibility:"); 5587 for (Account account : allVisibilityValues.keySet()) { 5588 fout.println(" " + account.name); 5589 Map<String, Integer> visibilities = allVisibilityValues.get(account); 5590 for (Entry<String, Integer> entry : visibilities.entrySet()) { 5591 fout.println(" " + entry.getKey() + ", " + entry.getValue()); 5592 } 5593 } 5594 } 5595 } 5596 } 5597 5598 private void doNotification(UserAccounts accounts, Account account, CharSequence message, 5599 Intent intent, String packageName, final int userId) { 5600 final long identityToken = clearCallingIdentity(); 5601 try { 5602 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5603 Log.v(TAG, "doNotification: " + message + " intent:" + intent); 5604 } 5605 5606 if (intent.getComponent() != null && 5607 GrantCredentialsPermissionActivity.class.getName().equals( 5608 intent.getComponent().getClassName())) { 5609 createNoCredentialsPermissionNotification(account, intent, packageName, accounts); 5610 } else { 5611 Context contextForUser = getContextForUser(new UserHandle(userId)); 5612 final NotificationId id = getSigninRequiredNotificationId(accounts, account); 5613 intent.addCategory(id.mTag); 5614 5615 final String notificationTitleFormat = 5616 contextForUser.getText(R.string.notification_title).toString(); 5617 Notification n = 5618 new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT) 5619 .setWhen(0) 5620 .setSmallIcon(android.R.drawable.stat_sys_warning) 5621 .setColor(contextForUser.getColor( 5622 com.android.internal.R.color.system_notification_accent_color)) 5623 .setContentTitle(String.format(notificationTitleFormat, account.name)) 5624 .setContentText(message) 5625 .setContentIntent(PendingIntent.getActivityAsUser( 5626 mContext, 0, intent, 5627 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, 5628 null, new UserHandle(userId))) 5629 .build(); 5630 installNotification(id, n, packageName, userId); 5631 } 5632 } finally { 5633 restoreCallingIdentity(identityToken); 5634 } 5635 } 5636 5637 private void installNotification(NotificationId id, final Notification notification, 5638 String packageName, int userId) { 5639 final long token = clearCallingIdentity(); 5640 try { 5641 INotificationManager notificationManager = mInjector.getNotificationManager(); 5642 try { 5643 // The calling uid must match either the package or op package, so use an op 5644 // package that matches the cleared calling identity. 5645 notificationManager.enqueueNotificationWithTag(packageName, "android", 5646 id.mTag, id.mId, notification, userId); 5647 } catch (RemoteException e) { 5648 /* ignore - local call */ 5649 } 5650 } finally { 5651 Binder.restoreCallingIdentity(token); 5652 } 5653 } 5654 5655 private void cancelNotification(NotificationId id, UserAccounts accounts) { 5656 cancelNotification(id, mContext.getPackageName(), accounts); 5657 } 5658 5659 private void cancelNotification(NotificationId id, String packageName, UserAccounts accounts) { 5660 final long identityToken = clearCallingIdentity(); 5661 try { 5662 INotificationManager service = mInjector.getNotificationManager(); 5663 service.cancelNotificationWithTag( 5664 packageName, "android", id.mTag, id.mId, 5665 UserHandle.of(accounts.userId).getIdentifier()); 5666 } catch (RemoteException e) { 5667 /* ignore - local call */ 5668 } finally { 5669 restoreCallingIdentity(identityToken); 5670 } 5671 } 5672 5673 private boolean isPermittedForPackage(String packageName, int userId, String... permissions) { 5674 final long identity = Binder.clearCallingIdentity(); 5675 try { 5676 final int uid = mPackageManager.getPackageUidAsUser(packageName, userId); 5677 IPackageManager pm = ActivityThread.getPackageManager(); 5678 for (String perm : permissions) { 5679 if (pm.checkPermission(perm, packageName, userId) 5680 == PackageManager.PERMISSION_GRANTED) { 5681 // Checks runtime permission revocation. 5682 final int opCode = AppOpsManager.permissionToOpCode(perm); 5683 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.checkOpNoThrow( 5684 opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) { 5685 return true; 5686 } 5687 } 5688 } 5689 } catch (NameNotFoundException | RemoteException e) { 5690 // Assume permission is not granted if an error accrued. 5691 } finally { 5692 Binder.restoreCallingIdentity(identity); 5693 } 5694 return false; 5695 } 5696 5697 /** 5698 * Checks that package has at least one of given permissions and makes note of app 5699 * performing the action. 5700 */ 5701 private boolean checkPermissionAndNote(String opPackageName, int callingUid, 5702 String... permissions) { 5703 for (String perm : permissions) { 5704 if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) { 5705 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5706 Log.v(TAG, " caller uid " + callingUid + " has " + perm); 5707 } 5708 final int opCode = AppOpsManager.permissionToOpCode(perm); 5709 if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow( 5710 opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) { 5711 return true; 5712 } 5713 } 5714 } 5715 return false; 5716 } 5717 5718 private int handleIncomingUser(int userId) { 5719 try { 5720 return ActivityManager.getService().handleIncomingUser( 5721 Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null); 5722 } catch (RemoteException re) { 5723 // Shouldn't happen, local. 5724 } 5725 return userId; 5726 } 5727 5728 private boolean isPrivileged(int callingUid) { 5729 String[] packages; 5730 final long identityToken = Binder.clearCallingIdentity(); 5731 try { 5732 packages = mPackageManager.getPackagesForUid(callingUid); 5733 if (packages == null) { 5734 Log.d(TAG, "No packages for callingUid " + callingUid); 5735 return false; 5736 } 5737 for (String name : packages) { 5738 try { 5739 PackageInfo packageInfo = 5740 mPackageManager.getPackageInfo(name, 0 /* flags */); 5741 if (packageInfo != null 5742 && (packageInfo.applicationInfo.privateFlags 5743 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { 5744 return true; 5745 } 5746 } catch (PackageManager.NameNotFoundException e) { 5747 Log.w(TAG, "isPrivileged#Package not found " + e.getMessage()); 5748 } 5749 } 5750 } finally { 5751 Binder.restoreCallingIdentity(identityToken); 5752 } 5753 return false; 5754 } 5755 5756 private boolean permissionIsGranted( 5757 Account account, String authTokenType, int callerUid, int userId) { 5758 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) { 5759 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5760 Log.v(TAG, "Access to " + account + " granted calling uid is system"); 5761 } 5762 return true; 5763 } 5764 5765 if (isPrivileged(callerUid)) { 5766 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5767 Log.v(TAG, "Access to " + account + " granted calling uid " 5768 + callerUid + " privileged"); 5769 } 5770 return true; 5771 } 5772 if (account != null && isAccountManagedByCaller(account.type, callerUid, userId)) { 5773 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5774 Log.v(TAG, "Access to " + account + " granted calling uid " 5775 + callerUid + " manages the account"); 5776 } 5777 return true; 5778 } 5779 if (account != null && hasExplicitlyGrantedPermission(account, authTokenType, callerUid)) { 5780 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5781 Log.v(TAG, "Access to " + account + " granted calling uid " 5782 + callerUid + " user granted access"); 5783 } 5784 return true; 5785 } 5786 5787 if (Log.isLoggable(TAG, Log.VERBOSE)) { 5788 Log.v(TAG, "Access to " + account + " not granted for uid " + callerUid); 5789 } 5790 5791 return false; 5792 } 5793 5794 private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId, 5795 String opPackageName) { 5796 if (accountType == null) { 5797 return false; 5798 } else { 5799 return getTypesVisibleToCaller(callingUid, userId, 5800 opPackageName).contains(accountType); 5801 } 5802 } 5803 5804 // Method checks visibility for applications targeing API level below {@link 5805 // android.os.Build.VERSION_CODES#O}, 5806 // returns true if the the app has GET_ACCOUNTS or GET_ACCOUNTS_PRIVILEGED permission. 5807 private boolean checkGetAccountsPermission(String packageName, int userId) { 5808 return isPermittedForPackage(packageName, userId, Manifest.permission.GET_ACCOUNTS, 5809 Manifest.permission.GET_ACCOUNTS_PRIVILEGED); 5810 } 5811 5812 private boolean checkReadContactsPermission(String packageName, int userId) { 5813 return isPermittedForPackage(packageName, userId, Manifest.permission.READ_CONTACTS); 5814 } 5815 5816 // Heuristic to check that account type may be associated with some contacts data and 5817 // therefore READ_CONTACTS permission grants the access to account by default. 5818 private boolean accountTypeManagesContacts(String accountType, int userId) { 5819 if (accountType == null) { 5820 return false; 5821 } 5822 final long identityToken = Binder.clearCallingIdentity(); 5823 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos; 5824 try { 5825 serviceInfos = mAuthenticatorCache.getAllServices(userId); 5826 } finally { 5827 Binder.restoreCallingIdentity(identityToken); 5828 } 5829 // Check contacts related permissions for authenticator. 5830 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo 5831 : serviceInfos) { 5832 if (accountType.equals(serviceInfo.type.type)) { 5833 return isPermittedForPackage(serviceInfo.type.packageName, userId, 5834 Manifest.permission.WRITE_CONTACTS); 5835 } 5836 } 5837 return false; 5838 } 5839 5840 /** 5841 * Method checks package uid and signature with Authenticator which manages accountType. 5842 * 5843 * @return SIGNATURE_CHECK_UID_MATCH for uid match, SIGNATURE_CHECK_MATCH for signature match, 5844 * SIGNATURE_CHECK_MISMATCH otherwise. 5845 */ 5846 private int checkPackageSignature(String accountType, int callingUid, int userId) { 5847 if (accountType == null) { 5848 return SIGNATURE_CHECK_MISMATCH; 5849 } 5850 5851 final long identityToken = Binder.clearCallingIdentity(); 5852 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos; 5853 try { 5854 serviceInfos = mAuthenticatorCache.getAllServices(userId); 5855 } finally { 5856 Binder.restoreCallingIdentity(identityToken); 5857 } 5858 // Check for signature match with Authenticator.LocalServices.getService(PackageManagerInternal.class); 5859 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 5860 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo 5861 : serviceInfos) { 5862 if (accountType.equals(serviceInfo.type.type)) { 5863 if (serviceInfo.uid == callingUid) { 5864 return SIGNATURE_CHECK_UID_MATCH; 5865 } 5866 if (pmi.hasSignatureCapability( 5867 serviceInfo.uid, callingUid, CertCapabilities.AUTH)) { 5868 return SIGNATURE_CHECK_MATCH; 5869 } 5870 } 5871 } 5872 return SIGNATURE_CHECK_MISMATCH; 5873 } 5874 5875 // returns true for applications with the same signature as authenticator. 5876 private boolean isAccountManagedByCaller(String accountType, int callingUid, int userId) { 5877 if (accountType == null) { 5878 return false; 5879 } else { 5880 return getTypesManagedByCaller(callingUid, userId).contains(accountType); 5881 } 5882 } 5883 5884 private List<String> getTypesVisibleToCaller(int callingUid, int userId, 5885 String opPackageName) { 5886 return getTypesForCaller(callingUid, userId, true /* isOtherwisePermitted*/); 5887 } 5888 5889 private List<String> getTypesManagedByCaller(int callingUid, int userId) { 5890 return getTypesForCaller(callingUid, userId, false); 5891 } 5892 5893 private List<String> getTypesForCaller( 5894 int callingUid, int userId, boolean isOtherwisePermitted) { 5895 List<String> managedAccountTypes = new ArrayList<>(); 5896 final long identityToken = Binder.clearCallingIdentity(); 5897 Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos; 5898 try { 5899 serviceInfos = mAuthenticatorCache.getAllServices(userId); 5900 } finally { 5901 Binder.restoreCallingIdentity(identityToken); 5902 } 5903 5904 PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); 5905 for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo : 5906 serviceInfos) { 5907 if (isOtherwisePermitted || pmi.hasSignatureCapability( 5908 serviceInfo.uid, callingUid, CertCapabilities.AUTH)) { 5909 managedAccountTypes.add(serviceInfo.type.type); 5910 } 5911 } 5912 return managedAccountTypes; 5913 } 5914 5915 private boolean isAccountPresentForCaller(String accountName, String accountType) { 5916 if (getUserAccountsForCaller().accountCache.containsKey(accountType)) { 5917 for (Account account : getUserAccountsForCaller().accountCache.get(accountType)) { 5918 if (account.name.equals(accountName)) { 5919 return true; 5920 } 5921 } 5922 } 5923 return false; 5924 } 5925 5926 private static void checkManageUsersPermission(String message) { 5927 if (ActivityManager.checkComponentPermission( 5928 android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true) 5929 != PackageManager.PERMISSION_GRANTED) { 5930 throw new SecurityException("You need MANAGE_USERS permission to: " + message); 5931 } 5932 } 5933 5934 private static void checkManageOrCreateUsersPermission(String message) { 5935 if (ActivityManager.checkComponentPermission(android.Manifest.permission.MANAGE_USERS, 5936 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED && 5937 ActivityManager.checkComponentPermission(android.Manifest.permission.CREATE_USERS, 5938 Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) { 5939 throw new SecurityException("You need MANAGE_USERS or CREATE_USERS permission to: " 5940 + message); 5941 } 5942 } 5943 5944 private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType, 5945 int callerUid) { 5946 if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) { 5947 return true; 5948 } 5949 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid)); 5950 synchronized (accounts.dbLock) { 5951 synchronized (accounts.cacheLock) { 5952 long grantsCount; 5953 if (authTokenType != null) { 5954 grantsCount = accounts.accountsDb 5955 .findMatchingGrantsCount(callerUid, authTokenType, account); 5956 } else { 5957 grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid, 5958 account); 5959 } 5960 final boolean permissionGranted = grantsCount > 0; 5961 5962 if (!permissionGranted && ActivityManager.isRunningInTestHarness()) { 5963 // TODO: Skip this check when running automated tests. Replace this 5964 // with a more general solution. 5965 Log.d(TAG, "no credentials permission for usage of " 5966 + account.toSafeString() + ", " 5967 + authTokenType + " by uid " + callerUid 5968 + " but ignoring since device is in test harness."); 5969 return true; 5970 } 5971 return permissionGranted; 5972 } 5973 } 5974 } 5975 5976 private boolean isSystemUid(int callingUid) { 5977 String[] packages = null; 5978 final long ident = Binder.clearCallingIdentity(); 5979 try { 5980 packages = mPackageManager.getPackagesForUid(callingUid); 5981 if (packages != null) { 5982 for (String name : packages) { 5983 try { 5984 PackageInfo packageInfo = 5985 mPackageManager.getPackageInfo(name, 0 /* flags */); 5986 if (packageInfo != null 5987 && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 5988 != 0) { 5989 return true; 5990 } 5991 } catch (NameNotFoundException e) { 5992 Log.w(TAG, String.format("Could not find package [%s]", name), e); 5993 } 5994 } 5995 } else { 5996 Log.w(TAG, "No known packages with uid " + callingUid); 5997 } 5998 } finally { 5999 Binder.restoreCallingIdentity(ident); 6000 } 6001 return false; 6002 } 6003 6004 /** Succeeds if any of the specified permissions are granted. */ 6005 private void checkReadAccountsPermitted( 6006 int callingUid, 6007 String accountType, 6008 int userId, 6009 String opPackageName) { 6010 if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) { 6011 String msg = String.format( 6012 "caller uid %s cannot access %s accounts", 6013 callingUid, 6014 accountType); 6015 Log.w(TAG, " " + msg); 6016 throw new SecurityException(msg); 6017 } 6018 } 6019 6020 private boolean canUserModifyAccounts(int userId, int callingUid) { 6021 // the managing app can always modify accounts 6022 if (isProfileOwner(callingUid)) { 6023 return true; 6024 } 6025 if (getUserManager().getUserRestrictions(new UserHandle(userId)) 6026 .getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) { 6027 return false; 6028 } 6029 return true; 6030 } 6031 6032 private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) { 6033 return Binder.withCleanCallingIdentity(() -> { 6034 // the managing app can always modify accounts 6035 if (isProfileOwner(callingUid)) { 6036 return true; 6037 } 6038 DevicePolicyManager dpm = (DevicePolicyManager) mContext 6039 .getSystemService(Context.DEVICE_POLICY_SERVICE); 6040 String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId); 6041 if (typesArray == null) { 6042 return true; 6043 } 6044 for (String forbiddenType : typesArray) { 6045 if (forbiddenType.equals(accountType)) { 6046 return false; 6047 } 6048 } 6049 return true; 6050 }); 6051 } 6052 6053 private boolean isProfileOwner(int uid) { 6054 final DevicePolicyManagerInternal dpmi = 6055 LocalServices.getService(DevicePolicyManagerInternal.class); 6056 //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. 6057 return (dpmi != null) && (dpmi.isActiveProfileOwner(uid) || dpmi.isActiveDeviceOwner(uid)); 6058 } 6059 6060 /** 6061 * Filter the access to the target package by rules of the package visibility if the caller 6062 * targeting API level U and above. Otherwise, returns true if the package is installed on 6063 * the device. 6064 * 6065 * @param targetPkgName The package name to check. 6066 * @param callingUid The caller that is going to access the package. 6067 * @param userId The user ID where the target package resides. 6068 * @return true if the caller is able to access the package. 6069 */ 6070 private boolean canCallerAccessPackage(@NonNull String targetPkgName, int callingUid, 6071 int userId) { 6072 final PackageManagerInternal pmInternal = 6073 LocalServices.getService(PackageManagerInternal.class); 6074 if (!CompatChanges.isChangeEnabled(ENFORCE_PACKAGE_VISIBILITY_FILTERING, callingUid)) { 6075 return pmInternal.getPackageUid( 6076 targetPkgName, 0 /* flags */, userId) != Process.INVALID_UID; 6077 } 6078 final boolean canAccess = !pmInternal.filterAppAccess(targetPkgName, callingUid, userId); 6079 if (!canAccess && Log.isLoggable(TAG, Log.DEBUG)) { 6080 Log.d(TAG, "Package " + targetPkgName + " is not visible to caller " + callingUid 6081 + " for user " + userId); 6082 } 6083 return canAccess; 6084 } 6085 6086 @Override 6087 public void updateAppPermission(Account account, String authTokenType, int uid, boolean value) 6088 throws RemoteException { 6089 final int callingUid = getCallingUid(); 6090 6091 if (UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) { 6092 throw new SecurityException(); 6093 } 6094 6095 if (value) { 6096 grantAppPermission(account, authTokenType, uid); 6097 } else { 6098 revokeAppPermission(account, authTokenType, uid); 6099 } 6100 } 6101 6102 /** 6103 * Allow callers with the given uid permission to get credentials for account/authTokenType. 6104 * <p> 6105 * Although this is public it can only be accessed via the AccountManagerService object 6106 * which is in the system. This means we don't need to protect it with permissions. 6107 * @hide 6108 */ 6109 void grantAppPermission(Account account, String authTokenType, int uid) { 6110 if (account == null || authTokenType == null) { 6111 Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception()); 6112 return; 6113 } 6114 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); 6115 synchronized (accounts.dbLock) { 6116 synchronized (accounts.cacheLock) { 6117 long accountId = accounts.accountsDb.findDeAccountId(account); 6118 if (accountId >= 0) { 6119 accounts.accountsDb.insertGrant(accountId, authTokenType, uid); 6120 } 6121 cancelNotification( 6122 getCredentialPermissionNotificationId( 6123 account, authTokenType, uid, accounts), 6124 accounts); 6125 6126 cancelAccountAccessRequestNotificationIfNeeded(account, uid, true, accounts); 6127 } 6128 } 6129 6130 // Listeners are a final CopyOnWriteArrayList, hence no lock needed. 6131 for (AccountManagerInternal.OnAppPermissionChangeListener listener 6132 : mAppPermissionChangeListeners) { 6133 mHandler.post(() -> listener.onAppPermissionChanged(account, uid)); 6134 } 6135 } 6136 6137 /** 6138 * Don't allow callers with the given uid permission to get credentials for 6139 * account/authTokenType. 6140 * <p> 6141 * Although this is public it can only be accessed via the AccountManagerService object 6142 * which is in the system. This means we don't need to protect it with permissions. 6143 * @hide 6144 */ 6145 private void revokeAppPermission(Account account, String authTokenType, int uid) { 6146 if (account == null || authTokenType == null) { 6147 Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception()); 6148 return; 6149 } 6150 UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid)); 6151 synchronized (accounts.dbLock) { 6152 synchronized (accounts.cacheLock) { 6153 accounts.accountsDb.beginTransaction(); 6154 try { 6155 long accountId = accounts.accountsDb.findDeAccountId(account); 6156 if (accountId >= 0) { 6157 accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid( 6158 accountId, authTokenType, uid); 6159 accounts.accountsDb.setTransactionSuccessful(); 6160 } 6161 } finally { 6162 accounts.accountsDb.endTransaction(); 6163 } 6164 6165 cancelNotification( 6166 getCredentialPermissionNotificationId( 6167 account, authTokenType, uid, accounts), 6168 accounts); 6169 } 6170 } 6171 6172 // Listeners are a final CopyOnWriteArrayList, hence no lock needed. 6173 for (AccountManagerInternal.OnAppPermissionChangeListener listener 6174 : mAppPermissionChangeListeners) { 6175 mHandler.post(() -> listener.onAppPermissionChanged(account, uid)); 6176 } 6177 } 6178 6179 private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) { 6180 final Account[] oldAccountsForType = accounts.accountCache.get(account.type); 6181 if (oldAccountsForType != null) { 6182 ArrayList<Account> newAccountsList = new ArrayList<>(); 6183 for (Account curAccount : oldAccountsForType) { 6184 if (!curAccount.equals(account)) { 6185 newAccountsList.add(curAccount); 6186 } 6187 } 6188 if (newAccountsList.isEmpty()) { 6189 accounts.accountCache.remove(account.type); 6190 } else { 6191 Account[] newAccountsForType = new Account[newAccountsList.size()]; 6192 newAccountsForType = newAccountsList.toArray(newAccountsForType); 6193 accounts.accountCache.put(account.type, newAccountsForType); 6194 } 6195 } 6196 accounts.userDataCache.remove(account); 6197 accounts.authTokenCache.remove(account); 6198 accounts.previousNameCache.remove(account); 6199 accounts.visibilityCache.remove(account); 6200 6201 AccountManager.invalidateLocalAccountsDataCaches(); 6202 } 6203 6204 /** 6205 * This assumes that the caller has already checked that the account is not already present. 6206 * IMPORTANT: The account being inserted will begin to be tracked for access in remote 6207 * processes and if you will return this account to apps you should return the result. 6208 * @return The inserted account which is a new instance that is being tracked. 6209 */ 6210 private Account insertAccountIntoCacheLocked(UserAccounts accounts, Account account) { 6211 Account[] accountsForType = accounts.accountCache.get(account.type); 6212 int oldLength = (accountsForType != null) ? accountsForType.length : 0; 6213 Account[] newAccountsForType = new Account[oldLength + 1]; 6214 if (accountsForType != null) { 6215 System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength); 6216 } 6217 String token = account.getAccessId() != null ? account.getAccessId() 6218 : UUID.randomUUID().toString(); 6219 newAccountsForType[oldLength] = new Account(account, token); 6220 accounts.accountCache.put(account.type, newAccountsForType); 6221 AccountManager.invalidateLocalAccountsDataCaches(); 6222 return newAccountsForType[oldLength]; 6223 } 6224 6225 @NonNull 6226 private Account[] filterAccounts(UserAccounts accounts, Account[] unfiltered, int callingUid, 6227 @Nullable String callingPackage, boolean includeManagedNotVisible) { 6228 String visibilityFilterPackage = callingPackage; 6229 if (visibilityFilterPackage == null) { 6230 visibilityFilterPackage = getPackageNameForUid(callingUid); 6231 } 6232 Map<Account, Integer> firstPass = new LinkedHashMap<>(); 6233 for (Account account : unfiltered) { 6234 int visibility = resolveAccountVisibility(account, visibilityFilterPackage, accounts); 6235 if ((visibility == AccountManager.VISIBILITY_VISIBLE 6236 || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) 6237 || (includeManagedNotVisible 6238 && (visibility 6239 == AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE))) { 6240 firstPass.put(account, visibility); 6241 } 6242 } 6243 Map<Account, Integer> secondPass = 6244 filterSharedAccounts(accounts, firstPass, callingUid, callingPackage); 6245 6246 Account[] filtered = new Account[secondPass.size()]; 6247 filtered = secondPass.keySet().toArray(filtered); 6248 return filtered; 6249 } 6250 6251 @NonNull 6252 private Map<Account, Integer> filterSharedAccounts(UserAccounts userAccounts, 6253 @NonNull Map<Account, Integer> unfiltered, int callingUid, 6254 @Nullable String callingPackage) { 6255 // first part is to filter shared accounts. 6256 // unfiltered type check is not necessary. 6257 if (getUserManager() == null || userAccounts == null || userAccounts.userId < 0 6258 || callingUid == Process.SYSTEM_UID) { 6259 return unfiltered; 6260 } 6261 UserInfo user = getUserManager().getUserInfo(userAccounts.userId); 6262 if (user != null && user.isRestricted()) { 6263 String[] packages = mPackageManager.getPackagesForUid(callingUid); 6264 if (packages == null) { 6265 packages = new String[] {}; 6266 } 6267 // If any of the packages is a visible listed package, return the full set, 6268 // otherwise return non-shared accounts only. 6269 // This might be a temporary way to specify a visible list 6270 String visibleList = mContext.getResources().getString( 6271 com.android.internal.R.string.config_appsAuthorizedForSharedAccounts); 6272 for (String packageName : packages) { 6273 if (visibleList.contains(";" + packageName + ";")) { 6274 return unfiltered; 6275 } 6276 } 6277 Account[] sharedAccounts = getSharedAccountsAsUser(userAccounts.userId); 6278 if (ArrayUtils.isEmpty(sharedAccounts)) { 6279 return unfiltered; 6280 } 6281 String requiredAccountType = ""; 6282 try { 6283 // If there's an explicit callingPackage specified, check if that package 6284 // opted in to see restricted accounts. 6285 if (callingPackage != null) { 6286 PackageInfo pi = mPackageManager.getPackageInfo(callingPackage, 0); 6287 if (pi != null && pi.restrictedAccountType != null) { 6288 requiredAccountType = pi.restrictedAccountType; 6289 } 6290 } else { 6291 // Otherwise check if the callingUid has a package that has opted in 6292 for (String packageName : packages) { 6293 PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0); 6294 if (pi != null && pi.restrictedAccountType != null) { 6295 requiredAccountType = pi.restrictedAccountType; 6296 break; 6297 } 6298 } 6299 } 6300 } catch (NameNotFoundException e) { 6301 Log.w(TAG, "filterSharedAccounts#Package not found " + e.getMessage()); 6302 } 6303 Map<Account, Integer> filtered = new LinkedHashMap<>(); 6304 for (Map.Entry<Account, Integer> entry : unfiltered.entrySet()) { 6305 Account account = entry.getKey(); 6306 if (account.type.equals(requiredAccountType)) { 6307 filtered.put(account, entry.getValue()); 6308 } else { 6309 boolean found = false; 6310 for (Account shared : sharedAccounts) { 6311 if (shared.equals(account)) { 6312 found = true; 6313 break; 6314 } 6315 } 6316 if (!found) { 6317 filtered.put(account, entry.getValue()); 6318 } 6319 } 6320 } 6321 return filtered; 6322 } else { 6323 return unfiltered; 6324 } 6325 } 6326 6327 /* 6328 * packageName can be null. If not null, it should be used to filter out restricted accounts 6329 * that the package is not allowed to access. 6330 * 6331 * <p>The method shouldn't be called with UserAccounts#cacheLock held, otherwise it will cause a 6332 * deadlock 6333 */ 6334 @NonNull 6335 protected Account[] getAccountsFromCache(UserAccounts userAccounts, String accountType, 6336 int callingUid, @Nullable String callingPackage, boolean includeManagedNotVisible) { 6337 Preconditions.checkState(!Thread.holdsLock(userAccounts.cacheLock), 6338 "Method should not be called with cacheLock"); 6339 if (accountType != null) { 6340 Account[] accounts; 6341 synchronized (userAccounts.cacheLock) { 6342 accounts = userAccounts.accountCache.get(accountType); 6343 } 6344 if (accounts == null) { 6345 return EMPTY_ACCOUNT_ARRAY; 6346 } else { 6347 return filterAccounts(userAccounts, Arrays.copyOf(accounts, accounts.length), 6348 callingUid, callingPackage, includeManagedNotVisible); 6349 } 6350 } else { 6351 int totalLength = 0; 6352 Account[] accountsArray; 6353 synchronized (userAccounts.cacheLock) { 6354 for (Account[] accounts : userAccounts.accountCache.values()) { 6355 totalLength += accounts.length; 6356 } 6357 if (totalLength == 0) { 6358 return EMPTY_ACCOUNT_ARRAY; 6359 } 6360 accountsArray = new Account[totalLength]; 6361 totalLength = 0; 6362 for (Account[] accountsOfType : userAccounts.accountCache.values()) { 6363 System.arraycopy(accountsOfType, 0, accountsArray, totalLength, 6364 accountsOfType.length); 6365 totalLength += accountsOfType.length; 6366 } 6367 } 6368 return filterAccounts(userAccounts, accountsArray, callingUid, callingPackage, 6369 includeManagedNotVisible); 6370 } 6371 } 6372 6373 /** protected by the {@code dbLock}, {@code cacheLock} */ 6374 protected void writeUserDataIntoCacheLocked(UserAccounts accounts, 6375 Account account, String key, String value) { 6376 Map<String, String> userDataForAccount = accounts.userDataCache.get(account); 6377 if (userDataForAccount == null) { 6378 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account); 6379 accounts.userDataCache.put(account, userDataForAccount); 6380 } 6381 if (value == null) { 6382 userDataForAccount.remove(key); 6383 } else { 6384 userDataForAccount.put(key, value); 6385 } 6386 } 6387 6388 protected TokenCache.Value readCachedTokenInternal( 6389 UserAccounts accounts, 6390 Account account, 6391 String tokenType, 6392 String callingPackage, 6393 byte[] pkgSigDigest) { 6394 synchronized (accounts.cacheLock) { 6395 return accounts.accountTokenCaches.get( 6396 account, tokenType, callingPackage, pkgSigDigest); 6397 } 6398 } 6399 6400 /** protected by the {@code dbLock}, {@code cacheLock} */ 6401 protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, 6402 Account account, String key, String value) { 6403 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account); 6404 if (authTokensForAccount == null) { 6405 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account); 6406 accounts.authTokenCache.put(account, authTokensForAccount); 6407 } 6408 if (value == null) { 6409 authTokensForAccount.remove(key); 6410 } else { 6411 authTokensForAccount.put(key, value); 6412 } 6413 } 6414 6415 protected String readAuthTokenInternal(UserAccounts accounts, Account account, 6416 String authTokenType) { 6417 // Fast path - check if account is already cached 6418 synchronized (accounts.cacheLock) { 6419 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account); 6420 if (authTokensForAccount != null) { 6421 return authTokensForAccount.get(authTokenType); 6422 } 6423 } 6424 // If not cached yet - do slow path and sync with db if necessary 6425 synchronized (accounts.dbLock) { 6426 synchronized (accounts.cacheLock) { 6427 Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account); 6428 if (authTokensForAccount == null) { 6429 // need to populate the cache for this account 6430 authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account); 6431 accounts.authTokenCache.put(account, authTokensForAccount); 6432 } 6433 return authTokensForAccount.get(authTokenType); 6434 } 6435 } 6436 } 6437 6438 private String readUserDataInternal(UserAccounts accounts, Account account, String key) { 6439 Map<String, String> userDataForAccount; 6440 // Fast path - check if data is already cached 6441 synchronized (accounts.cacheLock) { 6442 userDataForAccount = accounts.userDataCache.get(account); 6443 } 6444 // If not cached yet - do slow path and sync with db if necessary 6445 if (userDataForAccount == null) { 6446 synchronized (accounts.dbLock) { 6447 synchronized (accounts.cacheLock) { 6448 userDataForAccount = accounts.userDataCache.get(account); 6449 if (userDataForAccount == null) { 6450 // need to populate the cache for this account 6451 userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account); 6452 accounts.userDataCache.put(account, userDataForAccount); 6453 } 6454 } 6455 } 6456 } 6457 return userDataForAccount.get(key); 6458 } 6459 6460 private Context getContextForUser(UserHandle user) { 6461 try { 6462 return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user); 6463 } catch (NameNotFoundException e) { 6464 // Default to mContext, not finding the package system is running as is unlikely. 6465 return mContext; 6466 } 6467 } 6468 6469 private void sendResponse(IAccountManagerResponse response, Bundle result) { 6470 try { 6471 response.onResult(result); 6472 } catch (RemoteException e) { 6473 // if the caller is dead then there is no one to care about remote 6474 // exceptions 6475 if (Log.isLoggable(TAG, Log.VERBOSE)) { 6476 Log.v(TAG, "failure while notifying response", e); 6477 } 6478 } 6479 } 6480 6481 private void sendErrorResponse(IAccountManagerResponse response, int errorCode, 6482 String errorMessage) { 6483 try { 6484 response.onError(errorCode, errorMessage); 6485 } catch (RemoteException e) { 6486 // if the caller is dead then there is no one to care about remote 6487 // exceptions 6488 if (Log.isLoggable(TAG, Log.VERBOSE)) { 6489 Log.v(TAG, "failure while notifying response", e); 6490 } 6491 } 6492 } 6493 6494 /** 6495 * Returns true if the config_canRemoveOrRenameFirstUser is false, and the given account type 6496 * matches the one provided by config_accountTypeToKeepFirstUser. 6497 */ 6498 private boolean isFirstAccountRemovalDisabled(Account account) { 6499 // Skip if not targeting the first user. 6500 int userId = UserHandle.getCallingUserId(); 6501 if (userId != 0) { 6502 return false; 6503 } 6504 6505 // Skip if we are allowed to remove/rename first account. 6506 if (mContext.getResources() 6507 .getBoolean(com.android.internal.R.bool.config_canRemoveFirstAccount)) { 6508 return false; 6509 } 6510 6511 // Skip if needed for testing. 6512 if (Settings.Secure.getIntForUser( 6513 mContext.getContentResolver(), 6514 Settings.Secure.ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS, 6515 0 /* default */, 6516 0 /* userHandle */) != 0) { 6517 return false; 6518 } 6519 6520 // Skip if not targeting desired account. 6521 String typeToKeep = 6522 mContext.getResources() 6523 .getString( 6524 com.android.internal.R.string.config_accountTypeToKeepFirstAccount); 6525 if (typeToKeep.isEmpty() || !typeToKeep.equals(account.type)) { 6526 return false; 6527 } 6528 6529 // Only restrict first account. 6530 UserAccounts accounts = getUserAccounts(0 /* userId */); 6531 Account[] accountsOfType = getAccountsFromCache(accounts, typeToKeep, 6532 Process.SYSTEM_UID, "android" /* packageName */, false); 6533 return accountsOfType.length > 0 && accountsOfType[0].equals(account); 6534 } 6535 6536 private final class AccountManagerInternalImpl extends AccountManagerInternal { 6537 private final Object mLock = new Object(); 6538 6539 @GuardedBy("mLock") 6540 private AccountManagerBackupHelper mBackupHelper; 6541 6542 @Override 6543 public void requestAccountAccess(@NonNull Account account, @NonNull String packageName, 6544 @IntRange(from = 0) int userId, @NonNull RemoteCallback callback) { 6545 if (account == null) { 6546 Slog.w(TAG, "account cannot be null"); 6547 return; 6548 } 6549 if (packageName == null) { 6550 Slog.w(TAG, "packageName cannot be null"); 6551 return; 6552 } 6553 if (userId < UserHandle.USER_SYSTEM) { 6554 Slog.w(TAG, "user id must be concrete"); 6555 return; 6556 } 6557 if (callback == null) { 6558 Slog.w(TAG, "callback cannot be null"); 6559 return; 6560 } 6561 6562 int visibility = 6563 resolveAccountVisibility(account, packageName, getUserAccounts(userId)); 6564 if (visibility == AccountManager.VISIBILITY_NOT_VISIBLE) { 6565 Slog.w(TAG, "requestAccountAccess: account is hidden"); 6566 return; 6567 } 6568 6569 if (AccountManagerService.this.hasAccountAccess(account, packageName, 6570 new UserHandle(userId))) { 6571 Bundle result = new Bundle(); 6572 result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true); 6573 callback.sendResult(result); 6574 return; 6575 } 6576 6577 final int uid; 6578 try { 6579 final long identityToken = clearCallingIdentity(); 6580 try { 6581 uid = mPackageManager.getPackageUidAsUser(packageName, userId); 6582 } finally { 6583 restoreCallingIdentity(identityToken); 6584 } 6585 } catch (NameNotFoundException e) { 6586 Slog.e(TAG, "Unknown package " + packageName); 6587 return; 6588 } 6589 6590 Intent intent = newRequestAccountAccessIntent(account, packageName, uid, callback); 6591 final UserAccounts userAccounts; 6592 synchronized (mUsers) { 6593 userAccounts = mUsers.get(userId); 6594 } 6595 SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext); 6596 doNotification(userAccounts, account, null, intent, packageName, userId); 6597 } 6598 6599 @Override 6600 public void addOnAppPermissionChangeListener(OnAppPermissionChangeListener listener) { 6601 // Listeners are a final CopyOnWriteArrayList, hence no lock needed. 6602 mAppPermissionChangeListeners.add(listener); 6603 } 6604 6605 @Override 6606 public boolean hasAccountAccess(@NonNull Account account, @IntRange(from = 0) int uid) { 6607 return AccountManagerService.this.hasAccountAccess(account, null, uid); 6608 } 6609 6610 @Override 6611 public byte[] backupAccountAccessPermissions(int userId) { 6612 synchronized (mLock) { 6613 if (mBackupHelper == null) { 6614 mBackupHelper = new AccountManagerBackupHelper( 6615 AccountManagerService.this, this); 6616 } 6617 return mBackupHelper.backupAccountAccessPermissions(userId); 6618 } 6619 } 6620 6621 @Override 6622 public void restoreAccountAccessPermissions(byte[] data, int userId) { 6623 synchronized (mLock) { 6624 if (mBackupHelper == null) { 6625 mBackupHelper = new AccountManagerBackupHelper( 6626 AccountManagerService.this, this); 6627 } 6628 mBackupHelper.restoreAccountAccessPermissions(data, userId); 6629 } 6630 } 6631 } 6632 6633 @VisibleForTesting 6634 static class Injector { 6635 private final Context mContext; 6636 6637 public Injector(Context context) { 6638 mContext = context; 6639 } 6640 6641 Looper getMessageHandlerLooper() { 6642 ServiceThread serviceThread = new ServiceThread(TAG, 6643 android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */); 6644 serviceThread.start(); 6645 return serviceThread.getLooper(); 6646 } 6647 6648 Context getContext() { 6649 return mContext; 6650 } 6651 6652 void addLocalService(AccountManagerInternal service) { 6653 LocalServices.addService(AccountManagerInternal.class, service); 6654 } 6655 6656 String getDeDatabaseName(int userId) { 6657 File databaseFile = new File(Environment.getDataSystemDeDirectory(userId), 6658 AccountsDb.DE_DATABASE_NAME); 6659 return databaseFile.getPath(); 6660 } 6661 6662 String getCeDatabaseName(int userId) { 6663 File databaseFile = new File(Environment.getDataSystemCeDirectory(userId), 6664 AccountsDb.CE_DATABASE_NAME); 6665 return databaseFile.getPath(); 6666 } 6667 6668 String getPreNDatabaseName(int userId) { 6669 File systemDir = Environment.getDataSystemDirectory(); 6670 File databaseFile = new File(Environment.getUserSystemDirectory(userId), 6671 PRE_N_DATABASE_NAME); 6672 if (userId == 0) { 6673 // Migrate old file, if it exists, to the new location. 6674 // Make sure the new file doesn't already exist. A placeholder file could have been 6675 // accidentally created in the old location, 6676 // causing the new one to become corrupted as well. 6677 File oldFile = new File(systemDir, PRE_N_DATABASE_NAME); 6678 if (oldFile.exists() && !databaseFile.exists()) { 6679 // Check for use directory; create if it doesn't exist, else renameTo will fail 6680 File userDir = Environment.getUserSystemDirectory(userId); 6681 if (!userDir.exists()) { 6682 if (!userDir.mkdirs()) { 6683 throw new IllegalStateException( 6684 "User dir cannot be created: " + userDir); 6685 } 6686 } 6687 if (!oldFile.renameTo(databaseFile)) { 6688 throw new IllegalStateException( 6689 "User dir cannot be migrated: " + databaseFile); 6690 } 6691 } 6692 } 6693 return databaseFile.getPath(); 6694 } 6695 6696 IAccountAuthenticatorCache getAccountAuthenticatorCache() { 6697 return new AccountAuthenticatorCache(mContext); 6698 } 6699 6700 INotificationManager getNotificationManager() { 6701 return NotificationManager.getService(); 6702 } 6703 } 6704 6705 private static class NotificationId { 6706 final String mTag; 6707 private final int mId; 6708 6709 NotificationId(String tag, int type) { 6710 mTag = tag; 6711 mId = type; 6712 } 6713 } 6714 } 6715