2026-03-17 16:35:15 +11:00
2026-03-17 16:35:15 +11:00
2026-03-17 16:35:15 +11:00
2026-03-17 11:45:14 +11:00

PAM C++ + Rust Backend Monorepo

This project provides a Linux PAM module written in C++ (GNU g++, C++17) that delegates authentication and logging to a Rust static library backend. The build is orchestrated by CMake, which triggers Cargo for the Rust backend.

Structure

  • pam-module/: C++ PAM module source
  • rust-backend/: Rust static library backend
  • tests/: Integration tests

Build Requirements

  • GNU g++ (C++17)
  • CMake >= 3.15
  • Rust (cargo)
  • PAM development headers

Build Instructions

mkdir build && cd build
cmake ..
cmake --build .

Install

Copy the built PAM module to /lib/security/ or /lib64/security/ as needed.

Logging

Rust backend logs to /var/log/pam_rust_backend.log by default.

C / C++ Logging Wrappers (examples)

This project exposes a simple Rust FFI sink and provides lightweight C and C++ wrappers for convenient logging without changing the Rust side.

Headers:

  • pam-module/include/rust_backend_ffi.h — canonical FFI declarations and level enum.
  • pam-module/include/rust_backend_logging_c.h — C printf-style helpers.
  • pam-module/include/rust_backend_logging_cpp.h — C++ cout/cerr-style RAII stream helpers.

C example (printf-style):

#include "rust_backend_logging_c.h"

// simple formatted info log
RUST_LOGF_INFO("user=%s result=%d", user, result);

C notes:

  • Formatting uses a fixed buffer (RUST_LOG_FMT_BUFSZ, default 2048) and is performed in C; the formatted string is forwarded to Rust.
  • If the formatted output is longer than the buffer it will be truncated; vsnprintf errors or a NULL format will log a small fallback message.

C++ example (stream-style):

#include "rust_backend_ffi.h"

// stream-style; message sent to Rust on destructor
RUST_COUT() << "user=" << user << " authenticated=" << (ok?"yes":"no") << std::flush;

// error example
RUST_CERR() << "authentication failed for user=" << user << std::flush;

C++ notes:

  • RUST_COUT() and RUST_CERR() are thin factories that return a RustLogStream object which buffers via std::ostringstream and sends the accumulated string to rust_log_event_with_level when the temporary is destroyed.
  • The destructor is noexcept and swallow exceptions to avoid crossing FFI boundaries.

Compatibility:

  • The canonical ABI function is rust_log_event_with_level(const char* event, RustLogLevel level) and is implemented in Rust.
  • A legacy rust_log_event(const char* event) wrapper remains and maps to INFO for backward compatibility.
  • Wrappers are header-only and additive; no changes to the Rust backend are required.

Safety

  • Rust panics are contained and never cross FFI.
  • C++ exceptions are caught before returning to PAM.

Extending

Add new subprojects as needed for future business logic or integrations.

Test Application (PAM Client)

This repository includes a test PAM client at tests/pam_test_app.cpp.

Build the test

mkdir -p build && cd build
cmake ..
cmake --build .

The executable will be generated at build/tests/pam_test_app.

Copy the PAM module

After building, copy the PAM module to the system PAM module path:

sudo cp build/pam-module/pam_module.so /lib/security/

On some distributions, use /lib64/security/ instead.

Configure /etc/pam.d service

Create /etc/pam.d/pam_test_app with:

auth required pam_module.so
account required pam_permit.so

You can also pass module arguments which are exposed as argc and argv to pam_sm_authenticate, for example:

auth required pam_module.so debug log_path=/var/log/pam_rust_backend.log
account required pam_permit.so

Run the test client

./tests/pam_test_app pam_test_app <user> <password>

The first argument (pam_test_app) must match the service filename in /etc/pam.d/pam_test_app.

Description
No description provided
Readme 51 KiB
Languages
C++ 35.7%
Rust 27.3%
C 24.1%
CMake 10.3%
Dockerfile 2.6%