diff options
author | bju <bju@maxi.fritz.box> | 2017-05-04 23:58:02 +0200 |
---|---|---|
committer | bju <bju@maxi.fritz.box> | 2017-05-04 23:58:02 +0200 |
commit | 049975cbda6327aae542bac5dd1acd6fe97d18a4 (patch) | |
tree | 687b5cf1191b03613d321aadf0438d28c886778b | |
parent | 888f87e2ac5fc9ed6e8f40141252dac302ddb688 (diff) | |
download | vdr-manager-049975cbda6327aae542bac5dd1acd6fe97d18a4.tar.gz vdr-manager-049975cbda6327aae542bac5dd1acd6fe97d18a4.tar.bz2 |
Feature #2496: Support certificate replacement without VDR restart
-rw-r--r-- | vdr-vdrmanager/clientsock.cpp | 81 | ||||
-rw-r--r-- | vdr-vdrmanager/clientsock.h | 6 | ||||
-rw-r--r-- | vdr-vdrmanager/serversock.cpp | 107 | ||||
-rw-r--r-- | vdr-vdrmanager/serversock.h | 1 | ||||
-rw-r--r-- | vdr-vdrmanager/sock.h | 2 |
5 files changed, 117 insertions, 80 deletions
diff --git a/vdr-vdrmanager/clientsock.cpp b/vdr-vdrmanager/clientsock.cpp index 3f78007..0bce192 100644 --- a/vdr-vdrmanager/clientsock.cpp +++ b/vdr-vdrmanager/clientsock.cpp @@ -17,7 +17,7 @@ static int clientno = 0; /* * cVdrmonClientSocket */ -cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password, int compressionMode) { +cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password, int compressionMode, const char * certFile, const char * keyFile) { readbuf = ""; writebuf = ""; sendbuf = NULL; @@ -28,6 +28,8 @@ cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password, int comp client = ++clientno; this->password = password; this->compressionMode = compressionMode; + this->certFile = certFile; + this->keyFile = keyFile; login = false; compression = false; initCompression = false; @@ -43,6 +45,9 @@ cVdrmanagerClientSocket::~cVdrmanagerClientSocket() { if (ssl) { SSL_free(ssl); } + if (sslCtx) { + SSL_CTX_free(sslCtx); + } #endif } @@ -292,6 +297,64 @@ int cVdrmanagerClientSocket::FlushNoSSL() { #if VDRMANAGER_USE_SSL +bool cVdrmanagerClientSocket::LoadCerts() { + + if (certFile) { + isyslog("[vdrmanager] initialize SSL context"); + + SSL_METHOD * method = (SSL_METHOD *)SSLv23_server_method(); + sslCtx = SSL_CTX_new(method); + if (sslCtx == NULL) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error initializing SSL context: %s", error); + SSL_CTX_free(sslCtx); + sslCtx = NULL; + return false; + } + SSL_CTX_set_options(sslCtx, SSL_OP_NO_SSLv3); + + /* set the local certificate from CertFile */ + if (SSL_CTX_use_certificate_chain_file(sslCtx, certFile) != 1) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error loading cert chain file %s: %s", certFile, error); + SSL_CTX_free(sslCtx); + sslCtx = NULL; + } else { + isyslog("[vdrmanager] cert chain file loaded %s", certFile); + } + + /* set the private key from KeyFile */ + if (SSL_CTX_use_PrivateKey_file(sslCtx, keyFile, SSL_FILETYPE_PEM) != 1) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error loading key file %s: %s", keyFile, error); + SSL_CTX_free(sslCtx); + sslCtx = NULL; + return false; + } else { + isyslog("[vdrmanager] key file loaded %s", keyFile); + } + + /* verify private key */ + if (!SSL_CTX_check_private_key(sslCtx)) { + long errorCode = ERR_get_error(); + char * error = ERR_error_string(errorCode, NULL); + esyslog("[vdrmanager] Error checking SSL keys: %s", error); + SSL_CTX_free(sslCtx); + sslCtx = NULL; + return false; + } + + SSL_CTX_set_mode(sslCtx, SSL_MODE_ENABLE_PARTIAL_WRITE); + + return true; + } + + return true; +} + int cVdrmanagerClientSocket::FlushSSL() { sslReadWrite = SSL_NO_RETRY; @@ -325,20 +388,22 @@ int cVdrmanagerClientSocket::FlushSSL() { #endif -bool cVdrmanagerClientSocket::Attach(int fd, SSL_CTX * sslCtx) { +bool cVdrmanagerClientSocket::Attach(int fd) { sock = fd; if (!MakeDontBlock()) { return false; } #if VDRMANAGER_USE_SSL - if (sslCtx) { - ssl = SSL_new(sslCtx); - SSL_set_accept_state(ssl); - BIO *bio = BIO_new_socket(sock, BIO_NOCLOSE); - SSL_set_bio(ssl, bio, bio); - BIO_set_nbio(bio, 1); + + if (!LoadCerts()) { + return false; } + ssl = SSL_new(sslCtx); + SSL_set_accept_state(ssl); + BIO *bio = BIO_new_socket(sock, BIO_NOCLOSE); + SSL_set_bio(ssl, bio, bio); + BIO_set_nbio(bio, 1); #endif return true; diff --git a/vdr-vdrmanager/clientsock.h b/vdr-vdrmanager/clientsock.h index 6c3fba3..c2062e6 100644 --- a/vdr-vdrmanager/clientsock.h +++ b/vdr-vdrmanager/clientsock.h @@ -37,14 +37,15 @@ private: bool initCompression; int compressionMode; #if VDRMANAGER_USE_SSL + SSL_CTX * sslCtx; SSL * ssl; int sslReadWrite; int sslWantsSelect; #endif public: - cVdrmanagerClientSocket(const char * password, int compressionMode); + cVdrmanagerClientSocket(const char * password, int compressionMode, const char * certFile, const char * keyFile); virtual ~cVdrmanagerClientSocket(); - bool Attach(int fd, SSL_CTX * sslCtx); + bool Attach(int fd); bool IsLineComplete(); bool GetLine(string& line); void Write(string line); @@ -58,6 +59,7 @@ public: int GetSslReadWrite(); int GetSslWantsSelect(); bool IsSSL(); + bool LoadCerts(); #endif bool Disconnected(); void Disconnect(); diff --git a/vdr-vdrmanager/serversock.cpp b/vdr-vdrmanager/serversock.cpp index 0cd9f1f..0c44a45 100644 --- a/vdr-vdrmanager/serversock.cpp +++ b/vdr-vdrmanager/serversock.cpp @@ -19,14 +19,9 @@ static int clientno = 0; */ cVdrmanagerServerSocket::cVdrmanagerServerSocket() : cVdrmanagerSocket() { port = -1; - sslCtx = NULL; } cVdrmanagerServerSocket::~cVdrmanagerServerSocket() { -#if VDRMANAGER_USE_SSL - if (sslCtx) - SSL_CTX_free(sslCtx); -#endif } bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp, int compressionMode, @@ -34,8 +29,10 @@ bool cVdrmanagerServerSocket::Create(int port, const char * password, bool force this->port = port; this->password = password; - this->forceCheckSvdrp = forceCheckSvrp; - this->compressionMode = compressionMode; + this->forceCheckSvdrp = forceCheckSvrp; + this->compressionMode = compressionMode; + this->certFile = certFile; + this->keyFile = keyFile; // create socket sock = socket(PF_INET, SOCK_STREAM, 0); @@ -75,8 +72,7 @@ bool cVdrmanagerServerSocket::Create(int port, const char * password, bool force } #if VDRMANAGER_USE_SSL - - if (certFile) { + if (certFile) { isyslog("[vdrmanager] initialize SSL"); OpenSSL_add_all_algorithms(); @@ -86,71 +82,44 @@ bool cVdrmanagerServerSocket::Create(int port, const char * password, bool force SSL_load_error_strings(); SSL_library_init(); - - SSL_METHOD * method = (SSL_METHOD *)SSLv23_server_method(); - sslCtx = SSL_CTX_new(method); - if (sslCtx == NULL) { - long errorCode = ERR_get_error(); - char * error = ERR_error_string(errorCode, NULL); - esyslog("[vdrmanager] Error initializing SSL context: %s", error); - Close(); - return false; - } - SSL_CTX_set_options(sslCtx, SSL_OP_NO_SSLv3); - - /* set the local certificate from CertFile */ - SSL_CTX_use_certificate_file(sslCtx, certFile, SSL_FILETYPE_PEM); - /* set the private key from KeyFile */ - SSL_CTX_use_PrivateKey_file(sslCtx, keyFile, SSL_FILETYPE_PEM); - /* verify private key */ - if (!SSL_CTX_check_private_key(sslCtx)) { - long errorCode = ERR_get_error(); - char * error = ERR_error_string(errorCode, NULL); - esyslog("[vdrmanager] Error checking SSL keys: %s", error); - Close(); - return false; - } - - SSL_CTX_set_mode(sslCtx, SSL_MODE_ENABLE_PARTIAL_WRITE); - } + } #endif - return true; } cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { - cVdrmanagerClientSocket * newsocket = NULL; - - isyslog("[vdrmanager] new %sclient on port %d", sslCtx ? "SSL " : "", port); - - // accept the connection - struct sockaddr_in clientname; - uint size = sizeof(clientname); - int newsock = accept(sock, (struct sockaddr *) &clientname, &size); - if (newsock > 0) { - // create client socket - newsocket = new cVdrmanagerClientSocket(password, compressionMode); - if (!newsocket->Attach(newsock, sslCtx)) { - delete newsocket; - return NULL; - } - - if (!IsPasswordSet() || forceCheckSvdrp == true) { - bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); - if (!accepted) { - newsocket->Write(string("NACC Access denied.\n")); - newsocket->Flush(); - delete newsocket; - newsocket = NULL; - } - dsyslog( - "[vdrmanager] connect from %s, port %hd - %s", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), accepted ? "accepted" : "DENIED"); - } - } else if (errno != EINTR && errno != EAGAIN - ) - LOG_ERROR; - - return newsocket; + cVdrmanagerClientSocket * newsocket = NULL; + + isyslog("[vdrmanager] new client on port %d", port); + + // accept the connection + struct sockaddr_in clientname; + uint size = sizeof(clientname); + int newsock = accept(sock, (struct sockaddr *) &clientname, &size); + if (newsock > 0) { + // create client socket + newsocket = new cVdrmanagerClientSocket(password, compressionMode, certFile, keyFile); + if (!newsocket->Attach(newsock)) { + delete newsocket; + return NULL; + } + + if (!IsPasswordSet() || forceCheckSvdrp == true) { + bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); + if (!accepted) { + newsocket->Write(string("NACC Access denied.\n")); + newsocket->Flush(); + delete newsocket; + newsocket = NULL; + } + dsyslog("[vdrmanager] connect from %s, port %hd - %s", + inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port), + accepted ? "accepted" : "DENIED"); + } + } else if (errno != EINTR && errno != EAGAIN) + LOG_ERROR; + + return newsocket; } int cVdrmanagerServerSocket::GetPort() { diff --git a/vdr-vdrmanager/serversock.h b/vdr-vdrmanager/serversock.h index e8c939e..6269574 100644 --- a/vdr-vdrmanager/serversock.h +++ b/vdr-vdrmanager/serversock.h @@ -24,7 +24,6 @@ class cVdrmanagerServerSocket : public cVdrmanagerSocket { private: int port; - SSL_CTX * sslCtx; public: cVdrmanagerServerSocket(); virtual ~cVdrmanagerServerSocket(); diff --git a/vdr-vdrmanager/sock.h b/vdr-vdrmanager/sock.h index bc19d6d..4cc550f 100644 --- a/vdr-vdrmanager/sock.h +++ b/vdr-vdrmanager/sock.h @@ -25,6 +25,8 @@ protected: const char * password; bool forceCheckSvdrp; int compressionMode; + const char * certFile; + const char * keyFile; protected: cVdrmanagerSocket(); bool IsPasswordSet(); |