blob: 59c8cd6ec264da86055bf397990a0b7a210a4a51 [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
26 std::strcpy(pass, appPass);
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 {
33 return PAM_AUTH_ERR;
34 }
35
Ed Tanous1abe55e2018-09-05 08:30:59 -070036 for (int i = 0; i < numMsg; ++i)
37 {
38 /* Ignore all PAM messages except prompting for hidden input */
39 if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
40 {
41 continue;
42 }
43
44 /* Assume PAM is only prompting for the password as hidden input */
45 resp[i]->resp = pass;
Ed Tanous911ac312017-08-15 09:37:42 -070046 }
Ed Tanousf3d847c2017-06-12 16:01:42 -070047
Ed Tanous1abe55e2018-09-05 08:30:59 -070048 return PAM_SUCCESS;
Ed Tanousf3d847c2017-06-12 16:01:42 -070049}
50
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060051/**
52 * @brief Attempt username/password authentication via PAM.
53 * @param username The provided username aka account name.
54 * @param password The provided password.
55 * @returns PAM error code or PAM_SUCCESS for success. */
56inline int pamAuthenticateUser(const std::string_view username,
57 const std::string_view password)
Ed Tanous1abe55e2018-09-05 08:30:59 -070058{
59 std::string userStr(username);
60 std::string passStr(password);
61 const struct pam_conv localConversation = {
62 pamFunctionConversation, const_cast<char*>(passStr.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070063 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousf3d847c2017-06-12 16:01:42 -070064
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060065 int retval = pam_start("webserver", userStr.c_str(), &localConversation,
66 &localAuthHandle);
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 if (retval != PAM_SUCCESS)
68 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060069 return retval;
70 }
71
72 retval = pam_authenticate(localAuthHandle,
73 PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
74 if (retval != PAM_SUCCESS)
75 {
76 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
77 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -070078 }
Ed Tanous911ac312017-08-15 09:37:42 -070079
Ed Tanous1abe55e2018-09-05 08:30:59 -070080 /* check that the account is healthy */
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060081 retval = pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK);
82 if (retval != PAM_SUCCESS)
Ed Tanous1abe55e2018-09-05 08:30:59 -070083 {
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060084 pam_end(localAuthHandle, PAM_SUCCESS); // ignore retval
85 return retval;
Ed Tanous1abe55e2018-09-05 08:30:59 -070086 }
Ed Tanous911ac312017-08-15 09:37:42 -070087
Joseph Reynoldsd887fff2020-01-14 16:34:09 -060088 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanous911ac312017-08-15 09:37:42 -070089}
Ed Tanousa8408792018-09-05 16:08:38 -070090
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +000091inline int pamUpdatePassword(const std::string& username,
92 const std::string& password)
Ed Tanousa8408792018-09-05 16:08:38 -070093{
94 const struct pam_conv localConversation = {
95 pamFunctionConversation, const_cast<char*>(password.c_str())};
Ed Tanous99131cd2019-10-24 11:12:47 -070096 pam_handle_t* localAuthHandle = nullptr; // this gets set by pam_start
Ed Tanousa8408792018-09-05 16:08:38 -070097
Joseph Reynolds96b39e02019-12-05 17:53:35 -060098 int retval = pam_start("webserver", username.c_str(), &localConversation,
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +000099 &localAuthHandle);
Ed Tanousa8408792018-09-05 16:08:38 -0700100
101 if (retval != PAM_SUCCESS)
102 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000103 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700104 }
105
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000106 retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
107 if (retval != PAM_SUCCESS)
Ed Tanousa8408792018-09-05 16:08:38 -0700108 {
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000109 pam_end(localAuthHandle, PAM_SUCCESS);
110 return retval;
Ed Tanousa8408792018-09-05 16:08:38 -0700111 }
112
jayaprakash Mutyala66b5ca72019-08-07 20:26:37 +0000113 return pam_end(localAuthHandle, PAM_SUCCESS);
Ed Tanousa8408792018-09-05 16:08:38 -0700114}