mirror of
https://github.com/YTVanced/VancedMicroG
synced 2024-11-27 21:53:00 +00:00
Allow to bypass Android O+ account restrictions for Google Apps
This commit is contained in:
parent
7a646e3346
commit
30ed2720a0
10 changed files with 147 additions and 21 deletions
|
@ -25,6 +25,7 @@ import android.content.pm.PackageManager;
|
|||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
@ -51,6 +52,7 @@ public class AccountContentProvider extends ContentProvider {
|
|||
@Nullable
|
||||
@Override
|
||||
public Bundle call(String method, String arg, Bundle extras) {
|
||||
String packageName = PackageUtils.packageFromProcessId(getContext(), Binder.getCallingPid());
|
||||
if (!PackageUtils.callerHasExtendedAccess(getContext())) {
|
||||
String[] packagesForUid = getContext().getPackageManager().getPackagesForUid(Binder.getCallingUid());
|
||||
if (packagesForUid != null && packagesForUid.length != 0)
|
||||
|
@ -61,7 +63,8 @@ public class AccountContentProvider extends ContentProvider {
|
|||
}
|
||||
if (PROVIDER_METHOD_GET_ACCOUNTS.equals(method) && AuthConstants.DEFAULT_ACCOUNT_TYPE.equals(arg)) {
|
||||
Bundle result = new Bundle();
|
||||
result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, AccountManager.get(getContext()).getAccountsByType(arg));
|
||||
AccountManager am = AccountManager.get(getContext());
|
||||
result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 ? am.getAccountsByTypeForPackage(arg, packageName) : am.getAccountsByType(arg));
|
||||
return result;
|
||||
} else if (PROVIDER_METHOD_CLEAR_PASSWORD.equals(method)) {
|
||||
Account a = extras.getParcelable(PROVIDER_EXTRA_CLEAR_PASSWORD);
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.content.pm.ApplicationInfo;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
|
@ -49,6 +50,7 @@ import static android.accounts.AccountManager.KEY_ACCOUNT_NAME;
|
|||
import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
|
||||
import static android.accounts.AccountManager.KEY_ANDROID_PACKAGE_NAME;
|
||||
import static android.accounts.AccountManager.KEY_AUTHTOKEN;
|
||||
import static android.accounts.AccountManager.KEY_CALLER_PID;
|
||||
import static android.accounts.AccountManager.KEY_CALLER_UID;
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
@ -96,7 +98,7 @@ public class AskPermissionActivity extends AccountAuthenticatorActivity {
|
|||
|
||||
if (getIntent().hasExtra(EXTRA_FROM_ACCOUNT_MANAGER)) fromAccountManager = true;
|
||||
int callerUid = getIntent().getIntExtra(KEY_CALLER_UID, 0);
|
||||
PackageUtils.checkPackageUid(this, packageName, callerUid);
|
||||
packageName = PackageUtils.getAndCheckPackage(this, packageName, getIntent().getIntExtra(KEY_CALLER_UID, 0), getIntent().getIntExtra(KEY_CALLER_PID, 0));
|
||||
authManager = new AuthManager(this, account.name, packageName, service);
|
||||
|
||||
// receive package info
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.accounts.Account;
|
|||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -35,6 +36,7 @@ public class AuthManager {
|
|||
private static final String TAG = "GmsAuthManager";
|
||||
public static final String PERMISSION_TREE_BASE = "com.google.android.googleapps.permission.GOOGLE_AUTH.";
|
||||
private static final String PREF_AUTH_TRUST_GOOGLE = "auth_manager_trust_google";
|
||||
public static final String PREF_AUTH_VISIBLE = "auth_manager_visible";
|
||||
public static final int ONE_HOUR_IN_SECONDS = 60 * 60;
|
||||
|
||||
private final Context context;
|
||||
|
@ -91,6 +93,10 @@ public class AuthManager {
|
|||
|
||||
public void setPermitted(boolean value) {
|
||||
setUserData(buildPermKey(), value ? "1" : "0");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && value && packageName != null) {
|
||||
// Make account persistently visible as we already granted access
|
||||
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPermitted() {
|
||||
|
@ -148,6 +154,10 @@ public class AuthManager {
|
|||
|
||||
public void setAuthToken(String service, String auth) {
|
||||
getAccountManager().setAuthToken(getAccount(), buildTokenKey(service), auth);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && packageName != null && auth != null) {
|
||||
// Make account persistently visible as we already granted access
|
||||
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void storeResponse(AuthResponse response) {
|
||||
|
@ -172,6 +182,10 @@ public class AuthManager {
|
|||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_TRUST_GOOGLE, true);
|
||||
}
|
||||
|
||||
public static boolean isAuthVisible(Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_VISIBLE, false);
|
||||
}
|
||||
|
||||
private boolean isSystemApp() {
|
||||
try {
|
||||
int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags;
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Base64;
|
||||
|
@ -44,6 +45,7 @@ import java.util.List;
|
|||
import static android.accounts.AccountManager.KEY_ACCOUNT_NAME;
|
||||
import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
|
||||
import static android.accounts.AccountManager.KEY_AUTHTOKEN;
|
||||
import static android.accounts.AccountManager.KEY_CALLER_PID;
|
||||
import static org.microg.gms.auth.AskPermissionActivity.EXTRA_CONSENT_DATA;
|
||||
|
||||
public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
||||
|
@ -74,8 +76,7 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
|||
String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME);
|
||||
if (packageName == null || packageName.isEmpty())
|
||||
packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME);
|
||||
int callerUid = extras.getInt(KEY_CALLER_UID, 0);
|
||||
PackageUtils.checkPackageUid(context, packageName, callerUid, getCallingUid());
|
||||
packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));
|
||||
boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false);
|
||||
|
||||
Log.d(TAG, "getToken: account:" + accountName + " scope:" + scope + " extras:" + extras + ", notify: " + notify);
|
||||
|
@ -163,10 +164,16 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
|||
public Bundle clearToken(String token, Bundle extras) throws RemoteException {
|
||||
String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME);
|
||||
if (packageName == null) packageName = extras.getString(KEY_CLIENT_PACKAGE_NAME);
|
||||
int callerUid = extras.getInt(KEY_CALLER_UID, 0);
|
||||
PackageUtils.checkPackageUid(context, packageName, callerUid, getCallingUid());
|
||||
packageName = PackageUtils.getAndCheckCallingPackage(context, packageName, extras.getInt(KEY_CALLER_UID, 0), extras.getInt(KEY_CALLER_PID, 0));
|
||||
|
||||
Log.d(TAG, "clearToken: token:" + token + " extras:" + extras);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
|
||||
if (super.onTransact(code, data, reply, flags)) return true;
|
||||
Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,8 @@ import org.microg.gms.people.PeopleManager;
|
|||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;
|
||||
import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.GINGERBREAD_MR1;
|
||||
import static android.os.Build.VERSION_CODES.HONEYCOMB;
|
||||
|
@ -130,9 +132,12 @@ public class LoginActivity extends AssistantActivity {
|
|||
});
|
||||
if (getIntent().hasExtra(EXTRA_TOKEN)) {
|
||||
if (getIntent().hasExtra(EXTRA_EMAIL)) {
|
||||
AccountManager accountManager = AccountManager.get(LoginActivity.this);
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), accountType);
|
||||
accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null);
|
||||
if (AuthManager.isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) {
|
||||
accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE);
|
||||
}
|
||||
retrieveGmsToken(account);
|
||||
} else {
|
||||
retrieveRtToken(getIntent().getStringExtra(EXTRA_TOKEN));
|
||||
|
|
|
@ -45,6 +45,7 @@ import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE;
|
|||
import static android.accounts.AccountManager.KEY_ANDROID_PACKAGE_NAME;
|
||||
import static android.accounts.AccountManager.KEY_AUTHTOKEN;
|
||||
import static android.accounts.AccountManager.KEY_BOOLEAN_RESULT;
|
||||
import static android.accounts.AccountManager.KEY_CALLER_PID;
|
||||
import static android.accounts.AccountManager.KEY_CALLER_UID;
|
||||
import static android.accounts.AccountManager.KEY_INTENT;
|
||||
|
||||
|
@ -90,7 +91,7 @@ class AccountAuthenticator extends AbstractAccountAuthenticator {
|
|||
options.keySet();
|
||||
Log.d(TAG, "getAuthToken: " + account + ", " + authTokenType + ", " + options);
|
||||
String app = options.getString(KEY_ANDROID_PACKAGE_NAME);
|
||||
PackageUtils.checkPackageUid(context, app, options.getInt(KEY_CALLER_UID), options.getInt(KEY_CALLER_UID));
|
||||
app = PackageUtils.getAndCheckPackage(context, app, options.getInt(KEY_CALLER_UID), options.getInt(KEY_CALLER_PID));
|
||||
AuthManager authManager = new AuthManager(context, account.name, app, authTokenType);
|
||||
try {
|
||||
AuthResponse res = authManager.requestAuth(true);
|
||||
|
|
|
@ -87,17 +87,7 @@ public class PackageUtils {
|
|||
}
|
||||
|
||||
public static void checkPackageUid(Context context, String packageName, int callingUid) {
|
||||
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null && !Arrays.asList(packagesForUid).contains(packageName)) {
|
||||
throw new SecurityException("callingUid [" + callingUid + "] is not related to packageName [" + packageName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkPackageUid(Context context, String packageName, int callerUid, int callingUid) {
|
||||
if (callerUid != 0 && callerUid != callingUid) {
|
||||
throw new SecurityException("callerUid [" + callerUid + "] and real calling uid [" + callingUid + "] mismatch!");
|
||||
}
|
||||
checkPackageUid(context, packageName, callingUid);
|
||||
getAndCheckPackage(context, packageName, callingUid, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -120,10 +110,62 @@ public class PackageUtils {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckCallingPackage(Context context, String suggestedPackageName) {
|
||||
return getAndCheckCallingPackage(context, suggestedPackageName, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckCallingPackage(Context context, int suggestedCallerUid) {
|
||||
return getAndCheckCallingPackage(context, null, suggestedCallerUid);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckCallingPackage(Context context, String suggestedPackageName, int suggestedCallerUid) {
|
||||
return getAndCheckCallingPackage(context, suggestedPackageName, suggestedCallerUid, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckCallingPackage(Context context, String suggestedPackageName, int suggestedCallerUid, int suggestedCallerPid) {
|
||||
int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();
|
||||
if (suggestedCallerUid > 0 && suggestedCallerUid != callingUid) {
|
||||
throw new SecurityException("suggested UID [" + suggestedCallerUid + "] and real calling UID [" + callingUid + "] mismatch!");
|
||||
}
|
||||
if (suggestedCallerPid > 0 && suggestedCallerPid != callingPid) {
|
||||
throw new SecurityException("suggested PID [" + suggestedCallerPid + "] and real calling PID [" + callingPid + "] mismatch!");
|
||||
}
|
||||
return getAndCheckPackage(context, suggestedPackageName, callingUid, Binder.getCallingPid());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckPackage(Context context, String suggestedPackageName, int callingUid) {
|
||||
return getAndCheckPackage(context, suggestedPackageName, callingUid, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getAndCheckPackage(Context context, String suggestedPackageName, int callingUid, int callingPid) {
|
||||
String packageName = packageFromProcessId(context, callingPid);
|
||||
if (packageName == null) {
|
||||
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null && packagesForUid.length != 0) {
|
||||
if (packagesForUid.length == 1) {
|
||||
packageName = packagesForUid[0];
|
||||
} else if (Arrays.asList(packagesForUid).contains(suggestedPackageName)) {
|
||||
packageName = suggestedPackageName;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packageName != null && !packageName.equals(suggestedPackageName)) {
|
||||
throw new SecurityException("UID [" + callingUid + "] is not related to packageName [" + packageName + "]");
|
||||
}
|
||||
return packageName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String packageFromProcessId(Context context, int pid) {
|
||||
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (manager == null) return null;
|
||||
if (pid <= 0) return null;
|
||||
for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
|
||||
if (processInfo.pid == pid) return processInfo.processName;
|
||||
}
|
||||
|
|
|
@ -16,12 +16,57 @@
|
|||
|
||||
package org.microg.gms.ui;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.preference.Preference;
|
||||
|
||||
import com.google.android.gms.R;
|
||||
|
||||
import org.microg.gms.auth.AuthConstants;
|
||||
import org.microg.gms.auth.AuthManager;
|
||||
import org.microg.tools.ui.AbstractSettingsActivity;
|
||||
import org.microg.tools.ui.ResourceSettingsFragment;
|
||||
|
||||
import static android.accounts.AccountManager.PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE;
|
||||
import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE;
|
||||
import static android.accounts.AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
|
||||
import static org.microg.gms.auth.AuthManager.PREF_AUTH_VISIBLE;
|
||||
|
||||
public class AccountSettingsActivity extends AbstractSettingsActivity {
|
||||
public AccountSettingsActivity() {
|
||||
preferencesResource = R.xml.preferences_account;
|
||||
|
||||
@Override
|
||||
protected Fragment getFragment() {
|
||||
return new AccountSettingsFragment();
|
||||
}
|
||||
|
||||
public static class AccountSettingsFragment extends ResourceSettingsFragment {
|
||||
public AccountSettingsFragment() {
|
||||
preferencesResource = R.xml.preferences_account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferencesFix(@Nullable Bundle savedInstanceState, String rootKey) {
|
||||
super.onCreatePreferencesFix(savedInstanceState, rootKey);
|
||||
Preference pref = findPreference(PREF_AUTH_VISIBLE);
|
||||
if (pref != null) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
pref.setVisible(false);
|
||||
} else {
|
||||
pref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
if (newValue instanceof Boolean) {
|
||||
AccountManager am = AccountManager.get(getContext());
|
||||
for (Account account : am.getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)) {
|
||||
am.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, (Boolean) newValue ? VISIBILITY_USER_MANAGED_VISIBLE : VISIBILITY_USER_MANAGED_NOT_VISIBLE);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,8 @@ This can take a couple of minutes."</string>
|
|||
|
||||
<string name="pref_auth_trust_google_title">Trust Google for app permissions</string>
|
||||
<string name="pref_auth_trust_google_summary">When disabled, the user is asked before an apps authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>
|
||||
<string name="pref_auth_visible_title">Allow apps to find accounts</string>
|
||||
<string name="pref_auth_visible_summary">When enabled, all applications on this device will be able to see email address of your Google Accounts without prior authorization.</string>
|
||||
|
||||
<string name="pref_checkin_enable_summary">Registers your device to Google services and creates a unique device identifier. microG strips identifying bits other than your Google account name from registration data.</string>
|
||||
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
android:key="auth_manager_trust_google"
|
||||
android:summary="@string/pref_auth_trust_google_summary"
|
||||
android:title="@string/pref_auth_trust_google_title"/>
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="auth_manager_visible"
|
||||
android:summary="@string/pref_auth_visible_summary"
|
||||
android:title="@string/pref_auth_visible_title"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<Preference
|
||||
|
|
Loading…
Reference in a new issue