comparison plugins/filesystem_attachments/filesystem_attachments.php @ 8:bf99236cc5cd

try to recover from upgrade fail
author Charlie Root
date Sat, 29 Dec 2018 07:07:34 -0500
parents 4681f974d28b
children
comparison
equal deleted inserted replaced
7:65fd7d441cf1 8:bf99236cc5cd
5 * This is a core plugin which provides basic, filesystem based 5 * This is a core plugin which provides basic, filesystem based
6 * attachment temporary file handling. This includes storing 6 * attachment temporary file handling. This includes storing
7 * attachments of messages currently being composed, writing attachments 7 * attachments of messages currently being composed, writing attachments
8 * to disk when drafts with attachments are re-opened and writing 8 * to disk when drafts with attachments are re-opened and writing
9 * attachments to disk for inline display in current html compositions. 9 * attachments to disk for inline display in current html compositions.
10 * It also handles uploaded files for other uses, so not only attachments.
10 * 11 *
11 * Developers may wish to extend this class when creating attachment 12 * Developers may wish to extend this class when creating attachment
12 * handler plugins: 13 * handler plugins:
13 * require_once('plugins/filesystem_attachments/filesystem_attachments.php'); 14 * require_once('plugins/filesystem_attachments/filesystem_attachments.php');
14 * class myCustom_attachments extends filesystem_attachments 15 * class myCustom_attachments extends filesystem_attachments
16 *
17 * Note for developers: It is plugin's responsibility to care about security.
18 * So, e.g. if the plugin is asked about some file path it should check
19 * if it's really the storage path of the plugin and not e.g. /etc/passwd.
20 * It is done by setting 'status' flag on every plugin hook it uses.
21 * Roundcube core will trust the returned path if status=true.
15 * 22 *
16 * @license GNU GPLv3+ 23 * @license GNU GPLv3+
17 * @author Ziba Scott <ziba@umich.edu> 24 * @author Ziba Scott <ziba@umich.edu>
18 * @author Thomas Bruederli <roundcube@gmail.com> 25 * @author Thomas Bruederli <roundcube@gmail.com>
19 */ 26 */
48 */ 55 */
49 function upload($args) 56 function upload($args)
50 { 57 {
51 $args['status'] = false; 58 $args['status'] = false;
52 $group = $args['group']; 59 $group = $args['group'];
53 $rcmail = rcmail::get_instance(); 60 $rcmail = rcube::get_instance();
54 61
55 // use common temp dir for file uploads 62 // use common temp dir for file uploads
56 $temp_dir = $rcmail->config->get('temp_dir'); 63 $temp_dir = $rcmail->config->get('temp_dir');
57 $tmpfname = tempnam($temp_dir, 'rcmAttmnt'); 64 $tmpfname = tempnam($temp_dir, 'rcmAttmnt');
58 65
76 { 83 {
77 $group = $args['group']; 84 $group = $args['group'];
78 $args['status'] = false; 85 $args['status'] = false;
79 86
80 if (!$args['path']) { 87 if (!$args['path']) {
81 $rcmail = rcmail::get_instance(); 88 $rcmail = rcube::get_instance();
82 $temp_dir = $rcmail->config->get('temp_dir'); 89 $temp_dir = $rcmail->config->get('temp_dir');
83 $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); 90 $tmp_path = tempnam($temp_dir, 'rcmAttmnt');
84 91
85 if ($fp = fopen($tmp_path, 'w')) { 92 if ($fp = fopen($tmp_path, 'w')) {
86 fwrite($fp, $args['data']); 93 fwrite($fp, $args['data']);
105 * Remove an attachment from storage 112 * Remove an attachment from storage
106 * This is triggered by the remove attachment button on the compose screen 113 * This is triggered by the remove attachment button on the compose screen
107 */ 114 */
108 function remove($args) 115 function remove($args)
109 { 116 {
110 $args['status'] = @unlink($args['path']); 117 $args['status'] = $this->verify_path($args['path']) && @unlink($args['path']);
111 return $args; 118 return $args;
112 } 119 }
113 120
114 /** 121 /**
115 * When composing an html message, image attachments may be shown 122 * When composing an html message, image attachments may be shown
116 * For this plugin, the file is already in place, just check for 123 * For this plugin, the file is already in place, just check for
117 * the existance of the proper metadata 124 * the existence of the proper metadata
118 */ 125 */
119 function display($args) 126 function display($args)
120 { 127 {
121 $args['status'] = file_exists($args['path']); 128 $args['status'] = $this->verify_path($args['path']) && file_exists($args['path']);
122 return $args; 129 return $args;
123 } 130 }
124 131
125 /** 132 /**
126 * This attachment plugin doesn't require any steps to put the file 133 * This attachment plugin doesn't require any steps to put the file
127 * on disk for use. This stub function is kept here to make this 134 * on disk for use. This stub function is kept here to make this
128 * class handy as a parent class for other plugins which may need it. 135 * class handy as a parent class for other plugins which may need it.
129 */ 136 */
130 function get($args) 137 function get($args)
131 { 138 {
139 if (!$this->verify_path($args['path'])) {
140 $args['path'] = null;
141 }
142
132 return $args; 143 return $args;
133 } 144 }
134 145
135 /** 146 /**
136 * Delete all temp files associated with this user 147 * Delete all temp files associated with this user
145 if ($args['group'] && $args['group'] != $group) { 156 if ($args['group'] && $args['group'] != $group) {
146 continue; 157 continue;
147 } 158 }
148 159
149 foreach ((array)$files as $filename) { 160 foreach ((array)$files as $filename) {
150 if(file_exists($filename)) { 161 if (file_exists($filename)) {
151 unlink($filename); 162 unlink($filename);
152 } 163 }
153 } 164 }
154 165
155 unset($_SESSION['plugins']['filesystem_attachments'][$group]); 166 unset($_SESSION['plugins']['filesystem_attachments'][$group]);
158 return $args; 169 return $args;
159 } 170 }
160 171
161 function file_id() 172 function file_id()
162 { 173 {
163 $userid = rcmail::get_instance()->user->ID; 174 $userid = rcube::get_instance()->user->ID;
164 list($usec, $sec) = explode(' ', microtime()); 175 list($usec, $sec) = explode(' ', microtime());
165 $id = preg_replace('/[^0-9]/', '', $userid . $sec . $usec); 176 $id = preg_replace('/[^0-9]/', '', $userid . $sec . $usec);
166 177
167 // make sure the ID is really unique (#1489546) 178 // make sure the ID is really unique (#1489546)
168 while ($this->find_file_by_id($id)) { 179 while ($this->find_file_by_id($id)) {
180 if (isset($files[$id])) { 191 if (isset($files[$id])) {
181 return true; 192 return true;
182 } 193 }
183 } 194 }
184 } 195 }
196
197 /**
198 * For security we'll always verify the file path stored in session,
199 * as session entries can be faked in various ways e.g. #6026.
200 * We allow only files in Roundcube temp dir
201 */
202 protected function verify_path($path)
203 {
204 if (empty($path)) {
205 return false;
206 }
207
208 $rcmail = rcube::get_instance();
209 $temp_dir = $rcmail->config->get('temp_dir');
210 $file_path = pathinfo($path, PATHINFO_DIRNAME);
211
212 if ($temp_dir !== $file_path) {
213 rcube::raise_error(array(
214 'code' => 403,
215 'file' => __FILE__,
216 'line' => __LINE__,
217 'message' => sprintf("%s can't read %s (not in temp_dir)",
218 $rcmail->get_user_name(), substr($path, 0, 512))
219 ), true, false);
220
221 return false;
222 }
223
224 return true;
225 }
185 } 226 }