1 #pragma once
2 
3 #include <security/pam_appl.h>
4 #include <cstring>
5 #include <memory>
6 #include <boost/utility/string_view.hpp>
7 
8 // function used to get user input
9 inline int pamFunctionConversation(int numMsg, const struct pam_message** msg,
10                                    struct pam_response** resp,
11                                    void* appdataPtr) {
12   if (appdataPtr == nullptr) {
13     return PAM_AUTH_ERR;
14   }
15   auto* pass = reinterpret_cast<char*>(
16       malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1));
17   std::strcpy(pass, reinterpret_cast<char*>(appdataPtr));
18 
19   *resp = reinterpret_cast<pam_response*>(
20       calloc(numMsg, sizeof(struct pam_response)));
21 
22   for (int i = 0; i < numMsg; ++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 pamAuthenticateUser(const boost::string_view username,
36                                 const boost::string_view password) {
37   std::string userStr(username);
38   std::string passStr(password);
39   const struct pam_conv localConversation = {
40       pamFunctionConversation, const_cast<char*>(passStr.c_str())};
41   pam_handle_t* localAuthHandle = NULL;  // this gets set by pam_start
42 
43   if (pam_start("webserver", userStr.c_str(), &localConversation,
44                 &localAuthHandle) != PAM_SUCCESS) {
45     return false;
46   }
47   int retval =
48       pam_authenticate(localAuthHandle, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
49 
50   if (retval != PAM_SUCCESS) {
51     if (retval == PAM_AUTH_ERR) {
52       // printf("Authentication failure.\n");
53     } else {
54       // printf("pam_authenticate returned %d\n", retval);
55     }
56     pam_end(localAuthHandle, PAM_SUCCESS);
57     return false;
58   }
59 
60   /* check that the account is healthy */
61   if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
62       PAM_SUCCESS) {
63     pam_end(localAuthHandle, PAM_SUCCESS);
64     return false;
65   }
66 
67   if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) {
68     return false;
69   }
70 
71   return true;
72 }
73