Bwi/ws based auth (#6)

* Add websocket implementation

* Added configuration for build socket-io and rublon connector
This commit is contained in:
rublon-bwi 2023-12-11 18:02:21 +01:00 committed by GitHub
parent 25b29e6f32
commit 7715b6fb45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 642 additions and 58 deletions

View File

@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.5)
project(rublon-ssh LANGUAGES CXX)
include(CTest)
include(GNUInstallDirs)
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 1)
@ -16,6 +17,21 @@ add_compile_options(-Wall -Wextra -Wpedantic -Wno-format-security)
option(ENABLE_TESTS "Enable tests" ON)
add_custom_target(CONFIG_IDE SOURCES ${CMAKE_CURRENT_LIST_DIR}/rsc/rublon.config.defaults)
add_custom_target(INSTSCRIPTS_IDE SUORCES ${CMAKE_CURRENT_LIST_DIR}/service/postinst)
# TODO configure to fill sysconfdir in postinst
# TODO add postrm that will disable PAM
install(
FILES
${CMAKE_CURRENT_LIST_DIR}/rsc/rublon.config.defaults
DESTINATION
share/rublon
COMPONENT
PAM
)
if (${ENABLE_TESTS})
enable_testing()
endif()

View File

@ -11,12 +11,14 @@ set(INC
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/method/OTP.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/method/SMS.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/method/passcode_based_auth.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/method/websocket_based_auth.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/non_owning_ptr.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/pam_action.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/pam.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/rublon.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/sign.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/utils.hpp
${CMAKE_CURRENT_SOURCE_DIR}/include/rublon/websockets.hpp
)
add_library(rublon-ssh

View File

@ -15,5 +15,7 @@ class CoreHandlerInterface {
rublon::log(LogLevel::Debug, "%s", "CoreHandlerInterface::request");
return static_cast< const Impl * >(this)->request(mr, path, body);
}
// tl::expected< Document, Error >
};
} // namespace rublon

View File

@ -18,8 +18,18 @@
#include <tl/expected.hpp>
#include <curl/curl.h>
namespace rublon {
inline bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
namespace {
size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) {
const size_t realsize = size * nmemb;

View File

@ -8,11 +8,47 @@
#include <rublon/method/method_select.hpp>
#include <sys/utsname.h>
#include <regex>
namespace rublon {
class Verify {};
} // namespace rublon
namespace rublon {
std::pmr::string osName(std::pmr::memory_resource *mr) {
memory::MonotonicStackResource< 8 * 1024 > stackResource;
using Params = Configuration::Parameters;
Params configValues;
std::ifstream file(std::filesystem::path{"/etc/os-release"});
if(not file.good())
return {"unknown", mr};
std::pmr::string line{&stackResource};
line.reserve(100);
while(std::getline(file, line)) {
std::pmr::string _key{&stackResource};
std::pmr::string _value{&stackResource};
if(!line.length())
continue;
if(line[0] == '#' || line[0] == ';')
continue;
auto posEqual = line.find('=');
_key = line.substr(0, posEqual);
_value = line.substr(posEqual + 1);
if(_key == "PRETTY_NAME"){
return {_value, mr};
}
}
return {"unknown", mr};
}
template < class MethodSelect_t = MethodSelect >
class Init : public AuthenticationStep< Init< MethodSelect_t > > {
using base_t = AuthenticationStep< Init< MethodSelect_t > >;
@ -33,24 +69,23 @@ class Init : public AuthenticationStep< Init< MethodSelect_t > > {
template < typename PamInfo_t >
void addParams(Document & coreRequest, const PamInfo_t & pam) const {
memory::MonotonicStackResource< 256 > stackResource;
std::pmr::string osname{&stackResource};
memory::MonotonicStackResource< 512 > stackResource;
std::pmr::string releaseInfo{&stackResource};
auto & alloc = coreRequest.GetAllocator();
const auto hasIssueFile = readFile("/etc/issue", osname);
const auto osnameTrimed = details::rtrim(hasIssueFile ? osname : "unknown");
if(not hasIssueFile) {
const auto os= osName(&stackResource);
if(os== "unknown") {
log(LogLevel::Warning, "No OS information available");
}
Value os{osnameTrimed.data(), static_cast< unsigned >(osnameTrimed.size()), alloc};
Value params{rapidjson::kObjectType};
Value osNamePretty{os.data(), static_cast< unsigned >(os.size()), alloc};
Value ip{pam.ip().get(), alloc};
Value params{rapidjson::kObjectType};
params.AddMember("userIP", ip, alloc);
params.AddMember("appVer", "v.0.0.1", alloc); /// TODO add version to cmake
params.AddMember("os", os, alloc);
params.AddMember("os", osNamePretty, alloc);
coreRequest.AddMember("params", std::move(params), alloc);
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <tl/expected.hpp>
#include <rublon/authentication_step_interface.hpp>
#include <rublon/pam.hpp>
#include <rublon/pam_action.hpp>
#include <rublon/method/websocket_based_auth.hpp>
namespace rublon::method {
class PUSH : public WebsocketBasedAuth {
public:
PUSH(std::string systemToken, std::string tid) : WebsocketBasedAuth(std::move(systemToken), std::move(tid), "PUSH") {}
};
} // namespace rublon::method

View File

@ -11,6 +11,7 @@
#include <rublon/method/OTP.hpp>
#include <rublon/method/SMS.hpp>
#include <rublon/method/PUSH.hpp>
template < class F >
struct return_type;
@ -55,7 +56,7 @@ class MethodProxy {
}
private:
std::variant< method::OTP, method::SMS > _impl;
std::variant< method::OTP, method::SMS, method::PUSH > _impl;
};
class PostMethod : public rublon::AuthenticationStep< PostMethod > {
@ -72,6 +73,8 @@ class PostMethod : public rublon::AuthenticationStep< PostMethod > {
return MethodProxy{method::OTP{this->_systemToken, std::move(tid)}};
} else if(_method == "sms") {
return MethodProxy{method::SMS{this->_systemToken, std::move(tid)}};
} else if(_method == "push"){
return MethodProxy{method::PUSH{this->_systemToken, std::move(tid)}};
}
else
@ -147,16 +150,24 @@ class MethodSelect {
if(method == "totp") {
logMethodAvailable(method);
pam.print("%d: Mobile TOTP", i + 1);
methods_id[++i] = "totp";
methods_id[++i] = method;
continue;
}
if(method == "sms") {
logMethodAvailable(method);
pam.print("%d: SMS code", i + 1);
methods_id[++i] = "sms";
methods_id[++i] = method;
continue;
}
if(method == "push" ){
logMethodAvailable(method);
pam.print("%d: Mobile PUSH", i + 1);
methods_id[++i] = method;
continue;
}
logMethodNotAvailable(method);
}
};

View File

@ -0,0 +1,36 @@
#pragma once
#include <tl/expected.hpp>
#include <rublon/authentication_step_interface.hpp>
#include <rublon/pam.hpp>
#include <rublon/pam_action.hpp>
#include <rublon/websockets.hpp>
namespace rublon::method {
class WebsocketBasedAuth : public AuthenticationStep< WebsocketBasedAuth > {
using base_t = AuthenticationStep< WebsocketBasedAuth >;
public:
const char * name = "";
WebsocketBasedAuth(std::string systemToken, std::string tid, const char * name)
: base_t(std::move(systemToken), std::move(tid)), name{name} {}
template < typename Hander_t, typename PamInfo_t = LinuxPam >
tl::expected< AuthenticationStatus, Error > handle(const CoreHandlerInterface< Hander_t > & /*coreHandler*/,
const PamInfo_t & pam) const {
log(LogLevel::Info, "starting WS");
WebSocket ws;
pam.print("Waiting for user approval");
auto aproved = ws.connect(this->_tid);
return aproved ? AuthenticationStatus{AuthenticationStatus::Action::Confirmed} :
AuthenticationStatus{AuthenticationStatus::Action::Denied};
}
};
} // namespace rublon::method

View File

@ -45,14 +45,12 @@ class LinuxPam {
void print(const char * fmt, Ti... ti) const noexcept {
log(LogLevel::Debug, fmt, std::forward< Ti >(ti)...);
pam_prompt(pamh, PAM_TEXT_INFO, nullptr, fmt, std::forward< Ti >(ti)...);
sleep(1);
}
template < typename Fun, typename... Ti >
auto scan(Fun && f, const char * fmt, Ti... ti) const noexcept {
char * response = nullptr;
pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &response, fmt, std::forward< Ti >(ti)...);
sleep(1);
if(response) {
auto ret = f(response);
free(response);

View File

@ -30,12 +30,12 @@ class RublonBase {
int authenticate() {
std::byte sharedMemory[32 * 1024] = {};
std::pmr::monotonic_buffer_resource mr{sharedMemory, std::size(sharedMemory)};
std::pmr::unsynchronized_pool_resource rublonPoolResource{&mr};
std::pmr::set_default_resource(&rublonPoolResource);
}
// int authenticate() {
// std::byte sharedMemory[32 * 1024] = {};
// std::pmr::monotonic_buffer_resource mr{sharedMemory, std::size(sharedMemory)};
// std::pmr::unsynchronized_pool_resource rublonPoolResource{&mr};
// std::pmr::set_default_resource(&rublonPoolResource);
// }
};
} // namespace rublon

View File

@ -128,15 +128,15 @@ constexpr LogLevel g_level = LogLevel::Debug;
constexpr bool syncLogFile = true;
namespace details {
constexpr const char * logPath() {
constexpr auto path = "/var/log/rublon-ssh.log";
constexpr auto path = "/tmp/rublon-ssh.log";
return path;
}
static void doLog(LogLevel level, const char * line) noexcept {
auto fp = std::unique_ptr< FILE, int (*)(FILE *) >(fopen(logPath(), "a"), fclose);
if(fp) {
///TODO add transaction ID
fprintf(fp.get(), "%s [%s] %s\n", dateStr().data(), LogLevelNames[( int ) level], line);
if(syncLogFile)
sync();

View File

@ -0,0 +1,245 @@
#pragma once
#include <rublon/utils.hpp>
#include <sio_client.h>
#include <condition_variable>
#include <mutex>
#include <thread>
namespace rublon {
#define SERVER_ADDRESS "wss://staging-core.rublon.net/ws/socket.io"
#define TIMEOUT_SECONDS 90
/// {"status":"ERROR","code":400,"result":{"exception":"MobileAppMissingException","code":32,"errorMessage":"No mobile app
/// detected","details":null}}
class WebSocketConnectionListener {
public:
enum class Status { Disconnected, Conected };
private:
sio::client & _ws;
std::mutex & _lock;
std::condition_variable_any & _cond;
bool handshake{false};
Status _status{Status::Disconnected};
public:
WebSocketConnectionListener(sio::client & ws, std::mutex & lock, std::condition_variable_any & cond)
: _ws(ws), _lock{lock}, _cond{cond} {
_ws.set_open_listener([this]() { this->on_connected(); });
_ws.set_close_listener([this](sio::client::close_reason const & reason) { this->on_close(reason); });
_ws.set_fail_listener([this]() { this->on_fail(); });
}
tl::expected< Status, bool > waitForConnection() {
std::lock_guard lock{_lock};
if(!handshake) {
log(LogLevel::Info, "Waiting for connection");
_cond.wait(_lock);
log(LogLevel::Info, "Connection OK!");
}
return _status;
}
void on_connected() {
std::unique_lock{_lock};
log(LogLevel::Info, "WebSocket connection estamblished");
handshake = true;
_status = Status::Conected;
_cond.notify_all();
}
void on_close(sio::client::close_reason const & reason) {
std::unique_lock{_lock};
log(LogLevel::Info,
"WebSocket connection %s",
reason == sio::client::close_reason::close_reason_drop ? "dropped" : "closed normally");
handshake = true;
_status = Status::Disconnected;
_cond.notify_all();
}
void on_fail() {
std::unique_lock{_lock};
log(LogLevel::Info, "WebSocket connection failed");
handshake = true;
_status = Status::Disconnected;
_cond.notify_all();
}
};
class WebSocketSingleShotEventListener {
public:
enum class Status { Approved, Denied, Expired };
private:
sio::client & _ws;
std::mutex & _lock;
std::condition_variable_any & _cond;
bool event_received = false;
Status _status{};
void printobj (std::size_t i, const std::map< std::string, sio::message::ptr > & objects) {
for(const auto &[name, msg]:objects){
log(LogLevel::Debug, "Object %ld: %s", i, name.c_str());
printMessage(i, msg);
}
};
void printMessage (std::size_t i, const sio::message::ptr & message) {
switch(message->get_flag()) {
case sio::message::flag_integer:
log(LogLevel::Debug, "message %ld integer : %d", i, message->get_int());
break;
case sio::message::flag_double:
log(LogLevel::Debug, "message %ld double : %f", i, message->get_double());
break;
case sio::message::flag_string:
log(LogLevel::Debug, "message %ld string : %s", i, message->get_string().c_str());
break;
case sio::message::flag_binary:
log(LogLevel::Debug, "message %ld binary : %s", i, message->get_binary()->c_str());
break;
case sio::message::flag_array:
log(LogLevel::Debug, "message %ld array : blah", i);
break;
case sio::message::flag_object:
log(LogLevel::Debug, "message %ld object : obj ->", i);
printobj(i, message->get_map());
break;
case sio::message::flag_boolean:
log(LogLevel::Debug, "message %ld bool : %s", i, message->get_bool() ? "yes" : "no");
break;
case sio::message::flag_null:
log(LogLevel::Debug, "message %ld NULL", i);
break;
default:
log(LogLevel::Info, "Message with unknown type");
}
};
void generic(sio::event & e, Status status) {
std::lock_guard lock{_lock};
event_received = true;
_status = status;
log(LogLevel::Debug, "event name : %s", e.get_name().c_str());
log(LogLevel::Debug, "event nsp : %s", e.get_nsp().c_str());
log(LogLevel::Debug, "event messages: %d", e.get_messages().size());
for(std::size_t i = 0; i < e.get_messages().size(); i++) {
const auto & message = e.get_messages().at(i);
printMessage(i, message);
}
_cond.notify_all();
}
void onConfirmed(sio::event & e) {
generic(e, Status::Approved);
log(LogLevel::Info, "Autentication confirmed over PUSH");
}
void onDenied(sio::event & e) {
generic(e, Status::Denied);
log(LogLevel::Info, "Autentication denied by user");
sleep(30);
}
void onExpired(sio::event & e) {
generic(e, Status::Expired);
log(LogLevel::Error, "Autentication call expierd");
}
void onErrorEvent(sio::message::ptr const & message) {
std::lock_guard lock{_lock};
event_received = true;
log(LogLevel::Error, "Error: %s", message->get_string().c_str());
_cond.notify_all();
}
void onAny(sio::event & e) {
std::lock_guard lock{_lock};
event_received = true;
log(LogLevel::Info, "name %s", e.get_name().c_str());
_cond.notify_all();
}
public:
WebSocketSingleShotEventListener(sio::client & ws, std::mutex & lock, std::condition_variable_any & cond)
: _ws{ws}, _lock{lock}, _cond{cond} {
_ws.socket()->on("transactionConfirmed", [this](sio::event & e) { this->onConfirmed(e); });
_ws.socket()->on("transactionDenied", [this](sio::event & e) { this->onDenied(e); });
_ws.socket()->on("transactionExpired", [this](sio::event & e) { this->onExpired(e); });
_ws.socket()->on_error([this](sio::message::ptr const & message) { this->onErrorEvent(message); });
_ws.socket()->on_any([this](sio::event & e) { this->onAny(e); });
}
tl::expected< Status, bool > waitForEvent() {
std::lock_guard lock{_lock};
if(!event_received) {
log(LogLevel::Info, "Waiting for confirmation");
if(_cond.wait_until(_lock, std::chrono::system_clock::now() + std::chrono::minutes{2}) == std::cv_status::timeout) {
log(LogLevel::Info, "Waiting for confirmation failed due to WS timeout");
}
}
return _status;
}
};
class WebSocket {
sio::client ws;
public:
std::string token;
WebSocket() {}
~WebSocket() {}
bool connect(std::string _token) {
std::mutex _lock;
std::condition_variable_any _cond;
token = _token;
// ws.set_logs_verbose();
log(LogLevel::Debug, "start listening");
ws.connect("wss://staging-core.rublon.net/ws/socket.io/");
const auto attachToTransactionConfirmationChannel = [&](const auto & status) -> tl::expected< bool, bool > {
/// TODO check status
auto message = std::dynamic_pointer_cast< sio::object_message >(sio::object_message::create());
message->insert("channel", "transactionConfirmation." + _token);
ws.socket()->emit("subscribe", {message});
return true; /// TODO
};
const auto waitForUserAction = [&](const auto & connected) -> tl::expected< WebSocketSingleShotEventListener::Status, bool > {
WebSocketSingleShotEventListener eventListener{ws, _lock, _cond};
return eventListener.waitForEvent();
};
WebSocketConnectionListener l(ws, _lock, _cond);
auto v = l.waitForConnection() //
.and_then(attachToTransactionConfirmationChannel)
.and_then(waitForUserAction)
.value_or(WebSocketSingleShotEventListener::Status::Denied);
return v == WebSocketSingleShotEventListener::Status::Approved;
}
void listen() {}
};
} // namespace rublon

View File

@ -31,13 +31,27 @@ target_link_libraries(rublon-ssh-pam
-lcurl
-lssl
-lcrypto
-lsioclient_tls
)
execute_process (
COMMAND bash -c "awk -F= '/^ID=/{print $2}' /etc/os-release |tr -d '\n' | tr -d '\"'"
OUTPUT_VARIABLE outOS
)
if(${outOS} MATCHES "centos|rhel" )
message(INFO "detected rhen base system")
set(_destination /usr/lib64/security/)
elseif(${outOS} MATCHES "debian|ubuntu")
message(INFO "detected debian based system")
set(_destination /usr/lib/x86_64-linux-gnu/security/)
endif()
install(
TARGETS
rublon-ssh-pam
DESTINATION
/usr/lib/x86_64-linux-gnu/security/
${_destination}
COMPONENT
PAM
)

View File

@ -3,6 +3,7 @@
#include <security/pam_ext.h>
#include <security/pam_misc.h>
#include <security/pam_modules.h>
#include <syslog.h>
#include <rublon/init.hpp>
#include <rublon/json.hpp>
@ -12,8 +13,6 @@
#define DLL_PUBLIC __attribute__((visibility("default")))
using namespace std;
DLL_PUBLIC int pam_sm_setcred([[maybe_unused]] pam_handle_t * pamh,
[[maybe_unused]] int flags,
[[maybe_unused]] int argc,
@ -32,6 +31,10 @@ DLL_PUBLIC int
pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unused]] int argc, [[maybe_unused]] const char ** argv) {
using namespace rublon;
rublon::log(LogLevel::Debug, "flags: {%d}, argc: {%d}", flags, argc);
// std::freopen(rublon::details::logPath(), "a+", stdout);
// std::freopen(rublon::details::logPath(), "a+", stderr);
LinuxPam pam{pamh};
auto rublonConfig = ConfigurationFactory{}.systemConfig();
@ -72,22 +75,20 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu
pam.print("\n RUBLON authentication bypased");
return PAM_SUCCESS;
}
if(error.is< HttpError >()){
if(error.is< HttpError >()) {
pam.print("\n RUBLON server unavalible");
if(rublonConfig->parameters.bypass ){
if(rublonConfig->parameters.bypass) {
pam.print("\n RUBLON authentication bypased");
return PAM_SUCCESS;
}
else{
} else {
pam.print("RUBLON authentication FAILED");
return PAM_MAXTRIES;
}
}
if(error.is<CoreHandlerError>()){
pam.print("\n RUBLON server returned '%s' exception",
error.get<CoreHandlerError>().reson.c_str());
if(error.is< CoreHandlerError >()) {
pam.print("\n RUBLON server returned '%s' exception", error.get< CoreHandlerError >().reson.c_str());
}
pam.print("RUBLON authentication FAILED");
rublon::log(LogLevel::Warning, "User login failed");

View File

@ -44,4 +44,7 @@ static constexpr const char * result_broken_template = //
static constexpr const char * wrongPasscode = //
R"json({"status":"OK","result":{"error":"Hmm, that's not the right code. Try again."}})json";
static constexpr const char * projectError =
R"json({"status":"ERROR","code":400,"result":{"exception":"APIException","code":10,"errorMessage":"Project error","details":null}})json";
} // namespace

View File

@ -15,7 +15,7 @@ Vagrant.configure("2") do |config|
# Bridged networks make the machine appear as another physical device on
# your network.
config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
@ -36,7 +36,18 @@ Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: <<-SHELL
yum update
yum install -y gcc openssl-devel curl-devel pam-devel git rapidjson-devel cmake
yum install -y gcc openssl-devel curl-devel pam-devel git rapidjson-devel cmake policycoreutils-devel checkpolicy
# get dependencies
git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git
mkdir socket.io-client-cpp/build; cd socket.io-client-cpp/build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target install
#handle semodule
cd /home/vagrant/Rublon-Linux/service
checkmodule -M -m -o login_rublon.mod login_rublon.te
semodule_package -o login_rublon.pp -m login_rublon.mod
# Build project
cd /home/vagrant/Rublon-Linux
@ -46,11 +57,18 @@ Vagrant.configure("2") do |config|
sudo cmake --install build
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
#handle semodule
cd /home/vagrant/Rublon-Linux/service
semodule -i login_rublon.pp
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
#grep -q -e '#auth substack password-auth' /etc/pam.d/sshd || sed -i -e 's/auth substack password-auth/#auth substack password-auth/g' /etc/pam.d/sshd
#grep -q -e 'auth requisite pam_unix.so' /etc/pam.d/sshd || sed -i '\$aauth requisite pam_unix.so' /etc/pam.d/sshd
#grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
#grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
systemctl restart sshd.service
SHELL

View File

@ -23,6 +23,8 @@ Vagrant.configure("2") do |config|
config.vm.synced_folder "../../..", "/home/vagrant/Rublon-Linux"
config.vm.provider "virtualbox" do |vb|
vb.memory = 1024
vb.cpus = 4
# Display the VirtualBox GUI when booting the machine
vb.gui = true
@ -47,6 +49,12 @@ Vagrant.configure("2") do |config|
rapidjson-dev \
cmake
# get dependencies
git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git
mkdir socket.io-client-cpp/build; cd socket.io-client-cpp/build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target install
# Build project
cd /home/vagrant/Rublon-Linux
cmake -B build && cmake --build build
@ -56,11 +64,21 @@ Vagrant.configure("2") do |config|
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
SSHD_CONF=/etc/ssh/sshd_config
SSHD_PAM_CONF=/etc/pam.d/sshd
grep -qe "^PasswordAuthentication" $SSHD_CONF && sed -i 's/^#*PasswordAuthentication[[:space:]]\+.*/PasswordAuthentication yes/' $SSHD_CONF || echo "PasswordAuthentication yes" >> $SSHD_CONF
grep -qe "^ChallengeResponseAuthentication" $SSHD_CONF && sed -i 's/^#*ChallengeResponseAuthentication[[:space:]]\+.*/ChallengeResponseAuthentication yes/' $SSHD_CONF || echo "ChallengeResponseAuthentication yes" >> $SSHD_CONF
grep -qe "^UsePAM" $SSHD_CONF && sed -i 's/^#*UsePAM[[:space:]]\+.*/UsePAM yes/' $SSHD_CONF || echo "UsePAM yes" >> $SSHD_CONF
grep -qe 'auth required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aauth required pam_rublon.so' $SSHD_PAM_CONF
grep -qe 'account required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aaccount required pam_rublon.so' $SSHD_PAM_CONF
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
service sshd restart
SHELL
config.vm.provision "file", source: "/etc/rublon.config", destination: "/etc/rublon.config"
end

View File

@ -56,10 +56,18 @@ Vagrant.configure("2") do |config|
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
SSHD_CONF=/etc/ssh/sshd_config
SSHD_PAM_CONF=/etc/pam.d/sshd
grep -qe "^PasswordAuthentication" $SSHD_CONF && sed -i 's/^#*PasswordAuthentication[[:space:]]\+.*/PasswordAuthentication yes/' $SSHD_CONF || echo "PasswordAuthentication yes" >> $SSHD_CONF
grep -qe "^ChallengeResponseAuthentication" $SSHD_CONF && sed -i 's/^#*ChallengeResponseAuthentication[[:space:]]\+.*/ChallengeResponseAuthentication yes/' $SSHD_CONF || echo "ChallengeResponseAuthentication yes" >> $SSHD_CONF
grep -qe "^UsePAM" $SSHD_CONF && sed -i 's/^#*UsePAM[[:space:]]\+.*/UsePAM yes/' $SSHD_CONF || echo "UsePAM yes" >> $SSHD_CONF
grep -qe 'auth required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aauth required pam_rublon.so' $SSHD_PAM_CONF
grep -qe 'account required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aaccount required pam_rublon.so' $SSHD_PAM_CONF
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
service sshd restart
end

79
os/rhel/9/Vagrantfile vendored Executable file
View File

@ -0,0 +1,79 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Default user
# ----------------------
# login: vagrant
# pass: vagrant
Vagrant.configure("2") do |config|
# Basic configuration
config.vm.provider "virtualbox"
config.vm.box = "generic/rhel9"
config.ssh.forward_agent = true
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
config.vm.synced_folder "../../..", "/home/vagrant/Rublon-Linux"
config.vm.provider "virtualbox" do |vb|
vb.memory = 1024
vb.cpus = 4
# Display the VirtualBox GUI when booting the machine
vb.gui = true
# Fix for 'SSH auth method: Private key' stuck
vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
end
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision "shell", inline: <<-SHELL
yum update
yum install -y gcc openssl-devel curl-devel pam-devel git rapidjson-devel cmake
# get dependencies
git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git
mkdir socket.io-client-cpp/build; cd socket.io-client-cpp/build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target install
#handle semodule
cd /home/vagrant/Rublon-Linux/service
checkmodule -M -m -o login_rublon.mod login_rublon.te
semodule_package -o login_rublon.pp -m login_rublon.mod
# Build project
cd /home/vagrant/Rublon-Linux
cmake -B build && cmake --build build
# Install
sudo cmake --install build
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
#handle semodule
cd /home/vagrant/Rublon-Linux/service
semodule -i login_rublon.pp
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
systemctl restart sshd.service
SHELL
config.vm.provision "file", source: "/etc/rublon.config", destination: "/etc/rublon.config"
end

View File

@ -46,6 +46,12 @@ Vagrant.configure("2") do |config|
git \
rapidjson-dev \
cmake
# get dependencies
git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git
mkdir socket.io-client-cpp/build; cd socket.io-client-cpp/build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target install
# Build project
cd /home/vagrant/Rublon-Linux
@ -56,10 +62,18 @@ Vagrant.configure("2") do |config|
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
SSHD_CONF=/etc/ssh/sshd_config
SSHD_PAM_CONF=/etc/pam.d/sshd
grep -qe "^PasswordAuthentication" $SSHD_CONF && sed -i 's/^#*PasswordAuthentication[[:space:]]\+.*/PasswordAuthentication yes/' $SSHD_CONF || echo "PasswordAuthentication yes" >> $SSHD_CONF
grep -qe "^ChallengeResponseAuthentication" $SSHD_CONF && sed -i 's/^#*ChallengeResponseAuthentication[[:space:]]\+.*/ChallengeResponseAuthentication yes/' $SSHD_CONF || echo "ChallengeResponseAuthentication yes" >> $SSHD_CONF
grep -qe "^UsePAM" $SSHD_CONF && sed -i 's/^#*UsePAM[[:space:]]\+.*/UsePAM yes/' $SSHD_CONF || echo "UsePAM yes" >> $SSHD_CONF
grep -qe 'auth required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aauth required pam_rublon.so' $SSHD_PAM_CONF
grep -qe 'account required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aaccount required pam_rublon.so' $SSHD_PAM_CONF
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
service sshd restart
SHELL

View File

@ -47,6 +47,12 @@ Vagrant.configure("2") do |config|
rapidjson-dev \
cmake
# get dependencies
git clone --recurse-submodules https://github.com/socketio/socket.io-client-cpp.git
mkdir socket.io-client-cpp/build; cd socket.io-client-cpp/build
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target install
# Build project
cd /home/vagrant/Rublon-Linux
cmake -B build && cmake --build build
@ -56,10 +62,18 @@ Vagrant.configure("2") do |config|
sudo install -m 644 rsc/rublon.config.defaults /etc/rublon.config
# Register Rublon pam
sed -i 's/UsePAM .*/UsePAM yes/' /etc/ssh/sshd_config
sed -i 's/ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' /etc/ssh/sshd_config
grep -q -e 'auth required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aauth required pam_rublon.so' /etc/pam.d/sshd
grep -q -e 'account required pam_rublon.so' /etc/pam.d/sshd || sed -i '\$aaccount required pam_rublon.so' /etc/pam.d/sshd
SSHD_CONF=/etc/ssh/sshd_config
SSHD_PAM_CONF=/etc/pam.d/sshd
grep -qe "^PasswordAuthentication" $SSHD_CONF && sed -i 's/^#*PasswordAuthentication[[:space:]]\+.*/PasswordAuthentication yes/' $SSHD_CONF || echo "PasswordAuthentication yes" >> $SSHD_CONF
grep -qe "^ChallengeResponseAuthentication" $SSHD_CONF && sed -i 's/^#*ChallengeResponseAuthentication[[:space:]]\+.*/ChallengeResponseAuthentication yes/' $SSHD_CONF || echo "ChallengeResponseAuthentication yes" >> $SSHD_CONF
grep -qe "^UsePAM" $SSHD_CONF && sed -i 's/^#*UsePAM[[:space:]]\+.*/UsePAM yes/' $SSHD_CONF || echo "UsePAM yes" >> $SSHD_CONF
grep -qe 'auth required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aauth required pam_rublon.so' $SSHD_PAM_CONF
grep -qe 'account required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aaccount required pam_rublon.so' $SSHD_PAM_CONF
useradd -s /bin/bash -m bwi
echo "bwi:bwi"|chpasswd
service sshd restart
SHELL

View File

@ -29,6 +29,9 @@ set(CPACK_DEB_COMPONENT_INSTALL YES)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS YES)
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libcurl(>= 7.0.0), libc(>= 2.0)")
# set(CPACK_DEBIAN_DEV_PACKAGE_DEPENDS "libcurl4(>= 7.0.0), libc(>= 2.0)")
# set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcurl4(>= 7.0.0), libc(>= 2.0)")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/service/postinst")
include(CPack)

BIN
service/login_rublon.mod Normal file

Binary file not shown.

BIN
service/login_rublon.pp Normal file

Binary file not shown.

12
service/login_rublon.te Normal file
View File

@ -0,0 +1,12 @@
module login_rublon 1.0;
require {
type http_port_t;
type soundd_port_t;
type http_cache_port_t;
type sshd_t;
type unreserved_port_t;
class tcp_socket name_connect;
class udp_socket name_bind;
};
allow sshd_t {http_port_t http_cache_port_t soundd_port_t}:tcp_socket name_connect;
allow sshd_t {unreserved_port_t}:udp_socket name_bind;

27
service/postinst Normal file
View File

@ -0,0 +1,27 @@
#!/bin/bash
if [ ! -f /etc/rublon/rublon.config ]
then
mkdir -p /etc/rublon
cp -a /usr/share/rublon/rublon.config.defaults /etc/rublon/rublon.config
fi
# get system id
. /etc/os-release
SSHD_CONF=/etc/ssh/sshd_config
SSHD_PAM_CONF=/etc/pam.d/sshd
grep -qe "^PasswordAuthentication" $SSHD_CONF && \
sed -i 's/^#*PasswordAuthentication[[:space:]]\+.*/PasswordAuthentication yes/' $SSHD_CONF || \
echo "PasswordAuthentication yes" >> $SSHD_CONF
grep -qe "^ChallengeResponseAuthentication" $SSHD_CONF && \
sed -i 's/^#*ChallengeResponseAuthentication[[:space:]]\+.*/ChallengeResponseAuthentication yes/' $SSHD_CONF || \
echo "ChallengeResponseAuthentication yes" >> $SSHD_CONF
grep -qe "^UsePAM" $SSHD_CONF && \
sed -i 's/^#*UsePAM[[:space:]]\+.*/UsePAM yes/' $SSHD_CONF || \
echo "UsePAM yes" >> $SSHD_CONF
grep -qe 'auth required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aauth required pam_rublon.so' $SSHD_PAM_CONF
grep -qe 'account required pam_rublon.so' $SSHD_PAM_CONF || sed -i '\$aaccount required pam_rublon.so' $SSHD_PAM_CONF