1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 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: Brian Schaffner <brian@tool.net> | |
16 | | Shane Caraveo <shane@caraveo.com> | |
17 | | Zeev Suraski <zeev@zend.com> | |
18 | +----------------------------------------------------------------------+ |
19 | */ |
20 | |
21 | /* $Id$ */ |
22 | |
23 | #include "php.h" |
24 | #include "dl.h" |
25 | #include "php_globals.h" |
26 | #include "php_ini.h" |
27 | #include "ext/standard/info.h" |
28 | |
29 | #include "SAPI.h" |
30 | |
31 | #if defined(HAVE_LIBDL) |
32 | #include <stdlib.h> |
33 | #include <stdio.h> |
34 | #ifdef HAVE_STRING_H |
35 | #include <string.h> |
36 | #else |
37 | #include <strings.h> |
38 | #endif |
39 | #ifdef PHP_WIN32 |
40 | #include "win32/param.h" |
41 | #include "win32/winutil.h" |
42 | #define GET_DL_ERROR() php_win_err() |
43 | #elif defined(NETWARE) |
44 | #include <sys/param.h> |
45 | #define GET_DL_ERROR() dlerror() |
46 | #else |
47 | #include <sys/param.h> |
48 | #define GET_DL_ERROR() DL_ERROR() |
49 | #endif |
50 | #endif /* defined(HAVE_LIBDL) */ |
51 | |
52 | /* {{{ proto int dl(string extension_filename) |
53 | Load a PHP extension at runtime */ |
54 | PHPAPI PHP_FUNCTION(dl) |
55 | { |
56 | char *filename; |
57 | int filename_len; |
58 | |
59 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s" , &filename, &filename_len) == FAILURE) { |
60 | return; |
61 | } |
62 | |
63 | if (!PG(enable_dl)) { |
64 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Dynamically loaded extensions aren't enabled" ); |
65 | RETURN_FALSE; |
66 | } |
67 | |
68 | if (filename_len >= MAXPATHLEN) { |
69 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "File name exceeds the maximum allowed length of %d characters" , MAXPATHLEN); |
70 | RETURN_FALSE; |
71 | } |
72 | |
73 | if ((strncmp(sapi_module.name, "cgi" , 3) != 0) && |
74 | (strcmp(sapi_module.name, "cli" ) != 0) && |
75 | (strncmp(sapi_module.name, "embed" , 5) != 0) |
76 | ) { |
77 | #ifdef ZTS |
78 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported in multithreaded Web servers - use extension=%s in your php.ini" , filename); |
79 | RETURN_FALSE; |
80 | #else |
81 | php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "dl() is deprecated - use extension=%s in your php.ini" , filename); |
82 | #endif |
83 | } |
84 | |
85 | php_dl(filename, MODULE_TEMPORARY, return_value, 0 TSRMLS_CC); |
86 | if (Z_LVAL_P(return_value) == 1) { |
87 | EG(full_tables_cleanup) = 1; |
88 | } |
89 | } |
90 | /* }}} */ |
91 | |
92 | #if defined(HAVE_LIBDL) |
93 | |
94 | #ifdef ZTS |
95 | #define USING_ZTS 1 |
96 | #else |
97 | #define USING_ZTS 0 |
98 | #endif |
99 | |
100 | /* {{{ php_load_extension |
101 | */ |
102 | PHPAPI int php_load_extension(char *filename, int type, int start_now TSRMLS_DC) |
103 | { |
104 | void *handle; |
105 | char *libpath; |
106 | zend_module_entry *module_entry; |
107 | zend_module_entry *(*get_module)(void); |
108 | int error_type; |
109 | char *extension_dir; |
110 | |
111 | if (type == MODULE_PERSISTENT) { |
112 | extension_dir = INI_STR("extension_dir" ); |
113 | } else { |
114 | extension_dir = PG(extension_dir); |
115 | } |
116 | |
117 | if (type == MODULE_TEMPORARY) { |
118 | error_type = E_WARNING; |
119 | } else { |
120 | error_type = E_CORE_WARNING; |
121 | } |
122 | |
123 | /* Check if passed filename contains directory separators */ |
124 | if (strchr(filename, '/') != NULL || strchr(filename, DEFAULT_SLASH) != NULL) { |
125 | /* Passing modules with full path is not supported for dynamically loaded extensions */ |
126 | if (type == MODULE_TEMPORARY) { |
127 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Temporary module name should contain only filename" ); |
128 | return FAILURE; |
129 | } |
130 | libpath = estrdup(filename); |
131 | } else if (extension_dir && extension_dir[0]) { |
132 | int extension_dir_len = strlen(extension_dir); |
133 | |
134 | if (IS_SLASH(extension_dir[extension_dir_len-1])) { |
135 | spprintf(&libpath, 0, "%s%s" , extension_dir, filename); /* SAFE */ |
136 | } else { |
137 | spprintf(&libpath, 0, "%s%c%s" , extension_dir, DEFAULT_SLASH, filename); /* SAFE */ |
138 | } |
139 | } else { |
140 | return FAILURE; /* Not full path given or extension_dir is not set */ |
141 | } |
142 | |
143 | /* load dynamic symbol */ |
144 | handle = DL_LOAD(libpath); |
145 | if (!handle) { |
146 | #if PHP_WIN32 |
147 | char *err = GET_DL_ERROR(); |
148 | if (err && (*err != "" )) { |
149 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s" , libpath, err); |
150 | LocalFree(err); |
151 | } else { |
152 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s" , libpath, "Unknown reason" ); |
153 | } |
154 | #else |
155 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to load dynamic library '%s' - %s" , libpath, GET_DL_ERROR()); |
156 | GET_DL_ERROR(); /* free the buffer storing the error */ |
157 | #endif |
158 | efree(libpath); |
159 | return FAILURE; |
160 | } |
161 | efree(libpath); |
162 | |
163 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module" ); |
164 | |
165 | /* Some OS prepend _ to symbol names while their dynamic linker |
166 | * does not do that automatically. Thus we check manually for |
167 | * _get_module. */ |
168 | |
169 | if (!get_module) { |
170 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module" ); |
171 | } |
172 | |
173 | if (!get_module) { |
174 | if (DL_FETCH_SYMBOL(handle, "zend_extension_entry" ) || DL_FETCH_SYMBOL(handle, "_zend_extension_entry" )) { |
175 | DL_UNLOAD(handle); |
176 | php_error_docref(NULL TSRMLS_CC, error_type, "Invalid library (appears to be a Zend Extension, try loading using zend_extension=%s from php.ini)" , filename); |
177 | return FAILURE; |
178 | } |
179 | DL_UNLOAD(handle); |
180 | php_error_docref(NULL TSRMLS_CC, error_type, "Invalid library (maybe not a PHP library) '%s'" , filename); |
181 | return FAILURE; |
182 | } |
183 | module_entry = get_module(); |
184 | if (module_entry->zend_api != ZEND_MODULE_API_NO) { |
185 | /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ |
186 | struct pre_4_1_0_module_entry { |
187 | char *name; |
188 | zend_function_entry *functions; |
189 | int (*module_startup_func)(INIT_FUNC_ARGS); |
190 | int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS); |
191 | int (*request_startup_func)(INIT_FUNC_ARGS); |
192 | int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS); |
193 | void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS); |
194 | int (*global_startup_func)(void); |
195 | int (*global_shutdown_func)(void); |
196 | int globals_id; |
197 | int module_started; |
198 | unsigned char type; |
199 | void *handle; |
200 | int module_number; |
201 | unsigned char zend_debug; |
202 | unsigned char zts; |
203 | unsigned int zend_api; |
204 | }; |
205 | |
206 | const char *name; |
207 | int zend_api; |
208 | |
209 | if ((((struct pre_4_1_0_module_entry *)module_entry)->zend_api > 20000000) && |
210 | (((struct pre_4_1_0_module_entry *)module_entry)->zend_api < 20010901) |
211 | ) { |
212 | name = ((struct pre_4_1_0_module_entry *)module_entry)->name; |
213 | zend_api = ((struct pre_4_1_0_module_entry *)module_entry)->zend_api; |
214 | } else { |
215 | name = module_entry->name; |
216 | zend_api = module_entry->zend_api; |
217 | } |
218 | |
219 | php_error_docref(NULL TSRMLS_CC, error_type, |
220 | "%s: Unable to initialize module\n" |
221 | "Module compiled with module API=%d\n" |
222 | "PHP compiled with module API=%d\n" |
223 | "These options need to match\n" , |
224 | name, zend_api, ZEND_MODULE_API_NO); |
225 | DL_UNLOAD(handle); |
226 | return FAILURE; |
227 | } |
228 | if(strcmp(module_entry->build_id, ZEND_MODULE_BUILD_ID)) { |
229 | php_error_docref(NULL TSRMLS_CC, error_type, |
230 | "%s: Unable to initialize module\n" |
231 | "Module compiled with build ID=%s\n" |
232 | "PHP compiled with build ID=%s\n" |
233 | "These options need to match\n" , |
234 | module_entry->name, module_entry->build_id, ZEND_MODULE_BUILD_ID); |
235 | DL_UNLOAD(handle); |
236 | return FAILURE; |
237 | } |
238 | module_entry->type = type; |
239 | module_entry->module_number = zend_next_free_module(); |
240 | module_entry->handle = handle; |
241 | |
242 | if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) { |
243 | DL_UNLOAD(handle); |
244 | return FAILURE; |
245 | } |
246 | |
247 | if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { |
248 | DL_UNLOAD(handle); |
249 | return FAILURE; |
250 | } |
251 | |
252 | if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) { |
253 | if (module_entry->request_startup_func(type, module_entry->module_number TSRMLS_CC) == FAILURE) { |
254 | php_error_docref(NULL TSRMLS_CC, error_type, "Unable to initialize module '%s'" , module_entry->name); |
255 | DL_UNLOAD(handle); |
256 | return FAILURE; |
257 | } |
258 | } |
259 | return SUCCESS; |
260 | } |
261 | /* }}} */ |
262 | |
263 | /* {{{ php_dl |
264 | */ |
265 | PHPAPI void php_dl(char *file, int type, zval *return_value, int start_now TSRMLS_DC) |
266 | { |
267 | /* Load extension */ |
268 | if (php_load_extension(file, type, start_now TSRMLS_CC) == FAILURE) { |
269 | RETVAL_FALSE; |
270 | } else { |
271 | RETVAL_TRUE; |
272 | } |
273 | } |
274 | /* }}} */ |
275 | |
276 | PHP_MINFO_FUNCTION(dl) |
277 | { |
278 | php_info_print_table_row(2, "Dynamic Library Support" , "enabled" ); |
279 | } |
280 | |
281 | #else |
282 | |
283 | PHPAPI void php_dl(char *file, int type, zval *return_value, int start_now TSRMLS_DC) |
284 | { |
285 | php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot dynamically load %s - dynamic modules are not supported" , file); |
286 | RETURN_FALSE; |
287 | } |
288 | |
289 | PHP_MINFO_FUNCTION(dl) |
290 | { |
291 | PUTS("Dynamic Library support not available<br />.\n" ); |
292 | } |
293 | |
294 | #endif |
295 | |
296 | /* |
297 | * Local variables: |
298 | * tab-width: 4 |
299 | * c-basic-offset: 4 |
300 | * End: |
301 | * vim600: sw=4 ts=4 fdm=marker |
302 | * vim<600: sw=4 ts=4 |
303 | */ |
304 | |