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 if (retval == PAM_AUTH_ERR) 59 { 60 // printf("Authentication failure.\n"); 61 } 62 else 63 { 64 // printf("pam_authenticate returned %d\n", retval); 65 } 66 pam_end(localAuthHandle, PAM_SUCCESS); 67 return false; 68 } 69 70 /* check that the account is healthy */ 71 if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) != 72 PAM_SUCCESS) 73 { 74 pam_end(localAuthHandle, PAM_SUCCESS); 75 return false; 76 } 77 78 if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) 79 { 80 return false; 81 } 82 83 return true; 84 } 85