1 #pragma once 2 3 #include <security/pam_appl.h> 4 5 #include <boost/utility/string_view.hpp> 6 #include <cstring> 7 #include <memory> 8 9 // function used to get user input 10 inline int pamFunctionConversation(int numMsg, const struct pam_message** msg, 11 struct pam_response** resp, void* appdataPtr) 12 { 13 if (appdataPtr == nullptr) 14 { 15 return PAM_AUTH_ERR; 16 } 17 char* appPass = reinterpret_cast<char*>(appdataPtr); 18 size_t appPassSize = std::strlen(appPass); 19 char* pass = reinterpret_cast<char*>(malloc(appPassSize + 1)); 20 if (pass == nullptr) 21 { 22 return PAM_AUTH_ERR; 23 } 24 25 std::strcpy(pass, appPass); 26 27 *resp = reinterpret_cast<pam_response*>( 28 calloc(static_cast<size_t>(numMsg), sizeof(struct pam_response))); 29 30 if (resp == nullptr) 31 { 32 return PAM_AUTH_ERR; 33 } 34 35 for (int i = 0; i < numMsg; ++i) 36 { 37 /* Ignore all PAM messages except prompting for hidden input */ 38 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) 39 { 40 continue; 41 } 42 43 /* Assume PAM is only prompting for the password as hidden input */ 44 resp[i]->resp = pass; 45 } 46 47 return PAM_SUCCESS; 48 } 49 50 inline bool pamAuthenticateUser(const std::string_view username, 51 const std::string_view password) 52 { 53 std::string userStr(username); 54 std::string passStr(password); 55 const struct pam_conv localConversation = { 56 pamFunctionConversation, const_cast<char*>(passStr.c_str())}; 57 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 58 59 if (pam_start("webserver", userStr.c_str(), &localConversation, 60 &localAuthHandle) != PAM_SUCCESS) 61 { 62 return false; 63 } 64 int retval = pam_authenticate(localAuthHandle, 65 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); 66 67 if (retval != PAM_SUCCESS) 68 { 69 pam_end(localAuthHandle, PAM_SUCCESS); 70 return false; 71 } 72 73 /* check that the account is healthy */ 74 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) != 75 PAM_SUCCESS) 76 { 77 pam_end(localAuthHandle, PAM_SUCCESS); 78 return false; 79 } 80 81 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 82 { 83 return false; 84 } 85 86 return true; 87 } 88 89 inline bool pamUpdatePassword(const std::string& username, 90 const std::string& password) 91 { 92 const struct pam_conv localConversation = { 93 pamFunctionConversation, const_cast<char*>(password.c_str())}; 94 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 95 96 if (pam_start("passwd", username.c_str(), &localConversation, 97 &localAuthHandle) != PAM_SUCCESS) 98 { 99 return false; 100 } 101 int retval = pam_chauthtok(localAuthHandle, PAM_SILENT); 102 103 if (retval != PAM_SUCCESS) 104 { 105 pam_end(localAuthHandle, PAM_SUCCESS); 106 return false; 107 } 108 109 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 110 { 111 return false; 112 } 113 114 return true; 115 } 116