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