X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fsearch.c;h=ff9425bb5734c76d2c153f5d05906416ef094398;hb=01fbca597471f8be24c633c1c5154573b8070449;hp=e9f7fad4abdab0fc60bfefe4226920fc3297c979;hpb=a62249ed27b11d7c72517b9e54e7d175d2fa9967;p=openldap diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index e9f7fad4ab..ff9425bb57 100644 --- a/servers/slapd/back-ldap/search.c +++ b/servers/slapd/back-ldap/search.c @@ -1,38 +1,24 @@ /* search.c - ldap backend search function */ /* $OpenLDAP$ */ -/* - * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file - */ -/* This is an altered version */ -/* - * Copyright 1999, Howard Chu, All rights reserved. - * - * Permission is granted to anyone to use this software for any purpose - * on any computer system, and to alter it and redistribute it, subject - * to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits should appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits should appear in the documentation. - * - * 4. This notice may not be removed or altered. +/* This work is part of OpenLDAP Software . * + * Copyright 1999-2005 The OpenLDAP Foundation. + * Portions Copyright 1999-2003 Howard Chu. + * Portions Copyright 2000-2003 Pierangelo Masarati. + * All rights reserved. * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. * - * Copyright 2000, Pierangelo Masarati, All rights reserved. - * - * This software is being modified by Pierangelo Masarati. - * The previously reported conditions apply to the modified code as well. - * Changes in the original code are highlighted where required. - * Credits for the original code go to the author, Howard Chu. + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by the Howard Chu for inclusion + * in OpenLDAP Software and subsequently enhanced by Pierangelo + * Masarati. */ #include "portable.h" @@ -48,591 +34,733 @@ #undef ldap_debug /* silence a warning in ldap-int.h */ #include "../../../libraries/libldap/ldap-int.h" -static int ldap_send_entry( Backend *be, Operation *op, struct ldapconn *lc, - LDAPMessage *e, AttributeName *attrs, int attrsonly ); +#include "lutil.h" + +static int +ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, + struct berval *bdn ); + +/* + * Quick'n'dirty rewrite of filter in case of error, to deal with + * . + */ +static int +ldap_back_munge_filter( + Operation *op, + struct berval *filter ) +{ + struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; + + char *ptr; + int gotit = 0; + + Debug( LDAP_DEBUG_ARGS, "=> ldap_back_munge_filter \"%s\"\n", + filter->bv_val, 0, 0 ); + + for ( ptr = strstr( filter->bv_val, "(?=" ); + ptr; + ptr = strstr( ptr, "(?=" ) ) + { + static struct berval + bv_true = BER_BVC( "(?=true)" ), + bv_false = BER_BVC( "(?=false)" ), + bv_undefined = BER_BVC( "(?=undefined)" ), + bv_t = BER_BVC( "(&)" ), + bv_f = BER_BVC( "(|)" ), + bv_T = BER_BVC( "(objectClass=*)" ), + bv_F = BER_BVC( "(!(objectClass=*))" ); + struct berval *oldbv = NULL, + *newbv = NULL, + oldfilter = BER_BVNULL; + + if ( strncmp( ptr, bv_true.bv_val, bv_true.bv_len ) == 0 ) { + oldbv = &bv_true; + if ( li->flags & LDAP_BACK_F_SUPPORT_T_F ) { + newbv = &bv_t; + + } else { + newbv = &bv_T; + } + + } else if ( strncmp( ptr, bv_false.bv_val, bv_false.bv_len ) == 0 ) + { + oldbv = &bv_false; + if ( li->flags & LDAP_BACK_F_SUPPORT_T_F ) { + newbv = &bv_f; + + } else { + newbv = &bv_F; + } + + } else if ( strncmp( ptr, bv_undefined.bv_val, bv_undefined.bv_len ) == 0 ) + { + oldbv = &bv_undefined; + newbv = &bv_F; + + } else { + gotit = 0; + goto done; + } + + oldfilter = *filter; + if ( newbv->bv_len > oldbv->bv_len ) { + filter->bv_len += newbv->bv_len - oldbv->bv_len; + if ( filter->bv_val == op->ors_filterstr.bv_val ) { + filter->bv_val = op->o_tmpalloc( filter->bv_len + 1, + op->o_tmpmemctx ); + + AC_MEMCPY( filter->bv_val, op->ors_filterstr.bv_val, + op->ors_filterstr.bv_len + 1 ); + + } else { + filter->bv_val = op->o_tmprealloc( filter->bv_val, + filter->bv_len + 1, op->o_tmpmemctx ); + } + + ptr = filter->bv_val + ( ptr - oldfilter.bv_val ); + } + + AC_MEMCPY( &ptr[ newbv->bv_len ], + &ptr[ oldbv->bv_len ], + oldfilter.bv_len - ( ptr - filter->bv_val ) - oldbv->bv_len + 1 ); + AC_MEMCPY( ptr, newbv->bv_val, newbv->bv_len ); + + ptr += newbv->bv_len; + gotit = 1; + } + +done:; + Debug( LDAP_DEBUG_ARGS, "<= ldap_back_munge_filter \"%s\" (%d)\n", + filter->bv_val, gotit, 0 ); + + return gotit; +} int ldap_back_search( - Backend *be, - Connection *conn, - Operation *op, - struct berval *base, - struct berval *nbase, - int scope, - int deref, - int slimit, - int tlimit, - Filter *filter, - struct berval *filterstr, - AttributeName *attrs, - int attrsonly -) + Operation *op, + SlapReply *rs ) { - struct ldapinfo *li = (struct ldapinfo *) be->be_private; struct ldapconn *lc; struct timeval tv; - LDAPMessage *res, *e; - int count, rc = 0, msgid, sres = LDAP_SUCCESS; - char *match = NULL, *err = NULL; - char *mapped_filter = NULL, **mapped_attrs = NULL; - struct berval mbase; -#ifdef ENABLE_REWRITE - char *mmatch = NULL; - struct berval mfilter = { 0, NULL }; -#endif /* ENABLE_REWRITE */ - struct slap_limits_set *limit = NULL; - int isroot = 0; - BerVarray v2refs = NULL; - - lc = ldap_back_getconn(li, conn, op); - if ( !lc ) { - return( -1 ); + time_t stoptime; + LDAPMessage *res, + *e; + int rc = 0, + msgid; + struct berval match = BER_BVNULL, + filter = BER_BVNULL; + int i; + char **attrs = NULL; + int freetext = 0; + int do_retry = 1; + LDAPControl **ctrls = NULL; + + lc = ldap_back_getconn( op, rs, LDAP_BACK_SENDERR ); + if ( !lc || !ldap_back_dobind( lc, op, rs, LDAP_BACK_SENDERR ) ) { + return rs->sr_err; } /* - * controls are set in ldap_back_dobind() - * * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */ - if ( !ldap_back_dobind( lc, op ) ) { - return( -1 ); + + /* should we check return values? */ + if ( op->ors_deref != -1 ) { + ldap_set_option( lc->lc_ld, LDAP_OPT_DEREF, + (void *)&op->ors_deref ); } - /* if not root, get appropriate limits */ - if ( be_isroot( be, &op->o_ndn ) ) { - isroot = 1; + if ( op->ors_tlimit != SLAP_NO_LIMIT ) { + tv.tv_sec = op->ors_tlimit; + tv.tv_usec = 0; + stoptime = op->o_time + op->ors_tlimit; + } else { - ( void ) get_limits( be, &op->o_ndn, &limit ); + tv.tv_sec = 0; } - - /* if no time limit requested, rely on remote server limits */ - /* if requested limit higher than hard limit, abort */ - if ( !isroot && tlimit > limit->lms_t_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_t_hard == 0 - && limit->lms_t_soft > -1 - && tlimit > limit->lms_t_soft ) { - tlimit = limit->lms_t_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_t_hard > 0 ) { - send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED, - NULL, NULL, NULL, NULL ); - rc = 0; + + if ( op->ors_attrs ) { + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) + /* just count attrs */ ; + + attrs = ch_malloc( ( i + 1 )*sizeof( char * ) ); + if ( attrs == NULL ) { + rs->sr_err = LDAP_NO_MEMORY; + rc = -1; goto finish; } - - /* negative hard limit means no limit */ - } - /* if no size limit requested, rely on remote server limits */ - /* if requested limit higher than hard limit, abort */ - if ( !isroot && slimit > limit->lms_s_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_s_hard == 0 - && limit->lms_s_soft > -1 - && slimit > limit->lms_s_soft ) { - slimit = limit->lms_s_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_s_hard > 0 ) { - send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED, - NULL, NULL, NULL, NULL ); - rc = 0; - goto finish; + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) { + attrs[ i ] = op->ors_attrs[i].an_name.bv_val; } - - /* negative hard limit means no limit */ + attrs[ i ] = NULL; } - /* should we check return values? */ - if (deref != -1) - ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&deref); - if (tlimit != -1) - ldap_set_option( lc->ld, LDAP_OPT_TIMELIMIT, (void *)&tlimit); - if (slimit != -1) - ldap_set_option( lc->ld, LDAP_OPT_SIZELIMIT, (void *)&slimit); - - /* - * Rewrite the search base, if required - */ -#ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, "searchBase", - base->bv_val, conn, &mbase.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( mbase.bv_val == NULL ) { - mbase = *base; - } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchBase: \"%s\" -> \"%s\"\n", - base->bv_val, mbase.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s", - base->bv_val, mbase.bv_val, "" ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - NULL, "Operation not allowed", NULL, NULL ); - rc = -1; - goto finish; - - case REWRITE_REGEXEC_ERR: - send_ldap_result( conn, op, LDAP_OTHER, - NULL, "Rewrite error", NULL, NULL ); - rc = -1; + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { goto finish; } - - /* - * Rewrite the search filter, if required - */ - switch ( rewrite_session( li->rwinfo, "searchFilter", - filterstr->bv_val, conn, &mfilter.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( mfilter.bv_val == NULL || mfilter.bv_val[0] == '\0') { - if ( mfilter.bv_val != NULL ) { - free( mfilter.bv_val ); + + /* deal with filters */ + filter = op->ors_filterstr; +retry: + rs->sr_err = ldap_search_ext( lc->lc_ld, op->o_req_ndn.bv_val, + op->ors_scope, filter.bv_val, + attrs, op->ors_attrsonly, ctrls, NULL, + tv.tv_sec ? &tv : NULL, + op->ors_slimit, &msgid ); + + if ( rs->sr_err != LDAP_SUCCESS ) { +fail:; + switch ( rs->sr_err ) { + case LDAP_SERVER_DOWN: + if ( do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_DONTSEND ) ) { + goto retry; + } } - mfilter = *filterstr; - } else { - mfilter.bv_len = strlen( mfilter.bv_val ); - } + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); + ldap_back_freeconn( op, lc ); + lc = NULL; + goto finish; -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchFilter: \"%s\" -> \"%s\"\n", - filterstr->bv_val, mfilter.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, - "rw> searchFilter: \"%s\" -> \"%s\"\n%s", - filterstr->bv_val, mfilter.bv_val, "" ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, - NULL, "Operation not allowed", NULL, NULL ); - rc = -1; - goto finish; + case LDAP_FILTER_ERROR: + if ( ldap_back_munge_filter( op, &filter ) ) { + goto retry; + } - case REWRITE_REGEXEC_ERR: - send_ldap_result( conn, op, LDAP_OTHER, - NULL, "Rewrite error", NULL, NULL ); - rc = -1; - goto finish; - } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, base, &mbase, 0, 1 ); -#endif /* !ENABLE_REWRITE */ - - mapped_filter = ldap_back_map_filter(&li->at_map, &li->oc_map, -#ifdef ENABLE_REWRITE - &mfilter, -#else /* !ENABLE_REWRITE */ - filterstr, -#endif /* !ENABLE_REWRITE */ - 0); - if ( mapped_filter == NULL ) { -#ifdef ENABLE_REWRITE - mapped_filter = mfilter.bv_val; -#else /* !ENABLE_REWRITE */ - mapped_filter = filterstr->bv_val; -#endif /* !ENABLE_REWRITE */ - } - -#ifdef ENABLE_REWRITE - if ( mfilter.bv_val != filterstr->bv_val ) { - free( mfilter.bv_val ); - } -#endif /* ENABLE_REWRITE */ - - mapped_attrs = ldap_back_map_attrs(&li->at_map, attrs, 0); - if ( mapped_attrs == NULL && attrs) { - for (count=0; attrs[count].an_name.bv_val; count++); - mapped_attrs = ch_malloc( (count+1) * sizeof(char *)); - for (count=0; attrs[count].an_name.bv_val; count++) { - mapped_attrs[count] = attrs[count].an_name.bv_val; + /* invalid filters return success with no data */ + rs->sr_err = LDAP_SUCCESS; + rs->sr_text = NULL; + goto finish; + + default: + rs->sr_err = slap_map_api2result( rs ); + rs->sr_text = NULL; + goto finish; } - mapped_attrs[count] = NULL; - } - - msgid = ldap_search(lc->ld, mbase.bv_val, scope, mapped_filter, - mapped_attrs, attrsonly); - if ( msgid == -1 ) { -fail:; - rc = ldap_back_op_result(lc, op); - goto finish; } /* We pull apart the ber result, stuff it into a slapd entry, and * let send_search_entry stuff it back into ber format. Slow & ugly, * but this is necessary for version matching, and for ACL processing. */ - - for ( count=0, rc=0; - rc != -1; - rc = ldap_result(lc->ld, msgid, 0, &tv, &res)) + + for ( rc = 0; rc != -1; rc = ldap_result( lc->lc_ld, msgid, 0, &tv, &res ) ) { /* check for abandon */ - if (op->o_abandon) { - ldap_abandon(lc->ld, msgid); - rc = 0; + if ( op->o_abandon ) { + if ( rc > 0 ) { + ldap_msgfree( res ); + } + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); + rc = SLAPD_ABANDON; goto finish; } - if (rc == 0) { + if ( rc == 0 ) { tv.tv_sec = 0; tv.tv_usec = 100000; ldap_pvt_thread_yield(); - } else if (rc == LDAP_RES_SEARCH_ENTRY) { - e = ldap_first_entry(lc->ld,res); - if ( ldap_send_entry(be, op, lc, e, attrs, attrsonly) - == LDAP_SUCCESS ) { - count++; + /* check time limit */ + if ( op->ors_tlimit != SLAP_NO_LIMIT + && slap_get_time() > stoptime ) + { + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); + rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED; + goto finish; + } + + } else if ( rc == LDAP_RES_SEARCH_ENTRY ) { + Entry ent = { 0 }; + struct berval bdn = BER_BVNULL; + int abort = 0; + + do_retry = 0; + + e = ldap_first_entry( lc->lc_ld, res ); + rc = ldap_build_entry( op, e, &ent, &bdn ); + if ( rc == LDAP_SUCCESS ) { + rs->sr_entry = &ent; + rs->sr_attrs = op->ors_attrs; + rs->sr_operational_attrs = NULL; + rs->sr_flags = 0; + abort = send_search_entry( op, rs ); + if ( !BER_BVISNULL( &ent.e_name ) ) { + assert( ent.e_name.bv_val != bdn.bv_val ); + free( ent.e_name.bv_val ); + BER_BVZERO( &ent.e_name ); + } + if ( !BER_BVISNULL( &ent.e_nname ) ) { + free( ent.e_nname.bv_val ); + BER_BVZERO( &ent.e_nname ); + } + entry_clean( &ent ); + } + ldap_msgfree( res ); + if ( abort ) { + ldap_abandon_ext( lc->lc_ld, msgid, NULL, NULL ); + goto finish; } - ldap_msgfree(res); } else if ( rc == LDAP_RES_SEARCH_REFERENCE ) { char **references = NULL; - LDAPControl **ctrls = NULL; - BerVarray refs; - int cnt; - rc = ldap_parse_reference( lc->ld, res, - &references, &ctrls, 1 ); + do_retry = 0; + rc = ldap_parse_reference( lc->lc_ld, res, + &references, &rs->sr_ctrls, 1 ); if ( rc != LDAP_SUCCESS ) { continue; } - if ( references == NULL ) { - continue; - } + /* FIXME: there MUST be at least one */ + if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { + int cnt; - for ( cnt = 0; references[ cnt ]; cnt++ ) - /* NO OP */ ; - - refs = ch_calloc( cnt + 1, sizeof( struct berval ) ); + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; - for ( cnt = 0; references[ cnt ]; cnt++ ) { - refs[ cnt ].bv_val = references[ cnt ]; - refs[ cnt ].bv_len = strlen( references[ cnt ] ); - } + /* FIXME: there MUST be at least one */ + rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + ber_str2bv( references[ cnt ], 0, 0, &rs->sr_ref[ cnt ] ); + } + BER_BVZERO( &rs->sr_ref[ cnt ] ); - /* ignore return value by now */ - ( void )send_search_reference( be, conn, op, - NULL, refs, ctrls, &v2refs ); + /* ignore return value by now */ + ( void )send_search_reference( op, rs ); + + } else { + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_search: " + "got SEARCH_REFERENCE " + "with no referrals\n", + op->o_log_prefix, 0, 0 ); + } /* cleanup */ if ( references ) { ldap_value_free( references ); - ch_free( refs ); + ch_free( rs->sr_ref ); + rs->sr_ref = NULL; } - if ( ctrls ) { - ldap_controls_free( ctrls ); + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; } } else { - sres = ldap_result2error(lc->ld, res, 1); - sres = ldap_back_map_result(sres); - ldap_get_option(lc->ld, LDAP_OPT_ERROR_STRING, &err); - ldap_get_option(lc->ld, LDAP_OPT_MATCHED_DN, &match); + char **references = NULL; + + rc = ldap_parse_result( lc->lc_ld, res, &rs->sr_err, + &match.bv_val, (char **)&rs->sr_text, + &references, &rs->sr_ctrls, 1 ); + freetext = 1; + if ( rc != LDAP_SUCCESS ) { + rs->sr_err = rc; + } + rs->sr_err = slap_map_api2result( rs ); + + if ( references && references[ 0 ] && references[ 0 ][ 0 ] ) { + int cnt; + + if ( rs->sr_err != LDAP_REFERRAL ) { + /* FIXME: error */ + Debug( LDAP_DEBUG_ANY, + "%s ldap_back_search: " + "got referrals with %d\n", + op->o_log_prefix, + rs->sr_err, 0 ); + rs->sr_err = LDAP_REFERRAL; + } + + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; + + rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) ); + + for ( cnt = 0; references[ cnt ]; cnt++ ) { + /* duplicating ...*/ + ber_str2bv( references[ cnt ], 0, 1, &rs->sr_ref[ cnt ] ); + } + BER_BVZERO( &rs->sr_ref[ cnt ] ); + } + + if ( match.bv_val != NULL ) { + if ( match.bv_val[ 0 ] == '\0' ) { + LDAP_FREE( match.bv_val ); + BER_BVZERO( &match ); + } else { + match.bv_len = strlen( match.bv_val ); + } + } + + /* cleanup */ + if ( references ) { + ldap_value_free( references ); + } + rc = 0; break; } } - if (rc == -1) + if ( rc == -1 ) { + if ( do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, rs, LDAP_BACK_SENDERR ) ) { + goto retry; + } + } + rs->sr_err = LDAP_SERVER_DOWN; goto fail; + } -#ifdef ENABLE_REWRITE /* * Rewrite the matched portion of the search base, if required */ - if ( match != NULL ) { - switch ( rewrite_session( li->rwinfo, "matchedDn", - match, conn, &mmatch ) ) { - case REWRITE_REGEXEC_OK: - if ( mmatch == NULL ) { - mmatch = ( char * )match; - } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] matchedDn:" " \"%s\" -> \"%s\"\n", match, mmatch, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:" - " \"%s\" -> \"%s\"\n%s", - match, mmatch, "" ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - - case REWRITE_REGEXEC_ERR: - /* FIXME: no error, but no matched ... */ - mmatch = NULL; - break; - } + if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) { + rs->sr_matched = match.bv_val; + } + + if ( rs->sr_v2ref ) { + rs->sr_err = LDAP_REFERRAL; } - if ( v2refs ) { - sres = LDAP_REFERRAL; +finish:; + if ( rc != SLAPD_ABANDON ) { + send_ldap_result( op, rs ); } - send_search_result( conn, op, sres, - mmatch, err, v2refs, NULL, count ); + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); -#else /* !ENABLE_REWRITE */ - if ( v2refs ) { - sres = LDAP_REFERRAL; + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; } - send_search_result( conn, op, sres, - match, err, v2refs, NULL, count ); -#endif /* !ENABLE_REWRITE */ -finish:; - if ( match ) { -#ifdef ENABLE_REWRITE - if ( mmatch != match ) { - free( mmatch ); - } -#endif /* ENABLE_REWRITE */ - LDAP_FREE(match); + if ( match.bv_val ) { + rs->sr_matched = NULL; + LDAP_FREE( match.bv_val ); } - if ( err ) { - LDAP_FREE( err ); + + if ( !BER_BVISNULL( &filter ) && filter.bv_val != op->ors_filterstr.bv_val ) { + op->o_tmpfree( filter.bv_val, op->o_tmpmemctx ); } - if ( mapped_attrs ) { - ch_free( mapped_attrs ); + + if ( rs->sr_text ) { + if ( freetext ) { + LDAP_FREE( (char *)rs->sr_text ); + } + rs->sr_text = NULL; } - if ( mapped_filter != filterstr->bv_val ) { - ch_free( mapped_filter ); + + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; } - if ( mbase.bv_val != base->bv_val ) { - free( mbase.bv_val ); + + if ( attrs ) { + ch_free( attrs ); } - + + if ( lc != NULL ) { + ldap_back_release_conn( op, rs, lc ); + } + return rc; } static int -ldap_send_entry( - Backend *be, - Operation *op, - struct ldapconn *lc, - LDAPMessage *e, - AttributeName *attrs, - int attrsonly -) +ldap_build_entry( + Operation *op, + LDAPMessage *e, + Entry *ent, + struct berval *bdn ) { - struct ldapinfo *li = (struct ldapinfo *) be->be_private; - struct berval a, mapped; - Entry ent; - BerElement ber = *e->lm_ber; - Attribute *attr, **attrp; - struct berval dummy = { 0, NULL }; - struct berval *bv, bdn; - const char *text; - - if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) { - return LDAP_DECODING_ERROR; - } -#ifdef ENABLE_REWRITE + struct berval a; + BerElement ber = *e->lm_ber; + Attribute *attr, **attrp; + const char *text; + int last; - /* - * Rewrite the dn of the result, if needed - */ - switch ( rewrite_session( li->rwinfo, "searchResult", - bdn.bv_val, lc->conn, &ent.e_name.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( ent.e_name.bv_val == NULL ) { - ent.e_name = bdn; - } else { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchResult: \"%s\"" " -> \"%s\"\n", - bdn.bv_val, ent.e_dn, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> searchResult: \"%s\"" - " -> \"%s\"\n%s", bdn.bv_val, ent.e_dn, "" ); -#endif /* !NEW_LOGGING */ - ent.e_name.bv_len = strlen( ent.e_name.bv_val ); - } - break; - - case REWRITE_REGEXEC_ERR: - case REWRITE_REGEXEC_UNWILLING: - return LDAP_OTHER; + /* safe assumptions ... */ + assert( ent != NULL ); + BER_BVZERO( &ent->e_bv ); + + if ( ber_scanf( &ber, "{m{", bdn ) == LBER_ERROR ) { + return LDAP_DECODING_ERROR; } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, &bdn, &ent.e_name, 0, 0 ); -#endif /* !ENABLE_REWRITE */ /* * Note: this may fail if the target host(s) schema differs * from the one known to the meta, and a DN with unknown * attributes is returned. * - * FIXME: should we log anything, or delegate to dnNormalize2? + * FIXME: should we log anything, or delegate to dnNormalize? + */ + /* Note: if the distinguished values or the naming attributes + * change, should we massage them as well? */ - if ( dnNormalize2( NULL, &ent.e_name, &ent.e_nname ) != LDAP_SUCCESS ) { + if ( dnPrettyNormal( NULL, bdn, &ent->e_name, &ent->e_nname, + op->o_tmpmemctx ) != LDAP_SUCCESS ) + { return LDAP_INVALID_DN_SYNTAX; } - - ent.e_id = 0; - ent.e_attrs = 0; - ent.e_private = 0; - attrp = &ent.e_attrs; + + attrp = &ent->e_attrs; while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { - ldap_back_map(&li->at_map, &a, &mapped, 1); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') - continue; - attr = (Attribute *)ch_malloc( sizeof(Attribute) ); - if (attr == NULL) + int i; + slap_syntax_validate_func *validate; + slap_syntax_transform_func *pretty; + + attr = (Attribute *)ch_malloc( sizeof( Attribute ) ); + if ( attr == NULL ) { continue; + } attr->a_flags = 0; attr->a_next = 0; attr->a_desc = NULL; - if (slap_bv2ad(&mapped, &attr->a_desc, &text) != LDAP_SUCCESS) { - if (slap_bv2undef_ad(&mapped, &attr->a_desc, &text) - != LDAP_SUCCESS) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "slap_bv2undef_ad(%s): %s\n", mapped.bv_val, text, 0 ); -#else /* !NEW_LOGGING */ + if ( slap_bv2ad( &a, &attr->a_desc, &text ) + != LDAP_SUCCESS ) + { + if ( slap_bv2undef_ad( &a, &attr->a_desc, &text ) + != LDAP_SUCCESS ) + { Debug( LDAP_DEBUG_ANY, - "slap_bv2undef_ad(%s): " - "%s\n%s", mapped.bv_val, text, "" ); -#endif /* !NEW_LOGGING */ - ch_free(attr); + "slap_bv2undef_ad(%s): %s\n", + a.bv_val, text, 0 ); + ch_free( attr ); continue; } } /* no subschemaSubentry */ if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) { - ch_free(attr); + + /* + * We eat target's subschemaSubentry because + * a search for this value is likely not + * to resolve to the appropriate backend; + * later, the local subschemaSubentry is + * added. + */ + ( void )ber_scanf( &ber, "x" /* [W] */ ); + + ch_free( attr ); continue; } if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR - || attr->a_vals == NULL ) { + || attr->a_vals == NULL ) + { /* * Note: attr->a_vals can be null when using * values result filter */ - attr->a_vals = &dummy; - - } else if ( attr->a_desc == slap_schema.si_ad_objectClass - || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { - int i, last; - - for ( last = 0; attr->a_vals[last].bv_val; last++ ) ; - for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { - ldap_back_map(&li->oc_map, bv, &mapped, 1); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { - LBER_FREE(bv->bv_val); - bv->bv_val = NULL; - if (--last < 0) - break; - *bv = attr->a_vals[last]; - attr->a_vals[last].bv_val = NULL; - i--; - } else if ( mapped.bv_val != bv->bv_val ) { - /* - * FIXME: after LBER_FREEing - * the value is replaced by - * ch_alloc'ed memory - */ - LBER_FREE(bv->bv_val); - ber_dupbv( bv, &mapped ); - } + attr->a_vals = (struct berval *)&slap_dummy_bv; + last = 0; + + } else { + for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); last++ ) + /* just count vals */ ; + } + + validate = attr->a_desc->ad_type->sat_syntax->ssyn_validate; + pretty = attr->a_desc->ad_type->sat_syntax->ssyn_pretty; + + if ( !validate && !pretty ) { + attr->a_nvals = NULL; + attr_free( attr ); + goto next_attr; + } + + for ( i = 0; i < last; i++ ) { + struct berval pval; + int rc; + + if ( pretty ) { + rc = pretty( attr->a_desc->ad_type->sat_syntax, + &attr->a_vals[i], &pval, NULL ); + + } else { + rc = validate( attr->a_desc->ad_type->sat_syntax, + &attr->a_vals[i] ); } - /* - * It is necessary to try to rewrite attributes with - * dn syntax because they might be used in ACLs as - * members of groups; since ACLs are applied to the - * rewritten stuff, no dn-based subject clause could - * be used at the ldap backend side (see - * http://www.OpenLDAP.org/faq/data/cache/452.html) - * The problem can be overcome by moving the dn-based - * ACLs to the target directory server, and letting - * everything pass thru the ldap backend. - */ - } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid, - SLAPD_DN_SYNTAX ) == 0 ) { - int i; - for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++, i++ ) { - struct berval newval; - -#ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, - "searchResult", - bv->bv_val, - lc->conn, - &newval.bv_val )) { - case REWRITE_REGEXEC_OK: - /* left as is */ - if ( newval.bv_val == NULL ) { - break; - } - newval.bv_len = strlen( newval.bv_val ); -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchResult on attr=%s: \"%s\" -> \"%s\"\n", - attr->a_desc->ad_type->sat_cname.bv_val, - bv->bv_val, newval.bv_val ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, - "rw> searchResult on attr=%s: \"%s\" -> \"%s\"\n", - attr->a_desc->ad_type->sat_cname.bv_val, - bv->bv_val, newval.bv_val ); -#endif /* !NEW_LOGGING */ - free( bv->bv_val ); - *bv = newval; - break; - - case REWRITE_REGEXEC_UNWILLING: - - case REWRITE_REGEXEC_ERR: - /* - * FIXME: better give up, - * skip the attribute - * or leave it untouched? - */ - break; + if ( rc != LDAP_SUCCESS ) { + /* check if, by chance, it's an undefined objectClass */ + if ( attr->a_desc == slap_schema.si_ad_objectClass && + oc_bvfind_undef( &attr->a_vals[i] ) != NULL ) + { + ber_dupbv( &pval, &attr->a_vals[i] ); + + } else { + attr->a_nvals = NULL; + attr_free( attr ); + goto next_attr; } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, bv, &newval, 0, 0 ); - *bv = newval; -#endif /* !ENABLE_REWRITE */ + } + + if ( pretty ) { + LBER_FREE( attr->a_vals[i].bv_val ); + attr->a_vals[i] = pval; } } + if ( last && attr->a_desc->ad_type->sat_equality && + attr->a_desc->ad_type->sat_equality->smr_normalize ) + { + attr->a_nvals = ch_malloc( ( last + 1 )*sizeof( struct berval ) ); + for ( i = 0; i < last; i++ ) { + int rc; + + /* + * check that each value is valid per syntax + * and pretty if appropriate + */ + rc = attr->a_desc->ad_type->sat_equality->smr_normalize( + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + attr->a_desc->ad_type->sat_syntax, + attr->a_desc->ad_type->sat_equality, + &attr->a_vals[i], &attr->a_nvals[i], + NULL ); + + if ( rc != LDAP_SUCCESS ) { + BER_BVZERO( &attr->a_nvals[i] ); + ch_free( attr ); + goto next_attr; + } + } + BER_BVZERO( &attr->a_nvals[i] ); + + } else { + attr->a_nvals = attr->a_vals; + } *attrp = attr; attrp = &attr->a_next; + +next_attr:; } - send_search_entry( be, lc->conn, op, &ent, attrs, attrsonly, NULL ); - while (ent.e_attrs) { - attr = ent.e_attrs; - ent.e_attrs = attr->a_next; - if (attr->a_vals != &dummy) - ber_bvarray_free(attr->a_vals); - ch_free(attr); + + return LDAP_SUCCESS; +} + +/* return 0 IFF we can retrieve the entry with ndn + */ +int +ldap_back_entry_get( + Operation *op, + struct berval *ndn, + ObjectClass *oc, + AttributeDescription *at, + int rw, + Entry **ent +) +{ + struct ldapconn *lc; + int rc = 1, + do_not_cache; + struct berval bdn; + LDAPMessage *result = NULL, + *e = NULL; + char *gattr[3]; + char *filter = NULL; + SlapReply rs; + int do_retry = 1; + LDAPControl **ctrls = NULL; + + /* Tell getconn this is a privileged op */ + do_not_cache = op->o_do_not_cache; + op->o_do_not_cache = 1; + lc = ldap_back_getconn( op, &rs, LDAP_BACK_DONTSEND ); + if ( !lc || !ldap_back_dobind( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { + op->o_do_not_cache = do_not_cache; + return rs.sr_err; + } + op->o_do_not_cache = do_not_cache; + + if ( at ) { + if ( oc && at != slap_schema.si_ad_objectClass ) { + gattr[0] = slap_schema.si_ad_objectClass->ad_cname.bv_val; + gattr[1] = at->ad_cname.bv_val; + gattr[2] = NULL; + + } else { + gattr[0] = at->ad_cname.bv_val; + gattr[1] = NULL; + } + } + + if ( oc ) { + char *ptr; + + filter = ch_malloc( STRLENOF( "(objectclass=)" ) + + oc->soc_cname.bv_len + 1 ); + ptr = lutil_strcopy( filter, "(objectclass=" ); + ptr = lutil_strcopy( ptr, oc->soc_cname.bv_val ); + *ptr++ = ')'; + *ptr++ = '\0'; + } + + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( lc, op, &rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; } - if ( ent.e_dn && ( ent.e_dn != bdn.bv_val ) ) - free( ent.e_dn ); - if ( ent.e_ndn ) - free( ent.e_ndn ); +retry: + rc = ldap_search_ext_s( lc->lc_ld, ndn->bv_val, LDAP_SCOPE_BASE, filter, + at ? gattr : NULL, 0, ctrls, NULL, + LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result ); + if ( rc != LDAP_SUCCESS ) { + if ( rc == LDAP_SERVER_DOWN && do_retry ) { + do_retry = 0; + if ( ldap_back_retry( lc, op, &rs, LDAP_BACK_DONTSEND ) ) { + goto retry; + } + } + goto cleanup; + } - return LDAP_SUCCESS; + e = ldap_first_entry( lc->lc_ld, result ); + if ( e == NULL ) { + goto cleanup; + } + + *ent = ch_calloc( 1, sizeof( Entry ) ); + + rc = ldap_build_entry( op, e, *ent, &bdn ); + + if ( rc != LDAP_SUCCESS ) { + ch_free( *ent ); + *ent = NULL; + } + +cleanup: + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + + if ( result ) { + ldap_msgfree( result ); + } + + if ( filter ) { + ch_free( filter ); + } + + if ( lc != NULL ) { + ldap_back_release_conn( op, &rs, lc ); + } + + return rc; } +