blob: a24270f4b6046d739a0fee1a60602cbd7258891a [file] [log] [blame]
Ed Tanous911ac312017-08-15 09:37:42 -07001#pragma once
2
Ed Tanousf3d847c2017-06-12 16:01:42 -07003#include <security/pam_appl.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -07004
5#include <boost/utility/string_view.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05006
Ed Tanous911ac312017-08-15 09:37:42 -07007#include <cstring>
Ed Tanouse0d918b2018-03-27 17:41:04 -07008#include <memory>
Ed Tanousf3d847c2017-06-12 16:01:42 -07009
10// function used to get user input
Ed Tanous55c7b7a2018-05-22 15:27:24 -070011inline int pamFunctionConversation(int numMsg, const struct pam_message** msg,
Ed Tanous1abe55e2018-09-05 08:30:59 -070012 struct pam_response** resp, void* appdataPtr)
13{
14 if (appdataPtr == nullptr)
15 {
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053016 return PAM_CONV_ERR;
Ed Tanous1abe55e2018-09-05 08:30:59 -070017 }
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053018
19 if (numMsg <= 0 || numMsg >= PAM_MAX_NUM_MSG)
Ed Tanousf1eebf02019-03-04 15:57:09 -080020 {
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053021 return PAM_CONV_ERR;
Ed Tanousf1eebf02019-03-04 15:57:09 -080022 }
23
Ed Tanous1abe55e2018-09-05 08:30:59 -070024 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 */
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053033 /* Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred */
34
35 char* appPass = reinterpret_cast<char*>(appdataPtr);
36 size_t appPassSize = std::strlen(appPass);
37
38 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE)
39 {
40 return PAM_CONV_ERR;
41 }
42
43 char* pass = reinterpret_cast<char*>(malloc(appPassSize + 1));
44 if (pass == nullptr)
45 {
46 return PAM_BUF_ERR;
47 }
48
49 std::strncpy(pass, appPass, appPassSize + 1);
50
51 void* ptr =
52 calloc(static_cast<size_t>(numMsg), sizeof(struct pam_response));
53 if (ptr == nullptr)
54 {
55 free(pass);
56 return PAM_BUF_ERR;
57 }
58
59 *resp = reinterpret_cast<pam_response*>(ptr);
Ed Tanous1abe55e2018-09-05 08:30:59 -070060 resp[i]->resp = pass;
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053061
62 return PAM_SUCCESS;
Ed Tanous911ac312017-08-15 09:37:42 -070063 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070064
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053065 return PAM_CONV_ERR;
Ed Tanousf3d847c2017-06-12 16:01:42 -070066}
67
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060068/**
69 * @brief Attempt username/password authentication via PAM.
70 * @param username The provided username aka account name.
71 * @param password The provided password.
72 * @returns PAM error code or PAM_SUCCESS for success. */
73inline int pamAuthenticateUser(const std::string_view username,
74 const std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070075{
76 std::string userStr(username);
77 std::string passStr(password);
78 const struct pam_conv localConversation = {
79 pamFunctionConversation, const_cast<char*>(passStr.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070080 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousf3d847c2017-06-12 16:01:42 -070081
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060082 int retval = pam_start("webserver", userStr.c_str(), &localConversation,
83 &localAuthHandle);
Ed Tanous1abe55e2018-09-05 08:30:59 -070084 if (retval != PAM_SUCCESS)
85 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060086 return retval;
87 }
88
89 retval = pam_authenticate(localAuthHandle,
90 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
91 if (retval != PAM_SUCCESS)
92 {
93 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
94 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -070095 }
Ed Tanous911ac312017-08-15 09:37:42 -070096
Ed Tanous1abe55e2018-09-05 08:30:59 -070097 /* check that the account is healthy */
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060098 retval = pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK);
99 if (retval != PAM_SUCCESS)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600101 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
102 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700103 }
Ed Tanous911ac312017-08-15 09:37:42 -0700104
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600105 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanous911ac312017-08-15 09:37:42 -0700106}
Ed Tanousa8408792018-09-05 16:08:38 -0700107
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000108inline int pamUpdatePassword(const std::string& username,
109 const std::string& password)
Ed Tanousa8408792018-09-05 16:08:38 -0700110{
111 const struct pam_conv localConversation = {
112 pamFunctionConversation, const_cast<char*>(password.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -0700113 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -0700114
Joseph Reynolds96b39e02019-12-05 17:53:35 -0600115 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000116 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700117
118 if (retval != PAM_SUCCESS)
119 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000120 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700121 }
122
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000123 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
124 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700125 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000126 pam_end(localAuthHandle, PAM_SUCCESS);
127 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700128 }
129
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000130 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700131}