13
17
namespace vdrlive {
17
TntConfig::TntConfig()
22
void TntConfig::WriteConfig()
26
string const configDir(Plugin::GetConfigDirectory());
28
ostringstream builder;
29
builder << configDir << "/httpd.config";
30
m_configPath = builder.str();
32
ofstream file( m_configPath.c_str(), ios::out | ios::trunc );
21
TntConfig::TntConfig()
23
#if ! TNT_CONFIG_INTERNAL
28
#if ! TNT_CONFIG_INTERNAL
29
void TntConfig::WriteConfig()
33
string const configDir(Plugin::GetConfigDirectory());
34
35
ostringstream builder;
35
builder << "Can't open " << m_configPath << " for writing: " << strerror( errno );
36
throw runtime_error( builder.str() );
39
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
40
// ------------------------------------------------------------------------
41
// These MapUrl statements are very security sensitive!
42
// A wrong mapping to content@ may allow retrieval of arbitrary files
43
// from your VDR system via live.
44
// Two meassures are taken against this in our implementation:
45
// 1. The MapUrls need to be checked regulary against possible exploits
46
// One tool to do this can be found here:
47
// http://www.lumadis.be/regex/test_regex.php
48
// Newly inserted MapUrls should be marked with author and confirmed
49
// by a second party. (use source code comments for this)
50
// 2. content.ecpp checks the given path to be
51
// a. an absolute path starting at /
52
// b. not containing ../ paths components
53
// In order to do so, the MapUrl statements must create absolute
54
// path arguments to content@
55
// ------------------------------------------------------------------------
56
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
59
file << "MapUrl ^/$ login@" << endl;
61
// the following redirects vdr_request URL to the component
62
// specified by the action parameter.
63
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
64
file << "MapUrl ^/vdr_request/([^.]+) $1@" << endl;
66
// the following selects the theme specific 'theme.css' file
67
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
68
file << "MapUrl ^/themes/([^/]*)/css.*/(.+\\.css) content@ " << configDir << "/themes/$1/css/$2 text/css" << endl;
70
// the following rules provide a search scheme for images. The first
71
// rule where a image is found, terminates the search.
72
// 1. /themes/<theme>/img/<imgname>.<ext>
73
// 2. /img/<imgname>.<ext>
74
// deprecated: 3. <imgname>.<ext> (builtin images)
75
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
76
file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/themes/$1/img/$2.$3 image/$3" << endl;
77
file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/img/$2.$3 image/$3" << endl;
78
// deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl;
81
string const epgImgPath(LiveSetup().GetEpgImageDir());
82
if (!epgImgPath.empty()) {
83
// inserted by 'winni' -- EXPLOITABLE! (checked by tadi)
84
// file << "MapUrl ^/epgimages/(.*)\\.(.+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl;
86
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
87
file << "MapUrl ^/epgimages/([^/]*)\\.([^./]+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl;
90
// select additional (not build in) javascript.
91
// WARNING: no path components with '.' in the name are allowed. Only
92
// the basename may contain dots and must end with '.js'
93
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
94
file << "MapUrl ^/js(/[^.]*)([^/]*\\.js) content@ " << configDir << "/js$1$2 text/javascript" << endl;
96
// map to 'css/basename(uri)'
97
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
98
file << "MapUrl ^/css.*/(.+) content@ " << configDir << "/css/$1 text/css" << endl;
100
// map to 'img/basename(uri)'
101
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
102
file << "MapUrl ^/img.*/(.+)\\.([^.]+) content@ " << configDir << "/img/$1.$2 image/$2" << endl;
104
// Map favicon.ico into img directory
105
file << "MapUrl ^/favicon.ico$ content@ " << configDir << "/img/favicon.ico image/x-icon" << endl;
107
// insecure by default: DO NOT UNKOMMENT!!!
108
// file << "MapUrl /([^/]+/.+) content@ $1" << endl;
110
// takes first path components without 'extension' when it does not
112
// modified by 'tadi' -- verified with above, but not counterchecked yet!
113
file << "MapUrl ^/([^./]+)(.*)? $1@" << endl;
115
file << "PropertyFile " << m_propertiesPath << endl;
116
file << "SessionTimeout 86400" << endl;
117
file << "DefaultContentType \"text/html; charset=" << LiveI18n().CharacterEncoding() << "\"" << endl;
119
Setup::IpList const& ips = LiveSetup().GetServerIps();
120
int port = LiveSetup().GetServerPort();
121
for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) {
122
file << "Listen " << *ip << " " << port << endl;
126
int s_port = LiveSetup().GetServerSslPort();
127
string s_cert = LiveSetup().GetServerSslCert();
129
if (s_cert.empty()) {
130
s_cert = configDir + "/live.pem";
133
if ( ifstream( s_cert.c_str() ) ) {
36
builder << configDir << "/httpd.config";
37
m_configPath = builder.str();
39
ofstream file( m_configPath.c_str(), ios::out | ios::trunc );
41
ostringstream builder;
42
builder << "Can't open " << m_configPath << " for writing: " << strerror( errno );
43
throw runtime_error( builder.str() );
46
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
47
// ------------------------------------------------------------------------
48
// These MapUrl statements are very security sensitive!
49
// A wrong mapping to content@ may allow retrieval of arbitrary files
50
// from your VDR system via live.
51
// Two meassures are taken against this in our implementation:
52
// 1. The MapUrls need to be checked regulary against possible exploits
53
// One tool to do this can be found here:
54
// http://www.lumadis.be/regex/test_regex.php
55
// Newly inserted MapUrls should be marked with author and confirmed
56
// by a second party. (use source code comments for this)
57
// 2. content.ecpp checks the given path to be
58
// a. an absolute path starting at /
59
// b. not containing ../ paths components
60
// In order to do so, the MapUrl statements must create absolute
61
// path arguments to content@
62
// ------------------------------------------------------------------------
63
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
66
file << "MapUrl ^/$ login@" << endl;
68
// the following redirects vdr_request URL to the component
69
// specified by the action parameter.
70
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
71
file << "MapUrl ^/vdr_request/([^.]+) $1@" << endl;
73
// the following selects the theme specific 'theme.css' file
74
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
75
file << "MapUrl ^/themes/([^/]*)/css.*/(.+\\.css) content@ " << configDir << "/themes/$1/css/$2 text/css" << endl;
77
// the following rules provide a search scheme for images. The first
78
// rule where a image is found, terminates the search.
79
// 1. /themes/<theme>/img/<imgname>.<ext>
80
// 2. /img/<imgname>.<ext>
81
// deprecated: 3. <imgname>.<ext> (builtin images)
82
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
83
file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/themes/$1/img/$2.$3 image/$3" << endl;
84
file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) content@ " << configDir << "/img/$2.$3 image/$3" << endl;
85
// deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl;
88
string const epgImgPath(LiveSetup().GetEpgImageDir());
89
if (!epgImgPath.empty()) {
90
// inserted by 'winni' -- EXPLOITABLE! (checked by tadi)
91
// file << "MapUrl ^/epgimages/(.*)\\.(.+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl;
93
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
94
file << "MapUrl ^/epgimages/([^/]*)\\.([^./]+) content@ " << epgImgPath << "/$1.$2 image/$2" << endl;
97
// select additional (not build in) javascript.
98
// WARNING: no path components with '.' in the name are allowed. Only
99
// the basename may contain dots and must end with '.js'
100
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
101
file << "MapUrl ^/js(/[^.]*)([^/]*\\.js) content@ " << configDir << "/js$1$2 text/javascript" << endl;
103
// map to 'css/basename(uri)'
104
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
105
file << "MapUrl ^/css.*/(.+) content@ " << configDir << "/css/$1 text/css" << endl;
107
// map to 'img/basename(uri)'
108
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
109
file << "MapUrl ^/img.*/(.+)\\.([^.]+) content@ " << configDir << "/img/$1.$2 image/$2" << endl;
111
// Map favicon.ico into img directory
112
file << "MapUrl ^/favicon.ico$ content@ " << configDir << "/img/favicon.ico image/x-icon" << endl;
114
// insecure by default: DO NOT UNKOMMENT!!!
115
// file << "MapUrl /([^/]+/.+) content@ $1" << endl;
117
// takes first path components without 'extension' when it does not
119
// modified by 'tadi' -- verified with above, but not counterchecked yet!
120
file << "MapUrl ^/([^./]+)(.*)? $1@" << endl;
122
file << "PropertyFile " << m_propertiesPath << endl;
123
file << "SessionTimeout 86400" << endl;
124
file << "DefaultContentType \"text/html; charset=" << LiveI18n().CharacterEncoding() << "\"" << endl;
126
Setup::IpList const& ips = LiveSetup().GetServerIps();
127
int port = LiveSetup().GetServerPort();
134
128
for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) {
135
file << "SslListen " << *ip << " " << s_port << " " << s_cert << endl;
129
file << "Listen " << *ip << " " << port << endl;
139
esyslog( "ERROR: %s: %s", s_cert.c_str(), strerror( errno ) );
144
void TntConfig::WriteProperties()
146
ostringstream builder;
147
builder << Plugin::GetConfigDirectory() << "/httpd.properties";
148
m_propertiesPath = builder.str();
150
ofstream file( m_propertiesPath.c_str(), ios::out | ios::trunc );
134
#if ! TNT_CONFIG_INTERNAL
135
void TntConfig::WriteProperties()
152
137
ostringstream builder;
153
builder << "Can't open " << m_propertiesPath << " for writing: " << strerror( errno );
154
throw runtime_error( builder.str() );
158
file << "rootLogger=" << LiveSetup().GetTntnetLogLevel() << endl;
159
file << "logger.tntnet=" << LiveSetup().GetTntnetLogLevel() << endl;
162
TntConfig const& TntConfig::Get()
164
static TntConfig instance;
138
builder << Plugin::GetConfigDirectory() << "/httpd.properties";
139
m_propertiesPath = builder.str();
141
ofstream file( m_propertiesPath.c_str(), ios::out | ios::trunc );
143
ostringstream builder;
144
builder << "Can't open " << m_propertiesPath << " for writing: " << strerror( errno );
145
throw runtime_error( builder.str() );
149
file << "rootLogger=" << LiveSetup().GetTntnetLogLevel() << endl;
150
file << "logger.tntnet=" << LiveSetup().GetTntnetLogLevel() << endl;
151
file << "logger.cxxtools=" << LiveSetup().GetTntnetLogLevel() << endl;
155
#if TNT_CONFIG_INTERNAL
156
void TntConfig::Configure(tnt::Tntnet& app) const
158
string const configDir(Plugin::GetConfigDirectory());
160
std::istringstream logConf(
161
"rootLogger=" + LiveSetup().GetTntnetLogLevel() + "\n"
162
"logger.tntnet=" + LiveSetup().GetTntnetLogLevel() + "\n"
163
"logger.cxxtools=" + LiveSetup().GetTntnetLogLevel() + "\n"
167
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
168
// ------------------------------------------------------------------------
169
// These mapUrl statements are very security sensitive!
170
// A wrong mapping to content may allow retrieval of arbitrary files
171
// from your VDR system via live.
172
// Two meassures are taken against this in our implementation:
173
// 1. The MapUrls need to be checked regulary against possible exploits
174
// One tool to do this can be found here:
175
// http://www.lumadis.be/regex/test_regex.php
176
// Newly inserted MapUrls should be marked with author and confirmed
177
// by a second party. (use source code comments for this)
178
// 2. content.ecpp checks the given path to be
179
// a. an absolute path starting at /
180
// b. not containing ../ paths components
181
// In order to do so, the MapUrl statements must create absolute
182
// path arguments to content@
183
// ------------------------------------------------------------------------
184
// +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++ CAUTION +++
186
app.mapUrl("^/$", "login");
188
// the following redirects vdr_request URL to the component
189
// specified by the action parameter.
190
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
191
app.mapUrl("^/vdr_request/([^.]+)", "$1");
193
// the following redirects play_video URL to the content component.
194
// inserted by 'tadi' -- not verified, not counterchecked yet!
195
//app.mapUrl("^/vlc/(.+)", "static@tntnet")
196
// .setPathInfo("/$1")
197
// .pushArg(string("DocumentRoot=") + VideoDirectory);
199
// the following selects the theme specific 'theme.css' file
200
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
201
app.mapUrl("^/themes/([^/]*)/css.*/(.+\\.css)", "content")
202
.setPathInfo(configDir + "/themes/$1/css/$2")
203
.pushArg("text/css");
205
// the following rules provide a search scheme for images. The first
206
// rule where a image is found, terminates the search.
207
// 1. /themes/<theme>/img/<imgname>.<ext>
208
// 2. /img/<imgname>.<ext>
209
// deprecated: 3. <imgname>.<ext> (builtin images)
210
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
211
app.mapUrl("^/themes/([^/]*)/img.*/(.+)\\.(.+)", "content")
212
.setPathInfo(configDir + "/themes/$1/img/$2.$3")
213
.pushArg("image/$3");
214
app.mapUrl("^/themes/([^/]*)/img.*/(.+)\\.(.+)", "content")
215
.setPathInfo(configDir + "/img/$2.$3")
216
.pushArg("image/$3");
217
// deprecated: file << "MapUrl ^/themes/([^/]*)/img.*/(.+)\\.(.+) $2@" << endl;
220
string const epgImgPath(LiveSetup().GetEpgImageDir());
221
if (!epgImgPath.empty()) {
222
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
223
app.mapUrl("^/epgimages/([^/]*)\\.([^./]+)", "content")
224
.setPathInfo(epgImgPath + "/$1.$2")
225
.pushArg("image/$2");
228
// select additional (not build in) javascript.
229
// WARNING: no path components with '.' in the name are allowed. Only
230
// the basename may contain dots and must end with '.js'
231
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
232
app.mapUrl("^/js(/[^.]*)([^/]*\\.js)", "content")
233
.setPathInfo(configDir + "/js$1$2")
234
.pushArg("text/javascript");
236
// map to 'css/basename(uri)'
237
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
238
app.mapUrl("^/css.*/(.+)", "content")
239
.setPathInfo(configDir + "/css/$1")
240
.pushArg("text/css");
242
// map to 'img/basename(uri)'
243
// inserted by 'tadi' -- verified with above, but not counterchecked yet!
244
app.mapUrl("^/img.*/(.+)\\.([^.]+)", "content")
245
.setPathInfo(configDir + "/img/$1.$2")
246
.pushArg("image/$2");
248
// Map favicon.ico into img directory
249
app.mapUrl("^/favicon.ico$", "content")
250
.setPathInfo(configDir + "/img/favicon.ico")
251
.pushArg("image/x-icon");
253
// takes first path components without 'extension' when it does not
255
// modified by 'tadi' -- verified with above, but not counterchecked yet!
256
app.mapUrl("^/([^./]+)(.*)?", "$1");
258
tnt::Sessionscope::setDefaultTimeout(86400);
259
tnt::HttpReply::setDefaultContentType(string("text/html; charset=") + LiveI18n().CharacterEncoding());
261
Setup::IpList const& ips = LiveSetup().GetServerIps();
262
int port = LiveSetup().GetServerPort();
263
size_t listenFailures = 0;
264
for (Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip) {
266
esyslog("[live] INFO: attempt to listen on ip = '%s'", ip->c_str());
267
app.listen(*ip, port);
269
catch (exception const & ex) {
270
esyslog("[live] ERROR: ip = %s is invalid: exception = %s", ip->c_str(), ex.what());
271
if (++listenFailures == ips.size()) {
272
// if no listener was initialized we throw at
273
// least the last exception to the next layer.
280
int s_port = LiveSetup().GetServerSslPort();
281
string s_cert = LiveSetup().GetServerSslCert();
282
string s_key = LiveSetup().GetServerSslKey();
284
if (s_cert.empty()) {
285
s_cert = configDir + "/live.pem";
289
s_key = configDir + "/live-key.pem";
292
if ( ifstream( s_cert.c_str() ) && ifstream( s_key.c_str() ) ) {
293
for ( Setup::IpList::const_iterator ip = ips.begin(); ip != ips.end(); ++ip ) {
294
app.sslListen(s_cert, s_key, *ip, s_port);
298
esyslog( "[live] ERROR: Unable to load cert/key (%s/%s): %s", s_cert.c_str(), s_key.c_str(), strerror( errno ) );
300
#endif // TNT_SSL_SUPPORT
304
TntConfig const& TntConfig::Get()
306
static TntConfig instance;
168
309
} // namespace vdrlive