From e87693d989df0d9a809accd8305f9bbc80995e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 26 Aug 2015 20:39:08 +0200 Subject: [PATCH] Add Privileged F-Droid project --- .../privileged/IPrivilegedCallback.aidl | 26 ++ .../fdroid/privileged/IPrivilegedService.aidl | 65 ++++ Privileged-F-Droid/.gitignore | 33 ++ Privileged-F-Droid/build.gradle | 51 +++ .../src/main/AndroidManifest.xml | 33 ++ .../privileged/IPrivilegedCallback.aidl | 26 ++ .../fdroid/privileged/IPrivilegedService.aidl | 65 ++++ .../content/pm/IPackageDeleteObserver.java | 54 ++++ .../content/pm/IPackageInstallObserver.java | 54 ++++ .../fdroid/privileged/PrivilegedService.java | 305 ++++++++++++++++++ .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 4548 bytes .../main/res/drawable-ldpi/ic_launcher.png | Bin 0 -> 1986 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 2664 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 6033 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 10295 bytes .../main/res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 14497 bytes .../src/main/res/values/strings.xml | 6 + 17 files changed, 718 insertions(+) create mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl create mode 100644 F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl create mode 100644 Privileged-F-Droid/.gitignore create mode 100644 Privileged-F-Droid/build.gradle create mode 100644 Privileged-F-Droid/src/main/AndroidManifest.xml create mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl create mode 100644 Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl create mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java create mode 100644 Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java create mode 100644 Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java create mode 100644 Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-ldpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png create mode 100644 Privileged-F-Droid/src/main/res/values/strings.xml diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl new file mode 100644 index 000000000..fc476fafe --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +interface IPrivilegedCallback { + + void handleResult(in String packageName, in int returnCode); + +} \ No newline at end of file diff --git a/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl new file mode 100644 index 000000000..b5b74ff4b --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import org.fdroid.fdroid.privileged.IPrivilegedCallback; + +/** + * Asynchronous (oneway) IPC calls! + */ +oneway interface IPrivilegedService { + + /** + * Docs based on PackageManager.installPackage() + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given callback. An installation will fail if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param callback An callback to get notified when the package installation is + * complete. + */ + void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + in IPrivilegedCallback callback); + + + /** + * Docs based on PackageManager.deletePackage() + * + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the + * named package cannot be found, or if the named package is a "system package". + * + * @param packageName The name of the package to delete + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. + * @param callback An callback to get notified when the package deletion is + * complete. + */ + void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/.gitignore b/Privileged-F-Droid/.gitignore new file mode 100644 index 000000000..a44cc0f0f --- /dev/null +++ b/Privileged-F-Droid/.gitignore @@ -0,0 +1,33 @@ +#Android specific +bin +gen +obj +lint.xml +local.properties +release.properties +ant.properties +*.class +*.apk + +#Gradle +.gradle +build +gradle.properties + +#Maven +target +pom.xml.* + +#Eclipse +.project +.classpath +.settings +.metadata + +#IntelliJ IDEA +.idea +*.iml + +#Lint output +lint-report.html +lint-report_files/* \ No newline at end of file diff --git a/Privileged-F-Droid/build.gradle b/Privileged-F-Droid/build.gradle new file mode 100644 index 000000000..5545f4366 --- /dev/null +++ b/Privileged-F-Droid/build.gradle @@ -0,0 +1,51 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 22 + buildToolsVersion '23.0.0' + + defaultConfig { + minSdkVersion 8 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + + compileOptions { + compileOptions.encoding = "UTF-8" + + // Use Java 1.7, requires minSdk 8 + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + buildTypes { + release { + minifyEnabled true + + // Reference them in the java files with e.g. BuildConfig.F_DROID_CERT_SHA512. + buildConfigField "String", "F_DROID_CERT_SHA512", "\"9ba5d51a0d5c3627e270c2542b761937c721b0d8a1caed88bd3b2f21add138c2f16e295ce67bef21b21e0b75d5a0c6fd13d67efeb85c198cffa365755c94f4c2\"" + } + + debug { + + // Reference them in the java files with e.g. BuildConfig.F_DROID_CERT_SHA512. + buildConfigField "String", "F_DROID_CERT_SHA512", "\"9ba5d51a0d5c3627e270c2542b761937c721b0d8a1caed88bd3b2f21add138c2f16e295ce67bef21b21e0b75d5a0c6fd13d67efeb85c198cffa365755c94f4c2\"" + } + } + + lintOptions { + // Do not abort build if lint finds errors + abortOnError false + } + +} diff --git a/Privileged-F-Droid/src/main/AndroidManifest.xml b/Privileged-F-Droid/src/main/AndroidManifest.xml new file mode 100644 index 000000000..63bf561ed --- /dev/null +++ b/Privileged-F-Droid/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl new file mode 100644 index 000000000..fc476fafe --- /dev/null +++ b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedCallback.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +interface IPrivilegedCallback { + + void handleResult(in String packageName, in int returnCode); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl new file mode 100644 index 000000000..b5b74ff4b --- /dev/null +++ b/Privileged-F-Droid/src/main/aidl/org/fdroid/fdroid/privileged/IPrivilegedService.aidl @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import org.fdroid.fdroid.privileged.IPrivilegedCallback; + +/** + * Asynchronous (oneway) IPC calls! + */ +oneway interface IPrivilegedService { + + /** + * Docs based on PackageManager.installPackage() + * + * Install a package. Since this may take a little while, the result will + * be posted back to the given callback. An installation will fail if the + * package named in the package file's manifest is already installed, or if there's no space + * available on the device. + * + * @param packageURI The location of the package file to install. This can be a 'file:' or a + * 'content:' URI. + * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK}, + * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}. + * @param installerPackageName Optional package name of the application that is performing the + * installation. This identifies which market the package came from. + * @param callback An callback to get notified when the package installation is + * complete. + */ + void installPackage(in Uri packageURI, in int flags, in String installerPackageName, + in IPrivilegedCallback callback); + + + /** + * Docs based on PackageManager.deletePackage() + * + * Attempts to delete a package. Since this may take a little while, the result will + * be posted back to the given observer. A deletion will fail if the + * named package cannot be found, or if the named package is a "system package". + * + * @param packageName The name of the package to delete + * @param flags - possible values: {@link #DELETE_KEEP_DATA}, + * {@link #DELETE_ALL_USERS}. + * @param callback An callback to get notified when the package deletion is + * complete. + */ + void deletePackage(in String packageName, in int flags, in IPrivilegedCallback callback); + +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java new file mode 100644 index 000000000..be0d4de81 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageDeleteObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageDeleteObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageDeleteObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static IPackageDeleteObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageDeleted(java.lang.String packageName, int returnCode) throws RemoteException; +} diff --git a/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java new file mode 100644 index 000000000..ae5b3ab12 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/android/content/pm/IPackageInstallObserver.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package android.content.pm; + +import android.os.Binder; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +/** + * Just a non-working implementation of this Stub to satisfy compiler! + */ +public interface IPackageInstallObserver extends IInterface { + + abstract class Stub extends Binder implements android.content.pm.IPackageInstallObserver { + + public Stub() { + throw new RuntimeException("Stub!"); + } + + public static android.content.pm.IPackageInstallObserver asInterface(IBinder obj) { + throw new RuntimeException("Stub!"); + } + + public IBinder asBinder() { + throw new RuntimeException("Stub!"); + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + throw new RuntimeException("Stub!"); + } + } + + void packageInstalled(String packageName, int returnCode) throws RemoteException; +} \ No newline at end of file diff --git a/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java new file mode 100644 index 000000000..b727e7408 --- /dev/null +++ b/Privileged-F-Droid/src/main/java/org/fdroid/fdroid/privileged/PrivilegedService.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 3 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +package org.fdroid.fdroid.privileged; + +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Intent; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallObserver; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * This service provides an API via AIDL IPC for the main F-Droid app to install/delete packages. + *

+ * Security: + * Binding only works when,... + * - packageName is "org.fdroid.fdroid" + * - signature is equal or BuildConfig.DEBUG + */ +public class PrivilegedService extends Service { + + public static final String TAG = "PrivilegedFDroid"; + + private static final String F_DROID_PACKAGE = "org.fdroid.fdroid"; + + private Method mInstallMethod; + private Method mDeleteMethod; + + private void installPackageImpl(Uri packageURI, int flags, String installerPackageName, + final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageInstallObserver.Stub installObserver = new IPackageInstallObserver.Stub() { + @Override + public void packageInstalled(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mInstallMethod.invoke(getPackageManager(), packageURI, installObserver, + flags, installerPackageName); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + } + + private void deletePackageImpl(String packageName, int flags, final IPrivilegedCallback callback) { + + // Internal callback from the system + IPackageDeleteObserver.Stub deleteObserver = new IPackageDeleteObserver.Stub() { + @Override + public void packageDeleted(String packageName, int returnCode) throws RemoteException { + // forward this internal callback to our callback + try { + callback.handleResult(packageName, returnCode); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + }; + + // execute internal method + try { + mDeleteMethod.invoke(getPackageManager(), packageName, deleteObserver, flags); + } catch (Exception e) { + Log.e(TAG, "Android not compatible!", e); + try { + callback.handleResult(null, 0); + } catch (RemoteException e1) { + Log.e(TAG, "RemoteException", e1); + } + } + + } + + private final IPrivilegedService.Stub mBinder = new IPrivilegedService.Stub() { + @Override + public void installPackage(Uri packageURI, int flags, String installerPackageName, + IPrivilegedCallback callback) { + if (isAllowed()) { + installPackageImpl(packageURI, flags, installerPackageName, callback); + } + } + + @Override + public void deletePackage(String packageName, int flags, IPrivilegedCallback callback) { + if (isAllowed()) { + deletePackageImpl(packageName, flags, callback); + } + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + private boolean isAllowed() { + // Check that binding app is allowed to use this API + try { + + barrierPackageName(); + barrierPackageCertificate(); + + } catch (WrongPackageCertificateException e) { + Log.e(TAG, "package certificate is not allowed!", e); + return false; + } catch (WrongPackageNameException e) { + Log.e(TAG, "package name is not allowed!", e); + return false; + } + + return true; + } + + /** + * Checks if process that binds to this service (i.e. the package name corresponding to the + * process) is allowed. Only returns when package name is allowed! + * + * @throws WrongPackageNameException + */ + private void barrierPackageName() throws WrongPackageNameException { + int uid = Binder.getCallingUid(); + String[] callingPackages = getPackageManager().getPackagesForUid(uid); + + // is calling package allowed to use this service? + for (String currentPkg : callingPackages) { + if (F_DROID_PACKAGE.equals(currentPkg)) { + return; + } + } + + throw new WrongPackageNameException("package name is not allowed"); + } + + private void barrierPackageCertificate() throws WrongPackageCertificateException { + String packageName = getCurrentCallingPackage(); + + byte[] packageCertificate; + try { + packageCertificate = getPackageCertificate(packageName); + } catch (PackageManager.NameNotFoundException e) { + throw new WrongPackageCertificateException(e.getMessage()); + } + + MessageDigest md; + try { + md = MessageDigest.getInstance("SHA-512"); + } catch (NoSuchAlgorithmException e) { + throw new WrongPackageCertificateException("SHA-512 not available!"); + } + byte[] hash = md.digest(packageCertificate); + + Log.d(TAG, "hash:" + getHex(hash)); + Log.d(TAG, "F_DROID_CERT_SHA512:" + BuildConfig.F_DROID_CERT_SHA512); + + if (getHex(hash).equals(BuildConfig.F_DROID_CERT_SHA512) + || BuildConfig.DEBUG) { + return; + } + + throw new WrongPackageCertificateException("certificate not allowed!"); + } + + private byte[] getPackageCertificate(String packageName) throws PackageManager.NameNotFoundException { + // we do check the byte array of *all* signatures + @SuppressLint("PackageManagerGetSignatures") + PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + + // NOTE: Silly Android API naming: Signatures are actually certificates + Signature[] certificates = pkgInfo.signatures; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + for (Signature cert : certificates) { + try { + outputStream.write(cert.toByteArray()); + } catch (IOException e) { + throw new RuntimeException("Should not happen! Writing ByteArrayOutputStream to concat certificates failed"); + } + } + + // Even if an apk has several certificates, these certificates should never change + // Google Play does not allow the introduction of new certificates into an existing apk + // Also see this attack: http://stackoverflow.com/a/10567852 + return outputStream.toByteArray(); + } + + /** + * Returns package name associated with the UID, which is assigned to the process that sent you the + * current transaction that is being processed :) + * + * @return package name + */ + protected String getCurrentCallingPackage() { + String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); + + // NOTE: No support for sharedUserIds + // callingPackages contains more than one entry when sharedUserId has been used + // No plans to support sharedUserIds due to many bugs connected to them: + // http://java-hamster.blogspot.de/2010/05/androids-shareduserid.html + return callingPackages[0]; + } + + @Override + public void onCreate() { + super.onCreate(); + + // get internal methods via reflection + try { + Class[] installTypes = { + Uri.class, IPackageInstallObserver.class, int.class, + String.class + }; + Class[] deleteTypes = { + String.class, IPackageDeleteObserver.class, + int.class + }; + + PackageManager pm = getPackageManager(); + mInstallMethod = pm.getClass().getMethod("installPackage", installTypes); + mDeleteMethod = pm.getClass().getMethod("deletePackage", deleteTypes); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Android not compatible!", e); + stopSelf(); + } + } + + private String getHex(byte[] byteData) { + StringBuilder hexString = new StringBuilder(); + for (byte aByteData : byteData) { + String hex = Integer.toHexString(0xff & aByteData); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } + + public static class WrongPackageCertificateException extends Exception { + private static final long serialVersionUID = -1294642703122196028L; + + public WrongPackageCertificateException(String message) { + super(message); + } + } + + public static class WrongPackageNameException extends Exception { + private static final long serialVersionUID = -2294642703111196028L; + + public WrongPackageNameException(String message) { + super(message); + } + } + + public static class AndroidNotCompatibleException extends Exception { + private static final long serialVersionUID = -3294642703111196028L; + + public AndroidNotCompatibleException(String message) { + super(message); + } + } +} diff --git a/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..88138a47a6560ff25978dc35fb11cc0f85459952 GIT binary patch literal 4548 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 W!7{!k@hV3E0000bhm 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 WCEE79^Y#25Kwd^gx?0jK^nU=My12^# literal 0 HcmV?d00001 diff --git a/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png b/Privileged-F-Droid/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c012986f5299366d0a00859626c75b4046c8b5c7 GIT binary patch literal 14497 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 + + + F-Droid Privileged + +