blob: 3e5c6915c56f2afe4bbd052f91d94c52ad853489 [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 {
16 return PAM_AUTH_ERR;
17 }
Ed Tanousf1eebf02019-03-04 15:57:09 -080018 char* appPass = reinterpret_cast<char*>(appdataPtr);
19 size_t appPassSize = std::strlen(appPass);
20 char* pass = reinterpret_cast<char*>(malloc(appPassSize + 1));
Ed Tanous39e77502019-03-04 17:35:53 -080021 if (pass == nullptr)
Ed Tanousf1eebf02019-03-04 15:57:09 -080022 {
23 return PAM_AUTH_ERR;
24 }
25
Ed Tanouseb7d3d52019-10-24 10:23:56 -070026 std::strncpy(pass, appPass, appPassSize + 1);
Ed Tanousf3d847c2017-06-12 16:01:42 -070027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028 *resp = reinterpret_cast<pam_response*>(
Ed Tanous271584a2019-07-09 16:24:22 -070029 calloc(static_cast<size_t>(numMsg), sizeof(struct pam_response)));
Ed Tanousf3d847c2017-06-12 16:01:42 -070030
Ed Tanous39e77502019-03-04 17:35:53 -080031 if (resp == nullptr)
Ed Tanousf1eebf02019-03-04 15:57:09 -080032 {
AppaRao Puli87f171a2020-08-07 01:37:28 +053033 free(pass);
Ed Tanousf1eebf02019-03-04 15:57:09 -080034 return PAM_AUTH_ERR;
35 }
36
Ed Tanous1abe55e2018-09-05 08:30:59 -070037 for (int i = 0; i < numMsg; ++i)
38 {
39 /* Ignore all PAM messages except prompting for hidden input */
40 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
41 {
42 continue;
43 }
44
45 /* Assume PAM is only prompting for the password as hidden input */
46 resp[i]->resp = pass;
Ed Tanous911ac312017-08-15 09:37:42 -070047 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 return PAM_SUCCESS;
Ed Tanousf3d847c2017-06-12 16:01:42 -070050}
51
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060052/**
53 * @brief Attempt username/password authentication via PAM.
54 * @param username The provided username aka account name.
55 * @param password The provided password.
56 * @returns PAM error code or PAM_SUCCESS for success. */
57inline int pamAuthenticateUser(const std::string_view username,
58 const std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070059{
60 std::string userStr(username);
61 std::string passStr(password);
62 const struct pam_conv localConversation = {
63 pamFunctionConversation, const_cast<char*>(passStr.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070064 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousf3d847c2017-06-12 16:01:42 -070065
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060066 int retval = pam_start("webserver", userStr.c_str(), &localConversation,
67 &localAuthHandle);
Ed Tanous1abe55e2018-09-05 08:30:59 -070068 if (retval != PAM_SUCCESS)
69 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060070 return retval;
71 }
72
73 retval = pam_authenticate(localAuthHandle,
74 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
75 if (retval != PAM_SUCCESS)
76 {
77 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
78 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -070079 }
Ed Tanous911ac312017-08-15 09:37:42 -070080
Ed Tanous1abe55e2018-09-05 08:30:59 -070081 /* check that the account is healthy */
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060082 retval = pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK);
83 if (retval != PAM_SUCCESS)
Ed Tanous1abe55e2018-09-05 08:30:59 -070084 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060085 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
86 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -070087 }
Ed Tanous911ac312017-08-15 09:37:42 -070088
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060089 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanous911ac312017-08-15 09:37:42 -070090}
Ed Tanousa8408792018-09-05 16:08:38 -070091
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +000092inline int pamUpdatePassword(const std::string& username,
93 const std::string& password)
Ed Tanousa8408792018-09-05 16:08:38 -070094{
95 const struct pam_conv localConversation = {
96 pamFunctionConversation, const_cast<char*>(password.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070097 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -070098
Joseph Reynolds96b39e02019-12-05 17:53:35 -060099 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000100 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700101
102 if (retval != PAM_SUCCESS)
103 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000104 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700105 }
106
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000107 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
108 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700109 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000110 pam_end(localAuthHandle, PAM_SUCCESS);
111 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700112 }
113
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000114 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700115}