#include "pam_auth.h" #ifdef ENABLE_PAM_AUTH #include #include #include #include #include #include #endif PamAuth::PamAuth(const std::string& serviceName) : m_serviceName(serviceName) , m_initialized(false) { } PamAuth::~PamAuth() { } bool PamAuth::initialize() { #ifdef ENABLE_PAM_AUTH m_initialized = true; return true; #else m_initialized = false; return false; #endif } PamAuthResult PamAuth::authenticate(const std::string& username, const std::string& password) { PamAuthResult result; result.success = false; if (!m_initialized) { result.errorMessage = "PAM authentication not initialized"; result.errorCode = "PAM_NOT_INITIALIZED"; return result; } #ifdef ENABLE_PAM_AUTH return authenticateInternal(username, password); #else result.errorMessage = "PAM authentication not available (compiled without PAM support)"; result.errorCode = "PAM_NOT_AVAILABLE"; return result; #endif } bool PamAuth::isAvailable() const { return m_initialized; } std::string PamAuth::getServiceName() const { return m_serviceName; } void PamAuth::setServiceName(const std::string& serviceName) { m_serviceName = serviceName; } #ifdef ENABLE_PAM_AUTH // Structure to hold authentication data for PAM conversation struct PamAuthData { std::string username; std::string password; PamAuthResult* result; }; int PamAuth::conversationFunction(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) { if (num_msg <= 0 || msg == NULL || resp == NULL || appdata_ptr == NULL) { return PAM_CONV_ERR; } PamAuthData* authData = static_cast(appdata_ptr); // Allocate response array struct pam_response* response = static_cast( calloc(num_msg, sizeof(struct pam_response))); if (response == NULL) { return PAM_CONV_ERR; } for (int i = 0; i < num_msg; i++) { const struct pam_message* message = msg[i]; switch (message->msg_style) { case PAM_PROMPT_ECHO_OFF: // Password prompt - return the password response[i].resp = strdup(authData->password.c_str()); response[i].resp_retcode = 0; break; case PAM_PROMPT_ECHO_ON: // Username prompt - return the username response[i].resp = strdup(authData->username.c_str()); response[i].resp_retcode = 0; break; case PAM_ERROR_MSG: // Error message - log it if (authData->result) { authData->result->errorMessage = message->msg; } response[i].resp = NULL; response[i].resp_retcode = 0; break; case PAM_TEXT_INFO: // Information message - ignore response[i].resp = NULL; response[i].resp_retcode = 0; break; default: // Unknown message type for (int j = 0; j <= i; j++) { if (response[j].resp != NULL) { free(response[j].resp); } } free(response); return PAM_CONV_ERR; } } *resp = response; return PAM_SUCCESS; } PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password) { PamAuthResult result; result.success = false; result.username = username; // Prepare authentication data PamAuthData authData; authData.username = username; authData.password = password; authData.result = &result; // PAM conversation structure struct pam_conv pam_conv; pam_conv.conv = conversationFunction; pam_conv.appdata_ptr = &authData; pam_handle_t* pamh = NULL; int pam_status; // Start PAM transaction pam_status = pam_start(m_serviceName.c_str(), username.c_str(), &pam_conv, &pamh); if (pam_status != PAM_SUCCESS) { result.errorMessage = pamErrorToString(pam_status); result.errorCode = pamErrorToErrorCode(pam_status); return result; } // Authenticate user pam_status = pam_authenticate(pamh, PAM_SILENT); if (pam_status != PAM_SUCCESS) { result.errorMessage = pamErrorToString(pam_status); result.errorCode = pamErrorToErrorCode(pam_status); pam_end(pamh, pam_status); return result; } // Check account validity pam_status = pam_acct_mgmt(pamh, PAM_SILENT); if (pam_status != PAM_SUCCESS) { result.errorMessage = pamErrorToString(pam_status); result.errorCode = pamErrorToErrorCode(pam_status); pam_end(pamh, pam_status); return result; } // Get user information struct passwd* pw = getpwnam(username.c_str()); if (pw != NULL) { // Use system UID as user ID result.userId = std::to_string(pw->pw_uid); } else { // Fallback: use username as ID result.userId = username; } result.success = true; result.errorMessage = ""; result.errorCode = ""; // End PAM transaction pam_end(pamh, PAM_SUCCESS); return result; } std::string PamAuth::pamErrorToString(int pamError) { switch (pamError) { case PAM_SUCCESS: return "Success"; case PAM_ABORT: return "General failure"; case PAM_AUTH_ERR: return "Authentication failure"; case PAM_CRED_INSUFFICIENT: return "Insufficient credentials"; case PAM_AUTHINFO_UNAVAIL: return "Authentication information unavailable"; case PAM_USER_UNKNOWN: return "Unknown user"; case PAM_MAXTRIES: return "Maximum number of tries exceeded"; case PAM_NEW_AUTHTOK_REQD: return "New authentication token required"; case PAM_ACCT_EXPIRED: return "User account has expired"; case PAM_SESSION_ERR: return "Session error"; case PAM_CRED_ERR: return "Credential error"; case PAM_CRED_UNAVAIL: return "Credential unavailable"; case PAM_CRED_EXPIRED: return "Credential expired"; case PAM_NO_MODULE_DATA: return "No module data available"; case PAM_CONV_ERR: return "Conversation error"; case PAM_AUTHTOK_ERR: return "Authentication token error"; case PAM_AUTHTOK_RECOVERY_ERR: return "Authentication token recovery error"; case PAM_AUTHTOK_LOCK_BUSY: return "Authentication token lock busy"; case PAM_AUTHTOK_DISABLE_AGING: return "Authentication token aging disabled"; case PAM_TRY_AGAIN: return "Try again"; case PAM_IGNORE: return "Ignore"; case PAM_MODULE_UNKNOWN: return "Unknown module"; case PAM_BAD_ITEM: return "Bad item"; case PAM_CONV_AGAIN: return "Conversation again"; case PAM_INCOMPLETE: return "Incomplete"; default: return "Unknown PAM error"; } } std::string PamAuth::pamErrorToErrorCode(int pamError) { switch (pamError) { case PAM_SUCCESS: return "SUCCESS"; case PAM_AUTH_ERR: case PAM_CRED_INSUFFICIENT: return "AUTHENTICATION_FAILED"; case PAM_USER_UNKNOWN: return "USER_NOT_FOUND"; case PAM_CRED_EXPIRED: return "CREDENTIAL_EXPIRED"; case PAM_ACCT_EXPIRED: return "ACCOUNT_EXPIRED"; case PAM_NEW_AUTHTOK_REQD: return "PASSWORD_CHANGE_REQUIRED"; case PAM_MAXTRIES: return "MAX_TRIES_EXCEEDED"; case PAM_AUTHINFO_UNAVAIL: case PAM_CRED_UNAVAIL: return "AUTHENTICATION_UNAVAILABLE"; default: return "PAM_ERROR"; } } #else // Stub implementations when PAM is not enabled PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password) { PamAuthResult result; result.success = false; result.errorMessage = "PAM authentication not available (compiled without PAM support)"; result.errorCode = "PAM_NOT_AVAILABLE"; return result; } std::string PamAuth::pamErrorToString(int pamError) { return "PAM not available"; } std::string PamAuth::pamErrorToErrorCode(int pamError) { return "PAM_NOT_AVAILABLE"; } #endif