#include #include #include #include #include #include #include #include "i18n.h" #include "live.h" #include "setup.h" #include "tntconfig.h" namespace vdrlive { using namespace std; TntConfig::TntConfig() { WriteConfig(); } void TntConfig::WriteConfig() { WriteProperties(); string const configDir(Plugin::GetConfigDirectory()); ostringstream builder; 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 +++ 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//img/. // 2. /img/. // deprecated: 3. . (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; // inserted by 'tadi' -- verified with above, but not counterchecked yet! file << "MapUrl ^/epgimages/([^/]*)\\.([^./]+) content@ " << epgImgPath << "/$1.$2 image/$2" << 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; // 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; // 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; // Map favicon.ico into img directory file << "MapUrl ^/favicon.ico$ content@ " << configDir << "/img/favicon.ico image/x-icon" << endl; // insecure by default: DO NOT UNKOMMENT!!! // file << "MapUrl /([^/]+/.+) content@ $1" << 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; 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 << "Listen " << *ip << " " << port << endl; } } 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 ) { 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; } TntConfig const& TntConfig::Get() { static TntConfig instance; return instance; } } // namespace vdrlive