#include #include #include #include #include #include #include #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; // std::freopen(rublon::details::logPath(), "a+", stdout); LinuxPam pam{pamh}; // std::freopen(rublon::details::logPath(), "a+", stderr); auto config = ConfigurationFactory{}.systemConfig(); if(not config.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; } std::byte sharedMemory[32 * 1024] = {}; std::pmr::monotonic_buffer_resource mr{sharedMemory, std::size(sharedMemory)}; std::pmr::unsynchronized_pool_resource rublonPoolResource{&mr}; std::pmr::set_default_resource(&rublonPoolResource); CoreHandler CH{*config}; 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(config->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 >()) { const auto &reson = error.get< CoreHandlerError >().reson; pam.print("\n RUBLON server returned '%s' exception", reson.c_str()); if(reson == "UserBypassedException" or reson == "UserNotFoundException") return printAuthMessageAndExit(AuthenticationStatus::Action::Bypass); } return printAuthMessageAndExit(AuthenticationStatus::Action::Denied); }; auto ret = Init{config.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); }