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 auto* pass = reinterpret_cast<char*>( 18 malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1)); 19 std::strcpy(pass, reinterpret_cast<char*>(appdataPtr)); 20 21 *resp = reinterpret_cast<pam_response*>( 22 calloc(numMsg, sizeof(struct pam_response))); 23 24 for (int i = 0; i < numMsg; ++i) 25 { 26 /* Ignore all PAM messages except prompting for hidden input */ 27 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) 28 { 29 continue; 30 } 31 32 /* Assume PAM is only prompting for the password as hidden input */ 33 resp[i]->resp = pass; 34 } 35 36 return PAM_SUCCESS; 37 } 38 39 inline bool pamAuthenticateUser(const boost::string_view username, 40 const boost::string_view password) 41 { 42 std::string userStr(username); 43 std::string passStr(password); 44 const struct pam_conv localConversation = { 45 pamFunctionConversation, const_cast<char*>(passStr.c_str())}; 46 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 47 48 if (pam_start("webserver", userStr.c_str(), &localConversation, 49 &localAuthHandle) != PAM_SUCCESS) 50 { 51 return false; 52 } 53 int retval = pam_authenticate(localAuthHandle, 54 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); 55 56 if (retval != PAM_SUCCESS) 57 { 58 pam_end(localAuthHandle, PAM_SUCCESS); 59 return false; 60 } 61 62 /* check that the account is healthy */ 63 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) != 64 PAM_SUCCESS) 65 { 66 pam_end(localAuthHandle, PAM_SUCCESS); 67 return false; 68 } 69 70 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 71 { 72 return false; 73 } 74 75 return true; 76 } 77 78 inline bool pamUpdatePassword(const std::string& username, 79 const std::string& password) 80 { 81 const struct pam_conv localConversation = { 82 pamFunctionConversation, const_cast<char*>(password.c_str())}; 83 pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start 84 85 if (pam_start("passwd", username.c_str(), &localConversation, 86 &localAuthHandle) != PAM_SUCCESS) 87 { 88 return false; 89 } 90 int retval = pam_chauthtok(localAuthHandle, PAM_SILENT); 91 92 if (retval != PAM_SUCCESS) 93 { 94 pam_end(localAuthHandle, PAM_SUCCESS); 95 return false; 96 } 97 98 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 99 { 100 return false; 101 } 102 103 return true; 104 } 105