summaryrefslogtreecommitdiff
path: root/src/sp_wrapper.c
blob: 7610114fef9f2aede433ae94ba5c308f992fff47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "php_snuffleupagus.h"

static bool wrapper_is_whitelisted(const zend_string *const zs) {
  const sp_list_node *list = SNUFFLEUPAGUS_G(config).config_wrapper->whitelist;

  if (!zs) {
    return false;  // LCOV_EXCL_LINE
  }

  while (list) {
    if (zend_string_equals_ci(zs, (const zend_string *)list->data)) {
      return true;
    }
    list = list->next;
  }
  return false;
}

void sp_disable_wrapper() {
  HashTable *orig = php_stream_get_url_stream_wrappers_hash();
  HashTable *orig_complete = pemalloc(sizeof(HashTable), 1);
  zval *zv;
  zend_string *zs;

  // Copy the original hashtable into a temporary one, as I'm not sure about
  // the behaviour of ZEND_HASH_FOREACH when element are removed from the
  // hashtable used in the loop.
  zend_hash_init(orig_complete, zend_hash_num_elements(orig), NULL, NULL, 1);
  zend_hash_copy(orig_complete, orig, NULL);
  zend_hash_clean(orig);

  ZEND_HASH_FOREACH_STR_KEY_VAL(orig_complete, zs, zv) {
    if (wrapper_is_whitelisted(zs)) {
      zend_hash_add(orig, zs, zv);
    }
  }
  ZEND_HASH_FOREACH_END();

  zend_hash_destroy(orig_complete);
  pefree(orig_complete, 1);
  SNUFFLEUPAGUS_G(config).config_wrapper->num_wrapper =
      zend_hash_num_elements(orig);
}

PHP_FUNCTION(sp_stream_wrapper_register) {
  zif_handler orig_handler;
  zend_string *protocol_name = NULL;

  // LCOV_EXCL_BR_START
  ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 2, EX_NUM_ARGS());
  Z_PARAM_STR(protocol_name);
  ZEND_PARSE_PARAMETERS_END_EX((void)0);
  // LCOV_EXCL_BR_END

  if (wrapper_is_whitelisted(protocol_name)) {
    orig_handler = zend_hash_str_find_ptr(
        SNUFFLEUPAGUS_G(sp_internal_functions_hook), "stream_wrapper_register",
        sizeof("stream_wrapper_register") - 1);
    orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  }
}

int hook_stream_wrappers() {
  TSRMLS_FETCH();

  HOOK_FUNCTION("stream_wrapper_register", sp_internal_functions_hook,
                PHP_FN(sp_stream_wrapper_register));

  return SUCCESS;
}