2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00
2026-04-20 09:09:23 -07:00

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
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)

# 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)

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

# 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

#!/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.

# 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:

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.

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/<if>/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
S
Description
No description provided
Readme
6.8 MiB
Languages
C++ 51.3%
Makefile 41.6%
CMake 6.5%
AIDL 0.6%