# vesperprofiled VesperOS unified device management daemon. One binary. Two subsystems. Ships on every VesperOS device. --- ## Subsystems ### Profile Service D-Bus system service at `me.oxmc.vesperos.ProfileService`. Parses, verifies, persists, and applies `.vconfig` profiles. The allowed payload types are controlled by the separately-installed `vesperprofiled-config-schema` package — OEMs can restrict the configuration surface without touching the daemon binary. ### ZTE Client Zero-Touch Enrollment. Runs as a background thread. Watches NetworkManager for internet connectivity. On first connection, queries a ZTE lookup server with the device's hardware identity. Downloads and installs the enrollment profile automatically via the local D-Bus service. Handles the deferred case: if no network at first boot, enrolls on the first successful connection later. --- ## Package layout ``` vesperprofiled/ ├── Android.bp AOSP Soong build ├── CMakeLists.txt Linux CMake build ├── vesperprofiled.rc Android init script ├── vesperprofiled.xml Android VINTF fragment ├── zte.conf.example ZTE client config │ ├── aidl/me/oxmc/vesperos/profile/ │ └── IVesperProfileService.aidl Binder interface (Android) │ ├── src/ │ ├── main.cpp Entry point │ ├── VesperProfileService.h/.cpp D-Bus service (Linux) │ ├── 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 │ ├── src/zte/ │ ├── DeviceIdentity.h/.cpp Hardware identity collection │ ├── ZTELookupClient.h/.cpp ZTE server HTTPS client (libcurl) │ └── ConnectivityWatcher.h/.cpp NM D-Bus connectivity watcher │ ├── systemd/vesperprofiled.service Systemd unit ├── dbus/me.oxmc.vesperos.ProfileService.conf D-Bus policy ├── apparmor/vesperprofiled AppArmor MAC profile ├── sepolicy/ Android SELinux policy └── debian/ Debian Trixie packaging ``` --- ## Dependencies ### Runtime | Package | Used for | |---|---| | `vesperprofiled-config-schema` | Schema defining allowed payload types | | `libssl3` | CMS signature verification, PBKDF2 | | `libyaml-0-2` | YAML parsing | | `libdbus-1-3` | D-Bus system service | | `libcurl4` | ZTE HTTPS lookups | | `network-manager` | WiFi/Ethernet/VPN keyfile reload | ### Recommended (enable specific payload handlers) | Package | Payload types | |---|---| | `cloud-init` | `mdm`, `first-boot` | | `nftables` | `firewall` | | `network-manager-strongswan` | `vpn` (IKEv2) | | `network-manager-l2tp` | `vpn` (L2TP) | | `libpam-pwquality` | `passcode` (complexity) | | `libpam-faillock` | `passcode` (lockout) | | `libnss3-tools` | `pkcs12` (NSSDB import) | | `unattended-upgrades` | `software-update` | | `dconf-cli` | `desktop`, `screensaver`, `first-boot` | | `tpm2-tools` | ZTE TPM EK detection | --- ## Building — Linux (Debian Trixie) ```bash # Build dependencies sudo apt install -y \ cmake libssl-dev libyaml-dev libdbus-1-dev \ libsystemd-dev libcurl4-openssl-dev pkg-config # Build .deb (includes vesperprofiled-config-schema as a dep) dpkg-buildpackage -us -uc -b sudo apt install \ ../vesperprofiled-config-schema_1.0.0-1_all.deb \ ../vesperprofiled_1.0.0-1_amd64.deb # Or build without packaging cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j$(nproc) sudo cmake --install build ``` --- ## Building — Android (AOSP) ```bash cp -r vesperprofiled/ $AOSP_ROOT/vendor/oxmc/vesperprofiled/ # Add to device makefile echo 'PRODUCT_PACKAGES += vesperprofiled' \ >> device/oxmc/vesperos/vesperos.mk echo 'BOARD_SEPOLICY_DIRS += vendor/oxmc/vesperprofiled/sepolicy' \ >> device/oxmc/vesperos/BoardConfig.mk source build/envsetup.sh && lunch vesperos_arm64-userdebug m vesperprofiled ``` --- ## Verifying the installation ```bash # Service status systemctl status vesperprofiled # D-Bus connectivity dbus-send --system --print-reply \ --dest=me.oxmc.vesperos.ProfileService \ /me/oxmc/vesperos/ProfileService \ me.oxmc.vesperos.IProfileService.IsDeviceManaged # List installed profiles dbus-send --system --print-reply \ --dest=me.oxmc.vesperos.ProfileService \ /me/oxmc/vesperos/ProfileService \ me.oxmc.vesperos.IProfileService.ListProfiles # ZTE enrollment state cat /var/lib/vesperprofiled/zte_state.json # Live logs journalctl -u vesperprofiled -f ``` --- ## Installing a profile from the command line ```python #!/usr/bin/env python3 import dbus, sys with open(sys.argv[1], 'rb') as f: data = f.read() bus = dbus.SystemBus() obj = bus.get_object('me.oxmc.vesperos.ProfileService', '/me/oxmc/vesperos/ProfileService') svc = dbus.Interface(obj, 'me.oxmc.vesperos.IProfileService') uuid = svc.InstallProfile(dbus.ByteArray(data)) print('Installed profile UUID:', uuid) ``` --- ## Signing profiles Profiles containing `mdm`, `kiosk`, `asam`, or `removal-password` payloads must be CMS/PKCS#7 signed. Unsigned profiles install with a trust warning. ```bash # Generate a development signing key and CA openssl req -x509 -newkey rsa:4096 -days 3650 -nodes \ -keyout /etc/vesperprofiled/signing_key.pem \ -out /etc/vesperprofiled/profile_ca.pem \ -subj "/CN=VesperOS Profile Signing/O=oxmc" # Sign a profile openssl cms -sign \ -in my.vconfig \ -out my.signed.vconfig \ -signer /etc/vesperprofiled/profile_ca.pem \ -inkey /etc/vesperprofiled/signing_key.pem \ -outform DER -nodetach ``` The CA at `/etc/vesperprofiled/profile_ca.pem` is trusted automatically. For a system-wide trusted badge, also install it as a system CA: ```bash cp /etc/vesperprofiled/profile_ca.pem \ /usr/local/share/ca-certificates/vesperos-profile-ca.crt update-ca-certificates ``` --- ## Preinstalled profiles Drop signed `.vconfig` files into `/etc/vesperprofiled/preinstalled/` before first boot. The daemon applies them at startup, **before** `cloud-init-local.service` starts (enforced via `Before=cloud-init-local.service` in the systemd unit). This lets image builders bake in WiFi credentials, first-boot GNOME setup suppression, and MDM enrollment — all applied before cloud-init tries to reach its datasource. --- ## Zero-Touch Enrollment ZTE configuration lives at `/etc/vesperprofiled/zte.conf` (copy from `zte.conf.example`). The key setting is `server_url`, which points to your `vesper-zte-server` instance. ```ini server_url=https://zte.yourdomain.com ``` Hardware identity priority used for the ZTE lookup: | Priority | Source | Path | |---|---|---| | 1 | DMI system UUID | `/sys/class/dmi/id/product_uuid` | | 2 | Board serial | `/sys/class/dmi/id/board_serial` | | 3 | System serial | `/sys/class/dmi/id/product_serial` | | 4 | machine-id | `/etc/machine-id` | | 5 | Permanent MAC | `/sys/class/net//perm_address` | --- ## Bugs fixed vs. previous iterations | Bug | Fix | |---|---| | `ProfileParser.cpp` used `android-base/logging.h` and `LOG()` | Replaced with `syslog()` throughout | | `debian/rules` had postinst `install -d` lines leaked after `override_dh_installsystemd` | Removed stray lines | | `sepolicy/vesperprofiled.te` had typo `vesperprofrofiled` | Fixed | | `apparmor/vesperprofiled` used `abstractions/openssl` (doesn't exist on Debian) | Replaced with explicit `/etc/ssl/certs/` and network socket rules | | `ZTELookupClient` called `curl_global_init` but never `curl_global_cleanup` | Added to destructor | | `debian/control` missing `Depends: vesperprofiled-config-schema` | Added |