xref: /openbmc/bmcweb/include/pam_authenticate.hpp (revision 911ac31759cb7b77a856af8806b4e064d50d7422)
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