all Ref to support uprefable types
This commit is contained in:
parent
f5b49ebf66
commit
5801a5404a
@ -47,7 +47,7 @@ add_executable(xbot
|
||||
client.cpp
|
||||
connection.cpp
|
||||
ircmsg.cpp
|
||||
openssl_errors.cpp
|
||||
openssl_utils.cpp
|
||||
registration.cpp
|
||||
sasl_mechanism.cpp
|
||||
settings.cpp
|
||||
|
@ -1,8 +1,9 @@
|
||||
#include "challenge.hpp"
|
||||
|
||||
#include "openssl_errors.hpp"
|
||||
#include "openssl_utils.hpp"
|
||||
|
||||
#include <mybase64.hpp>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
@ -16,13 +17,6 @@ Challenge::Challenge(EVP_PKEY_Ref key, Connection & connection)
|
||||
, connection_{connection}
|
||||
{}
|
||||
|
||||
|
||||
auto Challenge::stop() -> void
|
||||
{
|
||||
slot_.disconnect();
|
||||
buffer_.clear();
|
||||
}
|
||||
|
||||
auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
||||
switch (cmd) {
|
||||
default: break;
|
||||
@ -30,42 +24,56 @@ auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
||||
buffer_ += msg.args[1];
|
||||
break;
|
||||
case IrcCommand::ERR_NOOPERHOST:
|
||||
slot_.disconnect();
|
||||
BOOST_LOG_TRIVIAL(error) << "Challenge: No oper host";
|
||||
stop();
|
||||
break;
|
||||
case IrcCommand::RPL_YOUREOPER:
|
||||
slot_.disconnect();
|
||||
BOOST_LOG_TRIVIAL(error) << "Challenge: Already oper";
|
||||
stop();
|
||||
break;
|
||||
case IrcCommand::RPL_ENDOFRSACHALLENGE2:
|
||||
{
|
||||
slot_.disconnect();
|
||||
finish_challenge();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto Challenge::finish_challenge() -> void
|
||||
{
|
||||
EVP_PKEY_CTX_Ref ctx;
|
||||
unsigned int digestlen = EVP_MAX_MD_SIZE;
|
||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||
size_t len = mybase64::decoded_size(buffer_.size());
|
||||
std::vector<unsigned char> ciphertext(len, 0);
|
||||
|
||||
if (not mybase64::decode(buffer_, reinterpret_cast<char*>(ciphertext.data()), &len)) goto error;
|
||||
if (not mybase64::decode(buffer_, reinterpret_cast<char*>(ciphertext.data()), &len))
|
||||
return log_openssl_errors("Challenge base64::decode: ");
|
||||
ciphertext.resize(len);
|
||||
|
||||
// Setup decryption context
|
||||
ctx.reset(EVP_PKEY_CTX_new(key_.get(), nullptr));
|
||||
if (ctx.get() == nullptr) goto error;
|
||||
if (1 != EVP_PKEY_decrypt_init(ctx.get())) goto error;
|
||||
if (0 >= EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING)) goto error;
|
||||
if (ctx.get() == nullptr)
|
||||
return log_openssl_errors("Challenge EVP_PKEY_CTX_new: ");
|
||||
|
||||
if (1 != EVP_PKEY_decrypt_init(ctx.get()))
|
||||
return log_openssl_errors("Challenge EVP_PKEY_decrypt_init: ");
|
||||
|
||||
if (0 >= EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING))
|
||||
return log_openssl_errors("Challenge EVP_PKEY_CTX_set_rsa_padding: ");
|
||||
|
||||
// Determine output size
|
||||
if (1 != EVP_PKEY_decrypt(ctx.get(), nullptr, &len, ciphertext.data(), ciphertext.size())) goto error;
|
||||
if (1 != EVP_PKEY_decrypt(ctx.get(), nullptr, &len, ciphertext.data(), ciphertext.size()))
|
||||
return log_openssl_errors("Challenge EVP_PKEY_decrypt (size): ");
|
||||
buffer_.resize(len);
|
||||
|
||||
// Decrypt ciphertext
|
||||
if (1 != EVP_PKEY_decrypt(ctx.get(), reinterpret_cast<unsigned char*>(buffer_.data()), &len, ciphertext.data(), ciphertext.size())) goto error;
|
||||
if (1 != EVP_PKEY_decrypt(ctx.get(), reinterpret_cast<unsigned char*>(buffer_.data()), &len, ciphertext.data(), ciphertext.size()))
|
||||
return log_openssl_errors("Challenge EVP_PKEY_decrypt: ");
|
||||
buffer_.resize(len);
|
||||
|
||||
// Hash the decrypted message
|
||||
if (1 != EVP_Digest(buffer_.data(), buffer_.size(), digest, &digestlen, EVP_sha1(), nullptr)) goto error;
|
||||
if (1 != EVP_Digest(buffer_.data(), buffer_.size(), digest, &digestlen, EVP_sha1(), nullptr))
|
||||
return log_openssl_errors("Challenge EVP_Digest: ");
|
||||
|
||||
// Construct reply as '+' and base64 encoded digest
|
||||
buffer_.resize(mybase64::encoded_size(digestlen) + 1);
|
||||
@ -73,13 +81,8 @@ auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
||||
mybase64::encode(std::string_view{(char*)digest, digestlen}, buffer_.data() + 1);
|
||||
|
||||
connection_.send_challenge(buffer_);
|
||||
return;
|
||||
|
||||
error:
|
||||
log_openssl_errors("Challenge: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
connection_.send_ping("oper_up mitigation");
|
||||
}
|
||||
|
||||
auto Challenge::start(Connection &connection, const std::string_view user, EVP_PKEY_Ref ref) -> std::shared_ptr<Challenge>
|
||||
{
|
||||
|
@ -16,9 +16,9 @@ class Challenge : std::enable_shared_from_this<Challenge>
|
||||
std::string buffer_;
|
||||
|
||||
auto on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void;
|
||||
auto finish_challenge() -> void;
|
||||
|
||||
public:
|
||||
Challenge(EVP_PKEY_Ref, Connection &);
|
||||
auto stop() -> void;
|
||||
static auto start(Connection &, std::string_view user, EVP_PKEY_Ref) -> std::shared_ptr<Challenge>;
|
||||
};
|
||||
|
76
main.cpp
76
main.cpp
@ -1,9 +1,8 @@
|
||||
#include "bot.hpp"
|
||||
#include "c_callback.hpp"
|
||||
#include "challenge.hpp"
|
||||
#include "client.hpp"
|
||||
#include "connection.hpp"
|
||||
#include "openssl_errors.hpp"
|
||||
#include "openssl_utils.hpp"
|
||||
#include "registration.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "irc_coroutine.hpp"
|
||||
@ -13,58 +12,12 @@
|
||||
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
static auto cert_from_file(const std::string &filename) -> X509_Ref
|
||||
{
|
||||
X509_Ref cert;
|
||||
if (const auto fp = fopen(filename.c_str(), "r"))
|
||||
{
|
||||
cert.reset(PEM_read_X509(fp, nullptr, nullptr, nullptr));
|
||||
if (cert.get() == nullptr)
|
||||
{
|
||||
log_openssl_errors("Reading certificate: "sv);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto err = strerror(errno);
|
||||
BOOST_LOG_TRIVIAL(error) << "Opening certificate: " << err;
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
|
||||
static auto key_from_file(const std::string &filename, const std::string_view password) -> EVP_PKEY_Ref
|
||||
{
|
||||
EVP_PKEY_Ref key;
|
||||
if (const auto fp = fopen(filename.c_str(), "r"))
|
||||
{
|
||||
auto cb = [password](char * const buf, int const size, int) -> int {
|
||||
if (size < password.size()) { return -1; }
|
||||
std::copy(password.begin(), password.end(), buf);
|
||||
return password.size();
|
||||
};
|
||||
|
||||
key.reset(PEM_read_PrivateKey(fp, nullptr, CCallback<decltype(cb)>::invoke, &cb));
|
||||
if (key.get() == nullptr)
|
||||
{
|
||||
log_openssl_errors("Reading private key: "sv);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto err = strerror(errno);
|
||||
BOOST_LOG_TRIVIAL(error) << "Opening private key: " << err;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
||||
{
|
||||
@ -86,30 +39,13 @@ static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
||||
|
||||
const auto bot = Bot::start(client);
|
||||
|
||||
/*
|
||||
connection->sig_snote.connect([](auto &match) {
|
||||
std::cout << "SNOTE " << static_cast<int>(match.get_tag()) << std::endl;
|
||||
for (auto c : match.get_results())
|
||||
{
|
||||
std::cout << " " << std::string_view{c.first, c.second} << std::endl;
|
||||
}
|
||||
if (not settings.challenge_username.empty() && not settings.challenge_key_file.empty()) {
|
||||
if (auto key = key_from_file(settings.challenge_key_file, settings.challenge_key_password)) {
|
||||
client->sig_registered.connect([&settings, connection, key = std::move(key)]() {
|
||||
Challenge::start(*connection, settings.challenge_username, key);
|
||||
});
|
||||
*/
|
||||
client->sig_registered.connect([&settings, connection, client]() {
|
||||
connection->send_join("##glguy"sv);
|
||||
connection->send_whois(client->get_my_nick());
|
||||
|
||||
if (not settings.challenge_username.empty() &&
|
||||
not settings.challenge_key_file.empty()) {
|
||||
auto key = key_from_file(settings.challenge_key_file, settings.challenge_key_password);
|
||||
Challenge::start(*connection, settings.challenge_username, std::move(key));
|
||||
}
|
||||
});
|
||||
|
||||
client->sig_chat.connect([client, connection](const Chat &chat){
|
||||
if (chat.source.starts_with("glguy!") && client->is_my_nick(chat.target)) {
|
||||
connection->send_notice("glguy", chat.message);
|
||||
}});
|
||||
}
|
||||
|
||||
connection->sig_disconnect.connect(
|
||||
[&io, &settings, client, bot]() {
|
||||
|
@ -1,14 +0,0 @@
|
||||
#include "openssl_errors.hpp"
|
||||
|
||||
#include "c_callback.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
auto log_openssl_errors(const std::string_view prefix) -> void
|
||||
{
|
||||
auto err_cb = [prefix](const char *str, size_t len) -> int {
|
||||
BOOST_LOG_TRIVIAL(error) << prefix << std::string_view{str, len};
|
||||
return 0;
|
||||
};
|
||||
ERR_print_errors_cb(CCallback<decltype(err_cb)>::invoke, &err_cb);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
auto log_openssl_errors(const std::string_view prefix) -> void;
|
42
ref.hpp
42
ref.hpp
@ -5,14 +5,40 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
template <typename T, void Free(T*)>
|
||||
struct FnDeleter {
|
||||
auto operator()(T *ptr) const -> void { Free(ptr); }
|
||||
template <typename> struct RefTraits {};
|
||||
|
||||
template <> struct RefTraits<EVP_PKEY> {
|
||||
static constexpr void (*Free)(EVP_PKEY*) = EVP_PKEY_free;
|
||||
static constexpr int (*UpRef)(EVP_PKEY*) = EVP_PKEY_up_ref;
|
||||
};
|
||||
|
||||
template <typename T, void(Free)(T*)>
|
||||
using Ref = std::unique_ptr<T, FnDeleter<T, Free>>;
|
||||
template <> struct RefTraits<X509> {
|
||||
static constexpr void (*Free)(X509*) = X509_free;
|
||||
static constexpr int (*UpRef)(X509*) = X509_up_ref;
|
||||
};
|
||||
|
||||
using EVP_PKEY_CTX_Ref = Ref<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||
using X509_Ref = Ref<X509, X509_free>;
|
||||
using EVP_PKEY_Ref = Ref<EVP_PKEY, EVP_PKEY_free>;
|
||||
template <> struct RefTraits<EVP_PKEY_CTX> {
|
||||
static constexpr void (*Free)(EVP_PKEY_CTX*) = EVP_PKEY_CTX_free;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FnDeleter {
|
||||
auto operator()(T *ptr) const -> void { RefTraits<T>::Free(ptr); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Ref : std::unique_ptr<T, FnDeleter<T>> {
|
||||
using std::unique_ptr<T, FnDeleter<T>>::unique_ptr;
|
||||
Ref(const Ref &ref) {
|
||||
*this = ref;
|
||||
}
|
||||
Ref &operator=(const Ref &ref) {
|
||||
RefTraits<T>::UpRef(ref.get());
|
||||
this->reset(ref.get());
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using EVP_PKEY_CTX_Ref = Ref<EVP_PKEY_CTX>;
|
||||
using X509_Ref = Ref<X509>;
|
||||
using EVP_PKEY_Ref = Ref<EVP_PKEY>;
|
||||
|
Loading…
x
Reference in New Issue
Block a user