pam_authenticate.hpp (05ecd3a9a2bb7d63470a183e23b3a158572003f4) | pam_authenticate.hpp (2ccce1f3a04ab72824820a6795878ce01f37a22c) |
---|---|
1#pragma once 2 3#include <security/pam_appl.h> 4 5#include <cstring> 6#include <memory> 7#include <span> 8#include <string_view> 9 | 1#pragma once 2 3#include <security/pam_appl.h> 4 5#include <cstring> 6#include <memory> 7#include <span> 8#include <string_view> 9 |
10struct PasswordData 11{ 12 std::string password; 13 std::optional<std::string> token; 14}; 15 |
|
10// function used to get user input 11inline int pamFunctionConversation(int numMsg, const struct pam_message** msgs, 12 struct pam_response** resp, void* appdataPtr) 13{ 14 if ((appdataPtr == nullptr) || (msgs == nullptr) || (resp == nullptr)) 15 { 16 return PAM_CONV_ERR; 17 } 18 19 if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG) 20 { 21 return PAM_CONV_ERR; 22 } | 16// function used to get user input 17inline int pamFunctionConversation(int numMsg, const struct pam_message** msgs, 18 struct pam_response** resp, void* appdataPtr) 19{ 20 if ((appdataPtr == nullptr) || (msgs == nullptr) || (resp == nullptr)) 21 { 22 return PAM_CONV_ERR; 23 } 24 25 if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG) 26 { 27 return PAM_CONV_ERR; 28 } |
29 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) 30 PasswordData* appPass = reinterpret_cast<PasswordData*>(appdataPtr); |
|
23 auto msgCount = static_cast<size_t>(numMsg); | 31 auto msgCount = static_cast<size_t>(numMsg); |
24 | |
25 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) 26 auto responseArrPtr = std::make_unique<pam_response[]>(msgCount); 27 auto responses = std::span(responseArrPtr.get(), msgCount); 28 auto messagePtrs = std::span(msgs, msgCount); 29 for (size_t i = 0; i < msgCount; ++i) 30 { 31 const pam_message& msg = *(messagePtrs[i]); 32 33 pam_response& response = responses[i]; 34 response.resp_retcode = 0; 35 response.resp = nullptr; 36 37 switch (msg.msg_style) 38 { 39 case PAM_PROMPT_ECHO_ON: 40 break; 41 case PAM_PROMPT_ECHO_OFF: 42 { 43 // Assume PAM is only prompting for the password as hidden input | 32 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) 33 auto responseArrPtr = std::make_unique<pam_response[]>(msgCount); 34 auto responses = std::span(responseArrPtr.get(), msgCount); 35 auto messagePtrs = std::span(msgs, msgCount); 36 for (size_t i = 0; i < msgCount; ++i) 37 { 38 const pam_message& msg = *(messagePtrs[i]); 39 40 pam_response& response = responses[i]; 41 response.resp_retcode = 0; 42 response.resp = nullptr; 43 44 switch (msg.msg_style) 45 { 46 case PAM_PROMPT_ECHO_ON: 47 break; 48 case PAM_PROMPT_ECHO_OFF: 49 { 50 // Assume PAM is only prompting for the password as hidden input |
44 // Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred 45 char* appPass = static_cast<char*>(appdataPtr); 46 size_t appPassSize = std::strlen(appPass); 47 | 51 // Allocate memory only when PAM_PROMPT_ECHO_OFF is encountered 52 size_t appPassSize = appPass->password.size(); |
48 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE) 49 { 50 return PAM_CONV_ERR; 51 } | 53 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE) 54 { 55 return PAM_CONV_ERR; 56 } |
52 // Create an array for pam to own 53 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) 54 auto passPtr = std::make_unique<char[]>(appPassSize + 1); 55 std::strncpy(passPtr.get(), appPass, appPassSize + 1); 56 57 responses[i].resp = passPtr.release(); | 57 std::string_view message(msg.msg); 58 constexpr std::string_view passwordPrompt = "Password: "; 59 // String used by Google authenticator to ask for one time code 60 constexpr std::string_view totpPrompt = "Verification code: "; 61 if (message.starts_with(passwordPrompt)) 62 { 63 response.resp = 64 strdup(appPass->password.c_str()); // Password input 65 } 66 else if (message.starts_with(totpPrompt)) 67 { 68 if (!appPass->token) 69 { 70 return PAM_CONV_ERR; 71 } 72 response.resp = 73 strdup(appPass->token->c_str()); // TOTP input 74 } 75 else 76 { 77 return PAM_CONV_ERR; 78 } |
58 } 59 break; 60 case PAM_ERROR_MSG: 61 BMCWEB_LOG_ERROR("Pam error {}", msg.msg); 62 break; 63 case PAM_TEXT_INFO: 64 BMCWEB_LOG_ERROR("Pam info {}", msg.msg); 65 break; --- 5 unchanged lines hidden (view full) --- 71 *resp = responseArrPtr.release(); 72 return PAM_SUCCESS; 73} 74 75/** 76 * @brief Attempt username/password authentication via PAM. 77 * @param username The provided username aka account name. 78 * @param password The provided password. | 79 } 80 break; 81 case PAM_ERROR_MSG: 82 BMCWEB_LOG_ERROR("Pam error {}", msg.msg); 83 break; 84 case PAM_TEXT_INFO: 85 BMCWEB_LOG_ERROR("Pam info {}", msg.msg); 86 break; --- 5 unchanged lines hidden (view full) --- 92 *resp = responseArrPtr.release(); 93 return PAM_SUCCESS; 94} 95 96/** 97 * @brief Attempt username/password authentication via PAM. 98 * @param username The provided username aka account name. 99 * @param password The provided password. |
100 * @param token The provided MFA token. |
|
79 * @returns PAM error code or PAM_SUCCESS for success. */ 80inline int pamAuthenticateUser(std::string_view username, | 101 * @returns PAM error code or PAM_SUCCESS for success. */ 102inline int pamAuthenticateUser(std::string_view username, |
81 std::string_view password) | 103 std::string_view password, 104 std::optional<std::string> token) |
82{ 83 std::string userStr(username); | 105{ 106 std::string userStr(username); |
84 std::string passStr(password); 85 86 char* passStrNoConst = passStr.data(); 87 const struct pam_conv localConversation = {pamFunctionConversation, 88 passStrNoConst}; | 107 PasswordData data{std::string(password), std::move(token)}; 108 const struct pam_conv localConversation = {pamFunctionConversation, &data}; |
89 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start 90 91 int retval = pam_start("webserver", userStr.c_str(), &localConversation, 92 &localAuthHandle); 93 if (retval != PAM_SUCCESS) 94 { 95 return retval; 96 } --- 46 unchanged lines hidden --- | 109 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start 110 111 int retval = pam_start("webserver", userStr.c_str(), &localConversation, 112 &localAuthHandle); 113 if (retval != PAM_SUCCESS) 114 { 115 return retval; 116 } --- 46 unchanged lines hidden --- |