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 #define GET_DL_ERROR() DL_ERROR()
38 #endif
39 #endif /* defined(HAVE_LIBDL) */
40
41 /* {{{ Load a PHP extension at runtime */
PHP_FUNCTION(dl)42 PHPAPI PHP_FUNCTION(dl)
43 {
44 char *filename;
45 size_t filename_len;
46
47 ZEND_PARSE_PARAMETERS_START(1, 1)
48 Z_PARAM_STRING(filename, filename_len)
49 ZEND_PARSE_PARAMETERS_END();
50
51 if (!PG(enable_dl)) {
52 php_error_docref(NULL, E_WARNING, "Dynamically loaded extensions aren't enabled");
53 RETURN_FALSE;
54 }
55
56 if (filename_len >= MAXPATHLEN) {
57 php_error_docref(NULL, E_WARNING, "Filename exceeds the maximum allowed length of %d characters", MAXPATHLEN);
58 RETURN_FALSE;
59 }
60
61 php_dl(filename, MODULE_TEMPORARY, return_value, 0);
62 if (Z_TYPE_P(return_value) == IS_TRUE) {
63 EG(full_tables_cleanup) = 1;
64 }
65 }
66 /* }}} */
67
68 #if defined(HAVE_LIBDL)
69
70 /* {{{ php_load_shlib */
php_load_shlib(const char * path,char ** errp)71 PHPAPI void *php_load_shlib(const char *path, char **errp)
72 {
73 void *handle;
74 char *err;
75
76 handle = DL_LOAD(path);
77 if (!handle) {
78 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 (*errp) = estrdup(err);
90 GET_DL_ERROR(); /* free the buffer storing the error */
91 #endif
92 }
93 return handle;
94 }
95 /* }}} */
96
97 /* {{{ php_load_extension */
php_load_extension(const char * filename,int type,int start_now)98 PHPAPI int php_load_extension(const char *filename, int type, int start_now)
99 {
100 void *handle;
101 char *libpath;
102 zend_module_entry *module_entry;
103 zend_module_entry *(*get_module)(void);
104 int error_type, slash_suffix = 0;
105 char *extension_dir;
106 char *err1, *err2;
107
108 if (type == MODULE_PERSISTENT) {
109 extension_dir = INI_STR("extension_dir");
110 } else {
111 extension_dir = PG(extension_dir);
112 }
113
114 if (type == MODULE_TEMPORARY) {
115 error_type = E_WARNING;
116 } else {
117 error_type = E_CORE_WARNING;
118 }
119
120 /* Check if passed filename contains directory separators */
121 if (strchr(filename, '/') != NULL || strchr(filename, DEFAULT_SLASH) != NULL) {
122 /* Passing modules with full path is not supported for dynamically loaded extensions */
123 if (type == MODULE_TEMPORARY) {
124 php_error_docref(NULL, E_WARNING, "Temporary module name should contain only filename");
125 return FAILURE;
126 }
127 libpath = estrdup(filename);
128 } else if (extension_dir && extension_dir[0]) {
129 slash_suffix = IS_SLASH(extension_dir[strlen(extension_dir)-1]);
130 /* Try as filename first */
131 if (slash_suffix) {
132 spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */
133 } else {
134 spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename); /* SAFE */
135 }
136 } else {
137 return FAILURE; /* Not full path given or extension_dir is not set */
138 }
139
140 handle = php_load_shlib(libpath, &err1);
141 if (!handle) {
142 /* Now, consider 'filename' as extension name and build file name */
143 char *orig_libpath = libpath;
144
145 if (slash_suffix) {
146 spprintf(&libpath, 0, "%s" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, filename); /* SAFE */
147 } else {
148 spprintf(&libpath, 0, "%s%c" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, DEFAULT_SLASH, filename); /* SAFE */
149 }
150
151 handle = php_load_shlib(libpath, &err2);
152 if (!handle) {
153 php_error_docref(NULL, error_type, "Unable to load dynamic library '%s' (tried: %s (%s), %s (%s))",
154 filename, orig_libpath, err1, libpath, err2);
155 efree(orig_libpath);
156 efree(err1);
157 efree(libpath);
158 efree(err2);
159 return FAILURE;
160 }
161 efree(orig_libpath);
162 efree(err1);
163 }
164 efree(libpath);
165
166 #ifdef PHP_WIN32
167 if (!php_win32_image_compatible(handle, &err1)) {
168 php_error_docref(NULL, error_type, err1);
169 efree(err1);
170 DL_UNLOAD(handle);
171 return FAILURE;
172 }
173 #endif
174
175 get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
176
177 /* Some OS prepend _ to symbol names while their dynamic linker
178 * does not do that automatically. Thus we check manually for
179 * _get_module. */
180
181 if (!get_module) {
182 get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module");
183 }
184
185 if (!get_module) {
186 if (DL_FETCH_SYMBOL(handle, "zend_extension_entry") || DL_FETCH_SYMBOL(handle, "_zend_extension_entry")) {
187 DL_UNLOAD(handle);
188 php_error_docref(NULL, error_type, "Invalid library (appears to be a Zend Extension, try loading using zend_extension=%s from php.ini)", filename);
189 return FAILURE;
190 }
191 DL_UNLOAD(handle);
192 php_error_docref(NULL, error_type, "Invalid library (maybe not a PHP library) '%s'", filename);
193 return FAILURE;
194 }
195 module_entry = get_module();
196 if (module_entry->zend_api != ZEND_MODULE_API_NO) {
197 php_error_docref(NULL, error_type,
198 "%s: Unable to initialize module\n"
199 "Module compiled with module API=%d\n"
200 "PHP compiled with module API=%d\n"
201 "These options need to match\n",
202 module_entry->name, module_entry->zend_api, ZEND_MODULE_API_NO);
203 DL_UNLOAD(handle);
204 return FAILURE;
205 }
206 if(strcmp(module_entry->build_id, ZEND_MODULE_BUILD_ID)) {
207 php_error_docref(NULL, error_type,
208 "%s: Unable to initialize module\n"
209 "Module compiled with build ID=%s\n"
210 "PHP compiled with build ID=%s\n"
211 "These options need to match\n",
212 module_entry->name, module_entry->build_id, ZEND_MODULE_BUILD_ID);
213 DL_UNLOAD(handle);
214 return FAILURE;
215 }
216 module_entry->type = type;
217 module_entry->module_number = zend_next_free_module();
218 module_entry->handle = handle;
219
220 if ((module_entry = zend_register_module_ex(module_entry)) == NULL) {
221 DL_UNLOAD(handle);
222 return FAILURE;
223 }
224
225 if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry) == FAILURE) {
226 DL_UNLOAD(handle);
227 return FAILURE;
228 }
229
230 if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) {
231 if (module_entry->request_startup_func(type, module_entry->module_number) == FAILURE) {
232 php_error_docref(NULL, error_type, "Unable to initialize module '%s'", module_entry->name);
233 DL_UNLOAD(handle);
234 return FAILURE;
235 }
236 }
237 return SUCCESS;
238 }
239 /* }}} */
240
241 #else
242
php_dl_error(const char * filename)243 static void php_dl_error(const char *filename)
244 {
245 php_error_docref(NULL, E_WARNING, "Cannot dynamically load %s - dynamic modules are not supported", filename);
246 }
247
php_load_shlib(const char * path,char ** errp)248 PHPAPI void *php_load_shlib(const char *path, char **errp)
249 {
250 php_dl_error(path);
251 (*errp) = estrdup("No DL support");
252 return NULL;
253 }
254
php_load_extension(const char * filename,int type,int start_now)255 PHPAPI int php_load_extension(const char *filename, int type, int start_now)
256 {
257 php_dl_error(filename);
258
259 return FAILURE;
260 }
261
262 #endif
263
264 /* {{{ php_dl */
php_dl(const char * file,int type,zval * return_value,int start_now)265 PHPAPI void php_dl(const char *file, int type, zval *return_value, int start_now)
266 {
267 /* Load extension */
268 if (php_load_extension(file, type, start_now) == FAILURE) {
269 RETVAL_FALSE;
270 } else {
271 RETVAL_TRUE;
272 }
273 }
274 /* }}} */
275
PHP_MINFO_FUNCTION(dl)276 PHP_MINFO_FUNCTION(dl)
277 {
278 #if defined(HAVE_LIBDL)
279 #define PHP_DL_SUPPORT_STATUS "enabled"
280 #else
281 #define PHP_DL_SUPPORT_STATUS "unavailable"
282 #endif
283 php_info_print_table_row(2, "Dynamic Library Support", PHP_DL_SUPPORT_STATUS);
284 }
285