Authenticate pam using a ssh session to your phone. Because why not?
  • C 97.5%
  • Makefile 2%
  • Shell 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-25 14:17:38 +02:00
.gitignore initial commit 2026-09-25 07:48:32 +02:00
auth.sh add example and docs 2026-09-25 09:56:08 +02:00
Makefile modularization 2026-09-25 14:17:38 +02:00
pam_termux_fingerprint.c modularization 2026-09-25 14:17:38 +02:00
pam_termux_fingerprint_parallel.c modularization 2026-09-25 14:17:38 +02:00
README.md modularization 2026-09-25 14:17:38 +02:00
ssh_auth.c modularization 2026-09-25 14:17:38 +02:00
ssh_auth.h modularization 2026-09-25 14:17:38 +02:00

pam-termux-fingerprint

A small, intentionally simple PAM module that authenticates users by executing a command over SSH and using its exit status as the authentication result.

Despite the original name, the module is not tied to fingerprints, Termux, Android, or any particular authentication mechanism. The remote command can perform whatever authentication logic you want, as long as it communicates the result through its exit code:

  • 0 → authentication succeeds
  • non-zero → authentication fails

The included auth.sh demonstrates using this mechanism with the Termux API's fingerprint authentication.

How it works

┌─────────┐       SSH       ┌──────────────────┐
│   PAM   │ ──────────────> │ Remote SSH host  │
│ module  │                 │                  │
└─────────┘                 │ authentication   │
     │                      │ command          │
     │                      └────────┬─────────┘
     │                               │
     │        exit status            │
     │ <─────────────────────────────┘
     │
     ├── 0     → PAM_SUCCESS
     └── != 0  → PAM_AUTH_ERR

The module:

  1. Receives an SSH host, port, username, and command from PAM configuration.
  2. Connects using /usr/bin/ssh.
  3. Executes the configured remote command.
  4. Waits for it to finish.
  5. Uses the command's exit status as the authentication result.

The module does not need to understand what the remote command actually does.

Configuration

The module takes its configuration as a single pipe-separated argument:

IP|PORT|USER|COMMAND

The command supports these placeholders: %h for the local hostname, %s for the PAM service, %u for the PAM username, %t for the TTY, %r for the remote user, and %R for the remote host. Colons in the command are converted to spaces, so sh:-c:check:%u is sent to SSH as sh -c check %u after placeholder expansion.

An optional v argument enables verbose logging.

Example:

auth sufficient pam_termux_fingerprint.so 100.115.238.73|2222|u0_a407|fprint v

This tells PAM to execute:

ssh -p 2222 u0_a407@100.115.238.73 fprint

and interpret the result as:

exit 0  → authentication succeeded
exit != 0 → authentication failed

Example: Termux fingerprint authentication

The repository includes auth.sh as an example of a remote authentication helper:

#!/data/data/com.termux/files/usr/bin/bash
# minimal executable to bridge termux api logic to exit codes
[ "$(termux-fingerprint | jq -r '.auth_result')" = "AUTH_RESULT_SUCCESS" ]

The script converts the Termux fingerprint API result into a normal Unix exit status.

A successful fingerprint authentication causes the test expression to return 0.

A failed authentication causes it to return a non-zero status.

The PAM module therefore does not need to know anything about Termux or fingerprint JSON.

PAM example

A complete PAM configuration might look like:

#%PAM-1.0

auth        sufficient    pam_termux_fingerprint.so 100.115.238.73|2222|u0_a407|fprint v
auth        sufficient    pam_fprintd_grosshack.so
auth        include       system-auth

account     include       system-auth
session     include       system-auth

The exact PAM stack depends on what you are trying to authenticate and how your system is configured.

Building

Dependencies:

  • gcc
  • make
  • PAM development headers

Build:

make

Install:

sudo make install

This installs the module to:

/usr/lib/security/pam_termux_fingerprint.so

SSH requirements

The PAM module invokes the system SSH client rather than implementing SSH itself.

The configured SSH connection therefore needs to work non-interactively.

In particular, the SSH connection must not require a password or interactive prompt, since PAM cannot wait for arbitrary SSH interaction.

The module uses:

BatchMode=yes
StrictHostKeyChecking=yes

and has connection/command timeouts to prevent an unavailable remote host from hanging authentication indefinitely.

Make sure the SSH host key is trusted before using the module.

Test the exact connection manually first:

ssh \
  -p 2222 \
  -o BatchMode=yes \
  -o StrictHostKeyChecking=yes \
  user@host \
  command

Then check the exit status:

echo $?

Logging

Verbose logging can be enabled by adding v after the module configuration:

auth sufficient pam_termux_fingerprint.so 100.115.238.73|2222|u0_a407|fprint v

Logs are written to:

/var/log/pam_termux_fingerprint.log

For example:

sudo tail -f /var/log/pam_termux_fingerprint.log

With verbose logging enabled, the log records the PAM context, expanded SSH command, SSH target, child-process failures, SSH output, timeout details, and the final exit status. This is useful when a polkit authentication request fails before the remote helper appears to run. The command and SSH output may contain usernames or other context from the PAM request.

Designing your own authentication helper

The important part of this project is the exit-code interface.

Your remote helper can perform any authentication logic you want:

#!/bin/sh

if authentication_succeeded; then
    exit 0
else
    exit 1
fi

The PAM module does not care whether the command uses:

  • a fingerprint sensor
  • a hardware token
  • a phone
  • a custom API
  • a challenge-response system
  • some completely cursed shell script

As long as the command returns the appropriate exit status.

Security considerations

This module is intentionally minimal, but SSH-backed authentication introduces several security considerations.

SSH authentication

The SSH connection itself must be authenticated securely. Avoid configurations that disable host-key verification or otherwise allow a malicious host to impersonate the authentication server.

Non-interactive authentication

The SSH credentials used by the PAM process should be carefully restricted. Ideally, the remote SSH account should only be capable of running the intended authentication helper.

Remote command

Treat the configured remote command as trusted code. A compromise of the remote account or authentication helper could directly affect authentication.

Availability

Authentication now depends on the SSH connection and remote device being available. Network failures, an unavailable phone, or an unresponsive authentication helper will cause authentication to fail.

Timeouts

The module places a limit on how long the remote command can run, preventing a stuck SSH connection from blocking PAM indefinitely.

Why exit codes?

Using exit codes keeps the PAM module deliberately dumb.

Instead of implementing every possible authentication protocol inside the module:

PAM module
    ↓
SSH
    ↓
arbitrary authentication program
    ↓
exit 0 / exit non-zero

The remote program owns the authentication logic, while the PAM module only provides the bridge between SSH and PAM.

Status

This is a small experimental PAM module rather than a polished general-purpose authentication framework.

Use it with care, especially in PAM configurations that could affect your ability to log into the system.