diff options
-rw-r--r-- | HISTORY | 1 | ||||
-rw-r--r-- | README | 24 | ||||
-rw-r--r-- | server/connection.h | 5 | ||||
-rw-r--r-- | server/connectionHTTP.c | 27 | ||||
-rw-r--r-- | server/connectionHTTP.h | 5 | ||||
-rw-r--r-- | server/server.c | 5 | ||||
-rw-r--r-- | server/server.h | 3 | ||||
-rw-r--r-- | streamdev-server.c | 23 |
8 files changed, 80 insertions, 13 deletions
@@ -1,6 +1,7 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- added HTTP authentication - compatibility for VDR 1.7.1 (thanks to Udo Richter) - added vdr-1.6.0-intcamdevices.patch (thanks to Anssi Hannula) - fixed problem when switching from one encrypted channel to an other @@ -118,16 +118,20 @@ make [options, if necessary] plugins ---------------------------------- Starting with streamdev 0.4.0, all additional files are kept in a directory -called "streamdev" inside VDR's plugin config directory. This affects in -particular the file "streamdevhosts.conf". You will have to move it to its -new location: +called "streamdev" inside VDR's plugin config directory. It is the new default +location of externremux.sh and the new place where streamdev-server expects the +file "streamdevhosts.conf". You will have to move this file to its new location: mv VDRCONFDIR/plugins/streamdevhosts.conf VDRCONFDIR/plugins/streamdev/ (Directory VDRCONFDIR/plugins/streamdev already exists, as you copied the whole folder from the sources directory as suggested above, right?) -The new default location for externremux.sh is also in this directory. +Now check the contents of streamdevhosts.conf. Does it contain a "0.0.0.0/0" +entry? If your VDR machine is connected to the Internet, this line gives +*anyone* full access to streamdev, unless you took some other measures to +prevent this (e.g. firewall). You might want to remove this line and enable +HTTP authentication instead. 3. Usage: @@ -205,6 +209,18 @@ externremux script. http://hostname:3000/EXTERN;some_parameter/3 +If you want to access streamdev's HTTP server from the Internet, do *not* grant +access for anyone by allowing any IP in "streamdevhosts.conf". Instead, pass the +"-a" commandline option to streamdev-server. It takes a username and a password +as argument. Clients with an IP not accepted by "streamdevhosts.conf" will then +have to login. The VDR commandline will have to look like this: + +vdr ... -P 'streamdev-server -a vdr:secret' ... + +Note the single quotes, as otherwise "-a" will be passed to VDR and not to +streamdev-server. The login ("vdr" in the example above) doesn't have to exist +as a system account. + 3.2 Usage VDR-to-VDR server: ---------------------------- diff --git a/server/connection.h b/server/connection.h index fe828d9..69c24fe 100644 --- a/server/connection.h +++ b/server/connection.h @@ -1,5 +1,5 @@ /* - * $Id: connection.h,v 1.5 2007/04/16 11:01:02 schmirl Exp $ + * $Id: connection.h,v 1.6 2008/10/14 11:05:47 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_CONNECTION_H @@ -47,6 +47,9 @@ public: cServerConnection(const char *Protocol); virtual ~cServerConnection(); + /* If true, any client IP will be accepted */ + virtual bool CanAuthenticate(void) { return false; } + /* Gets called if the client has been accepted by the core */ virtual void Welcome(void) { } diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index 38a82a3..2e867cf 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -1,11 +1,12 @@ /* - * $Id: connectionHTTP.c,v 1.13 2008/03/28 15:11:40 schmirl Exp $ + * $Id: connectionHTTP.c,v 1.14 2008/10/14 11:05:47 schmirl Exp $ */ #include <ctype.h> #include "server/connectionHTTP.h" #include "server/menuHTTP.h" +#include "server/server.h" #include "server/setup.h" cConnectionHTTP::cConnectionHTTP(void): @@ -26,6 +27,11 @@ cConnectionHTTP::~cConnectionHTTP() delete m_LiveStreamer; } +bool cConnectionHTTP::CanAuthenticate(void) +{ + return opt_auth != NULL; +} + bool cConnectionHTTP::Command(char *Cmd) { Dprintf("command %s\n", Cmd); @@ -44,6 +50,15 @@ bool cConnectionHTTP::Command(char *Cmd) if (strncasecmp(Cmd, "Host:", 5) == 0) { Dprintf("Host-Header\n"); m_Host = (std::string) skipspace(Cmd + 5); + return true; + } + else if (strncasecmp(Cmd, "Authorization:", 14) == 0) { + Cmd = skipspace(Cmd + 14); + if (strncasecmp(Cmd, "Basic", 5) == 0) { + Dprintf("'Authorization Basic'-Header\n"); + m_Authorization = (std::string) skipspace(Cmd + 5); + return true; + } } Dprintf("header\n"); return true; @@ -56,6 +71,16 @@ bool cConnectionHTTP::Command(char *Cmd) bool cConnectionHTTP::ProcessRequest(void) { Dprintf("process\n"); + if (!StreamdevHosts.Acceptable(RemoteIpAddr())) + { + if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) { + isyslog("streamdev-server: HTTP authorization required"); + DeferClose(); + return Respond("HTTP/1.0 401 Authorization Required") + && Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")") + && Respond(""); + } + } if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) { switch (m_Job) { case hjListing: diff --git a/server/connectionHTTP.h b/server/connectionHTTP.h index a3558ad..0548959 100644 --- a/server/connectionHTTP.h +++ b/server/connectionHTTP.h @@ -1,5 +1,5 @@ /* - * $Id: connectionHTTP.h,v 1.5 2008/03/28 15:11:40 schmirl Exp $ + * $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H @@ -30,6 +30,7 @@ private: std::string m_Request; std::string m_Host; + std::string m_Authorization; //std::map<std::string,std::string> m_Headers; TODO: later? eHTTPStatus m_Status; eHTTPJob m_Job; @@ -52,6 +53,8 @@ public: virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); } virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); } + virtual bool CanAuthenticate(void); + virtual bool Command(char *Cmd); bool CmdGET(const std::string &Opts); diff --git a/server/server.c b/server/server.c index 481e041..9399e61 100644 --- a/server/server.c +++ b/server/server.c @@ -1,5 +1,5 @@ /* - * $Id: server.c,v 1.6 2008/04/29 07:00:54 schmirl Exp $ + * $Id: server.c,v 1.7 2008/10/14 11:05:48 schmirl Exp $ */ #include "server/server.h" @@ -13,6 +13,7 @@ #include <errno.h> cSVDRPhosts StreamdevHosts; +char *opt_auth = NULL; char *opt_remux = NULL; cStreamdevServer *cStreamdevServer::m_Instance = NULL; @@ -122,7 +123,7 @@ void cStreamdevServer::Action(void) esyslog("streamdev: too many clients, rejecting %s:%d", client->RemoteIp().c_str(), client->RemotePort()); client->Reject(); - } else if (!StreamdevHosts.Acceptable(client->RemoteIpAddr())) { + } else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) { esyslog("streamdev: client %s:%d not allowed to connect", client->RemoteIp().c_str(), client->RemotePort()); client->Reject(); diff --git a/server/server.h b/server/server.h index c32fe09..339a05d 100644 --- a/server/server.h +++ b/server/server.h @@ -1,5 +1,5 @@ /* - * $Id: server.h,v 1.4 2008/04/29 07:00:54 schmirl Exp $ + * $Id: server.h,v 1.5 2008/10/14 11:05:48 schmirl Exp $ */ #ifndef VDR_STREAMDEV_SERVER_H @@ -13,6 +13,7 @@ #define DEFAULT_EXTERNREMUX (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "externremux.sh")) #define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "streamdevhosts.conf")) +extern char *opt_auth; extern char *opt_remux; class cStreamdevServer: public cThread { diff --git a/streamdev-server.c b/streamdev-server.c index 9892cb2..6b4ff6f 100644 --- a/streamdev-server.c +++ b/streamdev-server.c @@ -3,10 +3,11 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: streamdev-server.c,v 1.10 2008/10/13 11:30:05 schmirl Exp $ + * $Id: streamdev-server.c,v 1.11 2008/10/14 11:05:47 schmirl Exp $ */ #include <getopt.h> +#include <vdr/tools.h> #include "remux/extern.h" #include "streamdev-server.h" #include "server/setup.h" @@ -25,6 +26,7 @@ cPluginStreamdevServer::cPluginStreamdevServer(void) cPluginStreamdevServer::~cPluginStreamdevServer() { + free(opt_auth); free(opt_remux); } @@ -36,20 +38,35 @@ const char *cPluginStreamdevServer::Description(void) const char *cPluginStreamdevServer::CommandLineHelp(void) { // return a string that describes all known command line options. - return " -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n"; + return + " -a <LOGIN:PASSWORD>, --auth=<LOGIN:PASSWORD> Credentials for HTTP authentication.\n" + " -r <CMD>, --remux=<CMD> Define an external command for remuxing.\n" + ; } bool cPluginStreamdevServer::ProcessArgs(int argc, char *argv[]) { // implement command line argument processing here if applicable. static const struct option long_options[] = { + { "auth", required_argument, NULL, 'a' }, { "remux", required_argument, NULL, 'r' }, { NULL, 0, NULL, 0 } }; int c; - while((c = getopt_long(argc, argv, "r:", long_options, NULL)) != -1) { + while((c = getopt_long(argc, argv, "a:r:", long_options, NULL)) != -1) { switch (c) { + case 'a': + { + if (opt_auth) + free(opt_auth); + int l = strlen(optarg); + cBase64Encoder Base64((uchar*) optarg, l, l * 4 / 3 + 3); + const char *s = Base64.NextLine(); + if (s) + opt_auth = strdup(s); + } + break; case 'r': if (opt_remux) free(opt_remux); |