blob: 10d9116156b650ea3c11bc7fdc6ca45fbec9e0dd [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 */
Ed Tanousca45aa32022-01-07 09:28:45 -080027 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Ed Tanous1abe55e2018-09-05 08:30:59 -070028 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
29 {
30 continue;
31 }
32
33 /* Assume PAM is only prompting for the password as hidden input */
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053034 /* Allocate memory only when PAM_PROMPT_ECHO_OFF is encounterred */
35
Ed Tanous46ff87b2022-01-07 09:25:51 -080036 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053037 char* appPass = reinterpret_cast<char*>(appdataPtr);
38 size_t appPassSize = std::strlen(appPass);
39
40 if ((appPassSize + 1) > PAM_MAX_RESP_SIZE)
41 {
42 return PAM_CONV_ERR;
43 }
Ed Tanous46ff87b2022-01-07 09:25:51 -080044 // IDeally we'd like to avoid using malloc here, but because we're
45 // passing off ownership of this to a C application, there aren't a lot
46 // of sane ways to avoid it.
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053047
Ed Tanous46ff87b2022-01-07 09:25:51 -080048 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)'
49 void* passPtr = malloc(appPassSize + 1);
50 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
51 char* pass = reinterpret_cast<char*>(passPtr);
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053052 if (pass == nullptr)
53 {
54 return PAM_BUF_ERR;
55 }
56
57 std::strncpy(pass, appPass, appPassSize + 1);
58
Ed Tanous46ff87b2022-01-07 09:25:51 -080059 size_t numMsgSize = static_cast<size_t>(numMsg);
60 void* ptr = calloc(numMsgSize, sizeof(struct pam_response));
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053061 if (ptr == nullptr)
62 {
63 free(pass);
64 return PAM_BUF_ERR;
65 }
66
Ed Tanous46ff87b2022-01-07 09:25:51 -080067 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053068 *resp = reinterpret_cast<pam_response*>(ptr);
Ed Tanous46ff87b2022-01-07 09:25:51 -080069
Ed Tanousca45aa32022-01-07 09:28:45 -080070 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Ed Tanous1abe55e2018-09-05 08:30:59 -070071 resp[i]->resp = pass;
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053072
73 return PAM_SUCCESS;
Ed Tanous911ac312017-08-15 09:37:42 -070074 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070075
P Dheeraj Srujan Kumarba95fcc2021-07-12 21:47:59 +053076 return PAM_CONV_ERR;
Ed Tanousf3d847c2017-06-12 16:01:42 -070077}
78
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060079/**
80 * @brief Attempt username/password authentication via PAM.
81 * @param username The provided username aka account name.
82 * @param password The provided password.
83 * @returns PAM error code or PAM_SUCCESS for success. */
84inline int pamAuthenticateUser(const std::string_view username,
85 const std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070086{
87 std::string userStr(username);
88 std::string passStr(password);
Ed Tanous4ecc6182022-01-07 09:36:26 -080089
90 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
91 char* passStrNoConst = const_cast<char*>(passStr.c_str());
92 const struct pam_conv localConversation = {pamFunctionConversation,
93 passStrNoConst};
Ed Tanous99131cd2019-10-24 11:12:47 -070094 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousf3d847c2017-06-12 16:01:42 -070095
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060096 int retval = pam_start("webserver", userStr.c_str(), &localConversation,
97 &localAuthHandle);
Ed Tanous1abe55e2018-09-05 08:30:59 -070098 if (retval != PAM_SUCCESS)
99 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600100 return retval;
101 }
102
103 retval = pam_authenticate(localAuthHandle,
104 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
105 if (retval != PAM_SUCCESS)
106 {
107 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
108 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700109 }
Ed Tanous911ac312017-08-15 09:37:42 -0700110
Ed Tanous1abe55e2018-09-05 08:30:59 -0700111 /* check that the account is healthy */
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600112 retval = pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK);
113 if (retval != PAM_SUCCESS)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700114 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600115 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
116 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700117 }
Ed Tanous911ac312017-08-15 09:37:42 -0700118
Joseph Reynoldsd887fff2020-01-14 16:34:09 -0600119 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanous911ac312017-08-15 09:37:42 -0700120}
Ed Tanousa8408792018-09-05 16:08:38 -0700121
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000122inline int pamUpdatePassword(const std::string& username,
123 const std::string& password)
Ed Tanousa8408792018-09-05 16:08:38 -0700124{
Ed Tanous4ecc6182022-01-07 09:36:26 -0800125 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
126 char* passStrNoConst = const_cast<char*>(password.c_str());
127 const struct pam_conv localConversation = {pamFunctionConversation,
128 passStrNoConst};
Ed Tanous99131cd2019-10-24 11:12:47 -0700129 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -0700130
Joseph Reynolds96b39e02019-12-05 17:53:35 -0600131 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000132 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700133
134 if (retval != PAM_SUCCESS)
135 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000136 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700137 }
138
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000139 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
140 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700141 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000142 pam_end(localAuthHandle, PAM_SUCCESS);
143 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700144 }
145
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000146 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700147}