Skip to content

Instantly share code, notes, and snippets.

@ds17f
Created May 3, 2026 16:31
Show Gist options
  • Select an option

  • Save ds17f/7ec5bcaf7748430e578a394de0dcb540 to your computer and use it in GitHub Desktop.

Select an option

Save ds17f/7ec5bcaf7748430e578a394de0dcb540 to your computer and use it in GitHub Desktop.
Howdy face unlock on Fedora 44 — Lenovo Aura Edition i7 14"

Howdy Face Unlock on Fedora 44 — Lenovo Aura Edition i7 14"

Windows Hello–style face unlock for sudo and GNOME screen lock, using the built-in IR camera.

Hardware

  • Laptop: Lenovo Aura Edition i7 14"
  • Camera: Chicony integrated IR camera (04f2:b83d)
  • IR camera device: /dev/video2 (640×360, GREY format, 15fps)
  • Color camera device: /dev/video0

Identify your camera nodes:

sudo dnf install v4l-utils
v4l2-ctl --list-devices
# Look for "Integrated I" = IR camera, "Integrated C" = color camera

Why This Is Complicated on Fedora 44

  • pam_python requires Python 2.7, which is gone from Fedora 44 — the standard howdy install fails
  • The IR camera outputs GREY (monochrome) frames; OpenCV's default V4L2 backend fails to negotiate the format
  • GDM's SELinux context (xdm_t) has no policy to access video devices by default

Install Dependencies

# Enable howdy COPR
sudo dnf copr enable principis/howdy -y

# Build deps for dlib (Python 2 is gone, so we build from source)
sudo dnf install cmake gcc-c++ python3-devel python3-pip -y
sudo pip install dlib face_recognition ffmpeg-python

# System opencv (pip opencv doesn't work on Python 3.14)
sudo dnf install python3-opencv v4l-utils -y

# Install howdy RPM bypassing the broken dlib RPM dependency
sudo dnf download howdy
sudo rpm -i --nodeps howdy-*.x86_64.rpm

Configure Howdy

# Set the IR camera device
sudo sed -i 's|device_path = none|device_path = /dev/video2|' /usr/lib64/security/howdy/config.ini

# Set frame dimensions for this camera
sudo sed -i 's/frame_width = -1/frame_width = 640/' /usr/lib64/security/howdy/config.ini
sudo sed -i 's/frame_height = -1/frame_height = 360/' /usr/lib64/security/howdy/config.ini

# Use opencv plugin (ffmpeg reopens the camera per-batch, causing warmup/darkness issues)
sudo sed -i 's/recording_plugin = opencv/recording_plugin = opencv/' /usr/lib64/security/howdy/config.ini

Fix OpenCV Backend (Critical)

The IR camera requires the V4L2 backend hint or it fails with ioctl(VIDIOC_QBUF): Bad file descriptor.

Edit /usr/lib64/security/howdy/recorders/video_capture.py and change:

self.internal = cv2.VideoCapture(
    self.config.get("video", "device_path")
)

to:

self.internal = cv2.VideoCapture(self.config.get("video", "device_path"), cv2.CAP_V4L2)

Enroll Your Face

sudo howdy add
# Follow prompts, look straight at the camera
# The IR light will come on

PAM Setup (pam_exec instead of pam_python)

Since pam_python is dead on Fedora 44, we use pam_exec.so with a shell wrapper.

Create /usr/lib64/security/howdy/howdy-auth:

sudo tee /usr/lib64/security/howdy/howdy-auth << 'EOF'
#!/bin/bash
timeout 9 /usr/bin/python3 /usr/lib64/security/howdy/compare.py "$PAM_USER" &>/dev/null
EOF
sudo chmod +x /usr/lib64/security/howdy/howdy-auth

Enable for sudo

Add to the top of /etc/pam.d/sudo (after the #%PAM-1.0 line):

auth       sufficient    pam_exec.so quiet /usr/lib64/security/howdy/howdy-auth

Enable for GNOME Screen Lock

Add to /etc/pam.d/gdm-password after the pam_selinux_permit.so line:

auth       sufficient    pam_exec.so quiet /usr/lib64/security/howdy/howdy-auth

SELinux Policy (Required for Screen Lock)

GDM's xdm_t context has no permission to open video devices. Create and install a policy module:

cat > /tmp/howdy_xdm.te << 'EOF'
module howdy_xdm 1.0;

require {
    type xdm_t;
    type v4l_device_t;
    class chr_file { read write open ioctl map getattr };
}

allow xdm_t v4l_device_t:chr_file { read write open ioctl map getattr };
EOF

checkmodule -M -m -o /tmp/howdy_xdm.mod /tmp/howdy_xdm.te
semodule_package -o /tmp/howdy_xdm.pp -m /tmp/howdy_xdm.mod
sudo semodule -i /tmp/howdy_xdm.pp

Testing

# Test face recognition directly (should exit 0 and print timing report with end_report=true)
sudo python3 /usr/lib64/security/howdy/compare.py $USER

# Test sudo (camera IR light should come on, then sudo proceeds without password)
sudo ls

# Screen lock: Super+L, then look at camera

Troubleshooting

Camera frames too dark: The IR camera takes ~10 frames to warm up. If using the ffmpeg plugin, switch back to opencv — ffmpeg reopens the camera per-batch so it never warms up.

exit code 1 from gdm-password: SELinux is blocking camera access. Install the policy module above.

exit code 2 from gdm-password: The howdy-auth script failed before opening the camera (e.g. a log redirect to a non-existent file). Check the script for redirects.

sudo broken after adding PAM line: If pam_exec.so can't run the script (wrong path, not executable), PAM returns an error and blocks password fallback too. Use pkexec to fix /etc/pam.d/sudo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment