From 321bebe669a5aafc2c4ff0e9f59e60de2fa79bac Mon Sep 17 00:00:00 2001 From: bju Date: Wed, 22 Jan 2014 02:28:34 +0100 Subject: http://projects.vdr-developer.org/issues/1267: - some fixes on client side certificate validation - added SSL server side support to the plugin --- vdr-vdrmanager/Makefile | 4 +- vdr-vdrmanager/clientsock.cpp | 2 +- vdr-vdrmanager/compressor.cpp | 8 +- vdr-vdrmanager/handler.cpp | 177 ++++++------ vdr-vdrmanager/select.cpp | 90 ++++-- vdr-vdrmanager/select.h | 8 +- vdr-vdrmanager/sock.cpp | 302 +-------------------- vdr-vdrmanager/sock.h | 48 +--- vdr-vdrmanager/vdrmanager.cpp | 47 +++- vdr-vdrmanager/vdrmanagerthread.cpp | 42 ++- vdr-vdrmanager/vdrmanagerthread.h | 6 +- vdrmanager/res/values-de/strings.xml | 2 +- vdrmanager/res/values-it/strings.xml | 2 +- vdrmanager/res/values-uk/strings.xml | 2 +- vdrmanager/res/values/strings.xml | 2 +- vdrmanager/res/xml/vdr_prefs.xml | 2 +- .../vdrmanager/gui/CertificateProblemDialog.java | 9 +- .../vdrmanager/utils/svdrp/SvdrpClient.java | 1 + 18 files changed, 264 insertions(+), 490 deletions(-) diff --git a/vdr-vdrmanager/Makefile b/vdr-vdrmanager/Makefile index e63dc13..a5119ce 100644 --- a/vdr-vdrmanager/Makefile +++ b/vdr-vdrmanager/Makefile @@ -47,7 +47,7 @@ SOFILE = libvdr-$(PLUGIN).so ### The object files (add further files here): -OBJS = $(PLUGIN).o sock.o vdrmanagerthread.o select.o handler.o helpers.o compressor.o +OBJS = $(PLUGIN).o sock.o serversock.o clientsock.o vdrmanagerthread.o select.o handler.o helpers.o compressor.o ### The main target: @@ -96,7 +96,7 @@ install-i18n: $(I18Nmsgs) ### Targets: $(SOFILE): $(OBJS) - $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ -lz + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ -lz -lssl install-lib: $(SOFILE) install -D $^ $(LIBDIR)/$^.$(APIVERSION) diff --git a/vdr-vdrmanager/clientsock.cpp b/vdr-vdrmanager/clientsock.cpp index 82b12f4..91e6704 100644 --- a/vdr-vdrmanager/clientsock.cpp +++ b/vdr-vdrmanager/clientsock.cpp @@ -376,7 +376,7 @@ void cVdrmanagerClientSocket::Compress() { sendsize = compressor.getDataSize(); double ratio = 1.0 * writebuf.length() / sendsize; - isyslog("Compression stats: raw %ld, compressed %ld, ratio %f:1", writebuf.length(), sendsize, ratio); + dsyslog("[vdrmanager] Compression stats: raw %ld, compressed %ld, ratio %f:1", writebuf.length(), sendsize, ratio); } int cVdrmanagerClientSocket::GetSslReadWrite() { diff --git a/vdr-vdrmanager/compressor.cpp b/vdr-vdrmanager/compressor.cpp index 6a479f3..c8322b8 100644 --- a/vdr-vdrmanager/compressor.cpp +++ b/vdr-vdrmanager/compressor.cpp @@ -56,7 +56,13 @@ bool cCompressor::CompressGzip(string text) { close(in_fd[0]); close(out_fd[1]); - write(in_fd[1], text.c_str(), text.length()); + if (write(in_fd[1], text.c_str(), text.length()) != text.length()) + { + close(in_fd[1]); + close(out_fd[0]); + return false; + } + close(in_fd[1]); char buf[32*1024]; diff --git a/vdr-vdrmanager/handler.cpp b/vdr-vdrmanager/handler.cpp index ea15296..4a787c7 100644 --- a/vdr-vdrmanager/handler.cpp +++ b/vdr-vdrmanager/handler.cpp @@ -17,104 +17,97 @@ bool cHandler::HandleNewClient(cVdrmanagerClientSocket * sock) bool cHandler::HandleClientRequest(cVdrmanagerClientSocket * sock) { - bool closeSocket = true; + while (!sock->IsLineComplete() && sock->Read()) + ; - while(sock->Read()) - { - // get lines - while (sock->IsLineComplete()) - { - string line; - sock->GetLine(line); + if (sock->IsLineComplete()) { - // parse request - size_t space = line.find(' '); - string cmd; - string args; - if (space != string::npos) { - cmd = cHelpers::ToUpper(line.substr(0, space)); - args = cHelpers::Trim(line.substr(space+1)); - } else { - cmd = cHelpers::ToUpper(line); - args = ""; - } + string line; + sock->GetLine(line); - if (!sock->IsLoggedIn() && cmd != "PASSWD") { - sock->PutLine("!ERROR\r\n"); - } - else if (cmd == "PASSWD") - { - if (args != sock->GetPassword()) { - sock->PutLine("!ERROR\r\n"); - } else { - sock->SetLoggedIn(); - sock->PutLine("!OK\r\n"); - } - closeSocket = false; - } - else if (cmd == "COMPRESS") - { - sock->ActivateCompression(); - closeSocket = false; - } - else if (cmd == "TIMERS") - { - string text = cHelpers::GetTimers(args); - sock->PutLine(text); - } - else if (cmd == "CHANNELS") - { - string text = cHelpers::GetChannels(args); - sock->PutLine(text); - } - else if (cmd == "TEVENTS") - { - string text = cHelpers::GetTimeEvents(args); - sock->PutLine(text); - } - else if (cmd == "CEVENTS") - { - string text = cHelpers::GetChannelEvents(args); - sock->PutLine(text); - } - else if (cmd == "TIMER") - { - string text = cHelpers::SetTimer(args); - sock->PutLine(text); - } - else if (cmd == "SEARCH") - { - string text = cHelpers::SearchEvents(args); - sock->PutLine(text); - } - else if(cmd == "RECORDINGS") - { - string text = cHelpers::GetRecordings(args); - sock->PutLine(text); - } - else if(cmd == "DRECORDING") - { - string text = cHelpers::DelRecording(args); - sock->PutLine(text); - } - else if (cmd == "SETCHANNEL") - { - string text = cHelpers::SetChannel(args); - sock->PutLine(text); - } - else if (cmd == "QUIT") - { - // close socket - sock->PutLine(string("Good bye! :-)\r\n")); - sock->Disconnect(); - } + isyslog("[vdrmanager] got %s", line.c_str()); - if (closeSocket) { - sock->Disconnect(); - } + // parse request + size_t space = line.find(' '); + string cmd; + string args; + if (space != string::npos) { + cmd = cHelpers::ToUpper(line.substr(0, space)); + args = cHelpers::Trim(line.substr(space+1)); + } else { + cmd = cHelpers::ToUpper(line); + args = ""; + } - sock->Flush(); + if (!sock->IsLoggedIn() && cmd != "PASSWD") { + sock->Write("!ERROR\r\n"); } + else if (cmd == "PASSWD") + { + if (args != sock->GetPassword()) { + sock->Write("!ERROR\r\n"); + } else { + sock->SetLoggedIn(); + sock->Write("!OK\r\n"); + } + } + else if (cmd == "COMPRESS") + { + sock->ActivateCompression(); + } + else if (cmd == "TIMERS") + { + string text = cHelpers::GetTimers(args); + sock->Write(text); + } + else if (cmd == "CHANNELS") + { + string text = cHelpers::GetChannels(args); + sock->Write(text); + } + else if (cmd == "TEVENTS") + { + string text = cHelpers::GetTimeEvents(args); + sock->Write(text); + } + else if (cmd == "CEVENTS") + { + string text = cHelpers::GetChannelEvents(args); + sock->Write(text); + } + else if (cmd == "TIMER") + { + string text = cHelpers::SetTimer(args); + sock->Write(text); + } + else if (cmd == "SEARCH") + { + string text = cHelpers::SearchEvents(args); + sock->Write(text); + } + else if(cmd == "RECORDINGS") + { + string text = cHelpers::GetRecordings(args); + sock->Write(text); + } + else if(cmd == "DRECORDING") + { + string text = cHelpers::DelRecording(args); + sock->Write(text); + } + else if (cmd == "SETCHANNEL") + { + string text = cHelpers::SetChannel(args); + sock->Write(text); + } + else if (cmd == "QUIT") + { + // close socket + sock->Write(string("Good bye! :-)\r\n")); + sock->Disconnect(); + } + + sock->Flush(); } return true; diff --git a/vdr-vdrmanager/select.cpp b/vdr-vdrmanager/select.cpp index c569f42..2080ad0 100644 --- a/vdr-vdrmanager/select.cpp +++ b/vdr-vdrmanager/select.cpp @@ -17,6 +17,7 @@ struct node { cSelect::cSelect() { serversocket = NULL; + sslServersocket = NULL; clientsockets = NULL; clientsocketcount = 0; handler = new cHandler; @@ -29,6 +30,8 @@ cSelect::cSelect() { cSelect::~cSelect() { if (serversocket) delete serversocket; + if (sslServersocket) + delete sslServersocket; while (clientsockets) { node * next = clientsockets->next; @@ -44,8 +47,9 @@ cSelect::~cSelect() { delete pollfds; } -void cSelect::SetServerSocket(cVdrmanagerServerSocket * sock) { +void cSelect::SetServerSockets(cVdrmanagerServerSocket * sock, cVdrmanagerServerSocket * sslSock) { serversocket = sock; + sslServersocket = sslSock; } void cSelect::AddClientSocket(cVdrmanagerClientSocket * sock) { @@ -107,31 +111,58 @@ bool cSelect::Action() { return true; } -void cSelect::CreatePollfds() { +int cSelect::CreatePollfds() { + + int i = 0; + + int count = clientsocketcount + (sslServersocket ? 2 : 1); // we poll for the server socket and for each client socket - pollfds = new struct pollfd[clientsocketcount + 1]; - pollfds[0].fd = serversocket->GetSocket(); - pollfds[0].events = POLLIN; + pollfds = new struct pollfd[count]; + + pollfds[i].fd = serversocket->GetSocket(); + pollfds[i].revents = 0; + pollfds[i++].events = POLLIN; + + if (sslServersocket) { + pollfds[i].fd = sslServersocket->GetSocket(); + pollfds[i].revents = 0; + pollfds[i++].events = POLLIN; + } node * curnode = clientsockets; - int i = 1; while (curnode) { - pollfds[i].fd = curnode->socket->GetSocket(); - pollfds[i].events = POLLIN | POLLHUP; - if (curnode->socket->WritePending()) { - pollfds[i].events |= POLLOUT; + cVdrmanagerClientSocket * sock = curnode->socket; + pollfds[i].fd = sock->GetSocket(); + if (sock->IsSSL()) { + if (sock->GetSslWantsSelect() == SSL_ERROR_WANT_READ) { + pollfds[i].events = POLLIN | POLLHUP; + } else if (sock->GetSslWantsSelect() == SSL_ERROR_WANT_WRITE) { + pollfds[i].events = POLLOUT; + } else { + pollfds[i].events = POLLIN | POLLHUP; + if (sock->WritePending()) + pollfds[i].events |= POLLOUT; + } + } else { + pollfds[i].events = POLLIN | POLLHUP; + if (curnode->socket->WritePending()) + pollfds[i].events |= POLLOUT; } pollfds[i++].revents = 0; curnode = curnode->next; } + + return count; } bool cSelect::Poll() { + // poll for events - CreatePollfds(); + int count = CreatePollfds(); + int rc = 0; - while ((rc = poll(pollfds, clientsocketcount + 1, -1)) < 0) { + while ((rc = poll(pollfds, count, -1)) < 0) { if (errno != EINTR) break; } @@ -146,10 +177,16 @@ bool cSelect::Poll() { return true; // client requests or outstanding writes - for (int i = 1; i < clientsocketcount + 1; i++) { + for (int i = (sslServersocket ? 2 : 1); i < count; i++) { cVdrmanagerClientSocket * sock = GetClientSocket(pollfds[i].fd); if (sock) { - if (pollfds[i].revents & POLLOUT) { + if ((pollfds[i].revents & (POLLIN|POLLOUT)) && sock->GetSslReadWrite() != SSL_NO_RETRY) { + if (sock->GetSslReadWrite() == SSL_RETRY_READ) { + handler->HandleClientRequest(sock); + } else { + sock->Flush(); + } + } else if (pollfds[i].revents & POLLOUT) { // possibly outstanding writes sock->Flush(); } else if (pollfds[i].revents & (POLLIN | POLLHUP)) { @@ -165,15 +202,22 @@ bool cSelect::Poll() { } // new client? - if (pollfds[0].revents & POLLIN) { - // get client socket - cVdrmanagerClientSocket * sock = serversocket->Accept(); - if (sock) { - // Add client socket - AddClientSocket(sock); - // Send current data - handler->HandleNewClient(sock); - } + for(int i = 0; i < (sslServersocket ? 2 : 1); i++) { + if (pollfds[i].revents & POLLIN) { + // get client socket + cVdrmanagerClientSocket * sock; + if (i == 0) + sock = serversocket->Accept(); + else + sock = sslServersocket->Accept(); + + if (sock) { + // Add client socket + AddClientSocket(sock); + // Send current data + handler->HandleNewClient(sock); + } + } } delete pollfds; diff --git a/vdr-vdrmanager/select.h b/vdr-vdrmanager/select.h index fbdeb02..2a7f5ba 100644 --- a/vdr-vdrmanager/select.h +++ b/vdr-vdrmanager/select.h @@ -7,7 +7,8 @@ #include #include -#include "sock.h" +#include "clientsock.h" +#include "serversock.h" #include "handler.h" struct node; @@ -17,6 +18,7 @@ private: node * clientsockets; int clientsocketcount; cVdrmanagerServerSocket * serversocket; + cVdrmanagerServerSocket * sslServersocket; cHandler * handler; struct pollfd * pollfds; bool stopped; @@ -26,13 +28,13 @@ public: cSelect(); virtual ~cSelect(); void DispatchVdrEvent(string event); - void SetServerSocket(cVdrmanagerServerSocket * sock); + void SetServerSockets(cVdrmanagerServerSocket * sock, cVdrmanagerServerSocket * sslSock); void AddClientSocket(cVdrmanagerClientSocket * sock); void RemoveClientSocket(cVdrmanagerClientSocket * sock); bool Action(); bool Stop(); private: - void CreatePollfds(); + int CreatePollfds(); cVdrmanagerClientSocket * GetClientSocket(int fd); bool Poll(); void NotifyClients(string event); diff --git a/vdr-vdrmanager/sock.cpp b/vdr-vdrmanager/sock.cpp index 1d1d907..7e7da70 100644 --- a/vdr-vdrmanager/sock.cpp +++ b/vdr-vdrmanager/sock.cpp @@ -3,12 +3,11 @@ */ #include #include +#include #include "sock.h" #include "helpers.h" #include "compressor.h" -static int clientno = 0; - /* * cVdrmonSocket */ @@ -51,304 +50,7 @@ const char * cVdrmanagerSocket::GetPassword() { return password; } -/* - * cVdrmonServerSocket - */ -cVdrmanagerServerSocket::cVdrmanagerServerSocket() : - cVdrmanagerSocket() { -} - -cVdrmanagerServerSocket::~cVdrmanagerServerSocket() { -} - -bool cVdrmanagerServerSocket::Create(int port, const char * password, bool forceCheckSvrp, int compressionMode) { - - this->password = password; - this->forceCheckSvdrp = forceCheckSvrp; - this->compressionMode = compressionMode; - - // create socket - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock < 0) { - LOG_ERROR; - return false; - } - - // allow it to always reuse the same port: - int ReUseAddr = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ReUseAddr, sizeof(ReUseAddr)); - - // bind to address - struct sockaddr_in name; - name.sin_family = AF_INET; - name.sin_port = htons(port); - name.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { - LOG_ERROR; - Close(); - return false; - } - - // make it non-blocking: - if (!MakeDontBlock()) { - Close(); - return false; - } - - // listen to the socket: - if (listen(sock, 100) < 0) { - LOG_ERROR; - Close(); - return false; - } - - return true; -} - -cVdrmanagerClientSocket * cVdrmanagerServerSocket::Accept() { - cVdrmanagerClientSocket * newsocket = NULL; - - // 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)) { - delete newsocket; - return NULL; - } - - if (!IsPasswordSet() || forceCheckSvdrp == true) { - bool accepted = SVDRPhosts.Acceptable(clientname.sin_addr.s_addr); - if (!accepted) { - newsocket->PutLine(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; -} - -/* - * cVdrmonClientSocket - */ -cVdrmanagerClientSocket::cVdrmanagerClientSocket(const char * password, int compressionMode) { - readbuf = ""; - writebuf = ""; - sendbuf = NULL; - sendsize = 0; - sendoffset = 0; - disconnected = false; - initDisconnect = false; - client = ++clientno; - this->password = password; - this->compressionMode = compressionMode; - login = false; - compression = false; - initCompression = false; -} - -cVdrmanagerClientSocket::~cVdrmanagerClientSocket() { -} - -bool cVdrmanagerClientSocket::IsLineComplete() { - // check a for complete line - string::size_type pos = readbuf.find("\r", 0); - if (pos == string::npos) - pos = readbuf.find("\n"); - return pos != string::npos; -} - bool cVdrmanagerSocket::IsPasswordSet(){ - return strcmp(password, ""); -} - -bool cVdrmanagerClientSocket::GetLine(string& line) { - // check the line - string::size_type pos = readbuf.find("\r", 0); - if (pos == string::npos) - pos = readbuf.find("\n", 0); - if (pos == string::npos) - return false; - - // extract the line ... - line = readbuf.substr(0, pos); - - // handle \r\n - if (readbuf[pos] == '\r' && readbuf.length() > pos - && readbuf[pos + 1] == '\n') - pos++; - - // ... and move the remainder - readbuf = readbuf.substr(pos + 1); - - return true; + return strcmp(password, ""); } -bool cVdrmanagerClientSocket::Read() { - if (Disconnected()) - return false; - - int rc; - bool len = 0; - char buf[2001]; - while ((rc = read(sock, buf, sizeof(buf) - 1)) > 0) { - buf[rc] = 0; - readbuf += buf; - len += rc; - } - - if (rc < 0 && errno != EAGAIN) - { - LOG_ERROR; - return false; - } else if (rc == 0) { - disconnected = true; - } - - return len > 0; -} - -bool cVdrmanagerClientSocket::Disconnected() { - return disconnected; -} - -void cVdrmanagerClientSocket::Disconnect() { - initDisconnect = true; -} - -bool cVdrmanagerClientSocket::PutLine(string line) { - - // fill writebuf - if (line.length() > 0) { - writebuf += line; - return true; - } - - // initialize sendbuf if needed - if (sendbuf == NULL) { - if (!compression) { - sendbuf = (char *)malloc(writebuf.length()+1); - strcpy(sendbuf, writebuf.c_str()); - sendsize = writebuf.length(); - } else { - Compress(); - } - sendoffset = 0; - writebuf.clear(); - } - - // send data - if (sendsize > 0) { - - // write so many bytes as possible - int rc = write(sock, sendbuf + sendoffset, sendsize); - if (rc < 0 && errno != EAGAIN) - { - LOG_ERROR; - - if (sendbuf != NULL) { - free(sendbuf); - sendbuf = NULL; - } - - return false; - } - sendsize -= rc; - sendoffset += rc; - } - - if (sendsize == 0) { - - if (sendbuf != NULL) { - free(sendbuf); - sendbuf = NULL; - } - - if (initCompression) { - isyslog("Compression is activated now"); - initCompression = false; - compression = true; - } - - if (initDisconnect) { - initDisconnect = false; - disconnected = true; - } - } - - return true; -} - -bool cVdrmanagerClientSocket::Flush() { - return PutLine(""); -} - -bool cVdrmanagerClientSocket::Attach(int fd) { - sock = fd; - return MakeDontBlock(); -} - -int cVdrmanagerClientSocket::GetClientId() { - return client; -} - -bool cVdrmanagerClientSocket::WritePending() { - return sendsize > 0; -} - -bool cVdrmanagerClientSocket::IsLoggedIn() { - return login || !password || !*password; -} - -void cVdrmanagerClientSocket::SetLoggedIn() { - login = true; -} - -void cVdrmanagerClientSocket::ActivateCompression() { - - string mode = "NONE"; - switch (compressionMode) { - case COMPRESSION_GZIP: - mode = "GZIP"; - initCompression = true; - break; - case COMPRESSION_ZLIB: - mode = "ZLIB"; - initCompression = true; - break; - default: - mode = "NONE"; - break; - } - - PutLine("!OK " + mode + "\r\n"); -} - -void cVdrmanagerClientSocket::Compress() { - cCompressor compressor = cCompressor(); - - switch (compressionMode) { - case COMPRESSION_GZIP: - compressor.CompressGzip(writebuf); - break; - case COMPRESSION_ZLIB: - compressor.CompressZlib(writebuf); - break; - } - - sendbuf = compressor.GetData(); - sendsize = compressor.getDataSize(); - - double ratio = 1.0 * writebuf.length() / sendsize; - dsyslog("[vdrmanager] Compression stats: raw %ld, compressed %ld, ratio %f:1", writebuf.length(), sendsize, ratio); -} diff --git a/vdr-vdrmanager/sock.h b/vdr-vdrmanager/sock.h index 25a7b83..f9e3ebf 100644 --- a/vdr-vdrmanager/sock.h +++ b/vdr-vdrmanager/sock.h @@ -8,8 +8,13 @@ #include #include #include +#include #include +#define SSL_NO_RETRY 0 +#define SSL_RETRY_READ 1 +#define SSL_RETRY_WRITE 2 + using namespace std; class cVdrmanagerSocket @@ -30,47 +35,4 @@ public: const char * GetPassword(); }; -class cVdrmanagerClientSocket : public cVdrmanagerSocket -{ -private: - string readbuf; - string writebuf; - char * sendbuf; - size_t sendsize; - size_t sendoffset; - bool disconnected; - bool initDisconnect; - int client; - bool login; - bool compression; - bool initCompression; - int compressionMode; -public: - cVdrmanagerClientSocket(const char * password, int compressionMode); - virtual ~cVdrmanagerClientSocket(); - bool Attach(int fd); - bool IsLineComplete(); - bool GetLine(string& line); - bool PutLine(string line); - bool Read(); - bool Disconnected(); - void Disconnect(); - bool Flush(); - int GetClientId(); - bool WritePending(); - bool IsLoggedIn(); - void SetLoggedIn(); - void ActivateCompression(); - void Compress(); -}; - -class cVdrmanagerServerSocket : public cVdrmanagerSocket -{ -public: - cVdrmanagerServerSocket(); - virtual ~cVdrmanagerServerSocket(); - bool Create(int port, const char * password, bool forceCheckSvdrp, int compressionMode); - cVdrmanagerClientSocket * Accept(); -}; - #endif diff --git a/vdr-vdrmanager/vdrmanager.cpp b/vdr-vdrmanager/vdrmanager.cpp index 57393a3..4feb5f5 100644 --- a/vdr-vdrmanager/vdrmanager.cpp +++ b/vdr-vdrmanager/vdrmanager.cpp @@ -14,7 +14,10 @@ #include "vdrmanagerthread.h" #include "compressor.h" -#define VDRMANAGER_PORT 6420 +#define VDRMANAGER_PORT 6420 +#define VDRMANAGER_SSL_PORT 6421 +#define VDRMANAGER_CRT_FILE "/etc/vdr/plugins/vdrmanager/vdrmanager.pem" +#define VDRMANAGER_KEY_FILE "/etc/vdr/plugins/vdrmanager/vdrmanager.pem" static const char *VERSION = "0.11"; static const char *DESCRIPTION = "VDR-Manager support plugin"; @@ -24,9 +27,12 @@ private: // Add any member variables or functions you may need here. cVdrManagerThread * Thread; int port; + int sslport; const char * password; bool forceCheckSvdrp; int compressionMode; + const char * certFile; + const char * keyFile; protected: public: cVdrManager(void); @@ -56,9 +62,12 @@ cVdrManager::cVdrManager(void) { // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT! Thread = NULL; port = VDRMANAGER_PORT; + sslport = VDRMANAGER_SSL_PORT; password = ""; forceCheckSvdrp = false; compressionMode = COMPRESSION_NONE; + certFile = VDRMANAGER_CRT_FILE; + keyFile = VDRMANAGER_KEY_FILE; } cVdrManager::~cVdrManager() { @@ -74,18 +83,27 @@ cMenuSetupPage * cVdrManager::SetupMenu(void) { } const char * cVdrManager::CommandLineHelp(void) { - return " -p port port number to listen to\n" - " -P password password (none if not given). No password forces check against svdrphosts.conf.\n" - " -s force check against svdrphosts.conf, even if a password was given\n" - " -c compression selects the compression mode to use (zlib or gzip). Default is zlib"; + return + " -p port[,sslport] port number to listen to (sslport = port+1 if not given\n" + " -P password password (none if not given). No password forces check against svdrphosts.conf.\n" + " -s force check against svdrphosts.conf, even if a password was given\n" + " -c compression selects the compression mode to use (zlib or gzip). Default is zlib\n" + " -k certfile[,keyfile] cert and key file for SSL (or one file for both)"; } bool cVdrManager::ProcessArgs(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "c::p:P:s")) != -1) + while ((c = getopt(argc, argv, "c::p:P:st:k:")) != -1) switch (c) { case 'p': port = atoi(optarg); + { + const char * sep = strchr(optarg, ','); + if (sep) + sslport = atoi(sep+1); + else + sslport = port+1; + } break; case 'P': password = optarg; @@ -104,6 +122,17 @@ bool cVdrManager::ProcessArgs(int argc, char *argv[]) { return false; } break; + case 'k': + { + const char * sep = strchr(optarg, ','); + if (sep == NULL) { + certFile = keyFile = optarg; + } else { + certFile = strndup(optarg, sep-optarg); + keyFile = sep; + } + } + break; case '?': return false; default: @@ -113,6 +142,8 @@ bool cVdrManager::ProcessArgs(int argc, char *argv[]) { // default port if (port <= 0) port = VDRMANAGER_PORT; + if (sslport <= 0) + sslport = port+1; return true; } @@ -121,8 +152,8 @@ bool cVdrManager::Initialize(void) { // Initialize any background activities the plugin shall perform. // Start any background activities the plugin shall perform. - Thread = new cVdrManagerThread(port, password, forceCheckSvdrp, - compressionMode); + Thread = new cVdrManagerThread(port, sslport, password, forceCheckSvdrp, + compressionMode, certFile, keyFile); return Thread != NULL; } diff --git a/vdr-vdrmanager/vdrmanagerthread.cpp b/vdr-vdrmanager/vdrmanagerthread.cpp index 51301e5..55a3c90 100644 --- a/vdr-vdrmanager/vdrmanagerthread.cpp +++ b/vdr-vdrmanager/vdrmanagerthread.cpp @@ -8,13 +8,17 @@ #include "select.h" #include "helpers.h" -cVdrManagerThread::cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp, int compressionMode) +cVdrManagerThread::cVdrManagerThread(int port, int sslPort, const char * password, bool forceCheckSvdrp, int compressionMode, + const char * certFile, const char * keyFile) { select = NULL; - this -> port = port; - this -> password = password; - this -> forceCheckSvdrp = forceCheckSvdrp; - this -> compressionMode = compressionMode; + this->port = port; + this->sslPort = sslPort; + this->password = password; + this->forceCheckSvdrp = forceCheckSvdrp; + this->compressionMode = compressionMode; + this->certFile = certFile; + this->keyFile = keyFile; } cVdrManagerThread::~cVdrManagerThread() @@ -25,8 +29,10 @@ cVdrManagerThread::~cVdrManagerThread() void cVdrManagerThread::Action(void) { // create listener socket - if (!Init()) + if (!Init()) { + Cleanup(); return; + } // do processing select->Action(); @@ -44,19 +50,35 @@ bool cVdrManagerThread::Init() // create server socket cVdrmanagerServerSocket * sock = new cVdrmanagerServerSocket(); - if (sock == NULL || !sock->Create(port, password, forceCheckSvdrp, compressionMode)) + if (sock == NULL || !sock->Create(port, password, forceCheckSvdrp, compressionMode, NULL, NULL)) return false; - // register server socket - select->SetServerSocket(sock); + // register server sockets + select->SetServerSockets(sock, NULL); + + cVdrmanagerServerSocket * sslSock; + if (!access(certFile, R_OK) && !access(keyFile, R_OK)) { + sslSock = new cVdrmanagerServerSocket(); + if (sslSock == NULL || !sslSock->Create(sslPort, password, forceCheckSvdrp, compressionMode, certFile, keyFile)) { + return false; + } + } else { + sslSock = NULL; + isyslog("[vdrmanager] SSL key files %s and %s can't be read. SSL disabled.", certFile, keyFile); + } + + // register server sockets + select->SetServerSockets(sock, sslSock); return true; } void cVdrManagerThread::Cleanup() { - if (select) + if (select) { delete select; + select = NULL; + } } void cVdrManagerThread::Shutdown() diff --git a/vdr-vdrmanager/vdrmanagerthread.h b/vdr-vdrmanager/vdrmanagerthread.h index 0dd3646..57e129b 100644 --- a/vdr-vdrmanager/vdrmanagerthread.h +++ b/vdr-vdrmanager/vdrmanagerthread.h @@ -20,11 +20,15 @@ class cVdrManagerThread : public cThread { private: cSelect * select; int port; + int sslPort; const char * password; bool forceCheckSvdrp; int compressionMode; + const char * certFile; + const char * keyFile; public: - cVdrManagerThread(int port, const char * password, bool forceCheckSvdrp, int compressionMode); + cVdrManagerThread(int port, int sslPort, const char * password, bool forceCheckSvdrp, int compressionMode, + const char * certFile, const char * keyFile); virtual void Action(void); void Shutdown(); private: diff --git a/vdrmanager/res/values-de/strings.xml b/vdrmanager/res/values-de/strings.xml index 811cd02..e39997e 100644 --- a/vdrmanager/res/values-de/strings.xml +++ b/vdrmanager/res/values-de/strings.xml @@ -125,7 +125,7 @@ herrlado<herrlado@gmail.com> VDR Plugin Passwort Passwort für das VDR Plugin Sichere Verbindung - Verwende SSL für Verbindungen (aktuell nicht implementiert) + Verwende SSL für Verbindungen Kanaleinstellungen Begrenze Kanäle Nur ausgewählte Kanäle verwenden diff --git a/vdrmanager/res/values-it/strings.xml b/vdrmanager/res/values-it/strings.xml index 876c7ee..5f5425f 100644 --- a/vdrmanager/res/values-it/strings.xml +++ b/vdrmanager/res/values-it/strings.xml @@ -124,7 +124,7 @@ Password plugin VDR Password per il plugin di VDR Connessione sicura - Usa SSL per le connessioni (al momento non supportato) + Usa SSL per le connessioni Impostazioni canale Limita canali Usa solo determinati canali diff --git a/vdrmanager/res/values-uk/strings.xml b/vdrmanager/res/values-uk/strings.xml index 10e2fd8..b32c461 100644 --- a/vdrmanager/res/values-uk/strings.xml +++ b/vdrmanager/res/values-uk/strings.xml @@ -120,7 +120,7 @@ herrlado<herrlado@gmail.com> Пароль додатку VDR Пароль для додатка VDR Безпечне підключення - Використовувати SSL для підключень (в даний час не підтримується) + Використовувати SSL для підключень Налаштування каналу Обмеження на канали Вокористовувати тільки дані канали diff --git a/vdrmanager/res/values/strings.xml b/vdrmanager/res/values/strings.xml index 6169ccf..30f6108 100644 --- a/vdrmanager/res/values/strings.xml +++ b/vdrmanager/res/values/strings.xml @@ -144,7 +144,7 @@ VDR plugin password Password for the VDR plugin Secure connect - Use SSL for connections (currently not supported) + Use SSL for connections Channel settings diff --git a/vdrmanager/res/xml/vdr_prefs.xml b/vdrmanager/res/xml/vdr_prefs.xml index f53c19a..4cbd861 100644 --- a/vdrmanager/res/xml/vdr_prefs.xml +++ b/vdrmanager/res/xml/vdr_prefs.xml @@ -29,7 +29,7 @@ diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/gui/CertificateProblemDialog.java b/vdrmanager/src/de/bjusystems/vdrmanager/gui/CertificateProblemDialog.java index bf7034f..b0c58df 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/gui/CertificateProblemDialog.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/gui/CertificateProblemDialog.java @@ -32,7 +32,14 @@ public class CertificateProblemDialog implements CertificateProblemListener { final Semaphore semaphore = new Semaphore(0, true); // certificate properties - final String host = chain[0].getSubjectDN().getName().split(",")[0].replace("CN=", "").trim(); + final String[] values = chain[0].getSubjectDN().getName().split(","); + String host = "???"; + for(String value : values) { + if (value.contains("CN=")) { + host = value.replace("CN=", "").trim(); + break; + } + } final String creationDate = chain[0].getNotBefore().toLocaleString(); final String validUntil = chain[0].getNotAfter().toLocaleString(); diff --git a/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java b/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java index daf2bea..9171bcb 100644 --- a/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java +++ b/vdrmanager/src/de/bjusystems/vdrmanager/utils/svdrp/SvdrpClient.java @@ -301,6 +301,7 @@ public abstract class SvdrpClient { protected void disconnect() throws IOException { informListener(SvdrpEvent.DISCONNECTING); if (socket != null && socket.isConnected()) { + writeLine("quit"); socket.close(); socket = null; } -- cgit v1.2.3