File roundcubemail-1.1-csrf.patch of Package roundcubemail (Revision 47d10155de802c878f9b76f2a90be803)
Currently displaying revision 47d10155de802c878f9b76f2a90be803 , Show latest
786
1
diff -ur roundcubemail-1.1.orig/config/defaults.inc.php roundcubemail-1.1/config/defaults.inc.php
2
--- roundcubemail-1.1.orig/config/defaults.inc.php 2014-09-04 13:26:10.000000000 +0200
3
+++ roundcubemail-1.1/config/defaults.inc.php 2014-09-06 14:30:33.910366429 +0200
4
5
// Note: useful when SMTP server stores sent mail in user mailbox
6
$config['no_save_sent_messages'] = false;
7
8
+// Improve system security by using special URL with security token.
9
+// This can be set to a number defining token length. Default: 16.
10
+// Warning: This requires http server configuration. Sample:
11
+// RewriteRule ^/roundcubemail/[a-f0-9]{16}/(.*) /roundcubemail/$1 [PT]
12
+// Alias /roundcubemail /var/www/roundcubemail/
13
+// Note: Use assets_path to not prevent the browser from caching assets
14
+$config['use_secure_urls'] = false;
15
+
16
+// Allows to define separate server/path for image/js/css files
17
+// Warning: If the domain is different cross-domain access to some
18
+// resources need to be allowed
19
+// Sample:
20
+// <FilesMatch ".(eot|ttf|woff)">
21
+// Header set Access-Control-Allow-Origin "*"
22
+// </FilesMatch>
23
+$config['assets_path'] = '';
24
+
25
// ----------------------------------
26
// PLUGINS
27
// ----------------------------------
28
diff -ur roundcubemail-1.1.orig/.htaccess roundcubemail-1.1/.htaccess
29
--- roundcubemail-1.1.orig/.htaccess 2014-09-04 13:26:10.000000000 +0200
30
+++ roundcubemail-1.1/.htaccess 2014-09-06 14:30:33.908366428 +0200
31
32
# security rules:
33
# - deny access to files not containing a dot or starting with a dot
34
# in all locations except installer directory
35
-RewriteRule ^(?!installer)(\.?[^\.]+)$ - [F]
36
+RewriteRule ^(?!installer|[a-f0-9]{16})(\.?[^\.]+)$ - [F]
37
# - deny access to some locations
38
RewriteRule ^/?(\.git|\.tx|SQL|bin|config|logs|temp|tests|program\/(include|lib|localization|steps)) - [F]
39
# - deny access to some documentation files
40
diff -ur roundcubemail-1.1.orig/index.php roundcubemail-1.1/index.php
41
--- roundcubemail-1.1.orig/index.php 2014-09-04 13:26:10.000000000 +0200
42
+++ roundcubemail-1.1/index.php 2014-09-06 14:30:33.911366430 +0200
43
44
45
// try to log in
46
if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
47
- $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(rcube_utils::INPUT_POST, 'login');
48
+ $request_valid = $_SESSION['temp'] && $RCMAIL->check_request();
49
50
- // purge the session in case of new login when a session already exists
51
+ // purge the session in case of new login when a session already exists
52
$RCMAIL->kill_session();
53
54
$auth = $RCMAIL->plugins->exec_hook('authenticate', array(
55
56
unset($redir['abort'], $redir['_err']);
57
58
// send redirect
59
- $OUTPUT->redirect($redir);
60
+ $OUTPUT->redirect($redir, 0, true);
61
}
62
else {
63
if (!$auth['valid']) {
64
65
}
66
}
67
68
-// end session (after optional referer check)
69
-else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id'])
70
- && (!$RCMAIL->config->get('referer_check') || rcube_utils::check_referer())
71
-) {
72
+// end session
73
+else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id'])) {
74
+ $RCMAIL->request_security_check($mode = rcube_utils::INPUT_GET);
75
+
76
$userdata = array(
77
'user' => $_SESSION['username'],
78
'host' => $_SESSION['storage_host'],
79
80
81
$OUTPUT->send($plugin['task']);
82
}
83
-// CSRF prevention
84
else {
85
- // don't check for valid request tokens in these actions
86
- $request_check_whitelist = array('login'=>1, 'spell'=>1, 'spell_html'=>1);
87
-
88
- if (!$request_check_whitelist[$RCMAIL->action]) {
89
- // check client X-header to verify request origin
90
- if ($OUTPUT->ajax_call) {
91
- if (rcube_utils::request_header('X-Roundcube-Request') != $RCMAIL->get_request_token()) {
92
- header('HTTP/1.1 403 Forbidden');
93
- die("Invalid Request");
94
- }
95
- }
96
- // check request token in POST form submissions
97
- else if (!empty($_POST) && !$RCMAIL->check_request()) {
98
- $OUTPUT->show_message('invalidrequest', 'error');
99
- $OUTPUT->send($RCMAIL->task);
100
- }
101
-
102
- // check referer if configured
103
- if ($RCMAIL->config->get('referer_check') && !rcube_utils::check_referer()) {
104
- raise_error(array(
105
- 'code' => 403, 'type' => 'php',
106
- 'message' => "Referer check failed"), true, true);
107
- }
108
- }
109
+ // CSRF prevention
110
+ $RCMAIL->request_security_check();
111
112
// check access to disabled actions
113
$disabled_actions = (array) $RCMAIL->config->get('disabled_actions');
114
diff -ur roundcubemail-1.1.orig/plugins/acl/acl.js roundcubemail-1.1/plugins/acl/acl.js
115
--- roundcubemail-1.1.orig/plugins/acl/acl.js 2014-09-04 13:26:10.000000000 +0200
116
+++ roundcubemail-1.1/plugins/acl/acl.js 2014-09-06 14:30:33.911366430 +0200
117
118
var users = this.acl_get_usernames();
119
120
if (users && users.length && confirm(this.get_label('acl.deleteconfirm'))) {
121
- this.http_request('settings/plugin.acl', '_act=delete&_user='+urlencode(users.join(','))
122
- + '&_mbox='+urlencode(this.env.mailbox),
123
+ this.http_post('settings/plugin.acl', {
124
+ _act: 'delete',
125
+ _user: users.join(','),
126
+ _mbox: this.env.mailbox
127
+ },
128
this.set_busy(true, 'acl.deleting'));
129
}
130
}
131
132
// Save ACL data
133
rcube_webmail.prototype.acl_save = function()
134
{
135
- var user = $('#acluser', this.acl_form).val(), rights = '', type;
136
+ var data, type, rights = '', user = $('#acluser', this.acl_form).val();
137
138
$((this.env.acl_advanced ? '#advancedrights :checkbox' : '#simplerights :checkbox'), this.acl_form).map(function() {
139
if (this.checked)
140
141
return;
142
}
143
144
- this.http_request('settings/plugin.acl', '_act=save'
145
- + '&_user='+urlencode(user)
146
- + '&_acl=' +rights
147
- + '&_mbox='+urlencode(this.env.mailbox)
148
- + (this.acl_id ? '&_old='+this.acl_id : ''),
149
- this.set_busy(true, 'acl.saving'));
150
+ data = {
151
+ _act: 'save',
152
+ _user: user,
153
+ _acl: rights,
154
+ _mbox: this.env.mailbox
155
+ }
156
+
157
+ if (this.acl_id) {
158
+ data._old = this.acl_id;
159
+ }
160
+
161
+ this.http_post('settings/plugin.acl', data, this.set_busy(true, 'acl.saving'));
162
}
163
164
// Cancel/Hide form
165
diff -ur roundcubemail-1.1.orig/plugins/acl/acl.php roundcubemail-1.1/plugins/acl/acl.php
166
--- roundcubemail-1.1.orig/plugins/acl/acl.php 2014-09-04 13:26:10.000000000 +0200
167
+++ roundcubemail-1.1/plugins/acl/acl.php 2014-09-06 14:30:33.912366431 +0200
168
169
*/
170
private function action_save()
171
{
172
- $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP
173
- $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC));
174
- $acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_GPC));
175
- $oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_GPC));
176
+ $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true)); // UTF7-IMAP
177
+ $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST));
178
+ $acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_POST));
179
+ $oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_POST));
180
181
$acl = array_intersect(str_split($acl), $this->rights_supported());
182
$users = $oldid ? array($user) : explode(',', $user);
183
184
*/
185
private function action_delete()
186
{
187
- $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); //UTF7-IMAP
188
- $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC));
189
+ $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true)); //UTF7-IMAP
190
+ $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST));
191
192
$user = explode(',', $user);
193
194
diff -ur roundcubemail-1.1.orig/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php roundcubemail-1.1/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php
195
--- roundcubemail-1.1.orig/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php 2014-09-04 13:26:10.000000000 +0200
196
+++ roundcubemail-1.1/plugins/managesieve/lib/Roundcube/rcube_sieve_engine.php 2014-09-06 14:30:33.914366432 +0200
197
198
}
199
}
200
else if ($action == 'setact' && !$error) {
201
- $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
202
+ $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
203
$result = $this->activate_script($script_name);
204
$kep14 = $this->rc->config->get('managesieve_kolab_master');
205
206
207
}
208
}
209
else if ($action == 'deact' && !$error) {
210
- $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
211
+ $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
212
$result = $this->deactivate_script($script_name);
213
214
if ($result === true) {
215
216
}
217
}
218
else if ($action == 'setdel' && !$error) {
219
- $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_GPC, true);
220
+ $script_name = rcube_utils::get_input_value('_set', rcube_utils::INPUT_POST, true);
221
$result = $this->remove_script($script_name);
222
223
if ($result === true) {
224
225
$this->rc->output->command('managesieve_updatelist', 'list', array('list' => $result));
226
}
227
else if ($action == 'ruleadd') {
228
- $rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_GPC);
229
+ $rid = rcube_utils::get_input_value('_rid', rcube_utils::INPUT_POST);
230
$id = $this->genid();
231
$content = $this->rule_div($fid, $id, false);
232
233
$this->rc->output->command('managesieve_rulefill', $content, $id, $rid);
234
}
235
else if ($action == 'actionadd') {
236
- $aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_GPC);
237
+ $aid = rcube_utils::get_input_value('_aid', rcube_utils::INPUT_POST);
238
$id = $this->genid();
239
$content = $this->action_div($fid, $id, false);
240
241
Only in roundcubemail-1.1/plugins/managesieve/lib/Roundcube: rcube_sieve_engine.php.orig
242
diff -ur roundcubemail-1.1.orig/program/include/rcmail_output_html.php roundcubemail-1.1/program/include/rcmail_output_html.php
243
--- roundcubemail-1.1.orig/program/include/rcmail_output_html.php 2014-09-04 13:26:10.000000000 +0200
244
+++ roundcubemail-1.1/program/include/rcmail_output_html.php 2014-09-06 14:30:33.917366435 +0200
245
246
protected $footer = '';
247
protected $body = '';
248
protected $base_path = '';
249
+ protected $assets_path;
250
protected $devel_mode = false;
251
252
// deprecated names of templates used before 0.5
253
254
$this->set_skin($skin);
255
$this->set_env('skin', $skin);
256
257
+ $this->set_assets_path($this->config->get('assets_path'));
258
+
259
if (!empty($_REQUEST['_extwin']))
260
$this->set_env('extwin', 1);
261
if ($this->framed || $framed)
262
263
}
264
265
/**
266
+ * Parse and set assets path
267
+ *
268
+ * @param string Assets path (relative or absolute URL)
269
+ */
270
+ public function set_assets_path($path)
271
+ {
272
+ $path = trim($path, '/') . '/';
273
+
274
+ if (empty($path)) {
275
+ return;
276
+ }
277
+
278
+ // convert to absolute URL
279
+ if (!preg_match('|^https?://|', $path)) {
280
+ $base = preg_replace('/[?#&].*$/', '', $_SERVER['REQUEST_URI']);
281
+ $base = rtrim($base, '/');
282
+
283
+ // remove url token if exists
284
+ if ($len = intval($this->config->get('use_secure_urls'))) {
285
+ $_base = explode('/', $base);
286
+ $length = $len > 1 ? $len : 16; // as in rcube::get_secure_url_token()
287
+
288
+ // we can't use real token here because it
289
+ // does not exists in unauthenticated state,
290
+ // hope this will not produce false-positive matches
291
+ foreach ($_base as $idx => $token) {
292
+ if (preg_match('/^[a-f0-9]{' . $length . '}$/', $token)) {
293
+ unset($_base[$idx]);
294
+ break;
295
+ }
296
+ }
297
+
298
+ $base = implode('/', $_base);
299
+ }
300
+
301
+ $path = (rcube_utils::https_check() ? 'https' : 'http') . '://'
302
+ . $_SERVER['SERVER_NAME'] . $base . '/' . $path;
303
+ }
304
+
305
+ $this->assets_path = $path;
306
+ $this->set_env('assets_path', $path);
307
+ }
308
+
309
+ /**
310
* Getter for the current page title
311
*
312
* @return string The page title
313
314
/**
315
* Redirect to a certain url
316
*
317
- * @param mixed $p Either a string with the action or url parameters as key-value pairs
318
- * @param int $delay Delay in seconds
319
+ * @param mixed $p Either a string with the action or url parameters as key-value pairs
320
+ * @param int $delay Delay in seconds
321
+ * @param bool $secure Redirect to secure location (see rcmail::url())
322
*/
323
- public function redirect($p = array(), $delay = 1)
324
+ public function redirect($p = array(), $delay = 1, $secure = false)
325
{
326
if ($this->env['extwin'])
327
$p['extwin'] = 1;
328
- $location = $this->app->url($p);
329
+ $location = $this->app->url($p, false, false, $secure);
330
header('Location: ' . $location);
331
exit;
332
}
333
334
exit;
335
}
336
337
+ /**
338
+ * Modify path by adding URL prefix if configured
339
+ */
340
+ public function asset_url($path)
341
+ {
342
+ // iframe content can't be in a different domain
343
+ // @TODO: check if assests are on a different domain
344
+ if (!$this->assets_path || $path == $this->env['blankpage']) {
345
+ return $path;
346
+ }
347
+
348
+ if ($path[0] == '.' && $path[1] == '/') {
349
+ $path = substr($path, 2);
350
+ }
351
+
352
+ return $this->assets_path . $path;
353
+ }
354
+
355
356
/***** Template parsing methods *****/
357
358
359
$file = $this->file_mod($file);
360
}
361
362
+ $file = $this->asset_url($file);
363
+
364
return $matches[1] . '=' . $matches[2] . $file . $matches[4];
365
}
366
367
368
{
369
if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
370
$file = $this->file_mod($this->scripts_path . $file);
371
+ $file = $this->asset_url($file);
372
}
373
374
if (!is_array($this->script_files[$position])) {
375
376
}
377
378
$attrib['name'] = $attrib['id'];
379
- $attrib['src'] = $attrib['src'] ? $this->abs_url($attrib['src'], true) : 'program/resources/blank.gif';
380
+ $attrib['src'] = $this->asset_url($attrib['src'] ? $this->abs_url($attrib['src'], true) : 'program/resources/blank.gif');
381
382
// register as 'contentframe' object
383
if ($is_contentframe || $attrib['contentframe']) {
384
385
{
386
$images = preg_split('/[\s\t\n,]+/', $attrib['images'], -1, PREG_SPLIT_NO_EMPTY);
387
$images = array_map(array($this, 'abs_url'), $images);
388
+ $images = array_map(array($this, 'asset_url'), $images);
389
390
- if (empty($images) || $this->app->task == 'logout')
391
+ if (empty($images) || $_REQUEST['_task'] == 'logout') {
392
return;
393
+ }
394
395
$this->add_script('var images = ' . self::json_serialize($images) .';
396
for (var i=0; i<images.length; i++) {
397
diff -ur roundcubemail-1.1.orig/program/include/rcmail_output_json.php roundcubemail-1.1/program/include/rcmail_output_json.php
398
--- roundcubemail-1.1.orig/program/include/rcmail_output_json.php 2014-09-04 13:26:10.000000000 +0200
399
+++ roundcubemail-1.1/program/include/rcmail_output_json.php 2014-09-06 14:30:33.917366435 +0200
400
401
*/
402
public function raise_error($code, $message)
403
{
404
+ if ($code == 403) {
405
+ header('HTTP/1.1 403 Forbidden');
406
+ die("Invalid Request");
407
+ }
408
+
409
$this->show_message("Application Error ($code): $message", 'error');
410
$this->remote_response();
411
exit;
412
diff -ur roundcubemail-1.1.orig/program/include/rcmail.php roundcubemail-1.1/program/include/rcmail.php
413
--- roundcubemail-1.1.orig/program/include/rcmail.php 2014-09-04 13:26:10.000000000 +0200
414
+++ roundcubemail-1.1/program/include/rcmail.php 2014-09-06 14:30:33.916366434 +0200
415
416
}
417
418
/**
419
- * Generate a unique token to be used in a form request
420
- *
421
- * @return string The request token
422
- */
423
- public function get_request_token()
424
- {
425
- $sess_id = $_COOKIE[ini_get('session.name')];
426
-
427
- if (!$sess_id) {
428
- $sess_id = session_id();
429
- }
430
-
431
- $plugin = $this->plugins->exec_hook('request_token', array(
432
- 'value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id)));
433
-
434
- return $plugin['value'];
435
- }
436
-
437
- /**
438
- * Check if the current request contains a valid token
439
- *
440
- * @param int Request method
441
- *
442
- * @return boolean True if request token is valid false if not
443
- */
444
- public function check_request($mode = rcube_utils::INPUT_POST)
445
- {
446
- $token = rcube_utils::get_input_value('_token', $mode);
447
- $sess_id = $_COOKIE[ini_get('session.name')];
448
-
449
- return !empty($sess_id) && $token == $this->get_request_token();
450
- }
451
-
452
- /**
453
* Build a valid URL to this instance of Roundcube
454
*
455
* @param mixed Either a string with the action or url parameters as key-value pairs
456
* @param boolean Build an URL absolute to document root
457
* @param boolean Create fully qualified URL including http(s):// and hostname
458
+ * @param bool Return absolute URL in secure location
459
*
460
* @return string Valid application URL
461
*/
462
- public function url($p, $absolute = false, $full = false)
463
+ public function url($p, $absolute = false, $full = false, $secure = false)
464
{
465
if (!is_array($p)) {
466
if (strpos($p, 'http') === 0) {
467
468
}
469
}
470
471
+ $base_path = preg_replace('![^/]+$!', '', strval($_SERVER['SCRIPT_NAME']));
472
+
473
+ if ($secure && ($token = $this->get_secure_url_token(true))) {
474
+ // add token to the url
475
+ $url = $token . '/' . $url;
476
+
477
+ // remove old token from the path
478
+ $base_path = preg_replace('/\/[a-f0-9]{' . strlen($token) . '}$/', '', $base_path);
479
+
480
+ // this need to be full url to make redirects work
481
+ $absolute = true;
482
+ }
483
+
484
if ($absolute || $full) {
485
// add base path to this Roundcube installation
486
- $base_path = preg_replace('![^/]+$!', '', strval($_SERVER['SCRIPT_NAME']));
487
if ($base_path == '') $base_path = '/';
488
$prefix = $base_path;
489
490
491
}
492
}
493
494
+ /**
495
+ * CSRF attack prevention code
496
+ *
497
+ * @param int Request mode
498
+ */
499
+ public function request_security_check($mode = rcube_utils::INPUT_POST)
500
+ {
501
+ // don't check for valid request tokens in these actions
502
+ // @TODO: get rid of this
503
+ $request_check_whitelist = array('spell'=>1, 'spell_html'=>1);
504
+
505
+ if ($request_check_whitelist[$this->action]) {
506
+ return;
507
+ }
508
+
509
+ // check request token
510
+ if (!$this->check_request($mode)) {
511
+ self::raise_error(array(
512
+ 'code' => 403, 'type' => 'php',
513
+ 'message' => "Request security check failed"), false, true);
514
+ }
515
+
516
+ // check referer if configured
517
+ if ($this->config->get('referer_check') && !rcube_utils::check_referer()) {
518
+ self::raise_error(array(
519
+ 'code' => 403, 'type' => 'php',
520
+ 'message' => "Referer check failed"), true, true);
521
+ }
522
+ }
523
+
524
/**
525
* Registers action aliases for current task
526
*
527
diff -ur roundcubemail-1.1.orig/program/js/app.js roundcubemail-1.1/program/js/app.js
528
--- roundcubemail-1.1.orig/program/js/app.js 2014-09-04 13:26:10.000000000 +0200
529
+++ roundcubemail-1.1/program/js/app.js 2014-09-06 14:30:33.920366437 +0200
530
531
532
if (task == 'mail')
533
url += '&_mbox=INBOX';
534
- else if (task == 'logout' && !this.env.server_error)
535
+ else if (task == 'logout' && !this.env.server_error) {
536
+ url += '&_token=' + this.env.request_token;
537
this.clear_compose_data();
538
+ }
539
540
this.redirect(url);
541
};
542
543
if (!url)
544
url = this.env.comm_path;
545
546
- return url.replace(/_task=[a-z0-9_-]+/i, '_task='+task);
547
+ if (url.match(/[?&]_task=[a-zA-Z0-9_-]+/))
548
+ return url.replace(/_task=[a-zA-Z0-9_-]+/, '_task=' + task);
549
+ else
550
+ return url.replace(/\?.*$/, '') + '?_task=' + task;
551
};
552
553
this.reload = function(delay)
554
diff -ur roundcubemail-1.1.orig/program/js/editor.js roundcubemail-1.1/program/js/editor.js
555
--- roundcubemail-1.1.orig/program/js/editor.js 2014-09-04 13:26:10.000000000 +0200
556
+++ roundcubemail-1.1/program/js/editor.js 2014-09-06 14:30:33.921366438 +0200
557
558
function rcube_text_editor(config, id)
559
{
560
var ref = this,
561
+ abs_url = location.href.replace(/[?#].*$/, '').replace(/\/$/, ''),
562
conf = {
563
selector: '#' + ($('#' + id).is('.mce_editor') ? id : 'fake-editor-id'),
564
theme: 'modern',
565
language: config.lang,
566
- content_css: 'program/js/tinymce/roundcube/content.css?v1',
567
+ content_css: (rcmail.env.assets_path || '') + 'program/js/tinymce/roundcube/content.css?v1',
568
menubar: false,
569
statusbar: false,
570
toolbar_items_size: 'small',
571
572
toolbar: 'bold italic underline | alignleft aligncenter alignright alignjustify'
573
+ ' | bullist numlist outdent indent ltr rtl blockquote | forecolor backcolor | fontselect fontsizeselect'
574
+ ' | link unlink table | emoticons charmap image media | code searchreplace undo redo',
575
- spellchecker_rpc_url: '../../../../../?_task=utils&_action=spell_html&_remote=1',
576
+ spellchecker_rpc_url: abs_url + '/?_task=utils&_action=spell_html&_remote=1',
577
spellchecker_language: rcmail.env.spell_lang,
578
accessibility_focus: false,
579
file_browser_callback: function(name, url, type, win) { ref.file_browser_callback(name, url, type); },
580
diff -ur roundcubemail-1.1.orig/program/lib/Roundcube/rcube.php roundcubemail-1.1/program/lib/Roundcube/rcube.php
581
--- roundcubemail-1.1.orig/program/lib/Roundcube/rcube.php 2014-09-04 13:26:10.000000000 +0200
582
+++ roundcubemail-1.1/program/lib/Roundcube/rcube.php 2014-09-06 14:30:33.921366438 +0200
583
584
*/
585
class rcube
586
{
587
- const INIT_WITH_DB = 1;
588
+ // Init options
589
+ const INIT_WITH_DB = 1;
590
const INIT_WITH_PLUGINS = 2;
591
592
+ // Request status
593
+ const REQUEST_VALID = 0;
594
+ const REQUEST_ERROR_URL = 1;
595
+ const REQUEST_ERROR_TOKEN = 2;
596
+
597
/**
598
* Singleton instace of rcube
599
*
600
601
*/
602
public $user;
603
604
+ /**
605
+ * Request status
606
+ *
607
+ * @var int
608
+ */
609
+ public $request_status = 0;
610
611
/* private/protected vars */
612
protected $texts;
613
614
615
616
/**
617
+ * Returns session token for secure URLs
618
+ *
619
+ * @param bool $generate Generate token if not exists in session yet
620
+ *
621
+ * @return string|bool Token string, False when disabled
622
+ */
623
+ public function get_secure_url_token($generate = false)
624
+ {
625
+ if ($len = $this->config->get('use_secure_urls')) {
626
+ if (empty($_SESSION['secure_token']) && $generate) {
627
+ // generate x characters long token
628
+ $length = $len > 1 ? $len : 16;
629
+ $token = openssl_random_pseudo_bytes($length / 2);
630
+ $token = bin2hex($token);
631
+
632
+ $plugin = $this->plugins->exec_hook('secure_token',
633
+ array('value' => $token, 'length' => $length));
634
+
635
+ $_SESSION['secure_token'] = $plugin['value'];
636
+ }
637
+
638
+ return $_SESSION['secure_token'];
639
+ }
640
+
641
+ return false;
642
+ }
643
+
644
+
645
+ /**
646
+ * Generate a unique token to be used in a form request
647
+ *
648
+ * @return string The request token
649
+ */
650
+ public function get_request_token()
651
+ {
652
+ $sess_id = $_COOKIE[ini_get('session.name')];
653
+ if (!$sess_id) {
654
+ $sess_id = session_id();
655
+ }
656
+
657
+ $plugin = $this->plugins->exec_hook('request_token', array(
658
+ 'value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id)));
659
+
660
+ return $plugin['value'];
661
+ }
662
+
663
+
664
+ /**
665
+ * Check if the current request contains a valid token.
666
+ * Empty requests aren't checked until use_secure_urls is set.
667
+ *
668
+ * @param int Request method
669
+ *
670
+ * @return boolean True if request token is valid false if not
671
+ */
672
+ public function check_request($mode = rcube_utils::INPUT_POST)
673
+ {
674
+ // check secure token in URL if enabled
675
+ if ($token = $this->get_secure_url_token()) {
676
+ foreach (explode('/', preg_replace('/[?#&].*$/', '', $_SERVER['REQUEST_URI'])) as $tok) {
677
+ if ($tok == $token) {
678
+ return true;
679
+ }
680
+ }
681
+
682
+ $this->request_status = self::REQUEST_ERROR_URL;
683
+
684
+ return false;
685
+ }
686
+
687
+ $sess_tok = $this->get_request_token();
688
+
689
+ // ajax requests
690
+ if (rcube_utils::request_header('X-Roundcube-Request') == $sess_tok) {
691
+ return true;
692
+ }
693
+
694
+ // skip empty requests
695
+ if (($mode == rcube_utils::INPUT_POST && empty($_POST))
696
+ || ($mode == rcube_utils::INPUT_GET && empty($_GET))
697
+ ) {
698
+ return true;
699
+ }
700
+
701
+ // default method of securing requests
702
+ $token = rcube_utils::get_input_value('_token', $mode);
703
+ $sess_id = $_COOKIE[ini_get('session.name')];
704
+
705
+ if (empty($sess_id) || $token != $sess_tok) {
706
+ $this->request_status = self::REQUEST_ERROR_TOKEN;
707
+ return false;
708
+ }
709
+
710
+ return true;
711
+ }
712
+
713
+
714
+ /**
715
* Build a valid URL to this instance of Roundcube
716
*
717
* @param mixed Either a string with the action or url parameters as key-value pairs
718
719
720
$cli = php_sapi_name() == 'cli';
721
722
- if (($log || $terminate) && !$cli && $arg['message']) {
723
+ if ($log && !$cli && $arg['message']) {
724
$arg['fatal'] = $terminate;
725
self::log_bug($arg);
726
}
727
diff -ur roundcubemail-1.1.orig/program/steps/addressbook/delete.inc roundcubemail-1.1/program/steps/addressbook/delete.inc
728
--- roundcubemail-1.1.orig/program/steps/addressbook/delete.inc 2014-09-04 13:26:10.000000000 +0200
729
+++ roundcubemail-1.1/program/steps/addressbook/delete.inc 2014-09-06 14:30:33.922366438 +0200
730
731
*/
732
733
// process ajax requests only
734
-if (!$OUTPUT->ajax_call)
735
+if (!$OUTPUT->ajax_call) {
736
return;
737
+}
738
739
-$cids = rcmail_get_cids();
740
+$cids = rcmail_get_cids(null, rcube_utils::INPUT_POST);
741
$delcnt = 0;
742
743
// remove previous deletes
744
diff -ur roundcubemail-1.1.orig/program/steps/addressbook/func.inc roundcubemail-1.1/program/steps/addressbook/func.inc
745
--- roundcubemail-1.1.orig/program/steps/addressbook/func.inc 2014-09-04 13:26:10.000000000 +0200
746
+++ roundcubemail-1.1/program/steps/addressbook/func.inc 2014-09-06 14:30:33.922366438 +0200
747
748
*
749
* @return array List of contact IDs per-source
750
*/
751
-function rcmail_get_cids($filter = null)
752
+function rcmail_get_cids($filter = null, $request_type = rcube_utils::INPUT_GPC)
753
{
754
// contact ID (or comma-separated list of IDs) is provided in two
755
// forms. If _source is an empty string then the ID is a string
756
// containing contact ID and source name in form: <ID>-<SOURCE>
757
758
- $cid = rcube_utils::get_input_value('_cid', rcube_utils::INPUT_GPC);
759
+ $cid = rcube_utils::get_input_value('_cid', $request_type);
760
$source = (string) rcube_utils::get_input_value('_source', rcube_utils::INPUT_GPC);
761
762
if (is_array($cid)) {
763
diff -ur roundcubemail-1.1.orig/program/steps/utils/error.inc roundcubemail-1.1/program/steps/utils/error.inc
764
--- roundcubemail-1.1.orig/program/steps/utils/error.inc 2014-09-04 13:26:10.000000000 +0200
765
+++ roundcubemail-1.1/program/steps/utils/error.inc 2014-09-06 14:30:33.923366439 +0200
766
767
768
// forbidden due to request check
769
else if ($ERROR_CODE == 403) {
770
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' && $rcmail->request_status == rcube::REQUEST_ERROR_URL) {
771
+ parse_str($_SERVER['QUERY_STRING'], $url);
772
+ $url = $rcmail->url($url, true, false, true);
773
+ $add = "<br /><a href=\"$url\">Click here to try again.<a/>";
774
+ }
775
+ else {
776
+ $add = "Please contact your server-administrator.";
777
+ }
778
+
779
$__error_title = "REQUEST CHECK FAILED";
780
- $__error_text = "Access to this service was denied due to failing security checks!<br />\n"
781
- . "Please contact your server-administrator.";
782
+ $__error_text = "Access to this service was denied due to failing security checks!<br />\n$add";
783
}
784
785
// failed request (wrong step in URL)
786