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