initial commit: WIP debugging PAM module
This commit is contained in:
95
tests/app/pam_test_app.cpp
Normal file
95
tests/app/pam_test_app.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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 <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
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*>(appdata_ptr);
|
||||
auto* replies = static_cast<pam_response*>(calloc(static_cast<size_t>(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] << " <service> <user> [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;
|
||||
}
|
||||
Reference in New Issue
Block a user