blob: 22c869529f0c8a4e05c707d520045c7b7bd711a1 [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
Ed Tanous911ac312017-08-15 09:37:42 -07005#include <cstring>
Ed Tanouse0d918b2018-03-27 17:41:04 -07006#include <memory>
Patrick Williamsad7fa902023-05-10 19:57:29 -05007#include <span>
Ed Tanous5b904292024-04-16 11:10:17 -07008#include <string_view>
Ed Tanousf3d847c2017-06-12 16:01:42 -07009
10// function used to get user input
Ed Tanous05ecd3a2024-02-16 08:13:57 -080011inline int pamFunctionConversation(int numMsg, const struct pam_message** msgs,
Ed Tanous1abe55e2018-09-05 08:30:59 -070012 struct pam_response** resp, void* appdataPtr)
13{
Ed Tanous05ecd3a2024-02-16 08:13:57 -080014 if ((appdataPtr == nullptr) || (msgs == nullptr) || (resp == nullptr))
Ed Tanous1abe55e2018-09-05 08:30:59 -070015 {
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 }
Patrick Williamsad7fa902023-05-10 19:57:29 -050023 auto msgCount = static_cast<size_t>(numMsg);
Patrick Williamsad7fa902023-05-10 19:57:29 -050024
Ed Tanous05ecd3a2024-02-16 08:13:57 -080025 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
26 auto responseArrPtr = std::make_unique<pam_response[]>(msgCount);
27 auto responses = std::span(responseArrPtr.get(), msgCount);
28 auto messagePtrs = std::span(msgs, msgCount);
Patrick Williamsad7fa902023-05-10 19:57:29 -050029 for (size_t i = 0; i < msgCount; ++i)
Ed Tanous1abe55e2018-09-05 08:30:59 -070030 {
Ed Tanous05ecd3a2024-02-16 08:13:57 -080031 const pam_message& msg = *(messagePtrs[i]);
32
33 pam_response& response = responses[i];
34 response.resp_retcode = 0;
35 response.resp = nullptr;
36
37 switch (msg.msg_style)
Ed Tanous1abe55e2018-09-05 08:30:59 -070038 {
Ed Tanous05ecd3a2024-02-16 08:13:57 -080039 case PAM_PROMPT_ECHO_ON:
40 break;
41 case PAM_PROMPT_ECHO_OFF:
42 {
43 // Assume PAM is only prompting for the password as hidden input
44 // Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred
45 char* appPass = static_cast<char*>(appdataPtr);
46 size_t appPassSize = std::strlen(appPass);
47
48 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE)
49 {
50 return PAM_CONV_ERR;
51 }
52 // Create an array for pam to own
53 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
54 auto passPtr = std::make_unique<char[]>(appPassSize + 1);
55 std::strncpy(passPtr.get(), appPass, appPassSize + 1);
56
57 responses[i].resp = passPtr.release();
58 }
59 break;
60 case PAM_ERROR_MSG:
61 BMCWEB_LOG_ERROR("Pam error {}", msg.msg);
62 break;
63 case PAM_TEXT_INFO:
64 BMCWEB_LOG_ERROR("Pam info {}", msg.msg);
65 break;
66 default:
67 return PAM_CONV_ERR;
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 }
Ed Tanous911ac312017-08-15 09:37:42 -070069 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070070
Ed Tanous05ecd3a2024-02-16 08:13:57 -080071 *resp = responseArrPtr.release();
72 return PAM_SUCCESS;
Ed Tanousf3d847c2017-06-12 16:01:42 -070073}
74
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060075/**
76 * @brief Attempt username/password authentication via PAM.
77 * @param username The provided username aka account name.
78 * @param password The provided password.
79 * @returns PAM error code or PAM_SUCCESS for success. */
Ed Tanous26ccae32023-02-16 10:28:44 -080080inline int pamAuthenticateUser(std::string_view username,
81 std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070082{
83 std::string userStr(username);
84 std::string passStr(password);
Ed Tanous4ecc6182022-01-07 09:36:26 -080085
Ed Tanousf9c794f2023-06-06 11:46:49 -070086 char* passStrNoConst = passStr.data();
Ed Tanous4ecc6182022-01-07 09:36:26 -080087 const struct pam_conv localConversation = {pamFunctionConversation,
88 passStrNoConst};
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{
Ed Tanous4ecc6182022-01-07 09:36:26 -0800120 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
121 char* passStrNoConst = const_cast<char*>(password.c_str());
122 const struct pam_conv localConversation = {pamFunctionConversation,
123 passStrNoConst};
Ed Tanous99131cd2019-10-24 11:12:47 -0700124 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -0700125
Joseph Reynolds96b39e02019-12-05 17:53:35 -0600126 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000127 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700128
129 if (retval != PAM_SUCCESS)
130 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000131 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700132 }
133
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000134 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
135 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700136 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000137 pam_end(localAuthHandle, PAM_SUCCESS);
138 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700139 }
140
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000141 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700142}