initial commit: WIP debugging PAM module

This commit is contained in:
2026-03-16 11:59:16 +11:00
commit 1d3eaff622
20 changed files with 699 additions and 0 deletions

16
rust-backend/Cargo.lock generated Normal file
View File

@@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "rust-backend"
version = "0.1.0"
dependencies = [
"once_cell",
]

16
rust-backend/Cargo.toml Normal file
View File

@@ -0,0 +1,16 @@
[package]
name = "rust-backend"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["staticlib"]
[dependencies]
once_cell = "1.18"
[profile.release]
panic = "unwind"
[profile.dev]
panic = "unwind"

14
rust-backend/src/auth.rs Normal file
View File

@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Suyono
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
pub fn authenticate(user: &str, password: &str) -> Result<(), ()> {
// Stub: always fail if user == "fail", else succeed
if user == "fail" {
Err(())
} else {
Ok(())
}
}

10
rust-backend/src/error.rs Normal file
View File

@@ -0,0 +1,10 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Suyono
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
pub const SUCCESS: i32 = 0;
pub const ERR_INVALID_INPUT: i32 = -1;
pub const ERR_AUTH_FAILED: i32 = -2;
pub const ERR_PANIC: i32 = -99;

62
rust-backend/src/lib.rs Normal file
View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Suyono
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::panic::{catch_unwind, AssertUnwindSafe};
mod auth;
mod logging;
mod error;
#[no_mangle]
pub extern "C" fn rust_init_logging(log_path: *const c_char) {
let _ = catch_unwind(AssertUnwindSafe(|| {
let path = unsafe {
if log_path.is_null() {
"/var/log/pam_rust_backend.log"
} else {
CStr::from_ptr(log_path).to_str().unwrap_or("/var/log/pam_rust_backend.log")
}
};
logging::init_logger(path);
}));
}
#[no_mangle]
pub extern "C" fn rust_log_event(event: *const c_char) {
let _ = catch_unwind(AssertUnwindSafe(|| {
let msg = unsafe {
if event.is_null() {
return;
}
CStr::from_ptr(event).to_str().unwrap_or("")
};
logging::log_event(msg);
}));
}
#[no_mangle]
pub extern "C" fn rust_auth_user(user: *const c_char, password: *const c_char) -> i32 {
catch_unwind(AssertUnwindSafe(|| {
let u = unsafe {
if user.is_null() {
return error::ERR_INVALID_INPUT;
}
CStr::from_ptr(user).to_str().unwrap_or("")
};
let p = unsafe {
if password.is_null() {
return error::ERR_INVALID_INPUT;
}
CStr::from_ptr(password).to_str().unwrap_or("")
};
match auth::authenticate(u, p) {
Ok(_) => error::SUCCESS,
Err(_) => error::ERR_AUTH_FAILED,
}
})).unwrap_or(error::ERR_PANIC)
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Suyono
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
use std::fs::{OpenOptions, File};
use std::io::Write;
use std::sync::Mutex;
use once_cell::sync::OnceCell;
static LOGGER: OnceCell<Mutex<File>> = OnceCell::new();
pub fn init_logger(path: &str) {
if LOGGER.get().is_some() {
// Already initialized, do nothing
return;
}
let file = OpenOptions::new()
.create(true)
.append(true)
.open(path)
.expect("Failed to open log file");
LOGGER.set(Mutex::new(file)).ok();
}
pub fn log_event(event: &str) {
if let Some(logger) = LOGGER.get() {
let mut file = logger.lock().unwrap();
writeln!(file, "{}", event).ok();
}
}