rublon-ssh/PAM/ssh/lib/pam.cpp
rublon-bwi 351964199a
Bwi/v2.3.2 (#19)
* Prevent printing in noninteractive mode

* Allow PAM modules to be configurated directly in pam.d

* Configuration should be redable by everybody

* Add a way to read ip address in when no IP is awailable

* Enable read ip from pam

* Fix veritas BUG
2025-09-11 10:35:22 +02:00

112 lines
3.8 KiB
C++

#include <rublon/check_application.hpp>
#include <rublon/error.hpp>
#include <rublon/error_handler.hpp>
#include <rublon/finish.hpp>
#include <rublon/rublon.hpp>
#include <rublon/utils.hpp>
#define DLL_PUBLIC __attribute__((visibility("default")))
DLL_PUBLIC int pam_sm_setcred([[maybe_unused]] pam_handle_t * pamh,
[[maybe_unused]] int flags,
[[maybe_unused]] int argc,
[[maybe_unused]] const char ** argv) {
return PAM_SUCCESS;
}
DLL_PUBLIC int pam_sm_acct_mgmt([[maybe_unused]] pam_handle_t * pamh,
[[maybe_unused]] int flags,
[[maybe_unused]] int argc,
[[maybe_unused]] const char ** argv) {
return PAM_SUCCESS;
}
DLL_PUBLIC int
pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char ** argv) {
using namespace rublon;
details::initLog();
LinuxPam pam{pamh};
log(LogLevel::Info, "user '%s' authentication attempt", pam.username().get());
auto printAuthMessageAndExit = [&](const AuthenticationStatus status) {
switch(status.action()) {
case AuthenticationStatus::Action::Bypass:
log(LogLevel::Info, "user '%s' authentication BYPASSED", pam.username().get());
pam.print("RUBLON authentication BYPASSED");
return PAM_SUCCESS;
case AuthenticationStatus::Action::Denied:
log(LogLevel::Info, "user '%s' authentication FAILED", pam.username().get());
pam.print("RUBLON authentication FAILED");
return PAM_MAXTRIES;
case AuthenticationStatus::Action::Confirmed:
log(LogLevel::Info, "user '%s' authentication SUCCEEDED", pam.username().get());
pam.print("RUBLON authentication SUCCEEDED");
return PAM_SUCCESS;
}
pam.print("RUBLON connector has exited with unknown code, access DENY!\n");
return PAM_MAXTRIES;
};
Session session{pam};
auto ok = rublon::RublonFactory{}.initializeSession(session, flags, argc, argv);
if(not ok.has_value()) {
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
}
if(!session.config().logging) {
g_level = LogLevel::Warning;
}
CoreHandler_t CH{session.config()};
auto selectMethod = [&](const MethodSelect & selector) { //
return selector.create(pam);
};
auto confirmMethod = [&](const PostMethod & postMethod) { //
return postMethod.handle(CH);
};
auto confirmCode = [&](const MethodProxy & method) mutable { //
return method.fire(session, CH, pam);
};
auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > {
if(status.userAuthorized()) {
Finish{session, status.accessToken()}.handle(CH);
}
return status;
};
auto allowLogin = [&](const AuthenticationStatus & status) -> tl::expected< int, Error > { //
return printAuthMessageAndExit(status);
};
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
return printAuthMessageAndExit(rublon::ErrorHandler{pam, session.config()}.printErrorDetails(error));
};
{
CheckApplication ca{session};
const auto ret = ca.call(CH, session.config().systemToken).or_else(mapError);
if(not ret.has_value()) {
log(LogLevel::Error, "Check Application step failed, check configration");
return PAM_MAXTRIES;
}
}
auto ret = Init{session}
.handle(CH, pam) //
.and_then(selectMethod)
.and_then(confirmMethod)
.and_then(confirmCode)
.and_then(finalizeTransaction)
.and_then(allowLogin)
.or_else(mapError);
return ret.value_or(PAM_MAXTRIES);
}