pam_auth.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #include "pam_auth.h"
  2. #ifdef ENABLE_PAM_AUTH
  3. #include <security/pam_appl.h>
  4. #include <security/pam_misc.h>
  5. #include <pwd.h>
  6. #include <unistd.h>
  7. #include <cstring>
  8. #include <cstdlib>
  9. #endif
  10. PamAuth::PamAuth(const std::string& serviceName)
  11. : m_serviceName(serviceName)
  12. , m_initialized(false)
  13. {
  14. }
  15. PamAuth::~PamAuth() {
  16. }
  17. bool PamAuth::initialize() {
  18. #ifdef ENABLE_PAM_AUTH
  19. m_initialized = true;
  20. return true;
  21. #else
  22. m_initialized = false;
  23. return false;
  24. #endif
  25. }
  26. PamAuthResult PamAuth::authenticate(const std::string& username, const std::string& password) {
  27. PamAuthResult result;
  28. result.success = false;
  29. if (!m_initialized) {
  30. result.errorMessage = "PAM authentication not initialized";
  31. result.errorCode = "PAM_NOT_INITIALIZED";
  32. return result;
  33. }
  34. #ifdef ENABLE_PAM_AUTH
  35. return authenticateInternal(username, password);
  36. #else
  37. result.errorMessage = "PAM authentication not available (compiled without PAM support)";
  38. result.errorCode = "PAM_NOT_AVAILABLE";
  39. return result;
  40. #endif
  41. }
  42. bool PamAuth::isAvailable() const {
  43. return m_initialized;
  44. }
  45. std::string PamAuth::getServiceName() const {
  46. return m_serviceName;
  47. }
  48. void PamAuth::setServiceName(const std::string& serviceName) {
  49. m_serviceName = serviceName;
  50. }
  51. #ifdef ENABLE_PAM_AUTH
  52. // Structure to hold authentication data for PAM conversation
  53. struct PamAuthData {
  54. std::string username;
  55. std::string password;
  56. PamAuthResult* result;
  57. };
  58. int PamAuth::conversationFunction(int num_msg, const struct pam_message** msg,
  59. struct pam_response** resp, void* appdata_ptr) {
  60. if (num_msg <= 0 || msg == NULL || resp == NULL || appdata_ptr == NULL) {
  61. return PAM_CONV_ERR;
  62. }
  63. PamAuthData* authData = static_cast<PamAuthData*>(appdata_ptr);
  64. // Allocate response array
  65. struct pam_response* response = static_cast<struct pam_response*>(
  66. calloc(num_msg, sizeof(struct pam_response)));
  67. if (response == NULL) {
  68. return PAM_CONV_ERR;
  69. }
  70. for (int i = 0; i < num_msg; i++) {
  71. const struct pam_message* message = msg[i];
  72. switch (message->msg_style) {
  73. case PAM_PROMPT_ECHO_OFF:
  74. // Password prompt - return the password
  75. response[i].resp = strdup(authData->password.c_str());
  76. response[i].resp_retcode = 0;
  77. break;
  78. case PAM_PROMPT_ECHO_ON:
  79. // Username prompt - return the username
  80. response[i].resp = strdup(authData->username.c_str());
  81. response[i].resp_retcode = 0;
  82. break;
  83. case PAM_ERROR_MSG:
  84. // Error message - log it
  85. if (authData->result) {
  86. authData->result->errorMessage = message->msg;
  87. }
  88. response[i].resp = NULL;
  89. response[i].resp_retcode = 0;
  90. break;
  91. case PAM_TEXT_INFO:
  92. // Information message - ignore
  93. response[i].resp = NULL;
  94. response[i].resp_retcode = 0;
  95. break;
  96. default:
  97. // Unknown message type
  98. for (int j = 0; j <= i; j++) {
  99. if (response[j].resp != NULL) {
  100. free(response[j].resp);
  101. }
  102. }
  103. free(response);
  104. return PAM_CONV_ERR;
  105. }
  106. }
  107. *resp = response;
  108. return PAM_SUCCESS;
  109. }
  110. PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password) {
  111. PamAuthResult result;
  112. result.success = false;
  113. result.username = username;
  114. // Prepare authentication data
  115. PamAuthData authData;
  116. authData.username = username;
  117. authData.password = password;
  118. authData.result = &result;
  119. // PAM conversation structure
  120. struct pam_conv pam_conv;
  121. pam_conv.conv = conversationFunction;
  122. pam_conv.appdata_ptr = &authData;
  123. pam_handle_t* pamh = NULL;
  124. int pam_status;
  125. // Start PAM transaction
  126. pam_status = pam_start(m_serviceName.c_str(), username.c_str(), &pam_conv, &pamh);
  127. if (pam_status != PAM_SUCCESS) {
  128. result.errorMessage = pamErrorToString(pam_status);
  129. result.errorCode = pamErrorToErrorCode(pam_status);
  130. return result;
  131. }
  132. // Authenticate user
  133. pam_status = pam_authenticate(pamh, PAM_SILENT);
  134. if (pam_status != PAM_SUCCESS) {
  135. result.errorMessage = pamErrorToString(pam_status);
  136. result.errorCode = pamErrorToErrorCode(pam_status);
  137. pam_end(pamh, pam_status);
  138. return result;
  139. }
  140. // Check account validity
  141. pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
  142. if (pam_status != PAM_SUCCESS) {
  143. result.errorMessage = pamErrorToString(pam_status);
  144. result.errorCode = pamErrorToErrorCode(pam_status);
  145. pam_end(pamh, pam_status);
  146. return result;
  147. }
  148. // Get user information
  149. struct passwd* pw = getpwnam(username.c_str());
  150. if (pw != NULL) {
  151. // Use system UID as user ID
  152. result.userId = std::to_string(pw->pw_uid);
  153. } else {
  154. // Fallback: use username as ID
  155. result.userId = username;
  156. }
  157. result.success = true;
  158. result.errorMessage = "";
  159. result.errorCode = "";
  160. // End PAM transaction
  161. pam_end(pamh, PAM_SUCCESS);
  162. return result;
  163. }
  164. std::string PamAuth::pamErrorToString(int pamError) {
  165. switch (pamError) {
  166. case PAM_SUCCESS:
  167. return "Success";
  168. case PAM_ABORT:
  169. return "General failure";
  170. case PAM_AUTH_ERR:
  171. return "Authentication failure";
  172. case PAM_CRED_INSUFFICIENT:
  173. return "Insufficient credentials";
  174. case PAM_AUTHINFO_UNAVAIL:
  175. return "Authentication information unavailable";
  176. case PAM_USER_UNKNOWN:
  177. return "Unknown user";
  178. case PAM_MAXTRIES:
  179. return "Maximum number of tries exceeded";
  180. case PAM_NEW_AUTHTOK_REQD:
  181. return "New authentication token required";
  182. case PAM_ACCT_EXPIRED:
  183. return "User account has expired";
  184. case PAM_SESSION_ERR:
  185. return "Session error";
  186. case PAM_CRED_ERR:
  187. return "Credential error";
  188. case PAM_CRED_UNAVAIL:
  189. return "Credential unavailable";
  190. case PAM_CRED_EXPIRED:
  191. return "Credential expired";
  192. case PAM_NO_MODULE_DATA:
  193. return "No module data available";
  194. case PAM_CONV_ERR:
  195. return "Conversation error";
  196. case PAM_AUTHTOK_ERR:
  197. return "Authentication token error";
  198. case PAM_AUTHTOK_RECOVERY_ERR:
  199. return "Authentication token recovery error";
  200. case PAM_AUTHTOK_LOCK_BUSY:
  201. return "Authentication token lock busy";
  202. case PAM_AUTHTOK_DISABLE_AGING:
  203. return "Authentication token aging disabled";
  204. case PAM_TRY_AGAIN:
  205. return "Try again";
  206. case PAM_IGNORE:
  207. return "Ignore";
  208. case PAM_MODULE_UNKNOWN:
  209. return "Unknown module";
  210. case PAM_BAD_ITEM:
  211. return "Bad item";
  212. case PAM_CONV_AGAIN:
  213. return "Conversation again";
  214. case PAM_INCOMPLETE:
  215. return "Incomplete";
  216. default:
  217. return "Unknown PAM error";
  218. }
  219. }
  220. std::string PamAuth::pamErrorToErrorCode(int pamError) {
  221. switch (pamError) {
  222. case PAM_SUCCESS:
  223. return "SUCCESS";
  224. case PAM_AUTH_ERR:
  225. case PAM_CRED_INSUFFICIENT:
  226. return "AUTHENTICATION_FAILED";
  227. case PAM_USER_UNKNOWN:
  228. return "USER_NOT_FOUND";
  229. case PAM_CRED_EXPIRED:
  230. return "CREDENTIAL_EXPIRED";
  231. case PAM_ACCT_EXPIRED:
  232. return "ACCOUNT_EXPIRED";
  233. case PAM_NEW_AUTHTOK_REQD:
  234. return "PASSWORD_CHANGE_REQUIRED";
  235. case PAM_MAXTRIES:
  236. return "MAX_TRIES_EXCEEDED";
  237. case PAM_AUTHINFO_UNAVAIL:
  238. case PAM_CRED_UNAVAIL:
  239. return "AUTHENTICATION_UNAVAILABLE";
  240. default:
  241. return "PAM_ERROR";
  242. }
  243. }
  244. #else
  245. // Stub implementations when PAM is not enabled
  246. PamAuthResult PamAuth::authenticateInternal(const std::string& username, const std::string& password) {
  247. PamAuthResult result;
  248. result.success = false;
  249. result.errorMessage = "PAM authentication not available (compiled without PAM support)";
  250. result.errorCode = "PAM_NOT_AVAILABLE";
  251. return result;
  252. }
  253. std::string PamAuth::pamErrorToString(int pamError) {
  254. return "PAM not available";
  255. }
  256. std::string PamAuth::pamErrorToErrorCode(int pamError) {
  257. return "PAM_NOT_AVAILABLE";
  258. }
  259. #endif