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

256 lines
8.0 KiB
Markdown

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