blob: 0ce0bb4a849f57f46181f5543958695af884820f [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
Ed Tanous46ff87b2022-01-07 09:25:51 -080035 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053036 char* appPass = reinterpret_cast<char*>(appdataPtr);
37 size_t appPassSize = std::strlen(appPass);
38
39 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE)
40 {
41 return PAM_CONV_ERR;
42 }
Ed Tanous46ff87b2022-01-07 09:25:51 -080043 // IDeally we'd like to avoid using malloc here, but because we're
44 // passing off ownership of this to a C application, there aren't a lot
45 // of sane ways to avoid it.
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053046
Ed Tanous46ff87b2022-01-07 09:25:51 -080047 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)'
48 void* passPtr = malloc(appPassSize + 1);
49 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
50 char* pass = reinterpret_cast<char*>(passPtr);
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053051 if (pass == nullptr)
52 {
53 return PAM_BUF_ERR;
54 }
55
56 std::strncpy(pass, appPass, appPassSize + 1);
57
Ed Tanous46ff87b2022-01-07 09:25:51 -080058 size_t numMsgSize = static_cast<size_t>(numMsg);
59 void* ptr = calloc(numMsgSize, sizeof(struct pam_response));
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053060 if (ptr == nullptr)
61 {
62 free(pass);
63 return PAM_BUF_ERR;
64 }
65
Ed Tanous46ff87b2022-01-07 09:25:51 -080066 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053067 *resp = reinterpret_cast<pam_response*>(ptr);
Ed Tanous46ff87b2022-01-07 09:25:51 -080068
Ed Tanous1abe55e2018-09-05 08:30:59 -070069 resp[i]->resp = pass;
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053070
71 return PAM_SUCCESS;
Ed Tanous911ac312017-08-15 09:37:42 -070072 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070073
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053074 return PAM_CONV_ERR;
Ed Tanousf3d847c2017-06-12 16:01:42 -070075}
76
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060077/**
78 * @brief Attempt username/password authentication via PAM.
79 * @param username The provided username aka account name.
80 * @param password The provided password.
81 * @returns PAM error code or PAM_SUCCESS for success. */
82inline int pamAuthenticateUser(const std::string_view username,
83 const std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070084{
85 std::string userStr(username);
86 std::string passStr(password);
87 const struct pam_conv localConversation = {
88 pamFunctionConversation, const_cast<char*>(passStr.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070089 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousf3d847c2017-06-12 16:01:42 -070090
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060091 int retval = pam_start("webserver", userStr.c_str(), &localConversation,
92 &localAuthHandle);
Ed Tanous1abe55e2018-09-05 08:30:59 -070093 if (retval != PAM_SUCCESS)
94 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060095 return retval;
96 }
97
98 retval = pam_authenticate(localAuthHandle,
99 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
100 if (retval != PAM_SUCCESS)
101 {
102 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
103 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700104 }
Ed Tanous911ac312017-08-15 09:37:42 -0700105
Ed Tanous1abe55e2018-09-05 08:30:59 -0700106 /* check that the account is healthy */
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600107 retval = pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK);
108 if (retval != PAM_SUCCESS)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600110 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
111 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 }
Ed Tanous911ac312017-08-15 09:37:42 -0700113
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600114 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanous911ac312017-08-15 09:37:42 -0700115}
Ed Tanousa8408792018-09-05 16:08:38 -0700116
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000117inline int pamUpdatePassword(const std::string& username,
118 const std::string& password)
Ed Tanousa8408792018-09-05 16:08:38 -0700119{
120 const struct pam_conv localConversation = {
121 pamFunctionConversation, const_cast<char*>(password.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -0700122 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -0700123
Joseph Reynolds96b39e02019-12-05 17:53:35 -0600124 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000125 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700126
127 if (retval != PAM_SUCCESS)
128 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000129 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700130 }
131
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000132 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
133 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700134 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000135 pam_end(localAuthHandle, PAM_SUCCESS);
136 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700137 }
138
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000139 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700140}