blob: 6de6786cd66583637a69c308946048ae3abc3d6c [file] [log] [blame]
#ifndef THIRD_PARTY_GBMCWEB_INCLUDE_PAM_AUTHENTICATE_H_
#define THIRD_PARTY_GBMCWEB_INCLUDE_PAM_AUTHENTICATE_H_
#include <security/_pam_types.h>
#include <security/pam_appl.h>
#include <cstdlib>
#include <cstring>
#include <string>
#include <string_view>
#include "boost/utility/string_view.hpp" // NOLINT
// function used to get user input
inline int pamFunctionConversation(int numMsg, const struct pam_message** msg,
struct pam_response** resp,
void* appdataPtr) {
if (appdataPtr == nullptr) {
return PAM_CONV_ERR;
}
if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG) {
return PAM_CONV_ERR;
}
for (int i = 0; i < numMsg; ++i) {
/* Ignore all PAM messages except prompting for hidden input */
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) {
continue;
}
/* Assume PAM is only prompting for the password as hidden input */
/* Allocate memory only when PAM_PROMPT_ECHO_OFF is encountered */
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
char* app_pass = reinterpret_cast<char*>(appdataPtr);
size_t app_pass_size = std::strlen(app_pass);
if ((app_pass_size + 1) > PAM_MAX_RESP_SIZE) {
return PAM_CONV_ERR;
}
// IDeally we'd like to avoid using malloc here, but because we're
// passing off ownership of this to a C application, there aren't a lot
// of sane ways to avoid it.
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)'
void* pass_ptr = malloc(app_pass_size + 1);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
char* pass = reinterpret_cast<char*>(pass_ptr);
if (pass == nullptr) {
return PAM_BUF_ERR;
}
std::strncpy(pass, app_pass, app_pass_size + 1);
size_t num_msg_size = static_cast<size_t>(numMsg);
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
void* ptr = calloc(num_msg_size, sizeof(struct pam_response));
if (ptr == nullptr) {
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
free(pass);
return PAM_BUF_ERR;
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
*resp = reinterpret_cast<pam_response*>(ptr);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
resp[i]->resp = pass;
return PAM_SUCCESS;
}
return PAM_CONV_ERR;
}
/**
* @brief Attempt username/password authentication via PAM.
* @param username The provided username aka account name.
* @param password The provided password.
* @returns PAM error code or PAM_SUCCESS for success. */
inline int pamAuthenticateUser(std::string_view username,
std::string_view password) {
std::string user_str(username);
std::string pass_str(password);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
char* pass_str_no_const = const_cast<char*>(pass_str.c_str());
const struct pam_conv local_conversation = {pamFunctionConversation,
pass_str_no_const};
pam_handle_t* local_auth_handle = nullptr; // this gets set by pam_start
int retval = pam_start("webserver", user_str.c_str(), &local_conversation,
&local_auth_handle);
if (retval != PAM_SUCCESS) {
return retval;
}
retval = pam_authenticate(local_auth_handle,
PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
if (retval != PAM_SUCCESS) {
pam_end(local_auth_handle, PAM_SUCCESS); // ignore retval
return retval;
}
/* check that the account is healthy */
retval = pam_acct_mgmt(local_auth_handle, PAM_DISALLOW_NULL_AUTHTOK);
if (retval != PAM_SUCCESS) {
pam_end(local_auth_handle, PAM_SUCCESS); // ignore retval
return retval;
}
return pam_end(local_auth_handle, PAM_SUCCESS);
}
inline int pamUpdatePassword(const std::string& username,
const std::string& password) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
char* pass_str_no_const = const_cast<char*>(password.c_str());
const struct pam_conv local_conversation = {pamFunctionConversation,
pass_str_no_const};
pam_handle_t* local_auth_handle = nullptr; // this gets set by pam_start
int retval = pam_start("webserver", username.c_str(), &local_conversation,
&local_auth_handle);
if (retval != PAM_SUCCESS) {
return retval;
}
retval = pam_chauthtok(local_auth_handle, PAM_SILENT);
if (retval != PAM_SUCCESS) {
pam_end(local_auth_handle, PAM_SUCCESS);
return retval;
}
return pam_end(local_auth_handle, PAM_SUCCESS);
}
#endif // THIRD_PARTY_GBMCWEB_INCLUDE_PAM_AUTHENTICATE_H_