127 lines
3.8 KiB
Markdown
127 lines
3.8 KiB
Markdown
# 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
|
|
```bash
|
|
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):
|
|
|
|
```c
|
|
#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):
|
|
|
|
```cpp
|
|
#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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```conf
|
|
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:
|
|
|
|
```conf
|
|
auth required pam_module.so debug log_path=/var/log/pam_rust_backend.log
|
|
account required pam_permit.so
|
|
```
|
|
|
|
### Run the test client
|
|
|
|
```bash
|
|
./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`.
|