mirror of
				https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
				synced 2023-10-10 17:16:51 +00:00 
			
		
		
		
	- 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:
		
							
								
								
									
										1
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								HISTORY
									
									
									
									
									
								
							@@ -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
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README
									
									
									
									
									
								
							@@ -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:
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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) { }
 | 
			
		||||
	
 | 
			
		||||
 
 | 
			
		||||
@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user