Remove native Android build: Android is now a separate priv-app repo
The Android side is being rewritten as a platform-signed system app + device owner (android_packages_apps_PawletProfiled) instead of a native NDK Binder daemon -- most of what these payloads need on Android (DevicePolicyManager, VpnManager, WifiManager, WallpaperManager, KeyChain) is Java-SDK-first and awkward or impossible to reach cleanly from a native process. Drops: Android.bp, main_android.cpp, PawletProfileBinderService.*, platform/android/*.cpp, aidl/, sepolicy/, third_party/openssl-android/, pawletprofiled.rc/.xml. Also strips the now-dead __ANDROID__ branches from SignatureVerifier/ProfileStore. This repo is Linux-only from here on.
This commit is contained in:
-112
@@ -1,112 +0,0 @@
|
||||
// vendor/oxmc/pawletprofiled/Android.bp
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// Drop this entire directory at vendor/oxmc/pawletprofiled/ and add
|
||||
// "pawletprofiled" to PRODUCT_PACKAGES in your device makefile.
|
||||
//
|
||||
// m pawletprofiled — build the daemon
|
||||
// m os.pawlet.profiled-V1-java — build Java stubs for system apps
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// ── AIDL interface ────────────────────────────────────────────────────────
|
||||
|
||||
aidl_interface {
|
||||
name: "os.pawlet.profiled",
|
||||
srcs: ["aidl/os/pawlet/profiled/IPawletProfileService.aidl"],
|
||||
stability: "vintf",
|
||||
vendor_available: false,
|
||||
backend: {
|
||||
ndk: {
|
||||
enabled: true,
|
||||
},
|
||||
java: {
|
||||
enabled: true,
|
||||
sdk_version: "system_current",
|
||||
},
|
||||
cpp: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
versions: ["1"],
|
||||
}
|
||||
|
||||
// ── Vendored OpenSSL (Android-only, static, this binary only) ─────────────
|
||||
// See third_party/openssl-android/README.md — BoringSSL (the system
|
||||
// libcrypto/libssl) has no CMS/PKCS#7 support, so SignatureVerifier.cpp
|
||||
// links a private static copy instead of touching the platform's crypto
|
||||
// libs. third_party/openssl-android/Android.bp is picked up automatically
|
||||
// by Soong's normal recursive discovery — nothing to reference here beyond
|
||||
// the module names ("libssl_pawlet_static" / "libcrypto_pawlet_static")
|
||||
// used in static_libs below.
|
||||
|
||||
// ── Native daemon ─────────────────────────────────────────────────────────
|
||||
//
|
||||
// This file is the Android/Soong build only — the Linux/D-Bus build lives
|
||||
// in CMakeLists.txt and is entirely separate. Accordingly the source list
|
||||
// below is the Android-specific set: main_android.cpp (Binder entry point)
|
||||
// and PawletProfileBinderService.cpp instead of main.cpp/PawletProfileService.cpp
|
||||
// (D-Bus), and no ZTE client (it watches NetworkManager over D-Bus, which
|
||||
// doesn't exist on Android — separate follow-up work, see main_android.cpp's
|
||||
// header comment).
|
||||
|
||||
cc_binary {
|
||||
name: "pawletprofiled",
|
||||
|
||||
srcs: [
|
||||
"src/main_android.cpp",
|
||||
"src/PawletProfileBinderService.cpp",
|
||||
"src/ProfileParser.cpp",
|
||||
"src/ProfileStore.cpp",
|
||||
"src/SignatureVerifier.cpp",
|
||||
"src/payloads/PayloadHandlers.cpp", // shared dispatch — see its header comment
|
||||
"src/platform/android/Wifi.cpp",
|
||||
"src/platform/android/Ethernet.cpp",
|
||||
"src/platform/android/Vpn.cpp",
|
||||
"src/platform/android/Cert.cpp",
|
||||
"src/platform/android/Pkcs12.cpp",
|
||||
"src/platform/android/Passcode.cpp",
|
||||
"src/platform/android/Mdm.cpp",
|
||||
"src/platform/android/SoftwareUpdate.cpp",
|
||||
"src/platform/android/TimeServer.cpp",
|
||||
"src/platform/android/Proxy.cpp",
|
||||
"src/platform/android/DnsProxy.cpp",
|
||||
"src/platform/android/Firewall.cpp",
|
||||
"src/platform/android/Ldap.cpp",
|
||||
"src/platform/android/Wallpaper.cpp",
|
||||
"src/platform/android/Screensaver.cpp",
|
||||
"src/platform/android/FirstBoot.cpp",
|
||||
"src/platform/android/ContentCache.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libbase",
|
||||
"liblog",
|
||||
"os.pawlet.profiled-V1-ndk",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libyaml",
|
||||
"libssl_pawlet_static",
|
||||
"libcrypto_pawlet_static",
|
||||
],
|
||||
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-std=c++17",
|
||||
],
|
||||
|
||||
init_rc: ["pawletprofiled.rc"],
|
||||
vintf_fragments: ["pawletprofiled.xml"],
|
||||
|
||||
required: ["pawletprofiled_sepolicy"],
|
||||
}
|
||||
|
||||
// ── SELinux policy shim ───────────────────────────────────────────────────
|
||||
|
||||
prebuilt_etc {
|
||||
name: "pawletprofiled_sepolicy",
|
||||
src: "sepolicy/pawletprofiled.te",
|
||||
sub_dir: "selinux",
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
# pawletprofiled
|
||||
|
||||
PawletOS unified device management daemon.
|
||||
PawletOS's Linux device management daemon — a native root-run systemd
|
||||
service. One binary, two subsystems.
|
||||
|
||||
One binary. Two subsystems. Ships on every PawletOS device.
|
||||
This repo is Linux-only. The Android implementation is a separate,
|
||||
independently-written app (platform-signed priv-app + device owner, not a
|
||||
native daemon — most of what these payloads need on Android is Java-SDK
|
||||
first): [`android_packages_apps_PawletProfiled`](https://git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled).
|
||||
Same `.vconfig` profile format and payload types on both platforms; no
|
||||
shared code between the two implementations.
|
||||
|
||||
---
|
||||
|
||||
@@ -30,24 +36,21 @@ enrolls on the first successful connection later.
|
||||
|
||||
```
|
||||
pawletprofiled/
|
||||
├── Android.bp AOSP Soong build
|
||||
├── CMakeLists.txt Linux CMake build
|
||||
├── pawletprofiled.rc Android init script
|
||||
├── pawletprofiled.xml Android VINTF fragment
|
||||
├── zte.conf.example ZTE client config
|
||||
│
|
||||
├── aidl/os/pawlet/profiled/
|
||||
│ └── IPawletProfileService.aidl Binder interface (Android)
|
||||
│
|
||||
├── src/
|
||||
│ ├── main.cpp Entry point
|
||||
│ ├── PawletProfileService.h/.cpp D-Bus service (Linux)
|
||||
│ ├── PawletProfileService.h/.cpp D-Bus service
|
||||
│ ├── ProfileParser.h/.cpp YAML parser (libyaml)
|
||||
│ ├── ProfileStore.h/.cpp Disk persistence + password hashing
|
||||
│ ├── SignatureVerifier.h/.cpp CMS/PKCS#7 verification (OpenSSL)
|
||||
│ └── payloads/
|
||||
│ ├── PayloadHandler.h Base class + handler registry
|
||||
│ └── PayloadHandlers.cpp All 55 payload implementations
|
||||
│ ├── payloads/
|
||||
│ │ ├── PayloadHandler.h Handler contract + PayloadUtil.h helpers
|
||||
│ │ └── PayloadHandlers.cpp Dispatch — forwards to platform/linux/*.cpp
|
||||
│ └── platform/
|
||||
│ ├── <Name>.h Per-payload-type contract (apply/revert)
|
||||
│ └── linux/<Name>.cpp One real implementation per payload type
|
||||
│
|
||||
├── src/zte/
|
||||
│ ├── DeviceIdentity.h/.cpp Hardware identity collection
|
||||
@@ -57,7 +60,6 @@ pawletprofiled/
|
||||
├── systemd/pawletprofiled.service Systemd unit
|
||||
├── dbus/os.pawlet.ProfiledService.conf D-Bus policy
|
||||
├── apparmor/pawletprofiled AppArmor MAC profile
|
||||
├── sepolicy/ Android SELinux policy
|
||||
└── debian/ Debian Trixie packaging
|
||||
```
|
||||
|
||||
@@ -113,20 +115,12 @@ sudo cmake --install build
|
||||
|
||||
---
|
||||
|
||||
## Building — Android (AOSP)
|
||||
## Android
|
||||
|
||||
```bash
|
||||
cp -r pawletprofiled/ $AOSP_ROOT/vendor/oxmc/pawletprofiled/
|
||||
|
||||
# Add to device makefile
|
||||
echo 'PRODUCT_PACKAGES += pawletprofiled' \
|
||||
>> device/oxmc/pawletos/pawletos.mk
|
||||
echo 'BOARD_SEPOLICY_DIRS += vendor/oxmc/pawletprofiled/sepolicy' \
|
||||
>> device/oxmc/pawletos/BoardConfig.mk
|
||||
|
||||
source build/envsetup.sh && lunch pawletos_arm64-userdebug
|
||||
m pawletprofiled
|
||||
```
|
||||
Not built from this repo — see
|
||||
[`android_packages_apps_PawletProfiled`](https://git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled),
|
||||
a platform-signed priv-app + device owner with its own independent
|
||||
implementation of every payload type in this daemon's schema.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package os.pawlet.profiled;
|
||||
|
||||
// IPawletProfileService — Binder interface exposed by pawletprofiled.
|
||||
// Clients (system apps, Settings, installer UI) talk to the daemon via this.
|
||||
// NDK backend; link against libpawletprofiled-ndk.
|
||||
@VintfStability
|
||||
interface IPawletProfileService {
|
||||
|
||||
// ── Profile lifecycle ─────────────────────────────────────────────────
|
||||
|
||||
// Install a profile from raw YAML bytes (unsigned) or a CMS/PKCS#7
|
||||
// blob (signed). Returns the installed profile's UUID on success.
|
||||
// Throws ServiceSpecificException on validation or signature failure.
|
||||
String installProfile(in byte[] profileData);
|
||||
|
||||
// Remove an installed profile by UUID.
|
||||
// Throws if the profile is MDM-locked or removal-password protected
|
||||
// and no password is supplied.
|
||||
void removeProfile(in String uuid, in String removalPassword);
|
||||
|
||||
// List all installed profile UUIDs.
|
||||
String[] listProfiles();
|
||||
|
||||
// Return JSON-encoded metadata for a single profile.
|
||||
String getProfileInfo(in String uuid);
|
||||
|
||||
// ── MDM state ─────────────────────────────────────────────────────────
|
||||
|
||||
// True if a valid MDM payload is enrolled.
|
||||
boolean isDeviceManaged();
|
||||
|
||||
// Return the enrolled MDM server URL, or empty string if not managed.
|
||||
String getMdmServerUrl();
|
||||
|
||||
// ── Supervised / kiosk state ──────────────────────────────────────────
|
||||
|
||||
// True if a kiosk or ASAM payload is active.
|
||||
boolean isSupervised();
|
||||
|
||||
// ── Payload query helpers ─────────────────────────────────────────────
|
||||
|
||||
// Return JSON array of payloads of the given type across all profiles.
|
||||
// e.g. getPayloadsOfType("wifi") → [{ssid:..., uuid:...}, ...]
|
||||
String getPayloadsOfType(in String payloadType);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# vendor/oxmc/pawletprofiled/pawletprofiled.rc
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# Android init language script — starts pawletprofiled at boot.
|
||||
# Placed in /system/etc/init/ by the build system via init_rc in Android.bp.
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
service pawletprofiled /system/bin/pawletprofiled
|
||||
class main
|
||||
user system
|
||||
group system
|
||||
# Capabilities needed to write to /data/system/pawletos/ and to
|
||||
# call privileged Binder services (DevicePolicyManager, KeyChain, etc.)
|
||||
capabilities SETUID SETGID
|
||||
# Restart automatically if the daemon crashes.
|
||||
restart_period 5
|
||||
# SELinux domain (matches the type defined in pawletprofiled.te)
|
||||
seclabel u:r:pawletprofiled:s0
|
||||
# Only start once the filesystem is decrypted and /data is available.
|
||||
on_property:vold.decrypt=trigger_restart_framework
|
||||
|
||||
# Create the data directory on first boot.
|
||||
on post-fs-data
|
||||
mkdir /data/system/pawletos 0700 system system
|
||||
mkdir /data/system/pawletos/profiles 0700 system system
|
||||
mkdir /data/system/pawletos/preinstalled 0700 system system
|
||||
# content-cache payload's policy override — world-readable by design,
|
||||
# PawletCacheService (a regular app UID) reads it directly. See
|
||||
# PayloadHandlers.cpp's ContentCacheHandler and PolicyOverride.kt.
|
||||
# PawletOS-fork-specific (see PayloadHandlers.cpp's header comment).
|
||||
mkdir /data/misc/pawletcache 0755 system system
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
vendor/oxmc/pawletprofiled/pawletprofiled.xml
|
||||
VINTF compatibility matrix fragment.
|
||||
Declares that this device provides the IPawletProfileService AIDL HAL.
|
||||
Installed to /system/etc/vintf/manifest/ by the build system.
|
||||
-->
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>os.pawlet.profiled</name>
|
||||
<version>1</version>
|
||||
<fqname>IPawletProfileService/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
@@ -1,11 +0,0 @@
|
||||
# vendor/oxmc/pawletprofiled/sepolicy/file_contexts
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
# Maps filesystem paths to SELinux security contexts.
|
||||
# Included automatically when BOARD_SEPOLICY_DIRS points here.
|
||||
# ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# Daemon binary
|
||||
/system/bin/pawletprofiled u:object_r:pawletprofiled_exec:s0
|
||||
|
||||
# Profile data directory and all contents
|
||||
/data/system/pawletos(/.*)? u:object_r:pawletprofiled_data_file:s0
|
||||
@@ -1,69 +0,0 @@
|
||||
# vendor/oxmc/pawletprofiled/sepolicy/pawletprofiled.te
|
||||
# SELinux policy for the pawletprofiled system daemon (Android/AOSP).
|
||||
#
|
||||
# To activate, add to your device's BoardConfig.mk:
|
||||
# BOARD_SEPOLICY_DIRS += vendor/oxmc/pawletprofiled/sepolicy
|
||||
|
||||
# ── Type declarations ──────────────────────────────────────────────────────
|
||||
|
||||
type pawletprofiled, domain;
|
||||
type pawletprofiled_exec, exec_type, file_type, system_file_type;
|
||||
type pawletprofiled_data_file, file_type, data_file_type;
|
||||
type pawletprofiled_service, service_manager_type;
|
||||
|
||||
# ── Domain transition ──────────────────────────────────────────────────────
|
||||
|
||||
init_daemon_domain(pawletprofiled)
|
||||
|
||||
# ── Binder IPC ────────────────────────────────────────────────────────────
|
||||
|
||||
binder_use(pawletprofiled)
|
||||
add_service(pawletprofiled, pawletprofiled_service)
|
||||
|
||||
# Allow system apps and shell to call into pawletprofiled via Binder
|
||||
binder_call(system_app, pawletprofiled)
|
||||
binder_call(shell, pawletprofiled)
|
||||
|
||||
# ── Profile data directory ────────────────────────────────────────────────
|
||||
|
||||
allow pawletprofiled pawletprofiled_data_file:dir { create search getattr setattr add_name remove_name };
|
||||
allow pawletprofiled pawletprofiled_data_file:file { create open read write getattr setattr unlink rename };
|
||||
|
||||
# ── System file access (CA certs for signature chain validation) ──────────
|
||||
|
||||
allow pawletprofiled system_file:dir { search getattr };
|
||||
allow pawletprofiled system_file:file { open read getattr };
|
||||
|
||||
# ── Network (ZTE HTTPS lookups) ───────────────────────────────────────────
|
||||
|
||||
allow pawletprofiled self:tcp_socket { create connect read write shutdown };
|
||||
allow pawletprofiled self:udp_socket { create connect read write };
|
||||
allow pawletprofiled port:tcp_socket name_connect;
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────────
|
||||
|
||||
allow pawletprofiled log_device:chr_file { open read write };
|
||||
|
||||
# ── System properties (ZTE state and MDM enrollment state) ───────────────
|
||||
|
||||
set_prop(pawletprofiled, pawletos_prop)
|
||||
get_prop(pawletprofiled, pawletos_prop)
|
||||
|
||||
# ── DevicePolicyManager / KeyStore Binder calls ───────────────────────────
|
||||
|
||||
allow pawletprofiled device_policy_service:service_manager { find };
|
||||
allow pawletprofiled keystore_service:service_manager { find };
|
||||
binder_call(pawletprofiled, system_server)
|
||||
binder_call(pawletprofiled, keystore)
|
||||
|
||||
# ── Process self-permissions ──────────────────────────────────────────────
|
||||
|
||||
allow pawletprofiled self:process { fork sigchld };
|
||||
allow pawletprofiled self:unix_stream_socket { create connect read write };
|
||||
|
||||
# ── content-cache payload's policy override file (PawletOS-fork-specific) ──
|
||||
# Type declared in android_packages_apps_PawletCache/sepolicy/pawlet_cache.te
|
||||
# (both dirs land in BOARD_SEPOLICY_DIRS) — see ContentCacheHandler and
|
||||
# PolicyOverride.kt for the read/write contract on this file.
|
||||
allow pawletprofiled pawletcache_policy_file:dir { create search getattr add_name };
|
||||
allow pawletprofiled pawletcache_policy_file:file create_file_perms;
|
||||
@@ -1,4 +0,0 @@
|
||||
# vendor/oxmc/pawletprofiled/sepolicy/property_contexts
|
||||
# Declares the persist.pawletos.* property namespace.
|
||||
|
||||
persist.pawletos. u:object_r:pawletos_prop:s0
|
||||
@@ -1,6 +0,0 @@
|
||||
# vendor/oxmc/pawletprofiled/sepolicy/service_contexts
|
||||
# Maps the Binder service name to its SELinux type.
|
||||
# This is what allows AServiceManager_addService / getService to work
|
||||
# under SELinux enforcement.
|
||||
|
||||
os.pawlet.profiled.IPawletProfileService/default u:object_r:pawletprofiled_service:s0
|
||||
@@ -1,322 +0,0 @@
|
||||
#include "PawletProfileBinderService.h"
|
||||
#include "payloads/PayloadHandler.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <syslog.h>
|
||||
|
||||
namespace pawletos::profile {
|
||||
|
||||
using ::ndk::ScopedAStatus;
|
||||
|
||||
// Service-specific error codes returned via ScopedAStatus — mirrors
|
||||
// PawletProfileService's D-Bus error domain (kErrNotFound etc.) one-for-one
|
||||
// so a future shared client-side error mapping stays simple.
|
||||
namespace {
|
||||
constexpr int kErrNotFound = 1;
|
||||
constexpr int kErrSignature = 2;
|
||||
constexpr int kErrParse = 3;
|
||||
constexpr int kErrLocked = 4;
|
||||
constexpr int kErrWrongPassword = 5;
|
||||
constexpr int kErrSigningRequired = 6;
|
||||
} // namespace
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::serviceError(const char* name, const std::string& message) {
|
||||
syslog(LOG_WARNING, "pawletprofiled: %s: %s", name, message.c_str());
|
||||
int code = 0;
|
||||
if (strcmp(name, "NotFound") == 0) code = kErrNotFound;
|
||||
else if (strcmp(name, "Signature") == 0) code = kErrSignature;
|
||||
else if (strcmp(name, "Parse") == 0) code = kErrParse;
|
||||
else if (strcmp(name, "Locked") == 0) code = kErrLocked;
|
||||
else if (strcmp(name, "WrongPassword") == 0) code = kErrWrongPassword;
|
||||
else if (strcmp(name, "SigningRequired") == 0) code = kErrSigningRequired;
|
||||
return ScopedAStatus::fromServiceSpecificErrorWithMessage(code, message.c_str());
|
||||
}
|
||||
|
||||
PawletProfileBinderService::PawletProfileBinderService() {
|
||||
syslog(LOG_INFO, "pawletprofiled: Binder service starting");
|
||||
mStore.load();
|
||||
}
|
||||
|
||||
// ── installProfileDirect (preinstalled profiles, same as D-Bus version) ────
|
||||
|
||||
bool PawletProfileBinderService::installProfileDirect(
|
||||
const std::vector<uint8_t>& profileData, std::string& outUuid) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
std::vector<uint8_t> yamlBytes;
|
||||
bool isSigned = false;
|
||||
SignatureVerifier::TrustLevel trust = SignatureVerifier::TrustLevel::UNSIGNED;
|
||||
|
||||
if (mVerifier.isCmsWrapped(profileData)) {
|
||||
auto result = mVerifier.verify(profileData, yamlBytes);
|
||||
if (result == SignatureVerifier::VerifyResult::INVALID) {
|
||||
syslog(LOG_ERR, "[installProfileDirect] signature invalid");
|
||||
return false;
|
||||
}
|
||||
isSigned = true;
|
||||
trust = (result == SignatureVerifier::VerifyResult::TRUSTED)
|
||||
? SignatureVerifier::TrustLevel::TRUSTED
|
||||
: SignatureVerifier::TrustLevel::UNVERIFIED;
|
||||
} else {
|
||||
yamlBytes = profileData;
|
||||
}
|
||||
|
||||
ParsedProfile profile;
|
||||
if (!mParser.parse(yamlBytes, profile)) {
|
||||
syslog(LOG_ERR, "[installProfileDirect] parse failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ParsedProfile existing;
|
||||
if (mStore.load(profile.uuid, existing)) {
|
||||
syslog(LOG_INFO, "[installProfileDirect] already installed uuid=%s, skipping",
|
||||
profile.uuid.c_str());
|
||||
outUuid = profile.uuid;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& payload : profile.payloads) {
|
||||
bool sigRequired =
|
||||
payload.type == "mdm" ||
|
||||
payload.type == "removal-password" ||
|
||||
payload.type == "kiosk" ||
|
||||
payload.type == "asam";
|
||||
if (sigRequired && !isSigned) {
|
||||
syslog(LOG_ERR, "[installProfileDirect] type=%s requires signed profile",
|
||||
payload.type.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
profile.trustLevel = trust;
|
||||
if (!mStore.save(profile)) {
|
||||
syslog(LOG_ERR, "[installProfileDirect] save failed uuid=%s", profile.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
applyProfile(profile);
|
||||
outUuid = profile.uuid;
|
||||
syslog(LOG_INFO, "[installProfileDirect] installed uuid=%s", profile.uuid.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── installProfile ──────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::installProfile(
|
||||
const std::vector<uint8_t>& in_profileData, std::string* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
std::vector<uint8_t> yamlBytes;
|
||||
bool isSigned = false;
|
||||
SignatureVerifier::TrustLevel trust = SignatureVerifier::TrustLevel::UNSIGNED;
|
||||
|
||||
if (mVerifier.isCmsWrapped(in_profileData)) {
|
||||
auto result = mVerifier.verify(in_profileData, yamlBytes);
|
||||
if (result == SignatureVerifier::VerifyResult::INVALID) {
|
||||
return serviceError("Signature", "Profile signature is invalid or tampered.");
|
||||
}
|
||||
isSigned = true;
|
||||
trust = (result == SignatureVerifier::VerifyResult::TRUSTED)
|
||||
? SignatureVerifier::TrustLevel::TRUSTED
|
||||
: SignatureVerifier::TrustLevel::UNVERIFIED;
|
||||
} else {
|
||||
yamlBytes = in_profileData;
|
||||
}
|
||||
|
||||
ParsedProfile profile;
|
||||
if (!mParser.parse(yamlBytes, profile)) {
|
||||
return serviceError("Parse", "Profile YAML is malformed or schema-invalid.");
|
||||
}
|
||||
|
||||
for (const auto& payload : profile.payloads) {
|
||||
bool sigRequired =
|
||||
payload.type == "mdm" ||
|
||||
payload.type == "removal-password" ||
|
||||
payload.type == "kiosk" ||
|
||||
payload.type == "asam";
|
||||
if (sigRequired && !isSigned) {
|
||||
return serviceError("SigningRequired",
|
||||
"Payload type '" + payload.type + "' requires a signed profile.");
|
||||
}
|
||||
}
|
||||
|
||||
profile.trustLevel = trust;
|
||||
if (!mStore.save(profile)) {
|
||||
return serviceError("Parse", "Failed to persist profile.");
|
||||
}
|
||||
|
||||
applyProfile(profile);
|
||||
syslog(LOG_INFO, "pawletprofiled: installed profile uuid=%s", profile.uuid.c_str());
|
||||
|
||||
*_aidl_return = profile.uuid;
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── removeProfile ────────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::removeProfile(
|
||||
const std::string& in_uuid, const std::string& in_removalPassword) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
ParsedProfile profile;
|
||||
if (!mStore.load(in_uuid, profile)) {
|
||||
return serviceError("NotFound", "Profile not found: " + in_uuid);
|
||||
}
|
||||
|
||||
if (profile.lifecycle.removal == "locked") {
|
||||
return serviceError("Locked", "This profile can only be removed by the MDM server.");
|
||||
}
|
||||
if (profile.lifecycle.removal == "password") {
|
||||
if (in_removalPassword.empty() || !mStore.checkRemovalPassword(in_uuid, in_removalPassword)) {
|
||||
return serviceError("WrongPassword", "Incorrect removal password.");
|
||||
}
|
||||
}
|
||||
|
||||
revertProfile(profile);
|
||||
mStore.remove(in_uuid);
|
||||
syslog(LOG_INFO, "pawletprofiled: removed profile uuid=%s", in_uuid.c_str());
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── listProfiles ─────────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::listProfiles(std::vector<std::string>* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
*_aidl_return = mStore.listUuids();
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── getProfileInfo ───────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::getProfileInfo(
|
||||
const std::string& in_uuid, std::string* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
ParsedProfile profile;
|
||||
if (!mStore.load(in_uuid, profile)) {
|
||||
return serviceError("NotFound", "Not found: " + in_uuid);
|
||||
}
|
||||
|
||||
std::ostringstream j;
|
||||
j << "{"
|
||||
<< "\"uuid\":\"" << profile.uuid << "\","
|
||||
<< "\"id\":\"" << profile.id << "\","
|
||||
<< "\"name\":\"" << profile.meta.name << "\","
|
||||
<< "\"organization\":\"" << profile.meta.organization << "\","
|
||||
<< "\"scope\":\"" << profile.scope << "\","
|
||||
<< "\"removal\":\"" << profile.lifecycle.removal << "\","
|
||||
<< "\"trusted\":" << (profile.trustLevel != SignatureVerifier::TrustLevel::UNSIGNED ? "true" : "false") << ","
|
||||
<< "\"payloadCount\":" << profile.payloads.size()
|
||||
<< "}";
|
||||
|
||||
*_aidl_return = j.str();
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── isDeviceManaged ──────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::isDeviceManaged(bool* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
bool managed = false;
|
||||
for (const auto& uuid : mStore.listUuids()) {
|
||||
ParsedProfile p;
|
||||
if (mStore.load(uuid, p))
|
||||
for (const auto& pl : p.payloads)
|
||||
if (pl.type == "mdm") { managed = true; break; }
|
||||
if (managed) break;
|
||||
}
|
||||
*_aidl_return = managed;
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── getMdmServerUrl ──────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::getMdmServerUrl(std::string* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
std::string url;
|
||||
for (const auto& uuid : mStore.listUuids()) {
|
||||
ParsedProfile p;
|
||||
if (!mStore.load(uuid, p)) continue;
|
||||
for (const auto& pl : p.payloads) {
|
||||
if (pl.type == "mdm") {
|
||||
auto it = pl.fields.find("server-url");
|
||||
if (it != pl.fields.end()) url = it->second;
|
||||
if (url.size() >= 2 && url.front() == '"') url = url.substr(1, url.size() - 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!url.empty()) break;
|
||||
}
|
||||
*_aidl_return = url;
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── isSupervised ─────────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::isSupervised(bool* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
bool supervised = false;
|
||||
for (const auto& uuid : mStore.listUuids()) {
|
||||
ParsedProfile p;
|
||||
if (!mStore.load(uuid, p)) continue;
|
||||
for (const auto& pl : p.payloads)
|
||||
if (pl.type == "kiosk" || pl.type == "asam") { supervised = true; break; }
|
||||
if (supervised) break;
|
||||
}
|
||||
*_aidl_return = supervised;
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── getPayloadsOfType ────────────────────────────────────────────────────
|
||||
|
||||
ScopedAStatus PawletProfileBinderService::getPayloadsOfType(
|
||||
const std::string& in_payloadType, std::string* _aidl_return) {
|
||||
std::lock_guard<std::mutex> lock(mLock);
|
||||
|
||||
std::ostringstream j;
|
||||
j << "[";
|
||||
bool first = true;
|
||||
for (const auto& uuid : mStore.listUuids()) {
|
||||
ParsedProfile p;
|
||||
if (!mStore.load(uuid, p)) continue;
|
||||
for (const auto& pl : p.payloads) {
|
||||
if (pl.type != in_payloadType) continue;
|
||||
if (!first) j << ",";
|
||||
first = false;
|
||||
j << "{\"profileUuid\":\"" << p.uuid << "\","
|
||||
<< "\"payloadUuid\":\"" << pl.uuid << "\"";
|
||||
for (const auto& [k, v] : pl.fields)
|
||||
j << ",\"" << k << "\":" << v;
|
||||
j << "}";
|
||||
}
|
||||
}
|
||||
j << "]";
|
||||
|
||||
*_aidl_return = j.str();
|
||||
return ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// ── applyProfile / revertProfile ─────────────────────────────────────────
|
||||
|
||||
void PawletProfileBinderService::applyProfile(const ParsedProfile& profile) {
|
||||
for (const auto& payload : profile.payloads) {
|
||||
auto* handler = PayloadHandlerRegistry::get(payload.type);
|
||||
if (handler) {
|
||||
if (!handler->apply(payload))
|
||||
syslog(LOG_WARNING, "pawletprofiled: handler failed type=%s uuid=%s",
|
||||
payload.type.c_str(), payload.uuid.c_str());
|
||||
} else {
|
||||
syslog(LOG_WARNING, "pawletprofiled: no handler for type=%s", payload.type.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PawletProfileBinderService::revertProfile(const ParsedProfile& profile) {
|
||||
for (auto it = profile.payloads.rbegin(); it != profile.payloads.rend(); ++it) {
|
||||
auto* handler = PayloadHandlerRegistry::get(it->type);
|
||||
if (handler) handler->revert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile
|
||||
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "ProfileParser.h"
|
||||
#include "ProfileStore.h"
|
||||
#include "SignatureVerifier.h"
|
||||
|
||||
#include <aidl/os/pawlet/profiled/BnPawletProfileService.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pawletos::profile {
|
||||
|
||||
// ── Android Binder counterpart to PawletProfileService (D-Bus) ─────────────
|
||||
// Same install/remove/query logic, same ProfileStore/ProfileParser/
|
||||
// PayloadHandlerRegistry underneath — only the transport differs. See
|
||||
// main_android.cpp for how this gets registered with servicemanager.
|
||||
//
|
||||
// Registered service name: "os.pawlet.profiled.IPawletProfileService/default"
|
||||
// (must match pawletprofiled.xml's VINTF fragment and sepolicy/service_contexts).
|
||||
class PawletProfileBinderService
|
||||
: public aidl::me::oxmc::pawletos::profile::BnPawletProfileService {
|
||||
public:
|
||||
PawletProfileBinderService();
|
||||
|
||||
// Same direct-install path PawletProfileService exposes for main.cpp's
|
||||
// preinstalled-profile loader — see applyPreinstalledProfiles() in
|
||||
// main_android.cpp.
|
||||
bool installProfileDirect(const std::vector<uint8_t>& data, std::string& outUuid);
|
||||
|
||||
::ndk::ScopedAStatus installProfile(
|
||||
const std::vector<uint8_t>& in_profileData, std::string* _aidl_return) override;
|
||||
::ndk::ScopedAStatus removeProfile(
|
||||
const std::string& in_uuid, const std::string& in_removalPassword) override;
|
||||
::ndk::ScopedAStatus listProfiles(std::vector<std::string>* _aidl_return) override;
|
||||
::ndk::ScopedAStatus getProfileInfo(
|
||||
const std::string& in_uuid, std::string* _aidl_return) override;
|
||||
::ndk::ScopedAStatus isDeviceManaged(bool* _aidl_return) override;
|
||||
::ndk::ScopedAStatus getMdmServerUrl(std::string* _aidl_return) override;
|
||||
::ndk::ScopedAStatus isSupervised(bool* _aidl_return) override;
|
||||
::ndk::ScopedAStatus getPayloadsOfType(
|
||||
const std::string& in_payloadType, std::string* _aidl_return) override;
|
||||
|
||||
private:
|
||||
void applyProfile(const ParsedProfile& profile);
|
||||
void revertProfile(const ParsedProfile& profile);
|
||||
|
||||
static ::ndk::ScopedAStatus serviceError(const char* name, const std::string& message);
|
||||
|
||||
std::mutex mLock;
|
||||
ProfileStore mStore;
|
||||
ProfileParser mParser;
|
||||
SignatureVerifier mVerifier;
|
||||
};
|
||||
|
||||
} // namespace pawletos::profile
|
||||
+4
-11
@@ -18,21 +18,14 @@ namespace pawletos::profile {
|
||||
// meta.json install time, trust level, payload count
|
||||
// removal_hash.bin PBKDF2-SHA256 hash of removal password (if set)
|
||||
//
|
||||
// Android's path matches what pawletprofiled.rc already mkdir's at
|
||||
// post-fs-data and what sepolicy/file_contexts already labels
|
||||
// pawletprofiled_data_file — see android_packages_apps_PawletCache's
|
||||
// equivalent PolicyOverride.kt contract for the analogous device-side path.
|
||||
#if defined(__ANDROID__)
|
||||
static constexpr const char* kProfilesDir =
|
||||
"/data/system/pawletos/profiles";
|
||||
static constexpr const char* kIndexFile =
|
||||
"/data/system/pawletos/profiles/index.json";
|
||||
#else
|
||||
// The Android implementation (git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled's
|
||||
// ProfileStore.kt) uses the same /data/system/pawletos/profiles path and
|
||||
// on-disk layout, for whatever a shared UUID/profile means across both
|
||||
// platforms — but it's an independent implementation, not shared code.
|
||||
static constexpr const char* kProfilesDir =
|
||||
"/var/lib/pawletprofiled/profiles";
|
||||
static constexpr const char* kIndexFile =
|
||||
"/var/lib/pawletprofiled/profiles/index.json";
|
||||
#endif
|
||||
|
||||
class ProfileStore {
|
||||
public:
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "SignatureVerifier.h"
|
||||
|
||||
// AOSP's system libcrypto/libssl is BoringSSL, which has no CMS/PKCS#7
|
||||
// support — so this file links against a vendored, statically-linked real
|
||||
// OpenSSL on Android instead of the system one (see
|
||||
// third_party/openssl-android/ and Android.bp's Android-target static_libs).
|
||||
// The Linux build (CMakeLists.txt) links Debian's system OpenSSL the normal
|
||||
// way. Either way, the code below is the same real CMS_verify() — no
|
||||
// platform split needed here, only at the link-config level.
|
||||
// Links Debian's system OpenSSL (libcrypto/libssl) for real CMS_verify().
|
||||
// The Android implementation lives in a separate app now
|
||||
// (git.oxmc.me/PawletOS/android_packages_apps_PawletProfiled's
|
||||
// SignatureVerifier.kt, via Bouncy Castle — BoringSSL has no CMS/PKCS#7
|
||||
// support, the same gap that used to be solved here by vendoring a static
|
||||
// OpenSSL for the Android build; a pure-Java CMS library sidesteps that
|
||||
// entirely instead).
|
||||
#include <openssl/cms.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/pem.h>
|
||||
@@ -43,13 +43,8 @@ static StorePtr buildTrustStore() {
|
||||
X509_STORE* store = X509_STORE_new();
|
||||
if (!store) return nullptr;
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// AOSP's cacerts dir is CApath-style (hash-named PEM files), not one bundle.
|
||||
X509_STORE_load_locations(store, nullptr, SignatureVerifier::kTrustStorePath);
|
||||
#else
|
||||
// Debian's ca-certificates.crt is a single CAfile bundle.
|
||||
X509_STORE_load_locations(store, SignatureVerifier::kTrustStorePath, nullptr);
|
||||
#endif
|
||||
|
||||
// Load PawletOS profile signing CA if installed
|
||||
struct stat st{};
|
||||
|
||||
@@ -25,24 +25,12 @@ public:
|
||||
VerifyResult verify(const std::vector<uint8_t>& cmsData,
|
||||
std::vector<uint8_t>& outPayload);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// AOSP's system CA store is a *directory* of hash-named PEM files
|
||||
// (c_rehash layout), not one bundle file — buildTrustStore() loads it
|
||||
// via X509_STORE's CApath, not CAfile. See SignatureVerifier.cpp.
|
||||
static constexpr const char* kTrustStorePath =
|
||||
"/system/etc/security/cacerts";
|
||||
// PawletOS profile signing CA (optional) — writable partition, covered
|
||||
// by sepolicy's pawletprofiled_data_file type.
|
||||
static constexpr const char* kPawletCaPath =
|
||||
"/data/system/pawletos/profile_ca.pem";
|
||||
#else
|
||||
// System CA trust bundle
|
||||
static constexpr const char* kTrustStorePath =
|
||||
"/etc/ssl/certs/ca-certificates.crt";
|
||||
// PawletOS profile signing CA (optional; installed by the pawletos-ca package)
|
||||
static constexpr const char* kPawletCaPath =
|
||||
"/etc/pawletprofiled/profile_ca.pem";
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace pawletos::profile
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#include "PawletProfileBinderService.h"
|
||||
#include "payloads/PayloadHandler.h"
|
||||
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// pawletprofiled — Android entry point
|
||||
//
|
||||
// Counterpart to main.cpp (Linux/D-Bus). Registers PawletProfileBinderService
|
||||
// as "os.pawlet.profiled.IPawletProfileService/default" — the exact
|
||||
// name pawletprofiled.xml's VINTF fragment and sepolicy/service_contexts
|
||||
// already declare — and applies preinstalled profiles the same way
|
||||
// main.cpp does, from an Android-appropriate path.
|
||||
//
|
||||
// Not ported here: the ZTE ConnectivityWatcher (main.cpp's background
|
||||
// thread) — it watches NetworkManager over D-Bus, which doesn't exist on
|
||||
// Android. Zero-touch enrollment on PawletOS is separate follow-up work,
|
||||
// not silently dropped-but-unmentioned.
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
|
||||
static constexpr const char* kPreinstalledDir =
|
||||
"/data/system/pawletos/preinstalled";
|
||||
|
||||
static bool fileExists(const std::string& path) {
|
||||
struct stat st{};
|
||||
return ::stat(path.c_str(), &st) == 0;
|
||||
}
|
||||
|
||||
static void applyPreinstalledProfiles(pawletos::profile::PawletProfileBinderService& svc) {
|
||||
DIR* d = opendir(kPreinstalledDir);
|
||||
if (!d) return;
|
||||
|
||||
syslog(LOG_INFO, "pawletprofiled: scanning %s for preinstalled profiles", kPreinstalledDir);
|
||||
|
||||
struct dirent* ent;
|
||||
while ((ent = readdir(d)) != nullptr) {
|
||||
std::string name = ent->d_name;
|
||||
if (name == "." || name == "..") continue;
|
||||
if (name.find(".vconfig") == std::string::npos) continue;
|
||||
|
||||
std::string path = std::string(kPreinstalledDir) + "/" + name;
|
||||
std::ifstream f(path, std::ios::binary);
|
||||
if (!f) {
|
||||
syslog(LOG_WARNING, "pawletprofiled: cannot read %s", path.c_str());
|
||||
continue;
|
||||
}
|
||||
std::ostringstream buf;
|
||||
buf << f.rdbuf();
|
||||
std::string content = buf.str();
|
||||
std::vector<uint8_t> data(content.begin(), content.end());
|
||||
|
||||
std::string uuid;
|
||||
bool ok = svc.installProfileDirect(data, uuid);
|
||||
if (ok)
|
||||
syslog(LOG_INFO, "pawletprofiled: preinstalled %s -> uuid=%s", name.c_str(), uuid.c_str());
|
||||
else
|
||||
syslog(LOG_WARNING, "pawletprofiled: failed to apply %s", name.c_str());
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
int main() {
|
||||
openlog("pawletprofiled", LOG_PID | LOG_CONS, LOG_DAEMON);
|
||||
syslog(LOG_INFO, "pawletprofiled starting (Android/Binder)");
|
||||
|
||||
pawletos::profile::PayloadHandlerRegistry::registerAll();
|
||||
|
||||
auto service = ndk::SharedRefBase::make<pawletos::profile::PawletProfileBinderService>();
|
||||
|
||||
if (fileExists(kPreinstalledDir)) {
|
||||
applyPreinstalledProfiles(*service);
|
||||
}
|
||||
|
||||
const char* instanceName = "os.pawlet.profiled.IPawletProfileService/default";
|
||||
binder_status_t status = AServiceManager_addService(service->asBinder().get(), instanceName);
|
||||
if (status != STATUS_OK) {
|
||||
syslog(LOG_ERR, "pawletprofiled: AServiceManager_addService failed: %d", status);
|
||||
return 1;
|
||||
}
|
||||
syslog(LOG_INFO, "pawletprofiled: registered as %s", instanceName);
|
||||
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(4);
|
||||
ABinderProcess_startThreadPool();
|
||||
ABinderProcess_joinThreadPool(); // blocks forever
|
||||
|
||||
syslog(LOG_INFO, "pawletprofiled stopped");
|
||||
closelog();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Cert.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs DevicePolicyManager's
|
||||
// installCaCert() (device-owner) or the KeyChain install-cert intent flow —
|
||||
// AOSP has no /etc/ssl/certs-equivalent a daemon can just write files into.
|
||||
|
||||
namespace pawletos::profile::platform::cert {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[cert] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[cert] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::cert
|
||||
@@ -1,52 +0,0 @@
|
||||
#include "../ContentCache.h"
|
||||
#include "../../payloads/PayloadUtil.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <syslog.h>
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// CONTENT CACHE HANDLER (Android)
|
||||
// PawletOS-fork-specific — pawletprofiled's default PawletOS build doesn't
|
||||
// register this handler at all (see PayloadHandlers.cpp). Writes the
|
||||
// local-network-cache discovery override PawletCacheService reads — see
|
||||
// pawletcache-server/README.md and
|
||||
// android_packages_apps_PawletCache/src/os/pawlet/cache/PolicyOverride.kt.
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
namespace pawletos::profile::platform::content_cache {
|
||||
|
||||
using namespace pawletos::profile::util;
|
||||
|
||||
namespace {
|
||||
constexpr const char* kPolicyDir = "/data/misc/pawletcache";
|
||||
constexpr const char* kPolicyFile = "/data/misc/pawletcache/policy.json";
|
||||
}
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
std::string mode = field(p, "mode", "both");
|
||||
|
||||
std::ostringstream json;
|
||||
json << "{\n \"mode\": \"" << mode << "\"";
|
||||
|
||||
auto pinned = p.fields.find("pinned-server");
|
||||
if (pinned != p.fields.end()) {
|
||||
// Already valid JSON text (ProfileParser re-serializes nested
|
||||
// objects) — relay it verbatim under the camelCase key
|
||||
// PolicyOverride.kt expects, no reparsing needed here.
|
||||
json << ",\n \"pinnedServer\": " << pinned->second;
|
||||
}
|
||||
json << "\n}\n";
|
||||
|
||||
ensureDir(kPolicyDir);
|
||||
// World-readable by design — PawletCacheService reads this as a
|
||||
// regular app UID, and it's policy, not a secret (see PolicyOverride.kt).
|
||||
writeFile(kPolicyFile, json.str(), 0644);
|
||||
syslog(LOG_INFO, "[content-cache] applied mode=%s", mode.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& /*p*/) {
|
||||
removeFile(kPolicyFile);
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::content_cache
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../DnsProxy.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would write
|
||||
// Settings.Global.PRIVATE_DNS_MODE / PRIVATE_DNS_SPECIFIER (needs
|
||||
// WRITE_SECURE_SETTINGS) — no systemd-resolved.conf.d equivalent.
|
||||
|
||||
namespace pawletos::profile::platform::dns_proxy {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[dns-proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[dns-proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::dns_proxy
|
||||
@@ -1,19 +0,0 @@
|
||||
#include "../Ethernet.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would use the hidden/system
|
||||
// android.net.EthernetManager API — no NetworkManager equivalent exists.
|
||||
|
||||
namespace pawletos::profile::platform::ethernet {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[ethernet] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[ethernet] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::ethernet
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Firewall.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. There's no nftables/nft CLI on stock
|
||||
// AOSP — a real port would need NetworkPolicyManager rules or a local
|
||||
// VpnService-based firewall, a fundamentally different mechanism.
|
||||
|
||||
namespace pawletos::profile::platform::firewall {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[firewall] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[firewall] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::firewall
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../FirstBoot.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would suppress AOSP's
|
||||
// SetupWizard (Settings.Global DEVICE_PROVISIONED / USER_SETUP_COMPLETE) —
|
||||
// no cloud-init/GNOME Initial Setup equivalent here.
|
||||
|
||||
namespace pawletos::profile::platform::first_boot {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[first-boot] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[first-boot] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::first_boot
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "../Ldap.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android — and likely never will be as a direct
|
||||
// port. Android has no system LDAP client at all (no nslcd/libnss-ldapd
|
||||
// equivalent); this payload type doesn't map onto anything the platform
|
||||
// exposes. Logged for visibility rather than silently accepted.
|
||||
|
||||
namespace pawletos::profile::platform::ldap {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[ldap] not supported on Android (no system LDAP client), uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[ldap] not supported on Android (no system LDAP client), uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::ldap
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Mdm.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs Android's own
|
||||
// device-owner/EMM provisioning flow (DevicePolicyManager), a fundamentally
|
||||
// different enrollment model than cloud-init drop-ins.
|
||||
|
||||
namespace pawletos::profile::platform::mdm {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[mdm] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[mdm] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::mdm
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Passcode.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs
|
||||
// DevicePolicyManager.setPasswordQuality()/setPasswordMinimumLength() etc
|
||||
// (device-owner) — no pam_pwquality-equivalent config file to write.
|
||||
|
||||
namespace pawletos::profile::platform::passcode {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[passcode] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[passcode] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::passcode
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Pkcs12.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs
|
||||
// DevicePolicyManager.installKeyPair() (device-owner) — no system NSSDB
|
||||
// equivalent a daemon can write a .p12 into directly.
|
||||
|
||||
namespace pawletos::profile::platform::pkcs12 {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[pkcs12] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[pkcs12] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::pkcs12
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Proxy.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would use
|
||||
// DevicePolicyManager.setRecommendedGlobalProxy()/ProxyInfo (device-owner) —
|
||||
// no /etc/environment-equivalent to write.
|
||||
|
||||
namespace pawletos::profile::platform::proxy {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[proxy] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::proxy
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "../Screensaver.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would map to Daydream
|
||||
// (Settings.Secure SCREENSAVER_ENABLED / SCREENSAVER_COMPONENTS) plus
|
||||
// Settings.System SCREEN_OFF_TIMEOUT for the idle delay — no dconf profile
|
||||
// to write.
|
||||
|
||||
namespace pawletos::profile::platform::screensaver {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[screensaver] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[screensaver] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::screensaver
|
||||
@@ -1,22 +0,0 @@
|
||||
#include "../SoftwareUpdate.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. PawletOS already has a dedicated update
|
||||
// policy path — BgUpd's install_mode ("silent"/"manual" per component, see
|
||||
// android_packages_apps_BgUpd) — a real port would translate this payload's
|
||||
// automatic/deferral fields into BgUpd's manifest/policy rather than apt
|
||||
// settings, which don't apply here at all.
|
||||
|
||||
namespace pawletos::profile::platform::software_update {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[software-update] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[software-update] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::software_update
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../TimeServer.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would write
|
||||
// Settings.Global.NTP_SERVER (requires WRITE_SECURE_SETTINGS, same
|
||||
// permission pattern BgUpd already holds for its own settings writes).
|
||||
|
||||
namespace pawletos::profile::platform::time_server {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[time-server] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[time-server] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::time_server
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "../Vpn.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs an android.net.VpnService
|
||||
// component (IKEv2/L2TP have no NetworkManager-plugin equivalent on Android;
|
||||
// this would mean shipping a companion VPN app or a system VpnService, not
|
||||
// just writing a config file).
|
||||
|
||||
namespace pawletos::profile::platform::vpn {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[vpn] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[vpn] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::vpn
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Wallpaper.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port would use
|
||||
// android.app.WallpaperManager (setStream/setResource) — no dconf profile
|
||||
// to write.
|
||||
|
||||
namespace pawletos::profile::platform::wallpaper {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[wallpaper] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[wallpaper] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::wallpaper
|
||||
@@ -1,20 +0,0 @@
|
||||
#include "../Wifi.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
// Not yet implemented on Android. A real port needs WifiManager /
|
||||
// WifiNetworkSuggestion (API 29+) or a privileged wpa_supplicant config
|
||||
// write — NetworkManager keyfiles (the Linux implementation) don't apply.
|
||||
|
||||
namespace pawletos::profile::platform::wifi {
|
||||
|
||||
bool apply(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[wifi] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
void revert(const ParsedPayload& p) {
|
||||
syslog(LOG_WARNING, "[wifi] not implemented on Android yet, uuid=%s", p.uuid.c_str());
|
||||
}
|
||||
|
||||
} // namespace pawletos::profile::platform::wifi
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Vendored, statically-linked real OpenSSL — pawletprofiled's Android build
|
||||
// only, nothing else on the system links against these. See README.md for
|
||||
// why (BoringSSL has no CMS support) and how to populate lib/*/*.a.
|
||||
//
|
||||
|
||||
cc_prebuilt_library_static {
|
||||
name: "libcrypto_pawlet_static",
|
||||
arch: {
|
||||
arm64: { srcs: ["lib/arm64-v8a/libcrypto.a"] },
|
||||
arm: { srcs: ["lib/armeabi-v7a/libcrypto.a"] },
|
||||
x86_64: { srcs: ["lib/x86_64/libcrypto.a"] },
|
||||
x86: { srcs: ["lib/x86/libcrypto.a"] },
|
||||
},
|
||||
export_include_dirs: ["include"],
|
||||
strip: { none: true },
|
||||
}
|
||||
|
||||
cc_prebuilt_library_static {
|
||||
name: "libssl_pawlet_static",
|
||||
arch: {
|
||||
arm64: { srcs: ["lib/arm64-v8a/libssl.a"] },
|
||||
arm: { srcs: ["lib/armeabi-v7a/libssl.a"] },
|
||||
x86_64: { srcs: ["lib/x86_64/libssl.a"] },
|
||||
x86: { srcs: ["lib/x86/libssl.a"] },
|
||||
},
|
||||
export_include_dirs: ["include"],
|
||||
strip: { none: true },
|
||||
// libssl depends on libcrypto symbols; Soong needs this to order the
|
||||
// static link correctly.
|
||||
whole_static_libs: ["libcrypto_pawlet_static"],
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
# Vendored OpenSSL (Android, static, pawletprofiled-only)
|
||||
|
||||
AOSP's system `libcrypto`/`libssl` is BoringSSL, which has no CMS/PKCS#7
|
||||
support. Rather than touch the platform's crypto stack (used by Keystore,
|
||||
the TLS stack, other HALs — swapping it breaks far more than it fixes),
|
||||
pawletprofiled statically links its **own** copy of real OpenSSL, scoped to
|
||||
just this one binary. Nothing else on the system links against it or even
|
||||
knows it's there.
|
||||
|
||||
This directory holds the prebuilt static libs + headers and the Soong
|
||||
modules that expose them. **The `lib/*/` and `include/` directories are
|
||||
empty placeholders** — populate them by cross-compiling OpenSSL yourself
|
||||
(steps below) before `m pawletprofiled` will link on Android. Nothing here
|
||||
fabricates or ships a prebuilt binary sight-unseen.
|
||||
|
||||
---
|
||||
|
||||
## Building OpenSSL for Android
|
||||
|
||||
Needs the Android NDK (r26+) on your PATH as `$ANDROID_NDK_ROOT`, and
|
||||
OpenSSL source (3.x recommended — CMS support is stable there).
|
||||
|
||||
```bash
|
||||
git clone --branch openssl-3.2 --depth 1 https://github.com/openssl/openssl.git
|
||||
cd openssl
|
||||
|
||||
export ANDROID_NDK_ROOT=/path/to/android-ndk
|
||||
export PATH="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"
|
||||
|
||||
# Repeat per ABI. android-arm64 shown; swap target/API for the others.
|
||||
for target in android-arm64 android-arm android-x86_64 android-x86; do
|
||||
case $target in
|
||||
android-arm64) abi=arm64-v8a ;;
|
||||
android-arm) abi=armeabi-v7a ;;
|
||||
android-x86_64) abi=x86_64 ;;
|
||||
android-x86) abi=x86 ;;
|
||||
esac
|
||||
|
||||
./Configure "$target" -D__ANDROID_API__=26 no-shared no-tests \
|
||||
--prefix="$(pwd)/build-$abi"
|
||||
make clean
|
||||
make -j"$(nproc)"
|
||||
make install_sw
|
||||
|
||||
mkdir -p "../lib/$abi"
|
||||
cp "build-$abi/lib/libcrypto.a" "../lib/$abi/"
|
||||
cp "build-$abi/lib/libssl.a" "../lib/$abi/"
|
||||
done
|
||||
|
||||
# Headers are identical across ABIs — copy from any one build.
|
||||
cp -r build-arm64-v8a/include/openssl ../include/
|
||||
```
|
||||
|
||||
`no-shared` is what makes these static (`.a`) — deliberate, so nothing
|
||||
depends on an OpenSSL `.so` being present on-device at runtime. `no-tests`
|
||||
just skips building OpenSSL's own test suite to save time.
|
||||
|
||||
## Verifying
|
||||
|
||||
```
|
||||
third_party/openssl-android/
|
||||
├── include/openssl/*.h (same for every ABI)
|
||||
└── lib/
|
||||
├── arm64-v8a/{libcrypto,libssl}.a
|
||||
├── armeabi-v7a/{libcrypto,libssl}.a
|
||||
├── x86_64/{libcrypto,libssl}.a
|
||||
└── x86/{libcrypto,libssl}.a
|
||||
```
|
||||
|
||||
Once populated, `m pawletprofiled` picks these up via `Android.bp` in this
|
||||
directory — see `libcrypto_pawlet_static` / `libssl_pawlet_static` /
|
||||
`pawletprofiled_openssl_headers`, referenced from
|
||||
`pawletprofiled/Android.bp`'s Android `static_libs`.
|
||||
|
||||
## Updating
|
||||
|
||||
OpenSSL ships security fixes regularly — treat these `.a` files as a
|
||||
dependency you're responsible for rebuilding on new releases, same as any
|
||||
other vendored library. Nothing here auto-updates them.
|
||||
@@ -1 +0,0 @@
|
||||
Not populated. Copy the openssl/ header directory from any one ABI build per ../README.md — headers are identical across ABIs.
|
||||
@@ -1 +0,0 @@
|
||||
Not populated. Build libcrypto.a and libssl.a for arm64-v8a per ../../README.md and drop them in this directory.
|
||||
@@ -1 +0,0 @@
|
||||
Not populated. Build libcrypto.a and libssl.a for armeabi-v7a per ../../README.md and drop them in this directory.
|
||||
@@ -1 +0,0 @@
|
||||
Not populated. Build libcrypto.a and libssl.a for x86 per ../../README.md and drop them in this directory.
|
||||
@@ -1 +0,0 @@
|
||||
Not populated. Build libcrypto.a and libssl.a for x86_64 per ../../README.md and drop them in this directory.
|
||||
Reference in New Issue
Block a user