- added HTTP authentication (#475)

Modified Files:
 Tag: v0_4
	HISTORY README streamdev-server.c server/connection.h
	server/connectionHTTP.c server/connectionHTTP.h
	server/server.c server/server.h
This commit is contained in:
schmirl 2008-10-14 11:05:57 +00:00
parent 9258019e0f
commit 52b4bfcd8c
8 changed files with 80 additions and 14 deletions

View File

@ -1,6 +1,7 @@
VDR Plugin 'streamdev' Revision History
---------------------------------------
- added HTTP authentication
- added preprocessor directive for ancient gcc
- added Russian translation (thanks to Oleg Roitburd)
- fixed assignment of externremux.sh's default location (reported by plautze)

25
README
View File

@ -117,17 +117,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:
---------
@ -204,6 +207,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:
----------------------------

View File

@ -1,5 +1,5 @@
/*
* $Id: connection.h,v 1.5 2007/04/16 11:01:02 schmirl Exp $
* $Id: connection.h,v 1.5.2.1 2008/10/14 11:05:59 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) { }

View File

@ -1,11 +1,12 @@
/*
* $Id: connectionHTTP.c,v 1.13 2008/03/28 15:11:40 schmirl Exp $
* $Id: connectionHTTP.c,v 1.13.2.1 2008/10/14 11:05:59 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:

View File

@ -1,5 +1,5 @@
/*
* $Id: connectionHTTP.h,v 1.5 2008/03/28 15:11:40 schmirl Exp $
* $Id: connectionHTTP.h,v 1.5.2.1 2008/10/14 11:05:59 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);

View File

@ -1,5 +1,5 @@
/*
* $Id: server.c,v 1.5.2.1 2008/04/29 07:01:00 schmirl Exp $
* $Id: server.c,v 1.5.2.2 2008/10/14 11:05:59 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();

View File

@ -1,5 +1,5 @@
/*
* $Id: server.h,v 1.3.2.1 2008/04/29 07:01:00 schmirl Exp $
* $Id: server.h,v 1.3.2.2 2008/10/14 11:05:59 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 {

View File

@ -3,10 +3,11 @@
*
* See the README file for copyright information and how to reach the author.
*
* $Id: streamdev-server.c,v 1.7.2.1 2008/04/29 07:00:57 schmirl Exp $
* $Id: streamdev-server.c,v 1.7.2.2 2008/10/14 11:05:57 schmirl Exp $
*/
#include <getopt.h>
#include <vdr/tools.h>
#include "streamdev-server.h"
#include "server/setup.h"
#include "server/server.h"
@ -26,6 +27,7 @@ cPluginStreamdevServer::cPluginStreamdevServer(void)
cPluginStreamdevServer::~cPluginStreamdevServer()
{
free(opt_auth);
free(opt_remux);
}
@ -37,20 +39,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);