X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-sql%2Fsearch.c;h=cadd0366dcf6819c3b2cff8a382f533e3bffad91;hb=5fcc9285fb8c549a5264921a2b61cfc40803d720;hp=4c7326a8a000cecf01fdcf954be30513d7b8247f;hpb=433c7923c5402d6d5cc3020a4eb9c642b71183c5;p=openldap diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index 4c7326a8a0..cadd0366dc 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1999-2005 The OpenLDAP Foundation. + * Copyright 1999-2012 The OpenLDAP Foundation. * Portions Copyright 1999 Dmitry Kovalev. * Portions Copyright 2002 Pierangelo Masarati. * Portions Copyright 2004 Mark Adamson. @@ -28,6 +28,7 @@ #include "ac/string.h" #include "ac/ctype.h" +#include "lutil.h" #include "slap.h" #include "proto-sql.h" @@ -41,6 +42,27 @@ static int backsql_process_filter_like( backsql_srch_info *bsi, static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ); +/* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of + the state of paged results. The ldap_entries.id and oc_map_id values of the + last entry returned are used as the cookie, so 6 bits are used for the OC id + and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more + than 63, you will need to steal more bits from ldap_entries ID number and + put them into the OC ID part of the cookie. */ + +/* NOTE: not supported when BACKSQL_ARBITRARY_KEY is defined */ +#ifndef BACKSQL_ARBITRARY_KEY +#define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F)) +#define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6) +#define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F) + +static int parse_paged_cookie( Operation *op, SlapReply *rs ); + +static void send_paged_response( + Operation *op, + SlapReply *rs, + ID *lastid ); +#endif /* ! BACKSQL_ARBITRARY_KEY */ + static int backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ) { @@ -61,6 +83,11 @@ backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ) return 1; } + /* strip ';binary' */ + if ( slap_ad_is_binary( ad ) ) { + ad = ad->ad_type->sat_ad; + } + for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) { an = &bsi->bsi_attrs[ n_attrs ]; @@ -109,8 +136,6 @@ backsql_init_search( backsql_srch_info *bsi, struct berval *nbase, int scope, - int slimit, - int tlimit, time_t stoptime, Filter *filter, SQLHDBC dbh, @@ -127,8 +152,6 @@ backsql_init_search( BER_BVZERO( &bsi->bsi_base_id.eid_dn ); BER_BVZERO( &bsi->bsi_base_id.eid_ndn ); bsi->bsi_scope = scope; - bsi->bsi_slimit = slimit; - bsi->bsi_tlimit = tlimit; bsi->bsi_filter = filter; bsi->bsi_dbh = dbh; bsi->bsi_op = op; @@ -165,7 +188,7 @@ backsql_init_search( BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name ); for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) { - if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) { + if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) { /* handle "*" */ bsi->bsi_flags |= BSQL_SF_ALL_USER; @@ -179,7 +202,7 @@ backsql_init_search( } continue; - } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) { + } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) { /* handle "+" */ bsi->bsi_flags |= BSQL_SF_ALL_OPER; @@ -193,7 +216,7 @@ backsql_init_search( } continue; - } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) { + } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_no_attrs ) == 0 ) { /* ignore "1.1" */ continue; @@ -218,7 +241,7 @@ backsql_init_search( /* use hints if available */ for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) { - if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) { + if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) { /* handle "*" */ bsi->bsi_flags |= BSQL_SF_ALL_USER; @@ -232,7 +255,7 @@ backsql_init_search( } continue; - } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) { + } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) { /* handle "+" */ bsi->bsi_flags |= BSQL_SF_ALL_OPER; @@ -317,9 +340,18 @@ backsql_init_search( } } else { - rs->sr_ref = referral_rewrite( default_referral, - NULL, &op->o_req_dn, scope ); - rc = rs->sr_err = LDAP_REFERRAL; + rs->sr_err = rc; + } + } + + if ( gotit && BACKSQL_IS_GET_OC( flags ) ) { + bsi->bsi_base_id.eid_oc = backsql_id2oc( bi, + bsi->bsi_base_id.eid_oc_id ); + if ( bsi->bsi_base_id.eid_oc == NULL ) { + /* error? */ + backsql_free_entryID( &bsi->bsi_base_id, 1, + op->o_tmpmemctx ); + rc = rs->sr_err = LDAP_OTHER; } } } @@ -349,7 +381,8 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op ) return 0; } - backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); while ( 1 ) { res = backsql_process_filter( bsi, f ); @@ -368,20 +401,23 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op ) switch ( op ) { case LDAP_FILTER_AND: - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "l", (ber_len_t)STRLENOF( " AND " ), " AND " ); break; case LDAP_FILTER_OR: - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "l", (ber_len_t)STRLENOF( " OR " ), " OR " ); break; } } - backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' ); return 1; } @@ -486,7 +522,8 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, * SQL filters are more liberal. */ - backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); /* TimesTen */ Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n", @@ -499,14 +536,17 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, * If a pre-upper-cased version of the column * or a precompiled upper function exists, use it */ - backsql_strfcat( &bsi->bsi_flt_where, + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "bl", &at->bam_sel_expr_u, (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" ); } else { - backsql_strfcat( &bsi->bsi_flt_where, "bl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bl", &at->bam_sel_expr, (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" ); } @@ -522,14 +562,18 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, #endif /* BACKSQL_TRACE */ start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, "b", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "b", &f->f_sub_initial ); if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } } - backsql_strfcat( &bsi->bsi_flt_where, "c", '%' ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "c", '%' ); if ( f->f_sub_any != NULL ) { for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) { @@ -543,7 +587,8 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, #endif /* BACKSQL_TRACE */ start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "bc", &f->f_sub_any[ i ], '%' ); @@ -567,14 +612,18 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, #endif /* BACKSQL_TRACE */ start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, "b", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "b", &f->f_sub_final ); if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } } - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" ); return 1; @@ -588,18 +637,21 @@ backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls ) } if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) { - char *start, *end, *tmp; + char *start, *end; + struct berval tmp; - tmp = ch_strdup( from_tbls->bv_val ); + ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx ); - for ( start = tmp, end = strchr( start, ',' ); start; ) { + for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) { if ( end ) { end[0] = '\0'; } if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL ) { - backsql_strfcat( &bsi->bsi_from, "cs", ',', start ); + backsql_strfcat_x( &bsi->bsi_from, + bsi->bsi_op->o_tmpmemctx, + "cs", ',', start ); } if ( end ) { @@ -615,10 +667,12 @@ backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls ) } } - ch_free( tmp ); + bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx ); } else { - backsql_strfcat( &bsi->bsi_from, "b", from_tbls ); + backsql_strfcat_x( &bsi->bsi_from, + bsi->bsi_op->o_tmpmemctx, + "b", from_tbls ); } return LDAP_SUCCESS; @@ -635,9 +689,45 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 ); if ( f->f_choice == SLAPD_FILTER_COMPUTED ) { + struct berval flt; + char *msg = NULL; + + switch ( f->f_result ) { + case LDAP_COMPARE_TRUE: + BER_BVSTR( &flt, "10=10" ); + msg = "TRUE"; + break; + + case LDAP_COMPARE_FALSE: + BER_BVSTR( &flt, "11=0" ); + msg = "FALSE"; + break; + + case SLAPD_COMPARE_UNDEFINED: + BER_BVSTR( &flt, "12=0" ); + msg = "UNDEFINED"; + break; + + default: + rc = -1; + goto done; + } + Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): " - "invalid filter\n", 0, 0, 0 ); - rc = -1; + "filter computed (%s)\n", msg, 0, 0 ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, "b", &flt ); + rc = 1; + goto done; + } + + if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", + (ber_len_t)STRLENOF( "1=0" ), "1=0" ); + done = 1; + rc = 1; goto done; } @@ -655,11 +745,15 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) break; case LDAP_FILTER_NOT: - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "NOT (" /* ) */ ), "NOT (" /* ) */ ); rc = backsql_process_filter( bsi, f->f_not ); - backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "c", /* ( */ ')' ); done = 1; break; @@ -678,7 +772,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) * ldap_entries AS attributeName WHERE attributeName.dn * like '%attributeName=value%'" */ - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "1=1" ), "1=1" ); bsi->bsi_status = LDAP_SUCCESS; rc = 1; @@ -738,7 +834,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) backsql_merge_from_tbls( bsi, &ldap_entry_objclasses ); - backsql_strfcat( &bsi->bsi_flt_where, "lbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "lbl", (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ), "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */, &bsi->bsi_oc->bom_oc->soc_cname, @@ -753,7 +851,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) } case LDAP_FILTER_PRESENT: - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "3=3" ), "3=3" ); bsi->bsi_status = LDAP_SUCCESS; rc = 1; @@ -778,7 +878,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) struct berval keyval; #else /* ! BACKSQL_ARBITRARY_KEY */ unsigned long keyval; - char keyvalbuf[] = "18446744073709551615"; + char keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)]; #endif /* ! BACKSQL_ARBITRARY_KEY */ switch ( f->f_choice ) { @@ -792,21 +892,27 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) } #ifdef BACKSQL_ARBITRARY_KEY - backsql_strfcat( &bsi->bsi_flt_where, "bcblbc", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bcblbc", &bsi->bsi_oc->bom_keytbl, '.', &bsi->bsi_oc->bom_keycol, STRLENOF( " LIKE '" ), " LIKE '", &keyval, '\'' ); #else /* ! BACKSQL_ARBITRARY_KEY */ snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval ); - backsql_strfcat( &bsi->bsi_flt_where, "bcbcs", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bcbcs", &bsi->bsi_oc->bom_keytbl, '.', &bsi->bsi_oc->bom_keycol, '=', keyvalbuf ); #endif /* ! BACKSQL_ARBITRARY_KEY */ break; case LDAP_FILTER_PRESENT: - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "4=4" ), "4=4" ); break; @@ -822,20 +928,24 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) #ifdef BACKSQL_SYNCPROV } else if ( ad == slap_schema.si_ad_entryCSN ) { /* - * support for syncrepl as producer... + * support for syncrepl as provider... */ +#if 0 if ( !bsi->bsi_op->o_sync ) { /* unsupported at present... */ bsi->bsi_status = LDAP_OTHER; rc = -1; goto done; } +#endif bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID); /* if doing a syncrepl, try to return as much as possible, * and always match the filter */ - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "5=5" ), "5=5" ); /* save for later use in operational attributes */ @@ -869,7 +979,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) * selecting if there are descendants of the * candidate. */ - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "6=6" ), "6=6" ); if ( ad == slap_schema.si_ad_hasSubordinates ) { /* @@ -902,7 +1014,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) if ( vat == NULL ) { /* search anyway; other parts of the filter * may succeeed */ - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "7=7" ), "7=7" ); bsi->bsi_status = LDAP_SUCCESS; rc = 1; @@ -912,7 +1026,9 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) /* if required, open extra level of parens */ done = 0; if ( vat[0]->bam_next || vat[1] ) { - backsql_strfcat( &bsi->bsi_flt_where, "c", '(' ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "c", '(' ); done = 1; } @@ -925,7 +1041,9 @@ next:; /* if more definitions of the same attr, apply */ if ( vat[i]->bam_next ) { - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", STRLENOF( " OR " ), " OR " ); vat[i] = vat[i]->bam_next; goto next; @@ -934,14 +1052,18 @@ next:; /* if more descendants of the same attr, apply */ i++; if ( vat[i] ) { - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", STRLENOF( " OR " ), " OR " ); goto next; } /* if needed, close extra level of parens */ if ( done ) { - backsql_strfcat( &bsi->bsi_flt_where, "c", ')' ); + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "c", ')' ); } rc = 1; @@ -971,7 +1093,9 @@ backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ber_len_t start; - backsql_strfcat( &bsi->bsi_flt_where, "cbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cbl", '(', /* ) */ &at->bam_sel_expr_u, (ber_len_t)STRLENOF( "='" ), @@ -979,7 +1103,9 @@ backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, "bl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bl", filter_value, (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" ); @@ -987,7 +1113,9 @@ backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } else { - backsql_strfcat( &bsi->bsi_flt_where, "cblbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cblbl", '(', /* ) */ &at->bam_sel_expr, (ber_len_t)STRLENOF( "='" ), "='", @@ -1012,7 +1140,9 @@ backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ber_len_t start; - backsql_strfcat( &bsi->bsi_flt_where, "cbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cbl", '(', /* ) */ &at->bam_sel_expr_u, (ber_len_t)STRLENOF( " LIKE '%" ), @@ -1020,7 +1150,9 @@ backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, "bl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bl", filter_value, (ber_len_t)STRLENOF( /* (' */ "%')" ), /* (' */ "%')" ); @@ -1028,7 +1160,9 @@ backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } else { - backsql_strfcat( &bsi->bsi_flt_where, "cblbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cblbl", '(', /* ) */ &at->bam_sel_expr, (ber_len_t)STRLENOF( " LIKE '%" ), @@ -1065,11 +1199,21 @@ backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_r && strstr( bsi->bsi_join_where.bb_val.bv_val, at->bam_join_where.bv_val ) == NULL ) { - backsql_strfcat( &bsi->bsi_join_where, "lb", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "lb", (ber_len_t)STRLENOF( " AND " ), " AND ", &at->bam_join_where ); } + if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) { + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", + (ber_len_t)STRLENOF( "1=0" ), "1=0" ); + return 1; + } + switch ( f->f_choice ) { case LDAP_FILTER_EQUALITY: filter_value = &f->f_av_value; @@ -1135,7 +1279,9 @@ equality_match:; if ( at->bam_ad == slap_schema.si_ad_objectClass || at->bam_ad == slap_schema.si_ad_structuralObjectClass ) { - backsql_strfcat( &bsi->bsi_flt_where, "lbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "lbl", (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ), "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */, filter_value, @@ -1177,7 +1323,9 @@ equality_match:; if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ber_len_t start; - backsql_strfcat( &bsi->bsi_flt_where, "cbbc", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cbbc", '(', /* ) */ &at->bam_sel_expr_u, &ordering, @@ -1185,7 +1333,9 @@ equality_match:; start = bsi->bsi_flt_where.bb_val.bv_len; - backsql_strfcat( &bsi->bsi_flt_where, "bl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "bl", filter_value, (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" ); @@ -1193,7 +1343,9 @@ equality_match:; ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } else { - backsql_strfcat( &bsi->bsi_flt_where, "cbbcbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "cbbcbl", '(' /* ) */ , &at->bam_sel_expr, &ordering, @@ -1205,7 +1357,9 @@ equality_match:; break; case LDAP_FILTER_PRESENT: - backsql_strfcat( &bsi->bsi_flt_where, "lbl", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "lbl", (ber_len_t)STRLENOF( "NOT (" /* ) */), "NOT (", /* ) */ &at->bam_sel_expr, @@ -1232,7 +1386,9 @@ equality_match:; default: /* unhandled filter type; should not happen */ assert( 0 ); - backsql_strfcat( &bsi->bsi_flt_where, "l", + backsql_strfcat_x( &bsi->bsi_flt_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "8=8" ), "8=8" ); break; @@ -1266,7 +1422,9 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) BER_BVZERO( &bsi->bsi_flt_where.bb_val ); bsi->bsi_flt_where.bb_len = 0; - backsql_strfcat( &bsi->bsi_sel, "lbcbc", + backsql_strfcat_x( &bsi->bsi_sel, + bsi->bsi_op->o_tmpmemctx, + "lbcbc", (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ), "SELECT DISTINCT ldap_entries.id,", &bsi->bsi_oc->bom_keytbl, @@ -1275,7 +1433,9 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) ',' ); if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) { - backsql_strfcat( &bsi->bsi_sel, "blbl", + backsql_strfcat_x( &bsi->bsi_sel, + bsi->bsi_op->o_tmpmemctx, + "blbl", &bi->sql_strcast_func, (ber_len_t)STRLENOF( "('" /* ') */ ), "('" /* ') */ , @@ -1283,19 +1443,28 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" ); } else { - backsql_strfcat( &bsi->bsi_sel, "cbc", + backsql_strfcat_x( &bsi->bsi_sel, + bsi->bsi_op->o_tmpmemctx, + "cbc", '\'', &bsi->bsi_oc->bom_oc->soc_cname, '\'' ); } - backsql_strfcat( &bsi->bsi_sel, "b", &bi->sql_dn_oc_aliasing ); - backsql_strfcat( &bsi->bsi_from, "lb", + backsql_strfcat_x( &bsi->bsi_sel, + bsi->bsi_op->o_tmpmemctx, + "b", + &bi->sql_dn_oc_aliasing ); + backsql_strfcat_x( &bsi->bsi_from, + bsi->bsi_op->o_tmpmemctx, + "lb", (ber_len_t)STRLENOF( " FROM ldap_entries," ), " FROM ldap_entries,", &bsi->bsi_oc->bom_keytbl ); - backsql_strfcat( &bsi->bsi_join_where, "lbcbl", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "lbcbl", (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", &bsi->bsi_oc->bom_keytbl, '.', @@ -1306,12 +1475,16 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) switch ( bsi->bsi_scope ) { case LDAP_SCOPE_BASE: if ( BACKSQL_CANUPPERCASE( bi ) ) { - backsql_strfcat( &bsi->bsi_join_where, "bl", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "bl", &bi->sql_upper_func, (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ), "(ldap_entries.dn)=?" ); } else { - backsql_strfcat( &bsi->bsi_join_where, "l", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "ldap_entries.dn=?" ), "ldap_entries.dn=?" ); } @@ -1319,26 +1492,30 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) case BACKSQL_SCOPE_BASE_LIKE: if ( BACKSQL_CANUPPERCASE( bi ) ) { - backsql_strfcat( &bsi->bsi_join_where, "bl", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "bl", &bi->sql_upper_func, (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), "(ldap_entries.dn) LIKE ?" ); } else { - backsql_strfcat( &bsi->bsi_join_where, "l", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), "ldap_entries.dn LIKE ?" ); } break; case LDAP_SCOPE_ONELEVEL: - backsql_strfcat( &bsi->bsi_join_where, "l", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "ldap_entries.parent=?" ), "ldap_entries.parent=?" ); break; -#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: -#endif /* LDAP_SCOPE_SUBORDINATE */ case LDAP_SCOPE_SUBTREE: if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) { int i; @@ -1362,20 +1539,30 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) if ( bsi->bsi_use_subtree_shortcut ) { /* Skip the base DN filter, as every entry will match it */ - backsql_strfcat( &bsi->bsi_join_where, "l", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "9=9"), "9=9"); } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) { - backsql_strfcat( &bsi->bsi_join_where, "b", &bi->sql_subtree_cond ); + /* This should always be true... */ + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "b", + &bi->sql_subtree_cond ); } else if ( BACKSQL_CANUPPERCASE( bi ) ) { - backsql_strfcat( &bsi->bsi_join_where, "bl", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "bl", &bi->sql_upper_func, (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ), "(ldap_entries.dn) LIKE ?" ); } else { - backsql_strfcat( &bsi->bsi_join_where, "l", + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ), "ldap_entries.dn LIKE ?" ); } @@ -1386,11 +1573,39 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) assert( 0 ); } +#ifndef BACKSQL_ARBITRARY_KEY + /* If paged results are in effect, ignore low ldap_entries.id numbers */ + if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) { + unsigned long lowid = 0; + + /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */ + if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) ) + { + lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ); + } + + if ( lowid ) { + char lowidstring[48]; + int lowidlen; + + lowidlen = snprintf( lowidstring, sizeof( lowidstring ), + " AND ldap_entries.id>%lu", lowid ); + backsql_strfcat_x( &bsi->bsi_join_where, + bsi->bsi_op->o_tmpmemctx, + "l", + (ber_len_t)lowidlen, + lowidstring ); + } + } +#endif /* ! BACKSQL_ARBITRARY_KEY */ + rc = backsql_process_filter( bsi, bsi->bsi_filter ); if ( rc > 0 ) { struct berbuf bb = BB_NULL; - backsql_strfcat( &bb, "bbblb", + backsql_strfcat_x( &bb, + bsi->bsi_op->o_tmpmemctx, + "bbblb", &bsi->bsi_sel.bb_val, &bsi->bsi_from.bb_val, &bsi->bsi_join_where.bb_val, @@ -1408,16 +1623,16 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query ) BER_BVZERO( query ); } - free( bsi->bsi_sel.bb_val.bv_val ); + bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &bsi->bsi_sel.bb_val ); bsi->bsi_sel.bb_len = 0; - free( bsi->bsi_from.bb_val.bv_val ); + bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &bsi->bsi_from.bb_val ); bsi->bsi_from.bb_len = 0; - free( bsi->bsi_join_where.bb_val.bv_val ); + bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &bsi->bsi_join_where.bb_val ); bsi->bsi_join_where.bb_len = 0; - free( bsi->bsi_flt_where.bb_val.bv_val ); + bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &bsi->bsi_flt_where.bb_val ); bsi->bsi_flt_where.bb_len = 0; @@ -1463,6 +1678,16 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) return BACKSQL_AVL_STOP; } +#ifndef BACKSQL_ARBITRARY_KEY + /* If paged results have already completed this objectClass, skip it */ + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) ) + { + return BACKSQL_AVL_CONTINUE; + } + } +#endif /* ! BACKSQL_ARBITRARY_KEY */ + if ( bsi->bsi_n_candidates == -1 ) { Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " "unchecked limit has been overcome\n", 0, 0, 0 ); @@ -1511,7 +1736,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) query.bv_val, 0, 0 ); rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 ); - free( query.bv_val ); + bsi->bsi_op->o_tmpfree( query.bv_val, bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &query ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " @@ -1521,9 +1746,10 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) return BACKSQL_AVL_CONTINUE; } - Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 ); + Debug( LDAP_DEBUG_TRACE, "id: '" BACKSQL_IDNUMFMT "'\n", + bsi->bsi_oc->bom_id, 0, 0 ); - rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT, + rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT, &bsi->bsi_oc->bom_id ); if ( rc != SQL_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " @@ -1568,9 +1794,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) } break; -#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: -#endif /* LDAP_SCOPE_SUBORDINATE */ case LDAP_SCOPE_SUBTREE: { /* if short-cutting the search base, @@ -1609,11 +1833,9 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ]; } -#ifdef LDAP_SCOPE_SUBORDINATE if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { tmp_base_ndn[ i++ ] = ','; } -#endif /* LDAP_SCOPE_SUBORDINATE */ tmp_base_ndn[ i ] = '%'; tmp_base_ndn[ i + 1 ] = '\0'; @@ -1623,11 +1845,9 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) tmp_base_ndn[ i++ ] = '%'; -#ifdef LDAP_SCOPE_SUBORDINATE if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { tmp_base_ndn[ i++ ] = ','; } -#endif /* LDAP_SCOPE_SUBORDINATE */ AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val, bsi->bsi_base_ndn->bv_len + 1 ); @@ -1639,13 +1859,10 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) ldap_pvt_str2upper( tmp_base_ndn ); } -#ifdef LDAP_SCOPE_SUBORDINATE if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) { Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n", tmp_base_ndn, 0, 0 ); - } else -#endif /* LDAP_SCOPE_SUBORDINATE */ - { + } else { Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n", tmp_base_ndn, 0, 0 ); } @@ -1667,13 +1884,8 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) case LDAP_SCOPE_ONELEVEL: assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ); -#ifdef BACKSQL_ARBITRARY_KEY - Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n", - bsi->bsi_base_id.eid_id.bv_val, 0, 0 ); -#else /* ! BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n", - bsi->bsi_base_id.eid_id, 0, 0 ); -#endif /* ! BACKSQL_ARBITRARY_KEY */ + Debug( LDAP_DEBUG_TRACE, "(one)id=" BACKSQL_IDFMT "\n", + BACKSQL_IDARG(bsi->bsi_base_id.eid_id), 0, 0 ); rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT, &bsi->bsi_base_id.eid_id ); if ( rc != SQL_SUCCESS ) { @@ -1718,22 +1930,25 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) } if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) { - op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); - op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); - continue; + goto cleanup; } - c_id = (backsql_entryID *)ch_calloc( 1, - sizeof( backsql_entryID ) ); + c_id = (backsql_entryID *)op->o_tmpcalloc( 1, + sizeof( backsql_entryID ), op->o_tmpmemctx ); #ifdef BACKSQL_ARBITRARY_KEY ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id, op->o_tmpmemctx ); ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval, op->o_tmpmemctx ); #else /* ! BACKSQL_ARBITRARY_KEY */ - c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 ); - c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 ); + if ( BACKSQL_STR2ID( &c_id->eid_id, row.cols[ 0 ], 0 ) != 0 ) { + goto cleanup; + } + if ( BACKSQL_STR2ID( &c_id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) { + goto cleanup; + } #endif /* ! BACKSQL_ARBITRARY_KEY */ + c_id->eid_oc = bsi->bsi_oc; c_id->eid_oc_id = bsi->bsi_oc->bom_id; c_id->eid_dn = pdn; @@ -1744,22 +1959,29 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi ) *bsi->bsi_id_listtail = c_id; bsi->bsi_id_listtail = &c_id->eid_next; -#ifdef BACKSQL_ARBITRARY_KEY Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " - "added entry id=%s, keyval=%s dn=\"%s\"\n", - c_id->eid_id.bv_val, c_id->eid_keyval.bv_val, + "added entry id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDFMT " dn=\"%s\"\n", + BACKSQL_IDARG(c_id->eid_id), + BACKSQL_IDARG(c_id->eid_keyval), row.cols[ 3 ] ); -#else /* ! BACKSQL_ARBITRARY_KEY */ - Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): " - "added entry id=%ld, keyval=%ld dn=\"%s\"\n", - c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] ); -#endif /* ! BACKSQL_ARBITRARY_KEY */ /* count candidates, for unchecked limit */ bsi->bsi_n_candidates--; if ( bsi->bsi_n_candidates == -1 ) { break; } + continue; + +cleanup:; + if ( !BER_BVISNULL( &pdn ) ) { + op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx ); + } + if ( !BER_BVISNULL( &ndn ) ) { + op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); + } + if ( c_id != NULL ) { + ch_free( c_id ); + } } backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx ); SQLFreeStmt( sth, SQL_DROP ); @@ -1783,11 +2005,14 @@ backsql_search( Operation *op, SlapReply *rs ) backsql_srch_info bsi = { 0 }; backsql_entryID *eid = NULL; struct berval nbase = BER_BVNULL; +#ifndef BACKSQL_ARBITRARY_KEY + ID lastid = 0; +#endif /* ! BACKSQL_ARBITRARY_KEY */ Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): " "base=\"%s\", filter=\"%s\", scope=%d,", op->o_req_ndn.bv_val, - op->ors_filterstr.bv_val ? op->ors_filterstr.bv_val : "(no filter)", + op->ors_filterstr.bv_val, op->ors_scope ); Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, " "attributes to load: %s\n", @@ -1827,7 +2052,6 @@ backsql_search( Operation *op, SlapReply *rs ) bsi.bsi_e = &base_entry; rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn, op->ors_scope, - op->ors_slimit, op->ors_tlimit, stoptime, op->ors_filter, dbh, op, rs, op->ors_attrs, ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) ); @@ -1848,12 +2072,15 @@ backsql_search( Operation *op, SlapReply *rs ) } break; } + + /* an entry was created; free it */ + entry_clean( bsi.bsi_e ); + /* fall thru */ default: -#ifdef SLAP_ACL_HONOR_DISCLOSE if ( !BER_BVISNULL( &base_entry.e_nname ) - && ! access_allowed( op, &base_entry, + && !access_allowed( op, &base_entry, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) ) { @@ -1865,13 +2092,20 @@ backsql_search( Operation *op, SlapReply *rs ) rs->sr_matched = NULL; rs->sr_text = NULL; } -#endif /* SLAP_ACL_HONOR_DISCLOSE */ send_ldap_result( op, rs ); - goto done; + if ( rs->sr_ref ) { + ber_bvarray_free( rs->sr_ref ); + rs->sr_ref = NULL; + } + + if ( !BER_BVISNULL( &base_entry.e_nname ) ) { + entry_clean( &base_entry ); + } + + goto done; } -#ifdef SLAP_ACL_HONOR_DISCLOSE /* NOTE: __NEW__ "search" access is required * on searchBase object */ { @@ -1902,7 +2136,6 @@ backsql_search( Operation *op, SlapReply *rs ) goto done; } } -#endif /* SLAP_ACL_HONOR_DISCLOSE */ bsi.bsi_e = NULL; @@ -1911,6 +2144,17 @@ backsql_search( Operation *op, SlapReply *rs ) ( op->ors_limit->lms_s_unchecked == -1 ? -2 : ( op->ors_limit->lms_s_unchecked ) ) ); +#ifndef BACKSQL_ARBITRARY_KEY + /* If paged results are in effect, check the paging cookie */ + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { + rs->sr_err = parse_paged_cookie( op, rs ); + if ( rs->sr_err != LDAP_SUCCESS ) { + send_ldap_result( op, rs ); + goto done; + } + } +#endif /* ! BACKSQL_ARBITRARY_KEY */ + switch ( bsi.bsi_scope ) { case LDAP_SCOPE_BASE: case BACKSQL_SCOPE_BASE_LIKE: @@ -1938,13 +2182,14 @@ backsql_search( Operation *op, SlapReply *rs ) /* * for each objectclass we try to construct query which gets IDs * of entries matching LDAP query filter and scope (or at least - * candidates), and get the IDs + * candidates), and get the IDs. Do this in ID order for paging. */ - avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates, + avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates, &bsi, BACKSQL_AVL_STOP, AVL_INORDER ); /* check for abandon */ if ( op->o_abandon ) { + eid = bsi.bsi_id_list; rs->sr_err = SLAPD_ABANDON; goto send_results; } @@ -1965,9 +2210,9 @@ backsql_search( Operation *op, SlapReply *rs ) * and then send to client; don't free entry_id if baseObject... */ for ( eid = bsi.bsi_id_list; - eid != NULL; - eid = backsql_free_entryID( op, - eid, eid == &bsi.bsi_base_id ? 0 : 1 ) ) + eid != NULL; + eid = backsql_free_entryID( + eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) { int rc; Attribute *a_hasSubordinate = NULL, @@ -1992,16 +2237,11 @@ backsql_search( Operation *op, SlapReply *rs ) goto send_results; } -#ifdef BACKSQL_ARBITRARY_KEY - Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data " - "for entry id=%s, oc_id=%ld, keyval=%s\n", - eid->eid_id.bv_val, eid->eid_oc_id, - eid->eid_keyval.bv_val ); -#else /* ! BACKSQL_ARBITRARY_KEY */ Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data " - "for entry id=%ld, oc_id=%ld, keyval=%ld\n", - eid->eid_id, eid->eid_oc_id, eid->eid_keyval ); -#endif /* ! BACKSQL_ARBITRARY_KEY */ + "for entry id=" BACKSQL_IDFMT " oc_id=" BACKSQL_IDNUMFMT ", keyval=" BACKSQL_IDFMT "\n", + BACKSQL_IDARG(eid->eid_id), + eid->eid_oc_id, + BACKSQL_IDARG(eid->eid_keyval) ); /* check scope */ switch ( op->ors_scope ) { @@ -2023,19 +2263,15 @@ backsql_search( Operation *op, SlapReply *rs ) /* fall thru */ } -#ifdef LDAP_SCOPE_SUBORDINATE case LDAP_SCOPE_SUBORDINATE: /* discard the baseObject entry */ if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) { goto next_entry2; } - /* FALLTHRU */ -#endif /* LDAP_SCOPE_SUBORDINATE */ - + /* FALLTHRU */ case LDAP_SCOPE_SUBTREE: /* FIXME: this should never fail... */ if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) { - assert( 0 ); goto next_entry2; } break; @@ -2078,7 +2314,6 @@ backsql_search( Operation *op, SlapReply *rs ) rc = backsql_init_search( &bsi2, &e->e_nname, LDAP_SCOPE_BASE, - SLAP_NO_LIMIT, SLAP_NO_LIMIT, (time_t)(-1), NULL, dbh, op, rs, NULL, BACKSQL_ISF_GET_ENTRY ); @@ -2121,6 +2356,9 @@ backsql_search( Operation *op, SlapReply *rs ) rs->sr_ref = NULL; rs->sr_matched = NULL; rs->sr_entry = NULL; + if ( rs->sr_err == LDAP_REFERRAL ) { + rs->sr_err = LDAP_SUCCESS; + } goto next_entry; } @@ -2187,19 +2425,32 @@ backsql_search( Operation *op, SlapReply *rs ) if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE ) { +#ifndef BACKSQL_ARBITRARY_KEY + /* If paged results are in effect, see if the page limit was exceeded */ + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size ) + { + e = NULL; + send_paged_response( op, rs, &lastid ); + goto done; + } + lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id ); + } +#endif /* ! BACKSQL_ARBITRARY_KEY */ rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_entry = e; - if ( e == &user_entry ) { - rs->sr_flags = REP_ENTRY_MODIFIABLE; - } + e->e_private = (void *)eid; + rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0; /* FIXME: need the whole entry (ITS#3480) */ - sres = send_search_entry( op, rs ); + rs->sr_err = send_search_entry( op, rs ); + e->e_private = NULL; rs->sr_entry = NULL; rs->sr_attrs = NULL; rs->sr_operational_attrs = NULL; - if ( sres == -1 ) { + switch ( rs->sr_err ) { + case LDAP_UNAVAILABLE: /* * FIXME: send_search_entry failed; * better stop @@ -2207,6 +2458,9 @@ backsql_search( Operation *op, SlapReply *rs ) Debug( LDAP_DEBUG_TRACE, "backsql_search(): " "connection lost\n", 0, 0, 0 ); goto end_of_search; + + case LDAP_SIZELIMIT_EXCEEDED: + goto send_results; } } @@ -2216,12 +2470,6 @@ next_entry:; } next_entry2:; - if ( op->ors_slimit != SLAP_NO_LIMIT - && rs->sr_nentries >= op->ors_slimit ) - { - rs->sr_err = LDAP_SIZELIMIT_EXCEEDED; - goto send_results; - } } end_of_search:; @@ -2236,13 +2484,20 @@ end_of_search:; send_results:; if ( rs->sr_err != SLAPD_ABANDON ) { - send_ldap_result( op, rs ); +#ifndef BACKSQL_ARBITRARY_KEY + if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) { + send_paged_response( op, rs, NULL ); + } else +#endif /* ! BACKSQL_ARBITRARY_KEY */ + { + send_ldap_result( op, rs ); + } } /* cleanup in case of abandon */ for ( ; eid != NULL; - eid = backsql_free_entryID( op, - eid, eid == &bsi.bsi_base_id ? 0 : 1 ) ) + eid = backsql_free_entryID( + eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) ) ; backsql_entry_clean( op, &base_entry ); @@ -2258,26 +2513,29 @@ send_results:; #ifdef BACKSQL_SYNCPROV if ( op->o_sync ) { Operation op2 = *op; - SlapReply rs2 = { 0 }; - Entry e = { 0 }; + SlapReply rs2 = { REP_RESULT }; + Entry *e = entry_alloc(); slap_callback cb = { 0 }; op2.o_tag = LDAP_REQ_ADD; - op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 ); - op2.ora_e = &e; + op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 ); + op2.ora_e = e; op2.o_callback = &cb; - e.e_name = op->o_bd->be_suffix[0]; - e.e_nname = op->o_bd->be_nsuffix[0]; + ber_dupbv( &e->e_name, op->o_bd->be_suffix ); + ber_dupbv( &e->e_nname, op->o_bd->be_nsuffix ); cb.sc_response = slap_null_cb; op2.o_bd->be_add( &op2, &rs2 ); + + if ( op2.ora_e == e ) + entry_free( e ); } #endif /* BACKSQL_SYNCPROV */ done:; - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); if ( bsi.bsi_attrs != NULL ) { op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx ); @@ -2320,8 +2578,8 @@ backsql_entry_get( *ent = NULL; rc = backsql_get_db_conn( op, &dbh ); - if ( !dbh ) { - return LDAP_OTHER; + if ( rc != LDAP_SUCCESS ) { + return rc; } if ( at ) { @@ -2330,17 +2588,16 @@ backsql_entry_get( BER_BVZERO( &anlist[ 1 ].an_name ); } - bsi.bsi_e = ch_malloc( sizeof( Entry ) ); + bsi.bsi_e = entry_alloc(); rc = backsql_init_search( &bsi, ndn, LDAP_SCOPE_BASE, - SLAP_NO_LIMIT, SLAP_NO_LIMIT, (time_t)(-1), NULL, dbh, op, &rs, at ? anlist : NULL, BACKSQL_ISF_GET_ENTRY ); if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) { - (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 ); + (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx ); } if ( rc == LDAP_SUCCESS ) { @@ -2422,7 +2679,113 @@ backsql_entry_release( { backsql_entry_clean( op, e ); - ch_free( e ); + entry_free( e ); return 0; } + +#ifndef BACKSQL_ARBITRARY_KEY +/* This function is copied verbatim from back-bdb/search.c */ +static int +parse_paged_cookie( Operation *op, SlapReply *rs ) +{ + int rc = LDAP_SUCCESS; + PagedResultsState *ps = op->o_pagedresults_state; + + /* this function must be invoked only if the pagedResults + * control has been detected, parsed and partially checked + * by the frontend */ + assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); + + /* cookie decoding/checks deferred to backend... */ + if ( ps->ps_cookieval.bv_len ) { + PagedResultsCookie reqcookie; + if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + } + + AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); + + if ( reqcookie > ps->ps_cookie ) { + /* bad cookie */ + rs->sr_text = "paged results cookie is invalid"; + rc = LDAP_PROTOCOL_ERROR; + goto done; + + } else if ( reqcookie < ps->ps_cookie ) { + rs->sr_text = "paged results cookie is invalid or old"; + rc = LDAP_UNWILLING_TO_PERFORM; + goto done; + } + + } else { + /* Initial request. Initialize state. */ + ps->ps_cookie = 0; + ps->ps_count = 0; + } + +done:; + + return rc; +} + +/* This function is copied nearly verbatim from back-bdb/search.c */ +static void +send_paged_response( + Operation *op, + SlapReply *rs, + ID *lastid ) +{ + LDAPControl ctrl, *ctrls[2]; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + PagedResultsCookie respcookie; + struct berval cookie; + + Debug(LDAP_DEBUG_ARGS, + "send_paged_response: lastid=0x%08lx nentries=%d\n", + lastid ? *lastid : 0, rs->sr_nentries, NULL ); + + BER_BVZERO( &ctrl.ldctl_value ); + ctrls[0] = &ctrl; + ctrls[1] = NULL; + + ber_init2( ber, NULL, LBER_USE_DER ); + + if ( lastid ) { + respcookie = ( PagedResultsCookie )(*lastid); + cookie.bv_len = sizeof( respcookie ); + cookie.bv_val = (char *)&respcookie; + + } else { + respcookie = ( PagedResultsCookie )0; + BER_BVSTR( &cookie, "" ); + } + + op->o_conn->c_pagedresults_state.ps_cookie = respcookie; + op->o_conn->c_pagedresults_state.ps_count = + ((PagedResultsState *)op->o_pagedresults_state)->ps_count + + rs->sr_nentries; + + /* return size of 0 -- no estimate */ + ber_printf( ber, "{iO}", 0, &cookie ); + + if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) { + goto done; + } + + ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS; + ctrls[0]->ldctl_iscritical = 0; + + rs->sr_ctrls = ctrls; + rs->sr_err = LDAP_SUCCESS; + send_ldap_result( op, rs ); + rs->sr_ctrls = NULL; + +done: + (void) ber_free_buf( ber ); +} +#endif /* ! BACKSQL_ARBITRARY_KEY */