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