Files
usercontainer/tests/app/pam_test_app.cpp

96 lines
2.7 KiB
C++

// 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;
}