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 | https://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 | Author: Zeev Suraski <zeev@php.net> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "php.h"
18 #include "ext/standard/info.h"
19 #include "zend_ini.h"
20 #include "zend_ini_scanner.h"
21 #include "php_ini.h"
22 #include "ext/standard/dl.h"
23 #include "zend_extensions.h"
24 #include "zend_highlight.h"
25 #include "SAPI.h"
26 #include "php_main.h"
27 #include "php_scandir.h"
28 #ifdef PHP_WIN32
29 #include "win32/php_registry.h"
30 #include "win32/winutil.h"
31 #endif
32
33 #if HAVE_SCANDIR && HAVE_ALPHASORT && HAVE_DIRENT_H
34 #include <dirent.h>
35 #endif
36
37 #ifdef PHP_WIN32
38 #define TRANSLATE_SLASHES_LOWER(path) \
39 { \
40 char *tmp = path; \
41 while (*tmp) { \
42 if (*tmp == '\\') *tmp = '/'; \
43 else *tmp = tolower(*tmp); \
44 tmp++; \
45 } \
46 }
47 #else
48 #define TRANSLATE_SLASHES_LOWER(path)
49 #endif
50
51
52 typedef struct _php_extension_lists {
53 zend_llist engine;
54 zend_llist functions;
55 } php_extension_lists;
56
57 /* True globals */
58 static int is_special_section = 0;
59 static HashTable *active_ini_hash;
60 static HashTable configuration_hash;
61 static int has_per_dir_config = 0;
62 static int has_per_host_config = 0;
63 PHPAPI char *php_ini_opened_path=NULL;
64 static php_extension_lists extension_lists;
65 PHPAPI char *php_ini_scanned_path=NULL;
66 PHPAPI char *php_ini_scanned_files=NULL;
67
68 /* {{{ php_ini_displayer_cb */
php_ini_displayer_cb(zend_ini_entry * ini_entry,int type)69 static ZEND_COLD void php_ini_displayer_cb(zend_ini_entry *ini_entry, int type)
70 {
71 if (ini_entry->displayer) {
72 ini_entry->displayer(ini_entry, type);
73 } else {
74 char *display_string;
75 size_t display_string_length;
76 int esc_html=0;
77
78 if (type == ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
79 if (ini_entry->orig_value && ZSTR_VAL(ini_entry->orig_value)[0]) {
80 display_string = ZSTR_VAL(ini_entry->orig_value);
81 display_string_length = ZSTR_LEN(ini_entry->orig_value);
82 esc_html = !sapi_module.phpinfo_as_text;
83 } else {
84 if (!sapi_module.phpinfo_as_text) {
85 display_string = "<i>no value</i>";
86 display_string_length = sizeof("<i>no value</i>") - 1;
87 } else {
88 display_string = "no value";
89 display_string_length = sizeof("no value") - 1;
90 }
91 }
92 } else if (ini_entry->value && ZSTR_VAL(ini_entry->value)[0]) {
93 display_string = ZSTR_VAL(ini_entry->value);
94 display_string_length = ZSTR_LEN(ini_entry->value);
95 esc_html = !sapi_module.phpinfo_as_text;
96 } else {
97 if (!sapi_module.phpinfo_as_text) {
98 display_string = "<i>no value</i>";
99 display_string_length = sizeof("<i>no value</i>") - 1;
100 } else {
101 display_string = "no value";
102 display_string_length = sizeof("no value") - 1;
103 }
104 }
105
106 if (esc_html) {
107 php_html_puts(display_string, display_string_length);
108 } else {
109 PHPWRITE(display_string, display_string_length);
110 }
111 }
112 }
113 /* }}} */
114
115 /* {{{ display_ini_entries */
display_ini_entries(zend_module_entry * module)116 PHPAPI ZEND_COLD void display_ini_entries(zend_module_entry *module)
117 {
118 int module_number;
119 zend_ini_entry *ini_entry;
120 bool first = 1;
121
122 if (module) {
123 module_number = module->module_number;
124 } else {
125 module_number = 0;
126 }
127
128 ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), ini_entry) {
129 if (ini_entry->module_number != module_number) {
130 continue;
131 }
132 if (first) {
133 php_info_print_table_start();
134 php_info_print_table_header(3, "Directive", "Local Value", "Master Value");
135 first = 0;
136 }
137 if (!sapi_module.phpinfo_as_text) {
138 PUTS("<tr>");
139 PUTS("<td class=\"e\">");
140 PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
141 PUTS("</td><td class=\"v\">");
142 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
143 PUTS("</td><td class=\"v\">");
144 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
145 PUTS("</td></tr>\n");
146 } else {
147 PHPWRITE(ZSTR_VAL(ini_entry->name), ZSTR_LEN(ini_entry->name));
148 PUTS(" => ");
149 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ACTIVE);
150 PUTS(" => ");
151 php_ini_displayer_cb(ini_entry, ZEND_INI_DISPLAY_ORIG);
152 PUTS("\n");
153 }
154 } ZEND_HASH_FOREACH_END();
155 if (!first) {
156 php_info_print_table_end();
157 }
158 }
159 /* }}} */
160
161 /* php.ini support */
162 #define PHP_EXTENSION_TOKEN "extension"
163 #define ZEND_EXTENSION_TOKEN "zend_extension"
164
165 /* {{{ config_zval_dtor */
config_zval_dtor(zval * zvalue)166 PHPAPI void config_zval_dtor(zval *zvalue)
167 {
168 if (Z_TYPE_P(zvalue) == IS_ARRAY) {
169 zend_hash_destroy(Z_ARRVAL_P(zvalue));
170 free(Z_ARR_P(zvalue));
171 } else if (Z_TYPE_P(zvalue) == IS_STRING) {
172 zend_string_release_ex(Z_STR_P(zvalue), 1);
173 }
174 }
175 /* Reset / free active_ini_sectin global */
176 #define RESET_ACTIVE_INI_HASH() do { \
177 active_ini_hash = NULL; \
178 is_special_section = 0; \
179 } while (0)
180 /* }}} */
181
182 /* {{{ php_ini_parser_cb */
php_ini_parser_cb(zval * arg1,zval * arg2,zval * arg3,int callback_type,HashTable * target_hash)183 static void php_ini_parser_cb(zval *arg1, zval *arg2, zval *arg3, int callback_type, HashTable *target_hash)
184 {
185 zval *entry;
186 HashTable *active_hash;
187 char *extension_name;
188
189 if (active_ini_hash) {
190 active_hash = active_ini_hash;
191 } else {
192 active_hash = target_hash;
193 }
194
195 switch (callback_type) {
196 case ZEND_INI_PARSER_ENTRY: {
197 if (!arg2) {
198 /* bare string - nothing to do */
199 break;
200 }
201
202 /* PHP and Zend extensions are not added into configuration hash! */
203 if (!is_special_section && zend_string_equals_literal_ci(Z_STR_P(arg1), PHP_EXTENSION_TOKEN)) { /* load PHP extension */
204 extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
205 zend_llist_add_element(&extension_lists.functions, &extension_name);
206 } else if (!is_special_section && zend_string_equals_literal_ci(Z_STR_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */
207 extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
208 zend_llist_add_element(&extension_lists.engine, &extension_name);
209
210 /* All other entries are added into either configuration_hash or active ini section array */
211 } else {
212 /* Store in active hash */
213 entry = zend_hash_update(active_hash, Z_STR_P(arg1), arg2);
214 Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
215 }
216 }
217 break;
218
219 case ZEND_INI_PARSER_POP_ENTRY: {
220 zval option_arr;
221 zval *find_arr;
222
223 if (!arg2) {
224 /* bare string - nothing to do */
225 break;
226 }
227
228 /* fprintf(stdout, "ZEND_INI_PARSER_POP_ENTRY: %s[%s] = %s\n",Z_STRVAL_P(arg1), Z_STRVAL_P(arg3), Z_STRVAL_P(arg2)); */
229
230 /* If option not found in hash or is not an array -> create array, otherwise add to existing array */
231 if ((find_arr = zend_hash_find(active_hash, Z_STR_P(arg1))) == NULL || Z_TYPE_P(find_arr) != IS_ARRAY) {
232 ZVAL_NEW_PERSISTENT_ARR(&option_arr);
233 zend_hash_init(Z_ARRVAL(option_arr), 8, NULL, config_zval_dtor, 1);
234 find_arr = zend_hash_update(active_hash, Z_STR_P(arg1), &option_arr);
235 }
236
237 /* arg3 is possible option offset name */
238 if (arg3 && Z_STRLEN_P(arg3) > 0) {
239 entry = zend_symtable_update(Z_ARRVAL_P(find_arr), Z_STR_P(arg3), arg2);
240 } else {
241 entry = zend_hash_next_index_insert(Z_ARRVAL_P(find_arr), arg2);
242 }
243 Z_STR_P(entry) = zend_string_dup(Z_STR_P(entry), 1);
244 }
245 break;
246
247 case ZEND_INI_PARSER_SECTION: { /* Create an array of entries of each section */
248
249 /* fprintf(stdout, "ZEND_INI_PARSER_SECTION: %s\n",Z_STRVAL_P(arg1)); */
250
251 char *key = NULL;
252 size_t key_len;
253
254 /* PATH sections */
255 if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "PATH", sizeof("PATH") - 1, sizeof("PATH") - 1)) {
256 key = Z_STRVAL_P(arg1);
257 key = key + sizeof("PATH") - 1;
258 key_len = Z_STRLEN_P(arg1) - sizeof("PATH") + 1;
259 is_special_section = 1;
260 has_per_dir_config = 1;
261
262 /* make the path lowercase on Windows, for case insensitivity. Does nothing for other platforms */
263 TRANSLATE_SLASHES_LOWER(key);
264
265 /* HOST sections */
266 } else if (!zend_binary_strncasecmp(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1), "HOST", sizeof("HOST") - 1, sizeof("HOST") - 1)) {
267 key = Z_STRVAL_P(arg1);
268 key = key + sizeof("HOST") - 1;
269 key_len = Z_STRLEN_P(arg1) - sizeof("HOST") + 1;
270 is_special_section = 1;
271 has_per_host_config = 1;
272 zend_str_tolower(key, key_len); /* host names are case-insensitive. */
273
274 } else {
275 is_special_section = 0;
276 }
277
278 if (key && key_len > 0) {
279 /* Strip any trailing slashes */
280 while (key_len > 0 && (key[key_len - 1] == '/' || key[key_len - 1] == '\\')) {
281 key_len--;
282 key[key_len] = 0;
283 }
284
285 /* Strip any leading whitespace and '=' */
286 while (*key && (
287 *key == '=' ||
288 *key == ' ' ||
289 *key == '\t'
290 )) {
291 key++;
292 key_len--;
293 }
294
295 /* Search for existing entry and if it does not exist create one */
296 if ((entry = zend_hash_str_find(target_hash, key, key_len)) == NULL) {
297 zval section_arr;
298
299 ZVAL_NEW_PERSISTENT_ARR(§ion_arr);
300 zend_hash_init(Z_ARRVAL(section_arr), 8, NULL, (dtor_func_t) config_zval_dtor, 1);
301 entry = zend_hash_str_update(target_hash, key, key_len, §ion_arr);
302 }
303 if (Z_TYPE_P(entry) == IS_ARRAY) {
304 active_ini_hash = Z_ARRVAL_P(entry);
305 }
306 }
307 }
308 break;
309 }
310 }
311 /* }}} */
312
313 /* {{{ php_load_php_extension_cb */
php_load_php_extension_cb(void * arg)314 static void php_load_php_extension_cb(void *arg)
315 {
316 #ifdef HAVE_LIBDL
317 php_load_extension(*((char **) arg), MODULE_PERSISTENT, 0);
318 #endif
319 }
320 /* }}} */
321
322 /* {{{ php_load_zend_extension_cb */
323 #ifdef HAVE_LIBDL
php_load_zend_extension_cb(void * arg)324 static void php_load_zend_extension_cb(void *arg)
325 {
326 char *filename = *((char **) arg);
327 const size_t length = strlen(filename);
328
329 #ifndef PHP_WIN32
330 (void) length;
331 #endif
332
333 if (IS_ABSOLUTE_PATH(filename, length)) {
334 zend_load_extension(filename);
335 } else {
336 DL_HANDLE handle;
337 char *libpath;
338 char *extension_dir = INI_STR("extension_dir");
339 int slash_suffix = 0;
340 char *err1, *err2;
341
342 if (extension_dir && extension_dir[0]) {
343 slash_suffix = IS_SLASH(extension_dir[strlen(extension_dir)-1]);
344 }
345
346 /* Try as filename first */
347 if (slash_suffix) {
348 spprintf(&libpath, 0, "%s%s", extension_dir, filename); /* SAFE */
349 } else {
350 spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, filename); /* SAFE */
351 }
352
353 handle = (DL_HANDLE)php_load_shlib(libpath, &err1);
354 if (!handle) {
355 /* If file does not exist, consider as extension name and build file name */
356 char *orig_libpath = libpath;
357
358 if (slash_suffix) {
359 spprintf(&libpath, 0, "%s" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, filename); /* SAFE */
360 } else {
361 spprintf(&libpath, 0, "%s%c" PHP_SHLIB_EXT_PREFIX "%s." PHP_SHLIB_SUFFIX, extension_dir, DEFAULT_SLASH, filename); /* SAFE */
362 }
363
364 handle = (DL_HANDLE)php_load_shlib(libpath, &err2);
365 if (!handle) {
366 php_error(E_CORE_WARNING, "Failed loading Zend extension '%s' (tried: %s (%s), %s (%s))",
367 filename, orig_libpath, err1, libpath, err2);
368 efree(orig_libpath);
369 efree(err1);
370 efree(libpath);
371 efree(err2);
372 return;
373 }
374
375 efree(orig_libpath);
376 efree(err1);
377 }
378
379 #ifdef PHP_WIN32
380 if (!php_win32_image_compatible(handle, &err1)) {
381 php_error(E_CORE_WARNING, err1);
382 efree(err1);
383 efree(libpath);
384 DL_UNLOAD(handle);
385 return;
386 }
387 #endif
388
389 zend_load_extension_handle(handle, libpath);
390 efree(libpath);
391 }
392 }
393 #else
php_load_zend_extension_cb(void * arg)394 static void php_load_zend_extension_cb(void *arg) { }
395 #endif
396 /* }}} */
397
398 /* {{{ php_init_config */
php_init_config(void)399 int php_init_config(void)
400 {
401 char *php_ini_file_name = NULL;
402 char *php_ini_search_path = NULL;
403 int php_ini_scanned_path_len;
404 char *open_basedir;
405 int free_ini_search_path = 0;
406 zend_string *opened_path = NULL;
407
408 zend_hash_init(&configuration_hash, 8, NULL, config_zval_dtor, 1);
409
410 if (sapi_module.ini_defaults) {
411 sapi_module.ini_defaults(&configuration_hash);
412 }
413
414 zend_llist_init(&extension_lists.engine, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
415 zend_llist_init(&extension_lists.functions, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
416
417 open_basedir = PG(open_basedir);
418
419 if (sapi_module.php_ini_path_override) {
420 php_ini_file_name = sapi_module.php_ini_path_override;
421 php_ini_search_path = sapi_module.php_ini_path_override;
422 free_ini_search_path = 0;
423 } else if (!sapi_module.php_ini_ignore) {
424 int search_path_size;
425 char *default_location;
426 char *env_location;
427 static const char paths_separator[] = { ZEND_PATHS_SEPARATOR, 0 };
428 #ifdef PHP_WIN32
429 char *reg_location;
430 char phprc_path[MAXPATHLEN];
431 #endif
432
433 env_location = getenv("PHPRC");
434
435 #ifdef PHP_WIN32
436 if (!env_location) {
437 char dummybuf;
438 int size;
439
440 SetLastError(0);
441
442 /*If the given buffer is not large enough to hold the data, the return value is
443 the buffer size, in characters, required to hold the string and its terminating
444 null character. We use this return value to alloc the final buffer. */
445 size = GetEnvironmentVariableA("PHPRC", &dummybuf, 0);
446 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
447 /* The environment variable doesn't exist. */
448 env_location = "";
449 } else {
450 if (size == 0) {
451 env_location = "";
452 } else {
453 size = GetEnvironmentVariableA("PHPRC", phprc_path, size);
454 if (size == 0) {
455 env_location = "";
456 } else {
457 env_location = phprc_path;
458 }
459 }
460 }
461 }
462 #else
463 if (!env_location) {
464 env_location = "";
465 }
466 #endif
467 /*
468 * Prepare search path
469 */
470
471 search_path_size = MAXPATHLEN * 4 + (int)strlen(env_location) + 3 + 1;
472 php_ini_search_path = (char *) emalloc(search_path_size);
473 free_ini_search_path = 1;
474 php_ini_search_path[0] = 0;
475
476 /* Add environment location */
477 if (env_location[0]) {
478 if (*php_ini_search_path) {
479 strlcat(php_ini_search_path, paths_separator, search_path_size);
480 }
481 strlcat(php_ini_search_path, env_location, search_path_size);
482 php_ini_file_name = env_location;
483 }
484
485 #ifdef PHP_WIN32
486 /* Add registry location */
487 reg_location = GetIniPathFromRegistry();
488 if (reg_location != NULL) {
489 if (*php_ini_search_path) {
490 strlcat(php_ini_search_path, paths_separator, search_path_size);
491 }
492 strlcat(php_ini_search_path, reg_location, search_path_size);
493 efree(reg_location);
494 }
495 #endif
496
497 /* Add cwd (not with CLI) */
498 if (!sapi_module.php_ini_ignore_cwd) {
499 if (*php_ini_search_path) {
500 strlcat(php_ini_search_path, paths_separator, search_path_size);
501 }
502 strlcat(php_ini_search_path, ".", search_path_size);
503 }
504
505 if (PG(php_binary)) {
506 char *separator_location, *binary_location;
507
508 binary_location = estrdup(PG(php_binary));
509 separator_location = strrchr(binary_location, DEFAULT_SLASH);
510
511 if (separator_location && separator_location != binary_location) {
512 *(separator_location) = 0;
513 }
514 if (*php_ini_search_path) {
515 strlcat(php_ini_search_path, paths_separator, search_path_size);
516 }
517 strlcat(php_ini_search_path, binary_location, search_path_size);
518 efree(binary_location);
519 }
520
521 /* Add default location */
522 #ifdef PHP_WIN32
523 default_location = (char *) emalloc(MAXPATHLEN + 1);
524
525 if (0 < GetWindowsDirectory(default_location, MAXPATHLEN)) {
526 if (*php_ini_search_path) {
527 strlcat(php_ini_search_path, paths_separator, search_path_size);
528 }
529 strlcat(php_ini_search_path, default_location, search_path_size);
530 }
531
532 /* For people running under terminal services, GetWindowsDirectory will
533 * return their personal Windows directory, so lets add the system
534 * windows directory too */
535 if (0 < GetSystemWindowsDirectory(default_location, MAXPATHLEN)) {
536 if (*php_ini_search_path) {
537 strlcat(php_ini_search_path, paths_separator, search_path_size);
538 }
539 strlcat(php_ini_search_path, default_location, search_path_size);
540 }
541 efree(default_location);
542
543 #else
544 default_location = PHP_CONFIG_FILE_PATH;
545 if (*php_ini_search_path) {
546 strlcat(php_ini_search_path, paths_separator, search_path_size);
547 }
548 strlcat(php_ini_search_path, default_location, search_path_size);
549 #endif
550 }
551
552 PG(open_basedir) = NULL;
553
554 /*
555 * Find and open actual ini file
556 */
557
558 FILE *fp = NULL;
559 char *filename = NULL;
560 bool free_filename = false;
561
562 /* If SAPI does not want to ignore all ini files OR an overriding file/path is given.
563 * This allows disabling scanning for ini files in the PHP_CONFIG_FILE_SCAN_DIR but still
564 * load an optional ini file. */
565 if (!sapi_module.php_ini_ignore || sapi_module.php_ini_path_override) {
566
567 /* Check if php_ini_file_name is a file and can be opened */
568 if (php_ini_file_name && php_ini_file_name[0]) {
569 zend_stat_t statbuf = {0};
570
571 if (!VCWD_STAT(php_ini_file_name, &statbuf)) {
572 if (!((statbuf.st_mode & S_IFMT) == S_IFDIR)) {
573 fp = VCWD_FOPEN(php_ini_file_name, "r");
574 if (fp) {
575 filename = expand_filepath(php_ini_file_name, NULL);
576 free_filename = true;
577 }
578 }
579 }
580 }
581
582 /* Otherwise search for php-%sapi-module-name%.ini file in search path */
583 if (!fp) {
584 const char *fmt = "php-%s.ini";
585 char *ini_fname;
586 spprintf(&ini_fname, 0, fmt, sapi_module.name);
587 fp = php_fopen_with_path(ini_fname, "r", php_ini_search_path, &opened_path);
588 efree(ini_fname);
589 if (fp) {
590 filename = ZSTR_VAL(opened_path);
591 }
592 }
593
594 /* If still no ini file found, search for php.ini file in search path */
595 if (!fp) {
596 fp = php_fopen_with_path("php.ini", "r", php_ini_search_path, &opened_path);
597 if (fp) {
598 filename = ZSTR_VAL(opened_path);
599 }
600 }
601 }
602
603 if (free_ini_search_path) {
604 efree(php_ini_search_path);
605 }
606
607 PG(open_basedir) = open_basedir;
608
609 if (fp) {
610 zend_file_handle fh;
611 zend_stream_init_fp(&fh, fp, filename);
612 RESET_ACTIVE_INI_HASH();
613
614 zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
615
616 {
617 zval tmp;
618
619 ZVAL_NEW_STR(&tmp, zend_string_init(filename, strlen(filename), 1));
620 zend_hash_str_update(&configuration_hash, "cfg_file_path", sizeof("cfg_file_path")-1, &tmp);
621 if (opened_path) {
622 zend_string_release_ex(opened_path, 0);
623 }
624 php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
625 }
626 zend_destroy_file_handle(&fh);
627
628 if (free_filename) {
629 efree(filename);
630 }
631 }
632
633 /* Check for PHP_INI_SCAN_DIR environment variable to override/set config file scan directory */
634 php_ini_scanned_path = getenv("PHP_INI_SCAN_DIR");
635 if (!php_ini_scanned_path) {
636 /* Or fall back using possible --with-config-file-scan-dir setting (defaults to empty string!) */
637 php_ini_scanned_path = PHP_CONFIG_FILE_SCAN_DIR;
638 }
639 php_ini_scanned_path_len = (int)strlen(php_ini_scanned_path);
640
641 /* Scan and parse any .ini files found in scan path if path not empty. */
642 if (!sapi_module.php_ini_ignore && php_ini_scanned_path_len) {
643 struct dirent **namelist;
644 int ndir, i;
645 zend_stat_t sb = {0};
646 char ini_file[MAXPATHLEN];
647 char *p;
648 zend_llist scanned_ini_list;
649 zend_llist_element *element;
650 int l, total_l = 0;
651 char *bufpath, *debpath, *endpath;
652 int lenpath;
653
654 zend_llist_init(&scanned_ini_list, sizeof(char *), (llist_dtor_func_t) free_estring, 1);
655
656 bufpath = estrdup(php_ini_scanned_path);
657 for (debpath = bufpath ; debpath ; debpath=endpath) {
658 endpath = strchr(debpath, DEFAULT_DIR_SEPARATOR);
659 if (endpath) {
660 *(endpath++) = 0;
661 }
662 if (!debpath[0]) {
663 /* empty string means default builtin value
664 to allow "/foo/php.d:" or ":/foo/php.d" */
665 debpath = PHP_CONFIG_FILE_SCAN_DIR;
666 }
667 lenpath = (int)strlen(debpath);
668
669 if (lenpath > 0 && (ndir = php_scandir(debpath, &namelist, 0, php_alphasort)) > 0) {
670
671 for (i = 0; i < ndir; i++) {
672
673 /* check for any file with .ini extension */
674 if (!(p = strrchr(namelist[i]->d_name, '.')) || (p && strcmp(p, ".ini"))) {
675 free(namelist[i]);
676 continue;
677 }
678 /* Reset active ini section */
679 RESET_ACTIVE_INI_HASH();
680
681 if (IS_SLASH(debpath[lenpath - 1])) {
682 snprintf(ini_file, MAXPATHLEN, "%s%s", debpath, namelist[i]->d_name);
683 } else {
684 snprintf(ini_file, MAXPATHLEN, "%s%c%s", debpath, DEFAULT_SLASH, namelist[i]->d_name);
685 }
686 if (VCWD_STAT(ini_file, &sb) == 0) {
687 if (S_ISREG(sb.st_mode)) {
688 zend_file_handle fh;
689 FILE *file = VCWD_FOPEN(ini_file, "r");
690 if (file) {
691 zend_stream_init_fp(&fh, file, ini_file);
692 if (zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash) == SUCCESS) {
693 /* Here, add it to the list of ini files read */
694 l = (int)strlen(ini_file);
695 total_l += l + 2;
696 p = estrndup(ini_file, l);
697 zend_llist_add_element(&scanned_ini_list, &p);
698 }
699 zend_destroy_file_handle(&fh);
700 }
701 }
702 }
703 free(namelist[i]);
704 }
705 free(namelist);
706 }
707 }
708 efree(bufpath);
709
710 if (total_l) {
711 int php_ini_scanned_files_len = (php_ini_scanned_files) ? (int)strlen(php_ini_scanned_files) + 1 : 0;
712 php_ini_scanned_files = (char *) realloc(php_ini_scanned_files, php_ini_scanned_files_len + total_l + 1);
713 if (!php_ini_scanned_files_len) {
714 *php_ini_scanned_files = '\0';
715 }
716 total_l += php_ini_scanned_files_len;
717 for (element = scanned_ini_list.head; element; element = element->next) {
718 if (php_ini_scanned_files_len) {
719 strlcat(php_ini_scanned_files, ",\n", total_l);
720 }
721 strlcat(php_ini_scanned_files, *(char **)element->data, total_l);
722 strlcat(php_ini_scanned_files, element->next ? ",\n" : "\n", total_l);
723 }
724 }
725 zend_llist_destroy(&scanned_ini_list);
726 } else {
727 /* Make sure an empty php_ini_scanned_path ends up as NULL */
728 php_ini_scanned_path = NULL;
729 }
730
731 if (sapi_module.ini_entries) {
732 /* Reset active ini section */
733 RESET_ACTIVE_INI_HASH();
734 zend_parse_ini_string(sapi_module.ini_entries, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash);
735 }
736
737 return SUCCESS;
738 }
739 /* }}} */
740
741 /* {{{ php_shutdown_config */
php_shutdown_config(void)742 int php_shutdown_config(void)
743 {
744 zend_hash_destroy(&configuration_hash);
745 if (php_ini_opened_path) {
746 free(php_ini_opened_path);
747 php_ini_opened_path = NULL;
748 }
749 if (php_ini_scanned_files) {
750 free(php_ini_scanned_files);
751 php_ini_scanned_files = NULL;
752 }
753 return SUCCESS;
754 }
755 /* }}} */
756
757 /* {{{ php_ini_register_extensions */
php_ini_register_extensions(void)758 void php_ini_register_extensions(void)
759 {
760 zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb);
761 zend_llist_apply(&extension_lists.functions, php_load_php_extension_cb);
762
763 zend_llist_destroy(&extension_lists.engine);
764 zend_llist_destroy(&extension_lists.functions);
765 }
766 /* }}} */
767
768 /* {{{ php_parse_user_ini_file */
php_parse_user_ini_file(const char * dirname,const char * ini_filename,HashTable * target_hash)769 PHPAPI int php_parse_user_ini_file(const char *dirname, const char *ini_filename, HashTable *target_hash)
770 {
771 zend_stat_t sb = {0};
772 char ini_file[MAXPATHLEN];
773
774 snprintf(ini_file, MAXPATHLEN, "%s%c%s", dirname, DEFAULT_SLASH, ini_filename);
775
776 if (VCWD_STAT(ini_file, &sb) == 0) {
777 if (S_ISREG(sb.st_mode)) {
778 zend_file_handle fh;
779 int ret = FAILURE;
780
781 zend_stream_init_fp(&fh, VCWD_FOPEN(ini_file, "r"), ini_file);
782 if (fh.handle.fp) {
783 /* Reset active ini section */
784 RESET_ACTIVE_INI_HASH();
785
786 #if ZEND_RC_DEBUG
787 /* User inis are parsed during SAPI activate (part of the request),
788 * but persistently allocated to allow caching. This is fine as long as
789 * strings are duplicated in php_ini_activate_config(). */
790 bool orig_rc_debug = zend_rc_debug;
791 zend_rc_debug = false;
792 #endif
793 ret = zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, (zend_ini_parser_cb_t) php_ini_parser_cb, target_hash);
794 #if ZEND_RC_DEBUG
795 zend_rc_debug = orig_rc_debug;
796 #endif
797 if (ret == SUCCESS) {
798 /* FIXME: Add parsed file to the list of user files read? */
799 }
800 }
801 zend_destroy_file_handle(&fh);
802 return ret;
803 }
804 }
805 return FAILURE;
806 }
807 /* }}} */
808
809 /* {{{ php_ini_activate_config */
php_ini_activate_config(HashTable * source_hash,int modify_type,int stage)810 PHPAPI void php_ini_activate_config(HashTable *source_hash, int modify_type, int stage)
811 {
812 zend_string *str;
813 zval *data;
814
815 /* Walk through config hash and alter matching ini entries using the values found in the hash */
816 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(source_hash, str, data) {
817 zend_string *data_str = zend_string_dup(Z_STR_P(data), 0);
818 zend_alter_ini_entry_ex(str, data_str, modify_type, stage, 0);
819 zend_string_release(data_str);
820 } ZEND_HASH_FOREACH_END();
821 }
822 /* }}} */
823
824 /* {{{ php_ini_has_per_dir_config */
php_ini_has_per_dir_config(void)825 PHPAPI int php_ini_has_per_dir_config(void)
826 {
827 return has_per_dir_config;
828 }
829 /* }}} */
830
831 /* {{{ php_ini_activate_per_dir_config */
php_ini_activate_per_dir_config(char * path,size_t path_len)832 PHPAPI void php_ini_activate_per_dir_config(char *path, size_t path_len)
833 {
834 zval *tmp2;
835 char *ptr;
836
837 #ifdef PHP_WIN32
838 char path_bak[MAXPATHLEN];
839 #endif
840
841 #ifdef PHP_WIN32
842 /* MAX_PATH is \0-terminated, path_len == MAXPATHLEN would overrun path_bak */
843 if (path_len >= MAXPATHLEN) {
844 #else
845 if (path_len > MAXPATHLEN) {
846 #endif
847 return;
848 }
849
850 #ifdef PHP_WIN32
851 memcpy(path_bak, path, path_len);
852 path_bak[path_len] = 0;
853 TRANSLATE_SLASHES_LOWER(path_bak);
854 path = path_bak;
855 #endif
856
857 /* Walk through each directory in path and apply any found per-dir-system-configuration from configuration_hash */
858 if (has_per_dir_config && path && path_len) {
859 ptr = path + 1;
860 while ((ptr = strchr(ptr, '/')) != NULL) {
861 *ptr = 0;
862 /* Search for source array matching the path from configuration_hash */
863 if ((tmp2 = zend_hash_str_find(&configuration_hash, path, strlen(path))) != NULL) {
864 php_ini_activate_config(Z_ARRVAL_P(tmp2), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
865 }
866 *ptr = '/';
867 ptr++;
868 }
869 }
870 }
871 /* }}} */
872
873 /* {{{ php_ini_has_per_host_config */
874 PHPAPI int php_ini_has_per_host_config(void)
875 {
876 return has_per_host_config;
877 }
878 /* }}} */
879
880 /* {{{ php_ini_activate_per_host_config */
881 PHPAPI void php_ini_activate_per_host_config(const char *host, size_t host_len)
882 {
883 zval *tmp;
884
885 if (has_per_host_config && host && host_len) {
886 /* Search for source array matching the host from configuration_hash */
887 if ((tmp = zend_hash_str_find(&configuration_hash, host, host_len)) != NULL) {
888 php_ini_activate_config(Z_ARRVAL_P(tmp), PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
889 }
890 }
891 }
892 /* }}} */
893
894 /* {{{ cfg_get_entry */
895 PHPAPI zval *cfg_get_entry_ex(zend_string *name)
896 {
897 return zend_hash_find(&configuration_hash, name);
898 }
899 /* }}} */
900
901 /* {{{ cfg_get_entry */
902 PHPAPI zval *cfg_get_entry(const char *name, size_t name_length)
903 {
904 return zend_hash_str_find(&configuration_hash, name, name_length);
905 }
906 /* }}} */
907
908 /* {{{ cfg_get_long */
909 PHPAPI int cfg_get_long(const char *varname, zend_long *result)
910 {
911 zval *tmp;
912
913 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
914 *result = 0;
915 return FAILURE;
916 }
917 *result = zval_get_long(tmp);
918 return SUCCESS;
919 }
920 /* }}} */
921
922 /* {{{ cfg_get_double */
923 PHPAPI int cfg_get_double(const char *varname, double *result)
924 {
925 zval *tmp;
926
927 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
928 *result = (double) 0;
929 return FAILURE;
930 }
931 *result = zval_get_double(tmp);
932 return SUCCESS;
933 }
934 /* }}} */
935
936 /* {{{ cfg_get_string */
937 PHPAPI int cfg_get_string(const char *varname, char **result)
938 {
939 zval *tmp;
940
941 if ((tmp = zend_hash_str_find(&configuration_hash, varname, strlen(varname))) == NULL) {
942 *result = NULL;
943 return FAILURE;
944 }
945 *result = Z_STRVAL_P(tmp);
946 return SUCCESS;
947 }
948 /* }}} */
949
950 PHPAPI HashTable* php_ini_get_configuration_hash(void) /* {{{ */
951 {
952 return &configuration_hash;
953 } /* }}} */
954