1 #pragma once 2 3 #include <security/pam_appl.h> 4 #include <cstring> 5 6 // function used to get user input 7 inline int pam_function_conversation(int num_msg, 8 const struct pam_message** msg, 9 struct pam_response** resp, 10 void* appdata_ptr) { 11 if (appdata_ptr == nullptr) { 12 return PAM_AUTH_ERR; 13 } 14 auto* pass = reinterpret_cast<char*>( 15 malloc(std::strlen(reinterpret_cast<char*>(appdata_ptr)) + 1)); 16 std::strcpy(pass, reinterpret_cast<char*>(appdata_ptr)); 17 18 *resp = reinterpret_cast<pam_response*>( 19 calloc(num_msg, sizeof(struct pam_response))); 20 21 for (int i = 0; i < num_msg; ++i) { 22 /* Ignore all PAM messages except prompting for hidden input */ 23 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) { 24 continue; 25 } 26 27 /* Assume PAM is only prompting for the password as hidden input */ 28 resp[i]->resp = pass; 29 } 30 31 return PAM_SUCCESS; 32 } 33 34 inline bool pam_authenticate_user(const std::string& username, 35 const std::string& password) { 36 const struct pam_conv local_conversation = { 37 pam_function_conversation, const_cast<char*>(password.c_str())}; 38 pam_handle_t* local_auth_handle = NULL; // this gets set by pam_start 39 40 if (pam_start("su", username.c_str(), &local_conversation, 41 &local_auth_handle) != PAM_SUCCESS) { 42 return false; 43 } 44 int retval = pam_authenticate(local_auth_handle, 45 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); 46 47 if (retval != PAM_SUCCESS) { 48 if (retval == PAM_AUTH_ERR) { 49 // printf("Authentication failure.\n"); 50 } else { 51 // printf("pam_authenticate returned %d\n", retval); 52 } 53 pam_end(local_auth_handle, PAM_SUCCESS); 54 return false; 55 } 56 57 /* check that the account is healthy */ 58 if (pam_acct_mgmt(local_auth_handle, PAM_DISALLOW_NULL_AUTHTOK) != 59 PAM_SUCCESS) { 60 pam_end(local_auth_handle, PAM_SUCCESS); 61 return false; 62 } 63 64 if (pam_end(local_auth_handle, PAM_SUCCESS) != PAM_SUCCESS) { 65 return false; 66 } 67 68 return true; 69 } 70