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