Implement SSL support.

This commit is contained in:
Gunnar Beutner 2012-04-24 14:02:15 +02:00
parent 576181f304
commit 21ef4836ee
37 changed files with 735 additions and 54 deletions

View File

@ -8,6 +8,11 @@ using namespace icinga;
Application::Ptr I2_EXPORT Application::Instance;
/**
* Application
*
* Constructor for the Application class.
*/
Application::Application(void)
{
#ifdef _WIN32
@ -29,8 +34,14 @@ Application::Application(void)
m_ConfigHive = make_shared<ConfigHive>();
}
/**
* ~Application
*
* Destructor for the application class.
*/
Application::~Application(void)
{
/* stop all components */
for (map<string, Component::Ptr>::iterator i = m_Components.begin();
i != m_Components.end(); i++) {
i->second->Stop();
@ -45,6 +56,11 @@ Application::~Application(void)
#endif /* _WIN32 */
}
/**
* RunEventLoop
*
* Processes events (e.g. sockets and timers).
*/
void Application::RunEventLoop(void)
{
while (!m_ShuttingDown) {
@ -141,16 +157,38 @@ void Application::RunEventLoop(void)
}
}
/**
* Shutdown
*
* Signals the application to shut down during the next
* execution of the event loop.
*/
void Application::Shutdown(void)
{
m_ShuttingDown = true;
}
/**
* GetConfigHive
*
* Returns the application's configuration hive.
*
* @returns The config hive.
*/
ConfigHive::Ptr Application::GetConfigHive(void) const
{
return m_ConfigHive;
}
/**
* LoadComponent
*
* Loads a component from a library.
*
* @param path The path of the component library.
* @param componentConfig The configuration for the component.
* @returns The component.
*/
Component::Ptr Application::LoadComponent(const string& path,
const ConfigObject::Ptr& componentConfig)
{
@ -186,6 +224,13 @@ Component::Ptr Application::LoadComponent(const string& path,
return component;
}
/**
* RegisterComponent
*
* Registers a component object and starts it.
*
* @param component The component.
*/
void Application::RegisterComponent(Component::Ptr component)
{
component->SetApplication(static_pointer_cast<Application>(shared_from_this()));
@ -194,18 +239,33 @@ void Application::RegisterComponent(Component::Ptr component)
component->Start();
}
/**
* UnregisterComponent
*
* Unregisters a component object and stops it.
*
* @param component The component.
*/
void Application::UnregisterComponent(Component::Ptr component)
{
string name = component->GetName();
Log("Unloading component '%s'", name.c_str());
map<string, Component::Ptr>::iterator i = m_Components.find(name);
if (i != m_Components.end()) {
if (i != m_Components.end())
m_Components.erase(i);
component->Stop();
}
}
/**
* GetComponent
*
* Finds a loaded component by name.
*
* @param name The name of the component.
* @returns The component or a null pointer if the component could not be found.
*/
Component::Ptr Application::GetComponent(const string& name)
{
map<string, Component::Ptr>::iterator ci = m_Components.find(name);
@ -216,6 +276,14 @@ Component::Ptr Application::GetComponent(const string& name)
return ci->second;
}
/**
* Log
*
* Logs a message.
*
* @param format The format string.
* @param ... Additional parameters for the format string.
*/
void Application::Log(const char *format, ...)
{
char message[512];
@ -229,16 +297,37 @@ void Application::Log(const char *format, ...)
fprintf(stderr, "%s\n", message);
}
/**
* SetArguments
*
* Sets the application's arguments.
*
* @param arguments The arguments.
*/
void Application::SetArguments(const vector<string>& arguments)
{
m_Arguments = arguments;
}
/**
* GetArguments
*
* Retrieves the application's arguments.
*
* @returns The arguments.
*/
const vector<string>& Application::GetArguments(void) const
{
return m_Arguments;
}
/**
* GetExeDirectory
*
* Retrieves the directory the application's binary is contained in.
*
* @returns The directory.
*/
string Application::GetExeDirectory(void) const
{
static string ExePath;
@ -314,6 +403,13 @@ string Application::GetExeDirectory(void) const
return ExePath;
}
/**
* AddComponentSearchDir
*
* Adds a directory to the component search path.
*
* @param componentDirectory The directory.
*/
void Application::AddComponentSearchDir(const string& componentDirectory)
{
#ifdef _WIN32
@ -323,14 +419,30 @@ void Application::AddComponentSearchDir(const string& componentDirectory)
#endif /* _WIN32 */
}
/**
* IsDebugging
*
* Retrieves the debugging mode of the application.
*
* @returns true if the application is being debugged, false otherwise
*/
bool Application::IsDebugging(void) const
{
return m_Debugging;
}
#ifndef _WIN32
/**
* ApplicationSigIntHandler
*
* Signal handler for SIGINT.
*
* @param signum The signal number.
*/
static void ApplicationSigIntHandler(int signum)
{
assert(signum == SIGINT);
Application::Instance->Shutdown();
struct sigaction sa;
@ -340,6 +452,16 @@ static void ApplicationSigIntHandler(int signum)
}
#endif /* _WIN32 */
/**
* RunApplication
*
* Runs the specified application.
*
* @param argc The number of arguments.
* @param argv The arguments that should be passed to the application.
* @param instance The application instance.
* @returns The application's exit code.
*/
int icinga::RunApplication(int argc, char **argv, Application *instance)
{
int result;

View File

@ -29,6 +29,7 @@
<ClCompile Include="tcpsocket.cpp" />
<ClCompile Include="thread.cpp" />
<ClCompile Include="timer.cpp" />
<ClCompile Include="tlsclient.cpp" />
<ClCompile Include="unix.cpp" />
<ClCompile Include="utility.cpp" />
<ClCompile Include="variant.cpp" />
@ -56,6 +57,7 @@
<ClInclude Include="tcpsocket.h" />
<ClInclude Include="thread.h" />
<ClInclude Include="timer.h" />
<ClInclude Include="tlsclient.h" />
<ClInclude Include="unix.h" />
<ClInclude Include="utility.h" />
<ClInclude Include="variant.h" />
@ -103,7 +105,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib;libeay32MTd.lib;ssleay32MTd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib</AdditionalDependencies>
@ -125,7 +127,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib;libeay32MT.lib;ssleay32MT.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>ws2_32.lib;shlwapi.lib</AdditionalDependencies>

View File

@ -2,21 +2,49 @@
using namespace icinga;
/**
* SetApplication
*
* Sets the application this component belongs to.
*
* @param application The application.
*/
void Component::SetApplication(const Application::WeakPtr& application)
{
m_Application = application;
}
/**
* GetApplication
*
* Retrieves the application this component belongs to.
*
* @returns The application.
*/
Application::Ptr Component::GetApplication(void) const
{
return m_Application.lock();
}
/**
* SetConfig
*
* Sets the configuration for this component.
*
* @param componentConfig The configuration.
*/
void Component::SetConfig(const ConfigObject::Ptr& componentConfig)
{
m_Config = componentConfig;
}
/**
* GetConfig
*
* Retrieves the configuration for this component.
*
* @returns The configuration.
*/
ConfigObject::Ptr Component::GetConfig(void) const
{
return m_Config;

View File

@ -2,6 +2,11 @@
using namespace icinga;
/**
* CondVar
*
* Constructor for the CondVar class.
*/
CondVar::CondVar(void)
{
#ifdef _WIN32
@ -11,6 +16,11 @@ CondVar::CondVar(void)
#endif /* _WIN32 */
}
/**
* ~CondVar
*
* Destructor for the CondVar class.
*/
CondVar::~CondVar(void)
{
#ifdef _WIN32
@ -20,6 +30,14 @@ CondVar::~CondVar(void)
#endif /* _WIN32 */
}
/**
* Wait
*
* Waits for the condition variable to be signaled. Releases the specified mutex
* before it begins to wait and re-acquires the mutex after waiting.
*
* @param mtx The mutex that should be released during waiting.
*/
void CondVar::Wait(Mutex& mtx)
{
#ifdef _WIN32
@ -29,6 +47,11 @@ void CondVar::Wait(Mutex& mtx)
#endif /* _WIN32 */
}
/**
* Signal
*
* Wakes up at least one waiting thread.
*/
void CondVar::Signal(void)
{
#ifdef _WIN32
@ -38,6 +61,11 @@ void CondVar::Signal(void)
#endif /* _WIN32 */
}
/**
* Broadcast
*
* Wakes up all waiting threads.
*/
void CondVar::Broadcast(void)
{
#ifdef _WIN32
@ -47,7 +75,13 @@ void CondVar::Broadcast(void)
#endif /* _WIN32 */
}
/**
* Get
*
* Retrieves the platform-specific condition variable handle.
*
* @returns The platform-specific condition variable handle.
*/
#ifdef _WIN32
CONDITION_VARIABLE *CondVar::Get(void)
#else /* _WIN32 */

View File

@ -2,16 +2,37 @@
using namespace icinga;
/**
* SetHive
*
* Sets the hive this collection belongs to.
*
* @param hive The hive.
*/
void ConfigCollection::SetHive(const ConfigHive::WeakPtr& hive)
{
m_Hive = hive;
}
/**
* GetHive
*
* Retrieves the hive this collection belongs to.
*
* @returns The hive.
*/
ConfigHive::WeakPtr ConfigCollection::GetHive(void) const
{
return m_Hive;
}
/**
* AddObject
*
* Adds a new object to this collection.
*
* @param object The new object.
*/
void ConfigCollection::AddObject(const ConfigObject::Ptr& object)
{
RemoveObject(object);
@ -27,6 +48,13 @@ void ConfigCollection::AddObject(const ConfigObject::Ptr& object)
hive->OnObjectCreated(ea);
}
/**
* RemoveObject
*
* Removes an object from this collection
*
* @param object The object that is to be removed.
*/
void ConfigCollection::RemoveObject(const ConfigObject::Ptr& object)
{
ObjectIterator oi = Objects.find(object->GetName());
@ -44,9 +72,18 @@ void ConfigCollection::RemoveObject(const ConfigObject::Ptr& object)
}
}
ConfigObject::Ptr ConfigCollection::GetObject(const string& name)
/**
* GetObject
*
* Retrieves an object by name.
*
* @param name The name of the object.
* @returns The object or a null pointer if the specified object
* could not be found.
*/
ConfigObject::Ptr ConfigCollection::GetObject(const string& name) const
{
ObjectIterator oi = Objects.find(name);
ObjectConstIterator oi = Objects.find(name);
if (oi == Objects.end())
return ConfigObject::Ptr();
@ -54,6 +91,13 @@ ConfigObject::Ptr ConfigCollection::GetObject(const string& name)
return oi->second;
}
/**
* ForEachObject
*
* Invokes the specified callback for each object contained in this collection.
*
* @param callback The callback.
*/
void ConfigCollection::ForEachObject(function<int (const EventArgs&)> callback)
{
EventArgs ea;

View File

@ -16,6 +16,7 @@ public:
typedef weak_ptr<ConfigCollection> WeakPtr;
typedef map<string, ConfigObject::Ptr>::iterator ObjectIterator;
typedef map<string, ConfigObject::Ptr>::const_iterator ObjectConstIterator;
map<string, ConfigObject::Ptr> Objects;
void SetHive(const weak_ptr<ConfigHive>& hive);
@ -23,7 +24,7 @@ public:
void AddObject(const ConfigObject::Ptr& object);
void RemoveObject(const ConfigObject::Ptr& object);
ConfigObject::Ptr GetObject(const string& name = string());
ConfigObject::Ptr GetObject(const string& name = string()) const;
void ForEachObject(function<int (const EventArgs&)> callback);

View File

@ -2,25 +2,59 @@
using namespace icinga;
/**
* AddObject
*
* Adds a new object to this hive.
*
* @param object The new object.
*/
void ConfigHive::AddObject(const ConfigObject::Ptr& object)
{
object->SetHive(static_pointer_cast<ConfigHive>(shared_from_this()));
GetCollection(object->GetType())->AddObject(object);
}
/**
* RemoveObject
*
* Removes an object from this hive.
*
* @param object The object that is to be removed.
*/
void ConfigHive::RemoveObject(const ConfigObject::Ptr& object)
{
GetCollection(object->GetType())->RemoveObject(object);
}
/**
* GetObject
*
* Retrieves an object by type and name.
*
* @param type The type of the object.
* @param name The name of the object.
* @returns The object or a null pointer if the specified object
* could not be found.
*/
ConfigObject::Ptr ConfigHive::GetObject(const string& type, const string& name)
{
return GetCollection(type)->GetObject(name);
}
/**
* GetCollection
*
* Retrieves a collection by name. Creates an empty collection
* if the collection doesn't already exist.
*
* @param collection The name of the collection.
* @returns The collection or a null pointer if the specified collection
* could not be found.
*/
ConfigCollection::Ptr ConfigHive::GetCollection(const string& collection)
{
CollectionIterator ci = Collections.find(collection);
CollectionConstIterator ci = Collections.find(collection);
if (ci == Collections.end()) {
Collections[collection] = make_shared<ConfigCollection>();
@ -30,6 +64,13 @@ ConfigCollection::Ptr ConfigHive::GetCollection(const string& collection)
return ci->second;
}
/**
* ForEachObject
*
* Invokes the specified callback for each object contained in this hive.
*
* @param callback The callback.
*/
void ConfigHive::ForEachObject(const string& type,
function<int (const EventArgs&)> callback)
{

View File

@ -11,6 +11,7 @@ public:
typedef weak_ptr<ConfigHive> WeakPtr;
typedef map<string, ConfigCollection::Ptr>::iterator CollectionIterator;
typedef map<string, ConfigCollection::Ptr>::const_iterator CollectionConstIterator;
map<string, ConfigCollection::Ptr> Collections;
void AddObject(const ConfigObject::Ptr& object);

View File

@ -2,6 +2,14 @@
using namespace icinga;
/**
* ConfigObject
*
* Constructor for the ConfigObject class.
*
* @param type The type of the object.
* @param name The name of the object.
*/
ConfigObject::ConfigObject(const string& type, const string& name)
{
m_Type = type;
@ -9,6 +17,13 @@ ConfigObject::ConfigObject(const string& type, const string& name)
m_Replicated = false;
}
/**
* SetHive
*
* Sets the hive this object belongs to.
*
* @param hive The hive.
*/
void ConfigObject::SetHive(const ConfigHive::WeakPtr& hive)
{
if (m_Hive.lock())
@ -18,41 +33,99 @@ void ConfigObject::SetHive(const ConfigHive::WeakPtr& hive)
OnPropertyChanged += bind_weak(&ConfigObject::PropertyChangedHandler, shared_from_this());
}
/**
* GetHive
*
* Retrieves the hive this object belongs to.
*
* @returns The hive.
*/
ConfigHive::WeakPtr ConfigObject::GetHive(void) const
{
return m_Hive;
}
/**
* SetName
*
* Sets the name of this object.
*
* @param name The name.
*/
void ConfigObject::SetName(const string& name)
{
m_Name = name;
}
/**
* GetName
*
* Retrieves the name of this object.
*
* @returns The name.
*/
string ConfigObject::GetName(void) const
{
return m_Name;
}
/**
* SetType
*
* Sets the type of this object.
*
* @param type The type.
*/
void ConfigObject::SetType(const string& type)
{
m_Type = type;
}
/**
* GetType
*
* Retrieves the type of this object.
*
* @returns The type.
*/
string ConfigObject::GetType(void) const
{
return m_Type;
}
/**
* SetReplicated
*
* Sets whether this object was replicated.
*
* @param replicated Whether this object was replicated.
*/
void ConfigObject::SetReplicated(bool replicated)
{
m_Replicated = replicated;
}
/**
* GetReplicated
*
* Retrieves whether this object was replicated.
*
* @returns Whether this object was replicated.
*/
bool ConfigObject::GetReplicated(void) const
{
return m_Replicated;
}
/**
* PropertyChangedHandler
*
* Handles changed properties by propagating them to the hive
* and collection this object is contained in.
*
* @param dpcea The event arguments.
* @returns 0.
*/
int ConfigObject::PropertyChangedHandler(const PropertyChangedEventArgs& dpcea)
{
ConfigHive::Ptr hive = m_Hive.lock();

View File

@ -26,6 +26,10 @@
#include <map>
#include <list>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#ifdef HAVE_GCC_ABI_DEMANGLE
# include <cxxabi.h>
#endif /* HAVE_GCC_ABI_DEMANGLE */
@ -81,6 +85,7 @@ using namespace std::tr1::placeholders;
#include "tcpsocket.h"
#include "tcpclient.h"
#include "tcpserver.h"
#include "tlsclient.h"
#include "configobject.h"
#include "configcollection.h"
#include "confighive.h"

View File

@ -44,19 +44,6 @@ public:
}
};
typedef function<Object::Ptr ()> factory_function;
/**
* factory<T>
*
* Returns a new object of type T.
*/
template<class T>
Object::Ptr factory(void)
{
return make_shared<T>();
}
}
#endif /* OBJECT_H */

View File

@ -11,7 +11,7 @@ Socket::Socket(void)
Socket::~Socket(void)
{
Close(true);
CloseInternal(true);
}
void Socket::Start(void)
@ -45,10 +45,10 @@ SOCKET Socket::GetFD(void) const
void Socket::Close(void)
{
Close(false);
CloseInternal(false);
}
void Socket::Close(bool from_dtor)
void Socket::CloseInternal(bool from_dtor)
{
if (m_FD != INVALID_SOCKET) {
closesocket(m_FD);

View File

@ -23,7 +23,7 @@ protected:
Socket(void);
void HandleSocketError(void);
void Close(bool from_dtor);
virtual void CloseInternal(bool from_dtor);
public:
typedef shared_ptr<Socket> Ptr;

View File

@ -2,14 +2,21 @@
using namespace icinga;
TCPClient::TCPClient(void)
TCPClient::TCPClient(TCPClientRole role)
{
m_Role = role;
m_SendQueue = make_shared<FIFO>();
m_RecvQueue = make_shared<FIFO>();
m_PeerPort = 0;
}
TCPClientRole TCPClient::GetRole(void) const
{
return m_Role;
}
void TCPClient::Start(void)
{
TCPSocket::Start();
@ -44,6 +51,7 @@ void TCPClient::Connect(const string& hostname, unsigned short port)
HandleSocketError();
}
m_Role = RoleOutbound;
m_PeerHost = hostname;
m_PeerPort = port;
}
@ -123,3 +131,8 @@ bool TCPClient::WantsToWrite(void) const
{
return (m_SendQueue->GetSize() > 0);
}
TCPClient::Ptr icinga::TCPClientFactory(TCPClientRole role)
{
return make_shared<TCPClient>(role);
}

View File

@ -4,23 +4,33 @@
namespace icinga
{
enum I2_BASE_API TCPClientRole
{
RoleInbound,
RoleOutbound
};
class I2_BASE_API TCPClient : public TCPSocket
{
private:
TCPClientRole m_Role;
string m_PeerHost;
int m_PeerPort;
FIFO::Ptr m_SendQueue;
FIFO::Ptr m_RecvQueue;
int ReadableEventHandler(const EventArgs& ea);
int WritableEventHandler(const EventArgs& ea);
virtual int ReadableEventHandler(const EventArgs& ea);
virtual int WritableEventHandler(const EventArgs& ea);
public:
typedef shared_ptr<TCPClient> Ptr;
typedef weak_ptr<TCPClient> WeakPtr;
TCPClient(void);
TCPClient(TCPClientRole role);
TCPClientRole GetRole(void) const;
virtual void Start(void);
@ -38,6 +48,8 @@ public:
Event<EventArgs> OnDataAvailable;
};
TCPClient::Ptr TCPClientFactory(TCPClientRole role);
}
#endif /* TCPCLIENT_H */

View File

@ -4,15 +4,15 @@ using namespace icinga;
TCPServer::TCPServer(void)
{
m_ClientFactory = factory<TCPClient>;
m_ClientFactory = bind(&TCPClientFactory, RoleInbound);
}
void TCPServer::SetClientFactory(factory_function clientFactory)
void TCPServer::SetClientFactory(function<TCPClient::Ptr()> clientFactory)
{
m_ClientFactory = clientFactory;
}
factory_function TCPServer::GetFactoryFunction(void)
function<TCPClient::Ptr()> TCPServer::GetFactoryFunction(void) const
{
return m_ClientFactory;
}

View File

@ -17,7 +17,7 @@ class I2_BASE_API TCPServer : public TCPSocket
private:
int ReadableEventHandler(const EventArgs& ea);
factory_function m_ClientFactory;
function<TCPClient::Ptr()> m_ClientFactory;
public:
typedef shared_ptr<TCPServer> Ptr;
@ -25,8 +25,8 @@ public:
TCPServer(void);
void SetClientFactory(factory_function function);
factory_function GetFactoryFunction(void);
void SetClientFactory(function<TCPClient::Ptr()> function);
function<TCPClient::Ptr()> GetFactoryFunction(void) const;
virtual void Start();

119
base/tlsclient.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "i2-base.h"
using namespace icinga;
TLSClient::TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext) : TCPClient(role)
{
m_SSLContext = sslContext;
}
shared_ptr<X509> TLSClient::GetClientCertificate(void) const
{
return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), X509_free);
}
shared_ptr<X509> TLSClient::GetPeerCertificate(void) const
{
return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
}
void TLSClient::Start(void)
{
TCPClient::Start();
m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free);
if (!m_SSL)
; /* TODO: deal with error */
BIO *bio = BIO_new_socket(GetFD(), 0);
SSL_set_bio(m_SSL.get(), bio, bio);
if (GetRole() == RoleInbound)
SSL_set_accept_state(m_SSL.get());
else
SSL_set_connect_state(m_SSL.get());
}
int TLSClient::ReadableEventHandler(const EventArgs& ea)
{
int rc;
size_t bufferSize = FIFO::BlockSize / 2;
char *buffer = (char *)GetRecvQueue()->GetWriteBuffer(&bufferSize);
rc = SSL_read(m_SSL.get(), buffer, bufferSize);
if (rc <= 0) {
switch (SSL_get_error(m_SSL.get(), rc)) {
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
return 0;
case SSL_ERROR_ZERO_RETURN:
Close();
return 0;
default:
/* TODO: deal with error */
return 0;
}
}
GetRecvQueue()->Write(NULL, rc);
EventArgs dea;
dea.Source = shared_from_this();
OnDataAvailable(dea);
return 0;
}
int TLSClient::WritableEventHandler(const EventArgs& ea)
{
int rc;
rc = SSL_write(m_SSL.get(), (const char *)GetSendQueue()->GetReadBuffer(), GetSendQueue()->GetSize());
if (rc <= 0) {
switch (SSL_get_error(m_SSL.get(), rc)) {
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
return 0;
case SSL_ERROR_ZERO_RETURN:
Close();
return 0;
default:
/* TODO: deal with error */
return 0;
}
}
GetSendQueue()->Read(NULL, rc);
return 0;
}
bool TLSClient::WantsToWrite(void) const
{
if (SSL_want_write(m_SSL.get()))
return true;
if (SSL_state(m_SSL.get()) != SSL_ST_OK)
return false;
return TCPClient::WantsToWrite();
}
void TLSClient::CloseInternal(bool from_dtor)
{
SSL_shutdown(m_SSL.get());
TCPClient::CloseInternal(from_dtor);
}
TCPClient::Ptr icinga::TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
{
return make_shared<TLSClient>(role, sslContext);
}

41
base/tlsclient.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef TLSCLIENT_H
#define TLSCLIENT_H
namespace icinga
{
struct I2_BASE_API VerifyCertificateEventArgs : public EventArgs
{
bool ValidCertificate;
X509_STORE_CTX *Context;
};
class I2_BASE_API TLSClient : public TCPClient
{
private:
shared_ptr<SSL_CTX> m_SSLContext;
shared_ptr<SSL> m_SSL;
virtual int ReadableEventHandler(const EventArgs& ea);
virtual int WritableEventHandler(const EventArgs& ea);
virtual void CloseInternal(bool from_dtor);
public:
TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
shared_ptr<X509> GetClientCertificate(void) const;
shared_ptr<X509> GetPeerCertificate(void) const;
virtual void Start(void);
virtual bool WantsToWrite(void) const;
Event<VerifyCertificateEventArgs> OnVerifyCertificate;
};
TCPClient::Ptr TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
}
#endif /* TLSCLIENT_H */

View File

@ -2,6 +2,8 @@
using namespace icinga;
bool I2_EXPORT Utility::m_SSLInitialized = false;
/**
* Daemonize
*
@ -40,3 +42,35 @@ void Utility::Daemonize(void) {
throw PosixException("setsid failed", errno);
#endif
}
void Utility::InitializeOpenSSL(void)
{
if (!m_SSLInitialized) {
SSL_library_init();
SSL_load_error_strings();
m_SSLInitialized = true;
}
}
shared_ptr<SSL_CTX> Utility::MakeSSLContext(string pubkey, string privkey, string cakey)
{
InitializeOpenSSL();
SSL_METHOD *sslMethod = (SSL_METHOD *)TLSv1_method();
shared_ptr<SSL_CTX> sslContext = shared_ptr<SSL_CTX>(SSL_CTX_new(sslMethod), SSL_CTX_free);
SSL_CTX_set_mode(sslContext.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (!SSL_CTX_use_certificate_chain_file(sslContext.get(), pubkey.c_str()))
throw InvalidArgumentException("Could not load public X509 key file.");
if (!SSL_CTX_use_PrivateKey_file(sslContext.get(), privkey.c_str(), SSL_FILETYPE_PEM))
throw InvalidArgumentException("Could not load private X509 key file.");
if (!SSL_CTX_load_verify_locations(sslContext.get(), cakey.c_str(), NULL))
throw InvalidArgumentException("Could not load public CA key file.");
return sslContext;
}

View File

@ -12,8 +12,12 @@ namespace icinga
class I2_BASE_API Utility
{
private:
static bool m_SSLInitialized;
Utility(void);
static void InitializeOpenSSL(void);
public:
/**
* GetTypeName
@ -39,6 +43,8 @@ public:
}
static void Daemonize(void);
static shared_ptr<SSL_CTX> MakeSSLContext(string pubkey, string privkey, string cakey);
};
}

17
icinga-app/ca.crt Normal file
View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICnjCCAgegAwIBAgIJAOP3gULX9+xgMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
BAYTAkRFMRAwDgYDVQQIDAdCYXZhcmlhMRIwEAYDVQQHDAlOdXJlbWJlcmcxFTAT
BgNVBAoMDE5FVFdBWVMgR21iSDEcMBoGA1UEAwwTSWNpbmdhIFNuYWtlIE9pbCBD
QTAeFw0xMjA0MjQxMTQyMzFaFw0yMjA0MjIxMTQyMzFaMGgxCzAJBgNVBAYTAkRF
MRAwDgYDVQQIDAdCYXZhcmlhMRIwEAYDVQQHDAlOdXJlbWJlcmcxFTATBgNVBAoM
DE5FVFdBWVMgR21iSDEcMBoGA1UEAwwTSWNpbmdhIFNuYWtlIE9pbCBDQTCBnzAN
BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyxlEqY9AcY0YwpMIsirzy/6o9M29LRa4
ziHURLugpyTKugtAkS5c2Gyt9lf7gdZBcVZ8KD6cszanQqKlZrl0h74E/S13tDqM
rhR4DHeZssstn5LNK57WYx/vw84bmd6Yq6SeP4geq0JfO+y3Ruu+eePtQSOSzS9F
wGpKyAHo4AcCAwEAAaNQME4wHQYDVR0OBBYEFNVJHVPJNwqEcG51lpqZJWVPaysF
MB8GA1UdIwQYMBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQEFBQADgYEAA1CMZgzQuQAslZ/i6OpFmRzuT/0KAfd6s8n6rf+6
xRvbgLlop8b8XfhhC/IwwoHU0i86o3vV3ZJjEVcdwTDEwpnyCfhFjhXzNZFqL8Ak
Olqy5HFd/+xysTLbdmhHtBIdOeUK1qz/u9I14A71XWiknjcxHya2Ghxg4yIZVdKh
oTQ=
-----END CERTIFICATE-----

16
icinga-app/ca.key Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMsZRKmPQHGNGMKT
CLIq88v+qPTNvS0WuM4h1ES7oKckyroLQJEuXNhsrfZX+4HWQXFWfCg+nLM2p0Ki
pWa5dIe+BP0td7Q6jK4UeAx3mbLLLZ+SzSue1mMf78POG5nemKuknj+IHqtCXzvs
t0brvnnj7UEjks0vRcBqSsgB6OAHAgMBAAECgYBg4Ku06cUGpRQjc/lY604hh1bW
dvD++fCrOs3C/3DRaaZd+hIRbnkRLz4H3M32j9nlkyhkFgGvJqnACk81Yc8oOu86
Pm7bOdEj8v31qq943NCps5tdKHepXM0Z6A8GjaR2ias39NKxVDacBoFzSDAVArTL
p6dyqLjsW5Y3INeHmQJBAPB6w9iqa31GLXMEMeP5LA4+2p3aHPQ25ptMCUcp/Vc6
40GOSIlLb8rfE+q1ZacChv94jSNLybR+U9++8DLIxnMCQQDYNORSo57mVSebDr7e
Gx8BDbyC+yAgiAi+qfJRekQ0I+R1SxfkCIBSWNrQ944isn0eRcr7+BWVl/WOrVSk
vccdAkBEwbURU9ib3t7Lzd0941ZXVF1JWL2CjdftexYEBNtsf2fOrJHMv4bdKF8X
cnn4AF782EjyWI75Tk1I4dzniERFAkBKZ9lzvy9+ISwiJq71DOxclnebtATYbThl
NWNZOvSh5QBIhXFRXsOak02qwKc/taFte6Nhl30GIGe3lFse3tjZAkBguOZFeSOO
hIAxMD+QpDUHZRYEjhDtPn3oAkLgBNUdeajffLdt4SmRa26t4QnSAE8kkbadIm6A
z52CJc8G2ALA
-----END PRIVATE KEY-----

17
icinga-app/icinga-c1.crt Normal file
View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICtzCCAiCgAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJERTEQ
MA4GA1UECAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxO
RVRXQVlTIEdtYkgxHDAaBgNVBAMME0ljaW5nYSBTbmFrZSBPaWwgQ0EwHhcNMTIw
NDI0MTE0NzQ2WhcNMTMwNDI0MTE0NzQ2WjBeMQswCQYDVQQGEwJERTEQMA4GA1UE
CAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxORVRXQVlT
IEdtYkgxEjAQBgNVBAMMCWljaW5nYS1jMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEAysHrzHs9WfQR4cEUx2hFZQmbM+Ssi5L63yqnzxEvVQ3GlM+uIceK1Kvx
9EexoUDLhxJOaUmigc6Pcs2mAjcpEwObnzW4pLuMKa7ngGLrnUpmmDXdGoxkCbi7
CP3s5yC7ZZ6bDiPMhRi/TRvY6+uQf+yew5daA3p87jocgRjhRicCAwEAAaN7MHkw
CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
dGlmaWNhdGUwHQYDVR0OBBYEFPzsYbQZdbq+pcFJWoenWREW6WhMMB8GA1UdIwQY
MBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMA0GCSqGSIb3DQEBBQUAA4GBAMLP1GJf
0hFdrEpGq+NvxTVx7wD30enAot5x2HLx4HuFohQJz/VZ45v+srrA+HEXbBFXPOd4
nB2XtcDDidFKTt5E03HBwDGGZvnB3f1KXYi7B50imKrwVVzgp5nGBM4hSzWGovEX
EYofmhk0fQg9qiKQrjwNib/4/b0srwEswfdj
-----END CERTIFICATE-----

16
icinga-app/icinga-c1.key Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMrB68x7PVn0EeHB
FMdoRWUJmzPkrIuS+t8qp88RL1UNxpTPriHHitSr8fRHsaFAy4cSTmlJooHOj3LN
pgI3KRMDm581uKS7jCmu54Bi651KZpg13RqMZAm4uwj97Ocgu2Wemw4jzIUYv00b
2OvrkH/snsOXWgN6fO46HIEY4UYnAgMBAAECgYBj/1QOG1HcxXT0REe9OP3QoPY8
l7FJfQnheqYch7syVYL07aBR5Jnh3ZONCLbgcpZuXWbyonBVWMyCsE4Jla7ZYnBB
plZPMYmzGxEbTM5Bu+PZ0M1NLvdLCRq24IVwTZwBBZ3sr7rVSnAYi2Li0SWQEaCN
P+PbZP1P9i9WiI+VIQJBAPYBfVWNk3gY1V0YuuH9fmYRBg5/B1qy8bYS9FLVIq2z
5r7eI1EypcVtyTx6yMmLuWj4mpNOKv5sxQsHalzRo18CQQDS/qPoDqMkDB9r9XeZ
qS2XQdX6YxzGisqL8vWcZ/Y6YX81qm3Lpp2wEexUXvWXRI5RdguctZFKTVyG/Mic
C9o5AkAEtvKX+SaiXpd4OUkbm6gYfKsJDBYv/s3zF1nnXH5VpeT+M3Op0raqmfgJ
WLEQa8UZ5enQeOcKCTudgn7fWIUxAkEAmXWfXP6YZXVzvR+xt08225aEvTItEbKM
krFJNlLe4aNb1Hp6lO5ALnk6vDq8wSKZqGIFHBtq6vHNZFiix+xO8QJAIZ3pB/Bz
Il8NjZMg8t/1sJdn32Xe9D0lZRtZTKC8zF/78NDFEo9qqE4Sr1CUfqlx18HXOxCO
Vg4lv6+jUj+LmA==
-----END PRIVATE KEY-----

17
icinga-app/icinga-c2.crt Normal file
View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICtzCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJERTEQ
MA4GA1UECAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxO
RVRXQVlTIEdtYkgxHDAaBgNVBAMME0ljaW5nYSBTbmFrZSBPaWwgQ0EwHhcNMTIw
NDI0MTE0NzU1WhcNMTMwNDI0MTE0NzU1WjBeMQswCQYDVQQGEwJERTEQMA4GA1UE
CAwHQmF2YXJpYTESMBAGA1UEBwwJTnVyZW1iZXJnMRUwEwYDVQQKDAxORVRXQVlT
IEdtYkgxEjAQBgNVBAMMCWljaW5nYS1jMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEArOcVui1AWojbPuK/7We9uwIBLaOLfBxQRI3+k6PzzjdtaXT4ijT/DSav
Q5U4wGOLYh0yuSyqS88QX/DsqDGLXnSVs8mT37bioMOw2XinqaNQ6xK4vyi0FYxS
ewI6YOkYi7135NEaSUgd82hk4wFtiIb67T7hkHRc7Aui6FmT/SkCAwEAAaN7MHkw
CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy
dGlmaWNhdGUwHQYDVR0OBBYEFGvpolD5na6L70kNFO1tYGYIwDhqMB8GA1UdIwQY
MBaAFNVJHVPJNwqEcG51lpqZJWVPaysFMA0GCSqGSIb3DQEBBQUAA4GBAIhhjKWw
5JKirNidgG9PuD8x47VsRTkESLlq/pS7KjkE1nWCG9JpR5oVSzx2WXomiaAZ4q2C
WS1z4HD9HF4NbhY+xVBi0Fj/kotuXCCweRo5EVp7Q4fabm1maJemFwMTHGhBLu7a
v4dquYyOk9Dhkwcjajyn+KWceCoUTdI3LB2t
-----END CERTIFICATE-----

16
icinga-app/icinga-c2.key Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKznFbotQFqI2z7i
v+1nvbsCAS2ji3wcUESN/pOj8843bWl0+Io0/w0mr0OVOMBji2IdMrksqkvPEF/w
7Kgxi150lbPJk9+24qDDsNl4p6mjUOsSuL8otBWMUnsCOmDpGIu9d+TRGklIHfNo
ZOMBbYiG+u0+4ZB0XOwLouhZk/0pAgMBAAECgYEAkbEavslYm7EMRX4dyXcMCaNT
yNgxNcBJ5qpbpJ6XVuGfoSf+Mb8cV0GMl38K1hpLHb6Kujwntz9ghedmEwfEbcw0
TkSaNz1+7omM+485S2YvXJyR1kO8eEKONVlGuxgO/ItiR+e1J6wMnY5JhctgRH6W
aOqy+5Ua1ATIdiOYrI0CQQDku3CNDOipwDmguBIrlxa+6NsATJRjqFmHqWdu2pYh
KRl3Sypn+LfhdFRbo3licU5a1OqydGmVpRTpQPJO7MoHAkEAwYPQIGZd/60O2LWV
M5eLnwKrrQSfrQ/Lngz0Qko4Yo913Ef2PC2QQ6p9cOt3vMPZDK5znlzQbBCa6cAH
tBvzTwJAT+uaaP5wsRdkS17lomt5XB1aoCEh3Cxvk/JCHL6tpEqLBl6yI4AJJ/KQ
ozBccmQqv5wToWUBm3MB+nph7+fWswJAMKcQQ6UZCvganHeCzJbUXqUQPo7ECoHH
IrSFEMmSRY1mB3z8NoMKG0kZArPgxc/DmUGfBfi12gWOvSgvh6PjVwJBALKECoe5
nmxhHTFbs4+UCFTzp6BGtSBdr6to0ID7ykZWT6kBX/BHUnoJUEpDtNLXzbek/KeI
ymg0LgRkHoWNpLY=
-----END PRIVATE KEY-----

View File

@ -2,6 +2,11 @@
using namespace icinga;
EndpointManager::EndpointManager(shared_ptr<SSL_CTX> sslContext)
{
m_SSLContext = sslContext;
}
void EndpointManager::SetIdentity(string identity)
{
m_Identity = identity;
@ -14,7 +19,7 @@ string EndpointManager::GetIdentity(void) const
void EndpointManager::AddListener(unsigned short port)
{
JsonRpcServer::Ptr server = make_shared<JsonRpcServer>();
JsonRpcServer::Ptr server = make_shared<JsonRpcServer>(m_SSLContext);
RegisterServer(server);
server->MakeSocket();
@ -26,7 +31,7 @@ void EndpointManager::AddListener(unsigned short port)
void EndpointManager::AddConnection(string host, unsigned short port)
{
JsonRpcEndpoint::Ptr endpoint = make_shared<JsonRpcEndpoint>();
endpoint->Connect(host, port);
endpoint->Connect(host, port, m_SSLContext);
RegisterEndpoint(endpoint);
}

View File

@ -11,6 +11,7 @@ struct I2_ICINGA_API NewEndpointEventArgs : public EventArgs
class I2_ICINGA_API EndpointManager : public Object
{
shared_ptr<SSL_CTX> m_SSLContext;
list<JsonRpcServer::Ptr> m_Servers;
list<Endpoint::Ptr> m_Endpoints;
string m_Identity;
@ -27,6 +28,8 @@ public:
typedef shared_ptr<EndpointManager> Ptr;
typedef weak_ptr<EndpointManager> WeakPtr;
EndpointManager(shared_ptr<SSL_CTX> sslContext);
void SetIdentity(string identity);
string GetIdentity(void) const;

View File

@ -9,11 +9,6 @@
using namespace icinga;
IcingaApplication::IcingaApplication(void)
{
m_EndpointManager = make_shared<EndpointManager>();
}
int IcingaApplication::Main(const vector<string>& args)
{
#ifdef _WIN32
@ -27,6 +22,10 @@ int IcingaApplication::Main(const vector<string>& args)
return EXIT_FAILURE;
}
shared_ptr<SSL_CTX> sslContext = Utility::MakeSSLContext("icinga-c1.crt", "icinga-c1.key", "ca.crt");
m_EndpointManager = make_shared<EndpointManager>(sslContext);
string componentDirectory = GetExeDirectory() + "/../lib/icinga";
AddComponentSearchDir(componentDirectory);

View File

@ -23,8 +23,6 @@ public:
typedef shared_ptr<IcingaApplication> Ptr;
typedef weak_ptr<IcingaApplication> WeakPtr;
IcingaApplication(void);
int Main(const vector<string>& args);
void PrintUsage(const string& programPath);

View File

@ -59,13 +59,13 @@ bool JsonRpcEndpoint::IsAllowedMethodSource(string method) const
return false;
}
void JsonRpcEndpoint::Connect(string host, unsigned short port)
void JsonRpcEndpoint::Connect(string host, unsigned short port, shared_ptr<SSL_CTX> sslContext)
{
char portStr[20];
sprintf(portStr, "%d", port);
SetAddress("jsonrpc-tcp://" + host + ":" + portStr);
JsonRpcClient::Ptr client = make_shared<JsonRpcClient>();
JsonRpcClient::Ptr client = make_shared<JsonRpcClient>(RoleOutbound, sslContext);
client->MakeSocket();
client->Connect(host, port);
client->Start();

View File

@ -7,6 +7,7 @@ namespace icinga
class I2_ICINGA_API JsonRpcEndpoint : public Endpoint
{
private:
shared_ptr<SSL_CTX> m_SSLContext;
string m_Address;
JsonRpcClient::Ptr m_Client;
map<string, Endpoint::Ptr> m_PendingCalls;
@ -25,7 +26,8 @@ public:
typedef shared_ptr<JsonRpcEndpoint> Ptr;
typedef weak_ptr<JsonRpcEndpoint> WeakPtr;
void Connect(string host, unsigned short port);
void Connect(string host, unsigned short port,
shared_ptr<SSL_CTX> sslContext);
JsonRpcClient::Ptr GetClient(void);
void SetClient(JsonRpcClient::Ptr client);

View File

@ -2,9 +2,12 @@
using namespace icinga;
JsonRpcClient::JsonRpcClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
: TLSClient(role, sslContext) { }
void JsonRpcClient::Start(void)
{
TCPClient::Start();
TLSClient::Start();
OnDataAvailable += bind_weak(&JsonRpcClient::DataAvailableHandler, shared_from_this());
}
@ -40,3 +43,8 @@ int JsonRpcClient::DataAvailableHandler(const EventArgs& ea)
return 0;
}
TCPClient::Ptr icinga::JsonRpcClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
{
return make_shared<JsonRpcClient>(role, sslContext);
}

View File

@ -12,7 +12,7 @@ struct I2_JSONRPC_API NewMessageEventArgs : public EventArgs
icinga::Message Message;
};
class I2_JSONRPC_API JsonRpcClient : public TCPClient
class I2_JSONRPC_API JsonRpcClient : public TLSClient
{
private:
int DataAvailableHandler(const EventArgs& ea);
@ -21,6 +21,8 @@ public:
typedef shared_ptr<JsonRpcClient> Ptr;
typedef weak_ptr<JsonRpcClient> WeakPtr;
JsonRpcClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
void SendMessage(const Message& message);
virtual void Start(void);
@ -28,6 +30,8 @@ public:
Event<NewMessageEventArgs> OnNewMessage;
};
TCPClient::Ptr JsonRpcClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
}
#endif /* JSONRPCCLIENT_H */

View File

@ -2,7 +2,7 @@
using namespace icinga;
JsonRpcServer::JsonRpcServer(void)
JsonRpcServer::JsonRpcServer(shared_ptr<SSL_CTX> sslContext)
{
SetClientFactory(factory<JsonRpcClient>);
SetClientFactory(bind(&JsonRpcClientFactory, RoleInbound, sslContext));
}

View File

@ -10,7 +10,7 @@ public:
typedef shared_ptr<JsonRpcServer> Ptr;
typedef weak_ptr<JsonRpcServer> WeakPtr;
JsonRpcServer(void);
JsonRpcServer(shared_ptr<SSL_CTX> sslContext);
};
}