|
38 | 38 | #include "ext/standard/php_standard.h"
|
39 | 39 | #include "zend_compile.h"
|
40 | 40 | #include "php_network.h"
|
| 41 | +#include "zend_smart_str.h" |
41 | 42 |
|
42 | 43 | #if HAVE_PWD_H
|
43 | 44 | #include <pwd.h>
|
@@ -81,60 +82,51 @@ PHPAPI ZEND_INI_MH(OnUpdateBaseDir)
|
81 | 82 | return SUCCESS;
|
82 | 83 | }
|
83 | 84 |
|
84 |
| - /* Otherwise we're in runtime */ |
85 |
| - if (!*p || !**p) { |
86 |
| - /* open_basedir not set yet, go ahead and give it a value */ |
87 |
| - *p = ZSTR_VAL(new_value); |
88 |
| - return SUCCESS; |
89 |
| - } |
90 |
| - |
91 | 85 | /* Shortcut: When we have a open_basedir and someone tries to unset, we know it'll fail */
|
92 | 86 | if (!new_value || !*ZSTR_VAL(new_value)) {
|
93 | 87 | return FAILURE;
|
94 | 88 | }
|
95 | 89 |
|
96 | 90 | /* Is the proposed open_basedir at least as restrictive as the current setting? */
|
| 91 | + smart_str buf = {0}; |
97 | 92 | ptr = pathbuf = estrdup(ZSTR_VAL(new_value));
|
98 | 93 | while (ptr && *ptr) {
|
99 | 94 | end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
|
100 | 95 | if (end != NULL) {
|
101 | 96 | *end = '\0';
|
102 | 97 | end++;
|
103 | 98 | }
|
104 |
| - /* Don't allow paths with a parent dir component (..) to be set at runtime */ |
105 |
| - char *substr_pos = ptr; |
106 |
| - while (*substr_pos) { |
107 |
| - // Check if we have a .. path component |
108 |
| - if (substr_pos[0] == '.' |
109 |
| - && substr_pos[1] == '.' |
110 |
| - && (substr_pos[2] == '\0' || IS_SLASH(substr_pos[2]))) { |
111 |
| - efree(pathbuf); |
112 |
| - return FAILURE; |
113 |
| - } |
114 |
| - // Skip to the next path component |
115 |
| - while (true) { |
116 |
| - substr_pos++; |
117 |
| - if (*substr_pos == '\0' || *substr_pos == DEFAULT_DIR_SEPARATOR) { |
118 |
| - goto no_parent_dir_component; |
119 |
| - } else if (IS_SLASH(*substr_pos)) { |
120 |
| - // Also skip the slash |
121 |
| - substr_pos++; |
122 |
| - break; |
123 |
| - } |
124 |
| - } |
| 99 | + char resolved_name[MAXPATHLEN + 1]; |
| 100 | + if (expand_filepath(ptr, resolved_name) == NULL) { |
| 101 | + efree(pathbuf); |
| 102 | + smart_str_free(&buf); |
| 103 | + return FAILURE; |
125 | 104 | }
|
126 |
| -no_parent_dir_component: |
127 |
| - if (php_check_open_basedir_ex(ptr, 0) != 0) { |
| 105 | + if (php_check_open_basedir_ex(resolved_name, 0) != 0) { |
128 | 106 | /* At least one portion of this open_basedir is less restrictive than the prior one, FAIL */
|
129 | 107 | efree(pathbuf);
|
| 108 | + smart_str_free(&buf); |
130 | 109 | return FAILURE;
|
131 | 110 | }
|
| 111 | + if (smart_str_get_len(&buf) != 0) { |
| 112 | + smart_str_appendc(&buf, DEFAULT_DIR_SEPARATOR); |
| 113 | + } |
| 114 | + smart_str_appends(&buf, resolved_name); |
132 | 115 | ptr = end;
|
133 | 116 | }
|
134 | 117 | efree(pathbuf);
|
135 | 118 |
|
136 | 119 | /* Everything checks out, set it */
|
137 |
| - *p = ZSTR_VAL(new_value); |
| 120 | + if (*p) { |
| 121 | + /* Unfortunately entry->modified has already been set to true so we compare entry->value |
| 122 | + * against entry->orig_value. */ |
| 123 | + if (entry->modified && entry->value != entry->orig_value) { |
| 124 | + efree(*p); |
| 125 | + } |
| 126 | + } |
| 127 | + zend_string *tmp = smart_str_extract(&buf); |
| 128 | + *p = estrdup(ZSTR_VAL(tmp)); |
| 129 | + zend_string_release(tmp); |
138 | 130 |
|
139 | 131 | return SUCCESS;
|
140 | 132 | }
|
|
0 commit comments