X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldap%2Fsearch.c;h=ff9425bb5734c76d2c153f5d05906416ef094398;hb=01fbca597471f8be24c633c1c5154573b8070449;hp=5991d996a9d11e10b2fd227c1b3d9d8334024be6;hpb=cb33a9ff4404cedb8f8f134fcb38b83f250593d2;p=openldap diff --git a/servers/slapd/back-ldap/search.c b/servers/slapd/back-ldap/search.c index 5991d996a9..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" @@ -52,169 +38,211 @@ static int ldap_build_entry( Operation *op, LDAPMessage *e, Entry *ent, - struct berval *bdn, int flags ); -#define LDAP_BUILD_ENTRY_PRIVATE 0x01 -#define LDAP_BUILD_ENTRY_NORMALIZE 0x02 + 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 ); -static struct berval dummy = { 0, NULL }; + 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( - Operation *op, - SlapReply *rs ) + Operation *op, + SlapReply *rs ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; struct ldapconn *lc; struct timeval tv; - LDAPMessage *res, *e; - int count, rc = 0, msgid; - char *match = NULL; - char **mapped_attrs = NULL; - struct berval mbase; - struct berval mfilter = { 0, NULL }; - struct slap_limits_set *limit = NULL; - int isroot = 0; - - lc = ldap_back_getconn(op, rs); - 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; } /* * FIXME: in case of values return filter, we might want * to map attrs and maybe rewrite value */ - if ( !ldap_back_dobind( lc, op, rs ) ) { - return( -1 ); - } - /* if not root, get appropriate limits */ - if ( be_isroot( op->o_bd, &op->o_ndn ) ) { - isroot = 1; - } else { - ( void ) get_limits( op->o_bd, &op->o_ndn, &limit ); - } - - /* if no time limit requested, rely on remote server limits */ - /* if requested limit higher than hard limit, abort */ - if ( !isroot && op->oq_search.rs_tlimit > limit->lms_t_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_t_hard == 0 - && limit->lms_t_soft > -1 - && op->oq_search.rs_tlimit > limit->lms_t_soft ) { - op->oq_search.rs_tlimit = limit->lms_t_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_t_hard > 0 ) { - rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; - send_ldap_result( op, rs ); - rc = 0; - 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 && op->oq_search.rs_slimit > limit->lms_s_hard ) { - /* no hard limit means use soft instead */ - if ( limit->lms_s_hard == 0 - && limit->lms_s_soft > -1 - && op->oq_search.rs_slimit > limit->lms_s_soft ) { - op->oq_search.rs_slimit = limit->lms_s_soft; - - /* positive hard limit means abort */ - } else if ( limit->lms_s_hard > 0 ) { - rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED; - send_ldap_result( op, rs ); - rc = 0; - goto finish; - } - - /* negative hard limit means no limit */ + /* should we check return values? */ + if ( op->ors_deref != -1 ) { + ldap_set_option( lc->lc_ld, LDAP_OPT_DEREF, + (void *)&op->ors_deref ); } - /* should we check return values? */ - if (op->oq_search.rs_deref != -1) - ldap_set_option( lc->ld, LDAP_OPT_DEREF, (void *)&op->oq_search.rs_deref); - if (op->oq_search.rs_tlimit != -1) { - tv.tv_sec = op->oq_search.rs_tlimit; + 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 { tv.tv_sec = 0; } - /* - * Rewrite the search base, if required - */ -#ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, "searchBase", - op->o_req_dn.bv_val, op->o_conn, &mbase.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( mbase.bv_val == NULL ) { - mbase = op->o_req_dn; - } else { - mbase.bv_len = strlen( mbase.bv_val ); - } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchBase: \"%s\" -> \"%s\"\n", - op->o_req_dn.bv_val, mbase.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n%s", - op->o_req_dn.bv_val, mbase.bv_val, "" ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, - "Operation not allowed" ); - rc = -1; - goto finish; + if ( op->ors_attrs ) { + for ( i = 0; !BER_BVISNULL( &op->ors_attrs[i].an_name ); i++ ) + /* just count attrs */ ; - case REWRITE_REGEXEC_ERR: - send_ldap_error( op, rs, LDAP_OTHER, - "Rewrite error" ); - rc = -1; - goto finish; + attrs = ch_malloc( ( i + 1 )*sizeof( char * ) ); + 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; + } + attrs[ i ] = NULL; } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, &op->o_req_dn, &mbase, 0, 1 ); -#endif /* !ENABLE_REWRITE */ - -#ifdef ENABLE_REWRITE - rc = ldap_back_filter_map_rewrite_( li->rwinfo, op->o_conn, - &li->at_map, &li->oc_map, op->oq_search.rs_filter, &mfilter, - BACKLDAP_MAP ); -#else /* ! ENABLE_REWRITE */ - rc = ldap_back_filter_map_rewrite_( &li->at_map, &li->oc_map, - op->oq_search.rs_filter, &mfilter, BACKLDAP_MAP ); -#endif /* ! ENABLE_REWRITE */ - - if ( rc ) { - rc = -1; + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( lc, op, rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { goto finish; } - mapped_attrs = ldap_back_map_attrs(&li->at_map, op->oq_search.rs_attrs, BACKLDAP_MAP); - if ( mapped_attrs == NULL && op->oq_search.rs_attrs) { - for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++); - mapped_attrs = ch_malloc( (count+1) * sizeof(char *)); - for (count=0; op->oq_search.rs_attrs[count].an_name.bv_val; count++) { - mapped_attrs[count] = op->oq_search.rs_attrs[count].an_name.bv_val; - } - mapped_attrs[count] = NULL; - } + /* 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 ); - rs->sr_err = ldap_search_ext(lc->ld, mbase.bv_val, op->oq_search.rs_scope, mfilter.bv_val, - mapped_attrs, op->oq_search.rs_attrsonly, op->o_ctrls, NULL, tv.tv_sec ? &tv - : NULL, op->oq_search.rs_slimit, &msgid); if ( rs->sr_err != LDAP_SUCCESS ) { fail:; - rc = ldap_back_op_result(lc, op, rs, msgid, 0); - goto finish; + 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; + } + } + rc = ldap_back_op_result( lc, op, rs, msgid, LDAP_BACK_DONTSEND ); + ldap_back_freeconn( op, lc ); + lc = NULL; + goto finish; + + case LDAP_FILTER_ERROR: + if ( ldap_back_munge_filter( op, &filter ) ) { + goto retry; + } + + /* 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; + } } /* We pull apart the ber result, stuff it into a slapd entry, and @@ -222,80 +250,100 @@ fail:; * but this is necessary for version matching, and for ACL processing. */ - for ( 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) { - Entry ent; - struct berval bdn; - e = ldap_first_entry(lc->ld,res); - if ( ldap_build_entry(op, e, &ent, &bdn, - LDAP_BUILD_ENTRY_PRIVATE) == LDAP_SUCCESS ) { + /* 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->oq_search.rs_attrs; - send_search_entry( op, rs ); - while (ent.e_attrs) { - Attribute *a; - BerVarray v; - - a = ent.e_attrs; - ent.e_attrs = a->a_next; - - v = a->a_vals; - if (a->a_vals != &dummy) - ber_bvarray_free(a->a_vals); -#ifdef SLAP_NVALUES - if (a->a_nvals != v) - ber_bvarray_free(a->a_nvals); -#endif - ch_free(a); + 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 ( ent.e_dn && ( ent.e_dn != bdn.bv_val ) ) - free( ent.e_dn ); - if ( ent.e_ndn ) - free( ent.e_ndn ); + 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; - int cnt; - rc = ldap_parse_reference( lc->ld, res, + 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 */ ; - - rs->sr_ref = ch_calloc( cnt + 1, sizeof( struct berval ) ); + for ( cnt = 0; references[ cnt ]; cnt++ ) + /* NO OP */ ; - for ( cnt = 0; references[ cnt ]; cnt++ ) { - rs->sr_ref[ cnt ].bv_val = references[ cnt ]; - rs->sr_ref[ cnt ].bv_len = strlen( references[ cnt ] ); - } + /* FIXME: there MUST be at least one */ + rs->sr_ref = ch_malloc( ( cnt + 1 ) * sizeof( struct berval ) ); - /* ignore return value by now */ - ( void )send_search_reference( op, rs ); + 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( 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 ) { @@ -310,191 +358,194 @@ fail:; } } else { - rc = ldap_parse_result(lc->ld, res, &rs->sr_err, &match, - (char **)&rs->sr_text, NULL, NULL, 1); - if (rc != LDAP_SUCCESS ) rs->sr_err = rc; - rs->sr_err = ldap_back_map_result(rs); + 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, op->o_conn, (char **)&rs->sr_matched ) ) { - case REWRITE_REGEXEC_OK: - if ( rs->sr_matched == NULL ) { - rs->sr_matched = ( char * )match; - } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] matchedDn:" " \"%s\" -> \"%s\"\n", match, rs->sr_matched, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> matchedDn:" - " \"%s\" -> \"%s\"\n%s", - match, rs->sr_matched, "" ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - - case REWRITE_REGEXEC_ERR: - /* FIXME: no error, but no matched ... */ - rs->sr_matched = NULL; - break; - } + if ( !BER_BVISNULL( &match ) && !BER_BVISEMPTY( &match ) ) { + rs->sr_matched = match.bv_val; } -#else /* !ENABLE_REWRITE */ - if ( match != NULL ) { - struct berval dn, mdn; - ber_str2bv(match, 0, 0, &dn); - ldap_back_dn_massage(li, &dn, &mdn, 0, 0); - rs->sr_matched = mdn.bv_val; - } -#endif /* !ENABLE_REWRITE */ if ( rs->sr_v2ref ) { rs->sr_err = LDAP_REFERRAL; } - send_ldap_result( op, rs ); finish:; - if ( match ) { - if ( rs->sr_matched != match ) { - free( (char *)rs->sr_matched ); - } + if ( rc != SLAPD_ABANDON ) { + send_ldap_result( op, rs ); + } + + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + + if ( rs->sr_ctrls ) { + ldap_controls_free( rs->sr_ctrls ); + rs->sr_ctrls = NULL; + } + + if ( match.bv_val ) { rs->sr_matched = NULL; - LDAP_FREE(match); + LDAP_FREE( match.bv_val ); + } + + if ( !BER_BVISNULL( &filter ) && filter.bv_val != op->ors_filterstr.bv_val ) { + op->o_tmpfree( filter.bv_val, op->o_tmpmemctx ); } + if ( rs->sr_text ) { - LDAP_FREE( (char *)rs->sr_text ); + if ( freetext ) { + LDAP_FREE( (char *)rs->sr_text ); + } rs->sr_text = NULL; } - if ( mapped_attrs ) { - ch_free( mapped_attrs ); + + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; } - if ( mfilter.bv_val != op->oq_search.rs_filterstr.bv_val ) { - ch_free( mfilter.bv_val ); + + if ( attrs ) { + ch_free( attrs ); } - if ( mbase.bv_val != op->o_req_dn.bv_val ) { - free( mbase.bv_val ); + + if ( lc != NULL ) { + ldap_back_release_conn( op, rs, lc ); } - + return rc; } static int ldap_build_entry( - Operation *op, - LDAPMessage *e, - Entry *ent, - struct berval *bdn, - int flags -) + Operation *op, + LDAPMessage *e, + Entry *ent, + struct berval *bdn ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; - struct berval a, mapped; - BerElement ber = *e->lm_ber; - Attribute *attr, **attrp; - struct berval *bv; - const char *text; - int last; - int private = flags & LDAP_BUILD_ENTRY_PRIVATE; -#ifdef SLAP_NVALUES - int normalize = flags & LDAP_BUILD_ENTRY_NORMALIZE; -#endif /* SLAP_NVALUES */ + struct berval a; + BerElement ber = *e->lm_ber; + Attribute *attr, **attrp; + const char *text; + int last; /* safe assumptions ... */ - assert( ent ); - ent->e_bv.bv_val = NULL; + assert( ent != NULL ); + BER_BVZERO( &ent->e_bv ); if ( ber_scanf( &ber, "{m{", bdn ) == LBER_ERROR ) { return LDAP_DECODING_ERROR; } -#ifdef ENABLE_REWRITE - - /* - * Rewrite the dn of the result, if needed - */ - switch ( rewrite_session( li->rwinfo, "searchResult", - bdn->bv_val, op->o_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; - } -#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? */ - if ( dnNormalize2( NULL, &ent->e_name, &ent->e_nname ) != LDAP_SUCCESS ) { + /* Note: if the distinguished values or the naming attributes + * change, should we massage them as well? + */ + 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; while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) { - ldap_back_map(&li->at_map, &a, &mapped, BACKLDAP_REMAP); - 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 ) { - BerVarray vals; /* * We eat target's subschemaSubentry because @@ -505,156 +556,102 @@ ldap_build_entry( */ ( void )ber_scanf( &ber, "x" /* [W] */ ); - ch_free(attr); + 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 */ - if (private) { - attr->a_vals = &dummy; - } else { - attr->a_vals = ch_malloc(sizeof(struct berval)); - attr->a_vals->bv_val = NULL; - attr->a_vals->bv_len = 0; - } + attr->a_vals = (struct berval *)&slap_dummy_bv; last = 0; + } else { - for ( last = 0; attr->a_vals[last].bv_val; last++ ); + for ( last = 0; !BER_BVISNULL( &attr->a_vals[ last ] ); last++ ) + /* just count vals */ ; } - if ( last == 0 ) { - /* empty */ - } else if ( attr->a_desc == slap_schema.si_ad_objectClass - || attr->a_desc == slap_schema.si_ad_structuralObjectClass ) { - for ( bv = attr->a_vals; bv->bv_val; bv++ ) { - ldap_back_map(&li->oc_map, bv, &mapped, - BACKLDAP_REMAP); - 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; - bv--; - - } 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 ); - } + + 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 ) { - for ( bv = attr->a_vals; bv->bv_val; bv++ ) { - struct berval newval; - -#ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, - "searchResult", - bv->bv_val, - op->o_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: - LBER_FREE(bv->bv_val); - bv->bv_val = NULL; - if (--last < 0) - goto next_attr; - *bv = attr->a_vals[last]; - attr->a_vals[last].bv_val = NULL; - bv--; - break; - - case REWRITE_REGEXEC_ERR: - /* - * FIXME: better give up, - * skip the attribute - * or leave it untouched? - */ - break; - } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, bv, &newval, 0, 0 ); - if ( bv->bv_val != newval.bv_val ) { - LBER_FREE( bv->bv_val ); + 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; } - *bv = newval; -#endif /* !ENABLE_REWRITE */ } - } -next_attr:; + if ( pretty ) { + LBER_FREE( attr->a_vals[i].bv_val ); + attr->a_vals[i] = pval; + } + } -#ifdef SLAP_NVALUES - if ( normalize ) { - if ( last && attr->a_desc->ad_type->sat_equality && - attr->a_desc->ad_type->sat_equality->smr_normalize ) { - int i; - - attr->a_nvals = ch_malloc((last+1)*sizeof(struct berval)); - for (i=0; ia_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] ); + 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; } - attr->a_nvals[i].bv_val = NULL; - attr->a_nvals[i].bv_len = 0; - } else { - attr->a_nvals = attr->a_vals; } + BER_BVZERO( &attr->a_nvals[i] ); + } else { - attr->a_nvals = NULL; + attr->a_nvals = attr->a_vals; } -#endif *attrp = attr; attrp = &attr->a_next; + +next_attr:; } - /* make sure it's free'able */ - if (!private && ent->e_name.bv_val == bdn->bv_val) - ber_dupbv( &ent->e_name, bdn ); + return LDAP_SUCCESS; } @@ -662,129 +659,108 @@ next_attr:; */ int ldap_back_entry_get( - Operation *op, - struct berval *ndn, - ObjectClass *oc, - AttributeDescription *at, - int rw, - Entry **ent + Operation *op, + struct berval *ndn, + ObjectClass *oc, + AttributeDescription *at, + int rw, + Entry **ent ) { - struct ldapinfo *li = (struct ldapinfo *) op->o_bd->be_private; struct ldapconn *lc; - int rc = 1, is_oc; - struct berval mapped = { 0, NULL }, bdn, mdn; - LDAPMessage *result = NULL, *e = NULL; - char *gattr[3]; - char *filter = NULL; - Connection *oconn; - SlapReply rs; + 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 */ - is_oc = op->o_do_not_cache; + do_not_cache = op->o_do_not_cache; op->o_do_not_cache = 1; - lc = ldap_back_getconn(op, &rs); - oconn = op->o_conn; - op->o_conn = NULL; - if ( !lc || !ldap_back_dobind(lc, op, &rs) ) { - op->o_do_not_cache = is_oc; - op->o_conn = oconn; - return 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 = is_oc; - op->o_conn = oconn; + 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; - /* - * Rewrite the search base, if required - */ -#ifdef ENABLE_REWRITE - switch ( rewrite_session( li->rwinfo, "searchBase", - ndn->bv_val, op->o_conn, &mdn.bv_val ) ) { - case REWRITE_REGEXEC_OK: - if ( mdn.bv_val == NULL ) { - mdn = *ndn; } else { - mdn.bv_len = strlen( mdn.bv_val ); + gattr[0] = at->ad_cname.bv_val; + gattr[1] = NULL; } - -#ifdef NEW_LOGGING - LDAP_LOG( BACK_LDAP, DETAIL1, - "[rw] searchBase: \"%s\" -> \"%s\"\n", - ndn->bv_val, mdn.bv_val, 0 ); -#else /* !NEW_LOGGING */ - Debug( LDAP_DEBUG_ARGS, "rw> searchBase: \"%s\" -> \"%s\"\n", - ndn->bv_val, mdn.bv_val, 0 ); -#endif /* !NEW_LOGGING */ - break; - - case REWRITE_REGEXEC_UNWILLING: - case REWRITE_REGEXEC_ERR: - return 1; } -#else /* !ENABLE_REWRITE */ - ldap_back_dn_massage( li, ndn, &mdn, 0, 1 ); -#endif /* !ENABLE_REWRITE */ + if ( oc ) { + char *ptr; - ldap_back_map(&li->at_map, &at->ad_cname, &mapped, BACKLDAP_MAP); - if (mapped.bv_val == NULL || mapped.bv_val[0] == '\0') { - rc = 1; - goto cleanup; - } - - is_oc = (strcasecmp("objectclass", mapped.bv_val) == 0); - if (oc && !is_oc) { - gattr[0] = "objectclass"; - gattr[1] = mapped.bv_val; - gattr[2] = NULL; - } else { - gattr[0] = mapped.bv_val; - gattr[1] = NULL; - } - if (oc) { - char *ptr; - ldap_back_map(&li->oc_map, &oc->soc_cname, &mapped, - BACKLDAP_MAP); - filter = ch_malloc(sizeof("(objectclass=)") + mapped.bv_len); - ptr = lutil_strcopy(filter, "(objectclass="); - ptr = lutil_strcopy(ptr, mapped.bv_val); + 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'; } - - if (ldap_search_ext_s(lc->ld, mdn.bv_val, LDAP_SCOPE_BASE, filter, - gattr, 0, NULL, NULL, LDAP_NO_LIMIT, - LDAP_NO_LIMIT, &result) != LDAP_SUCCESS) - { + + ctrls = op->o_ctrls; + rc = ldap_back_proxy_authz_ctrl( lc, op, &rs, &ctrls ); + if ( rc != LDAP_SUCCESS ) { + goto cleanup; + } + +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; } - if ((e = ldap_first_entry(lc->ld, result)) == NULL) { + e = ldap_first_entry( lc->lc_ld, result ); + if ( e == NULL ) { goto cleanup; } - *ent = ch_calloc(1,sizeof(Entry)); + *ent = ch_calloc( 1, sizeof( Entry ) ); - rc = ldap_build_entry(op, e, *ent, &bdn, LDAP_BUILD_ENTRY_NORMALIZE); + rc = ldap_build_entry( op, e, *ent, &bdn ); - if (rc != LDAP_SUCCESS) { - ch_free(*ent); + if ( rc != LDAP_SUCCESS ) { + ch_free( *ent ); *ent = NULL; } cleanup: - if (result) { - ldap_msgfree(result); + (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls ); + + if ( result ) { + ldap_msgfree( result ); } if ( filter ) { ch_free( filter ); } - if ( mdn.bv_val != ndn->bv_val ) { - ch_free( mdn.bv_val ); + if ( lc != NULL ) { + ldap_back_release_conn( op, &rs, lc ); } - return(rc); + return rc; }