Compare commits
3 Commits
1d3eaff622
...
793a643731
| Author | SHA1 | Date | |
|---|---|---|---|
| 793a643731 | |||
| bdbd94eda2 | |||
| 2b3fe0630f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
/.vscode/settings.json
|
||||||
build/
|
build/
|
||||||
rust-backend/target/
|
rust-backend/target/
|
||||||
pam-module/*.so
|
pam-module/*.so
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -26,6 +26,50 @@ Copy the built PAM module to `/lib/security/` or `/lib64/security/` as needed.
|
|||||||
## Logging
|
## Logging
|
||||||
Rust backend logs to `/var/log/pam_rust_backend.log` by default.
|
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
|
## Safety
|
||||||
- Rust panics are contained and never cross FFI.
|
- Rust panics are contained and never cross FFI.
|
||||||
- C++ exceptions are caught before returning to PAM.
|
- C++ exceptions are caught before returning to PAM.
|
||||||
|
|||||||
@@ -23,3 +23,15 @@ target_link_libraries(pam_usercontainer PRIVATE ${RUST_STATICLIB})
|
|||||||
|
|
||||||
# Install target
|
# Install target
|
||||||
install(TARGETS pam_usercontainer DESTINATION lib/security)
|
install(TARGETS pam_usercontainer DESTINATION lib/security)
|
||||||
|
|
||||||
|
# Examples: small programs demonstrating logging wrappers
|
||||||
|
set_source_files_properties(examples/logging_example.c PROPERTIES LANGUAGE CXX)
|
||||||
|
add_executable(logging_example_c examples/logging_example.c)
|
||||||
|
target_include_directories(logging_example_c PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
add_dependencies(logging_example_c rust_backend_build)
|
||||||
|
target_link_libraries(logging_example_c PRIVATE ${RUST_STATICLIB})
|
||||||
|
|
||||||
|
add_executable(logging_example_cpp examples/logging_example.cpp)
|
||||||
|
target_include_directories(logging_example_cpp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
add_dependencies(logging_example_cpp rust_backend_build)
|
||||||
|
target_link_libraries(logging_example_cpp PRIVATE ${RUST_STATICLIB})
|
||||||
|
|||||||
18
pam-module/examples/logging_example.c
Normal file
18
pam-module/examples/logging_example.c
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// C example demonstrating printf-style Rust logging wrapper
|
||||||
|
|
||||||
|
#include "../include/rust_backend_ffi.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
(void)argc; (void)argv;
|
||||||
|
// Ensure logger is initialized (nullptr -> default path)
|
||||||
|
rust_init_logging(NULL);
|
||||||
|
|
||||||
|
const char* user = "alice";
|
||||||
|
int result = 0; // pretend success
|
||||||
|
|
||||||
|
RUST_LOGF_INFO("C example: user=%s authenticated=%d", user, result);
|
||||||
|
RUST_LOGF_DEBUG("C example: debug details: x=%d y=%d", 10, 20);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
17
pam-module/examples/logging_example.cpp
Normal file
17
pam-module/examples/logging_example.cpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// C++ example demonstrating stream-style Rust logging wrapper
|
||||||
|
|
||||||
|
#include "../include/rust_backend_ffi.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
rust_init_logging(nullptr);
|
||||||
|
|
||||||
|
std::string user = "bob";
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
RUST_COUT() << "C++ example: user=" << user << " authenticated=" << (ok?"yes":"no") << std::flush;
|
||||||
|
RUST_CERR() << "C++ example: an error message for user=" << user << std::flush;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -6,6 +6,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Log level constants shared between C/C++ and Rust
|
||||||
|
typedef enum {
|
||||||
|
RUST_LOG_LEVEL_FATAL = 0,
|
||||||
|
RUST_LOG_LEVEL_ERROR = 1,
|
||||||
|
RUST_LOG_LEVEL_WARN = 2,
|
||||||
|
RUST_LOG_LEVEL_INFO = 3,
|
||||||
|
RUST_LOG_LEVEL_DEBUG = 4,
|
||||||
|
RUST_LOG_LEVEL_TRACE = 5,
|
||||||
|
} RustLogLevel;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -16,9 +26,27 @@ void rust_init_logging(const char* log_path);
|
|||||||
// Authenticate user (stub)
|
// Authenticate user (stub)
|
||||||
int rust_auth_user(const char* user, const char* password);
|
int rust_auth_user(const char* user, const char* password);
|
||||||
|
|
||||||
// Log event (file sink)
|
// Legacy: Log event (file sink) — forwards to INFO level on Rust side
|
||||||
void rust_log_event(const char* event);
|
void rust_log_event(const char* event);
|
||||||
|
|
||||||
|
// New: Log event with explicit level
|
||||||
|
void rust_log_event_with_level(const char* event, RustLogLevel level);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Convenience macros for C/C++ callers
|
||||||
|
#define RUST_LOG_FATAL(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_FATAL)
|
||||||
|
#define RUST_LOG_ERROR(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_ERROR)
|
||||||
|
#define RUST_LOG_WARN(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_WARN)
|
||||||
|
#define RUST_LOG_INFO(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_INFO)
|
||||||
|
#define RUST_LOG_DEBUG(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_DEBUG)
|
||||||
|
#define RUST_LOG_TRACE(msg) rust_log_event_with_level((msg), RUST_LOG_LEVEL_TRACE)
|
||||||
|
|
||||||
|
// C wrapper: printf-style helpers (header-only)
|
||||||
|
#include "rust_backend_logging_c.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include "rust_backend_logging_cpp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|||||||
74
pam-module/include/rust_backend_logging_c.h
Normal file
74
pam-module/include/rust_backend_logging_c.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// C printf-style wrappers for Rust logging FFI
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "rust_backend_ffi.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Buffer size for formatted messages. Documented truncation behavior.
|
||||||
|
#define RUST_LOG_FMT_BUFSZ 2048
|
||||||
|
|
||||||
|
static inline void rust_log_vprintf_level(RustLogLevel level, const char* fmt, va_list ap) {
|
||||||
|
if (fmt == NULL) {
|
||||||
|
rust_log_event_with_level("(null format)", level);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char buf[RUST_LOG_FMT_BUFSZ];
|
||||||
|
int ret = vsnprintf(buf, RUST_LOG_FMT_BUFSZ, fmt, ap);
|
||||||
|
if (ret < 0) {
|
||||||
|
rust_log_event_with_level("(format error)", level);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// vsnprintf guarantees NUL-termination as long as size>0
|
||||||
|
buf[RUST_LOG_FMT_BUFSZ - 1] = '\0';
|
||||||
|
rust_log_event_with_level(buf, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void rust_log_printf_level(RustLogLevel level, const char* fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
rust_log_vprintf_level(level, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience per-level functions
|
||||||
|
static inline void rust_logf_fatal(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_FATAL, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
static inline void rust_logf_error(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_ERROR, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
static inline void rust_logf_warn(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_WARN, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
static inline void rust_logf_info(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_INFO, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
static inline void rust_logf_debug(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_DEBUG, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
static inline void rust_logf_trace(const char* fmt, ...) {
|
||||||
|
va_list ap; va_start(ap, fmt); rust_log_vprintf_level(RUST_LOG_LEVEL_TRACE, fmt, ap); va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience macros for C/C++ callers (variadic macro)
|
||||||
|
// Support both C99 and C++ compilers that support variadic macros
|
||||||
|
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus)
|
||||||
|
#define RUST_LOGF_FATAL(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_FATAL, (fmt), ##__VA_ARGS__)
|
||||||
|
#define RUST_LOGF_ERROR(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_ERROR, (fmt), ##__VA_ARGS__)
|
||||||
|
#define RUST_LOGF_WARN(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_WARN, (fmt), ##__VA_ARGS__)
|
||||||
|
#define RUST_LOGF_INFO(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_INFO, (fmt), ##__VA_ARGS__)
|
||||||
|
#define RUST_LOGF_DEBUG(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_DEBUG, (fmt), ##__VA_ARGS__)
|
||||||
|
#define RUST_LOGF_TRACE(fmt, ...) rust_log_printf_level(RUST_LOG_LEVEL_TRACE, (fmt), ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
75
pam-module/include/rust_backend_logging_cpp.h
Normal file
75
pam-module/include/rust_backend_logging_cpp.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// C++ stream-style wrappers for Rust logging FFI
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// This header expects `rust_backend_ffi.h` to have been included first
|
||||||
|
// so that `RustLogLevel` and `rust_log_event_with_level` are available.
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
class RustLogStream {
|
||||||
|
public:
|
||||||
|
explicit RustLogStream(RustLogLevel level) noexcept : level_(level) {}
|
||||||
|
|
||||||
|
// Generic stream insertion
|
||||||
|
template<typename T>
|
||||||
|
RustLogStream& operator<<(const T& v) {
|
||||||
|
try {
|
||||||
|
oss_ << v;
|
||||||
|
} catch (...) {
|
||||||
|
// swallow; avoid exceptions crossing FFI
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support manipulators like std::endl
|
||||||
|
RustLogStream& operator<<(std::ostream& (*manip)(std::ostream&)) {
|
||||||
|
try {
|
||||||
|
manip(oss_);
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor emits buffered message
|
||||||
|
~RustLogStream() noexcept {
|
||||||
|
try {
|
||||||
|
const std::string s = oss_.str();
|
||||||
|
if (!s.empty()) {
|
||||||
|
rust_log_event_with_level(s.c_str(), level_);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
// never throw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-copyable
|
||||||
|
RustLogStream(const RustLogStream&) = delete;
|
||||||
|
RustLogStream& operator=(const RustLogStream&) = delete;
|
||||||
|
|
||||||
|
// Movable
|
||||||
|
RustLogStream(RustLogStream&&) = default;
|
||||||
|
RustLogStream& operator=(RustLogStream&&) = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RustLogLevel level_;
|
||||||
|
std::ostringstream oss_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Factories and macros
|
||||||
|
inline RustLogStream rust_log_info_stream() { return RustLogStream(RUST_LOG_LEVEL_INFO); }
|
||||||
|
inline RustLogStream rust_log_warn_stream() { return RustLogStream(RUST_LOG_LEVEL_WARN); }
|
||||||
|
inline RustLogStream rust_log_error_stream() { return RustLogStream(RUST_LOG_LEVEL_ERROR); }
|
||||||
|
inline RustLogStream rust_log_debug_stream() { return RustLogStream(RUST_LOG_LEVEL_DEBUG); }
|
||||||
|
inline RustLogStream rust_log_trace_stream() { return RustLogStream(RUST_LOG_LEVEL_TRACE); }
|
||||||
|
inline RustLogStream rust_log_fatal_stream() { return RustLogStream(RUST_LOG_LEVEL_FATAL); }
|
||||||
|
|
||||||
|
#define RUST_COUT() rust_log_info_stream()
|
||||||
|
#define RUST_CERR() rust_log_error_stream()
|
||||||
|
#define RUST_CDEBUG() rust_log_debug_stream()
|
||||||
|
|
||||||
|
// Usage example:
|
||||||
|
// RUST_COUT() << "User=" << user << " logged in" << std::endl;
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <security/pam_appl.h>
|
#include <security/pam_appl.h>
|
||||||
#include <security/pam_modules.h>
|
#include <security/pam_modules.h>
|
||||||
|
#include <security/pam_ext.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "rust_backend_ffi.h"
|
#include "rust_backend_ffi.h"
|
||||||
#include "auth_client.h"
|
#include "auth_client.h"
|
||||||
@@ -15,14 +16,24 @@ extern "C" {
|
|||||||
int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv) {
|
int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char** argv) {
|
||||||
try {
|
try {
|
||||||
rust_init_logging(nullptr); // Ensure logger is initialized
|
rust_init_logging(nullptr); // Ensure logger is initialized
|
||||||
rust_log_event("PAM authentication attempt");
|
RUST_CDEBUG() << "PAM authentication attempt" << std::flush;
|
||||||
|
|
||||||
|
|
||||||
const char* user = nullptr;
|
const char* user = nullptr;
|
||||||
pam_get_user(pamh, &user, NULL);
|
int rc = pam_get_user(pamh, &user, nullptr);
|
||||||
const void* pw_ptr = nullptr;
|
if (rc != PAM_SUCCESS || user == nullptr) {
|
||||||
int item_result = pam_get_item(pamh, PAM_AUTHTOK, &pw_ptr);
|
RUST_CERR() << "Failed to get username: " << pam_strerror(pamh, rc) << std::flush;
|
||||||
const char* password = (item_result == PAM_SUCCESS && pw_ptr) ? static_cast<const char*>(pw_ptr) : nullptr;
|
return PAM_AUTH_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* password = nullptr;
|
||||||
|
rc = pam_get_authtok(pamh, PAM_AUTHTOK, &password, nullptr);
|
||||||
|
if (rc != PAM_SUCCESS || password == nullptr) {
|
||||||
|
RUST_CERR() << "Failed to get password: " << pam_strerror(pamh, rc) << std::flush;
|
||||||
|
return PAM_AUTH_ERR;
|
||||||
|
}
|
||||||
|
RUST_CDEBUG() << "Extracted credentials: user='" << (user ? user : "(null)") << "' password='" << (password ? "(redacted)" : "(null)") << "'" << std::flush;
|
||||||
|
|
||||||
int result = auth_client_authenticate(user, password);
|
int result = auth_client_authenticate(user, password);
|
||||||
return result;
|
return result;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|||||||
@@ -4,9 +4,24 @@
|
|||||||
// you may not use this file except in compliance with 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
|
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::CStr;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
// Formatting macros for crate-local logging.
|
||||||
|
// Define these in the crate root so any module can invoke them as `crate::log!(...)`.
|
||||||
|
macro_rules! pam_log_with_level {
|
||||||
|
($level:expr, $($arg:tt)+) => {
|
||||||
|
crate::logging::log_event_with_level($level, &format!($($arg)+));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! pam_log {
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
crate::logging::log_event_with_level(crate::logging::LogLevel::Info, &format!($($arg)+));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
mod logging;
|
mod logging;
|
||||||
@@ -15,14 +30,19 @@ mod error;
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_init_logging(log_path: *const c_char) {
|
pub extern "C" fn rust_init_logging(log_path: *const c_char) {
|
||||||
let _ = catch_unwind(AssertUnwindSafe(|| {
|
let _ = catch_unwind(AssertUnwindSafe(|| {
|
||||||
let path = unsafe {
|
let env_path = env::var("PAM_RUST_LOG_PATH").ok().and_then(|s| if s.is_empty() { None } else { Some(s) });
|
||||||
if log_path.is_null() {
|
let path = if let Some(p) = env_path {
|
||||||
"/var/log/pam_rust_backend.log"
|
p
|
||||||
} else {
|
} else {
|
||||||
CStr::from_ptr(log_path).to_str().unwrap_or("/var/log/pam_rust_backend.log")
|
unsafe {
|
||||||
|
if log_path.is_null() {
|
||||||
|
"/var/log/pam_rust_backend.log".to_string()
|
||||||
|
} else {
|
||||||
|
CStr::from_ptr(log_path).to_str().unwrap_or("/var/log/pam_rust_backend.log").to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
logging::init_logger(path);
|
logging::init_logger(&path);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,25 +55,44 @@ pub extern "C" fn rust_log_event(event: *const c_char) {
|
|||||||
}
|
}
|
||||||
CStr::from_ptr(event).to_str().unwrap_or("")
|
CStr::from_ptr(event).to_str().unwrap_or("")
|
||||||
};
|
};
|
||||||
logging::log_event(msg);
|
// Legacy wrapper: default to INFO
|
||||||
|
pam_log_with_level!(logging::LogLevel::Info, "{}", msg);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_log_event_with_level(event: *const c_char, level: i32) {
|
||||||
|
let _ = catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
let msg = unsafe {
|
||||||
|
if event.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CStr::from_ptr(event).to_str().unwrap_or("")
|
||||||
|
};
|
||||||
|
let lvl = logging::LogLevel::from(level);
|
||||||
|
pam_log_with_level!(lvl, "{}", msg);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_auth_user(user: *const c_char, password: *const c_char) -> i32 {
|
pub extern "C" fn rust_auth_user(user: *const c_char, password: *const c_char) -> i32 {
|
||||||
catch_unwind(AssertUnwindSafe(|| {
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
|
||||||
let u = unsafe {
|
let u = unsafe {
|
||||||
if user.is_null() {
|
if user.is_null() {
|
||||||
|
pam_log_with_level!(logging::LogLevel::Error, "Null pointer for username"); // Log error
|
||||||
return error::ERR_INVALID_INPUT;
|
return error::ERR_INVALID_INPUT;
|
||||||
}
|
}
|
||||||
CStr::from_ptr(user).to_str().unwrap_or("")
|
CStr::from_ptr(user).to_str().unwrap_or("")
|
||||||
};
|
};
|
||||||
let p = unsafe {
|
let p = unsafe {
|
||||||
if password.is_null() {
|
if password.is_null() {
|
||||||
|
pam_log_with_level!(logging::LogLevel::Error, "Null pointer for password"); // Log error
|
||||||
return error::ERR_INVALID_INPUT;
|
return error::ERR_INVALID_INPUT;
|
||||||
}
|
}
|
||||||
CStr::from_ptr(password).to_str().unwrap_or("")
|
CStr::from_ptr(password).to_str().unwrap_or("")
|
||||||
};
|
};
|
||||||
|
|
||||||
match auth::authenticate(u, p) {
|
match auth::authenticate(u, p) {
|
||||||
Ok(_) => error::SUCCESS,
|
Ok(_) => error::SUCCESS,
|
||||||
Err(_) => error::ERR_AUTH_FAILED,
|
Err(_) => error::ERR_AUTH_FAILED,
|
||||||
|
|||||||
@@ -9,6 +9,50 @@ use std::io::Write;
|
|||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
#[repr(i32)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum LogLevel {
|
||||||
|
Fatal = 0,
|
||||||
|
Error = 1,
|
||||||
|
Warn = 2,
|
||||||
|
Info = 3,
|
||||||
|
Debug = 4,
|
||||||
|
Trace = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogLevel {
|
||||||
|
pub fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
LogLevel::Fatal => "FATAL",
|
||||||
|
LogLevel::Error => "ERROR",
|
||||||
|
LogLevel::Warn => "WARN",
|
||||||
|
LogLevel::Info => "INFO",
|
||||||
|
LogLevel::Debug => "DEBUG",
|
||||||
|
LogLevel::Trace => "TRACE",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for LogLevel {
|
||||||
|
fn from(v: i32) -> Self {
|
||||||
|
match v {
|
||||||
|
0 => LogLevel::Fatal,
|
||||||
|
1 => LogLevel::Error,
|
||||||
|
2 => LogLevel::Warn,
|
||||||
|
3 => LogLevel::Info,
|
||||||
|
4 => LogLevel::Debug,
|
||||||
|
5 => LogLevel::Trace,
|
||||||
|
_ => LogLevel::Info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LogLevel {
|
||||||
|
fn default() -> Self {
|
||||||
|
LogLevel::Info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static LOGGER: OnceCell<Mutex<File>> = OnceCell::new();
|
static LOGGER: OnceCell<Mutex<File>> = OnceCell::new();
|
||||||
|
|
||||||
pub fn init_logger(path: &str) {
|
pub fn init_logger(path: &str) {
|
||||||
@@ -24,9 +68,14 @@ pub fn init_logger(path: &str) {
|
|||||||
LOGGER.set(Mutex::new(file)).ok();
|
LOGGER.set(Mutex::new(file)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_event(event: &str) {
|
pub fn log_event_with_level(level: LogLevel, event: &str) {
|
||||||
if let Some(logger) = LOGGER.get() {
|
if let Some(logger) = LOGGER.get() {
|
||||||
let mut file = logger.lock().unwrap();
|
let mut file = logger.lock().unwrap();
|
||||||
writeln!(file, "{}", event).ok();
|
writeln!(file, "[{}] {}", level.as_str(), event).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backwards-compatible wrapper: default to INFO
|
||||||
|
pub fn log_event(event: &str) {
|
||||||
|
log_event_with_level(LogLevel::Info, event);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user