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: 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 | ||||
| - 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 | ||||
|   | ||||
							
								
								
									
										24
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								README
									
									
									
									
									
								
							| @@ -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: | ||||
| ---------------------------- | ||||
|  | ||||
|   | ||||
| @@ -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) { } | ||||
| 	 | ||||
|   | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user