ext/ldap: Refactor verification of modification entry

This commit is contained in:
Gina Peter Banyard 2024-09-27 13:16:00 +01:00
parent 3af914d858
commit cf043af8fc
4 changed files with 91 additions and 139 deletions

View file

@ -2491,24 +2491,6 @@ PHP_FUNCTION(ldap_delete_ext)
} }
/* }}} */ /* }}} */
/* {{{ _ldap_str_equal_to_const */
static size_t _ldap_str_equal_to_const(const char *str, size_t str_len, const char *cstr)
{
size_t i;
if (strlen(cstr) != str_len)
return 0;
for (i = 0; i < str_len; ++i) {
if (str[i] != cstr[i]) {
return 0;
}
}
return 1;
}
/* }}} */
/* {{{ Perform multiple modifications as part of one operation */ /* {{{ Perform multiple modifications as part of one operation */
PHP_FUNCTION(ldap_modify_batch) PHP_FUNCTION(ldap_modify_batch)
{ {
@ -2554,10 +2536,6 @@ PHP_FUNCTION(ldap_modify_batch)
/* perform validation */ /* perform validation */
{ {
zend_string *modkey;
/* to store the wrongly-typed keys */
zend_ulong tmpUlong;
/* make sure the DN contains no NUL bytes */ /* make sure the DN contains no NUL bytes */
if (zend_char_has_nul_byte(dn, dn_len)) { if (zend_char_has_nul_byte(dn, dn_len)) {
zend_argument_value_error(2, "must not contain null bytes"); zend_argument_value_error(2, "must not contain null bytes");
@ -2579,117 +2557,91 @@ PHP_FUNCTION(ldap_modify_batch)
zend_argument_value_error(3, "must have consecutive integer indices starting from 0"); zend_argument_value_error(3, "must have consecutive integer indices starting from 0");
RETURN_THROWS(); RETURN_THROWS();
} }
mod = fetched; zval *modification_zv = fetched;
/* is it an array? */ if (Z_TYPE_P(modification_zv) != IS_ARRAY) {
if (Z_TYPE_P(mod) != IS_ARRAY) { zend_argument_type_error(3, "must only contain arrays");
zend_argument_value_error(3, "must only contain arrays");
RETURN_THROWS(); RETURN_THROWS();
} }
SEPARATE_ARRAY(mod); SEPARATE_ARRAY(modification_zv);
/* for the modification hashtable... */ const HashTable *modification = Z_ARRVAL_P(modification_zv);
zend_hash_internal_pointer_reset(Z_ARRVAL_P(mod)); uint32_t modification_size = zend_hash_num_elements(modification);
uint32_t num_modprops = zend_hash_num_elements(Z_ARRVAL_P(mod));
bool has_attrib_key = false;
bool has_modtype_key = false;
for (j = 0; j < num_modprops; j++) { if (modification_size != 2 && modification_size != 3) {
zend_argument_value_error(3, "a modification entry must only contain the keys "
/* are the keys strings? */ "\"" LDAP_MODIFY_BATCH_ATTRIB "\", \"" LDAP_MODIFY_BATCH_MODTYPE "\", and \"" LDAP_MODIFY_BATCH_VALUES "\"");
if (zend_hash_get_current_key(Z_ARRVAL_P(mod), &modkey, &tmpUlong) != HASH_KEY_IS_STRING) {
zend_argument_type_error(3, "must only contain string-indexed arrays");
RETURN_THROWS();
}
/* is this a valid entry? */
if (
!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB) &&
!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE) &&
!_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)
) {
zend_argument_value_error(3, "must contain arrays only containing the \"" LDAP_MODIFY_BATCH_ATTRIB "\", \"" LDAP_MODIFY_BATCH_MODTYPE "\" and \"" LDAP_MODIFY_BATCH_VALUES "\" keys");
RETURN_THROWS();
}
fetched = zend_hash_get_current_data(Z_ARRVAL_P(mod));
zval *modinfo = fetched;
/* does the value type match the key? */
if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_ATTRIB)) {
has_attrib_key = true;
if (Z_TYPE_P(modinfo) != IS_STRING) {
zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must be of type string, %s given", get_active_function_name(), zend_zval_value_name(modinfo));
RETURN_THROWS();
}
if (zend_str_has_nul_byte(Z_STR_P(modinfo))) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must not contain null bytes");
RETURN_THROWS();
}
}
else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_MODTYPE)) {
has_modtype_key = true;
if (Z_TYPE_P(modinfo) != IS_LONG) {
zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be of type int, %s given", get_active_function_name(), zend_zval_value_name(modinfo));
RETURN_THROWS();
}
/* is the value in range? */
zend_long modtype = Z_LVAL_P(modinfo);
if (
modtype != LDAP_MODIFY_BATCH_ADD &&
modtype != LDAP_MODIFY_BATCH_REMOVE &&
modtype != LDAP_MODIFY_BATCH_REPLACE &&
modtype != LDAP_MODIFY_BATCH_REMOVE_ALL
) {
zend_value_error("%s(): Option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be one of the LDAP_MODIFY_BATCH_* constants", get_active_function_name());
RETURN_THROWS();
}
/* if it's REMOVE_ALL, there must not be a values array; otherwise, there must */
if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL) {
if (zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
zend_value_error("%s(): If option \"" LDAP_MODIFY_BATCH_MODTYPE "\" is LDAP_MODIFY_BATCH_REMOVE_ALL, option \"" LDAP_MODIFY_BATCH_VALUES "\" cannot be provided", get_active_function_name());
RETURN_THROWS();
}
}
else {
if (!zend_hash_str_exists(Z_ARRVAL_P(mod), LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES))) {
zend_value_error("%s(): If option \"" LDAP_MODIFY_BATCH_MODTYPE "\" is not LDAP_MODIFY_BATCH_REMOVE_ALL, option \"" LDAP_MODIFY_BATCH_VALUES "\" must be provided", get_active_function_name());
RETURN_THROWS();
}
}
}
else if (_ldap_str_equal_to_const(ZSTR_VAL(modkey), ZSTR_LEN(modkey), LDAP_MODIFY_BATCH_VALUES)) {
if (Z_TYPE_P(modinfo) != IS_ARRAY) {
zend_type_error("%s(): Option \"" LDAP_MODIFY_BATCH_VALUES "\" must be of type array, %s given", get_active_function_name(), zend_zval_value_name(modinfo));
RETURN_THROWS();
}
SEPARATE_ARRAY(modinfo);
const HashTable *modification_values = Z_ARRVAL_P(modinfo);
/* is the array not empty? */
uint32_t num_modification_values = zend_hash_num_elements(modification_values);
if (num_modification_values == 0) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_VALUES "\" must not be empty");
RETURN_THROWS();
}
if (!zend_array_is_list(modification_values)) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_VALUES "\" must be a list");
RETURN_THROWS();
}
}
zend_hash_move_forward(Z_ARRVAL_P(mod));
}
if (!has_attrib_key) {
zend_value_error("%s(): Required option \"" LDAP_MODIFY_BATCH_ATTRIB "\" is missing", get_active_function_name());
RETURN_THROWS(); RETURN_THROWS();
} }
if (!has_modtype_key) {
zend_value_error("%s(): Required option \"" LDAP_MODIFY_BATCH_MODTYPE "\" is missing", get_active_function_name()); const zval *attrib = zend_hash_str_find(modification, LDAP_MODIFY_BATCH_ATTRIB, strlen(LDAP_MODIFY_BATCH_ATTRIB));
if (UNEXPECTED(attrib == NULL)) {
zend_argument_value_error(3, "a modification entry must contain the \"" LDAP_MODIFY_BATCH_ATTRIB "\" option");
RETURN_THROWS();
}
if (UNEXPECTED(Z_TYPE_P(attrib) != IS_STRING)) {
zend_argument_type_error(3, "the value for option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must be of type string, %s given", zend_zval_value_name(attrib));
RETURN_THROWS();
}
if (zend_str_has_nul_byte(Z_STR_P(attrib))) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_ATTRIB "\" must not contain null bytes");
RETURN_THROWS();
}
const zval *modtype_zv = zend_hash_str_find(modification, LDAP_MODIFY_BATCH_MODTYPE, strlen(LDAP_MODIFY_BATCH_MODTYPE));
if (UNEXPECTED(modtype_zv == NULL)) {
zend_argument_value_error(3, "a modification entry must contain the \"" LDAP_MODIFY_BATCH_MODTYPE "\" option");
RETURN_THROWS();
}
if (UNEXPECTED(Z_TYPE_P(modtype_zv) != IS_LONG)) {
zend_argument_type_error(3, "the value for option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be of type int, %s given", zend_zval_value_name(attrib));
RETURN_THROWS();
}
zend_long modtype = Z_LVAL_P(modtype_zv);
if (
modtype != LDAP_MODIFY_BATCH_ADD &&
modtype != LDAP_MODIFY_BATCH_REMOVE &&
modtype != LDAP_MODIFY_BATCH_REPLACE &&
modtype != LDAP_MODIFY_BATCH_REMOVE_ALL
) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_MODTYPE "\" must be"
" LDAP_MODIFY_BATCH_ADD, LDAP_MODIFY_BATCH_REMOVE, LDAP_MODIFY_BATCH_REPLACE,"
" or LDAP_MODIFY_BATCH_REMOVE_ALL");
RETURN_THROWS();
}
/* We assume that the modification array is well-formed and only ever contains an extra "values" key */
if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL && modification_size == 3) {
zend_argument_value_error(3, "a modification entry must not contain the "
"\"" LDAP_MODIFY_BATCH_VALUES "\" option when option \"" LDAP_MODIFY_BATCH_MODTYPE "\" "
"is LDAP_MODIFY_BATCH_REMOVE_ALL");
RETURN_THROWS();
}
zval *modification_values_zv = zend_hash_str_find(modification, LDAP_MODIFY_BATCH_VALUES, strlen(LDAP_MODIFY_BATCH_VALUES));
if (modification_values_zv == NULL) {
if (modtype != LDAP_MODIFY_BATCH_REMOVE_ALL) {
zend_argument_value_error(3, "a modification entry must contain the "
"\"" LDAP_MODIFY_BATCH_VALUES "\" option when the \"" LDAP_MODIFY_BATCH_MODTYPE "\" option "
"is not LDAP_MODIFY_BATCH_REMOVE_ALL");
RETURN_THROWS();
}
continue;
}
if (Z_TYPE_P(modification_values_zv) != IS_ARRAY) {
zend_argument_type_error(3, "the value for option \"" LDAP_MODIFY_BATCH_VALUES "\" must be of type array, %s given", zend_zval_value_name(attrib));
RETURN_THROWS();
}
SEPARATE_ARRAY(modification_values_zv);
const HashTable *modification_values = Z_ARRVAL_P(modification_values_zv);
/* is the array not empty? */
uint32_t num_modvals = zend_hash_num_elements(modification_values);
if (num_modvals == 0) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_VALUES "\" must not be empty");
RETURN_THROWS();
}
if (!zend_array_is_list(modification_values)) {
zend_argument_value_error(3, "the value for option \"" LDAP_MODIFY_BATCH_VALUES "\" must be a list");
RETURN_THROWS(); RETURN_THROWS();
} }
} }

View file

@ -23,4 +23,4 @@ try {
?> ?>
--EXPECT-- --EXPECT--
ValueError: ldap_modify_batch(): Required option "attrib" is missing ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must contain the "attrib" option

View file

@ -23,4 +23,4 @@ try {
?> ?>
--EXPECT-- --EXPECT--
ValueError: ldap_modify_batch(): Required option "modtype" is missing ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must contain the "modtype" option

View file

@ -259,18 +259,18 @@ ValueError: ldap_modify_batch(): Argument #2 ($dn) must not contain null bytes
TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must be integer-indexed TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must be integer-indexed
TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must be integer-indexed TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must be integer-indexed
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) must have consecutive integer indices starting from 0 ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) must have consecutive integer indices starting from 0
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) must only contain arrays TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must only contain arrays
TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) must only contain string-indexed arrays ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must not contain the "values" option when option "modtype" is LDAP_MODIFY_BATCH_REMOVE_ALL
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) must contain arrays only containing the "attrib", "modtype" and "values" keys ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must only contain the keys "attrib", "modtype", and "values"
TypeError: ldap_modify_batch(): Option "attrib" must be of type string, int given TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "attrib" must be of type string, int given
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "attrib" must not contain null bytes ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "attrib" must not contain null bytes
TypeError: ldap_modify_batch(): Option "modtype" must be of type int, stdClass given TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "modtype" must be of type int, string given
ValueError: ldap_modify_batch(): Option "modtype" must be one of the LDAP_MODIFY_BATCH_* constants ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "modtype" must be LDAP_MODIFY_BATCH_ADD, LDAP_MODIFY_BATCH_REMOVE, LDAP_MODIFY_BATCH_REPLACE, or LDAP_MODIFY_BATCH_REMOVE_ALL
ValueError: ldap_modify_batch(): If option "modtype" is LDAP_MODIFY_BATCH_REMOVE_ALL, option "values" cannot be provided ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must not contain the "values" option when option "modtype" is LDAP_MODIFY_BATCH_REMOVE_ALL
ValueError: ldap_modify_batch(): If option "modtype" is not LDAP_MODIFY_BATCH_REMOVE_ALL, option "values" must be provided ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must contain the "values" option when the "modtype" option is not LDAP_MODIFY_BATCH_REMOVE_ALL
TypeError: ldap_modify_batch(): Option "values" must be of type array, string given TypeError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must be of type array, string given
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must not be empty ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must not be empty
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must be a list ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must be a list
ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must be a list ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) the value for option "values" must be a list
ValueError: ldap_modify_batch(): Required option "attrib" is missing ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must contain the "attrib" option
ValueError: ldap_modify_batch(): Required option "modtype" is missing ValueError: ldap_modify_batch(): Argument #3 ($modifications_info) a modification entry must contain the "modtype" option