Mercurial > hg > rc2
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 } |
