diff --git a/dirsrvtests/tests/suites/filter/basic_filter_test.py b/dirsrvtests/tests/suites/filter/basic_filter_test.py index 3b7717d695..69f485f44b 100644 --- a/dirsrvtests/tests/suites/filter/basic_filter_test.py +++ b/dirsrvtests/tests/suites/filter/basic_filter_test.py @@ -15,9 +15,80 @@ from lib389.idm.user import UserAccount, UserAccounts from lib389.idm.group import UniqueGroups from lib389.idm.account import Accounts +from lib389.idm.domain import Domain pytestmark = pytest.mark.tier0 +class CreateUsers(): + """ + Will create users with different testUserAccountControl, testUserStatus + """ + def __init__(self, *args): + self.args = args + + def user_create(self): + """ + Will create users with different testUserAccountControl, testUserStatus + """ + import pdb + #pdb.set_trace() + #f"dc=syntaxes,{DEFAULT_SUFFIX}") + self.args[0].create(rdn=f"uid={str(self.args[1])}", properties={ + 'uid': str(self.args[1]), + 'sn': str(self.args[1]), + 'cn': str(self.args[1]), + 'userpassword': 'password', + 'displayName': self.args[2], + 'legalName': self.args[2], + 'objectclass': 'top nsPerson account organizationalPerson inetOrgPerson posixAccount'.split(), + 'uidNumber': str(self.args[4]), + 'gidNumber': str(self.args[4]), + 'homeDirectory': self.args[3], + 'loginShell': self.args[3] + }) + + def create_users_other(self): + """ + Will create users with different testUserAccountControl(8388608) + """ + self.args[0].create(properties={ + 'telephoneNumber': '98989819{}'.format(self.args[1]), + 'uid': 'anuj_{}'.format(self.args[1]), + 'sn': 'testwise_{}'.format(self.args[1]), + 'cn': 'bit testwise{}'.format(self.args[1]), + 'userpassword': PW_DM, + 'givenName': 'anuj_{}'.format(self.args[1]), + 'mail': 'anuj_{}@example.com'.format(self.args[1]), + 'objectclass': 'top account posixaccount organizationalPerson ' + 'inetOrgPerson testperson'.split(), + 'testUserAccountControl': '8388608', + 'testUserStatus': 'PasswordExpired', + 'uidNumber': str(self.args[1]), + 'gidNumber': str(self.args[1]), + 'homeDirectory': '/home/' + 'testwise_{}'.format(self.args[1]) + }) + + def user_create_52(self): + """ + Will create users with different testUserAccountControl(16777216) + """ + self.args[0].create(properties={ + 'telephoneNumber': '98989819{}'.format(self.args[1]), + 'uid': 'bditwfilter52_test{}'.format(self.args[1]), + 'sn': 'bditwfilter52_test{}'.format(self.args[1]), + 'cn': 'bit bditwfilter52_test{}'.format(self.args[1]), + 'userpassword': PW_DM, + 'givenName': 'bditwfilter52_test{}'.format(self.args[1]), + 'mail': 'bditwfilter52_test{}@example.com'.format(self.args[1]), + 'objectclass': 'top account posixaccount organizationalPerson ' + 'inetOrgPerson testperson'.split(), + 'testUserAccountControl': '16777216', + 'testUserStatus': 'PasswordExpired', + 'uidNumber': str(self.args[1]), + 'gidNumber': str(self.args[1]), + 'homeDirectory': '/home/' + 'bditwfilter52_test{}'.format(self.args[1]) + }) + def test_search_attr(topo): """Test filter can search attributes @@ -77,6 +148,174 @@ def fin(): request.addfinalizer(fin) +def test_handling_spaces_in_substring(topo): + """Test ldapsearch with substring filters + and the filters contains spaces + + :id: fa7cc247-cc70-4ca9-8d70-6a8e5fa83618 + :setup: Standalone instance + :steps: + 1. Adding 11 users. 11 is above filter shortcut + 2. Check a list of substring filters that contain spaces + :expectedresults: + 1. This should pass + 2. This should pass + """ + + # Creating suffix + syntaxes = Domain(topo.standalone, f"dc=syntaxes,{DEFAULT_SUFFIX}").create(properties={'dc': 'syntaxes'}) + + # Creating 11 users to avoid shortcut in candidate list + users = UserAccounts(topo.standalone, syntaxes.dn, rdn=None) + + # args 1: uid, sn, cn (all indexed) + # args 2: displayName, legalName + # args 3: homeDirectory, loginShell + # args 4: uidNumber, gidNumber + for user in [('V-1 uid', ['name'], ['/bin/my bash'], 101), + ('V-2 uid', ['name'], ['/bin/my bash'], 102), + ('V-3 uid', ['name'], ['/bin/my bash'], 103), + ('V-4 uid', ['name'], ['/bin/my bash'], 104), + ('V-5 uid', ['name'], ['/bin/my bash'], 105), + ('V-6 uid', ['name'], ['/bin/my bash'], 106), + ('V-7 uid', ['name'], ['/bin/my bash'], 107), + ('V-8 uid', ['name'], ['/bin/my bash'], 108), + ('V-9 uid', ['name'], ['/bin/my bash'], 109), + ('V-10 uid', ['name'], ['/bin/my bash'], 110), + ('V-11 uid', ['name'], ['/bin/my bash'], 111)]: + CreateUsers(users, user[0], user[1], user[2], user[3]).user_create() + + FILTER=0 + BASE=1 + SCOPE=2 + COUNT=3 + # + # uid, cn, sn, displayName, legalName are CIS + for srch_filter in [('(uid=V-1 uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # equality + ('(uid=V-1 uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # equality + ('(uid=v-1 uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # equality + ('(uid=V-10 uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # equality + ('(uid=V-10 uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # equality + ('(uid=v-10 uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # equality + ('(uid=V-1 *)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # initial + ('(uid=V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=V-1*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + ('(uid=V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid=v-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= v-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid=V-1 *)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # initial + ('(uid=V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=*1 *)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 U*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 U*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=V-1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # final + ('(uid=V-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=v-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=V-1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # final + ('(uid=V-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=v-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid= V-1* ui*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + any + ('(uid= V-1* ui*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + any + ('(uid= V-1*ui*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + any + ('(uid= V-1*ui*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + any + ('(uid=*-1 * uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # any + final + ('(uid=*-1 * uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1 *uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1* uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=v-*1 u*id)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # inital + any + final + ('(uid=v-*1 u*id)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # inital + any + final + ('(uid=v-*1 u*id)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # inital + any + final + ('(uid=v-*1 u*id)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # inital + any + final + ]: + assert len(UserAccounts(topo.standalone, srch_filter[BASE], rdn=None).filter(srch_filter[FILTER], scope=srch_filter[SCOPE])) == srch_filter[COUNT] + + # homeDirectory ExactIA5 + for srch_filter in [('(homeDirectory=/bin/my bash)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 11), # equality + ('(homeDirectory=/bin/my bash)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # equality + ('(homeDirectory=/bin/my bAsh)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # equality + ('(homeDirectory=/bin/my bAsh)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 0), # equality + ('(homeDirectory=/bin*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 11), # initial + ('(homeDirectory=/bin*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 11), # initial + ('(homeDirectory=/bIn*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 0), # initial + ('(homeDirectory=/bin/my *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/my *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/mY *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # initial + ('(homeDirectory=/bin/my *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/my *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/mY *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # initial + ('(homeDirectory=/bin/my b*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/my b*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial + ('(homeDirectory=/bin/mY b*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # initial + ('(homeDirectory=/bin/*my b*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial and any + ('(homeDirectory=/bin/*my b*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 11), # initial and any + ('(uid=v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=V-1*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + ('(uid=V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid=v-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= V-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid= v-1*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + ('(uid=V-1 *)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # initial + ('(uid=V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= V-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid= v-1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # initial + ('(uid=*1 *)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 *)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 U*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # any + ('(uid=*1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=*1 U*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # any + ('(uid=V-1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # final + ('(uid=V-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=v-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=V-1 u*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # final + ('(uid=V-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid=v-1 u*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # final + ('(uid= V-1* ui*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + any + ('(uid= V-1* ui*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + any + ('(uid= V-1*ui*)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # initial + any + ('(uid= V-1*ui*)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # initial + any + ('(uid=*-1 * uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # any + final + ('(uid=*-1 * uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 0), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1 *uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 1), # any + final + ('(uid=*-1 *uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 1), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=*-1* uid)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 3), # any + final + ('(uid=*-1* uid)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 3), # any + final + ('(uid=v-*1 u*id)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # inital + any + final + ('(uid=v-*1 u*id)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # inital + any + final + ('(uid=v-*1 u*id)', DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 2), # inital + any + final + ('(uid=v-*1 u*id)', syntaxes.dn, ldap.SCOPE_ONELEVEL, 2), # inital + any + final + ]: + assert len(UserAccounts(topo.standalone, srch_filter[BASE], rdn=None).filter(srch_filter[FILTER], scope=srch_filter[SCOPE])) == srch_filter[COUNT] + if __name__ == "__main__": CURRENT_FILE = os.path.realpath(__file__) pytest.main("-s -v %s" % CURRENT_FILE) diff --git a/dirsrvtests/tests/suites/filter/filter_match_test.py b/dirsrvtests/tests/suites/filter/filter_match_test.py index de1976bf0f..fec06e6abb 100644 --- a/dirsrvtests/tests/suites/filter/filter_match_test.py +++ b/dirsrvtests/tests/suites/filter/filter_match_test.py @@ -769,6 +769,7 @@ def test_extensible_search(topology_st, _searches, attr, value): :expectedresults: 1. Pass """ + topology_st.standalone.config.set("nsslapd-verify-filter-schema", "warn-invalid") cos = CosTemplates(topology_st.standalone, DEFAULT_SUFFIX) assert len(cos.filter(attr)) == value diff --git a/ldap/servers/plugins/syntaxes/bitstring.c b/ldap/servers/plugins/syntaxes/bitstring.c index c213f90c3c..0d77e6d12a 100644 --- a/ldap/servers/plugins/syntaxes/bitstring.c +++ b/ldap/servers/plugins/syntaxes/bitstring.c @@ -230,6 +230,17 @@ bitstring_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CES, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = TRIM_LEADING_BLANK | TRIM_TRAILING_BLANK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CES, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/ces.c b/ldap/servers/plugins/syntaxes/ces.c index cbd9b532e0..fa15c5a0c9 100644 --- a/ldap/servers/plugins/syntaxes/ces.c +++ b/ldap/servers/plugins/syntaxes/ces.c @@ -440,6 +440,17 @@ ces_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CES, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CES, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/cis.c b/ldap/servers/plugins/syntaxes/cis.c index c9274f37f6..02f8096f82 100644 --- a/ldap/servers/plugins/syntaxes/cis.c +++ b/ldap/servers/plugins/syntaxes/cis.c @@ -1290,6 +1290,17 @@ cis_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/deliverymethod.c b/ldap/servers/plugins/syntaxes/deliverymethod.c index 9cd4e50b38..d34f099b08 100644 --- a/ldap/servers/plugins/syntaxes/deliverymethod.c +++ b/ldap/servers/plugins/syntaxes/deliverymethod.c @@ -299,6 +299,17 @@ delivery_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/dn.c b/ldap/servers/plugins/syntaxes/dn.c index 6cf301c145..95782fbb3f 100644 --- a/ldap/servers/plugins/syntaxes/dn.c +++ b/ldap/servers/plugins/syntaxes/dn.c @@ -198,6 +198,17 @@ dn_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/facsimile.c b/ldap/servers/plugins/syntaxes/facsimile.c index 40e95a94ef..11959a953d 100644 --- a/ldap/servers/plugins/syntaxes/facsimile.c +++ b/ldap/servers/plugins/syntaxes/facsimile.c @@ -305,6 +305,17 @@ facsimile_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/guide.c b/ldap/servers/plugins/syntaxes/guide.c index 495c151e4a..b2d3a1f04f 100644 --- a/ldap/servers/plugins/syntaxes/guide.c +++ b/ldap/servers/plugins/syntaxes/guide.c @@ -712,6 +712,17 @@ guide_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/inchain.c b/ldap/servers/plugins/syntaxes/inchain.c index 07e58ea842..709f0b295b 100644 --- a/ldap/servers/plugins/syntaxes/inchain.c +++ b/ldap/servers/plugins/syntaxes/inchain.c @@ -411,7 +411,18 @@ inchain_normalize( int trim_spaces, char **alt) { + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } slapi_log_err(SLAPI_LOG_ERR, "inchain", "inchain_normalize %s \n", s); - value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_spaces, alt); + value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/int.c b/ldap/servers/plugins/syntaxes/int.c index 3d30ed927b..62ce388b2c 100644 --- a/ldap/servers/plugins/syntaxes/int.c +++ b/ldap/servers/plugins/syntaxes/int.c @@ -280,6 +280,17 @@ int_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_INT | SYNTAX_CES, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_INT | SYNTAX_CES, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/nameoptuid.c b/ldap/servers/plugins/syntaxes/nameoptuid.c index eed1eda35e..eb8fa8838d 100644 --- a/ldap/servers/plugins/syntaxes/nameoptuid.c +++ b/ldap/servers/plugins/syntaxes/nameoptuid.c @@ -274,6 +274,17 @@ nameoptuid_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS | SYNTAX_DN, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/numericstring.c b/ldap/servers/plugins/syntaxes/numericstring.c index 2b6e600c3d..94d31d1cea 100644 --- a/ldap/servers/plugins/syntaxes/numericstring.c +++ b/ldap/servers/plugins/syntaxes/numericstring.c @@ -280,6 +280,17 @@ numstr_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_SI | SYNTAX_CES, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_SI | SYNTAX_CES, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/sicis.c b/ldap/servers/plugins/syntaxes/sicis.c index c1ea23e9cd..6791d1dfd5 100644 --- a/ldap/servers/plugins/syntaxes/sicis.c +++ b/ldap/servers/plugins/syntaxes/sicis.c @@ -162,6 +162,17 @@ sicis_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_SI | SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_SI | SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/string.c b/ldap/servers/plugins/syntaxes/string.c index 61b3e9cf06..209ca21a4e 100644 --- a/ldap/servers/plugins/syntaxes/string.c +++ b/ldap/servers/plugins/syntaxes/string.c @@ -48,7 +48,7 @@ string_filter_ava(struct berval *bvfilter, Slapi_Value **bvals, int syntax, int } else { slapi_ber_bvcpy(&bvfilter_norm, bvfilter); /* 3rd arg: 1 - trim leading blanks */ - value_normalize_ext(bvfilter_norm.bv_val, syntax, 1, &alt); + value_normalize_ext(bvfilter_norm.bv_val, syntax, TRIM_LEADING_BLANK, &alt); if (alt) { slapi_ber_bvdone(&bvfilter_norm); bvfilter_norm.bv_val = alt; @@ -259,7 +259,15 @@ string_filter_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Sla if (initial != NULL) { /* 3rd arg: 1 - trim leading blanks */ if (!filter_normalized) { - value_normalize_ext(initial, syntax, 1, &alt); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an initial or an any substring that ends in + * one or more space characters, it is modified to end with exactly + * one SPACE character; + */ + value_normalize_ext(initial, syntax, TRIM_LEADING_BLANK & SHRINK_TRAILING_BLANK, &alt); } *p++ = '^'; if (alt) { @@ -274,7 +282,19 @@ string_filter_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Sla for (i = 0; any[i] != NULL; i++) { /* 3rd arg: 0 - DO NOT trim leading blanks */ if (!filter_normalized) { - value_normalize_ext(any[i], syntax, 0, &alt); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an initial or an any substring that ends in + * one or more space characters, it is modified to end with exactly + * one SPACE character; + * + * If the input string is an any or a final substring that starts in + * one or more space characters, it is modified to start with exactly + * one SPACE character; + */ + value_normalize_ext(any[i], syntax, SHRINK_LEADING_BLANK & SHRINK_TRAILING_BLANK, &alt); } /* ".*" + value */ *p++ = '.'; @@ -291,7 +311,15 @@ string_filter_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Sla if (final != NULL) { /* 3rd arg: 0 - DO NOT trim leading blanks */ if (!filter_normalized) { - value_normalize_ext(final, syntax, 0, &alt); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an any or a final substring that starts in + * one or more space characters, it is modified to start with exactly + * one SPACE character; + */ + value_normalize_ext(final, syntax, SHRINK_LEADING_BLANK, &alt); } /* ".*" + value */ *p++ = '.'; @@ -357,7 +385,7 @@ string_filter_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Sla } /* 3rd arg: 1 - trim leading blanks */ if (!(slapi_value_get_flags(bvals[j]) & SLAPI_ATTR_FLAG_NORMALIZED)) { - value_normalize_ext(realval, syntax, 1, &alt); + value_normalize_ext(realval, syntax, TRIM_LEADING_BLANK, &alt); } else if (syntax & SYNTAX_DN) { slapi_dn_ignore_case(realval); } @@ -434,7 +462,7 @@ string_values2keys(Slapi_PBlock *pb, Slapi_Value **bvals, Slapi_Value ***ivals, /* if the NORMALIZED flag is set, skip normalizing */ if (!(value_flags & SLAPI_ATTR_FLAG_NORMALIZED)) { /* 3rd arg: 1 - trim leading blanks */ - value_normalize_ext(c, syntax, 1, &alt); + value_normalize_ext(c, syntax, TRIM_LEADING_BLANK, &alt); value_flags |= SLAPI_ATTR_FLAG_NORMALIZED; } else if ((syntax & SYNTAX_DN) && (value_flags & SLAPI_ATTR_FLAG_NORMALIZED_CES)) { @@ -566,7 +594,7 @@ string_values2keys(Slapi_PBlock *pb, Slapi_Value **bvals, Slapi_Value ***ivals, /* 3rd arg: 1 - trim leading blanks */ if (!(value_flags & SLAPI_ATTR_FLAG_NORMALIZED)) { c = slapi_ch_strdup(slapi_value_get_string(*bvlp)); - value_normalize_ext(c, syntax, 1, &alt); + value_normalize_ext(c, syntax, TRIM_LEADING_BLANK, &alt); if (alt) { slapi_ch_free_string(&c); slapi_value_set_string_passin(bvdup, alt); @@ -668,7 +696,7 @@ string_assertion2keys_ava( tmpval->bv.bv_val[len] = '\0'; if (!(flags & SLAPI_ATTR_FLAG_NORMALIZED)) { /* 3rd arg: 1 - trim leading blanks */ - value_normalize_ext(tmpval->bv.bv_val, syntax, 1, &alt); + value_normalize_ext(tmpval->bv.bv_val, syntax, TRIM_LEADING_BLANK, &alt); if (alt) { if (len >= tmpval->bv.bv_len) { slapi_ch_free_string(&tmpval->bv.bv_val); @@ -693,7 +721,7 @@ string_assertion2keys_ava( (*ivals)[0] = val ? slapi_value_dup(val) : NULL; if (val && !(flags & SLAPI_ATTR_FLAG_NORMALIZED)) { /* 3rd arg: 1 - trim leading blanks */ - value_normalize_ext((*ivals)[0]->bv.bv_val, syntax, 1, &alt); + value_normalize_ext((*ivals)[0]->bv.bv_val, syntax, TRIM_LEADING_BLANK, &alt); if (alt) { slapi_ch_free_string(&(*ivals)[0]->bv.bv_val); (*ivals)[0]->bv.bv_val = alt; diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h index 7e53c35861..49bf630aa2 100644 --- a/ldap/servers/plugins/syntaxes/syntax.h +++ b/ldap/servers/plugins/syntaxes/syntax.h @@ -76,14 +76,15 @@ IS_RPAREN(c) || (c == '+') || (c == ',') || (c == '-') || (c == '.') || \ (c == '=') || (c == '/') || (c == ':') || (c == '?') || IS_SPACE(c)) + int string_filter_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Slapi_Value **bvals, int syntax); int string_filter_ava(struct berval *bvfilter, Slapi_Value **bvals, int syntax, int ftype, Slapi_Value **retVal); int string_values2keys(Slapi_PBlock *pb, Slapi_Value **bvals, Slapi_Value ***ivals, int syntax, int ftype); int string_assertion2keys_ava(Slapi_PBlock *pb, Slapi_Value *val, Slapi_Value ***ivals, int syntax, int ftype); int string_assertion2keys_sub(Slapi_PBlock *pb, char *initial, char **any, char * final, Slapi_Value ***ivals, int syntax); int value_cmp(struct berval *v1, struct berval *v2, int syntax, int normalize); -void value_normalize(char *s, int syntax, int trim_leading_blanks); -void value_normalize_ext(char *s, int syntax, int trim_leading_blanks, char **alt); +void value_normalize(char *s, int syntax, int trim_mask_blanks); +void value_normalize_ext(char *s, int syntax, int trim_mask_blanks, char **alt); char *first_word(char *s); char *next_word(char *s); diff --git a/ldap/servers/plugins/syntaxes/tel.c b/ldap/servers/plugins/syntaxes/tel.c index 3552c50065..78f8156469 100644 --- a/ldap/servers/plugins/syntaxes/tel.c +++ b/ldap/servers/plugins/syntaxes/tel.c @@ -289,6 +289,17 @@ tel_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_TEL | SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_TEL | SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/teletex.c b/ldap/servers/plugins/syntaxes/teletex.c index db108e6df6..57f16ea7dc 100644 --- a/ldap/servers/plugins/syntaxes/teletex.c +++ b/ldap/servers/plugins/syntaxes/teletex.c @@ -323,6 +323,17 @@ teletex_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/telex.c b/ldap/servers/plugins/syntaxes/telex.c index 7c4a9812b2..7449c312bc 100644 --- a/ldap/servers/plugins/syntaxes/telex.c +++ b/ldap/servers/plugins/syntaxes/telex.c @@ -238,6 +238,17 @@ telex_normalize( int trim_spaces, char **alt) { - value_normalize_ext(s, SYNTAX_CIS, trim_spaces, alt); + int trim_mask = 0; + if (trim_spaces == COMPATIBLE_NOT_TRIM_SPACES) { + /* value 0x00 */ + trim_mask = NO_TRIM_SHRINK_BLANK; + } else if (trim_spaces == COMPATIBLE_TRIM_SPACES) { + /* value 0x01 */ + trim_mask = COMPATIBLE_TRIM_MASK; + } else { + /* value 0x10-0x80 */ + trim_mask = trim_spaces; + } + value_normalize_ext(s, SYNTAX_CIS, trim_mask, alt); return; } diff --git a/ldap/servers/plugins/syntaxes/value.c b/ldap/servers/plugins/syntaxes/value.c index 3758849a34..979bcfdd70 100644 --- a/ldap/servers/plugins/syntaxes/value.c +++ b/ldap/servers/plugins/syntaxes/value.c @@ -100,7 +100,17 @@ value_normalize_ext( } d = s; - if (trim_spaces) { + if (trim_spaces & SHRINK_LEADING_BLANK) { + /* consum all leading blanks */ + while (utf8isspace_fast(s)) { + LDAP_UTF8INC(s); + } + /* if there was leading blanks keep only one*/ + if (d != s) { + LDAP_UTF8DEC(s); + } + } + if (trim_spaces & TRIM_LEADING_BLANK) { /* strip leading blanks */ while (utf8isspace_fast(s)) { LDAP_UTF8INC(s); @@ -184,8 +194,25 @@ value_normalize_ext( } } *d = '\0'; + /* compress trailing blanks */ + if (prevspace && (trim_spaces & SHRINK_TRAILING_BLANK)) { + char *nd; + + nd = ldap_utf8prev(d); + while (nd && nd >= head && utf8isspace_fast(nd)) { + d = nd; + nd = ldap_utf8prev(d); + if (utf8isspace_fast(nd)) { + /* consum the space referred by 'd' */ + *d = '\0'; + } else { + /* this was the last space => preserve it */ + break; + } + } + } /* strip trailing blanks */ - if (prevspace && trim_spaces) { + if (prevspace && (trim_spaces & TRIM_TRAILING_BLANK)) { char *nd; nd = ldap_utf8prev(d); @@ -252,7 +279,7 @@ value_cmp( free_v1 = 1; } value_normalize_ext(v1->bv_val, syntax, - 1 /* trim leading blanks */, &alt); + TRIM_LEADING_BLANK /* trim leading blanks */, &alt); if (alt) { int inserted = 0; @@ -297,7 +324,7 @@ value_cmp( free_v2 = 1; } value_normalize_ext(v2->bv_val, syntax, - 1 /* trim leading blanks */, &alt); + TRIM_LEADING_BLANK /* trim leading blanks */, &alt); if (alt) { int inserted = 0; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c index ec9bdb5e7d..eea1c8ff77 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_search.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c @@ -355,6 +355,96 @@ ldbm_back_search_cleanup(Slapi_PBlock *pb, return function_result; } +/* + * RFC 4518 2.6.1 insignificant space handling for substring assertion values. + * Returns a newly allocated string if the value was modified, NULL if unchanged. + */ +static char * +ldbm_search_substring_shrink_blanks(const char *val, int trim_spaces) +{ + char *head; + char *s; + char *end; + int ends_with_space = 0; + + if (val == NULL) { + return NULL; + } + + head = slapi_ch_strdup(val); + s = head; + + if (trim_spaces & SHRINK_LEADING_BLANK) { + while (ldap_utf8isspace(s)) { + LDAP_UTF8INC(s); + } + if (head != s) { + LDAP_UTF8DEC(s); + } + } + if (trim_spaces & TRIM_LEADING_BLANK) { + while (ldap_utf8isspace(s)) { + LDAP_UTF8INC(s); + } + } + + if (*s == '\0' && s != head) { + head[0] = ' '; + head[1] = '\0'; + if (strcmp(head, val) == 0) { + slapi_ch_free_string(&head); + return NULL; + } + return head; + } + + if (s != head) { + memmove(head, s, strlen(s) + 1); + } + + end = head + strlen(head); + if (end > head) { + char *nd = ldap_utf8prev(end); + + if (nd && nd >= head && ldap_utf8isspace(nd)) { + ends_with_space = 1; + } + } + + if (ends_with_space && (trim_spaces & SHRINK_TRAILING_BLANK)) { + char *nd; + char *d = end; + + nd = ldap_utf8prev(d); + while (nd && nd >= head && ldap_utf8isspace(nd)) { + d = nd; + nd = ldap_utf8prev(d); + if (ldap_utf8isspace(nd)) { + *d = '\0'; + } else { + break; + } + } + } + if (ends_with_space && (trim_spaces & TRIM_TRAILING_BLANK)) { + char *nd; + char *d = end; + + nd = ldap_utf8prev(d); + while (nd && nd >= head && ldap_utf8isspace(nd)) { + d = nd; + nd = ldap_utf8prev(d); + *d = '\0'; + } + } + + if (strcmp(head, val) == 0) { + slapi_ch_free_string(&head); + return NULL; + } + return head; +} + static int ldbm_search_compile_filter(Slapi_Filter *f, void *arg __attribute__((unused))) { @@ -395,20 +485,72 @@ ldbm_search_compile_filter(Slapi_Filter *f, void *arg __attribute__((unused))) p = bigpat; } if (f->f_sub_initial != NULL) { + char *alt; *p++ = '^'; - p = filter_strcpy_special_ext(p, f->f_sub_initial, FILTER_STRCPY_ESCAPE_RECHARS); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an initial or an any substring that ends in + * one or more space characters, it is modified to end with exactly + * one SPACE character; + */ + alt = ldbm_search_substring_shrink_blanks(f->f_sub_initial, + TRIM_LEADING_BLANK | SHRINK_TRAILING_BLANK); + if (alt) { + p = filter_strcpy_special_ext(p, alt, FILTER_STRCPY_ESCAPE_RECHARS); + slapi_ch_free_string(&alt); + } else { + p = filter_strcpy_special_ext(p, f->f_sub_initial, FILTER_STRCPY_ESCAPE_RECHARS); + } + } for (i = 0; f->f_sub_any && f->f_sub_any[i]; i++) { + char *alt; /* ".*" + value */ *p++ = '.'; *p++ = '*'; - p = filter_strcpy_special_ext(p, f->f_sub_any[i], FILTER_STRCPY_ESCAPE_RECHARS); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an initial or an any substring that ends in + * one or more space characters, it is modified to end with exactly + * one SPACE character; + * + * If the input string is an any or a final substring that starts in + * one or more space characters, it is modified to start with exactly + * one SPACE character; + */ + alt = ldbm_search_substring_shrink_blanks(f->f_sub_any[i], + SHRINK_LEADING_BLANK | SHRINK_TRAILING_BLANK); + if (alt) { + p = filter_strcpy_special_ext(p, alt, FILTER_STRCPY_ESCAPE_RECHARS); + slapi_ch_free_string(&alt); + } else { + p = filter_strcpy_special_ext(p, f->f_sub_any[i], FILTER_STRCPY_ESCAPE_RECHARS); + } } if (f->f_sub_final != NULL) { + char *alt; /* ".*" + value */ *p++ = '.'; *p++ = '*'; - p = filter_strcpy_special_ext(p, f->f_sub_final, FILTER_STRCPY_ESCAPE_RECHARS); + /* + * rfc4518 2.6.1 Insignificant Space Handling + * For input strings that are substring assertion values: + * + * If the input string is an any or a final substring that starts in + * one or more space characters, it is modified to start with exactly + * one SPACE character; + */ + alt = ldbm_search_substring_shrink_blanks(f->f_sub_final, SHRINK_LEADING_BLANK); + if (alt) { + p = filter_strcpy_special_ext(p, alt, FILTER_STRCPY_ESCAPE_RECHARS); + slapi_ch_free_string(&alt); + } else { + p = filter_strcpy_special_ext(p, f->f_sub_final, FILTER_STRCPY_ESCAPE_RECHARS); + } strcat(p, "$"); } diff --git a/ldap/servers/slapd/filter.c b/ldap/servers/slapd/filter.c index f67c6d1d8b..187ae4c92e 100644 --- a/ldap/servers/slapd/filter.c +++ b/ldap/servers/slapd/filter.c @@ -1127,7 +1127,7 @@ filter_normalize_ava(struct slapi_filter *f, PRBool norm_values) /* NOTE: assumes ava->ava_value.bv_val is NULL terminated - get_ava/ber_scanf 'o' will NULL terminate the string by default */ slapi_attr_value_normalize_ext(NULL, NULL, ava->ava_type, - ava->ava_value.bv_val, 1, &newval, f->f_choice); + ava->ava_value.bv_val, TRIM_LEADING_BLANK | TRIM_TRAILING_BLANK, &newval, f->f_choice); if (newval && (newval != ava->ava_value.bv_val)) { slapi_ch_free_string(&ava->ava_value.bv_val); ava->ava_value.bv_val = newval; @@ -1157,7 +1157,7 @@ filter_normalize_subfilt(struct slapi_filter *f, PRBool norm_values) int ii; slapi_attr_init(&attr, sf->sf_type); - slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_initial, 1, &newval, f->f_choice); + slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_initial, TRIM_LEADING_BLANK | SHRINK_TRAILING_BLANK, &newval, f->f_choice); if (newval && (newval != sf->sf_initial)) { slapi_ch_free_string(&sf->sf_initial); sf->sf_initial = newval; @@ -1165,7 +1165,7 @@ filter_normalize_subfilt(struct slapi_filter *f, PRBool norm_values) for (ii = 0; sf->sf_any && sf->sf_any[ii]; ++ii) { newval = NULL; /* do not trim spaces of sf_any values - see string_filter_sub() */ - slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_any[ii], 0, &newval, f->f_choice); + slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_any[ii], SHRINK_LEADING_BLANK | SHRINK_TRAILING_BLANK, &newval, f->f_choice); if (newval && (newval != sf->sf_any[ii])) { slapi_ch_free_string(&sf->sf_any[ii]); sf->sf_any[ii] = newval; @@ -1173,7 +1173,7 @@ filter_normalize_subfilt(struct slapi_filter *f, PRBool norm_values) } newval = NULL; /* do not trim spaces of sf_final values - see string_filter_sub() */ - slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_final, 0, &newval, f->f_choice); + slapi_attr_value_normalize_ext(NULL, &attr, NULL, sf->sf_final, SHRINK_LEADING_BLANK, &newval, f->f_choice); if (newval && (newval != sf->sf_final)) { slapi_ch_free_string(&sf->sf_final); sf->sf_final = newval; diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 9bae9ca648..62c1afdc65 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -145,6 +145,15 @@ PR_fprintf(struct PRFileDesc *fd, const char *fmt, ...) __ATTRIBUTE__((format(pr including case. \ Used for DN. */ +#define TRIM_LEADING_BLANK 0x10 +#define TRIM_TRAILING_BLANK 0x20 +#define SHRINK_LEADING_BLANK 0x40 +#define SHRINK_TRAILING_BLANK 0x80 +#define NO_TRIM_SHRINK_BLANK 0x00 +#define COMPATIBLE_TRIM_SPACES 0x01 +#define COMPATIBLE_NOT_TRIM_SPACES 0x00 +#define COMPATIBLE_TRIM_MASK (TRIM_LEADING_BLANK | TRIM_TRAILING_BLANK) +#define COMPATIBLE_NOT_TRIM_MASK 0x00 /** * Flag to indicate that the attribute value is not exposed if specified. * diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c index 2fa1d5c298..f6072f590c 100644 --- a/ldap/servers/slapd/util.c +++ b/ldap/servers/slapd/util.c @@ -319,7 +319,7 @@ filter_stuff_func(void *arg, const char *val, PRUint32 slen) char *norm_val = NULL; if (ctx->attr_found) { - slapi_attr_value_normalize(NULL, NULL, ctx->attr, buf, 1, &norm_val); + slapi_attr_value_normalize(NULL, NULL, ctx->attr, buf, TRIM_LEADING_BLANK | TRIM_TRAILING_BLANK, &norm_val); if (norm_val) { buf = norm_val; filter_len = strlen(buf);