125 lines
4.8 KiB
C++
125 lines
4.8 KiB
C++
#include <security/pam_appl.h>
|
|
#include <security/pam_client.h>
|
|
#include <security/pam_ext.h>
|
|
#include <security/pam_misc.h>
|
|
#include <security/pam_modules.h>
|
|
#include <syslog.h>
|
|
|
|
#include <rublon/rublon.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, [[maybe_unused]] int flags, [[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
|
|
using namespace rublon;
|
|
|
|
LinuxPam pam{pamh};
|
|
|
|
RublonLinux rublon{pam};
|
|
|
|
auto rublonConfig = ConfigurationFactory{}.systemConfig();
|
|
if(not rublonConfig.has_value()) {
|
|
pam.print("\n");
|
|
pam.print("Rublon configuration does not exists or is invalid");
|
|
pam.print("\tcheck '%s' for more details\n", details::logPath());
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
RublonMemory mem;
|
|
|
|
CoreHandler CH{rublonConfig.value()};
|
|
|
|
auto selectMethod = [&](const MethodSelect & selector) { return selector.create(pam); };
|
|
auto confirmMethod = [&](const PostMethod & confirm) { return confirm.fire(CH); };
|
|
auto confirmCode = [&](const MethodProxy & method) { return method.fire(CH, pam); };
|
|
|
|
auto printAuthMessageAndExit = [&](const AuthenticationStatus status) {
|
|
switch(status.action()) {
|
|
case AuthenticationStatus::Action::Bypass:
|
|
pam.print("\n\tRUBLON authentication bypased");
|
|
return PAM_SUCCESS;
|
|
|
|
case AuthenticationStatus::Action::Denied:
|
|
pam.print("\n\tRUBLON authentication FAILED");
|
|
return PAM_MAXTRIES;
|
|
|
|
case AuthenticationStatus::Action::Confirmed:
|
|
pam.print("\n\tRUBLON authentication SUCCESS");
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
pam.print("RUBLON connector has exited with unknown code, access DENY!\n");
|
|
return PAM_MAXTRIES;
|
|
};
|
|
|
|
auto allowLogin = [&](const AuthenticationStatus & status) -> tl::expected< int, Error > {
|
|
return printAuthMessageAndExit(status);
|
|
};
|
|
|
|
auto mapError = [&](const Error & error) -> tl::expected< int, Error > {
|
|
log(LogLevel::Error, "Authorization interrupted with {%s::%s}", error.errorClassName(), error.categoryName());
|
|
if(error.is< RublonAuthenticationInterrupt >()) {
|
|
switch(error.get< RublonAuthenticationInterrupt >().errorClass) {
|
|
case RublonAuthenticationInterrupt::ErrorClass::UserBaypass:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
|
case RublonAuthenticationInterrupt::ErrorClass::UserDenied:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Denied);
|
|
case RublonAuthenticationInterrupt::ErrorClass::UserPending:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
|
}
|
|
}
|
|
|
|
if(error.is< MethodError >()) {
|
|
switch(error.get< MethodError >().errorClass) {
|
|
case MethodError::ErrorClass::BadMethod:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Denied);
|
|
case MethodError::ErrorClass::BadUserInput:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Denied);
|
|
case MethodError::ErrorClass::NoMethodAvailable:
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
|
}
|
|
}
|
|
|
|
|
|
if(error.is< ConnectionError >()) {
|
|
if(rublonConfig->bypass) {
|
|
pam.print("Connection Error, bypass enabled");
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass);
|
|
} else {
|
|
pam.print("Connection Error, bypass disabled");
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Denied);
|
|
}
|
|
}
|
|
|
|
if(error.is< CoreHandlerError >()) {
|
|
pam.print("\n RUBLON server returned '%s' exception", error.get< CoreHandlerError >().reson.c_str());
|
|
}
|
|
|
|
return printAuthMessageAndExit(AuthenticationStatus::Action::Denied);
|
|
};
|
|
|
|
auto ret = Init{rublonConfig.value()}
|
|
.fire(CH, pam) //
|
|
.and_then(selectMethod)
|
|
.and_then(confirmMethod)
|
|
.and_then(confirmCode)
|
|
.and_then(allowLogin)
|
|
.or_else(mapError);
|
|
|
|
return ret.value_or(PAM_MAXTRIES);
|
|
}
|