Rework known google package system

We now store which special google package privilege to grant per package.
This commit is contained in:
Marvin W 2024-03-03 20:17:51 +01:00 • committed by Cuynu
commit fdcf3d7edd
23 changed files with 1002 additions and 72 deletions

View file

@ -32,6 +32,8 @@ import org.json.JSONObject
import org.microg.gms.BaseService
import org.microg.gms.common.GmsService
import org.microg.gms.common.PackageUtils
import org.microg.gms.utils.digest
import org.microg.gms.utils.getCertificates
private const val TAG = "GmsFirebaseAuth"
@ -83,7 +85,7 @@ class FirebaseAuthService : BaseService(TAG, GmsService.FIREBASE_AUTH) {
}
class FirebaseAuthServiceImpl(private val context: Context, override val lifecycle: Lifecycle, private val packageName: String, private val libraryVersion: String?, private val apiKey: String) : IFirebaseAuthService.Stub(), LifecycleOwner {
private val client by lazy { IdentityToolkitClient(context, apiKey, packageName, PackageUtils.firstSignatureDigestBytes(context, packageName)) }
private val client by lazy { IdentityToolkitClient(context, apiKey, packageName, context.packageManager.getCertificates(packageName).firstOrNull()?.digest("SHA1")) }
private var authorizedDomain: String? = null
private suspend fun getAuthorizedDomain(): String {

View file

@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.ads.identifier
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import androidx.core.os.bundleOf
import com.google.android.gms.ads.identifier.internal.IAdvertisingIdService
import org.microg.gms.common.GooglePackagePermission
import org.microg.gms.common.PackageUtils
import java.util.UUID
const val TAG = "AdvertisingId"
const val EMPTY_AD_ID = "00000000-0000-0000-0000-000000000000"
class AdvertisingIdService : Service() {
override fun onBind(intent: Intent): IBinder? {
return AdvertisingIdServiceImpl(this).asBinder()
}
}
class MemoryAdvertisingIdConfiguration(context: Context) : AdvertisingIdConfiguration(context) {
override val adTrackingLimitedPerApp: MutableMap<Int, Boolean> = hashMapOf()
override var adTrackingLimitedGlobally: Boolean = true
override var debugLogging: Boolean = false
override var adId: String = EMPTY_AD_ID
override var debugAdId: String = EMPTY_AD_ID
init {
resetAdvertisingId()
}
}
abstract class AdvertisingIdConfiguration(private val context: Context) {
abstract val adTrackingLimitedPerApp: MutableMap<Int, Boolean>
abstract var adTrackingLimitedGlobally: Boolean
abstract var debugLogging: Boolean
abstract var adId: String
abstract var debugAdId: String
fun isAdTrackingLimitedForApp(uid: Int): Boolean {
if (adTrackingLimitedGlobally) return true
return adTrackingLimitedPerApp[uid] ?: false
}
fun resetAdvertisingId(): String {
adId = UUID.randomUUID().toString()
debugAdId = UUID.randomUUID().toString().dropLast(12) + "10ca1ad1abe1"
return if (debugLogging) debugAdId else adId
}
fun getAdvertisingIdForApp(uid: Int): String {
if (isAdTrackingLimitedForApp(uid)) return EMPTY_AD_ID
try {
val packageNames = context.packageManager.getPackagesForUid(uid) ?: return EMPTY_AD_ID
for (packageName in packageNames) {
val applicationInfo = context.packageManager.getApplicationInfo(packageName, 0)
if (applicationInfo.targetSdkVersion > 33) {
if (context.packageManager.checkPermission("com.google.android.gms.permission.AD_ID", packageName) == PackageManager.PERMISSION_DENIED) {
throw SecurityException("Permission not granted")
}
}
}
} catch (e: Exception) {
Log.w(TAG, "Permission check failed", e)
return EMPTY_AD_ID
}
val adId = if (debugLogging) debugAdId else adId
return adId.ifEmpty { resetAdvertisingId() }
}
}
class AdvertisingIdServiceImpl(private val context: Context) : IAdvertisingIdService.Stub() {
private val configuration = MemoryAdvertisingIdConfiguration(context)
override fun getAdvertisingId(): String {
return configuration.getAdvertisingIdForApp(Binder.getCallingUid())
}
override fun isAdTrackingLimited(ignored: Boolean): Boolean {
return configuration.isAdTrackingLimitedForApp(Binder.getCallingUid())
}
override fun resetAdvertisingId(packageName: String): String {
PackageUtils.checkPackageUid(context, packageName, getCallingUid())
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
return configuration.resetAdvertisingId()
}
override fun setAdTrackingLimitedGlobally(packageName: String, limited: Boolean) {
PackageUtils.checkPackageUid(context, packageName, getCallingUid())
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
configuration.adTrackingLimitedGlobally = limited
}
override fun setDebugLoggingEnabled(packageName: String, enabled: Boolean): String {
PackageUtils.checkPackageUid(context, packageName, getCallingUid())
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
configuration.debugLogging = enabled
return advertisingId
}
override fun isDebugLoggingEnabled(): Boolean {
return configuration.debugLogging
}
override fun isAdTrackingLimitedGlobally(): Boolean {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
return configuration.adTrackingLimitedGlobally
}
override fun setAdTrackingLimitedForApp(uid: Int, limited: Boolean) {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
configuration.adTrackingLimitedPerApp[uid] = limited
}
override fun resetAdTrackingLimitedForApp(uid: Int) {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
configuration.adTrackingLimitedPerApp.remove(uid)
}
override fun getAllAppsLimitedAdTrackingConfiguration(): Bundle {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
return bundleOf(*configuration.adTrackingLimitedPerApp.map { it.key.toString() to it.value }.toTypedArray())
}
override fun getAdvertisingIdForApp(uid: Int): String {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.AD_ID)
return configuration.getAdvertisingIdForApp(uid)
}
}

View file

@ -16,8 +16,10 @@
package com.google.android.gms.common.internal;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.annotation.Nullable;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
@ -63,4 +65,40 @@ public class CertData extends ICertData.Stub {
public int remoteHashCode() {
return hashCode();
}
@Nullable
public static CertData unwrap(IBinder certDataBinder) {
if (certDataBinder instanceof CertData) {
return (CertData) certDataBinder;
} else if (certDataBinder instanceof IObjectWrapper) {
return unwrap((IObjectWrapper) certDataBinder);
} else if (certDataBinder instanceof ICertData) {
return unwrap((ICertData) certDataBinder);
}
return null;
}
public static CertData unwrap(IObjectWrapper certDataWrapper) {
CertData certData = ObjectWrapper.unwrapTyped(certDataWrapper, CertData.class);
if (certData != null) return certData;
byte[] bytes = ObjectWrapper.unwrapTyped(certDataWrapper, byte[].class);
if (bytes != null) return new CertData(bytes);
ICertData iCertData = ObjectWrapper.unwrapTyped(certDataWrapper, ICertData.class);
if (iCertData != null) return unwrap(iCertData);
return null;
}
public static CertData unwrap(ICertData iCertData) {
if (iCertData == null) return null;
if (iCertData instanceof CertData) return (CertData) iCertData;
try {
byte[] bytes = ObjectWrapper.unwrapTyped(iCertData.getWrappedBytes(), byte[].class);
if (bytes != null) {
return new CertData(bytes);
}
} catch (RemoteException e) {
// Ignore
}
return null;
}
}

View file

@ -46,33 +46,7 @@ public class GoogleCertificatesQuery extends AutoSafeParcelable {
public CertData getCertData() {
if (certData == null && certDataBinder != null) {
ICertData iCertData = null;
if (certDataBinder instanceof CertData) {
certData = (CertData) certDataBinder;
} else if (certDataBinder instanceof IObjectWrapper) {
certData = ObjectWrapper.unwrapTyped((IObjectWrapper) certDataBinder, CertData.class);
if (certData == null) {
byte[] bytes = ObjectWrapper.unwrapTyped((IObjectWrapper) certDataBinder, byte[].class);
if (bytes != null) {
certData = new CertData(bytes);
}
}
if (certData == null) {
iCertData = ObjectWrapper.unwrapTyped((IObjectWrapper) certDataBinder, ICertData.class);
}
} else if (certDataBinder instanceof ICertData) {
iCertData = (ICertData) certDataBinder;
}
if (iCertData != null) {
try {
byte[] bytes = ObjectWrapper.unwrapTyped(iCertData.getWrappedBytes(), byte[].class);
if (bytes != null) {
certData = new CertData(bytes);
}
} catch (RemoteException e) {
// Ignore
}
}
certData = CertData.unwrap(certDataBinder);
}
return certData;
}

View file

@ -27,14 +27,13 @@ import android.os.Binder;
import android.util.Log;
import androidx.annotation.Nullable;
import org.microg.gms.utils.ExtendedPackageInfo;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static android.os.Build.VERSION.SDK_INT;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
@ -48,6 +47,7 @@ public class PackageUtils {
private static final String GOOGLE_APP_KEY = "24bb24c05e47e0aefa68a58a766179d9b613a600";
private static final String[] GOOGLE_PRIMARY_KEYS = {GOOGLE_PLATFORM_KEY, GOOGLE_PLATFORM_KEY_2, GOOGLE_APP_KEY};
<<<<<<< HEAD:play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
private static final Map<String, String> KNOWN_GOOGLE_PACKAGES;
static {
@ -76,20 +76,32 @@ public class PackageUtils {
>>>>>>> 21ac41f4 (Fix account access for google wifi (#2205)):play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java
}
=======
@Deprecated
>>>>>>> a9906e52 (Rework known google package system):play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java
public static boolean isGooglePackage(Context context, String packageName) {
String signatureDigest = firstSignatureDigest(context, packageName);
return isGooglePackage(packageName, signatureDigest);
return new ExtendedPackageInfo(context, packageName).isGoogleOrPlatformPackage();
}
public static boolean isGooglePackage(PackageManager packageManager, String packageName) {
String signatureDigest = firstSignatureDigest(packageManager, packageName);
return isGooglePackage(packageName, signatureDigest);
/**
* @deprecated Extended access is a deprecated concept
*/
@Deprecated
public static boolean callerHasExtendedAccessPermission(Context context) {
return context.checkCallingPermission("org.microg.gms.EXTENDED_ACCESS") == PackageManager.PERMISSION_GRANTED;
}
public static boolean isGooglePackage(String packageName, byte[] bytes) {
return isGooglePackage(packageName, sha1sum(bytes));
public static void assertGooglePackagePermission(Context context, GooglePackagePermission permission) {
try {
if (!callerHasGooglePackagePermission(context, permission))
throw new SecurityException("Access denied, missing google package permission for " + permission.name());
} catch (SecurityException e) {
Log.w("ExtendedAccess", e);
throw e;
}
}
<<<<<<< HEAD:play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
public static boolean isGooglePackage(String packageName, String signatureDigest) {
if (signatureDigest == null) return false;
if (Arrays.asList(GOOGLE_PRIMARY_KEYS).contains(signatureDigest)) return true;
@ -112,17 +124,38 @@ public class PackageUtils {
}
}
return context.checkCallingPermission("org.mgoogle.gms.EXTENDED_ACCESS") == PackageManager.PERMISSION_GRANTED;
=======
public static boolean callerHasGooglePackagePermission(Context context, GooglePackagePermission permission) {
for (String packageCandidate : getCallingPackageCandidates(context)) {
if (new ExtendedPackageInfo(context, packageCandidate).hasGooglePackagePermission(permission)) {
return true;
}
}
// TODO: Replace with explicit permission instead of generic "extended access"
if (callerHasExtendedAccessPermission(context)) return true;
return false;
>>>>>>> a9906e52 (Rework known google package system):play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java
}
public static void checkPackageUid(Context context, String packageName, int callingUid) {
getAndCheckPackage(context, packageName, callingUid, 0);
}
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
@Nullable
public static String firstSignatureDigest(Context context, String packageName) {
return firstSignatureDigest(context.getPackageManager(), packageName);
}
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
@Nullable
public static String firstSignatureDigest(PackageManager packageManager, String packageName) {
if (packageName.equals("com.google.android.apps.youtube.music") || packageName.contains("youtube.music")) {
@ -155,11 +188,19 @@ public class PackageUtils {
return null;
}
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
@Nullable
public static byte[] firstSignatureDigestBytes(Context context, String packageName) {
return firstSignatureDigestBytes(context.getPackageManager(), packageName);
}
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
@Nullable
public static byte[] firstSignatureDigestBytes(PackageManager packageManager, String packageName) {
final PackageInfo info;
@ -205,17 +246,26 @@ public class PackageUtils {
return null;
}
public static String[] getCallingPackageCandidates(Context context) {
int callingUid = Binder.getCallingUid(), callingPid = Binder.getCallingPid();
String packageName = packageFromProcessId(context, callingPid);
if (packageName != null) return new String[]{packageName};
String[] candidates = context.getPackageManager().getPackagesForUid(callingUid);
if (candidates == null) return new String[0];
return candidates;
}
@Nullable
public static String getAndCheckCallingPackage(Context context, String suggestedPackageName) {
return getAndCheckCallingPackage(context, suggestedPackageName, 0);
}
@Nullable
public static String getAndCheckCallingPackageOrExtendedAccess(Context context, String suggestedPackageName) {
public static String getAndCheckCallingPackageOrImpersonation(Context context, String suggestedPackageName) {
try {
return getAndCheckCallingPackage(context, suggestedPackageName, 0);
} catch (Exception e) {
if (callerHasExtendedAccess(context)) {
if (callerHasGooglePackagePermission(context, GooglePackagePermission.IMPERSONATE)) {
return suggestedPackageName;
}
throw e;
@ -347,6 +397,10 @@ public class PackageUtils {
}
}
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
public static String sha1sum(byte[] bytes) {
MessageDigest md;
try {
@ -367,27 +421,38 @@ public class PackageUtils {
return null;
}
public static int versionCode(Context context, String packageName) {
<<<<<<< HEAD:play-services-base-core/src/main/java/org/microg/gms/common/PackageUtils.java
=======
/**
* @deprecated We should stop using SHA-1 for certificate fingerprints!
*/
@Deprecated
public static byte[] sha1bytes(byte[] bytes) {
MessageDigest md;
try {
return context.getPackageManager().getPackageInfo(packageName, 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
return -1;
}
}
public static String versionName(Context context, String packageName) {
try {
return context.getPackageManager().getPackageInfo(packageName, 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
md = MessageDigest.getInstance("SHA1");
} catch (final NoSuchAlgorithmException e) {
return null;
}
if (md != null) {
return md.digest(bytes);
}
return null;
}
@Deprecated
>>>>>>> a9906e52 (Rework known google package system):play-services-base/core/src/main/java/org/microg/gms/common/PackageUtils.java
public static int versionCode(Context context, String packageName) {
return new ExtendedPackageInfo(context, packageName).getShortVersionCode();
}
@Deprecated
public static String versionName(Context context, String packageName) {
return new ExtendedPackageInfo(context, packageName).getVersionName();
}
@Deprecated
public static int targetSdkVersion(Context context, String packageName) {
try {
return context.getPackageManager().getApplicationInfo(packageName, 0).targetSdkVersion;
} catch (PackageManager.NameNotFoundException e) {
return -1;
}
return new ExtendedPackageInfo(context, packageName).getTargetSdkVersion();
}
}

View file

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2024 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.utils
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.pm.PackageInfoCompat
import org.microg.gms.common.*
class ExtendedPackageInfo(private val packageManager: PackageManager, val packageName: String) {
constructor(context: Context, packageName: String) : this(context.packageManager, packageName)
private val basicPackageInfo by lazy { kotlin.runCatching { packageManager.getPackageInfo(packageName, 0) }.getOrNull() }
private val basicApplicationInfo by lazy { kotlin.runCatching { packageManager.getApplicationInfo(packageName, 0) }.getOrNull() }
val isInstalled by lazy { basicPackageInfo != null }
val certificates by lazy { packageManager.getCertificates(packageName) }
private val certificatesHashSha1 by lazy { certificates.map { it.digest("SHA1") } }
val firstCertificateSha1 by lazy { certificatesHashSha1.firstOrNull() }
val firstCertificateSha1Hex by lazy { firstCertificateSha1?.toHexString() }
private val certificatesHashSha256 by lazy { certificates.map { it.digest("SHA-256") } }
val firstCertificateSha256 by lazy { certificatesHashSha256.firstOrNull() }
private val certificatesHashSha1Strings by lazy { certificatesHashSha1.map { it.toHexString() } }
private val certificatesHashSha256Strings by lazy { certificatesHashSha256.map { it.toHexString() } }
val applicationLabel by lazy { packageManager.getApplicationLabel(packageName) }
@Deprecated("version code is now a long", replaceWith = ReplaceWith("versionCode"))
val shortVersionCode by lazy { basicPackageInfo?.versionCode ?: -1 }
val versionCode by lazy { basicPackageInfo?.let { PackageInfoCompat.getLongVersionCode(it) } ?: -1 }
val versionName by lazy { basicPackageInfo?.versionName }
val targetSdkVersion by lazy { basicApplicationInfo?.targetSdkVersion ?: -1 }
private val packageAndCertHashes by lazy {
listOf(
certificatesHashSha1Strings.map { PackageAndCertHash(packageName, "SHA1", it) },
certificatesHashSha256Strings.map { PackageAndCertHash(packageName, "SHA-256", it) },
).flatten()
}
val isGooglePackage by lazy { packageAndCertHashes.any { isGooglePackage(it) } }
val isPlatformPackage by lazy {
val platformCertificates = packageManager.getPlatformCertificates()
certificates.any { it in platformCertificates }
}
val isGoogleOrPlatformPackage by lazy { isGooglePackage || isPlatformPackage }
private val googlePackagePermissions by lazy { packageAndCertHashes.flatMap { getGooglePackagePermissions(it) }.toSet() }
fun hasGooglePackagePermission(permission: GooglePackagePermission) = permission in googlePackagePermissions
}

View file

@ -0,0 +1,164 @@
/*
* SPDX-FileCopyrightText: 2024 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.common
import com.google.android.gms.common.internal.CertData
import org.microg.gms.common.GooglePackagePermission.*
import org.microg.gms.utils.digest
import org.microg.gms.utils.toHexString
private const val SHA1 = "SHA1"
private const val SHA256 = "SHA-256"
val KNOWN_GOOGLE_PACKAGES = mapOf(
// Legacy set
// These include all previously KNOWN_GOOGLE_PACKAGES and grant them all google package permissions
// Those should be replaced by new entries that
// - use SHA-256 instead of SHA-1
// - has more accurate permission set (in most cases, ACCOUNT+AUTH+OWNER is sufficient)
Pair(
PackageAndCertHash("com.google.android.apps.classroom", SHA1, "46f6c8987311e131f4f558d8e0ae145bebab6da3"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.inbox", SHA1, "aa87ce1260c008d801197bb4ecea4ab8929da246"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.playconsole", SHA1, "d6c35e55b481aefddd74152ca7254332739a81d6"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.travel.onthego", SHA1, "0cbe08032217d45e61c0bc72f294395ee9ecb5d5"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.tycho", SHA1, "01b844184e360686aa98b48eb16e05c76d4a72ad"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.contacts", SHA1, "ee3e2b5d95365c5a1ccc2d8dfe48d94eb33b3ebe"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.wearable.app", SHA1, "a197f9212f2fed64f0ff9c2a4edf24b9c8801c8c"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.youtube.music", SHA1, "afb0fed5eeaebdd86f56a97742f4b6b33ef59875"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.vr.home", SHA1, "fc1edc68f7e3e4963c998e95fc38f3de8d1bfc96"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.vr.cyclops", SHA1, "188c5ca3863fa121216157a5baa80755ceda70ab"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.waze", SHA1, "35b438fe1bc69d975dc8702dc16ab69ebf65f26f"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.wellbeing", SHA1, "4ebdd02380f1fa0b6741491f0af35625dba76e9f"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.village.boond", SHA1, "48e7985b8f901df335b5d5223579c81618431c7b"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.subscriptions.red", SHA1, "de8304ace744ae4c4e05887a27a790815e610ff0"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.meetings", SHA1, "47a6936b733dbdb45d71997fbe1d610eca36b8bf"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.nbu.paisa.user", SHA1, "80df78bb700f9172bc671779b017ddefefcbf552"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.dynamite", SHA1, "519c5a17a60596e6fe5933b9cb4285e7b0e5eb7b"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.projection.gearhead", SHA1, "9ca91f9e704d630ef67a23f52bf1577a92b9ca5d"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.stadia.android", SHA1, "133aad3b3d3b580e286573c37f20549f9d3d1cce"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.kids.familylink", SHA1, "88652b8464743e5ce80da0d4b890d13f9b1873df"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.walletnfcrel", SHA1, "82759e2db43f9ccbafce313bc674f35748fabd7a"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.recorder", SHA1, "394d84cd2cf89d3453702c663f98ec6554afc3cd"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.messaging", SHA1, "0980a12be993528c19107bc21ad811478c63cefc"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.tachyon", SHA1, "a0bc09af527b6397c7a9ef171d6cf76f757becc3"),
GooglePackagePermission.entries.toSet()
),
Pair(
PackageAndCertHash("com.google.android.apps.access.wifi.consumer", SHA1,"d850379540d68fbec82a742ab6a8321a3f9a4c7c"),
GooglePackagePermission.entries.toSet()
),
// New
Pair(
PackageAndCertHash("com.google.android.apps.jam", SHA256, "9db7ff389ab6a30d5f5c92a8629ff0baa93fa8430f0503c04d72640a1cf323f5"),
setOf(ACCOUNT, AUTH, OWNER)
)
)
// These are SHA-256 hashes of the Google privileged signing certificates
val KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES = listOf(
"f0fd6c5b410f25cb25c3b53346c8972fae30f8ee7411df910480ad6b2d60db83",
"7ce83c1b71f3d572fed04c8d40c5cb10ff75e6d87d9df6fbd53f0468c2905053",
)
enum class GooglePackagePermission {
ACCOUNT, // Find accounts
AD_ID, // Advertising ID
APP_CERT, // Receive certificate confirming valid app installation (incl. Spatula)
AUTH, // Sign in to Google account without user interface confirmation
CREDENTIALS, // Access to credentials
GAMES, // Google Play Games first party access
IMPERSONATE, // Allow to act as another package
OWNER, // Details about own accounts (name, email, photo)
PEOPLE, // Details about contacts
REPORTING, // Access reporting service
SAFETYNET, // Access SafetyNet UUID
}
data class PackageAndCertHash(val packageName: String, val algorithm: String, val certHash: String)
fun isGooglePackage(pkg: PackageAndCertHash): Boolean {
if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES) return true
return KNOWN_GOOGLE_PACKAGES.containsKey(pkg)
}
fun getGooglePackagePermissions(pkg: PackageAndCertHash): Set<GooglePackagePermission> {
if (KNOWN_GOOGLE_PACKAGES.containsKey(pkg)) return KNOWN_GOOGLE_PACKAGES[pkg].orEmpty()
if (pkg.algorithm == SHA256 && pkg.certHash in KNOWN_GOOGLE_PRIVILEGED_CERT_HASHES) return GooglePackagePermission.entries.toSet()
return emptySet()
}
fun hasGooglePackagePermission(pkg: PackageAndCertHash, permission: GooglePackagePermission) = getGooglePackagePermissions(pkg).contains(permission)
fun isGooglePackage(packageName: String, certificate: CertData): Boolean =
listOf(SHA1, SHA256).any { isGooglePackage(PackageAndCertHash(packageName, it, certificate.digest(it).toHexString())) }

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.utils
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.content.pm.Signature
import android.util.Base64
import com.google.android.gms.common.internal.CertData
import java.security.MessageDigest
import java.util.*
fun PackageManager.isPlatformCertificate(cert: CertData) = getPlatformCertificates().contains(cert)
fun PackageManager.getPlatformCertificates() = getCertificates("android")
fun PackageManager.getCertificates(packageName: String): List<CertData> = try {
getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures.map { CertData(it.toByteArray()) }
} catch (e: NameNotFoundException) {
emptyList()
}
@Deprecated("It's actually a certificate", ReplaceWith("getCertificates"))
fun PackageManager.getSignatures(packageName: String): Array<Signature> = try {
getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures
} catch (e: NameNotFoundException) {
emptyArray()
}
fun PackageManager.getApplicationLabel(packageName: String): CharSequence = try {
getApplicationLabel(getApplicationInfo(packageName, 0))
} catch (e: Exception) {
packageName
}
fun PackageManager.getExtendedPackageInfo(packageName: String) = ExtendedPackageInfo(this, packageName)
fun ByteArray.toBase64(vararg flags: Int): String = Base64.encodeToString(this, flags.fold(0) { a, b -> a or b })
fun ByteArray.toHexString(separator: String = ""): String = joinToString(separator) { "%02x".format(it) }
fun PackageManager.getFirstSignatureDigest(packageName: String, md: String): ByteArray? =
getCertificates(packageName).firstOrNull()?.digest(md)
fun ByteArray.digest(md: String): ByteArray = MessageDigest.getInstance(md).digest(this)
@Deprecated("It's actually a certificate")
fun Signature.digest(md: String): ByteArray = toByteArray().digest(md)
fun CertData.digest(md: String): ByteArray = bytes.digest(md)

View file

@ -33,6 +33,7 @@ import android.util.Log;
import androidx.annotation.Nullable;
import org.microg.gms.common.GooglePackagePermission;
import org.microg.gms.common.PackageUtils;
import java.util.Arrays;
@ -57,15 +58,21 @@ public class AccountContentProvider extends ContentProvider {
String suggestedPackageName;
suggestedPackageName = getCallingPackage();
String packageName = PackageUtils.getAndCheckCallingPackage(getContext(), suggestedPackageName);
<<<<<<< HEAD
Log.d(TAG, "Call " + method + " from " + packageName + " with arg " + arg);
if (!PackageUtils.callerHasExtendedAccess(getContext())) {
=======
boolean hasGooglePackagePermission = PackageUtils.callerHasGooglePackagePermission(getContext(), GooglePackagePermission.ACCOUNT);
if (!hasGooglePackagePermission) {
>>>>>>> a9906e52 (Rework known google package system)
String[] packagesForUid = getContext().getPackageManager().getPackagesForUid(Binder.getCallingUid());
if (packagesForUid != null && packagesForUid.length != 0)
Log.w(TAG, "Not granting extended access to " + Arrays.toString(packagesForUid)
+ ", signature: " + PackageUtils.firstSignatureDigest(getContext(), packagesForUid[0]));
if (getContext().checkCallingPermission(Manifest.permission.GET_ACCOUNTS) != PackageManager.PERMISSION_GRANTED)
throw new SecurityException("Access denied, missing GET_ACCOUNTS or EXTENDED_ACCESS permission");
throw new SecurityException("Access denied, missing google package permission or GET_ACCOUNTS");
}
<<<<<<< HEAD
if (PROVIDER_METHOD_GET_ACCOUNTS.equals(method)) {
Bundle result = new Bundle();
Account[] accounts = null;
@ -80,14 +87,31 @@ public class AccountContentProvider extends ContentProvider {
if (am.getAccountVisibility(account, packageName) == AccountManager.VISIBILITY_UNDEFINED) {
Log.d(TAG, "Make account " + account + " visible to " + packageName);
am.setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);
=======
long identityToken = Binder.clearCallingIdentity();
try {
if (PROVIDER_METHOD_GET_ACCOUNTS.equals(method)) {
Bundle result = new Bundle();
Account[] accounts = null;
if (arg != null && (arg.equals(DEFAULT_ACCOUNT_TYPE) || arg.startsWith(DEFAULT_ACCOUNT_TYPE + "."))) {
AccountManager am = AccountManager.get(getContext());
accounts = am.getAccountsByTypeForPackage(arg, packageName);
if (SDK_INT >= 26 && accounts != null && arg.equals(DEFAULT_ACCOUNT_TYPE)) {
for (Account account : accounts) {
if (am.getAccountVisibility(account, packageName) == AccountManager.VISIBILITY_UNDEFINED &&
(hasGooglePackagePermission || AuthPrefs.isAuthVisible(getContext()))) {
Log.d(TAG, "Make account " + account + " visible to " + packageName);
am.setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);
}
>>>>>>> a9906e52 (Rework known google package system)
}
}
}
}
if (accounts == null) {
accounts = new Account[0];
}
if (accounts == null) {
accounts = new Account[0];
}
<<<<<<< HEAD
result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, accounts);
Log.d(TAG, "get_accounts returns: " + Arrays.toString(accounts));
return result;
@ -95,8 +119,19 @@ public class AccountContentProvider extends ContentProvider {
Account a = extras.getParcelable(PROVIDER_EXTRA_CLEAR_PASSWORD);
AccountManager.get(getContext()).clearPassword(a);
return null;
=======
result.putParcelableArray(PROVIDER_EXTRA_ACCOUNTS, accounts);
return result;
} else if (PROVIDER_METHOD_CLEAR_PASSWORD.equals(method) && hasGooglePackagePermission) {
Account a = extras.getParcelable(PROVIDER_EXTRA_CLEAR_PASSWORD);
AccountManager.get(getContext()).clearPassword(a);
return null;
}
throw new UnsupportedOperationException(String.format("Unsupported method call %s(%s).", method, arg));
} finally {
Binder.restoreCallingIdentity(identityToken);
>>>>>>> a9906e52 (Rework known google package system)
}
throw new UnsupportedOperationException(String.format("Unsupported method call %s(%s).", method, arg));
}
@Nullable

View file

@ -41,6 +41,7 @@ import com.google.android.gms.auth.HasCababilitiesRequest;
import com.google.android.gms.auth.TokenData;
import com.google.android.gms.common.api.Scope;
import org.microg.gms.common.GooglePackagePermission;
import org.microg.gms.common.PackageUtils;
import java.io.IOException;
@ -146,7 +147,7 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
@Override
public Bundle getAccounts(Bundle extras) {
PackageUtils.assertExtendedAccess(context);
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.ACCOUNT);
String[] accountFeatures = extras.getStringArray(KEY_ACCOUNT_FEATURES);
String accountType = extras.getString(KEY_ACCOUNT_TYPE);
Account[] accounts;
@ -172,8 +173,23 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
}
@Override
<<<<<<< HEAD
public Bundle requestGoogleAccountsAccess(String packageName) {
Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")");
=======
public Bundle requestGoogleAccountsAccess(String packageName) throws RemoteException {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.ACCOUNT);
if (SDK_INT >= 26) {
for (Account account : get(context).getAccountsByType(AuthConstants.DEFAULT_ACCOUNT_TYPE)) {
AccountManager.get(context).setAccountVisibility(account, packageName, VISIBILITY_VISIBLE);
}
Bundle res = new Bundle();
res.putString("Error", "Ok");
return res;
} else {
Log.w(TAG, "Not implemented: requestGoogleAccountsAccess(" + packageName + ")");
}
>>>>>>> a9906e52 (Rework known google package system)
return null;
}

View file

@ -29,6 +29,11 @@ import android.util.Log;
import org.microg.gms.checkin.LastCheckinInfo;
import org.microg.gms.common.HttpFormClient;
import org.microg.gms.common.PackageUtils;
<<<<<<< HEAD
=======
import org.microg.gms.common.Utils;
import org.microg.gms.utils.ExtendedPackageInfo;
>>>>>>> a9906e52 (Rework known google package system)
import java.io.IOException;
@ -69,15 +74,16 @@ public class PushRegisterManager {
public static void completeRegisterRequest(Context context, GcmDatabase database, String requestId, RegisterRequest request, BundleCallback callback) {
if (request.app != null) {
ExtendedPackageInfo packageInfo = new ExtendedPackageInfo(context, request.app);
if (request.appVersion <= 0)
request.appVersion = PackageUtils.versionCode(context, request.app);
request.appVersion = packageInfo.getShortVersionCode();
if (!request.delete) {
if (request.appSignature == null) {
request.appSignature = PackageUtils.firstSignatureDigest(context, request.app);
request.appSignature = packageInfo.getFirstCertificateSha1Hex();
}
request.sdkVersion = PackageUtils.targetSdkVersion(context, request.app);
request.sdkVersion = packageInfo.getTargetSdkVersion();
if (!request.hasExtraParam(GcmConstants.EXTRA_APP_VERSION_NAME))
request.extraParam(GcmConstants.EXTRA_APP_VERSION_NAME, PackageUtils.versionName(context, request.app));
request.extraParam(GcmConstants.EXTRA_APP_VERSION_NAME, packageInfo.getVersionName());
}
}

View file

@ -33,6 +33,7 @@ import com.google.android.gms.people.internal.IPeopleService;
import com.google.android.gms.people.model.AccountMetadata;
import org.microg.gms.auth.AuthConstants;
import org.microg.gms.common.GooglePackagePermission;
import org.microg.gms.common.NonCancelToken;
import org.microg.gms.common.PackageUtils;
@ -50,7 +51,13 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public void loadOwners(final IPeopleCallbacks callbacks, boolean var2, boolean var3, final String accountName, String var5, int sortOrder) {
Log.d(TAG, "loadOwners: " + var2 + ", " + var3 + ", " + accountName + ", " + var5 + ", " + sortOrder);
<<<<<<< HEAD
=======
if (context.checkCallingPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.OWNER);
}
>>>>>>> a9906e52 (Rework known google package system)
AccountManager accountManager = AccountManager.get(context);
Bundle accountMetadata = new Bundle();
String accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;
@ -88,7 +95,7 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public void loadCircles(IPeopleCallbacks callbacks, String account, String pageGaiaId, String circleId, int type, String var6, boolean var7) throws RemoteException {
Log.d(TAG, "loadCircles: " + account + ", " + pageGaiaId + ", " + circleId + ", " + type + ", " + var6 + ", " + var7);
PackageUtils.assertExtendedAccess(context);
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.PEOPLE);
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Cursor owner = databaseHelper.getOwner(account);
@ -115,6 +122,7 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
@Override
public ICancelToken loadOwnerAvatar(final IPeopleCallbacks callbacks, final String account, String pageId, int size, int flags) {
Log.d(TAG, "loadOwnerAvatar: " + account + ", " + pageId + ", " + size + ", " + flags);
<<<<<<< HEAD
PackageUtils.assertExtendedAccess(context);
final Thread thread = new Thread(() -> {
Bundle extras = new Bundle();
@ -126,6 +134,25 @@ public class PeopleServiceImpl extends IPeopleService.Stub {
ParcelFileDescriptor fileDescriptor = null;
if (avaterFile != null) {
fileDescriptor = ParcelFileDescriptor.open(avaterFile, ParcelFileDescriptor.MODE_READ_ONLY);
=======
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.OWNER);
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Bundle extras = new Bundle();
extras.putBoolean("rewindable", false);
extras.putInt("width", 0);
extras.putInt("height", 0);
File avaterFile = PeopleManager.getOwnerAvatarFile(context, account, true);
try {
ParcelFileDescriptor fileDescriptor = null;
if (avaterFile != null) {
fileDescriptor = ParcelFileDescriptor.open(avaterFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
callbacks.onParcelFileDescriptor(0, extras, fileDescriptor, extras);
} catch (Exception e) {
Log.w(TAG, e);
>>>>>>> a9906e52 (Rework known google package system)
}
callbacks.onParcelFileDescriptor(0, extras, fileDescriptor, extras);
} catch (Exception e) {

View file

@ -0,0 +1,96 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.common
import android.content.pm.PackageManager
import android.os.IBinder
import android.os.Parcel
import android.util.Log
import androidx.annotation.Keep
import com.google.android.gms.common.internal.CertData
import com.google.android.gms.common.internal.IGoogleCertificatesApi
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import org.microg.gms.common.PackageUtils
import org.microg.gms.common.isGooglePackage
import org.microg.gms.utils.ExtendedPackageInfo
import org.microg.gms.utils.getExtendedPackageInfo
import org.microg.gms.utils.isPlatformCertificate
import org.microg.gms.utils.warnOnTransactionIssues
private const val TAG = "GoogleCertificates"
@Keep
class GoogleCertificatesImpl : IGoogleCertificatesApi.Stub() {
private val googleCertificates = emptySet<CertData>()
private val googleReleaseCertificates = emptySet<CertData>()
override fun getGoogleCertificates(): IObjectWrapper {
Log.d(TAG, "unimplemented Method: getGoogleCertificates")
return ObjectWrapper.wrap(googleCertificates.toTypedArray<IBinder>())
}
override fun getGoogleReleaseCertificates(): IObjectWrapper {
Log.d(TAG, "unimplemented Method: getGoogleReleaseCertificates")
return ObjectWrapper.wrap(googleReleaseCertificates.toTypedArray<IBinder>())
}
override fun isGoogleReleaseSigned(packageName: String, certData: IObjectWrapper): Boolean {
return isGooglePackage(packageName, CertData.unwrap(certData) ?: return false)
}
override fun isGoogleSigned(packageName: String, certData: IObjectWrapper): Boolean {
return isGooglePackage(packageName, CertData.unwrap(certData) ?: return false)
}
override fun isGoogleOrPlatformSigned(query: GoogleCertificatesQuery?, packageManager: IObjectWrapper): Boolean {
val pm = ObjectWrapper.unwrapTyped(packageManager, PackageManager::class.java)
return when {
query?.callingPackage == null -> false
query.certData != null -> {
isGooglePackage(query.callingPackage, query.certData) || (pm != null && pm.isPlatformCertificate(query.certData))
}
pm != null -> pm.getExtendedPackageInfo(query.callingPackage).isGoogleOrPlatformPackage
else -> false
}
}
override fun isPackageGoogleOrPlatformSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {
return certificateLookup(query, true)
}
override fun isPackageGoogleOrPlatformSignedAvailable(): Boolean {
return true
}
override fun queryPackageSigned(query: GoogleCertificatesLookupQuery): GoogleCertificatesLookupResponse {
if (!isFineGrainedPackageVerificationAvailable) throw IllegalStateException("API unavailable")
return certificateLookup(query, false)
}
override fun isFineGrainedPackageVerificationAvailable(): Boolean {
return true
}
private fun certificateLookup(query: GoogleCertificatesLookupQuery, allowPlatform: Boolean): GoogleCertificatesLookupResponse {
val context = query.context
?: return GoogleCertificatesLookupResponse(false, "context is null", 5, 1)
val packageManager = context.packageManager
?: return GoogleCertificatesLookupResponse(false, "context has no package manager", 5, 1)
val callingPackage = query.callingPackage
?: return GoogleCertificatesLookupResponse(false, "callingPackage is null", 5, 1)
val packageInfo = packageManager.getExtendedPackageInfo(callingPackage)
if (!packageInfo.isInstalled)
return GoogleCertificatesLookupResponse(false, "callingPackage not found", 4, 1)
return if (packageInfo.isGooglePackage || (allowPlatform && packageInfo.isPlatformPackage)) {
GoogleCertificatesLookupResponse(true, null, 1, 3)
} else {
GoogleCertificatesLookupResponse(false, "not allowed", 2, 1)
}
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
}

View file

@ -34,8 +34,14 @@ import org.microg.mgms.settings.SettingsContract.getSettings
=======
import org.microg.gms.settings.SettingsContract.CheckIn
import org.microg.gms.settings.SettingsContract.getSettings
import org.microg.gms.utils.digest
import org.microg.gms.utils.getCertificates
import org.microg.gms.utils.singleInstanceOf
<<<<<<< HEAD
>>>>>>> d69a0f5a (Only use a single Volley instance per process)
=======
import org.microg.gms.utils.toBase64
>>>>>>> a9906e52 (Rework known google package system)
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.random.Random
@ -136,7 +142,7 @@ class AppCertManager(private val context: Context) {
suspend fun getSpatulaHeader(packageName: String): String? {
val deviceKey = deviceKey ?: if (fetchDeviceKey()) deviceKey else null
val packageCertificateHash = Base64.encodeToString(PackageUtils.firstSignatureDigestBytes(context, packageName), Base64.NO_WRAP)
val packageCertificateHash = context.packageManager.getCertificates(packageName).firstOrNull()?.digest("SHA1")?.toBase64(Base64.NO_WRAP)
val proto = if (deviceKey != null) {
val macSecret = deviceKey.macSecret?.toByteArray()
if (macSecret == null) {

View file

@ -13,6 +13,7 @@ import android.os.Parcel
import android.util.Log
import com.google.android.gms.auth.appcert.IAppCertService
import kotlinx.coroutines.runBlocking
import org.microg.gms.common.GooglePackagePermission
import org.microg.gms.common.PackageUtils
import org.microg.gms.utils.warnOnTransactionIssues
@ -29,12 +30,12 @@ class AppCertServiceImpl(private val context: Context) : IAppCertService.Stub()
private val manager = AppCertManager(context)
override fun fetchDeviceKey(): Boolean {
PackageUtils.assertExtendedAccess(context)
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.APP_CERT)
return runBlocking { manager.fetchDeviceKey() }
}
override fun getSpatulaHeader(packageName: String): String? {
PackageUtils.assertExtendedAccess(context)
PackageUtils.assertGooglePackagePermission(context, GooglePackagePermission.APP_CERT)
return runBlocking { manager.getSpatulaHeader(packageName) }
}

View file

@ -24,6 +24,7 @@ import kotlinx.coroutines.withContext
import org.microg.gms.BaseService
import org.microg.gms.auth.appcert.AppCertManager
import org.microg.gms.common.GmsService
import org.microg.gms.common.GooglePackagePermission
import org.microg.gms.common.PackageUtils
import org.microg.gms.utils.warnOnTransactionIssues
@ -32,9 +33,14 @@ private const val TAG = "AuthProxyService"
class AuthProxyService : BaseService(TAG, GmsService.AUTH_PROXY) {
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
val packageName = PackageUtils.getAndCheckCallingPackage(this, request.packageName)
<<<<<<< HEAD
?: throw IllegalArgumentException("Missing package name")
=======
?: throw IllegalArgumentException("Missing package name")
PackageUtils.assertGooglePackagePermission(this, GooglePackagePermission.APP_CERT)
>>>>>>> a9906e52 (Rework known google package system)
val consumerPackageName = request.extras.getString("consumerPkg")
if (consumerPackageName != null) PackageUtils.assertExtendedAccess(this)
if (consumerPackageName != null) PackageUtils.assertGooglePackagePermission(this, GooglePackagePermission.IMPERSONATE)
val serviceImpl = AuthServiceImpl(this, lifecycle, consumerPackageName ?: packageName)
callback.onPostInitComplete(CommonStatusCodes.SUCCESS, serviceImpl, Bundle())
}

View file

@ -26,6 +26,7 @@ import com.google.android.gms.credential.manager.firstparty.internal.ICredential
import com.google.android.gms.credential.manager.invocationparams.CredentialManagerInvocationParams
import org.microg.gms.BaseService
import org.microg.gms.common.GmsService
import org.microg.gms.common.GooglePackagePermission
import org.microg.gms.common.PackageUtils
import org.microg.gms.utils.toBase64
import org.microg.gms.utils.warnOnTransactionIssues
@ -34,7 +35,7 @@ private const val TAG = "CredentialManager"
class CredentialManagerService : BaseService(TAG, GmsService.CREDENTIAL_MANAGER) {
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
if (!PackageUtils.callerHasExtendedAccess(this)) {
if (!PackageUtils.callerHasGooglePackagePermission(this, GooglePackagePermission.CREDENTIALS)) {
Log.d(TAG, "No access to ${request.packageName}, lacks permission.")
callback.onPostInitComplete(ConnectionResult.API_DISABLED_FOR_CONNECTION, null, null)
return

View file

@ -0,0 +1,74 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.games
import android.content.Context
import android.os.Parcel
import android.util.Log
import androidx.lifecycle.Lifecycle
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status
import com.google.android.gms.common.data.DataHolder
import com.google.android.gms.common.internal.ConnectionInfo
import com.google.android.gms.common.internal.GetServiceRequest
import com.google.android.gms.common.internal.IGmsCallbacks
import com.google.android.gms.games.client.IPlayGamesCallbacks
import com.google.android.gms.games.client.IPlayGamesService
import com.google.android.gms.games.client.PlayGamesConsistencyTokens
import org.microg.gms.BaseService
import org.microg.gms.common.Constants
import org.microg.gms.common.GmsService
import org.microg.gms.common.GooglePackagePermission
import org.microg.gms.common.PackageUtils
import org.microg.gms.utils.warnOnTransactionIssues
private const val TAG = "PlayGamesService"
private val FIRST_PARTY_PACKAGES = setOf(Constants.GMS_PACKAGE_NAME, GAMES_PACKAGE_NAME)
class FirstPartyGamesService : BaseService(TAG, GmsService.GAMES) {
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this, request.packageName)
?: throw IllegalArgumentException("Missing package name")
val callingPackageName = PackageUtils.getCallingPackage(this) ?: packageName
if (!PackageUtils.callerHasGooglePackagePermission(this, GooglePackagePermission.GAMES))
throw IllegalArgumentException("$callingPackageName does not have google games access")
if (callingPackageName !in FIRST_PARTY_PACKAGES) throw IllegalArgumentException("$callingPackageName is not first-party")
callback.onPostInitCompleteWithConnectionInfo(
CommonStatusCodes.SUCCESS,
PlayGamesServiceImpl(this, lifecycle, packageName),
ConnectionInfo()
)
}
}
class PlayGamesServiceImpl(val context: Context, val lifecycle: Lifecycle, val packageName: String) : IPlayGamesService.Stub() {
override fun getGameCollection(callbacks: IPlayGamesCallbacks?, maxResults: Int, gameCollectionType: Int, z: Boolean, forceReload: Boolean) {
Log.d(TAG, "Not yet implemented: getGameCollection($maxResults, $gameCollectionType, $z, $forceReload)")
callbacks?.onData(DataHolder.empty(CommonStatusCodes.SUCCESS))
}
override fun loadGames(callbacks: IPlayGamesCallbacks?, playerId: String?, maxResults: Int, z: Boolean, forceReload: Boolean) {
Log.d(TAG, "Not yet implemented: loadGames($playerId, $maxResults, $z, $forceReload)")
callbacks?.onData(DataHolder.empty(CommonStatusCodes.SUCCESS))
}
override fun getConsistencyTokens(): PlayGamesConsistencyTokens {
Log.d(TAG, "Not yet implemented: getConsistencyTokens")
return PlayGamesConsistencyTokens(null, null)
}
override fun updateConsistencyTokens(tokens: PlayGamesConsistencyTokens?) {
Log.d(TAG, "Not yet implemented: updateConsistencyTokens($tokens)")
}
override fun fun5041(callbacks: IPlayGamesCallbacks?) {
callbacks?.onStatus5028(Status.SUCCESS)
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
warnOnTransactionIssues(code, reply, flags, TAG) { super.onTransact(code, data, reply, flags) }
}

View file

@ -48,7 +48,7 @@ private const val TAG = "GamesService"
class GamesService : BaseService(TAG, GmsService.GAMES) {
override fun handleServiceRequest(callback: IGmsCallbacks, request: GetServiceRequest, service: GmsService) {
val packageName = PackageUtils.getAndCheckCallingPackageOrExtendedAccess(this, request.packageName)
val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this, request.packageName)
?: throw IllegalArgumentException("Missing package name")
fun sendSignInRequired() {

View file

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2021 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.droidguard.core
import com.google.android.gms.common.internal.GetServiceRequest
import com.google.android.gms.common.internal.IGmsCallbacks
import com.google.android.gms.droidguard.DroidGuardChimeraService
import org.microg.gms.AbstractGmsServiceBroker
import org.microg.gms.common.GmsService
import org.microg.gms.common.PackageUtils
import java.util.*
class DroidGuardServiceBroker(val service: DroidGuardChimeraService) : AbstractGmsServiceBroker(EnumSet.of(GmsService.DROIDGUARD)) {
override fun getService(callback: IGmsCallbacks?, request: GetServiceRequest?) {
handleServiceRequest(callback, request, null)
}
override fun handleServiceRequest(callback: IGmsCallbacks?, request: GetServiceRequest?, service: GmsService?) {
val packageName = PackageUtils.getAndCheckCallingPackageOrImpersonation(this.service, request!!.packageName)
callback!!.onPostInitComplete(0, DroidGuardServiceImpl(this.service, packageName!!), null)
}
}

Some files were not shown because too many files have changed in this diff Show more