Become a daemon: a held session, a worker, and net.reactivated.Fprint
The probe becomes the thing the plan was for. Three threads: the supplicant services QTEE's callbacks; the worker owns the sensor rail, the QTEE session and the trustlet and is the only thread that ever invokes it, so every enrolment and authentication is serialised by construction; the main thread runs the GLib loop and speaks fprintd's own D-Bus interface, never touching the trustlet directly. Session is the bring-up from a cold /dev/tee0 to a calibrated sensor, plus the enrol and verify loops as methods that take a cancel flag and progress callbacks. Worker is a job queue on a pthread with an 8 MiB stack -- musl's default is 128 KiB and the session keeps request buffers on the stack. Results come back through g_idle_add so signals are emitted on the thread that owns the connection. net.reactivated.Fprint is implemented rather than wrapped: Manager with GetDevices/GetDefaultDevice, Device with Claim/Release, EnrollStart/Stop, VerifyStart/Stop, ListEnrolledFingers and the three Delete variants, the three signals, and the five properties. Owning fprintd's name is what lets pam_fprintd, the Plasma KCM and fprintd-enroll work unmodified. Two honest limits. Authorisation is the conservative rule -- you may act on your own prints, root on anyone's -- because polkit is not in this milestone. And DeleteEnrolledFingers removes the finger's NAME only: FF_CMD_TA_REMOVE exists but its payload is not reverse-engineered, and guessing at a command that writes to the store is exactly how an index got invalidated earlier today. A deleted finger loses its name and stops being offered; its template still occupies a slot in the group. Logged as such. The finger-name map is written per user under the state directory, tmp-file and rename. An enrolment records the fid the trustlet reported in the touch event's response; if none was reported the finger cannot be named yet, and the daemon says so rather than inventing one. Verified on the phone as a systemd unit: owns the bus name, init chain complete, floor calibrated, ready.
This commit is contained in:
parent
9b03329aa0
commit
e0bc02332f
3 changed files with 1041 additions and 459 deletions
File diff suppressed because it is too large
Load diff
21
packaging/net.reactivated.Fprint.conf
Normal file
21
packaging/net.reactivated.Fprint.conf
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
|
||||
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||
<!-- SPDX-License-Identifier: GPL-3.0-only
|
||||
SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
|
||||
fingerprintd owns fprintd's bus name so pam_fprintd, the Plasma KCM and
|
||||
fprintd-enroll work unmodified. Same shape as fprintd's own policy: root
|
||||
owns the name, anyone may call it, and the daemon enforces who may act on
|
||||
whose prints.
|
||||
Install: /usr/share/dbus-1/system.d/net.reactivated.Fprint.conf -->
|
||||
<busconfig>
|
||||
<policy user="root">
|
||||
<allow own="net.reactivated.Fprint"/>
|
||||
<allow send_destination="net.reactivated.Fprint"/>
|
||||
</policy>
|
||||
<policy context="default">
|
||||
<allow send_destination="net.reactivated.Fprint"/>
|
||||
<allow receive_sender="net.reactivated.Fprint"/>
|
||||
</policy>
|
||||
</busconfig>
|
||||
44
project.cpp
44
project.cpp
|
|
@ -36,6 +36,47 @@ static void ApplyQcomteeFlags(Configuration& cfg) {
|
|||
cfg.linkFlags.push_back((root / "libqcomtee.a").string());
|
||||
}
|
||||
|
||||
// pkg-config wrapper (std-only: no popen in import std). Returns the flags
|
||||
// split on whitespace, or empty if pkg-config is unavailable.
|
||||
static std::vector<std::string> PkgConfig(std::string_view args) {
|
||||
fs::path tmp = fs::temp_directory_path() /
|
||||
std::format("fingerprintd-pkgconfig-{}.txt", std::hash<std::string_view>{}(args));
|
||||
std::string cmd = std::format("pkg-config {} > {} 2>/dev/null", args, tmp.string());
|
||||
std::vector<std::string> flags;
|
||||
if (std::system(cmd.c_str()) == 0) {
|
||||
std::ifstream f(tmp);
|
||||
std::string flag;
|
||||
while (f >> flag)
|
||||
flags.push_back(flag);
|
||||
}
|
||||
std::error_code ec;
|
||||
fs::remove(tmp, ec);
|
||||
return flags;
|
||||
}
|
||||
|
||||
// GDBus (gio-2.0) for net.reactivated.Fprint. Same choice imsd made, for the
|
||||
// same reason: the platform stack is GLib, so a GMainLoop is wanted regardless.
|
||||
static void ApplyGioFlags(Configuration& cfg) {
|
||||
if (!cfg.sysroot.empty()) {
|
||||
// Cross build: the host's pkg-config would answer for the wrong
|
||||
// architecture. glib's include layout is stable; `-I=` resolves
|
||||
// inside the sysroot.
|
||||
cfg.compileFlags.push_back("-I=/usr/include/glib-2.0");
|
||||
cfg.compileFlags.push_back("-I=/usr/lib/glib-2.0/include");
|
||||
for (const char* l : { "-lgio-2.0", "-lgobject-2.0", "-lglib-2.0" })
|
||||
cfg.linkFlags.push_back(l);
|
||||
} else {
|
||||
for (std::string& f : PkgConfig("--cflags gio-2.0"))
|
||||
if (f.starts_with("-I") || f.starts_with("-D")) cfg.compileFlags.push_back(std::move(f));
|
||||
std::vector<std::string> libs;
|
||||
for (std::string& f : PkgConfig("--libs gio-2.0"))
|
||||
if (f.starts_with("-l") || f.starts_with("-L")) libs.push_back(std::move(f));
|
||||
if (libs.empty()) libs = { "-lgio-2.0", "-lgobject-2.0", "-lglib-2.0" };
|
||||
for (std::string& f : libs)
|
||||
cfg.linkFlags.push_back(std::move(f));
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||
// fingerprintd-core — the wire formats and state machines as a static
|
||||
// library of pure C++ modules. Deliberately free of GLib, libqcomtee and
|
||||
|
|
@ -79,7 +120,8 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
}
|
||||
|
||||
ApplyQcomteeFlags(cfg);
|
||||
cfg.linkFlags.push_back("-lpthread"); // the supplicant thread
|
||||
ApplyGioFlags(cfg);
|
||||
cfg.linkFlags.push_back("-lpthread"); // the supplicant and worker threads
|
||||
|
||||
cfg.AddTest("Sfs").Dependencies({ Core.get() });
|
||||
cfg.AddTest("Rpmb").Dependencies({ Core.get() });
|
||||
|
|
|
|||
Loading…
Reference in a new issue