// SPDX-License-Identifier: Apache-2.0 // Copyright 2026 Suyono // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 #include #include #include #include #include #include namespace { struct AppData { const char* password; }; int conversation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) { if (num_msg <= 0 || msg == nullptr || resp == nullptr) { return PAM_CONV_ERR; } auto* app_data = static_cast(appdata_ptr); auto* replies = static_cast(calloc(static_cast(num_msg), sizeof(pam_response))); if (replies == nullptr) { return PAM_BUF_ERR; } for (int i = 0; i < num_msg; ++i) { replies[i].resp_retcode = 0; replies[i].resp = nullptr; switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: if (app_data != nullptr && app_data->password != nullptr) { replies[i].resp = strdup(app_data->password); if (replies[i].resp == nullptr) { free(replies); return PAM_BUF_ERR; } } break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: break; default: free(replies); return PAM_CONV_ERR; } } *resp = replies; return PAM_SUCCESS; } } // namespace int main(int argc, char** argv) { if (argc < 3) { std::cerr << "Usage: " << argv[0] << " [password]" << std::endl; return 2; } const std::string service = argv[1]; const std::string user = argv[2]; const char* password = (argc >= 4) ? argv[3] : ""; AppData app_data{password}; pam_conv conv{conversation, &app_data}; pam_handle_t* pamh = nullptr; int rc = pam_start(service.c_str(), user.c_str(), &conv, &pamh); if (rc != PAM_SUCCESS) { std::cerr << "pam_start failed: " << pam_strerror(pamh, rc) << std::endl; return 1; } rc = pam_authenticate(pamh, 0); if (rc == PAM_SUCCESS) { std::cout << "Authentication succeeded" << std::endl; } else { std::cout << "Authentication failed: " << pam_strerror(pamh, rc) << std::endl; } const int end_rc = pam_end(pamh, rc); if (end_rc != PAM_SUCCESS) { std::cerr << "pam_end failed: " << pam_strerror(pamh, end_rc) << std::endl; } return (rc == PAM_SUCCESS) ? 0 : 1; }