diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 80e0bce7ac025bd9de2947f2028f2dcb8f76871f..43dec6df8ec467ded3f9c0dcbe4697bf034cd188 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -446,6 +446,20 @@ upon StartTLS operation receipt. disallows the StartTLS operation if authenticated (see also .BR tls_2_anon ). .TP +.B olcExtraAttrs: <attr> +Lists what attributes need to be added to search requests. +Local storage backends return the entire entry to the frontend. +The frontend takes care of only returning the requested attributes +that are allowed by ACLs. +However, features like access checking and so may need specific +attributes that are not automatically returned by remote storage +backends, like proxy backends and so on. +.B <attr> +is an attribute that is needed for internal purposes +and thus always needs to be collected, even when not explicitly +requested by clients. +This attribute is multi-valued. +.TP .B olcGentleHUP: { TRUE | FALSE } A SIGHUP signal will only cause a 'gentle' shutdown-attempt: .B Slapd diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index b28a2ebc5020d6afd3a2f3af6b164d23f247071a..dd6899bcea0622c95c97135a7a32d34b535d9451 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1278,6 +1278,19 @@ by default. See the manual page for more details on ACL requirements for Add operations. .TP +.B extra_attrs <attrlist> +Lists what attributes need to be added to search requests. +Local storage backends return the entire entry to the frontend. +The frontend takes care of only returning the requested attributes +that are allowed by ACLs. +However, features like access checking and so may need specific +attributes that are not automatically returned by remote storage +backends, like proxy backends and so on. +.B <attrlist> +is a list of attributes that are needed for internal purposes +and thus always need to be collected, even when not explicitly +requested by clients. +.TP .B hidden on | off Controls whether the database will be used to answer queries. A database that is hidden will never be diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 0120640e6d537801c78a8b4087795114250999a3..f5c9d30e7b4e12aa4a138aaa6544defcf64e664b 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -141,7 +141,7 @@ ldap_back_search( msgid; struct berval match = BER_BVNULL, filter = BER_BVNULL; - int i; + int i, x; char **attrs = NULL; int freetext = 0, filter_undef = 0; int do_retry = 1, dont_retry = 0; @@ -169,22 +169,48 @@ ldap_back_search( LDAP_BACK_TV_SET( &tv ); } + i = 0; if ( op->ors_attrs ) { - for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) + for ( ; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) /* just count attrs */ ; + } + + x = 0; + if ( op->o_bd->be_extra_anlist ) { + for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) + /* just count attrs */ ; + } - attrs = op->o_tmpalloc( ( i + 1 )*sizeof( char * ), + if ( i > 0 || x > 0 ) { + int j = 0; + + attrs = op->o_tmpalloc( ( i + x + 1 )*sizeof( char * ), op->o_tmpmemctx ); if ( attrs == NULL ) { rs->sr_err = LDAP_NO_MEMORY; rc = -1; goto finish; } - - for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) { - attrs[ i ] = op->ors_attrs[i].an_name.bv_val; + + if ( i > 0 ) { + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++, j++ ) { + attrs[ j ] = op->ors_attrs[i].an_name.bv_val; + } + } + + if ( x > 0 ) { + for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++, j++ ) { + if ( op->o_bd->be_extra_anlist[x].an_desc && + ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, op->ors_attrs ) ) + { + continue; + } + + attrs[ j ] = op->o_bd->be_extra_anlist[x].an_name.bv_val; + } } - attrs[ i ] = NULL; + + attrs[ j ] = NULL; } ctrls = op->o_ctrls; diff --git a/servers/slapd/back-meta/back-meta.h b/servers/slapd/back-meta/back-meta.h index 0aa7304a3974875d5508d5de9059b4128943927b..3f98381350073738de8a142cbd83cdfa2b64b975 100644 --- a/servers/slapd/back-meta/back-meta.h +++ b/servers/slapd/back-meta/back-meta.h @@ -118,11 +118,11 @@ ldap_back_map_filter( int ldap_back_map_attrs( + Operation *op, struct ldapmap *at_map, AttributeName *a, int remap, - char ***mapped_attrs, - void *memctx ); + char ***mapped_attrs ); extern int ldap_back_map_config( struct ldapmap *oc_map, diff --git a/servers/slapd/back-meta/map.c b/servers/slapd/back-meta/map.c index 0bdb1f765a123c66e29122a06d5d690004b0f33e..7bb172469b7362a308d468688d1351765d9887d3 100644 --- a/servers/slapd/back-meta/map.c +++ b/servers/slapd/back-meta/map.c @@ -171,42 +171,73 @@ ldap_back_map ( struct ldapmap *map, struct berval *s, struct berval *bv, int ldap_back_map_attrs( + Operation *op, struct ldapmap *at_map, AttributeName *an, int remap, - char ***mapped_attrs, - void *memctx ) + char ***mapped_attrs ) { - int i, j; + int i, x, j; char **na; struct berval mapped; - if ( an == NULL ) { + if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) { *mapped_attrs = NULL; return LDAP_SUCCESS; } - for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) - /* */ ; + i = 0; + if ( an != NULL ) { + for ( ; !BER_BVISNULL( &an[i].an_name ); i++ ) + /* */ ; + } + + x = 0; + if ( op->o_bd->be_extra_anlist != NULL ) { + for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) + /* */ ; + } - na = (char **)ber_memcalloc_x( i + 1, sizeof(char *), memctx ); + assert( i > 0 || x > 0 ); + + na = (char **)ber_memcalloc_x( i + x + 1, sizeof(char *), op->o_tmpmemctx ); if ( na == NULL ) { *mapped_attrs = NULL; return LDAP_NO_MEMORY; } - for ( i = j = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) { - ldap_back_map( at_map, &an[i].an_name, &mapped, remap ); - if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) { - na[j++] = mapped.bv_val; + j = 0; + if ( i > 0 ) { + for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) { + ldap_back_map( at_map, &an[i].an_name, &mapped, remap ); + if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) { + na[j++] = mapped.bv_val; + } + } + } + + if ( x > 0 ) { + for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) { + if ( op->o_bd->be_extra_anlist[x].an_desc && + ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, an ) ) + { + continue; + } + + ldap_back_map( at_map, &op->o_bd->be_extra_anlist[x].an_name, &mapped, remap ); + if ( !BER_BVISNULL( &mapped ) && !BER_BVISEMPTY( &mapped ) ) { + na[j++] = mapped.bv_val; + } } } - if ( j == 0 && i != 0 ) { + + if ( j == 0 && ( i > 0 || x > 0 ) ) { na[j++] = LDAP_NO_ATTRS; } na[j] = NULL; *mapped_attrs = na; + return LDAP_SUCCESS; } diff --git a/servers/slapd/back-meta/search.c b/servers/slapd/back-meta/search.c index a187939159105670b1af881a381dd34701a408f8..f4135fe2aba22549a91946805f7bbeebf612c3a3 100644 --- a/servers/slapd/back-meta/search.c +++ b/servers/slapd/back-meta/search.c @@ -603,9 +603,8 @@ meta_back_search_start( /* * Maps required attributes */ - rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at, - op->ors_attrs, BACKLDAP_MAP, &mapped_attrs, - op->o_tmpmemctx ); + rc = ldap_back_map_attrs( op, &mt->mt_rwmap.rwm_at, + op->ors_attrs, BACKLDAP_MAP, &mapped_attrs ); if ( rc != LDAP_SUCCESS ) { /* * this target is no longer candidate diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 0982a22485d7e2f78b5084b09c6ba51f43e54574..006c47370e97297b14fc0de87d38d3d13e155b85 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -464,6 +464,9 @@ void backend_destroy_one( BackendDB *bd, int dynamic ) } acl_destroy( bd->be_acl ); limits_destroy( bd->be_limits ); + if ( bd->be_extra_anlist ) { + anlist_free( bd->be_extra_anlist, 1, NULL ); + } if ( !BER_BVISNULL( &bd->be_update_ndn ) ) { ch_free( bd->be_update_ndn.bv_val ); } diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 42861ec1873b7190e1162b701658bccefa84de85..006647bf23f0ea76d5db4c4bc64b9098a9ee64c7 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -135,6 +135,7 @@ static ConfigDriver config_referral; static ConfigDriver config_loglevel; static ConfigDriver config_updatedn; static ConfigDriver config_updateref; +static ConfigDriver config_extra_attrs; static ConfigDriver config_include; static ConfigDriver config_obsolete; #ifdef HAVE_TLS @@ -366,6 +367,10 @@ static ConfigTable config_back_cf_table[] = { "SUBSTR caseIgnoreSubstringsMatch " "SYNTAX OMsDirectoryString X-ORDERED 'VALUES' )", NULL, NULL }, + { "extra_attrs", "attrlist", 2, 2, 0, ARG_DB|ARG_MAGIC, + &config_extra_attrs, "( OLcfgDbAt:0.20 NAME 'olcExtraAttrs' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { "gentlehup", "on|off", 2, 2, 0, #ifdef SIGHUP ARG_ON_OFF, &global_gentlehup, @@ -837,7 +842,7 @@ static ConfigOCs cf_ocs[] = { "olcReplogFile $ olcRequires $ olcRestrict $ olcRootDN $ olcRootPW $ " "olcSchemaDN $ olcSecurity $ olcSizeLimit $ olcSyncUseSubentry $ olcSyncrepl $ " "olcTimeLimit $ olcUpdateDN $ olcUpdateRef $ olcMirrorMode $ " - "olcMonitoring ) )", + "olcMonitoring $ olcExtraAttrs ) )", Cft_Database, NULL, cfAddDatabase }, { "( OLcfgGlOc:5 " "NAME 'olcOverlayConfig' " @@ -3174,6 +3179,58 @@ config_requires(ConfigArgs *c) { return(0); } +static int +config_extra_attrs(ConfigArgs *c) +{ + assert( c->be != NULL ); + + if ( c->op == SLAP_CONFIG_EMIT ) { + int i; + + if ( c->be->be_extra_anlist == NULL ) { + return 1; + } + + for ( i = 0; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) { + value_add_one( &c->rvalue_vals, &c->be->be_extra_anlist[i].an_name ); + } + + } else if ( c->op == LDAP_MOD_DELETE ) { + if ( c->be->be_extra_anlist == NULL ) { + return 1; + } + + if ( c->valx < 0 ) { + anlist_free( c->be->be_extra_anlist, 1, NULL ); + c->be->be_extra_anlist = NULL; + + } else { + int i; + + for ( i = 0; i < c->valx && !BER_BVISNULL( &c->be->be_extra_anlist[i + 1].an_name ); i++ ) + ; + + if ( BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ) ) { + return 1; + } + + ch_free( c->be->be_extra_anlist[i].an_name.bv_val ); + + for ( ; !BER_BVISNULL( &c->be->be_extra_anlist[i].an_name ); i++ ) { + c->be->be_extra_anlist[i] = c->be->be_extra_anlist[i + 1]; + } + } + + } else { + c->be->be_extra_anlist = str2anlist( c->be->be_extra_anlist, c->argv[1], " ,\t" ); + if ( c->be->be_extra_anlist == NULL ) { + return 1; + } + } + + return 0; +} + static slap_verbmasks *loglevel_ops; static int diff --git a/servers/slapd/overlays/rwmmap.c b/servers/slapd/overlays/rwmmap.c index d3c8c19a1dd316f472f7756969e8387156886bda..5141e6714a9463de3b4bc15fc6911ad62fe9da91 100644 --- a/servers/slapd/overlays/rwmmap.c +++ b/servers/slapd/overlays/rwmmap.c @@ -186,19 +186,30 @@ rwm_map_attrnames( AttributeName **anp, int remap ) { - int i, j; + int i, j, x; assert( anp != NULL ); *anp = NULL; - if ( an == NULL ) { + if ( an == NULL && op->o_bd->be_extra_anlist == NULL ) { return LDAP_SUCCESS; } - for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) - /* just count */ ; - *anp = op->o_tmpalloc( ( i + 1 )* sizeof( AttributeName ), + i = 0; + if ( an != NULL ) { + for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) + /* just count */ ; + } + + x = 0; + if ( op->o_bd->be_extra_anlist ) { + for ( ; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) + /* just count */ ; + } + + assert( i > 0 || x > 0 ); + *anp = op->o_tmpalloc( ( i + x + 1 )* sizeof( AttributeName ), op->o_tmpmemctx ); if ( *anp == NULL ) { return LDAP_NO_MEMORY; @@ -321,7 +332,22 @@ rwm_map_attrnames( } } - if ( j == 0 && i != 0 ) { + if ( op->o_bd->be_extra_anlist != NULL ) { + /* we assume be_extra_anlist are already mapped */ + for ( x = 0; !BER_BVISNULL( &op->o_bd->be_extra_anlist[x].an_name ); x++ ) { + BER_BVZERO( &(*anp)[j].an_name ); + if ( op->o_bd->be_extra_anlist[x].an_desc && + ad_inlist( op->o_bd->be_extra_anlist[x].an_desc, *anp ) ) + { + continue; + } + + (*anp)[j] = op->o_bd->be_extra_anlist[x]; + j++; + } + } + + if ( j == 0 && ( i != 0 || x != 0 ) ) { memset( &(*anp)[0], 0, sizeof( AttributeName ) ); (*anp)[0].an_name = *slap_bv_no_attrs; j = 1; diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 3ebc10a7d20719675fe1ffad4b16cd5ed6885124..9d524c6cbc73fe9304377a7556eaf178ef111e31 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1939,6 +1939,7 @@ struct BackendDB { struct slap_limits **be_limits; /* regex-based size and time limits */ AccessControl *be_acl; /* access control list for this backend */ slap_access_t be_dfltaccess; /* access given if no acl matches */ + AttributeName *be_extra_anlist; /* attributes that need to be added to search requests (ITS#6513) */ /* Replica Information */ struct berval be_update_ndn; /* allowed to make changes (in replicas) */