summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.m42
-rw-r--r--post_handler.c18
-rw-r--r--rfc1867_new.c1278
-rw-r--r--ufilter.c4
4 files changed, 1283 insertions, 19 deletions
diff --git a/config.m4 b/config.m4
index 2a756e3..ee4b7ba 100644
--- a/config.m4
+++ b/config.m4
@@ -5,5 +5,5 @@ PHP_ARG_ENABLE(suhosin, whether to enable suhosin support,
5[ --enable-suhosin Enable suhosin support]) 5[ --enable-suhosin Enable suhosin support])
6 6
7if test "$PHP_SUHOSIN" != "no"; then 7if test "$PHP_SUHOSIN" != "no"; then
8 PHP_NEW_EXTENSION(suhosin, suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c log.c header.c execute.c ex_imp.c session.c aes.c compat_snprintf.c, $ext_shared) 8 PHP_NEW_EXTENSION(suhosin, suhosin.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c rfc1867_new.c log.c header.c execute.c ex_imp.c session.c aes.c compat_snprintf.c, $ext_shared)
9fi 9fi
diff --git a/post_handler.c b/post_handler.c
index 267dfcb..7c678f4 100644
--- a/post_handler.c
+++ b/post_handler.c
@@ -130,9 +130,7 @@ static PHP_INI_MH(suhosin_OnUpdate_mbstring_encoding_translation)
130 */ 130 */
131static sapi_post_entry suhosin_post_entries[] = { 131static sapi_post_entry suhosin_post_entries[] = {
132 { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, suhosin_std_post_handler }, 132 { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, suhosin_std_post_handler },
133#if PHP_VERSION_ID < 50400
134 { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, suhosin_rfc1867_post_handler }, 133 { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, suhosin_rfc1867_post_handler },
135#endif
136 { NULL, 0, NULL, NULL } 134 { NULL, 0, NULL, NULL }
137}; 135};
138/* }}} */ 136/* }}} */
@@ -141,15 +139,7 @@ void suhosin_hook_post_handlers(TSRMLS_D)
141{ 139{
142 HashTable tempht; 140 HashTable tempht;
143 zend_ini_entry *ini_entry; 141 zend_ini_entry *ini_entry;
144 142
145 old_rfc1867_callback = php_rfc1867_callback;
146
147#if PHP_VERSION_ID >= 50400
148 /* the RFC1867 code is now good enough in PHP to handle our filter just as a registered callback */
149 php_rfc1867_callback = suhosin_rfc1867_filter;
150 sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC);
151 sapi_register_post_entries(suhosin_post_entries TSRMLS_CC);
152#else
153#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0) 143#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
154 sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC); 144 sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC);
155 sapi_unregister_post_entry(&suhosin_post_entries[1] TSRMLS_CC); 145 sapi_unregister_post_entry(&suhosin_post_entries[1] TSRMLS_CC);
@@ -159,7 +149,7 @@ void suhosin_hook_post_handlers(TSRMLS_D)
159 sapi_unregister_post_entry(&suhosin_post_entries[1]); 149 sapi_unregister_post_entry(&suhosin_post_entries[1]);
160 sapi_register_post_entries(suhosin_post_entries); 150 sapi_register_post_entries(suhosin_post_entries);
161#endif 151#endif
162#endif 152
163 /* we want to get notified if another extension deregisters the suhosin post handlers */ 153 /* we want to get notified if another extension deregisters the suhosin post handlers */
164 154
165 /* we need to tell suhosin patch that there is a new valid destructor */ 155 /* we need to tell suhosin patch that there is a new valid destructor */
@@ -182,10 +172,6 @@ void suhosin_unhook_post_handlers(TSRMLS_D)
182{ 172{
183 zend_ini_entry *ini_entry; 173 zend_ini_entry *ini_entry;
184 174
185#if PHP_VERSION_ID >= 50400
186 /* unhook the php_rfc1867_callback */
187 php_rfc1867_callback = old_rfc1867_callback;
188#endif
189 /* Restore to an empty destructor */ 175 /* Restore to an empty destructor */
190 SG(known_post_content_types).pDestructor = NULL; 176 SG(known_post_content_types).pDestructor = NULL;
191 177
diff --git a/rfc1867_new.c b/rfc1867_new.c
new file mode 100644
index 0000000..65a2fe8
--- /dev/null
+++ b/rfc1867_new.c
@@ -0,0 +1,1278 @@
1/*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Rasmus Lerdorf <rasmus@php.net> |
16 | Jani Taskinen <jani@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20/* $Id$ */
21
22/*
23 * This product includes software developed by the Apache Group
24 * for use in the Apache HTTP server project (http://www.apache.org/).
25 *
26 */
27
28#include <stdio.h>
29#include "php.h"
30#include "php_open_temporary_file.h"
31#include "zend_globals.h"
32#include "php_globals.h"
33#include "php_variables.h"
34#include "php_suhosin.h"
35#include "suhosin_rfc1867.h"
36#include "ext/standard/php_string.h"
37
38#if PHP_VERSION_ID >= 50400
39
40#define DEBUG_FILE_UPLOAD ZEND_DEBUG
41
42static int dummy_encoding_translation(TSRMLS_D)
43{
44 return 0;
45}
46
47static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC);
48static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC);
49
50static php_rfc1867_encoding_translation_t php_rfc1867_encoding_translation = dummy_encoding_translation;
51static php_rfc1867_get_detect_order_t php_rfc1867_get_detect_order = NULL;
52static php_rfc1867_set_input_encoding_t php_rfc1867_set_input_encoding = NULL;
53static php_rfc1867_getword_t php_rfc1867_getword = php_ap_getword;
54static php_rfc1867_getword_conf_t php_rfc1867_getword_conf = php_ap_getword_conf;
55static php_rfc1867_basename_t php_rfc1867_basename = NULL;
56
57static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
58
59/* The longest property name we use in an uploaded file array */
60#define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
61
62/* The longest anonymous name */
63#define MAX_SIZE_ANONNAME 33
64
65/* Errors */
66#define UPLOAD_ERROR_OK 0 /* File upload successful */
67#define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */
68#define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */
69#define UPLOAD_ERROR_C 3 /* Partially uploaded */
70#define UPLOAD_ERROR_D 4 /* No file uploaded */
71#define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */
72#define UPLOAD_ERROR_F 7 /* Failed to write file to disk */
73#define UPLOAD_ERROR_X 8 /* File upload stopped by extension */
74
75static void normalize_protected_variable(char *varname TSRMLS_DC) /* {{{ */
76{
77 char *s = varname, *index = NULL, *indexend = NULL, *p;
78
79 /* overjump leading space */
80 while (*s == ' ') {
81 s++;
82 }
83
84 /* and remove it */
85 if (s != varname) {
86 memmove(varname, s, strlen(s)+1);
87 }
88
89 for (p = varname; *p && *p != '['; p++) {
90 switch(*p) {
91 case ' ':
92 case '.':
93 *p = '_';
94 break;
95 }
96 }
97
98 /* find index */
99 index = strchr(varname, '[');
100 if (index) {
101 index++;
102 s = index;
103 } else {
104 return;
105 }
106
107 /* done? */
108 while (index) {
109 while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
110 index++;
111 }
112 indexend = strchr(index, ']');
113 indexend = indexend ? indexend + 1 : index + strlen(index);
114
115 if (s != index) {
116 memmove(s, index, strlen(index)+1);
117 s += indexend-index;
118 } else {
119 s = indexend;
120 }
121
122 if (*s == '[') {
123 s++;
124 index = s;
125 } else {
126 index = NULL;
127 }
128 }
129 *s = '\0';
130}
131/* }}} */
132
133static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
134{
135 int dummy = 1;
136
137 normalize_protected_variable(varname TSRMLS_CC);
138 zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
139}
140/* }}} */
141
142static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
143{
144 normalize_protected_variable(varname TSRMLS_CC);
145 return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1);
146}
147/* }}} */
148
149static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
150{
151 if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
152 php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
153 }
154}
155/* }}} */
156
157static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
158{
159 if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
160 php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
161 }
162}
163/* }}} */
164
165static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
166{
167 safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
168}
169/* }}} */
170
171static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
172{
173 safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
174}
175/* }}} */
176
177static int unlink_filename(char **filename TSRMLS_DC) /* {{{ */
178{
179 VCWD_UNLINK(*filename);
180 return 0;
181}
182/* }}} */
183
184void destroy_uploaded_files_hash(TSRMLS_D) /* {{{ */
185{
186 zend_hash_apply(SG(rfc1867_uploaded_files), (apply_func_t) unlink_filename TSRMLS_CC);
187 zend_hash_destroy(SG(rfc1867_uploaded_files));
188 FREE_HASHTABLE(SG(rfc1867_uploaded_files));
189}
190/* }}} */
191
192/* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
193
194#define FILLUNIT (1024 * 5)
195
196typedef struct {
197
198 /* read buffer */
199 char *buffer;
200 char *buf_begin;
201 int bufsize;
202 int bytes_in_buffer;
203
204 /* boundary info */
205 char *boundary;
206 char *boundary_next;
207 int boundary_next_len;
208
209 const zend_encoding *input_encoding;
210 const zend_encoding **detect_order;
211 size_t detect_order_size;
212} multipart_buffer;
213
214typedef struct {
215 char *key;
216 char *value;
217} mime_header_entry;
218
219/*
220 * Fill up the buffer with client data.
221 * Returns number of bytes added to buffer.
222 */
223static int fill_buffer(multipart_buffer *self TSRMLS_DC)
224{
225 int bytes_to_read, total_read = 0, actual_read = 0;
226
227 /* shift the existing data if necessary */
228 if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
229 memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
230 }
231
232 self->buf_begin = self->buffer;
233
234 /* calculate the free space in the buffer */
235 bytes_to_read = self->bufsize - self->bytes_in_buffer;
236
237 /* read the required number of bytes */
238 while (bytes_to_read > 0) {
239
240 char *buf = self->buffer + self->bytes_in_buffer;
241
242 actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
243
244 /* update the buffer length */
245 if (actual_read > 0) {
246 self->bytes_in_buffer += actual_read;
247 SG(read_post_bytes) += actual_read;
248 total_read += actual_read;
249 bytes_to_read -= actual_read;
250 } else {
251 break;
252 }
253 }
254
255 return total_read;
256}
257
258/* eof if we are out of bytes, or if we hit the final boundary */
259static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
260{
261 if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
262 return 1;
263 } else {
264 return 0;
265 }
266}
267
268/* create new multipart_buffer structure */
269static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len TSRMLS_DC)
270{
271 multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
272
273 int minsize = boundary_len + 6;
274 if (minsize < FILLUNIT) minsize = FILLUNIT;
275
276 self->buffer = (char *) ecalloc(1, minsize + 1);
277 self->bufsize = minsize;
278
279 spprintf(&self->boundary, 0, "--%s", boundary);
280
281 self->boundary_next_len = spprintf(&self->boundary_next, 0, "\n--%s", boundary);
282
283 self->buf_begin = self->buffer;
284 self->bytes_in_buffer = 0;
285
286 if (php_rfc1867_encoding_translation(TSRMLS_C)) {
287 php_rfc1867_get_detect_order(&self->detect_order, &self->detect_order_size TSRMLS_CC);
288 } else {
289 self->detect_order = NULL;
290 self->detect_order_size = 0;
291 }
292
293 self->input_encoding = NULL;
294
295 return self;
296}
297
298/*
299 * Gets the next CRLF terminated line from the input buffer.
300 * If it doesn't find a CRLF, and the buffer isn't completely full, returns
301 * NULL; otherwise, returns the beginning of the null-terminated line,
302 * minus the CRLF.
303 *
304 * Note that we really just look for LF terminated lines. This works
305 * around a bug in internet explorer for the macintosh which sends mime
306 * boundaries that are only LF terminated when you use an image submit
307 * button in a multipart/form-data form.
308 */
309static char *next_line(multipart_buffer *self)
310{
311 /* look for LF in the data */
312 char* line = self->buf_begin;
313 char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
314
315 if (ptr) { /* LF found */
316
317 /* terminate the string, remove CRLF */
318 if ((ptr - line) > 0 && *(ptr-1) == '\r') {
319 *(ptr-1) = 0;
320 } else {
321 *ptr = 0;
322 }
323
324 /* bump the pointer */
325 self->buf_begin = ptr + 1;
326 self->bytes_in_buffer -= (self->buf_begin - line);
327
328 } else { /* no LF found */
329
330 /* buffer isn't completely full, fail */
331 if (self->bytes_in_buffer < self->bufsize) {
332 return NULL;
333 }
334 /* return entire buffer as a partial line */
335 line[self->bufsize] = 0;
336 self->buf_begin = ptr;
337 self->bytes_in_buffer = 0;
338 }
339
340 return line;
341}
342
343/* Returns the next CRLF terminated line from the client */
344static char *get_line(multipart_buffer *self TSRMLS_DC)
345{
346 char* ptr = next_line(self);
347
348 if (!ptr) {
349 fill_buffer(self TSRMLS_CC);
350 ptr = next_line(self);
351 }
352
353 return ptr;
354}
355
356/* Free header entry */
357static void php_free_hdr_entry(mime_header_entry *h)
358{
359 if (h->key) {
360 efree(h->key);
361 }
362 if (h->value) {
363 efree(h->value);
364 }
365}
366
367/* finds a boundary */
368static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
369{
370 char *line;
371
372 /* loop thru lines */
373 while( (line = get_line(self TSRMLS_CC)) )
374 {
375 /* finished if we found the boundary */
376 if (!strcmp(line, boundary)) {
377 return 1;
378 }
379 }
380
381 /* didn't find the boundary */
382 return 0;
383}
384
385/* parse headers */
386static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
387{
388 char *line;
389 mime_header_entry prev_entry = {0}, entry;
390 int prev_len, cur_len;
391
392 /* didn't find boundary, abort */
393 if (!find_boundary(self, self->boundary TSRMLS_CC)) {
394 return 0;
395 }
396
397 /* get lines of text, or CRLF_CRLF */
398
399 while( (line = get_line(self TSRMLS_CC)) && line[0] != '\0' )
400 {
401 /* add header to table */
402 char *key = line;
403 char *value = NULL;
404
405 if (php_rfc1867_encoding_translation(TSRMLS_C)) {
406 self->input_encoding = zend_multibyte_encoding_detector(line, strlen(line), self->detect_order, self->detect_order_size TSRMLS_CC);
407 }
408
409 /* space in the beginning means same header */
410 if (!isspace(line[0])) {
411 value = strchr(line, ':');
412 }
413
414 if (value) {
415 *value = 0;
416 do { value++; } while(isspace(*value));
417
418 entry.value = estrdup(value);
419 entry.key = estrdup(key);
420
421 } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
422
423 prev_len = strlen(prev_entry.value);
424 cur_len = strlen(line);
425
426 entry.value = emalloc(prev_len + cur_len + 1);
427 memcpy(entry.value, prev_entry.value, prev_len);
428 memcpy(entry.value + prev_len, line, cur_len);
429 entry.value[cur_len + prev_len] = '\0';
430
431 entry.key = estrdup(prev_entry.key);
432
433 zend_llist_remove_tail(header);
434 } else {
435 continue;
436 }
437
438 zend_llist_add_element(header, &entry);
439 prev_entry = entry;
440 }
441
442 return 1;
443}
444
445static char *php_mime_get_hdr_value(zend_llist header, char *key)
446{
447 mime_header_entry *entry;
448
449 if (key == NULL) {
450 return NULL;
451 }
452
453 entry = zend_llist_get_first(&header);
454 while (entry) {
455 if (!strcasecmp(entry->key, key)) {
456 return entry->value;
457 }
458 entry = zend_llist_get_next(&header);
459 }
460
461 return NULL;
462}
463
464static char *php_ap_getword(const zend_encoding *encoding, char **line, char stop TSRMLS_DC)
465{
466 char *pos = *line, quote;
467 char *res;
468
469 while (*pos && *pos != stop) {
470 if ((quote = *pos) == '"' || quote == '\'') {
471 ++pos;
472 while (*pos && *pos != quote) {
473 if (*pos == '\\' && pos[1] && pos[1] == quote) {
474 pos += 2;
475 } else {
476 ++pos;
477 }
478 }
479 if (*pos) {
480 ++pos;
481 }
482 } else ++pos;
483 }
484 if (*pos == '\0') {
485 res = estrdup(*line);
486 *line += strlen(*line);
487 return res;
488 }
489
490 res = estrndup(*line, pos - *line);
491
492 while (*pos == stop) {
493 ++pos;
494 }
495
496 *line = pos;
497 return res;
498}
499
500static char *substring_conf(char *start, int len, char quote)
501{
502 char *result = emalloc(len + 1);
503 char *resp = result;
504 int i;
505
506 for (i = 0; i < len && start[i] != quote; ++i) {
507 if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
508 *resp++ = start[++i];
509 } else {
510 *resp++ = start[i];
511 }
512 }
513
514 *resp = '\0';
515 return result;
516}
517
518static char *php_ap_getword_conf(const zend_encoding *encoding, char *str TSRMLS_DC)
519{
520 while (*str && isspace(*str)) {
521 ++str;
522 }
523
524 if (!*str) {
525 return estrdup("");
526 }
527
528 if (*str == '"' || *str == '\'') {
529 char quote = *str;
530
531 str++;
532 return substring_conf(str, strlen(str), quote);
533 } else {
534 char *strend = str;
535
536 while (*strend && !isspace(*strend)) {
537 ++strend;
538 }
539 return substring_conf(str, strend - str, 0);
540 }
541}
542
543static char *php_ap_basename(const zend_encoding *encoding, char *path TSRMLS_DC)
544{
545 char *s = strrchr(path, '\\');
546 char *s2 = strrchr(path, '/');
547
548 if (s && s2) {
549 if (s > s2) {
550 ++s;
551 } else {
552 s = ++s2;
553 }
554 return s;
555 } else if (s) {
556 return ++s;
557 } else if (s2) {
558 return ++s2;
559 }
560 return path;
561}
562
563/*
564 * Search for a string in a fixed-length byte string.
565 * If partial is true, partial matches are allowed at the end of the buffer.
566 * Returns NULL if not found, or a pointer to the start of the first match.
567 */
568static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
569{
570 int len = haystacklen;
571 char *ptr = haystack;
572
573 /* iterate through first character matches */
574 while( (ptr = memchr(ptr, needle[0], len)) ) {
575
576 /* calculate length after match */
577 len = haystacklen - (ptr - (char *)haystack);
578
579 /* done if matches up to capacity of buffer */
580 if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
581 break;
582 }
583
584 /* next character */
585 ptr++; len--;
586 }
587
588 return ptr;
589}
590
591/* read until a boundary condition */
592static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
593{
594 int len, max;
595 char *bound;
596
597 /* fill buffer if needed */
598 if (bytes > self->bytes_in_buffer) {
599 fill_buffer(self TSRMLS_CC);
600 }
601
602 /* look for a potential boundary match, only read data up to that point */
603 if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
604 max = bound - self->buf_begin;
605 if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
606 *end = 1;
607 }
608 } else {
609 max = self->bytes_in_buffer;
610 }
611
612 /* maximum number of bytes we are reading */
613 len = max < bytes-1 ? max : bytes-1;
614
615 /* if we read any data... */
616 if (len > 0) {
617
618 /* copy the data */
619 memcpy(buf, self->buf_begin, len);
620 buf[len] = 0;
621
622 if (bound && len > 0 && buf[len-1] == '\r') {
623 buf[--len] = 0;
624 }
625
626 /* update the buffer */
627 self->bytes_in_buffer -= len;
628 self->buf_begin += len;
629 }
630
631 return len;
632}
633
634/*
635 XXX: this is horrible memory-usage-wise, but we only expect
636 to do this on small pieces of form data.
637*/
638static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
639{
640 char buf[FILLUNIT], *out=NULL;
641 int total_bytes=0, read_bytes=0;
642
643 while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
644 out = erealloc(out, total_bytes + read_bytes + 1);
645 memcpy(out + total_bytes, buf, read_bytes);
646 total_bytes += read_bytes;
647 }
648
649 if (out) {
650 out[total_bytes] = '\0';
651 }
652 *len = total_bytes;
653
654 return out;
655}
656/* }}} */
657
658/*
659 * The combined READER/HANDLER
660 *
661 */
662
663SAPI_POST_HANDLER_FUNC(suhosin_rfc1867_post_handler) /* {{{ */
664{
665 char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
666 char *temp_filename = NULL, *lbuf = NULL, *abuf = NULL;
667 int boundary_len = 0, total_bytes = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0;
668 int max_file_size = 0, skip_upload = 0, anonindex = 0, is_anonymous;
669 zval *http_post_files = NULL;
670 HashTable *uploaded_files = NULL;
671 multipart_buffer *mbuff;
672 zval *array_ptr = (zval *) arg;
673 int fd = -1;
674 zend_llist header;
675 void *event_extra_data = NULL;
676 unsigned int llen = 0;
677 int upload_cnt = INI_INT("max_file_uploads");
678 const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
679 php_rfc1867_getword_t getword;
680 php_rfc1867_getword_conf_t getword_conf;
681 php_rfc1867_basename_t _basename;
682 long count = 0;
683
684 if (php_rfc1867_encoding_translation(TSRMLS_C) && internal_encoding) {
685 getword = php_rfc1867_getword;
686 getword_conf = php_rfc1867_getword_conf;
687 _basename = php_rfc1867_basename;
688 } else {
689 getword = php_ap_getword;
690 getword_conf = php_ap_getword_conf;
691 _basename = php_ap_basename;
692 }
693
694 if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
695 sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
696 return;
697 }
698
699 /* Get the boundary */
700 boundary = strstr(content_type_dup, "boundary");
701 if (!boundary) {
702 int content_type_len = strlen(content_type_dup);
703 char *content_type_lcase = estrndup(content_type_dup, content_type_len);
704
705 php_strtolower(content_type_lcase, content_type_len);
706 boundary = strstr(content_type_lcase, "boundary");
707 if (boundary) {
708 boundary = content_type_dup + (boundary - content_type_lcase);
709 }
710 efree(content_type_lcase);
711 }
712
713 if (!boundary || !(boundary = strchr(boundary, '='))) {
714 sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
715 return;
716 }
717
718 boundary++;
719 boundary_len = strlen(boundary);
720
721 if (boundary[0] == '"') {
722 boundary++;
723 boundary_end = strchr(boundary, '"');
724 if (!boundary_end) {
725 sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
726 return;
727 }
728 } else {
729 /* search for the end of the boundary */
730 boundary_end = strpbrk(boundary, ",;");
731 }
732 if (boundary_end) {
733 boundary_end[0] = '\0';
734 boundary_len = boundary_end-boundary;
735 }
736
737 /* Initialize the buffer */
738 if (!(mbuff = multipart_buffer_new(boundary, boundary_len TSRMLS_CC))) {
739 sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
740 return;
741 }
742
743 /* Initialize $_FILES[] */
744 zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
745
746 ALLOC_HASHTABLE(uploaded_files);
747 zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
748 SG(rfc1867_uploaded_files) = uploaded_files;
749
750 ALLOC_ZVAL(http_post_files);
751 array_init(http_post_files);
752 INIT_PZVAL(http_post_files);
753 PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
754
755 zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
756
757 if (suhosin_rfc1867_filter != NULL) {
758 multipart_event_start event_start;
759
760 event_start.content_length = SG(request_info).content_length;
761 if (suhosin_rfc1867_filter(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
762 goto fileupload_done;
763 }
764 }
765
766 while (!multipart_buffer_eof(mbuff TSRMLS_CC))
767 {
768 char buff[FILLUNIT];
769 char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
770 size_t blen = 0, wlen = 0;
771 off_t offset;
772
773 zend_llist_clean(&header);
774
775 if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
776 goto fileupload_done;
777 }
778
779 if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
780 char *pair = NULL;
781 int end = 0;
782
783 while (isspace(*cd)) {
784 ++cd;
785 }
786
787 while (*cd && (pair = getword(mbuff->input_encoding, &cd, ';' TSRMLS_CC)))
788 {
789 char *key = NULL, *word = pair;
790
791 while (isspace(*cd)) {
792 ++cd;
793 }
794
795 if (strchr(pair, '=')) {
796 key = getword(mbuff->input_encoding, &pair, '=' TSRMLS_CC);
797
798 if (!strcasecmp(key, "name")) {
799 if (param) {
800 efree(param);
801 }
802 param = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
803 if (mbuff->input_encoding && internal_encoding) {
804 unsigned char *new_param;
805 size_t new_param_len;
806 if ((size_t)-1 != zend_multibyte_encoding_converter(&new_param, &new_param_len, (unsigned char *)param, strlen(param), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
807 efree(param);
808 param = (char *)new_param;
809 }
810 }
811 } else if (!strcasecmp(key, "filename")) {
812 if (filename) {
813 efree(filename);
814 }
815 filename = getword_conf(mbuff->input_encoding, pair TSRMLS_CC);
816 if (mbuff->input_encoding && internal_encoding) {
817 unsigned char *new_filename;
818 size_t new_filename_len;
819 if ((size_t)-1 != zend_multibyte_encoding_converter(&new_filename, &new_filename_len, (unsigned char *)filename, strlen(filename), internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
820 efree(filename);
821 filename = (char *)new_filename;
822 }
823 }
824 }
825 }
826 if (key) {
827 efree(key);
828 }
829 efree(word);
830 }
831
832 /* Normal form variable, safe to read all data into memory */
833 if (!filename && param) {
834 unsigned int value_len;
835 char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
836 unsigned int new_val_len; /* Dummy variable */
837
838 if (!value) {
839 value = estrdup("");
840 value_len = 0;
841 }
842
843 if (mbuff->input_encoding && internal_encoding) {
844 unsigned char *new_value;
845 size_t new_value_len;
846 if ((size_t)-1 != zend_multibyte_encoding_converter(&new_value, &new_value_len, (unsigned char *)value, value_len, internal_encoding, mbuff->input_encoding TSRMLS_CC)) {
847 efree(value);
848 value = (char *)new_value;
849 value_len = new_value_len;
850 }
851 }
852
853 if (suhosin_input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC) == 0) {
854 efree(param);
855 efree(value);
856 continue;
857 }
858
859 if (++count <= PG(max_input_vars) && sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
860 if (suhosin_rfc1867_filter != NULL) {
861 multipart_event_formdata event_formdata;
862 size_t newlength = new_val_len;
863
864 event_formdata.post_bytes_processed = SG(read_post_bytes);
865 event_formdata.name = param;
866 event_formdata.value = &value;
867 event_formdata.length = new_val_len;
868 event_formdata.newlength = &newlength;
869 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
870 efree(param);
871 efree(value);
872 continue;
873 }
874 new_val_len = newlength;
875 }
876 safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
877 } else {
878 if (count == PG(max_input_vars) + 1) {
879 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
880 }
881
882 if (suhosin_rfc1867_filter != NULL) {
883 multipart_event_formdata event_formdata;
884
885 event_formdata.post_bytes_processed = SG(read_post_bytes);
886 event_formdata.name = param;
887 event_formdata.value = &value;
888 event_formdata.length = value_len;
889 event_formdata.newlength = NULL;
890 suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
891 }
892 }
893
894 if (!strcasecmp(param, "MAX_FILE_SIZE")) {
895 max_file_size = atol(value);
896 }
897
898 efree(param);
899 efree(value);
900 continue;
901 }
902
903 /* If file_uploads=off, skip the file part */
904 if (!PG(file_uploads)) {
905 skip_upload = 1;
906 } else if (upload_cnt <= 0) {
907 skip_upload = 1;
908 sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
909 }
910
911 /* Return with an error if the posted data is garbled */
912 if (!param && !filename) {
913 sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
914 goto fileupload_done;
915 }
916
917 if (!param) {
918 is_anonymous = 1;
919 param = emalloc(MAX_SIZE_ANONNAME);
920 snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
921 } else {
922 is_anonymous = 0;
923 }
924
925 /* New Rule: never repair potential malicious user input */
926 if (!skip_upload) {
927 long c = 0;
928 tmp = param;
929
930 while (*tmp) {
931 if (*tmp == '[') {
932 c++;
933 } else if (*tmp == ']') {
934 c--;
935 if (tmp[1] && tmp[1] != '[') {
936 skip_upload = 1;
937 break;
938 }
939 }
940 if (c < 0) {
941 skip_upload = 1;
942 break;
943 }
944 tmp++;
945 }
946 /* Brackets should always be closed */
947 if(c != 0) {
948 skip_upload = 1;
949 }
950 }
951
952 total_bytes = cancel_upload = 0;
953 temp_filename = NULL;
954 fd = -1;
955
956 if (!skip_upload && suhosin_rfc1867_filter != NULL) {
957 multipart_event_file_start event_file_start;
958
959 event_file_start.post_bytes_processed = SG(read_post_bytes);
960 event_file_start.name = param;
961 event_file_start.filename = &filename;
962 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
963 temp_filename = "";
964 efree(param);
965 efree(filename);
966 continue;
967 }
968 }
969
970 if (skip_upload) {
971 efree(param);
972 efree(filename);
973 continue;
974 }
975
976 if (filename[0] == '\0') {
977#if DEBUG_FILE_UPLOAD
978 sapi_module.sapi_error(E_NOTICE, "No file uploaded");
979#endif
980 cancel_upload = UPLOAD_ERROR_D;
981 }
982
983 offset = 0;
984 end = 0;
985
986 if (!cancel_upload) {
987 /* only bother to open temp file if we have data */
988 blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
989#if DEBUG_FILE_UPLOAD
990 if (blen > 0) {
991#else
992 /* in non-debug mode we have no problem with 0-length files */
993 {
994#endif
995 fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
996 upload_cnt--;
997 if (fd == -1) {
998 sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
999 cancel_upload = UPLOAD_ERROR_E;
1000 }
1001 }
1002 }
1003
1004 while (!cancel_upload && (blen > 0))
1005 {
1006 if (suhosin_rfc1867_filter != NULL) {
1007 multipart_event_file_data event_file_data;
1008
1009 event_file_data.post_bytes_processed = SG(read_post_bytes);
1010 event_file_data.offset = offset;
1011 event_file_data.data = buff;
1012 event_file_data.length = blen;
1013 event_file_data.newlength = &blen;
1014 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
1015 cancel_upload = UPLOAD_ERROR_X;
1016 continue;
1017 }
1018 }
1019
1020 if (PG(upload_max_filesize) > 0 && (long)(total_bytes+blen) > PG(upload_max_filesize)) {
1021#if DEBUG_FILE_UPLOAD
1022 sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
1023#endif
1024 cancel_upload = UPLOAD_ERROR_A;
1025 } else if (max_file_size && ((long)(total_bytes+blen) > max_file_size)) {
1026#if DEBUG_FILE_UPLOAD
1027 sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
1028#endif
1029 cancel_upload = UPLOAD_ERROR_B;
1030 } else if (blen > 0) {
1031 wlen = write(fd, buff, blen);
1032
1033 if (wlen == -1) {
1034 /* write failed */
1035#if DEBUG_FILE_UPLOAD
1036 sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
1037#endif
1038 cancel_upload = UPLOAD_ERROR_F;
1039 } else if (wlen < blen) {
1040#if DEBUG_FILE_UPLOAD
1041 sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
1042#endif
1043 cancel_upload = UPLOAD_ERROR_F;
1044 } else {
1045 total_bytes += wlen;
1046 }
1047 offset += wlen;
1048 }
1049
1050 /* read data for next iteration */
1051 blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
1052 }
1053
1054 if (fd != -1) { /* may not be initialized if file could not be created */
1055 close(fd);
1056 }
1057
1058 if (!cancel_upload && !end) {
1059#if DEBUG_FILE_UPLOAD
1060 sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", filename[0] != '\0' ? filename : "");
1061#endif
1062 cancel_upload = UPLOAD_ERROR_C;
1063 }
1064#if DEBUG_FILE_UPLOAD
1065 if (filename[0] != '\0' && total_bytes == 0 && !cancel_upload) {
1066 sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
1067 cancel_upload = 5;
1068 }
1069#endif
1070 if (suhosin_rfc1867_filter != NULL) {
1071 multipart_event_file_end event_file_end;
1072
1073 event_file_end.post_bytes_processed = SG(read_post_bytes);
1074 event_file_end.temp_filename = temp_filename;
1075 event_file_end.cancel_upload = cancel_upload;
1076 if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
1077 cancel_upload = UPLOAD_ERROR_X;
1078 }
1079 }
1080
1081 if (cancel_upload) {
1082 if (temp_filename) {
1083 if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
1084 unlink(temp_filename);
1085 }
1086 efree(temp_filename);
1087 }
1088 temp_filename = "";
1089 } else {
1090 zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
1091 }
1092
1093 /* is_arr_upload is true when name of file upload field
1094 * ends in [.*]
1095 * start_arr is set to point to 1st [ */
1096 is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
1097
1098 if (is_arr_upload) {
1099 array_len = strlen(start_arr);
1100 if (array_index) {
1101 efree(array_index);
1102 }
1103 array_index = estrndup(start_arr + 1, array_len - 2);
1104 }
1105
1106 /* Add $foo_name */
1107 if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
1108 llen = strlen(param);
1109 lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
1110 llen += MAX_SIZE_OF_INDEX + 1;
1111 }
1112
1113 if (is_arr_upload) {
1114 if (abuf) efree(abuf);
1115 abuf = estrndup(param, strlen(param)-array_len);
1116 snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
1117 } else {
1118 snprintf(lbuf, llen, "%s_name", param);
1119 }
1120
1121 /* The \ check should technically be needed for win32 systems only where
1122 * it is a valid path separator. However, IE in all it's wisdom always sends
1123 * the full path of the file on the user's filesystem, which means that unless
1124 * the user does basename() they get a bogus file name. Until IE's user base drops
1125 * to nill or problem is fixed this code must remain enabled for all systems. */
1126 s = _basename(internal_encoding, filename TSRMLS_CC);
1127 if (!s) {
1128 s = filename;
1129 }
1130
1131 if (!is_anonymous) {
1132 safe_php_register_variable(lbuf, s, strlen(s), NULL, 0 TSRMLS_CC);
1133 }
1134
1135 /* Add $foo[name] */
1136 if (is_arr_upload) {
1137 snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
1138 } else {
1139 snprintf(lbuf, llen, "%s[name]", param);
1140 }
1141 register_http_post_files_variable(lbuf, s, http_post_files, 0 TSRMLS_CC);
1142 efree(filename);
1143 s = NULL;
1144
1145 /* Possible Content-Type: */
1146 if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
1147 cd = "";
1148 } else {
1149 /* fix for Opera 6.01 */
1150 s = strchr(cd, ';');
1151 if (s != NULL) {
1152 *s = '\0';
1153 }
1154 }
1155
1156 /* Add $foo_type */
1157 if (is_arr_upload) {
1158 snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
1159 } else {
1160 snprintf(lbuf, llen, "%s_type", param);
1161 }
1162 if (!is_anonymous) {
1163 safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
1164 }
1165
1166 /* Add $foo[type] */
1167 if (is_arr_upload) {
1168 snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
1169 } else {
1170 snprintf(lbuf, llen, "%s[type]", param);
1171 }
1172 register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
1173
1174 /* Restore Content-Type Header */
1175 if (s != NULL) {
1176 *s = ';';
1177 }
1178 s = "";
1179
1180 {
1181 /* store temp_filename as-is (in case upload_tmp_dir
1182 * contains escapeable characters. escape only the variable name.) */
1183 zval zfilename;
1184
1185 /* Initialize variables */
1186 add_protected_variable(param TSRMLS_CC);
1187
1188 /* if param is of form xxx[.*] this will cut it to xxx */
1189 if (!is_anonymous) {
1190 ZVAL_STRING(&zfilename, temp_filename, 1);
1191 safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
1192 }
1193
1194 /* Add $foo[tmp_name] */
1195 if (is_arr_upload) {
1196 snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
1197 } else {
1198 snprintf(lbuf, llen, "%s[tmp_name]", param);
1199 }
1200 add_protected_variable(lbuf TSRMLS_CC);
1201 ZVAL_STRING(&zfilename, temp_filename, 1);
1202 register_http_post_files_variable_ex(lbuf, &zfilename, http_post_files, 1 TSRMLS_CC);
1203 }
1204
1205 {
1206 zval file_size, error_type;
1207
1208 error_type.value.lval = cancel_upload;
1209 error_type.type = IS_LONG;
1210
1211 /* Add $foo[error] */
1212 if (cancel_upload) {
1213 file_size.value.lval = 0;
1214 file_size.type = IS_LONG;
1215 } else {
1216 file_size.value.lval = total_bytes;
1217 file_size.type = IS_LONG;
1218 }
1219
1220 if (is_arr_upload) {
1221 snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
1222 } else {
1223 snprintf(lbuf, llen, "%s[error]", param);
1224 }
1225 register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
1226
1227 /* Add $foo_size */
1228 if (is_arr_upload) {
1229 snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
1230 } else {
1231 snprintf(lbuf, llen, "%s_size", param);
1232 }
1233 if (!is_anonymous) {
1234 safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
1235 }
1236
1237 /* Add $foo[size] */
1238 if (is_arr_upload) {
1239 snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
1240 } else {
1241 snprintf(lbuf, llen, "%s[size]", param);
1242 }
1243 register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
1244 }
1245 efree(param);
1246 }
1247 }
1248
1249fileupload_done:
1250 if (suhosin_rfc1867_filter != NULL) {
1251 multipart_event_end event_end;
1252
1253 event_end.post_bytes_processed = SG(read_post_bytes);
1254 suhosin_rfc1867_filter(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
1255 }
1256
1257 if (lbuf) efree(lbuf);
1258 if (abuf) efree(abuf);
1259 if (array_index) efree(array_index);
1260 zend_hash_destroy(&PG(rfc1867_protected_variables));
1261 zend_llist_destroy(&header);
1262 if (mbuff->boundary_next) efree(mbuff->boundary_next);
1263 if (mbuff->boundary) efree(mbuff->boundary);
1264 if (mbuff->buffer) efree(mbuff->buffer);
1265 if (mbuff) efree(mbuff);
1266}
1267/* }}} */
1268
1269#endif
1270
1271/*
1272 * Local variables:
1273 * tab-width: 4
1274 * c-basic-offset: 4
1275 * End:
1276 * vim600: sw=4 ts=4 fdm=marker
1277 * vim<600: sw=4 ts=4
1278 */
diff --git a/ufilter.c b/ufilter.c
index 6584617..efab2ce 100644
--- a/ufilter.c
+++ b/ufilter.c
@@ -346,8 +346,8 @@ int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TS
346 } 346 }
347continue_with_next: 347continue_with_next:
348#if HAVE_RFC1867_CALLBACK 348#if HAVE_RFC1867_CALLBACK
349 if (old_rfc1867_callback != NULL) { 349 if (php_rfc1867_callback != NULL) {
350 return old_rfc1867_callback(event, event_data, extra TSRMLS_CC); 350 return php_rfc1867_callback(event, event_data, extra TSRMLS_CC);
351 } 351 }
352#endif 352#endif
353 return SUCCESS; 353 return SUCCESS;