diff options
Diffstat (limited to 'tntconfig.cpp')
-rw-r--r-- | tntconfig.cpp | 389 |
1 files changed, 265 insertions, 124 deletions
diff --git a/tntconfig.cpp b/tntconfig.cpp index cdc476e..71bee4d 100644 --- a/tntconfig.cpp +++ b/tntconfig.cpp @@ -3,8 +3,12 @@ #include <fstream> #include <sstream> #include <stdexcept> +#include <cxxtools/loginit.h> +#include <tnt/sessionscope.h> +#include <tnt/httpreply.h> #include <vdr/config.h> #include <vdr/plugin.h> +#include <vdr/videodir.h> #include "i18n.h" #include "live.h" #include "setup.h" @@ -12,157 +16,294 @@ namespace vdrlive { -using namespace std; + using namespace std; -TntConfig::TntConfig() -{ - WriteConfig(); -} - -void TntConfig::WriteConfig() -{ - WriteProperties(); + TntConfig::TntConfig() + { +#if TNTVERSION < 1606 + WriteConfig(); +#endif + } - string const configDir(Plugin::GetConfigDirectory()); +#if TNTVERSION < 1606 + void TntConfig::WriteConfig() + { + WriteProperties(); - ostringstream builder; - builder << configDir << "/httpd.config"; - m_configPath = builder.str(); + string const configDir(Plugin::GetConfigDirectory()); - ofstream file( m_configPath.c_str(), ios::out | ios::trunc ); - if ( !file ) { ostringstream builder; - builder << "Can't open " << m_configPath << " for writing: " << strerror( errno ); - throw runtime_error( builder.str() ); - } + builder << configDir << "/httpd.config"; + m_configPath = builder.str(); + + ofstream file( m_configPath.c_str(), ios::out | ios::trunc ); + if ( !file ) { + ostringstream builder; + builder << "Can't open " << m_configPath << " for writing: " << strerror( errno ); + throw runtime_error( builder.str() ); + } + + // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ + // ------------------------------------------------------------------------ + // These MapUrl statements are very security sensitive! + // A wrong mapping to content@ may allow retrieval of arbitrary files + // from your VDR system via live. + // Two meassures are taken against this in our implementation: + // 1. The MapUrls need to be checked regulary against possible exploits + // One tool to do this can be found here: + // http://www.lumadis.be/regex/test_regex.php + // Newly inserted MapUrls should be marked with author and confirmed + // by a second party. (use source code comments for this) + // 2. content.ecpp checks the given path to be + // a. an absolute path starting at / + // b. not containing ../ paths components + // In order to do so, the MapUrl statements must create absolute + // path arguments to content@ + // ------------------------------------------------------------------------ + // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ + - // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ - // ------------------------------------------------------------------------ - // These MapUrl statements are very security sensitive! - // A wrong mapping to content@ may allow retrieval of arbitrary files - // from your VDR system via live. - // Two meassures are taken against this in our implementation: - // 1. The MapUrls need to be checked regulary against possible exploits - // One tool to do this can be found here: - // http://www.lumadis.be/regex/test_regex.php - // Newly inserted MapUrls should be marked with author and confirmed - // by a second party. (use source code comments for this) - // 2. content.ecpp checks the given path to be - // a. an absolute path starting at / - // b. not containing ../ paths components - // In order to do so, the MapUrl statements must create absolute - // path arguments to content@ - // ------------------------------------------------------------------------ - // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ - - - file << "MapUrl ^/$ login@" << endl; - - // the following redirects vdr_request URL to the component - // specified by the action parameter. - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/vdr_request/([^.]+) $1@" << endl; - - // the following selects the theme specific 'theme.css' file - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/themes/([^/]*)/css.*/(.+\\.css) content@ " << configDir << "/themes/$1/css/$2 text/css" << endl; - - // the following rules provide a search scheme for images. The first - // rule where a image is found, terminates the search. - // 1. /themes/<theme>/img/<imgname>.<ext> - // 2. /img/<imgname>.<ext> - // deprecated: 3. <imgname>.<ext> (builtin images) - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/themes/$1/img/$2.$3 image/$3" << endl; - file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/img/$2.$3 image/$3" << endl; - // deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl; - - // Epg images - string const epgImgPath(LiveSetup().GetEpgImageDir()); - if (!epgImgPath.empty()) { - // inserted by 'winni' -- EXPLOITABLE! (checked by tadi) - // file << "MapUrl ^/epgimages/(.*)\\.(.+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl; + file << "MapUrl ^/$ login@" << endl; + // the following redirects vdr_request URL to the component + // specified by the action parameter. // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/epgimages/([^/]*)\\.([^./]+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl; - } + file << "MapUrl ^/vdr_request/([^.]+) $1@" << endl; - // select additional (not build in) javascript. - // WARNING: no path components with '.' in the name are allowed. Only - // the basename may contain dots and must end with '.js' - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/js(/[^.]*)([^/]*\\.js) content@ " << configDir << "/js$1$2 text/javascript" << endl; + // the following selects the theme specific 'theme.css' file + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/themes/([^/]*)/css.*/(.+\\.css) content@ " << configDir << "/themes/$1/css/$2 text/css" << endl; - // map to 'css/basename(uri)' - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/css.*/(.+) content@ " << configDir << "/css/$1 text/css" << endl; + // the following rules provide a search scheme for images. The first + // rule where a image is found, terminates the search. + // 1. /themes/<theme>/img/<imgname>.<ext> + // 2. /img/<imgname>.<ext> + // deprecated: 3. <imgname>.<ext> (builtin images) + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/themes/$1/img/$2.$3 image/$3" << endl; + file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/img/$2.$3 image/$3" << endl; + // deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl; - // map to 'img/basename(uri)' - // inserted by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/img.*/(.+)\\.([^.]+) content@ " << configDir << "/img/$1.$2 image/$2" << endl; + // Epg images + string const epgImgPath(LiveSetup().GetEpgImageDir()); + if (!epgImgPath.empty()) { + // inserted by 'winni' -- EXPLOITABLE! (checked by tadi) + // file << "MapUrl ^/epgimages/(.*)\\.(.+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl; - // Map favicon.ico into img directory - file << "MapUrl ^/favicon.ico$ content@ " << configDir << "/img/favicon.ico image/x-icon" << endl; + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/epgimages/([^/]*)\\.([^./]+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl; + } - // insecure by default: DO NOT UNKOMMENT!!! - // file << "MapUrl /([^/]+/.+) content@ $1" << endl; + // select additional (not build in) javascript. + // WARNING: no path components with '.' in the name are allowed. Only + // the basename may contain dots and must end with '.js' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/js(/[^.]*)([^/]*\\.js) content@ " << configDir << "/js$1$2 text/javascript" << endl; - // takes first path components without 'extension' when it does not - // contain '.' - // modified by 'tadi' -- verified with above, but not counterchecked yet! - file << "MapUrl ^/([^./]+)(.*)? $1@" << endl; + // map to 'css/basename(uri)' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/css.*/(.+) content@ " << configDir << "/css/$1 text/css" << endl; - file << "PropertyFile " << m_propertiesPath << endl; - file << "SessionTimeout 86400" << endl; - file << "DefaultContentType \"text/html; charset=" << LiveI18n().CharacterEncoding() << "\"" << endl; + // map to 'img/basename(uri)' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/img.*/(.+)\\.([^.]+) content@ " << configDir << "/img/$1.$2 image/$2" << endl; - Setup::IpList const& ips = LiveSetup().GetServerIps(); - int port = LiveSetup().GetServerPort(); - for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) { - file << "Listen " << *ip << " " << port << endl; - } + // Map favicon.ico into img directory + file << "MapUrl ^/favicon.ico$ content@ " << configDir << "/img/favicon.ico image/x-icon" << endl; -#ifdef TNTVERS7 - int s_port = LiveSetup().GetServerSslPort(); - string s_cert = LiveSetup().GetServerSslCert(); + // insecure by default: DO NOT UNKOMMENT!!! + // file << "MapUrl /([^/]+/.+) content@ $1" << endl; - if (s_cert.empty()) { - s_cert = configDir + "/live.pem"; - } + // takes first path components without 'extension' when it does not + // contain '.' + // modified by 'tadi' -- verified with above, but not counterchecked yet! + file << "MapUrl ^/([^./]+)(.*)? $1@" << endl; - if ( ifstream( s_cert.c_str() ) ) { + file << "PropertyFile " << m_propertiesPath << endl; + file << "SessionTimeout 86400" << endl; + file << "DefaultContentType \"text/html; charset=" << LiveI18n().CharacterEncoding() << "\"" << endl; + + Setup::IpList const& ips = LiveSetup().GetServerIps(); + int port = LiveSetup().GetServerPort(); for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) { - file << "SslListen " << *ip << " " << s_port << " " << s_cert << endl; + file << "Listen " << *ip << " " << port << endl; } - } - else { - esyslog( "ERROR: %s: %s", s_cert.c_str(), strerror( errno ) ); + +// not used any more see below: #ifdef TNTVERS7 +// not used any more see below: int s_port = LiveSetup().GetServerSslPort(); +// not used any more see below: string s_cert = LiveSetup().GetServerSslCert(); +// not used any more see below: +// not used any more see below: if (s_cert.empty()) { +// not used any more see below: s_cert = configDir + "/live.pem"; +// not used any more see below: } +// not used any more see below: +// not used any more see below: if ( ifstream( s_cert.c_str() ) ) { +// not used any more see below: for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) { +// not used any more see below: file << "SslListen " << *ip << " " << s_port << " " << s_cert << endl; +// not used any more see below: } +// not used any more see below: } +// not used any more see below: else { +// not used any more see below: esyslog( "ERROR: %s: %s", s_cert.c_str(), strerror( errno ) ); +// not used any more see below: } +// not used any more see below: #endif } #endif -} - -void TntConfig::WriteProperties() -{ - ostringstream builder; - builder << Plugin::GetConfigDirectory() << "/httpd.properties"; - m_propertiesPath = builder.str(); - ofstream file( m_propertiesPath.c_str(), ios::out | ios::trunc ); - if ( !file ) { +#if TNTVERSION < 1606 + void TntConfig::WriteProperties() + { ostringstream builder; - builder << "Can't open " << m_propertiesPath << " for writing: " << strerror( errno ); - throw runtime_error( builder.str() ); + builder << Plugin::GetConfigDirectory() << "/httpd.properties"; + m_propertiesPath = builder.str(); + + ofstream file( m_propertiesPath.c_str(), ios::out | ios::trunc ); + if ( !file ) { + ostringstream builder; + builder << "Can't open " << m_propertiesPath << " for writing: " << strerror( errno ); + throw runtime_error( builder.str() ); + } + + // XXX modularize + file << "rootLogger=" << LiveSetup().GetTntnetLogLevel() << endl; + file << "logger.tntnet=" << LiveSetup().GetTntnetLogLevel() << endl; } +#endif + +#if TNTVERSION >= 1606 + void TntConfig::Configure(tnt::Tntnet& app) const + { + string const configDir(Plugin::GetConfigDirectory()); - // XXX modularize - file << "rootLogger=" << LiveSetup().GetTntnetLogLevel() << endl; - file << "logger.tntnet=" << LiveSetup().GetTntnetLogLevel() << endl; -} + // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ + // ------------------------------------------------------------------------ + // These mapUrl statements are very security sensitive! + // A wrong mapping to content may allow retrieval of arbitrary files + // from your VDR system via live. + // Two meassures are taken against this in our implementation: + // 1. The MapUrls need to be checked regulary against possible exploits + // One tool to do this can be found here: + // http://www.lumadis.be/regex/test_regex.php + // Newly inserted MapUrls should be marked with author and confirmed + // by a second party. (use source code comments for this) + // 2. content.ecpp checks the given path to be + // a. an absolute path starting at / + // b. not containing ../ paths components + // In order to do so, the MapUrl statements must create absolute + // path arguments to content@ + // ------------------------------------------------------------------------ + // +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ + + app.mapUrl("^/$", "login"); + + // the following redirects vdr_request URL to the component + // specified by the action parameter. + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/vdr_request/([^.]+)", "$1"); -TntConfig const& TntConfig::Get() -{ - static TntConfig instance; - return instance; -} + // the following redirects play_video URL to the content component. + // inserted by 'tadi' -- not verified, not counterchecked yet! + //app.mapUrl("^/vlc/(.+)", "static@tntnet") + // .setPathInfo("/$1") + // .pushArg(string("DocumentRoot=") + VideoDirectory); + // the following selects the theme specific 'theme.css' file + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/themes/([^/]*)/css.*/(.+\\.css)", "content") + .setPathInfo(configDir + "/themes/$1/css/$2") + .pushArg("text/css"); + + // the following rules provide a search scheme for images. The first + // rule where a image is found, terminates the search. + // 1. /themes/<theme>/img/<imgname>.<ext> + // 2. /img/<imgname>.<ext> + // deprecated: 3. <imgname>.<ext> (builtin images) + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/themes/([^/]*)/img.*/(.+)\\.(.+)", "content") + .setPathInfo(configDir + "/themes/$1/img/$2.$3") + .pushArg("image/$3"); + app.mapUrl("^/themes/([^/]*)/img.*/(.+)\\.(.+)", "content") + .setPathInfo(configDir + "/img/$2.$3") + .pushArg("image/$3"); + // deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl; + + // Epg images + string const epgImgPath(LiveSetup().GetEpgImageDir()); + if (!epgImgPath.empty()) { + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/epgimages/([^/]*)\\.([^./]+)", "content") + .setPathInfo(epgImgPath + "/$1.$2") + .pushArg("image/$2"); + } + + // select additional (not build in) javascript. + // WARNING: no path components with '.' in the name are allowed. Only + // the basename may contain dots and must end with '.js' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/js(/[^.]*)([^/]*\\.js)", "content") + .setPathInfo(configDir + "/js$1$2") + .pushArg("text/javascript"); + + // map to 'css/basename(uri)' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/css.*/(.+)", "content") + .setPathInfo(configDir + "/css/$1") + .pushArg("text/css"); + + // map to 'img/basename(uri)' + // inserted by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/img.*/(.+)\\.([^.]+)", "content") + .setPathInfo(configDir + "/img/$1.$2") + .pushArg("image/$2"); + + // Map favicon.ico into img directory + app.mapUrl("^/favicon.ico$", "content") + .setPathInfo(configDir + "/img/favicon.ico") + .pushArg("image/x-icon"); + + // takes first path components without 'extension' when it does not + // contain '.' + // modified by 'tadi' -- verified with above, but not counterchecked yet! + app.mapUrl("^/([^./]+)(.*)?", "$1"); + + tnt::Sessionscope::setDefaultTimeout(86400); + tnt::HttpReply::setDefaultContentType(string("text/html; charset=") + LiveI18n().CharacterEncoding()); + + Setup::IpList const& ips = LiveSetup().GetServerIps(); + int port = LiveSetup().GetServerPort(); + for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) { + app.listen(*ip, port); + } + +#if TNTSSLSUPPORT + int s_port = LiveSetup().GetServerSslPort(); + string s_cert = LiveSetup().GetServerSslCert(); + + if (s_cert.empty()) { + s_cert = configDir + "/live.pem"; + } + + if ( ifstream( s_cert.c_str() ) ) { + for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) { + app.sslListen(s_cert, s_cert, *ip, s_port); + } + } + else { + esyslog( "ERROR: %s: %s", s_cert.c_str(), strerror( errno ) ); + } +#endif // TNTSSLSUPPORT + + std::istringstream logConf( + "rootLogger=" + LiveSetup().GetTntnetLogLevel() + "\n" + // "logger.tntnet.static=DEBUG\n" + // "logger.cxxtools.net.tcp=DEBUG\n" + ); + log_init(logConf); + } +#endif + + TntConfig const& TntConfig::Get() + { + static TntConfig instance; + return instance; + } } // namespace vdrlive |