/src/php-src/ext/standard/dl.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | +----------------------------------------------------------------------+ |
3 | | | Copyright (c) The PHP Group | |
4 | | +----------------------------------------------------------------------+ |
5 | | | This source file is subject to version 3.01 of the PHP license, | |
6 | | | that is bundled with this package in the file LICENSE, and is | |
7 | | | available through the world-wide-web at the following url: | |
8 | | | http://www.php.net/license/3_01.txt | |
9 | | | If you did not receive a copy of the PHP license and are unable to | |
10 | | | obtain it through the world-wide-web, please send a note to | |
11 | | | license@php.net so we can mail you a copy immediately. | |
12 | | +----------------------------------------------------------------------+ |
13 | | | Authors: Brian Schaffner <brian@tool.net> | |
14 | | | Shane Caraveo <shane@caraveo.com> | |
15 | | | Zeev Suraski <zeev@php.net> | |
16 | | +----------------------------------------------------------------------+ |
17 | | */ |
18 | | |
19 | | #include "php.h" |
20 | | #include "dl.h" |
21 | | #include "php_globals.h" |
22 | | #include "php_ini.h" |
23 | | #include "ext/standard/info.h" |
24 | | |
25 | | #include "SAPI.h" |
26 | | |
27 | | #if defined(HAVE_LIBDL) |
28 | | #include <stdlib.h> |
29 | | #include <stdio.h> |
30 | | #include <string.h> |
31 | | #ifdef PHP_WIN32 |
32 | | #include "win32/param.h" |
33 | | #include "win32/winutil.h" |
34 | | #define GET_DL_ERROR() php_win_err() |
35 | | #else |
36 | | #include <sys/param.h> |
37 | 0 | #define GET_DL_ERROR() DL_ERROR() |
38 | | #endif |
39 | | #endif /* defined(HAVE_LIBDL) */ |
40 | | |
41 | | /* {{{ Load a PHP extension at runtime */ |
42 | | PHPAPI PHP_FUNCTION(dl) |
43 | 0 | { |
44 | 0 | char *filename; |
45 | 0 | size_t filename_len; |
46 | |
|
47 | 0 | ZEND_PARSE_PARAMETERS_START(1, 1) |
48 | 0 | Z_PARAM_STRING(filename, filename_len) |
49 | 0 | ZEND_PARSE_PARAMETERS_END(); |
50 | |
|
51 | 0 | if (!PG(enable_dl)) { |
52 | 0 | php_error_docref(NULL, E_WARNING, "Dynamically loaded extensions aren't enabled"); |
53 | 0 | RETURN_FALSE; |
54 | 0 | } |
55 | |
|
56 | 0 | if (filename_len >= MAXPATHLEN) { |
57 | 0 | php_error_docref(NULL, E_WARNING, "File name exceeds the maximum allowed length of %d characters", MAXPATHLEN); |
58 | 0 | RETURN_FALSE; |
59 | 0 | } |
60 | |
|
61 | 0 | php_dl(filename, MODULE_TEMPORARY, return_value, 0); |
62 | 0 | if (Z_TYPE_P(return_value) == IS_TRUE) { |
63 | 0 | EG(full_tables_cleanup) = 1; |
64 | 0 | } |
65 | 0 | } |
66 | | /* }}} */ |
67 | | |
68 | | #if defined(HAVE_LIBDL) |
69 | | |
70 | | /* {{{ php_load_shlib */ |
71 | | PHPAPI void *php_load_shlib(const char *path, char **errp) |
72 | 0 | { |
73 | 0 | void *handle; |
74 | 0 | char *err; |
75 | |
|
76 | 0 | handle = DL_LOAD(path); |
77 | 0 | if (!handle) { |
78 | 0 | err = GET_DL_ERROR(); |
79 | | #ifdef PHP_WIN32 |
80 | | if (err && (*err)) { |
81 | | size_t i = strlen(err); |
82 | | (*errp)=estrdup(err); |
83 | | php_win32_error_msg_free(err); |
84 | | while (i > 0 && isspace((*errp)[i-1])) { (*errp)[i-1] = '\0'; i--; } |
85 | | } else { |
86 | | (*errp) = estrdup("<No message>"); |
87 | | } |
88 | | #else |
89 | 0 | (*errp) = estrdup(err); |
90 | 0 | GET_DL_ERROR(); /* free the buffer storing the error */ |
91 | 0 | #endif |
92 | 0 | } |
93 | 0 | return handle; |
94 | 0 | } |
95 | | /* }}} */ |
96 | | |
97 | | /* {{{ php_load_extension */ |
98 | | PHPAPI int php_load_extension(const char *filename, int type, int start_now) |
99 | 0 | { |
100 | 0 | void *handle; |
101 | 0 | char *libpath; |
102 | 0 | zend_module_entry *module_entry; |
103 | 0 | zend_module_entry *(*get_module)(void); |
104 | 0 | int error_type, slash_suffix = 0; |
105 | 0 | char *extension_dir; |
106 | 0 | char *err1, *err2; |
107 | |
|
108 | 0 | if (type == MODULE_PERSISTENT) { |
109 | 0 | extension_dir = INI_STR("extension_dir"); |
110 | 0 | } else { |
111 | 0 | extension_dir = PG(extension_dir); |
112 | 0 | } |
113 | |
|
114 | 0 | if (type == MODULE_TEMPORARY) { |
115 | 0 | error_type = E_WARNING; |
116 | 0 | } else { |
117 | 0 | error_type = E_CORE_WARNING; |
118 | 0 | } |
119 | | |
120 | | /* Check if passed filename contains directory separators */ |
121 | 0 | if (strchr(filename, '/') != NULL || strchr(filename, DEFAULT_SLASH) != NULL) { |
122 | | /* Passing modules with full path is not supported for dynamically loaded extensions */ |
123 | 0 | if (type == MODULE_TEMPORARY) { |
124 | 0 | php_error_docref(NULL, E_WARNING, "Temporary module name should contain only filename"); |
125 | 0 | return FAILURE; |
126 | 0 | } |
127 | 0 | libpath = estrdup(filename); |
128 | 0 | } else if (extension_dir && extension_dir[0]) { |
129 | 0 | slash_suffix = IS_SLASH(extension_dir[strlen(extension_dir)-1]); |
130 | | /* Try as filename first */ |
131 | 0 | if (slash_suffix) { |
132 | 0 | spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */ |
133 | 0 | } else { |
134 | 0 | spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename); /* SAFE */ |
135 | 0 | } |
136 | 0 | } else { |
137 | 0 | return FAILURE; /* Not full path given or extension_dir is not set */ |
138 | 0 | } |
139 | | |
140 | 0 | handle = php_load_shlib(libpath, &err1); |
141 | 0 | if (!handle) { |
142 | | /* Now, consider 'filename' as extension name and build file name */ |
143 | 0 | char *orig_libpath = libpath; |
144 | |
|
145 | 0 | if (slash_suffix) { |
146 | 0 | spprintf(&libpath, 0, "%s" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, filename); /* SAFE */ |
147 | 0 | } else { |
148 | 0 | spprintf(&libpath, 0, "%s%c" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, DEFAULT_SLASH, filename); /* SAFE */ |
149 | 0 | } |
150 | |
|
151 | 0 | handle = php_load_shlib(libpath, &err2); |
152 | 0 | if (!handle) { |
153 | 0 | php_error_docref(NULL, error_type, "Unable to load dynamic library '%s' (tried: %s (%s), %s (%s))", |
154 | 0 | filename, orig_libpath, err1, libpath, err2); |
155 | 0 | efree(orig_libpath); |
156 | 0 | efree(err1); |
157 | 0 | efree(libpath); |
158 | 0 | efree(err2); |
159 | 0 | return FAILURE; |
160 | 0 | } |
161 | 0 | efree(orig_libpath); |
162 | 0 | efree(err1); |
163 | 0 | } |
164 | |
|
165 | | #ifdef PHP_WIN32 |
166 | | if (!php_win32_image_compatible(libpath, &err1)) { |
167 | | php_error_docref(NULL, error_type, err1); |
168 | | efree(err1); |
169 | | efree(libpath); |
170 | | DL_UNLOAD(handle); |
171 | | return FAILURE; |
172 | | } |
173 | | #endif |
174 | |
|
175 | 0 | efree(libpath); |
176 | |
|
177 | 0 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); |
178 | | |
179 | | /* Some OS prepend _ to symbol names while their dynamic linker |
180 | | * does not do that automatically. Thus we check manually for |
181 | | * _get_module. */ |
182 | |
|
183 | 0 | if (!get_module) { |
184 | 0 | get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module"); |
185 | 0 | } |
186 | |
|
187 | 0 | if (!get_module) { |
188 | 0 | if (DL_FETCH_SYMBOL(handle, "zend_extension_entry") || DL_FETCH_SYMBOL(handle, "_zend_extension_entry")) { |
189 | 0 | DL_UNLOAD(handle); |
190 | 0 | php_error_docref(NULL, error_type, "Invalid library (appears to be a Zend Extension, try loading using zend_extension=%s from php.ini)", filename); |
191 | 0 | return FAILURE; |
192 | 0 | } |
193 | 0 | DL_UNLOAD(handle); |
194 | 0 | php_error_docref(NULL, error_type, "Invalid library (maybe not a PHP library) '%s'", filename); |
195 | 0 | return FAILURE; |
196 | 0 | } |
197 | 0 | module_entry = get_module(); |
198 | 0 | if (module_entry->zend_api != ZEND_MODULE_API_NO) { |
199 | 0 | php_error_docref(NULL, error_type, |
200 | 0 | "%s: Unable to initialize module\n" |
201 | 0 | "Module compiled with module API=%d\n" |
202 | 0 | "PHP compiled with module API=%d\n" |
203 | 0 | "These options need to match\n", |
204 | 0 | module_entry->name, module_entry->zend_api, ZEND_MODULE_API_NO); |
205 | 0 | DL_UNLOAD(handle); |
206 | 0 | return FAILURE; |
207 | 0 | } |
208 | 0 | if(strcmp(module_entry->build_id, ZEND_MODULE_BUILD_ID)) { |
209 | 0 | php_error_docref(NULL, error_type, |
210 | 0 | "%s: Unable to initialize module\n" |
211 | 0 | "Module compiled with build ID=%s\n" |
212 | 0 | "PHP compiled with build ID=%s\n" |
213 | 0 | "These options need to match\n", |
214 | 0 | module_entry->name, module_entry->build_id, ZEND_MODULE_BUILD_ID); |
215 | 0 | DL_UNLOAD(handle); |
216 | 0 | return FAILURE; |
217 | 0 | } |
218 | 0 | module_entry->type = type; |
219 | 0 | module_entry->module_number = zend_next_free_module(); |
220 | 0 | module_entry->handle = handle; |
221 | |
|
222 | 0 | if ((module_entry = zend_register_module_ex(module_entry)) == NULL) { |
223 | 0 | DL_UNLOAD(handle); |
224 | 0 | return FAILURE; |
225 | 0 | } |
226 | | |
227 | 0 | if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry) == FAILURE) { |
228 | 0 | DL_UNLOAD(handle); |
229 | 0 | return FAILURE; |
230 | 0 | } |
231 | | |
232 | 0 | if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) { |
233 | 0 | if (module_entry->request_startup_func(type, module_entry->module_number) == FAILURE) { |
234 | 0 | php_error_docref(NULL, error_type, "Unable to initialize module '%s'", module_entry->name); |
235 | 0 | DL_UNLOAD(handle); |
236 | 0 | return FAILURE; |
237 | 0 | } |
238 | 0 | } |
239 | 0 | return SUCCESS; |
240 | 0 | } |
241 | | /* }}} */ |
242 | | |
243 | | #else |
244 | | |
245 | | static void php_dl_error(const char *filename) |
246 | | { |
247 | | php_error_docref(NULL, E_WARNING, "Cannot dynamically load %s - dynamic modules are not supported", filename); |
248 | | } |
249 | | |
250 | | PHPAPI void *php_load_shlib(const char *path, char **errp) |
251 | | { |
252 | | php_dl_error(filename); |
253 | | (*errp) = estrdup("No DL support"); |
254 | | } |
255 | | |
256 | | PHPAPI int php_load_extension(const char *filename, int type, int start_now) |
257 | | { |
258 | | php_dl_error(filename); |
259 | | |
260 | | return FAILURE; |
261 | | } |
262 | | |
263 | | #endif |
264 | | |
265 | | /* {{{ php_dl */ |
266 | | PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_now) |
267 | 0 | { |
268 | | /* Load extension */ |
269 | 0 | if (php_load_extension(file, type, start_now) == FAILURE) { |
270 | 0 | RETVAL_FALSE; |
271 | 0 | } else { |
272 | 0 | RETVAL_TRUE; |
273 | 0 | } |
274 | 0 | } |
275 | | /* }}} */ |
276 | | |
277 | | PHP_MINFO_FUNCTION(dl) |
278 | 20 | { |
279 | 20 | #if defined(HAVE_LIBDL) |
280 | 20 | #define PHP_DL_SUPPORT_STATUS "enabled" |
281 | | #else |
282 | | #define PHP_DL_SUPPORT_STATUS "unavailable" |
283 | | #endif |
284 | 20 | php_info_print_table_row(2, "Dynamic Library Support", PHP_DL_SUPPORT_STATUS); |
285 | 20 | } |