mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-22 13:14:32 +02:00
parent
3fd20d56aa
commit
f433679b13
@ -6,4 +6,6 @@ object ApiListener "api" {
|
|||||||
cert_path = SysconfDir + "/icinga2/pki/" + NodeName + ".crt"
|
cert_path = SysconfDir + "/icinga2/pki/" + NodeName + ".crt"
|
||||||
key_path = SysconfDir + "/icinga2/pki/" + NodeName + ".key"
|
key_path = SysconfDir + "/icinga2/pki/" + NodeName + ".key"
|
||||||
ca_path = SysconfDir + "/icinga2/pki/ca.crt"
|
ca_path = SysconfDir + "/icinga2/pki/ca.crt"
|
||||||
|
|
||||||
|
//ticket_salt = "<secret key>"
|
||||||
}
|
}
|
||||||
|
@ -918,7 +918,7 @@ void Application::DeclareLocalStateDir(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetZonesDir(void)
|
String Application::GetZonesDir(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("ZonesDir");
|
return ScriptVariable::Get("ZonesDir", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -938,7 +938,8 @@ void Application::DeclareZonesDir(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetPkgDataDir(void)
|
String Application::GetPkgDataDir(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("PkgDataDir");
|
String defaultValue = "";
|
||||||
|
return ScriptVariable::Get("PkgDataDir", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -958,7 +959,7 @@ void Application::DeclarePkgDataDir(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetIncludeConfDir(void)
|
String Application::GetIncludeConfDir(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("IncludeConfDir");
|
return ScriptVariable::Get("IncludeConfDir", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -978,7 +979,7 @@ void Application::DeclareIncludeConfDir(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetStatePath(void)
|
String Application::GetStatePath(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("StatePath");
|
return ScriptVariable::Get("StatePath", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -998,7 +999,7 @@ void Application::DeclareStatePath(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetObjectsPath(void)
|
String Application::GetObjectsPath(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("ObjectsPath");
|
return ScriptVariable::Get("ObjectsPath", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1018,7 +1019,7 @@ void Application::DeclareObjectsPath(const String& path)
|
|||||||
*/
|
*/
|
||||||
String Application::GetPidPath(void)
|
String Application::GetPidPath(void)
|
||||||
{
|
{
|
||||||
return ScriptVariable::Get("PidPath");
|
return ScriptVariable::Get("PidPath", &Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,12 +51,16 @@ Value ScriptVariable::GetData(void) const
|
|||||||
return m_Data;
|
return m_Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ScriptVariable::Get(const String& name)
|
Value ScriptVariable::Get(const String& name, const Value *defaultValue)
|
||||||
{
|
{
|
||||||
ScriptVariable::Ptr sv = GetByName(name);
|
ScriptVariable::Ptr sv = GetByName(name);
|
||||||
|
|
||||||
if (!sv)
|
if (!sv) {
|
||||||
|
if (defaultValue)
|
||||||
|
return *defaultValue;
|
||||||
|
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Tried to access undefined script variable '" + name + "'"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("Tried to access undefined script variable '" + name + "'"));
|
||||||
|
}
|
||||||
|
|
||||||
return sv->GetData();
|
return sv->GetData();
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
static ScriptVariable::Ptr GetByName(const String& name);
|
static ScriptVariable::Ptr GetByName(const String& name);
|
||||||
static void Unregister(const String& name);
|
static void Unregister(const String& name);
|
||||||
|
|
||||||
static Value Get(const String& name);
|
static Value Get(const String& name, const Value *defaultValue = NULL);
|
||||||
static ScriptVariable::Ptr Set(const String& name, const Value& value, bool overwrite = true, bool make_const = false);
|
static ScriptVariable::Ptr Set(const String& name, const Value& value, bool overwrite = true, bool make_const = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -161,6 +161,14 @@ size_t TlsStream::Read(void *buffer, size_t count)
|
|||||||
std::ostringstream msgbuf;
|
std::ostringstream msgbuf;
|
||||||
char errbuf[120];
|
char errbuf[120];
|
||||||
|
|
||||||
|
bool want_read;
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||||
|
want_read = SSL_want_read(m_SSL.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (want_read)
|
||||||
m_Socket->Poll(true, false);
|
m_Socket->Poll(true, false);
|
||||||
|
|
||||||
boost::mutex::scoped_lock alock(m_IOActionLock);
|
boost::mutex::scoped_lock alock(m_IOActionLock);
|
||||||
@ -213,6 +221,14 @@ void TlsStream::Write(const void *buffer, size_t count)
|
|||||||
std::ostringstream msgbuf;
|
std::ostringstream msgbuf;
|
||||||
char errbuf[120];
|
char errbuf[120];
|
||||||
|
|
||||||
|
bool want_write;
|
||||||
|
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(m_SSLLock);
|
||||||
|
want_write = SSL_want_write(m_SSL.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (want_write)
|
||||||
m_Socket->Poll(false, true);
|
m_Socket->Poll(false, true);
|
||||||
|
|
||||||
boost::mutex::scoped_lock alock(m_IOActionLock);
|
boost::mutex::scoped_lock alock(m_IOActionLock);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "base/convert.hpp"
|
#include "base/convert.hpp"
|
||||||
#include "base/logger_fwd.hpp"
|
#include "base/logger_fwd.hpp"
|
||||||
#include "base/context.hpp"
|
#include "base/context.hpp"
|
||||||
|
#include "base/application.hpp"
|
||||||
|
|
||||||
namespace icinga
|
namespace icinga
|
||||||
{
|
{
|
||||||
@ -110,6 +111,7 @@ shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& privkey,
|
|||||||
<< errinfo_openssl_error(ERR_peek_error()));
|
<< errinfo_openssl_error(ERR_peek_error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cakey.IsEmpty()) {
|
||||||
if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) {
|
if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.CStr(), NULL)) {
|
||||||
msgbuf << "Error loading and verifying locations in ca key file '" << cakey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
msgbuf << "Error loading and verifying locations in ca key file '" << cakey << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
Log(LogCritical, "SSL", msgbuf.str());
|
||||||
@ -132,6 +134,7 @@ shared_ptr<SSL_CTX> MakeSSLContext(const String& pubkey, const String& privkey,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SSL_CTX_set_client_CA_list(sslContext.get(), cert_names);
|
SSL_CTX_set_client_CA_list(sslContext.get(), cert_names);
|
||||||
|
}
|
||||||
|
|
||||||
return sslContext;
|
return sslContext;
|
||||||
}
|
}
|
||||||
@ -268,7 +271,7 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
|
|||||||
X509_NAME *subject = X509_NAME_new();
|
X509_NAME *subject = X509_NAME_new();
|
||||||
X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0);
|
X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0);
|
||||||
|
|
||||||
X509 *cert = CreateCert(key, subject, subject, key, ca);
|
shared_ptr<X509> cert = CreateCert(key, subject, subject, key, ca);
|
||||||
|
|
||||||
X509_NAME_free(subject);
|
X509_NAME_free(subject);
|
||||||
|
|
||||||
@ -276,10 +279,8 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
|
|||||||
|
|
||||||
bio = BIO_new(BIO_s_file());
|
bio = BIO_new(BIO_s_file());
|
||||||
BIO_write_filename(bio, const_cast<char *>(certfile.CStr()));
|
BIO_write_filename(bio, const_cast<char *>(certfile.CStr()));
|
||||||
PEM_write_bio_X509(bio, cert);
|
PEM_write_bio_X509(bio, cert.get());
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
|
|
||||||
X509_free(cert);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!csrfile.IsEmpty()) {
|
if (!csrfile.IsEmpty()) {
|
||||||
@ -311,7 +312,7 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
X509 *CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile)
|
shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile)
|
||||||
{
|
{
|
||||||
X509 *cert = X509_new();
|
X509 *cert = X509_new();
|
||||||
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
|
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
|
||||||
@ -337,7 +338,79 @@ X509 *CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PK
|
|||||||
|
|
||||||
X509_sign(cert, cakey, EVP_sha1());
|
X509_sign(cert, cakey, EVP_sha1());
|
||||||
|
|
||||||
return cert;
|
return shared_ptr<X509>(cert, X509_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
String GetIcingaCADir(void)
|
||||||
|
{
|
||||||
|
return Application::GetLocalStateDir() + "/lib/icinga2/ca";
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject)
|
||||||
|
{
|
||||||
|
std::stringstream msgbuf;
|
||||||
|
char errbuf[120];
|
||||||
|
|
||||||
|
String cadir = GetIcingaCADir();
|
||||||
|
|
||||||
|
String cakeyfile = cadir + "/ca.key";
|
||||||
|
|
||||||
|
RSA *rsa;
|
||||||
|
|
||||||
|
BIO *cakeybio = BIO_new_file(const_cast<char *>(cakeyfile.CStr()), "r");
|
||||||
|
|
||||||
|
if (!cakeybio) {
|
||||||
|
msgbuf << "Could not open CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
|
Log(LogCritical, "SSL", msgbuf.str());
|
||||||
|
return shared_ptr<X509>();
|
||||||
|
}
|
||||||
|
|
||||||
|
rsa = PEM_read_bio_RSAPrivateKey(cakeybio, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (!rsa) {
|
||||||
|
msgbuf << "Could not read RSA key from CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
||||||
|
Log(LogCritical, "SSL", msgbuf.str());
|
||||||
|
return shared_ptr<X509>();
|
||||||
|
}
|
||||||
|
|
||||||
|
BIO_free(cakeybio);
|
||||||
|
|
||||||
|
String cacertfile = cadir + "/ca.crt";
|
||||||
|
|
||||||
|
shared_ptr<X509> cacert = GetX509Certificate(cacertfile);
|
||||||
|
|
||||||
|
EVP_PKEY *privkey = EVP_PKEY_new();
|
||||||
|
EVP_PKEY_assign_RSA(privkey, rsa);
|
||||||
|
|
||||||
|
return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false, cadir + "/serial.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
String CertificateToString(const shared_ptr<X509>& cert)
|
||||||
|
{
|
||||||
|
BIO *mem = BIO_new(BIO_s_mem());
|
||||||
|
PEM_write_bio_X509(mem, cert.get());
|
||||||
|
|
||||||
|
char *data;
|
||||||
|
long len = BIO_get_mem_data(mem, &data);
|
||||||
|
|
||||||
|
String result = String(data, data + len);
|
||||||
|
|
||||||
|
BIO_free(mem);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String PBKDF2_SHA512(const String& password, const String& salt, int iterations)
|
||||||
|
{
|
||||||
|
unsigned char digest[SHA512_DIGEST_LENGTH];
|
||||||
|
PKCS5_PBKDF2_HMAC(password.CStr(), password.GetLength(), reinterpret_cast<const unsigned char *>(salt.CStr()), salt.GetLength(),
|
||||||
|
iterations, EVP_sha512(), sizeof(digest), digest);
|
||||||
|
|
||||||
|
char output[SHA512_DIGEST_LENGTH*2+1];
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
sprintf(output + 2 * i, "%02x", digest[i]);
|
||||||
|
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
String SHA256(const String& s)
|
String SHA256(const String& s)
|
||||||
@ -371,9 +444,8 @@ String SHA256(const String& s)
|
|||||||
<< errinfo_openssl_error(ERR_peek_error()));
|
<< errinfo_openssl_error(ERR_peek_error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
|
||||||
char output[SHA256_DIGEST_LENGTH*2+1];
|
char output[SHA256_DIGEST_LENGTH*2+1];
|
||||||
for (i = 0; i < 32; i++)
|
for (int i = 0; i < 32; i++)
|
||||||
sprintf(output + 2 * i, "%02x", digest[i]);
|
sprintf(output + 2 * i, "%02x", digest[i]);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -35,12 +35,16 @@ namespace icinga
|
|||||||
{
|
{
|
||||||
|
|
||||||
void I2_BASE_API InitializeOpenSSL(void);
|
void I2_BASE_API InitializeOpenSSL(void);
|
||||||
shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey);
|
shared_ptr<SSL_CTX> I2_BASE_API MakeSSLContext(const String& pubkey, const String& privkey, const String& cakey = String());
|
||||||
void I2_BASE_API AddCRLToSSLContext(const shared_ptr<SSL_CTX>& context, const String& crlPath);
|
void I2_BASE_API AddCRLToSSLContext(const shared_ptr<SSL_CTX>& context, const String& crlPath);
|
||||||
String I2_BASE_API GetCertificateCN(const shared_ptr<X509>& certificate);
|
String I2_BASE_API GetCertificateCN(const shared_ptr<X509>& certificate);
|
||||||
shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
|
shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
|
||||||
int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), bool ca = false);
|
int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), bool ca = false);
|
||||||
X509 * I2_BASE_API CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile = String());
|
shared_ptr<X509> I2_BASE_API CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile = String());
|
||||||
|
String I2_BASE_API GetIcingaCADir(void);
|
||||||
|
String I2_BASE_API CertificateToString(const shared_ptr<X509>& cert);
|
||||||
|
shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
||||||
|
String I2_BASE_API PBKDF2_SHA512(const String& password, const String& salt, int iterations);
|
||||||
String I2_BASE_API SHA256(const String& s);
|
String I2_BASE_API SHA256(const String& s);
|
||||||
|
|
||||||
class I2_BASE_API openssl_error : virtual public std::exception, virtual public boost::exception { };
|
class I2_BASE_API openssl_error : virtual public std::exception, virtual public boost::exception { };
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
set(cli_SOURCES
|
set(cli_SOURCES
|
||||||
featureenablecommand.cpp featuredisablecommand.cpp featurelistcommand.cpp
|
featureenablecommand.cpp featuredisablecommand.cpp featurelistcommand.cpp
|
||||||
objectlistcommand.cpp
|
objectlistcommand.cpp
|
||||||
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp
|
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkiticketcommand.cpp
|
||||||
daemoncommand.cpp
|
daemoncommand.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ endif()
|
|||||||
|
|
||||||
add_library(cli SHARED ${cli_SOURCES})
|
add_library(cli SHARED ${cli_SOURCES})
|
||||||
|
|
||||||
target_link_libraries(cli ${Boost_LIBRARIES} base config)
|
target_link_libraries(cli ${Boost_LIBRARIES} base config remote)
|
||||||
|
|
||||||
set_target_properties (
|
set_target_properties (
|
||||||
cli PROPERTIES
|
cli PROPERTIES
|
||||||
|
@ -68,73 +68,11 @@ int PKISignCSRCommand::Run(const boost::program_options::variables_map& vm, cons
|
|||||||
|
|
||||||
BIO_free(csrbio);
|
BIO_free(csrbio);
|
||||||
|
|
||||||
String cadir = Application::GetLocalStateDir() + "/lib/icinga2/ca";
|
shared_ptr<X509> cert = CreateCertIcingaCA(X509_REQ_get_pubkey(req), X509_REQ_get_subject_name(req));
|
||||||
|
|
||||||
String cakeyfile = cadir + "/ca.key";
|
X509_REQ_free(req);
|
||||||
|
|
||||||
RSA *rsa;
|
std::cout << CertificateToString(cert);
|
||||||
|
|
||||||
BIO *cakeybio = BIO_new_file(const_cast<char *>(cakeyfile.CStr()), "r");
|
|
||||||
|
|
||||||
if (!cakeybio) {
|
|
||||||
msgbuf << "Could not open CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rsa = PEM_read_bio_RSAPrivateKey(cakeybio, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (!rsa) {
|
|
||||||
msgbuf << "Could not read RSA key from CA key file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_free(cakeybio);
|
|
||||||
|
|
||||||
String cacertfile = cadir + "/ca.crt";
|
|
||||||
|
|
||||||
BIO *cacertbio = BIO_new_file(const_cast<char *>(cacertfile.CStr()), "r");
|
|
||||||
|
|
||||||
if (!cacertbio) {
|
|
||||||
msgbuf << "Could not open CA certificate file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
X509 *cacert = PEM_read_bio_X509(cacertbio, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (!cacert) {
|
|
||||||
msgbuf << "Could not read X509 certificate from CA certificate file '" << cakeyfile << "': " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
BIO_free(cacertbio);
|
|
||||||
|
|
||||||
EVP_PKEY *privkey = EVP_PKEY_new();
|
|
||||||
EVP_PKEY_assign_RSA(privkey, rsa);
|
|
||||||
|
|
||||||
EVP_PKEY *pubkey = X509_REQ_get_pubkey(req);
|
|
||||||
|
|
||||||
X509 *cert = CreateCert(pubkey, X509_REQ_get_subject_name(req), X509_get_subject_name(cacert), privkey, false);
|
|
||||||
|
|
||||||
EVP_PKEY_free(pubkey);
|
|
||||||
X509_free(cacert);
|
|
||||||
|
|
||||||
BIO *certbio = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
||||||
|
|
||||||
if (!PEM_write_bio_X509(certbio, cert)) {
|
|
||||||
BIO_free(certbio);
|
|
||||||
|
|
||||||
msgbuf << "Could not write X509 certificate: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
|
|
||||||
Log(LogCritical, "SSL", msgbuf.str());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_free(cert);
|
|
||||||
|
|
||||||
BIO_free(certbio);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ using namespace icinga;
|
|||||||
|
|
||||||
static Value SetLogPositionHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
static Value SetLogPositionHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||||
REGISTER_APIFUNCTION(SetLogPosition, log, &SetLogPositionHandler);
|
REGISTER_APIFUNCTION(SetLogPosition, log, &SetLogPositionHandler);
|
||||||
|
static Value RequestCertificateHandler(const MessageOrigin& origin, const Dictionary::Ptr& params);
|
||||||
|
REGISTER_APIFUNCTION(RequestCertificate, pki, &RequestCertificateHandler);
|
||||||
|
|
||||||
ApiClient::ApiClient(const String& identity, bool authenticated, const Stream::Ptr& stream, ConnectionRole role)
|
ApiClient::ApiClient(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role)
|
||||||
: m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream), m_Role(role), m_Seen(Utility::GetTime())
|
: m_Identity(identity), m_Authenticated(authenticated), m_Stream(stream), m_Role(role), m_Seen(Utility::GetTime())
|
||||||
{
|
{
|
||||||
if (authenticated)
|
if (authenticated)
|
||||||
@ -60,7 +62,7 @@ Endpoint::Ptr ApiClient::GetEndpoint(void) const
|
|||||||
return m_Endpoint;
|
return m_Endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream::Ptr ApiClient::GetStream(void) const
|
TlsStream::Ptr ApiClient::GetStream(void) const
|
||||||
{
|
{
|
||||||
return m_Stream;
|
return m_Stream;
|
||||||
}
|
}
|
||||||
@ -220,3 +222,41 @@ Value SetLogPositionHandler(const MessageOrigin& origin, const Dictionary::Ptr&
|
|||||||
|
|
||||||
return Empty;
|
return Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value RequestCertificateHandler(const MessageOrigin& origin, const Dictionary::Ptr& params)
|
||||||
|
{
|
||||||
|
if (!params)
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||||
|
String salt = listener->GetTicketSalt();
|
||||||
|
|
||||||
|
Dictionary::Ptr result = make_shared<Dictionary>();
|
||||||
|
|
||||||
|
if (salt.IsEmpty()) {
|
||||||
|
result->Set("error", "Ticket salt is not configured.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ticket = params->Get("ticket");
|
||||||
|
String realTicket = PBKDF2_SHA512(origin.FromClient->GetIdentity(), salt, 50000);
|
||||||
|
|
||||||
|
if (ticket != realTicket) {
|
||||||
|
result->Set("error", "Invalid ticket.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_ptr<X509> cert = origin.FromClient->GetStream()->GetPeerCertificate();
|
||||||
|
|
||||||
|
EVP_PKEY *pubkey = X509_get_pubkey(cert.get());
|
||||||
|
X509_NAME *subject = X509_get_subject_name(cert.get());
|
||||||
|
|
||||||
|
shared_ptr<X509> newcert = CreateCertIcingaCA(pubkey, subject);
|
||||||
|
result->Set("cert", CertificateToString(newcert));
|
||||||
|
|
||||||
|
String cacertfile = GetIcingaCADir() + "/ca.crt";
|
||||||
|
shared_ptr<X509> cacert = GetX509Certificate(cacertfile);
|
||||||
|
result->Set("ca", CertificateToString(cacert));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#define APICLIENT_H
|
#define APICLIENT_H
|
||||||
|
|
||||||
#include "remote/endpoint.hpp"
|
#include "remote/endpoint.hpp"
|
||||||
#include "base/stream.hpp"
|
#include "base/tlsstream.hpp"
|
||||||
#include "base/timer.hpp"
|
#include "base/timer.hpp"
|
||||||
#include "base/workqueue.hpp"
|
#include "base/workqueue.hpp"
|
||||||
#include "remote/i2-remote.hpp"
|
#include "remote/i2-remote.hpp"
|
||||||
@ -45,14 +45,14 @@ class I2_REMOTE_API ApiClient : public Object
|
|||||||
public:
|
public:
|
||||||
DECLARE_PTR_TYPEDEFS(ApiClient);
|
DECLARE_PTR_TYPEDEFS(ApiClient);
|
||||||
|
|
||||||
ApiClient(const String& identity, bool authenticated, const Stream::Ptr& stream, ConnectionRole role);
|
ApiClient(const String& identity, bool authenticated, const TlsStream::Ptr& stream, ConnectionRole role);
|
||||||
|
|
||||||
void Start(void);
|
void Start(void);
|
||||||
|
|
||||||
String GetIdentity(void) const;
|
String GetIdentity(void) const;
|
||||||
bool IsAuthenticated(void) const;
|
bool IsAuthenticated(void) const;
|
||||||
Endpoint::Ptr GetEndpoint(void) const;
|
Endpoint::Ptr GetEndpoint(void) const;
|
||||||
Stream::Ptr GetStream(void) const;
|
TlsStream::Ptr GetStream(void) const;
|
||||||
ConnectionRole GetRole(void) const;
|
ConnectionRole GetRole(void) const;
|
||||||
|
|
||||||
void Disconnect(void);
|
void Disconnect(void);
|
||||||
@ -64,7 +64,7 @@ private:
|
|||||||
String m_Identity;
|
String m_Identity;
|
||||||
bool m_Authenticated;
|
bool m_Authenticated;
|
||||||
Endpoint::Ptr m_Endpoint;
|
Endpoint::Ptr m_Endpoint;
|
||||||
Stream::Ptr m_Stream;
|
TlsStream::Ptr m_Stream;
|
||||||
ConnectionRole m_Role;
|
ConnectionRole m_Role;
|
||||||
double m_Seen;
|
double m_Seen;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ class ApiListener : DynamicObject
|
|||||||
|
|
||||||
[config] bool accept_config;
|
[config] bool accept_config;
|
||||||
|
|
||||||
|
[config] String ticket_salt;
|
||||||
|
|
||||||
[state] double log_message_timestamp;
|
[state] double log_message_timestamp;
|
||||||
|
|
||||||
String identity;
|
String identity;
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
%attribute %string "bind_host",
|
%attribute %string "bind_host",
|
||||||
%attribute %string "bind_port",
|
%attribute %string "bind_port",
|
||||||
|
|
||||||
%attribute %number "accept_config"
|
%attribute %number "accept_config",
|
||||||
|
|
||||||
|
%attribute %string "ticket_salt"
|
||||||
}
|
}
|
||||||
|
|
||||||
%type Endpoint {
|
%type Endpoint {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user