From 1e74dc8545e1751a1ed4545594dea4ef73b2013c Mon Sep 17 00:00:00 2001 From: William Brown Date: Fri, 8 Jan 2016 09:47:44 +1000 Subject: [PATCH] Ticket 48363 - Support for rfc3673 '+' to return operational attributes Bug Description: We should support rfc3673 to return operational attributes in searches. Fix Description: We implement the '+' operator as per [0]. Additionally, we need to add "supportedFeatures" as per [1]. As a result, we have implemented both rfcs now. This can be shown by adding '+' to any search. We also add a test case that proves '+' works, that '*' works, and specific named attributes work also. Acis are also correctly respected by this change, even for operational attributes. [0] https://tools.ietf.org/html/rfc3673 [1] https://tools.ietf.org/html/rfc3674 https://fedorahosted.org/389/ticket/48363 Author: wibrown Review by: ??? --- Makefile.am | 1 + Makefile.in | 22 +++- dirsrvtests/create_test.py | 12 +- dirsrvtests/tickets/ticket48363_test.py | 206 ++++++++++++++++++++++++++++++++ ldap/servers/slapd/features.c | 53 ++++++++ ldap/servers/slapd/main.c | 5 + ldap/servers/slapd/proto-slap.h | 5 + ldap/servers/slapd/result.c | 31 +++-- ldap/servers/slapd/rootdse.c | 13 ++ ldap/servers/slapd/slapi-plugin.h | 19 ++- 10 files changed, 343 insertions(+), 24 deletions(-) create mode 100644 dirsrvtests/tickets/ticket48363_test.py create mode 100644 ldap/servers/slapd/features.c diff --git a/Makefile.am b/Makefile.am index bca6489..74e1a64 100644 --- a/Makefile.am +++ b/Makefile.am @@ -959,6 +959,7 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/errormap.c \ ldap/servers/slapd/eventq.c \ ldap/servers/slapd/factory.c \ + ldap/servers/slapd/features.c \ ldap/servers/slapd/fileio.c \ ldap/servers/slapd/filter.c \ ldap/servers/slapd/filtercmp.c \ diff --git a/Makefile.in b/Makefile.in index c5637ab..708db56 100644 --- a/Makefile.in +++ b/Makefile.in @@ -730,8 +730,9 @@ am__libslapd_la_SOURCES_DIST = ldap/servers/slapd/add.c \ ldap/servers/slapd/dse.c ldap/servers/slapd/dynalib.c \ ldap/servers/slapd/entry.c ldap/servers/slapd/entrywsi.c \ ldap/servers/slapd/errormap.c ldap/servers/slapd/eventq.c \ - ldap/servers/slapd/factory.c ldap/servers/slapd/fileio.c \ - ldap/servers/slapd/filter.c ldap/servers/slapd/filtercmp.c \ + ldap/servers/slapd/factory.c ldap/servers/slapd/features.c \ + ldap/servers/slapd/fileio.c ldap/servers/slapd/filter.c \ + ldap/servers/slapd/filtercmp.c \ ldap/servers/slapd/filterentry.c \ ldap/servers/slapd/generation.c \ ldap/servers/slapd/getfilelist.c \ @@ -802,6 +803,7 @@ am_libslapd_la_OBJECTS = ldap/servers/slapd/libslapd_la-add.lo \ ldap/servers/slapd/libslapd_la-errormap.lo \ ldap/servers/slapd/libslapd_la-eventq.lo \ ldap/servers/slapd/libslapd_la-factory.lo \ + ldap/servers/slapd/libslapd_la-features.lo \ ldap/servers/slapd/libslapd_la-fileio.lo \ ldap/servers/slapd/libslapd_la-filter.lo \ ldap/servers/slapd/libslapd_la-filtercmp.lo \ @@ -2347,8 +2349,9 @@ libslapd_la_SOURCES = ldap/servers/slapd/add.c \ ldap/servers/slapd/dse.c ldap/servers/slapd/dynalib.c \ ldap/servers/slapd/entry.c ldap/servers/slapd/entrywsi.c \ ldap/servers/slapd/errormap.c ldap/servers/slapd/eventq.c \ - ldap/servers/slapd/factory.c ldap/servers/slapd/fileio.c \ - ldap/servers/slapd/filter.c ldap/servers/slapd/filtercmp.c \ + ldap/servers/slapd/factory.c ldap/servers/slapd/features.c \ + ldap/servers/slapd/fileio.c ldap/servers/slapd/filter.c \ + ldap/servers/slapd/filtercmp.c \ ldap/servers/slapd/filterentry.c \ ldap/servers/slapd/generation.c \ ldap/servers/slapd/getfilelist.c \ @@ -4566,6 +4569,9 @@ ldap/servers/slapd/libslapd_la-eventq.lo: \ ldap/servers/slapd/libslapd_la-factory.lo: \ ldap/servers/slapd/$(am__dirstamp) \ ldap/servers/slapd/$(DEPDIR)/$(am__dirstamp) +ldap/servers/slapd/libslapd_la-features.lo: \ + ldap/servers/slapd/$(am__dirstamp) \ + ldap/servers/slapd/$(DEPDIR)/$(am__dirstamp) ldap/servers/slapd/libslapd_la-fileio.lo: \ ldap/servers/slapd/$(am__dirstamp) \ ldap/servers/slapd/$(DEPDIR)/$(am__dirstamp) @@ -5750,6 +5756,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-errormap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-eventq.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-factory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-features.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-fileio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ldap/servers/slapd/$(DEPDIR)/libslapd_la-filtercmp.Plo@am__quote@ @@ -8018,6 +8025,13 @@ ldap/servers/slapd/libslapd_la-factory.lo: ldap/servers/slapd/factory.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslapd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/slapd/libslapd_la-factory.lo `test -f 'ldap/servers/slapd/factory.c' || echo '$(srcdir)/'`ldap/servers/slapd/factory.c +ldap/servers/slapd/libslapd_la-features.lo: ldap/servers/slapd/features.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslapd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/slapd/libslapd_la-features.lo -MD -MP -MF ldap/servers/slapd/$(DEPDIR)/libslapd_la-features.Tpo -c -o ldap/servers/slapd/libslapd_la-features.lo `test -f 'ldap/servers/slapd/features.c' || echo '$(srcdir)/'`ldap/servers/slapd/features.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ldap/servers/slapd/$(DEPDIR)/libslapd_la-features.Tpo ldap/servers/slapd/$(DEPDIR)/libslapd_la-features.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ldap/servers/slapd/features.c' object='ldap/servers/slapd/libslapd_la-features.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslapd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ldap/servers/slapd/libslapd_la-features.lo `test -f 'ldap/servers/slapd/features.c' || echo '$(srcdir)/'`ldap/servers/slapd/features.c + ldap/servers/slapd/libslapd_la-fileio.lo: ldap/servers/slapd/fileio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslapd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ldap/servers/slapd/libslapd_la-fileio.lo -MD -MP -MF ldap/servers/slapd/$(DEPDIR)/libslapd_la-fileio.Tpo -c -o ldap/servers/slapd/libslapd_la-fileio.lo `test -f 'ldap/servers/slapd/fileio.c' || echo '$(srcdir)/'`ldap/servers/slapd/fileio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) ldap/servers/slapd/$(DEPDIR)/libslapd_la-fileio.Tpo ldap/servers/slapd/$(DEPDIR)/libslapd_la-fileio.Plo diff --git a/dirsrvtests/create_test.py b/dirsrvtests/create_test.py index e3b89aa..7b06fdb 100755 --- a/dirsrvtests/create_test.py +++ b/dirsrvtests/create_test.py @@ -174,7 +174,9 @@ if len(sys.argv) > 0: # TEST.write('logging.getLogger(__name__).setLevel(logging.DEBUG)\n') TEST.write('log = logging.getLogger(__name__)\n\n') - TEST.write('installation1_prefix = None\n\n\n') + + # We don't need the prefix anymore, it's worked out in lib389 + # TEST.write('installation1_prefix = None\n\n\n') # # Write the replication or standalone classes @@ -240,10 +242,10 @@ if len(sys.argv) > 0: # TEST.write('@pytest.fixture(scope="module")\n') TEST.write('def topology(request):\n') - TEST.write(' global installation1_prefix\n') - TEST.write(' if installation1_prefix:\n') - TEST.write(' args_instance[SER_DEPLOYED_DIR] = ' + - 'installation1_prefix\n\n') + #TEST.write(' global installation1_prefix\n') + #TEST.write(' if installation1_prefix:\n') + #TEST.write(' args_instance[SER_DEPLOYED_DIR] = ' + + # 'installation1_prefix\n\n') if repl_deployment: # diff --git a/dirsrvtests/tickets/ticket48363_test.py b/dirsrvtests/tickets/ticket48363_test.py new file mode 100644 index 0000000..33245a1 --- /dev/null +++ b/dirsrvtests/tickets/ticket48363_test.py @@ -0,0 +1,206 @@ +import os +import sys +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry, tools, tasks +from lib389.tools import DirSrvTools +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * + +logging.getLogger(__name__).setLevel(logging.DEBUG) +log = logging.getLogger(__name__) + +TEST_USER = 'uid=test,%s' % DEFAULT_SUFFIX +# Well, it's better than "password" or "password1" +TEST_PASS = 'banana cream pie' + +class TopologyStandalone(object): + def __init__(self, standalone): + standalone.open() + self.standalone = standalone + + +@pytest.fixture(scope="module") +def topology(request): + + # Creating standalone instance ... + standalone = DirSrv(verbose=False) + args_instance[SER_HOST] = HOST_STANDALONE + args_instance[SER_PORT] = PORT_STANDALONE + args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE + args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX + args_standalone = args_instance.copy() + standalone.allocate(args_standalone) + instance_standalone = standalone.exists() + if instance_standalone: + standalone.delete() + standalone.create() + standalone.open() + + # Delete each instance in the end + def fin(): + standalone.delete() + request.addfinalizer(fin) + + # Clear out the tmp dir + standalone.clearTmpDir(__file__) + + return TopologyStandalone(standalone) + + +def test_ticket48363(topology): + """ + Test the implementation of rfc3673, '+' for all operational attributes. + + Please see: https://tools.ietf.org/html/rfc3673 + + """ + + # Test the implementation of the supportFeatures + + # Section 2: + # Servers supporting this feature SHOULD publish the Object Identifier + # 1.3.6.1.4.1.4203.1.5.1 as a value of the 'supportedFeatures' + # [RFC3674] attribute in the root DSE. + + results = topology.standalone.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['supportedFeatures'] )[0] + if results.hasAttr('supportedfeatures') is False: + assert False + if results.hasValue('supportedfeatures', '1.3.6.1.4.1.4203.1.5.1') is False: + assert False + + # Section 2: + # The presence of the attribute description "+" (ASCII 43) in the list + # of attributes in a Search Request [RFC2251] SHALL signify a request + # for the return of all operational attributes. + + # Test the two backends, rootdse, and a real ldbm backend + + # Root DSE + results = topology.standalone.search_s('', ldap.SCOPE_BASE, 'objectClass=*', ['+'] )[0] + # There are a number of obvious ones in rootdse. These are: + + rootdse_op_attrs = [ + 'supportedExtension', + 'supportedControl', + 'supportedFeatures', + 'supportedSASLMechanisms', + 'supportedLDAPVersion', + 'vendorName', + 'vendorVersion', + ] + + for opattr in rootdse_op_attrs: + if results.hasAttr(opattr) is False: + assert False + + # LDBM backend + # We are going to examine the root of the suffix, as it's a good easy target + dc_op_attrs = [ + 'nsuniqueid', + 'entrydn', + 'entryid', + 'aci', + ] + dc_user_attrs = [ + 'objectClass', + 'dc', + ] + + # We should show that the following work: + + # '+' + results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+'] )[0] + for opattr in dc_op_attrs: + if results.hasAttr(opattr) is False: + assert False + for userattr in dc_user_attrs: + if results.hasAttr(userattr) is False: + assert True + + # '+' '*' + results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+', '*'] )[0] + for opattr in dc_op_attrs: + if results.hasAttr(opattr) is False: + assert False + for userattr in dc_user_attrs: + if results.hasAttr(userattr) is False: + assert False + + # Section 2: + # Client implementors should also note + # that certain operational attributes may be returned only if requested + # by name even when "+" is present. + + # We do not currently have any types that are excluded. + # However, we should ensure that a search for "+ namedType" returns + # both all operational and the namedType + + # '+' dc + results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['+', 'dc'] )[0] + for opattr in dc_op_attrs: + if results.hasAttr(opattr) is False: + assert False + if results.hasAttr('dc') is False: + assert False + if results.hasAttr('objectclass') is False: + assert True + + # '*' nsUniqueId + results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['*', 'nsuniqueid'] )[0] + for userattr in dc_user_attrs: + if results.hasAttr(userattr) is False: + assert False + if results.hasAttr('nsuniqueid') is False: + assert False + if results.hasAttr('entrydn') is False: + assert True + + # Section 2: + # As with all search requests, client implementors should note that + # results may not include all requested attributes due to access + # controls or other restrictions. + + # Test that with a user with limit read aci, that these are enforced on + # the + request. + + # Create the user + uentry = Entry(TEST_USER) + uentry.setValues('objectclass', 'top', 'extensibleobject') + uentry.setValues('uid', 'test') + uentry.setValues('userPassword', TEST_PASS) + topology.standalone.add_s(uentry) + + # Give them a limited read aci: We may need to purge other acis + anonaci = '(targetattr!="userPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn="ldap:///anyone";)' + topology.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_DELETE, 'aci', anonaci)]) + + # Now we need to create an aci that allows anon/all read to only a few attrs + # Lets make one real, and one operational. + + anonaci = '(targetattr="objectclass || dc || nsuniqueid")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn="ldap:///anyone";)' + topology.standalone.modify_s(DEFAULT_SUFFIX, [(ldap.MOD_ADD, 'aci', anonaci)]) + + # bind as them, and test. + topology.standalone.simple_bind_s(TEST_USER, TEST_PASS) + results = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_BASE, 'objectClass=*', ['*', '+'] )[0] + + if results.hasAttr('dc') is False: + assert False + if results.hasAttr('nsuniqueid') is False: + assert False + if results.hasAttr('entrydn') is False: + assert True + + log.info('Test complete') + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) diff --git a/ldap/servers/slapd/features.c b/ldap/servers/slapd/features.c new file mode 100644 index 0000000..aade6c3 --- /dev/null +++ b/ldap/servers/slapd/features.c @@ -0,0 +1,53 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. + * Copyright (C) 2005 Red Hat, Inc. + * All rights reserved. + * + * License: GPL (version 3 or any later version). + * See LICENSE for details. + * END COPYRIGHT BLOCK **/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +/* features.c - routines for dealing with supportedFeatures rfc3674 */ + +#include +#include "slap.h" + +static char **supported_features = NULL; +static Slapi_RWLock *supported_features_lock = NULL; + +void +init_features( void ) +{ + supported_features_lock = slapi_new_rwlock(); + if (supported_features_lock == NULL) { + slapi_log_error(SLAPI_LOG_FATAL, "startup", + "init_features: failed to create lock.\n"); + exit(1); + } + slapi_register_supported_feature( LDAP_FEATURE_RFC3673_ALLOPERATIONAL ); +} + +int +slapi_register_supported_feature( char *featureoid ) +{ + slapi_rwlock_wrlock(supported_features_lock); + charray_add( &supported_features, slapi_ch_strdup( featureoid )); + slapi_rwlock_unlock(supported_features_lock); + return LDAP_SUCCESS; +} + +int +slapi_get_supported_features_copy( char ***ftroidsp ) +{ + slapi_rwlock_unlock(supported_features_lock); + if ( ftroidsp != NULL ) { + *ftroidsp = charray_dup(supported_features); + } + slapi_rwlock_unlock(supported_features_lock); + return LDAP_SUCCESS; +} + diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c index b048dc5..1181628 100644 --- a/ldap/servers/slapd/main.c +++ b/ldap/servers/slapd/main.c @@ -702,6 +702,11 @@ main( int argc, char **argv) init_controls(); /* + * Register the server features that we support. + */ + init_features(); + + /* * Initialize the global plugin list lock */ global_plugin_init(); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index f0a5257..9dc5465 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -648,6 +648,11 @@ void *sym_load( char *libpath, char *symbol, char *plugin, int report_errors ); */ void *sym_load_with_flags( char *libpath, char *symbol, char *plugin, int report_errors, PRBool load_now, PRBool load_global ); +/* + * features.c + */ + +void init_features( void ); /* * filter.c diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c index cd58f50..6730fd5 100644 --- a/ldap/servers/slapd/result.c +++ b/ldap/servers/slapd/result.c @@ -1119,7 +1119,7 @@ static const char *idds_map_attrt_v3( /* Helper functions */ -static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_PBlock *pb,BerElement *ber,int attrsonly,int ldapversion, int real_attrs_only, int some_named_attrs) +static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_PBlock *pb,BerElement *ber,int attrsonly,int ldapversion, int real_attrs_only, int some_named_attrs, int alloperationalattrs, int alluserattrs ) { int i = 0; int rc = 0; @@ -1142,7 +1142,7 @@ static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_ vattr_flags |= SLAPI_VIRTUALATTRS_ONLY; } - if (some_named_attrs) { + if (some_named_attrs || alloperationalattrs) { /* * If the client listed some attribute types by name, one or * more of the requested types MAY be operational. Inform the @@ -1189,11 +1189,11 @@ static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_ name_to_return = current_type_name; /* We only return operational attributes if the client is LDAPv2 and the attribute is one of a special set, - OR if the client also requested the attribute by name. If it did, we use the specified name rather than - the base name. + OR if all operational attrs are requested, OR if the client also requested the attribute by name. + If it did, we use the specified name rather than the base name. */ if ( current_type_flags & SLAPI_ATTR_FLAG_OPATTR ) { - if ( LDAP_VERSION2 == ldapversion && LASTMODATTR( current_type_name) ) { + if ( (LDAP_VERSION2 == ldapversion && LASTMODATTR( current_type_name)) || alloperationalattrs ) { sendit = 1; } else { for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) { @@ -1215,7 +1215,7 @@ static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_ /* * it's a user attribute. send it. */ - } else { + } else if ( alluserattrs ) { sendit = 1; } /* Now send to the client */ @@ -1474,7 +1474,10 @@ send_ldap_search_entry_ext( Operation *op = pb->pb_op; BerElement *ber = NULL; int i, rc = 0, logit = 0; - int alluserattrs, noattrs, some_named_attrs; + int alluserattrs; + int noattrs; + int some_named_attrs; + int alloperationalattrs; Slapi_Operation *operation; int real_attrs_only = 0; LDAPControl **ctrlp = 0; @@ -1557,15 +1560,17 @@ send_ldap_search_entry_ext( /* * in ldapv3, the special attribute "*" means all user attributes, - * NULL means all user attributes, and "1.1" means no attributes. + * NULL means all user attributes, "1.1" means no attributes, and + * "+" means all operational attributes (rfc3673) * operational attributes are only retrieved if they are named - * specifically. + * specifically or when "+" is specified. */ /* figure out if we want all user attributes or no attributes at all */ alluserattrs = 0; noattrs = 0; some_named_attrs = 0; + alloperationalattrs = 0; if ( attrs == NULL ) { alluserattrs = 1; } else { @@ -1574,6 +1579,8 @@ send_ldap_search_entry_ext( alluserattrs = 1; } else if ( strcmp( LDAP_NO_ATTRS, attrs[i] ) == 0 ) { noattrs = 1; + } else if ( strcmp( LDAP_ALL_OPERATIONAL_ATTRS, attrs[i] ) == 0 ) { + alloperationalattrs = 1; } else { some_named_attrs = 1; } @@ -1611,9 +1618,9 @@ send_ldap_search_entry_ext( } /* look through each attribute in the entry */ - if ( alluserattrs ) { + if ( alluserattrs || alloperationalattrs ) { rc = send_all_attrs(e, attrs, op, pb, ber, attrsonly, conn->c_ldapversion, - real_attrs_only, some_named_attrs); + real_attrs_only, some_named_attrs, alloperationalattrs, alluserattrs); } /* if the client explicitly specified a list of attributes look through each attribute requested */ @@ -2213,7 +2220,7 @@ encode_read_entry (Slapi_PBlock *pb, Slapi_Entry *e, char **attrs, int alluserat /* Send all the attributes */ if ( alluserattrs ) { rc = send_all_attrs(e, attrs, op, pb, ber, 0, conn->c_ldapversion, - real_attrs_only, attr_count); + real_attrs_only, attr_count, 0, 1); if(rc){ goto cleanup; } diff --git a/ldap/servers/slapd/rootdse.c b/ldap/servers/slapd/rootdse.c index 9b30423..d839c92 100644 --- a/ldap/servers/slapd/rootdse.c +++ b/ldap/servers/slapd/rootdse.c @@ -25,6 +25,7 @@ static char *readonly_attributes[] = { "supportedldapversion", "supportedcontrol", "supportedextension", + "supportedfeatures", "supportedsaslmechanisms", "dataversion", "ref", @@ -190,6 +191,18 @@ read_root_dse( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *r charray_free(strs); } + /* supported features */ + attrlist_delete( &e->e_attrs, "supportedFeatures"); + if ( slapi_get_supported_features_copy( &strs ) == 0 + && strs != NULL ) { + for ( i = 0; strs[i] != NULL; ++i ) { + val.bv_val = strs[i]; + val.bv_len = strlen( strs[i] ); + attrlist_merge( &e->e_attrs, "supportedFeatures", vals ); + } + charray_free(strs); + } + /* supported sasl mechanisms */ attrlist_delete( &e->e_attrs, "supportedSASLMechanisms"); if (( strs = ids_sasl_listmech (pb)) != NULL ) { diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index d2b076b..5361973 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -5585,11 +5585,11 @@ LDAPControl * slapi_dup_control( LDAPControl *ctrl ); #define SLAPI_OPERATION_ANY 0xFFFFFFFFUL #define SLAPI_OPERATION_NONE 0x00000000UL int slapi_get_supported_controls_copy( char ***ctrloidsp, - unsigned long **ctrlopsp ); + unsigned long **ctrlopsp ); int slapi_build_control( char *oid, BerElement *ber, - char iscritical, LDAPControl **ctrlp ); + char iscritical, LDAPControl **ctrlp ); int slapi_build_control_from_berval( char *oid, struct berval *bvp, - char iscritical, LDAPControl **ctrlp ); + char iscritical, LDAPControl **ctrlp ); /* Given an array of controls e.g. LDAPControl **ctrls, add the given control to the end of the array, growing the array with realloc @@ -5615,6 +5615,13 @@ void slapi_add_controls( LDAPControl ***ctrlsp, LDAPControl **newctrls, int copy */ char **slapi_get_supported_extended_ops_copy( void ); +/* + * routines for dealing with supported features + */ + +#define LDAP_FEATURE_RFC3673_ALLOPERATIONAL "1.3.6.1.4.1.4203.1.5.1" + +int slapi_get_supported_features_copy( char ***ftroidsp ); /* * bind, including SASL @@ -7450,6 +7457,12 @@ char **slapi_str2charray_ext( char *str, char *brkstr, int allow_dups ); #endif #endif +/* + * As per rfc3673 + */ + +#define LDAP_ALL_OPERATIONAL_ATTRS "+" + #ifndef LDAP_SASL_EXTERNAL #define LDAP_SASL_EXTERNAL "EXTERNAL" /* TLS/SSL extension */ #endif -- 2.5.0