1 /* $NetBSD: search.c,v 1.3 2021/08/14 16:15:01 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2021 The OpenLDAP Foundation.
7 * Portions Copyright 1999 Dmitry Kovalev.
8 * Portions Copyright 2002 Pierangelo Masarati.
9 * Portions Copyright 2004 Mark Adamson.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted only as authorized by the OpenLDAP
14 * Public License.
15 *
16 * A copy of this license is available in the file LICENSE in the
17 * top-level directory of the distribution or, alternatively, at
18 * <http://www.OpenLDAP.org/license.html>.
19 */
20 /* ACKNOWLEDGEMENTS:
21 * This work was initially developed by Dmitry Kovalev for inclusion
22 * by OpenLDAP Software. Additional significant contributors include
23 * Pierangelo Masarati and Mark Adamson.
24 */
25
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: search.c,v 1.3 2021/08/14 16:15:01 christos Exp $");
28
29 #include "portable.h"
30
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include "ac/string.h"
34 #include "ac/ctype.h"
35
36 #include "lutil.h"
37 #include "slap.h"
38 #include "proto-sql.h"
39
40 static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
41 static int backsql_process_filter_eq( backsql_srch_info *bsi,
42 backsql_at_map_rec *at,
43 int casefold, struct berval *filter_value );
44 static int backsql_process_filter_like( backsql_srch_info *bsi,
45 backsql_at_map_rec *at,
46 int casefold, struct berval *filter_value );
47 static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f,
48 backsql_at_map_rec *at );
49
50 /* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of
51 the state of paged results. The ldap_entries.id and oc_map_id values of the
52 last entry returned are used as the cookie, so 6 bits are used for the OC id
53 and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more
54 than 63, you will need to steal more bits from ldap_entries ID number and
55 put them into the OC ID part of the cookie. */
56
57 /* NOTE: not supported when BACKSQL_ARBITRARY_KEY is defined */
58 #ifndef BACKSQL_ARBITRARY_KEY
59 #define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F))
60 #define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6)
61 #define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F)
62
63 static int parse_paged_cookie( Operation *op, SlapReply *rs );
64
65 static void send_paged_response(
66 Operation *op,
67 SlapReply *rs,
68 ID *lastid );
69 #endif /* ! BACKSQL_ARBITRARY_KEY */
70
71 static int
backsql_attrlist_add(backsql_srch_info * bsi,AttributeDescription * ad)72 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
73 {
74 int n_attrs = 0;
75 AttributeName *an = NULL;
76
77 if ( bsi->bsi_attrs == NULL ) {
78 return 1;
79 }
80
81 /*
82 * clear the list (retrieve all attrs)
83 */
84 if ( ad == NULL ) {
85 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx );
86 bsi->bsi_attrs = NULL;
87 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
88 return 1;
89 }
90
91 /* strip ';binary' */
92 if ( slap_ad_is_binary( ad ) ) {
93 ad = ad->ad_type->sat_ad;
94 }
95
96 for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
97 an = &bsi->bsi_attrs[ n_attrs ];
98
99 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
100 "attribute \"%s\" is in list\n",
101 an->an_name.bv_val );
102 /*
103 * We can live with strcmp because the attribute
104 * list has been normalized before calling be_search
105 */
106 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
107 return 1;
108 }
109 }
110
111 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
112 "adding \"%s\" to list\n", ad->ad_cname.bv_val );
113
114 an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs,
115 sizeof( AttributeName ) * ( n_attrs + 2 ),
116 bsi->bsi_op->o_tmpmemctx );
117 if ( an == NULL ) {
118 return -1;
119 }
120
121 an[ n_attrs ].an_name = ad->ad_cname;
122 an[ n_attrs ].an_desc = ad;
123 BER_BVZERO( &an[ n_attrs + 1 ].an_name );
124
125 bsi->bsi_attrs = an;
126
127 return 1;
128 }
129
130 /*
131 * Initializes the search structure.
132 *
133 * If get_base_id != 0, the field bsi_base_id is filled
134 * with the entryID of bsi_base_ndn; it must be freed
135 * by backsql_free_entryID() when no longer required.
136 *
137 * NOTE: base must be normalized
138 */
139 int
backsql_init_search(backsql_srch_info * bsi,struct berval * nbase,int scope,time_t stoptime,Filter * filter,SQLHDBC dbh,Operation * op,SlapReply * rs,AttributeName * attrs,unsigned flags)140 backsql_init_search(
141 backsql_srch_info *bsi,
142 struct berval *nbase,
143 int scope,
144 time_t stoptime,
145 Filter *filter,
146 SQLHDBC dbh,
147 Operation *op,
148 SlapReply *rs,
149 AttributeName *attrs,
150 unsigned flags )
151 {
152 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
153 int rc = LDAP_SUCCESS;
154
155 bsi->bsi_base_ndn = nbase;
156 bsi->bsi_use_subtree_shortcut = 0;
157 BER_BVZERO( &bsi->bsi_base_id.eid_dn );
158 BER_BVZERO( &bsi->bsi_base_id.eid_ndn );
159 bsi->bsi_scope = scope;
160 bsi->bsi_filter = filter;
161 bsi->bsi_dbh = dbh;
162 bsi->bsi_op = op;
163 bsi->bsi_rs = rs;
164 bsi->bsi_flags = BSQL_SF_NONE;
165
166 bsi->bsi_attrs = NULL;
167
168 if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) {
169 /*
170 * if requested, simply try to fetch all attributes
171 */
172 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
173
174 } else {
175 if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
176 bsi->bsi_flags |= BSQL_SF_ALL_USER;
177
178 } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
179 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
180 }
181
182 if ( attrs == NULL ) {
183 /* NULL means all user attributes */
184 bsi->bsi_flags |= BSQL_SF_ALL_USER;
185
186 } else {
187 AttributeName *p;
188 int got_oc = 0;
189
190 bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc(
191 sizeof( AttributeName ),
192 bsi->bsi_op->o_tmpmemctx );
193 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
194
195 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
196 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
197 /* handle "*" */
198 bsi->bsi_flags |= BSQL_SF_ALL_USER;
199
200 /* if all attrs are requested, there's
201 * no need to continue */
202 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
203 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
204 bsi->bsi_op->o_tmpmemctx );
205 bsi->bsi_attrs = NULL;
206 break;
207 }
208 continue;
209
210 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
211 /* handle "+" */
212 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
213
214 /* if all attrs are requested, there's
215 * no need to continue */
216 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
217 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
218 bsi->bsi_op->o_tmpmemctx );
219 bsi->bsi_attrs = NULL;
220 break;
221 }
222 continue;
223
224 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_no_attrs ) == 0 ) {
225 /* ignore "1.1" */
226 continue;
227
228 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
229 got_oc = 1;
230 }
231
232 backsql_attrlist_add( bsi, p->an_desc );
233 }
234
235 if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) {
236 /* add objectClass if not present,
237 * because it is required to understand
238 * if an entry is a referral, an alias
239 * or so... */
240 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
241 }
242 }
243
244 if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) {
245 AttributeName *p;
246
247 /* use hints if available */
248 for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) {
249 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
250 /* handle "*" */
251 bsi->bsi_flags |= BSQL_SF_ALL_USER;
252
253 /* if all attrs are requested, there's
254 * no need to continue */
255 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
256 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
257 bsi->bsi_op->o_tmpmemctx );
258 bsi->bsi_attrs = NULL;
259 break;
260 }
261 continue;
262
263 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
264 /* handle "+" */
265 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
266
267 /* if all attrs are requested, there's
268 * no need to continue */
269 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
270 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
271 bsi->bsi_op->o_tmpmemctx );
272 bsi->bsi_attrs = NULL;
273 break;
274 }
275 continue;
276 }
277
278 backsql_attrlist_add( bsi, p->an_desc );
279 }
280
281 }
282 }
283
284 bsi->bsi_id_list = NULL;
285 bsi->bsi_id_listtail = &bsi->bsi_id_list;
286 bsi->bsi_n_candidates = 0;
287 bsi->bsi_stoptime = stoptime;
288 BER_BVZERO( &bsi->bsi_sel.bb_val );
289 bsi->bsi_sel.bb_len = 0;
290 BER_BVZERO( &bsi->bsi_from.bb_val );
291 bsi->bsi_from.bb_len = 0;
292 BER_BVZERO( &bsi->bsi_join_where.bb_val );
293 bsi->bsi_join_where.bb_len = 0;
294 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
295 bsi->bsi_flt_where.bb_len = 0;
296 bsi->bsi_filter_oc = NULL;
297
298 if ( BACKSQL_IS_GET_ID( flags ) ) {
299 int matched = BACKSQL_IS_MATCHED( flags );
300 int getentry = BACKSQL_IS_GET_ENTRY( flags );
301 int gotit = 0;
302
303 assert( op->o_bd->be_private != NULL );
304
305 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
306 matched, 1 );
307
308 /* the entry is collected either if requested for by getentry
309 * or if get noSuchObject and requested to climb the tree,
310 * so that a matchedDN or a referral can be returned */
311 if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) {
312 if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) {
313 assert( bsi->bsi_e != NULL );
314
315 if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) )
316 {
317 gotit = 1;
318 }
319
320 /*
321 * let's see if it is a referral and, in case, get it
322 */
323 backsql_attrlist_add( bsi, slap_schema.si_ad_ref );
324 rc = backsql_id2entry( bsi, &bsi->bsi_base_id );
325 if ( rc == LDAP_SUCCESS ) {
326 if ( is_entry_referral( bsi->bsi_e ) )
327 {
328 BerVarray erefs = get_entry_referrals( op, bsi->bsi_e );
329 if ( erefs ) {
330 rc = rs->sr_err = LDAP_REFERRAL;
331 rs->sr_ref = referral_rewrite( erefs,
332 &bsi->bsi_e->e_nname,
333 &op->o_req_dn,
334 scope );
335 ber_bvarray_free( erefs );
336
337 } else {
338 rc = rs->sr_err = LDAP_OTHER;
339 rs->sr_text = "bad referral object";
340 }
341
342 } else if ( !gotit ) {
343 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
344 }
345 }
346
347 } else {
348 rs->sr_err = rc;
349 }
350 }
351
352 if ( gotit && BACKSQL_IS_GET_OC( flags ) ) {
353 bsi->bsi_base_id.eid_oc = backsql_id2oc( bi,
354 bsi->bsi_base_id.eid_oc_id );
355 if ( bsi->bsi_base_id.eid_oc == NULL ) {
356 /* error? */
357 backsql_free_entryID( &bsi->bsi_base_id, 1,
358 op->o_tmpmemctx );
359 rc = rs->sr_err = LDAP_OTHER;
360 }
361 }
362 }
363
364 bsi->bsi_status = rc;
365
366 switch ( rc ) {
367 case LDAP_SUCCESS:
368 case LDAP_REFERRAL:
369 break;
370
371 default:
372 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
373 bsi->bsi_op->o_tmpmemctx );
374 break;
375 }
376
377 return rc;
378 }
379
380 static int
backsql_process_filter_list(backsql_srch_info * bsi,Filter * f,int op)381 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
382 {
383 int res;
384
385 if ( !f ) {
386 return 0;
387 }
388
389 backsql_strfcat_x( &bsi->bsi_flt_where,
390 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
391
392 while ( 1 ) {
393 res = backsql_process_filter( bsi, f );
394 if ( res < 0 ) {
395 /*
396 * TimesTen : If the query has no answers,
397 * don't bother to run the query.
398 */
399 return -1;
400 }
401
402 f = f->f_next;
403 if ( f == NULL ) {
404 break;
405 }
406
407 switch ( op ) {
408 case LDAP_FILTER_AND:
409 backsql_strfcat_x( &bsi->bsi_flt_where,
410 bsi->bsi_op->o_tmpmemctx, "l",
411 (ber_len_t)STRLENOF( " AND " ),
412 " AND " );
413 break;
414
415 case LDAP_FILTER_OR:
416 backsql_strfcat_x( &bsi->bsi_flt_where,
417 bsi->bsi_op->o_tmpmemctx, "l",
418 (ber_len_t)STRLENOF( " OR " ),
419 " OR " );
420 break;
421 }
422 }
423
424 backsql_strfcat_x( &bsi->bsi_flt_where,
425 bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' );
426
427 return 1;
428 }
429
430 static int
backsql_process_sub_filter(backsql_srch_info * bsi,Filter * f,backsql_at_map_rec * at)431 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
432 backsql_at_map_rec *at )
433 {
434 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
435 int i;
436 int casefold = 0;
437
438 if ( !f ) {
439 return 0;
440 }
441
442 /* always uppercase strings by now */
443 #ifdef BACKSQL_UPPERCASE_FILTER
444 if ( f->f_sub_desc->ad_type->sat_substr &&
445 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
446 bi->sql_caseIgnoreMatch ) )
447 #endif /* BACKSQL_UPPERCASE_FILTER */
448 {
449 casefold = 1;
450 }
451
452 if ( f->f_sub_desc->ad_type->sat_substr &&
453 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
454 bi->sql_telephoneNumberMatch ) )
455 {
456
457 struct berval bv;
458 ber_len_t i, s, a;
459
460 /*
461 * to check for matching telephone numbers
462 * with intermixed chars, e.g. val='1234'
463 * use
464 *
465 * val LIKE '%1%2%3%4%'
466 */
467
468 BER_BVZERO( &bv );
469 if ( f->f_sub_initial.bv_val ) {
470 bv.bv_len += f->f_sub_initial.bv_len;
471 }
472 if ( f->f_sub_any != NULL ) {
473 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
474 bv.bv_len += f->f_sub_any[ a ].bv_len;
475 }
476 }
477 if ( f->f_sub_final.bv_val ) {
478 bv.bv_len += f->f_sub_final.bv_len;
479 }
480 bv.bv_len = 2 * bv.bv_len - 1;
481 bv.bv_val = ch_malloc( bv.bv_len + 1 );
482
483 s = 0;
484 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
485 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
486 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
487 bv.bv_val[ s + 2 * i - 1 ] = '%';
488 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
489 }
490 bv.bv_val[ s + 2 * i - 1 ] = '%';
491 s += 2 * i;
492 }
493
494 if ( f->f_sub_any != NULL ) {
495 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
496 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
497 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
498 bv.bv_val[ s + 2 * i - 1 ] = '%';
499 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
500 }
501 bv.bv_val[ s + 2 * i - 1 ] = '%';
502 s += 2 * i;
503 }
504 }
505
506 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
507 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
508 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
509 bv.bv_val[ s + 2 * i - 1 ] = '%';
510 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
511 }
512 bv.bv_val[ s + 2 * i - 1 ] = '%';
513 s += 2 * i;
514 }
515
516 bv.bv_val[ s - 1 ] = '\0';
517
518 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
519 ch_free( bv.bv_val );
520
521 return 1;
522 }
523
524 /*
525 * When dealing with case-sensitive strings
526 * we may omit normalization; however, normalized
527 * SQL filters are more liberal.
528 */
529
530 backsql_strfcat_x( &bsi->bsi_flt_where,
531 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
532
533 /* TimesTen */
534 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
535 at->bam_ad->ad_cname.bv_val );
536 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
537 at->bam_sel_expr_u.bv_val ? "' '" : "",
538 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
539 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
540 /*
541 * If a pre-upper-cased version of the column
542 * or a precompiled upper function exists, use it
543 */
544 backsql_strfcat_x( &bsi->bsi_flt_where,
545 bsi->bsi_op->o_tmpmemctx,
546 "bl",
547 &at->bam_sel_expr_u,
548 (ber_len_t)STRLENOF( " LIKE '" ),
549 " LIKE '" );
550
551 } else {
552 backsql_strfcat_x( &bsi->bsi_flt_where,
553 bsi->bsi_op->o_tmpmemctx,
554 "bl",
555 &at->bam_sel_expr,
556 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
557 }
558
559 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
560 ber_len_t start;
561
562 #ifdef BACKSQL_TRACE
563 Debug( LDAP_DEBUG_TRACE,
564 "==>backsql_process_sub_filter(%s): "
565 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
566 f->f_sub_initial.bv_val );
567 #endif /* BACKSQL_TRACE */
568
569 start = bsi->bsi_flt_where.bb_val.bv_len;
570 backsql_strfcat_x( &bsi->bsi_flt_where,
571 bsi->bsi_op->o_tmpmemctx,
572 "b",
573 &f->f_sub_initial );
574 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
575 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
576 }
577 }
578
579 backsql_strfcat_x( &bsi->bsi_flt_where,
580 bsi->bsi_op->o_tmpmemctx,
581 "c", '%' );
582
583 if ( f->f_sub_any != NULL ) {
584 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
585 ber_len_t start;
586
587 #ifdef BACKSQL_TRACE
588 Debug( LDAP_DEBUG_TRACE,
589 "==>backsql_process_sub_filter(%s): "
590 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
591 i, f->f_sub_any[ i ].bv_val );
592 #endif /* BACKSQL_TRACE */
593
594 start = bsi->bsi_flt_where.bb_val.bv_len;
595 backsql_strfcat_x( &bsi->bsi_flt_where,
596 bsi->bsi_op->o_tmpmemctx,
597 "bc",
598 &f->f_sub_any[ i ],
599 '%' );
600 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
601 /*
602 * Note: toupper('%') = '%'
603 */
604 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
605 }
606 }
607 }
608
609 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
610 ber_len_t start;
611
612 #ifdef BACKSQL_TRACE
613 Debug( LDAP_DEBUG_TRACE,
614 "==>backsql_process_sub_filter(%s): "
615 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
616 f->f_sub_final.bv_val );
617 #endif /* BACKSQL_TRACE */
618
619 start = bsi->bsi_flt_where.bb_val.bv_len;
620 backsql_strfcat_x( &bsi->bsi_flt_where,
621 bsi->bsi_op->o_tmpmemctx,
622 "b",
623 &f->f_sub_final );
624 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
625 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
626 }
627 }
628
629 backsql_strfcat_x( &bsi->bsi_flt_where,
630 bsi->bsi_op->o_tmpmemctx,
631 "l",
632 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
633
634 return 1;
635 }
636
637 static int
backsql_merge_from_tbls(backsql_srch_info * bsi,struct berval * from_tbls)638 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
639 {
640 if ( BER_BVISNULL( from_tbls ) ) {
641 return LDAP_SUCCESS;
642 }
643
644 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
645 char *start, *end;
646 struct berval tmp;
647
648 ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx );
649
650 for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) {
651 if ( end ) {
652 end[0] = '\0';
653 }
654
655 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
656 {
657 backsql_strfcat_x( &bsi->bsi_from,
658 bsi->bsi_op->o_tmpmemctx,
659 "cs", ',', start );
660 }
661
662 if ( end ) {
663 /* in case there are spaces after the comma... */
664 for ( start = &end[1]; isspace( start[0] ); start++ );
665 if ( start[0] ) {
666 end = strchr( start, ',' );
667 } else {
668 start = NULL;
669 }
670 } else {
671 start = NULL;
672 }
673 }
674
675 bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx );
676
677 } else {
678 backsql_strfcat_x( &bsi->bsi_from,
679 bsi->bsi_op->o_tmpmemctx,
680 "b", from_tbls );
681 }
682
683 return LDAP_SUCCESS;
684 }
685
686 static int
backsql_process_filter(backsql_srch_info * bsi,Filter * f)687 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
688 {
689 backsql_at_map_rec **vat = NULL;
690 AttributeDescription *ad = NULL;
691 unsigned i;
692 int done = 0;
693 int rc = 0;
694
695 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n" );
696 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
697 struct berval flt;
698 char *msg = NULL;
699
700 switch ( f->f_result ) {
701 case LDAP_COMPARE_TRUE:
702 BER_BVSTR( &flt, "10=10" );
703 msg = "TRUE";
704 break;
705
706 case LDAP_COMPARE_FALSE:
707 BER_BVSTR( &flt, "11=0" );
708 msg = "FALSE";
709 break;
710
711 case SLAPD_COMPARE_UNDEFINED:
712 BER_BVSTR( &flt, "12=0" );
713 msg = "UNDEFINED";
714 break;
715
716 default:
717 rc = -1;
718 goto done;
719 }
720
721 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
722 "filter computed (%s)\n", msg );
723 backsql_strfcat_x( &bsi->bsi_flt_where,
724 bsi->bsi_op->o_tmpmemctx, "b", &flt );
725 rc = 1;
726 goto done;
727 }
728
729 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
730 backsql_strfcat_x( &bsi->bsi_flt_where,
731 bsi->bsi_op->o_tmpmemctx,
732 "l",
733 (ber_len_t)STRLENOF( "1=0" ), "1=0" );
734 done = 1;
735 rc = 1;
736 goto done;
737 }
738
739 switch( f->f_choice ) {
740 case LDAP_FILTER_OR:
741 rc = backsql_process_filter_list( bsi, f->f_or,
742 LDAP_FILTER_OR );
743 done = 1;
744 break;
745
746 case LDAP_FILTER_AND:
747 rc = backsql_process_filter_list( bsi, f->f_and,
748 LDAP_FILTER_AND );
749 done = 1;
750 break;
751
752 case LDAP_FILTER_NOT:
753 backsql_strfcat_x( &bsi->bsi_flt_where,
754 bsi->bsi_op->o_tmpmemctx,
755 "l",
756 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
757 "NOT (" /* ) */ );
758 rc = backsql_process_filter( bsi, f->f_not );
759 backsql_strfcat_x( &bsi->bsi_flt_where,
760 bsi->bsi_op->o_tmpmemctx,
761 "c", /* ( */ ')' );
762 done = 1;
763 break;
764
765 case LDAP_FILTER_PRESENT:
766 ad = f->f_desc;
767 break;
768
769 case LDAP_FILTER_EXT:
770 ad = f->f_mra->ma_desc;
771 if ( f->f_mr_dnattrs ) {
772 /*
773 * if dn attrs filtering is requested, better return
774 * success and let test_filter() deal with candidate
775 * selection; otherwise we'd need to set conditions
776 * on the contents of the DN, e.g. "SELECT ... FROM
777 * ldap_entries AS attributeName WHERE attributeName.dn
778 * like '%attributeName=value%'"
779 */
780 backsql_strfcat_x( &bsi->bsi_flt_where,
781 bsi->bsi_op->o_tmpmemctx,
782 "l",
783 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
784 bsi->bsi_status = LDAP_SUCCESS;
785 rc = 1;
786 goto done;
787 }
788 break;
789
790 default:
791 ad = f->f_av_desc;
792 break;
793 }
794
795 if ( rc == -1 ) {
796 goto done;
797 }
798
799 if ( done ) {
800 rc = 1;
801 goto done;
802 }
803
804 /*
805 * Turn structuralObjectClass into objectClass
806 */
807 if ( ad == slap_schema.si_ad_objectClass
808 || ad == slap_schema.si_ad_structuralObjectClass )
809 {
810 /*
811 * If the filter is LDAP_FILTER_PRESENT, then it's done;
812 * otherwise, let's see if we are lucky: filtering
813 * for "structural" objectclass or ancestor...
814 */
815 switch ( f->f_choice ) {
816 case LDAP_FILTER_EQUALITY:
817 {
818 ObjectClass *oc = oc_bvfind( &f->f_av_value );
819
820 if ( oc == NULL ) {
821 Debug( LDAP_DEBUG_TRACE,
822 "backsql_process_filter(): "
823 "unknown objectClass \"%s\" "
824 "in filter\n",
825 f->f_av_value.bv_val );
826 bsi->bsi_status = LDAP_OTHER;
827 rc = -1;
828 goto done;
829 }
830
831 /*
832 * "structural" objectClass inheritance:
833 * - a search for "person" will also return
834 * "inetOrgPerson"
835 * - a search for "top" will return everything
836 */
837 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
838 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
839
840 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
841
842 backsql_strfcat_x( &bsi->bsi_flt_where,
843 bsi->bsi_op->o_tmpmemctx,
844 "lbl",
845 (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ),
846 "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */,
847 &bsi->bsi_oc->bom_oc->soc_cname,
848 (ber_len_t)STRLENOF( /* ((' */ "'))" ),
849 /* ((' */ "'))" );
850 bsi->bsi_status = LDAP_SUCCESS;
851 rc = 1;
852 goto done;
853 }
854
855 break;
856 }
857
858 case LDAP_FILTER_PRESENT:
859 backsql_strfcat_x( &bsi->bsi_flt_where,
860 bsi->bsi_op->o_tmpmemctx,
861 "l",
862 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
863 bsi->bsi_status = LDAP_SUCCESS;
864 rc = 1;
865 goto done;
866
867 /* FIXME: LDAP_FILTER_EXT? */
868
869 default:
870 Debug( LDAP_DEBUG_TRACE,
871 "backsql_process_filter(): "
872 "illegal/unhandled filter "
873 "on objectClass attribute" );
874 bsi->bsi_status = LDAP_OTHER;
875 rc = -1;
876 goto done;
877 }
878
879 } else if ( ad == slap_schema.si_ad_entryUUID ) {
880 unsigned long oc_id;
881 #ifdef BACKSQL_ARBITRARY_KEY
882 struct berval keyval;
883 #else /* ! BACKSQL_ARBITRARY_KEY */
884 unsigned long keyval;
885 char keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
886 #endif /* ! BACKSQL_ARBITRARY_KEY */
887
888 switch ( f->f_choice ) {
889 case LDAP_FILTER_EQUALITY:
890 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
891
892 if ( oc_id != bsi->bsi_oc->bom_id ) {
893 bsi->bsi_status = LDAP_SUCCESS;
894 rc = -1;
895 goto done;
896 }
897
898 #ifdef BACKSQL_ARBITRARY_KEY
899 backsql_strfcat_x( &bsi->bsi_flt_where,
900 bsi->bsi_op->o_tmpmemctx,
901 "bcblbc",
902 &bsi->bsi_oc->bom_keytbl, '.',
903 &bsi->bsi_oc->bom_keycol,
904 STRLENOF( " LIKE '" ), " LIKE '",
905 &keyval, '\'' );
906 #else /* ! BACKSQL_ARBITRARY_KEY */
907 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
908 backsql_strfcat_x( &bsi->bsi_flt_where,
909 bsi->bsi_op->o_tmpmemctx,
910 "bcbcs",
911 &bsi->bsi_oc->bom_keytbl, '.',
912 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
913 #endif /* ! BACKSQL_ARBITRARY_KEY */
914 break;
915
916 case LDAP_FILTER_PRESENT:
917 backsql_strfcat_x( &bsi->bsi_flt_where,
918 bsi->bsi_op->o_tmpmemctx,
919 "l",
920 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
921 break;
922
923 default:
924 rc = -1;
925 goto done;
926 }
927
928 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
929 rc = 1;
930 goto done;
931
932 #ifdef BACKSQL_SYNCPROV
933 } else if ( ad == slap_schema.si_ad_entryCSN ) {
934 /*
935 * support for syncrepl as provider...
936 */
937 #if 0
938 if ( !bsi->bsi_op->o_sync ) {
939 /* unsupported at present... */
940 bsi->bsi_status = LDAP_OTHER;
941 rc = -1;
942 goto done;
943 }
944 #endif
945
946 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
947
948 /* if doing a syncrepl, try to return as much as possible,
949 * and always match the filter */
950 backsql_strfcat_x( &bsi->bsi_flt_where,
951 bsi->bsi_op->o_tmpmemctx,
952 "l",
953 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
954
955 /* save for later use in operational attributes */
956 /* FIXME: saves only the first occurrence, because
957 * the filter during updates is written as
958 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
959 * so we want our fake entryCSN to match the greatest
960 * value
961 */
962 if ( bsi->bsi_op->o_private == NULL ) {
963 bsi->bsi_op->o_private = &f->f_av_value;
964 }
965 bsi->bsi_status = LDAP_SUCCESS;
966
967 rc = 1;
968 goto done;
969 #endif /* BACKSQL_SYNCPROV */
970
971 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
972 /*
973 * FIXME: this is not robust; e.g. a filter
974 * '(!(hasSubordinates=TRUE))' fails because
975 * in SQL it would read 'NOT (1=1)' instead
976 * of no condition.
977 * Note however that hasSubordinates is boolean,
978 * so a more appropriate filter would be
979 * '(hasSubordinates=FALSE)'
980 *
981 * A more robust search for hasSubordinates
982 * would * require joining the ldap_entries table
983 * selecting if there are descendants of the
984 * candidate.
985 */
986 backsql_strfcat_x( &bsi->bsi_flt_where,
987 bsi->bsi_op->o_tmpmemctx,
988 "l",
989 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
990 if ( ad == slap_schema.si_ad_hasSubordinates ) {
991 /*
992 * instruct candidate selection algorithm
993 * and attribute list to try to detect
994 * if an entry has subordinates
995 */
996 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
997
998 } else {
999 /*
1000 * clear attributes to fetch, to require ALL
1001 * and try extended match on all attributes
1002 */
1003 backsql_attrlist_add( bsi, NULL );
1004 }
1005 rc = 1;
1006 goto done;
1007 }
1008
1009 /*
1010 * attribute inheritance:
1011 */
1012 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
1013 bsi->bsi_status = LDAP_OTHER;
1014 rc = -1;
1015 goto done;
1016 }
1017
1018 if ( vat == NULL ) {
1019 /* search anyway; other parts of the filter
1020 * may succeed */
1021 backsql_strfcat_x( &bsi->bsi_flt_where,
1022 bsi->bsi_op->o_tmpmemctx,
1023 "l",
1024 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
1025 bsi->bsi_status = LDAP_SUCCESS;
1026 rc = 1;
1027 goto done;
1028 }
1029
1030 /* if required, open extra level of parens */
1031 done = 0;
1032 if ( vat[0]->bam_next || vat[1] ) {
1033 backsql_strfcat_x( &bsi->bsi_flt_where,
1034 bsi->bsi_op->o_tmpmemctx,
1035 "c", '(' );
1036 done = 1;
1037 }
1038
1039 i = 0;
1040 next:;
1041 /* apply attr */
1042 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
1043 return -1;
1044 }
1045
1046 /* if more definitions of the same attr, apply */
1047 if ( vat[i]->bam_next ) {
1048 backsql_strfcat_x( &bsi->bsi_flt_where,
1049 bsi->bsi_op->o_tmpmemctx,
1050 "l",
1051 STRLENOF( " OR " ), " OR " );
1052 vat[i] = vat[i]->bam_next;
1053 goto next;
1054 }
1055
1056 /* if more descendants of the same attr, apply */
1057 i++;
1058 if ( vat[i] ) {
1059 backsql_strfcat_x( &bsi->bsi_flt_where,
1060 bsi->bsi_op->o_tmpmemctx,
1061 "l",
1062 STRLENOF( " OR " ), " OR " );
1063 goto next;
1064 }
1065
1066 /* if needed, close extra level of parens */
1067 if ( done ) {
1068 backsql_strfcat_x( &bsi->bsi_flt_where,
1069 bsi->bsi_op->o_tmpmemctx,
1070 "c", ')' );
1071 }
1072
1073 rc = 1;
1074
1075 done:;
1076 if ( vat ) {
1077 ch_free( vat );
1078 }
1079
1080 Debug( LDAP_DEBUG_TRACE,
1081 "<==backsql_process_filter() %s\n",
1082 rc == 1 ? "succeeded" : "failed" );
1083
1084 return rc;
1085 }
1086
1087 static int
backsql_process_filter_eq(backsql_srch_info * bsi,backsql_at_map_rec * at,int casefold,struct berval * filter_value)1088 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
1089 int casefold, struct berval *filter_value )
1090 {
1091 /*
1092 * maybe we should check type of at->sel_expr here somehow,
1093 * to know whether upper_func is applicable, but for now
1094 * upper_func stuff is made for Oracle, where UPPER is
1095 * safely applicable to NUMBER etc.
1096 */
1097 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1098 ber_len_t start;
1099
1100 backsql_strfcat_x( &bsi->bsi_flt_where,
1101 bsi->bsi_op->o_tmpmemctx,
1102 "cbl",
1103 '(', /* ) */
1104 &at->bam_sel_expr_u,
1105 (ber_len_t)STRLENOF( "='" ),
1106 "='" );
1107
1108 start = bsi->bsi_flt_where.bb_val.bv_len;
1109
1110 backsql_strfcat_x( &bsi->bsi_flt_where,
1111 bsi->bsi_op->o_tmpmemctx,
1112 "bl",
1113 filter_value,
1114 (ber_len_t)STRLENOF( /* (' */ "')" ),
1115 /* (' */ "')" );
1116
1117 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1118
1119 } else {
1120 backsql_strfcat_x( &bsi->bsi_flt_where,
1121 bsi->bsi_op->o_tmpmemctx,
1122 "cblbl",
1123 '(', /* ) */
1124 &at->bam_sel_expr,
1125 (ber_len_t)STRLENOF( "='" ), "='",
1126 filter_value,
1127 (ber_len_t)STRLENOF( /* (' */ "')" ),
1128 /* (' */ "')" );
1129 }
1130
1131 return 1;
1132 }
1133
1134 static int
backsql_process_filter_like(backsql_srch_info * bsi,backsql_at_map_rec * at,int casefold,struct berval * filter_value)1135 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
1136 int casefold, struct berval *filter_value )
1137 {
1138 /*
1139 * maybe we should check type of at->sel_expr here somehow,
1140 * to know whether upper_func is applicable, but for now
1141 * upper_func stuff is made for Oracle, where UPPER is
1142 * safely applicable to NUMBER etc.
1143 */
1144 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1145 ber_len_t start;
1146
1147 backsql_strfcat_x( &bsi->bsi_flt_where,
1148 bsi->bsi_op->o_tmpmemctx,
1149 "cbl",
1150 '(', /* ) */
1151 &at->bam_sel_expr_u,
1152 (ber_len_t)STRLENOF( " LIKE '%" ),
1153 " LIKE '%" );
1154
1155 start = bsi->bsi_flt_where.bb_val.bv_len;
1156
1157 backsql_strfcat_x( &bsi->bsi_flt_where,
1158 bsi->bsi_op->o_tmpmemctx,
1159 "bl",
1160 filter_value,
1161 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1162 /* (' */ "%')" );
1163
1164 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1165
1166 } else {
1167 backsql_strfcat_x( &bsi->bsi_flt_where,
1168 bsi->bsi_op->o_tmpmemctx,
1169 "cblbl",
1170 '(', /* ) */
1171 &at->bam_sel_expr,
1172 (ber_len_t)STRLENOF( " LIKE '%" ),
1173 " LIKE '%",
1174 filter_value,
1175 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1176 /* (' */ "%')" );
1177 }
1178
1179 return 1;
1180 }
1181
1182 static int
backsql_process_filter_attr(backsql_srch_info * bsi,Filter * f,backsql_at_map_rec * at)1183 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
1184 {
1185 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1186 int casefold = 0;
1187 struct berval *filter_value = NULL;
1188 MatchingRule *matching_rule = NULL;
1189 struct berval ordering = BER_BVC("<=");
1190
1191 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1192 at->bam_ad->ad_cname.bv_val );
1193
1194 /*
1195 * need to add this attribute to list of attrs to load,
1196 * so that we can do test_filter() later
1197 */
1198 backsql_attrlist_add( bsi, at->bam_ad );
1199
1200 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1201
1202 if ( !BER_BVISNULL( &at->bam_join_where )
1203 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1204 at->bam_join_where.bv_val ) == NULL )
1205 {
1206 backsql_strfcat_x( &bsi->bsi_join_where,
1207 bsi->bsi_op->o_tmpmemctx,
1208 "lb",
1209 (ber_len_t)STRLENOF( " AND " ), " AND ",
1210 &at->bam_join_where );
1211 }
1212
1213 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
1214 backsql_strfcat_x( &bsi->bsi_flt_where,
1215 bsi->bsi_op->o_tmpmemctx,
1216 "l",
1217 (ber_len_t)STRLENOF( "1=0" ), "1=0" );
1218 return 1;
1219 }
1220
1221 switch ( f->f_choice ) {
1222 case LDAP_FILTER_EQUALITY:
1223 filter_value = &f->f_av_value;
1224 matching_rule = at->bam_ad->ad_type->sat_equality;
1225
1226 goto equality_match;
1227
1228 /* fail over into next case */
1229
1230 case LDAP_FILTER_EXT:
1231 filter_value = &f->f_mra->ma_value;
1232 matching_rule = f->f_mr_rule;
1233
1234 equality_match:;
1235 /* always uppercase strings by now */
1236 #ifdef BACKSQL_UPPERCASE_FILTER
1237 if ( SLAP_MR_ASSOCIATED( matching_rule,
1238 bi->sql_caseIgnoreMatch ) )
1239 #endif /* BACKSQL_UPPERCASE_FILTER */
1240 {
1241 casefold = 1;
1242 }
1243
1244 /* FIXME: directoryString filtering should use a similar
1245 * approach to deal with non-prettified values like
1246 * " A non prettified value ", by using a LIKE
1247 * filter with all whitespaces collapsed to a single '%' */
1248 if ( SLAP_MR_ASSOCIATED( matching_rule,
1249 bi->sql_telephoneNumberMatch ) )
1250 {
1251 struct berval bv;
1252 ber_len_t i;
1253
1254 /*
1255 * to check for matching telephone numbers
1256 * with intermized chars, e.g. val='1234'
1257 * use
1258 *
1259 * val LIKE '%1%2%3%4%'
1260 */
1261
1262 bv.bv_len = 2 * filter_value->bv_len - 1;
1263 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1264
1265 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1266 for ( i = 1; i < filter_value->bv_len; i++ ) {
1267 bv.bv_val[ 2 * i - 1 ] = '%';
1268 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1269 }
1270 bv.bv_val[ 2 * i - 1 ] = '\0';
1271
1272 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1273 ch_free( bv.bv_val );
1274
1275 break;
1276 }
1277
1278 /* NOTE: this is required by objectClass inheritance
1279 * and auxiliary objectClass use in filters for slightly
1280 * more efficient candidate selection. */
1281 /* FIXME: a bit too many specializations to deal with
1282 * very specific cases... */
1283 if ( at->bam_ad == slap_schema.si_ad_objectClass
1284 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1285 {
1286 backsql_strfcat_x( &bsi->bsi_flt_where,
1287 bsi->bsi_op->o_tmpmemctx,
1288 "lbl",
1289 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1290 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1291 filter_value,
1292 (ber_len_t)STRLENOF( /* (' */ "')" ),
1293 /* (' */ "')" );
1294 break;
1295 }
1296
1297 /*
1298 * maybe we should check type of at->sel_expr here somehow,
1299 * to know whether upper_func is applicable, but for now
1300 * upper_func stuff is made for Oracle, where UPPER is
1301 * safely applicable to NUMBER etc.
1302 */
1303 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1304 break;
1305
1306 case LDAP_FILTER_GE:
1307 ordering.bv_val = ">=";
1308
1309 /* fall thru to next case */
1310
1311 case LDAP_FILTER_LE:
1312 filter_value = &f->f_av_value;
1313
1314 /* always uppercase strings by now */
1315 #ifdef BACKSQL_UPPERCASE_FILTER
1316 if ( at->bam_ad->ad_type->sat_ordering &&
1317 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1318 bi->sql_caseIgnoreMatch ) )
1319 #endif /* BACKSQL_UPPERCASE_FILTER */
1320 {
1321 casefold = 1;
1322 }
1323
1324 /*
1325 * FIXME: should we uppercase the operands?
1326 */
1327 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1328 ber_len_t start;
1329
1330 backsql_strfcat_x( &bsi->bsi_flt_where,
1331 bsi->bsi_op->o_tmpmemctx,
1332 "cbbc",
1333 '(', /* ) */
1334 &at->bam_sel_expr_u,
1335 &ordering,
1336 '\'' );
1337
1338 start = bsi->bsi_flt_where.bb_val.bv_len;
1339
1340 backsql_strfcat_x( &bsi->bsi_flt_where,
1341 bsi->bsi_op->o_tmpmemctx,
1342 "bl",
1343 filter_value,
1344 (ber_len_t)STRLENOF( /* (' */ "')" ),
1345 /* (' */ "')" );
1346
1347 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1348
1349 } else {
1350 backsql_strfcat_x( &bsi->bsi_flt_where,
1351 bsi->bsi_op->o_tmpmemctx,
1352 "cbbcbl",
1353 '(' /* ) */ ,
1354 &at->bam_sel_expr,
1355 &ordering,
1356 '\'',
1357 &f->f_av_value,
1358 (ber_len_t)STRLENOF( /* (' */ "')" ),
1359 /* ( */ "')" );
1360 }
1361 break;
1362
1363 case LDAP_FILTER_PRESENT:
1364 backsql_strfcat_x( &bsi->bsi_flt_where,
1365 bsi->bsi_op->o_tmpmemctx,
1366 "lbl",
1367 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1368 "NOT (", /* ) */
1369 &at->bam_sel_expr,
1370 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1371 /* ( */ " IS NULL)" );
1372 break;
1373
1374 case LDAP_FILTER_SUBSTRINGS:
1375 backsql_process_sub_filter( bsi, f, at );
1376 break;
1377
1378 case LDAP_FILTER_APPROX:
1379 /* we do our best */
1380
1381 /*
1382 * maybe we should check type of at->sel_expr here somehow,
1383 * to know whether upper_func is applicable, but for now
1384 * upper_func stuff is made for Oracle, where UPPER is
1385 * safely applicable to NUMBER etc.
1386 */
1387 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1388 break;
1389
1390 default:
1391 /* unhandled filter type; should not happen */
1392 assert( 0 );
1393 backsql_strfcat_x( &bsi->bsi_flt_where,
1394 bsi->bsi_op->o_tmpmemctx,
1395 "l",
1396 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1397 break;
1398
1399 }
1400
1401 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1402 at->bam_ad->ad_cname.bv_val );
1403
1404 return 1;
1405 }
1406
1407 static int
backsql_srch_query(backsql_srch_info * bsi,struct berval * query)1408 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1409 {
1410 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1411 int rc;
1412
1413 assert( query != NULL );
1414 BER_BVZERO( query );
1415
1416 bsi->bsi_use_subtree_shortcut = 0;
1417
1418 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n" );
1419 BER_BVZERO( &bsi->bsi_sel.bb_val );
1420 BER_BVZERO( &bsi->bsi_sel.bb_val );
1421 bsi->bsi_sel.bb_len = 0;
1422 BER_BVZERO( &bsi->bsi_from.bb_val );
1423 bsi->bsi_from.bb_len = 0;
1424 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1425 bsi->bsi_join_where.bb_len = 0;
1426 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1427 bsi->bsi_flt_where.bb_len = 0;
1428
1429 backsql_strfcat_x( &bsi->bsi_sel,
1430 bsi->bsi_op->o_tmpmemctx,
1431 "lbcbc",
1432 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1433 "SELECT DISTINCT ldap_entries.id,",
1434 &bsi->bsi_oc->bom_keytbl,
1435 '.',
1436 &bsi->bsi_oc->bom_keycol,
1437 ',' );
1438
1439 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1440 backsql_strfcat_x( &bsi->bsi_sel,
1441 bsi->bsi_op->o_tmpmemctx,
1442 "blbl",
1443 &bi->sql_strcast_func,
1444 (ber_len_t)STRLENOF( "('" /* ') */ ),
1445 "('" /* ') */ ,
1446 &bsi->bsi_oc->bom_oc->soc_cname,
1447 (ber_len_t)STRLENOF( /* (' */ "')" ),
1448 /* (' */ "')" );
1449 } else {
1450 backsql_strfcat_x( &bsi->bsi_sel,
1451 bsi->bsi_op->o_tmpmemctx,
1452 "cbc",
1453 '\'',
1454 &bsi->bsi_oc->bom_oc->soc_cname,
1455 '\'' );
1456 }
1457
1458 backsql_strfcat_x( &bsi->bsi_sel,
1459 bsi->bsi_op->o_tmpmemctx,
1460 "b",
1461 &bi->sql_dn_oc_aliasing );
1462 backsql_strfcat_x( &bsi->bsi_from,
1463 bsi->bsi_op->o_tmpmemctx,
1464 "lb",
1465 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1466 " FROM ldap_entries,",
1467 &bsi->bsi_oc->bom_keytbl );
1468
1469 backsql_strfcat_x( &bsi->bsi_join_where,
1470 bsi->bsi_op->o_tmpmemctx,
1471 "lbcbl",
1472 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1473 &bsi->bsi_oc->bom_keytbl,
1474 '.',
1475 &bsi->bsi_oc->bom_keycol,
1476 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1477 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1478
1479 switch ( bsi->bsi_scope ) {
1480 case LDAP_SCOPE_BASE:
1481 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1482 backsql_strfcat_x( &bsi->bsi_join_where,
1483 bsi->bsi_op->o_tmpmemctx,
1484 "bl",
1485 &bi->sql_upper_func,
1486 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1487 "(ldap_entries.dn)=?" );
1488 } else {
1489 backsql_strfcat_x( &bsi->bsi_join_where,
1490 bsi->bsi_op->o_tmpmemctx,
1491 "l",
1492 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1493 "ldap_entries.dn=?" );
1494 }
1495 break;
1496
1497 case BACKSQL_SCOPE_BASE_LIKE:
1498 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1499 backsql_strfcat_x( &bsi->bsi_join_where,
1500 bsi->bsi_op->o_tmpmemctx,
1501 "bl",
1502 &bi->sql_upper_func,
1503 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1504 "(ldap_entries.dn) LIKE ?" );
1505 } else {
1506 backsql_strfcat_x( &bsi->bsi_join_where,
1507 bsi->bsi_op->o_tmpmemctx,
1508 "l",
1509 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1510 "ldap_entries.dn LIKE ?" );
1511 }
1512 break;
1513
1514 case LDAP_SCOPE_ONELEVEL:
1515 backsql_strfcat_x( &bsi->bsi_join_where,
1516 bsi->bsi_op->o_tmpmemctx,
1517 "l",
1518 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1519 "ldap_entries.parent=?" );
1520 break;
1521
1522 case LDAP_SCOPE_SUBORDINATE:
1523 case LDAP_SCOPE_SUBTREE:
1524 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1525 int i;
1526 BackendDB *bd = bsi->bsi_op->o_bd;
1527
1528 assert( bd->be_nsuffix != NULL );
1529
1530 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1531 {
1532 if ( dn_match( &bd->be_nsuffix[ i ],
1533 bsi->bsi_base_ndn ) )
1534 {
1535 /* pass this to the candidate selection
1536 * routine so that the DN is not bound
1537 * to the select statement */
1538 bsi->bsi_use_subtree_shortcut = 1;
1539 break;
1540 }
1541 }
1542 }
1543
1544 if ( bsi->bsi_use_subtree_shortcut ) {
1545 /* Skip the base DN filter, as every entry will match it */
1546 backsql_strfcat_x( &bsi->bsi_join_where,
1547 bsi->bsi_op->o_tmpmemctx,
1548 "l",
1549 (ber_len_t)STRLENOF( "9=9"), "9=9");
1550
1551 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1552 /* This should always be true... */
1553 backsql_strfcat_x( &bsi->bsi_join_where,
1554 bsi->bsi_op->o_tmpmemctx,
1555 "b",
1556 &bi->sql_subtree_cond );
1557
1558 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1559 backsql_strfcat_x( &bsi->bsi_join_where,
1560 bsi->bsi_op->o_tmpmemctx,
1561 "bl",
1562 &bi->sql_upper_func,
1563 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1564 "(ldap_entries.dn) LIKE ?" );
1565
1566 } else {
1567 backsql_strfcat_x( &bsi->bsi_join_where,
1568 bsi->bsi_op->o_tmpmemctx,
1569 "l",
1570 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1571 "ldap_entries.dn LIKE ?" );
1572 }
1573
1574 break;
1575
1576 default:
1577 assert( 0 );
1578 }
1579
1580 #ifndef BACKSQL_ARBITRARY_KEY
1581 /* If paged results are in effect, ignore low ldap_entries.id numbers */
1582 if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) {
1583 unsigned long lowid = 0;
1584
1585 /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */
1586 if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) )
1587 {
1588 lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie );
1589 }
1590
1591 if ( lowid ) {
1592 char lowidstring[48];
1593 int lowidlen;
1594
1595 lowidlen = snprintf( lowidstring, sizeof( lowidstring ),
1596 " AND ldap_entries.id>%lu", lowid );
1597 backsql_strfcat_x( &bsi->bsi_join_where,
1598 bsi->bsi_op->o_tmpmemctx,
1599 "l",
1600 (ber_len_t)lowidlen,
1601 lowidstring );
1602 }
1603 }
1604 #endif /* ! BACKSQL_ARBITRARY_KEY */
1605
1606 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1607 if ( rc > 0 ) {
1608 struct berbuf bb = BB_NULL;
1609
1610 backsql_strfcat_x( &bb,
1611 bsi->bsi_op->o_tmpmemctx,
1612 "bbblb",
1613 &bsi->bsi_sel.bb_val,
1614 &bsi->bsi_from.bb_val,
1615 &bsi->bsi_join_where.bb_val,
1616 (ber_len_t)STRLENOF( " AND " ), " AND ",
1617 &bsi->bsi_flt_where.bb_val );
1618
1619 *query = bb.bb_val;
1620
1621 } else if ( rc < 0 ) {
1622 /*
1623 * Indicates that there's no possible way the filter matches
1624 * anything. No need to issue the query
1625 */
1626 free( query->bv_val );
1627 BER_BVZERO( query );
1628 }
1629
1630 bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1631 BER_BVZERO( &bsi->bsi_sel.bb_val );
1632 bsi->bsi_sel.bb_len = 0;
1633 bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1634 BER_BVZERO( &bsi->bsi_from.bb_val );
1635 bsi->bsi_from.bb_len = 0;
1636 bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1637 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1638 bsi->bsi_join_where.bb_len = 0;
1639 bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1640 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1641 bsi->bsi_flt_where.bb_len = 0;
1642
1643 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1644 query->bv_val ? query->bv_val : "NULL" );
1645
1646 return ( rc <= 0 ? 1 : 0 );
1647 }
1648
1649 static int
backsql_oc_get_candidates(void * v_oc,void * v_bsi)1650 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1651 {
1652 backsql_oc_map_rec *oc = v_oc;
1653 backsql_srch_info *bsi = v_bsi;
1654 Operation *op = bsi->bsi_op;
1655 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1656 struct berval query;
1657 SQLHSTMT sth = SQL_NULL_HSTMT;
1658 RETCODE rc;
1659 int res;
1660 BACKSQL_ROW_NTS row;
1661 int i;
1662 int j;
1663 int n_candidates = bsi->bsi_n_candidates;
1664
1665 /*
1666 * + 1 because we need room for '%';
1667 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1668 * this makes a subtree
1669 * search for a DN BACKSQL_MAX_DN_LEN long legal
1670 * if it returns that DN only
1671 */
1672 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1673
1674 bsi->bsi_status = LDAP_SUCCESS;
1675
1676 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1677 BACKSQL_OC_NAME( oc ) );
1678
1679 /* check for abandon */
1680 if ( op->o_abandon ) {
1681 bsi->bsi_status = SLAPD_ABANDON;
1682 return BACKSQL_AVL_STOP;
1683 }
1684
1685 #ifndef BACKSQL_ARBITRARY_KEY
1686 /* If paged results have already completed this objectClass, skip it */
1687 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
1688 if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) )
1689 {
1690 return BACKSQL_AVL_CONTINUE;
1691 }
1692 }
1693 #endif /* ! BACKSQL_ARBITRARY_KEY */
1694
1695 if ( bsi->bsi_n_candidates == -1 ) {
1696 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1697 "unchecked limit has been overcome\n" );
1698 /* should never get here */
1699 assert( 0 );
1700 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1701 return BACKSQL_AVL_STOP;
1702 }
1703
1704 bsi->bsi_oc = oc;
1705 res = backsql_srch_query( bsi, &query );
1706 if ( res ) {
1707 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1708 "error while constructing query for objectclass \"%s\"\n",
1709 oc->bom_oc->soc_cname.bv_val );
1710 /*
1711 * FIXME: need to separate errors from legally
1712 * impossible filters
1713 */
1714 switch ( bsi->bsi_status ) {
1715 case LDAP_SUCCESS:
1716 case LDAP_UNDEFINED_TYPE:
1717 case LDAP_NO_SUCH_OBJECT:
1718 /* we are conservative... */
1719 default:
1720 bsi->bsi_status = LDAP_SUCCESS;
1721 /* try next */
1722 return BACKSQL_AVL_CONTINUE;
1723
1724 case LDAP_ADMINLIMIT_EXCEEDED:
1725 case LDAP_OTHER:
1726 /* don't try any more */
1727 return BACKSQL_AVL_STOP;
1728 }
1729 }
1730
1731 if ( BER_BVISNULL( &query ) ) {
1732 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1733 "could not construct query for objectclass \"%s\"\n",
1734 oc->bom_oc->soc_cname.bv_val );
1735 bsi->bsi_status = LDAP_SUCCESS;
1736 return BACKSQL_AVL_CONTINUE;
1737 }
1738
1739 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1740 query.bv_val );
1741
1742 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1743 bsi->bsi_op->o_tmpfree( query.bv_val, bsi->bsi_op->o_tmpmemctx );
1744 BER_BVZERO( &query );
1745 if ( rc != SQL_SUCCESS ) {
1746 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1747 "error preparing query\n" );
1748 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1749 bsi->bsi_status = LDAP_OTHER;
1750 return BACKSQL_AVL_CONTINUE;
1751 }
1752
1753 Debug( LDAP_DEBUG_TRACE, "id: '" BACKSQL_IDNUMFMT "'\n",
1754 bsi->bsi_oc->bom_id );
1755
1756 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT,
1757 &bsi->bsi_oc->bom_id );
1758 if ( rc != SQL_SUCCESS ) {
1759 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1760 "error binding objectclass id parameter\n" );
1761 bsi->bsi_status = LDAP_OTHER;
1762 return BACKSQL_AVL_CONTINUE;
1763 }
1764
1765 switch ( bsi->bsi_scope ) {
1766 case LDAP_SCOPE_BASE:
1767 case BACKSQL_SCOPE_BASE_LIKE:
1768 /*
1769 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1770 * however this should be handled earlier
1771 */
1772 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1773 bsi->bsi_status = LDAP_OTHER;
1774 return BACKSQL_AVL_CONTINUE;
1775 }
1776
1777 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1778 bsi->bsi_base_ndn->bv_len + 1 );
1779
1780 /* uppercase DN only if the stored DN can be uppercased
1781 * for comparison */
1782 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1783 ldap_pvt_str2upper( tmp_base_ndn );
1784 }
1785
1786 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1787 tmp_base_ndn );
1788
1789 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1790 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1791 if ( rc != SQL_SUCCESS ) {
1792 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1793 "error binding base_ndn parameter\n" );
1794 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1795 sth, rc );
1796 bsi->bsi_status = LDAP_OTHER;
1797 return BACKSQL_AVL_CONTINUE;
1798 }
1799 break;
1800
1801 case LDAP_SCOPE_SUBORDINATE:
1802 case LDAP_SCOPE_SUBTREE:
1803 {
1804 /* if short-cutting the search base,
1805 * don't bind any parameter */
1806 if ( bsi->bsi_use_subtree_shortcut ) {
1807 break;
1808 }
1809
1810 /*
1811 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1812 * however this should be handled earlier
1813 */
1814 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1815 bsi->bsi_status = LDAP_OTHER;
1816 return BACKSQL_AVL_CONTINUE;
1817 }
1818
1819 /*
1820 * Sets the parameters for the SQL built earlier
1821 * NOTE that all the databases could actually use
1822 * the TimesTen version, which would be cleaner
1823 * and would also eliminate the need for the
1824 * subtree_cond line in the configuration file.
1825 * For now, I'm leaving it the way it is,
1826 * so non-TimesTen databases use the original code.
1827 * But at some point this should get cleaned up.
1828 *
1829 * If "dn" is being used, do a suffix search.
1830 * If "dn_ru" is being used, do a prefix search.
1831 */
1832 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1833 tmp_base_ndn[ 0 ] = '\0';
1834
1835 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1836 j >= 0; i++, j--) {
1837 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1838 }
1839
1840 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1841 tmp_base_ndn[ i++ ] = ',';
1842 }
1843
1844 tmp_base_ndn[ i ] = '%';
1845 tmp_base_ndn[ i + 1 ] = '\0';
1846
1847 } else {
1848 i = 0;
1849
1850 tmp_base_ndn[ i++ ] = '%';
1851
1852 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1853 tmp_base_ndn[ i++ ] = ',';
1854 }
1855
1856 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1857 bsi->bsi_base_ndn->bv_len + 1 );
1858 }
1859
1860 /* uppercase DN only if the stored DN can be uppercased
1861 * for comparison */
1862 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1863 ldap_pvt_str2upper( tmp_base_ndn );
1864 }
1865
1866 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1867 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1868 tmp_base_ndn );
1869 } else {
1870 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1871 tmp_base_ndn );
1872 }
1873
1874 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1875 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1876 if ( rc != SQL_SUCCESS ) {
1877 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1878 "error binding base_ndn parameter (2)\n" );
1879 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1880 sth, rc );
1881 bsi->bsi_status = LDAP_OTHER;
1882 return BACKSQL_AVL_CONTINUE;
1883 }
1884 break;
1885 }
1886
1887 case LDAP_SCOPE_ONELEVEL:
1888 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1889
1890 Debug( LDAP_DEBUG_TRACE, "(one)id=" BACKSQL_IDFMT "\n",
1891 BACKSQL_IDARG(bsi->bsi_base_id.eid_id) );
1892 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1893 &bsi->bsi_base_id.eid_id );
1894 if ( rc != SQL_SUCCESS ) {
1895 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1896 "error binding base id parameter\n" );
1897 bsi->bsi_status = LDAP_OTHER;
1898 return BACKSQL_AVL_CONTINUE;
1899 }
1900 break;
1901 }
1902
1903 rc = SQLExecute( sth );
1904 if ( !BACKSQL_SUCCESS( rc ) ) {
1905 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1906 "error executing query\n" );
1907 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1908 SQLFreeStmt( sth, SQL_DROP );
1909 bsi->bsi_status = LDAP_OTHER;
1910 return BACKSQL_AVL_CONTINUE;
1911 }
1912
1913 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
1914 rc = SQLFetch( sth );
1915 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1916 struct berval dn, pdn, ndn;
1917 backsql_entryID *c_id = NULL;
1918 int ret;
1919
1920 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1921
1922 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1923 continue;
1924 }
1925
1926 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
1927 if ( dn.bv_val != row.cols[ 3 ] ) {
1928 free( dn.bv_val );
1929 }
1930
1931 if ( ret != LDAP_SUCCESS ) {
1932 continue;
1933 }
1934
1935 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1936 goto cleanup;
1937 }
1938
1939 c_id = (backsql_entryID *)op->o_tmpcalloc( 1,
1940 sizeof( backsql_entryID ), op->o_tmpmemctx );
1941 #ifdef BACKSQL_ARBITRARY_KEY
1942 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id,
1943 op->o_tmpmemctx );
1944 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval,
1945 op->o_tmpmemctx );
1946 #else /* ! BACKSQL_ARBITRARY_KEY */
1947 if ( BACKSQL_STR2ID( &c_id->eid_id, row.cols[ 0 ], 0 ) != 0 ) {
1948 goto cleanup;
1949 }
1950 if ( BACKSQL_STR2ID( &c_id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) {
1951 goto cleanup;
1952 }
1953 #endif /* ! BACKSQL_ARBITRARY_KEY */
1954 c_id->eid_oc = bsi->bsi_oc;
1955 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1956
1957 c_id->eid_dn = pdn;
1958 c_id->eid_ndn = ndn;
1959
1960 /* append at end of list ... */
1961 c_id->eid_next = NULL;
1962 *bsi->bsi_id_listtail = c_id;
1963 bsi->bsi_id_listtail = &c_id->eid_next;
1964
1965 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1966 "added entry id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDFMT " dn=\"%s\"\n",
1967 BACKSQL_IDARG(c_id->eid_id),
1968 BACKSQL_IDARG(c_id->eid_keyval),
1969 row.cols[ 3 ] );
1970
1971 /* count candidates, for unchecked limit */
1972 bsi->bsi_n_candidates--;
1973 if ( bsi->bsi_n_candidates == -1 ) {
1974 break;
1975 }
1976 continue;
1977
1978 cleanup:;
1979 if ( !BER_BVISNULL( &pdn ) ) {
1980 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
1981 }
1982 if ( !BER_BVISNULL( &ndn ) ) {
1983 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
1984 }
1985 if ( c_id != NULL ) {
1986 ch_free( c_id );
1987 }
1988 }
1989 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
1990 SQLFreeStmt( sth, SQL_DROP );
1991
1992 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1993 n_candidates - bsi->bsi_n_candidates );
1994
1995 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1996 }
1997
1998 int
backsql_search(Operation * op,SlapReply * rs)1999 backsql_search( Operation *op, SlapReply *rs )
2000 {
2001 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
2002 SQLHDBC dbh = SQL_NULL_HDBC;
2003 int sres;
2004 Entry user_entry = { 0 },
2005 base_entry = { 0 };
2006 int manageDSAit = get_manageDSAit( op );
2007 time_t stoptime = 0;
2008 backsql_srch_info bsi = { 0 };
2009 backsql_entryID *eid = NULL;
2010 struct berval nbase = BER_BVNULL;
2011 #ifndef BACKSQL_ARBITRARY_KEY
2012 ID lastid = 0;
2013 #endif /* ! BACKSQL_ARBITRARY_KEY */
2014
2015 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
2016 "base=\"%s\", filter=\"%s\", scope=%d,",
2017 op->o_req_ndn.bv_val,
2018 op->ors_filterstr.bv_val,
2019 op->ors_scope );
2020 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
2021 "attributes to load: %s\n",
2022 op->ors_deref,
2023 op->ors_attrsonly,
2024 op->ors_attrs == NULL ? "all" : "custom list" );
2025
2026 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
2027 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2028 "search base length (%ld) exceeds max length (%d)\n",
2029 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN );
2030 /*
2031 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
2032 * since it is impossible that such a long DN exists
2033 * in the backend
2034 */
2035 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
2036 send_ldap_result( op, rs );
2037 return 1;
2038 }
2039
2040 sres = backsql_get_db_conn( op, &dbh );
2041 if ( sres != LDAP_SUCCESS ) {
2042 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2043 "could not get connection handle - exiting\n" );
2044 rs->sr_err = sres;
2045 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
2046 send_ldap_result( op, rs );
2047 return 1;
2048 }
2049
2050 /* compute it anyway; root does not use it */
2051 stoptime = op->o_time + op->ors_tlimit;
2052
2053 /* init search */
2054 bsi.bsi_e = &base_entry;
2055 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
2056 op->ors_scope,
2057 stoptime, op->ors_filter,
2058 dbh, op, rs, op->ors_attrs,
2059 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
2060 switch ( rs->sr_err ) {
2061 case LDAP_SUCCESS:
2062 break;
2063
2064 case LDAP_REFERRAL:
2065 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
2066 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
2067 {
2068 rs->sr_err = LDAP_SUCCESS;
2069 rs->sr_text = NULL;
2070 rs->sr_matched = NULL;
2071 if ( rs->sr_ref ) {
2072 ber_bvarray_free( rs->sr_ref );
2073 rs->sr_ref = NULL;
2074 }
2075 break;
2076 }
2077
2078 /* an entry was created; free it */
2079 entry_clean( bsi.bsi_e );
2080
2081 /* fall thru */
2082
2083 default:
2084 if ( !BER_BVISNULL( &base_entry.e_nname )
2085 && !access_allowed( op, &base_entry,
2086 slap_schema.si_ad_entry, NULL,
2087 ACL_DISCLOSE, NULL ) )
2088 {
2089 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2090 if ( rs->sr_ref ) {
2091 ber_bvarray_free( rs->sr_ref );
2092 rs->sr_ref = NULL;
2093 }
2094 rs->sr_matched = NULL;
2095 rs->sr_text = NULL;
2096 }
2097
2098 send_ldap_result( op, rs );
2099
2100 if ( rs->sr_ref ) {
2101 ber_bvarray_free( rs->sr_ref );
2102 rs->sr_ref = NULL;
2103 }
2104
2105 if ( !BER_BVISNULL( &base_entry.e_nname ) ) {
2106 entry_clean( &base_entry );
2107 }
2108
2109 goto done;
2110 }
2111 /* NOTE: __NEW__ "search" access is required
2112 * on searchBase object */
2113 {
2114 slap_mask_t mask;
2115
2116 if ( get_assert( op ) &&
2117 ( test_filter( op, &base_entry, get_assertion( op ) )
2118 != LDAP_COMPARE_TRUE ) )
2119 {
2120 rs->sr_err = LDAP_ASSERTION_FAILED;
2121
2122 }
2123 if ( ! access_allowed_mask( op, &base_entry,
2124 slap_schema.si_ad_entry,
2125 NULL, ACL_SEARCH, NULL, &mask ) )
2126 {
2127 if ( rs->sr_err == LDAP_SUCCESS ) {
2128 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2129 }
2130 }
2131
2132 if ( rs->sr_err != LDAP_SUCCESS ) {
2133 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
2134 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2135 rs->sr_text = NULL;
2136 }
2137 send_ldap_result( op, rs );
2138 goto done;
2139 }
2140 }
2141
2142 bsi.bsi_e = NULL;
2143
2144 bsi.bsi_n_candidates =
2145 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
2146 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
2147 ( op->ors_limit->lms_s_unchecked ) ) );
2148
2149 #ifndef BACKSQL_ARBITRARY_KEY
2150 /* If paged results are in effect, check the paging cookie */
2151 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
2152 rs->sr_err = parse_paged_cookie( op, rs );
2153 if ( rs->sr_err != LDAP_SUCCESS ) {
2154 send_ldap_result( op, rs );
2155 goto done;
2156 }
2157 }
2158 #endif /* ! BACKSQL_ARBITRARY_KEY */
2159
2160 switch ( bsi.bsi_scope ) {
2161 case LDAP_SCOPE_BASE:
2162 case BACKSQL_SCOPE_BASE_LIKE:
2163 /*
2164 * probably already found...
2165 */
2166 bsi.bsi_id_list = &bsi.bsi_base_id;
2167 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2168 break;
2169
2170 case LDAP_SCOPE_SUBTREE:
2171 /*
2172 * if baseObject is defined, and if it is the root
2173 * of the search, add it to the candidate list
2174 */
2175 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
2176 {
2177 bsi.bsi_id_list = &bsi.bsi_base_id;
2178 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2179 }
2180
2181 /* FALLTHRU */
2182 default:
2183
2184 /*
2185 * for each objectclass we try to construct query which gets IDs
2186 * of entries matching LDAP query filter and scope (or at least
2187 * candidates), and get the IDs. Do this in ID order for paging.
2188 */
2189 ldap_avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates,
2190 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
2191
2192 /* check for abandon */
2193 if ( op->o_abandon ) {
2194 eid = bsi.bsi_id_list;
2195 rs->sr_err = SLAPD_ABANDON;
2196 goto send_results;
2197 }
2198 }
2199
2200 if ( op->ors_limit != NULL /* isroot == FALSE */
2201 && op->ors_limit->lms_s_unchecked != -1
2202 && bsi.bsi_n_candidates == -1 )
2203 {
2204 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
2205 send_ldap_result( op, rs );
2206 goto done;
2207 }
2208
2209 /*
2210 * now we load candidate entries (only those attributes
2211 * mentioned in attrs and filter), test it against full filter
2212 * and then send to client; don't free entry_id if baseObject...
2213 */
2214 for ( eid = bsi.bsi_id_list;
2215 eid != NULL;
2216 eid = backsql_free_entryID(
2217 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) )
2218 {
2219 int rc;
2220 Attribute *a_hasSubordinate = NULL,
2221 *a_entryUUID = NULL,
2222 *a_entryCSN = NULL,
2223 **ap = NULL;
2224 Entry *e = NULL;
2225
2226 /* check for abandon */
2227 if ( op->o_abandon ) {
2228 rs->sr_err = SLAPD_ABANDON;
2229 goto send_results;
2230 }
2231
2232 /* check time limit */
2233 if ( op->ors_tlimit != SLAP_NO_LIMIT
2234 && slap_get_time() > stoptime )
2235 {
2236 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
2237 rs->sr_ctrls = NULL;
2238 rs->sr_ref = rs->sr_v2ref;
2239 goto send_results;
2240 }
2241
2242 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2243 "for entry id=" BACKSQL_IDFMT " oc_id=" BACKSQL_IDNUMFMT ", keyval=" BACKSQL_IDFMT "\n",
2244 BACKSQL_IDARG(eid->eid_id),
2245 eid->eid_oc_id,
2246 BACKSQL_IDARG(eid->eid_keyval) );
2247
2248 /* check scope */
2249 switch ( op->ors_scope ) {
2250 case LDAP_SCOPE_BASE:
2251 case BACKSQL_SCOPE_BASE_LIKE:
2252 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2253 goto next_entry2;
2254 }
2255 break;
2256
2257 case LDAP_SCOPE_ONE:
2258 {
2259 struct berval rdn = eid->eid_ndn;
2260
2261 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
2262 if ( !dnIsOneLevelRDN( &rdn ) ) {
2263 goto next_entry2;
2264 }
2265 /* fall thru */
2266 }
2267
2268 case LDAP_SCOPE_SUBORDINATE:
2269 /* discard the baseObject entry */
2270 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2271 goto next_entry2;
2272 }
2273 /* FALLTHRU */
2274 case LDAP_SCOPE_SUBTREE:
2275 /* FIXME: this should never fail... */
2276 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
2277 goto next_entry2;
2278 }
2279 break;
2280 }
2281
2282 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
2283 /* don't recollect baseObject... */
2284 e = bi->sql_baseObject;
2285
2286 } else if ( eid == &bsi.bsi_base_id ) {
2287 /* don't recollect searchBase object... */
2288 e = &base_entry;
2289
2290 } else {
2291 bsi.bsi_e = &user_entry;
2292 rc = backsql_id2entry( &bsi, eid );
2293 if ( rc != LDAP_SUCCESS ) {
2294 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2295 "error %d in backsql_id2entry() "
2296 "- skipping\n", rc );
2297 continue;
2298 }
2299 e = &user_entry;
2300 }
2301
2302 if ( !manageDSAit &&
2303 op->ors_scope != LDAP_SCOPE_BASE &&
2304 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
2305 is_entry_referral( e ) )
2306 {
2307 BerVarray refs;
2308
2309 refs = get_entry_referrals( op, e );
2310 if ( !refs ) {
2311 backsql_srch_info bsi2 = { 0 };
2312 Entry user_entry2 = { 0 };
2313
2314 /* retry with the full entry... */
2315 bsi2.bsi_e = &user_entry2;
2316 rc = backsql_init_search( &bsi2,
2317 &e->e_nname,
2318 LDAP_SCOPE_BASE,
2319 (time_t)(-1), NULL,
2320 dbh, op, rs, NULL,
2321 BACKSQL_ISF_GET_ENTRY );
2322 if ( rc == LDAP_SUCCESS ) {
2323 if ( is_entry_referral( &user_entry2 ) )
2324 {
2325 refs = get_entry_referrals( op,
2326 &user_entry2 );
2327 } else {
2328 rs->sr_err = LDAP_OTHER;
2329 }
2330 backsql_entry_clean( op, &user_entry2 );
2331 }
2332 if ( bsi2.bsi_attrs != NULL ) {
2333 op->o_tmpfree( bsi2.bsi_attrs,
2334 op->o_tmpmemctx );
2335 }
2336 }
2337
2338 if ( refs ) {
2339 rs->sr_ref = referral_rewrite( refs,
2340 &e->e_name,
2341 &op->o_req_dn,
2342 op->ors_scope );
2343 ber_bvarray_free( refs );
2344 }
2345
2346 if ( rs->sr_ref ) {
2347 rs->sr_err = LDAP_REFERRAL;
2348
2349 } else {
2350 rs->sr_text = "bad referral object";
2351 }
2352
2353 rs->sr_entry = e;
2354 rs->sr_matched = user_entry.e_name.bv_val;
2355 send_search_reference( op, rs );
2356
2357 ber_bvarray_free( rs->sr_ref );
2358 rs->sr_ref = NULL;
2359 rs->sr_matched = NULL;
2360 rs->sr_entry = NULL;
2361 if ( rs->sr_err == LDAP_REFERRAL ) {
2362 rs->sr_err = LDAP_SUCCESS;
2363 }
2364
2365 goto next_entry;
2366 }
2367
2368 /*
2369 * We use this flag since we need to parse the filter
2370 * anyway; we should have used the frontend API function
2371 * filter_has_subordinates()
2372 */
2373 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2374 rc = backsql_has_children( op, dbh, &e->e_nname );
2375
2376 switch ( rc ) {
2377 case LDAP_COMPARE_TRUE:
2378 case LDAP_COMPARE_FALSE:
2379 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2380 if ( a_hasSubordinate != NULL ) {
2381 for ( ap = &user_entry.e_attrs;
2382 *ap;
2383 ap = &(*ap)->a_next );
2384
2385 *ap = a_hasSubordinate;
2386 }
2387 rc = 0;
2388 break;
2389
2390 default:
2391 Debug(LDAP_DEBUG_TRACE,
2392 "backsql_search(): "
2393 "has_children failed( %d)\n",
2394 rc );
2395 rc = 1;
2396 goto next_entry;
2397 }
2398 }
2399
2400 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2401 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2402 if ( a_entryUUID != NULL ) {
2403 if ( ap == NULL ) {
2404 ap = &user_entry.e_attrs;
2405 }
2406
2407 for ( ; *ap; ap = &(*ap)->a_next );
2408
2409 *ap = a_entryUUID;
2410 }
2411 }
2412
2413 #ifdef BACKSQL_SYNCPROV
2414 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2415 a_entryCSN = backsql_operational_entryCSN( op );
2416 if ( a_entryCSN != NULL ) {
2417 if ( ap == NULL ) {
2418 ap = &user_entry.e_attrs;
2419 }
2420
2421 for ( ; *ap; ap = &(*ap)->a_next );
2422
2423 *ap = a_entryCSN;
2424 }
2425 }
2426 #endif /* BACKSQL_SYNCPROV */
2427
2428 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2429 {
2430 #ifndef BACKSQL_ARBITRARY_KEY
2431 /* If paged results are in effect, see if the page limit was exceeded */
2432 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
2433 if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size )
2434 {
2435 e = NULL;
2436 send_paged_response( op, rs, &lastid );
2437 goto done;
2438 }
2439 lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id );
2440 }
2441 #endif /* ! BACKSQL_ARBITRARY_KEY */
2442 rs->sr_attrs = op->ors_attrs;
2443 rs->sr_operational_attrs = NULL;
2444 rs->sr_entry = e;
2445 e->e_private = (void *)eid;
2446 rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0;
2447 /* FIXME: need the whole entry (ITS#3480) */
2448 rs->sr_err = send_search_entry( op, rs );
2449 e->e_private = NULL;
2450 rs->sr_entry = NULL;
2451 rs->sr_attrs = NULL;
2452 rs->sr_operational_attrs = NULL;
2453
2454 switch ( rs->sr_err ) {
2455 case LDAP_UNAVAILABLE:
2456 /*
2457 * FIXME: send_search_entry failed;
2458 * better stop
2459 */
2460 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2461 "connection lost\n" );
2462 goto end_of_search;
2463
2464 case LDAP_SIZELIMIT_EXCEEDED:
2465 case LDAP_BUSY:
2466 goto send_results;
2467 }
2468 }
2469
2470 next_entry:;
2471 if ( e == &user_entry ) {
2472 backsql_entry_clean( op, &user_entry );
2473 }
2474
2475 next_entry2:;
2476 }
2477
2478 end_of_search:;
2479 if ( rs->sr_nentries > 0 ) {
2480 rs->sr_ref = rs->sr_v2ref;
2481 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2482 : LDAP_REFERRAL;
2483
2484 } else {
2485 rs->sr_err = bsi.bsi_status;
2486 }
2487
2488 send_results:;
2489 if ( rs->sr_err != SLAPD_ABANDON ) {
2490 #ifndef BACKSQL_ARBITRARY_KEY
2491 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
2492 send_paged_response( op, rs, NULL );
2493 } else
2494 #endif /* ! BACKSQL_ARBITRARY_KEY */
2495 {
2496 send_ldap_result( op, rs );
2497 }
2498 }
2499
2500 /* cleanup in case of abandon */
2501 for ( ; eid != NULL;
2502 eid = backsql_free_entryID(
2503 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) )
2504 ;
2505
2506 backsql_entry_clean( op, &base_entry );
2507
2508 /* in case we got here accidentally */
2509 backsql_entry_clean( op, &user_entry );
2510
2511 if ( rs->sr_v2ref ) {
2512 ber_bvarray_free( rs->sr_v2ref );
2513 rs->sr_v2ref = NULL;
2514 }
2515
2516 #ifdef BACKSQL_SYNCPROV
2517 if ( op->o_sync ) {
2518 Operation op2 = *op;
2519 SlapReply rs2 = { REP_RESULT };
2520 Entry *e = entry_alloc();
2521 slap_callback cb = { 0 };
2522
2523 op2.o_tag = LDAP_REQ_ADD;
2524 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 );
2525 op2.ora_e = e;
2526 op2.o_callback = &cb;
2527
2528 ber_dupbv( &e->e_name, op->o_bd->be_suffix );
2529 ber_dupbv( &e->e_nname, op->o_bd->be_nsuffix );
2530
2531 cb.sc_response = slap_null_cb;
2532
2533 op2.o_bd->be_add( &op2, &rs2 );
2534
2535 if ( op2.ora_e == e )
2536 entry_free( e );
2537 }
2538 #endif /* BACKSQL_SYNCPROV */
2539
2540 done:;
2541 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
2542
2543 if ( bsi.bsi_attrs != NULL ) {
2544 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2545 }
2546
2547 if ( !BER_BVISNULL( &nbase )
2548 && nbase.bv_val != op->o_req_ndn.bv_val )
2549 {
2550 ch_free( nbase.bv_val );
2551 }
2552
2553 /* restore scope ... FIXME: this should be done before ANY
2554 * frontend call that uses op */
2555 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2556 op->ors_scope = LDAP_SCOPE_BASE;
2557 }
2558
2559 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n" );
2560
2561 return rs->sr_err;
2562 }
2563
2564 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2565 */
2566 int
backsql_entry_get(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ent)2567 backsql_entry_get(
2568 Operation *op,
2569 struct berval *ndn,
2570 ObjectClass *oc,
2571 AttributeDescription *at,
2572 int rw,
2573 Entry **ent )
2574 {
2575 backsql_srch_info bsi = { 0 };
2576 SQLHDBC dbh = SQL_NULL_HDBC;
2577 int rc;
2578 SlapReply rs = { 0 };
2579 AttributeName anlist[ 2 ];
2580
2581 *ent = NULL;
2582
2583 rc = backsql_get_db_conn( op, &dbh );
2584 if ( rc != LDAP_SUCCESS ) {
2585 return rc;
2586 }
2587
2588 if ( at ) {
2589 anlist[ 0 ].an_name = at->ad_cname;
2590 anlist[ 0 ].an_desc = at;
2591 BER_BVZERO( &anlist[ 1 ].an_name );
2592 }
2593
2594 bsi.bsi_e = entry_alloc();
2595 rc = backsql_init_search( &bsi,
2596 ndn,
2597 LDAP_SCOPE_BASE,
2598 (time_t)(-1), NULL,
2599 dbh, op, &rs, at ? anlist : NULL,
2600 BACKSQL_ISF_GET_ENTRY );
2601
2602 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2603 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
2604 }
2605
2606 if ( rc == LDAP_SUCCESS ) {
2607
2608 #if 0 /* not supported at present */
2609 /* find attribute values */
2610 if ( is_entry_alias( bsi.bsi_e ) ) {
2611 Debug( LDAP_DEBUG_ACL,
2612 "<= backsql_entry_get: entry is an alias\n" );
2613 rc = LDAP_ALIAS_PROBLEM;
2614 goto return_results;
2615 }
2616 #endif
2617
2618 if ( is_entry_referral( bsi.bsi_e ) ) {
2619 Debug( LDAP_DEBUG_ACL,
2620 "<= backsql_entry_get: entry is a referral\n" );
2621 rc = LDAP_REFERRAL;
2622 goto return_results;
2623 }
2624
2625 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2626 Debug( LDAP_DEBUG_ACL,
2627 "<= backsql_entry_get: "
2628 "failed to find objectClass\n" );
2629 rc = LDAP_NO_SUCH_ATTRIBUTE;
2630 goto return_results;
2631 }
2632
2633 *ent = bsi.bsi_e;
2634 }
2635
2636 return_results:;
2637 if ( bsi.bsi_attrs != NULL ) {
2638 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2639 }
2640
2641 if ( rc != LDAP_SUCCESS ) {
2642 if ( bsi.bsi_e ) {
2643 entry_free( bsi.bsi_e );
2644 }
2645 }
2646
2647 return rc;
2648 }
2649
2650 void
backsql_entry_clean(Operation * op,Entry * e)2651 backsql_entry_clean(
2652 Operation *op,
2653 Entry *e )
2654 {
2655 void *ctx;
2656
2657 ctx = ldap_pvt_thread_pool_context();
2658
2659 if ( ctx == NULL || ctx != op->o_tmpmemctx ) {
2660 if ( !BER_BVISNULL( &e->e_name ) ) {
2661 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
2662 BER_BVZERO( &e->e_name );
2663 }
2664
2665 if ( !BER_BVISNULL( &e->e_nname ) ) {
2666 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
2667 BER_BVZERO( &e->e_nname );
2668 }
2669 }
2670
2671 entry_clean( e );
2672 }
2673
2674 int
backsql_entry_release(Operation * op,Entry * e,int rw)2675 backsql_entry_release(
2676 Operation *op,
2677 Entry *e,
2678 int rw )
2679 {
2680 backsql_entry_clean( op, e );
2681
2682 entry_free( e );
2683
2684 return 0;
2685 }
2686
2687 #ifndef BACKSQL_ARBITRARY_KEY
2688 /* This function is copied verbatim from back-bdb/search.c */
2689 static int
parse_paged_cookie(Operation * op,SlapReply * rs)2690 parse_paged_cookie( Operation *op, SlapReply *rs )
2691 {
2692 int rc = LDAP_SUCCESS;
2693 PagedResultsState *ps = op->o_pagedresults_state;
2694
2695 /* this function must be invoked only if the pagedResults
2696 * control has been detected, parsed and partially checked
2697 * by the frontend */
2698 assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
2699
2700 /* cookie decoding/checks deferred to backend... */
2701 if ( ps->ps_cookieval.bv_len ) {
2702 PagedResultsCookie reqcookie;
2703 if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) {
2704 /* bad cookie */
2705 rs->sr_text = "paged results cookie is invalid";
2706 rc = LDAP_PROTOCOL_ERROR;
2707 goto done;
2708 }
2709
2710 AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie ));
2711
2712 if ( reqcookie > ps->ps_cookie ) {
2713 /* bad cookie */
2714 rs->sr_text = "paged results cookie is invalid";
2715 rc = LDAP_PROTOCOL_ERROR;
2716 goto done;
2717
2718 } else if ( reqcookie < ps->ps_cookie ) {
2719 rs->sr_text = "paged results cookie is invalid or old";
2720 rc = LDAP_UNWILLING_TO_PERFORM;
2721 goto done;
2722 }
2723
2724 } else {
2725 /* Initial request. Initialize state. */
2726 ps->ps_cookie = 0;
2727 ps->ps_count = 0;
2728 }
2729
2730 done:;
2731
2732 return rc;
2733 }
2734
2735 /* This function is copied nearly verbatim from back-bdb/search.c */
2736 static void
send_paged_response(Operation * op,SlapReply * rs,ID * lastid)2737 send_paged_response(
2738 Operation *op,
2739 SlapReply *rs,
2740 ID *lastid )
2741 {
2742 LDAPControl ctrl, *ctrls[2];
2743 BerElementBuffer berbuf;
2744 BerElement *ber = (BerElement *)&berbuf;
2745 PagedResultsCookie respcookie;
2746 struct berval cookie;
2747
2748 Debug(LDAP_DEBUG_ARGS,
2749 "send_paged_response: lastid=0x%08lx nentries=%d\n",
2750 lastid ? *lastid : 0, rs->sr_nentries );
2751
2752 BER_BVZERO( &ctrl.ldctl_value );
2753 ctrls[0] = &ctrl;
2754 ctrls[1] = NULL;
2755
2756 ber_init2( ber, NULL, LBER_USE_DER );
2757
2758 if ( lastid ) {
2759 respcookie = ( PagedResultsCookie )(*lastid);
2760 cookie.bv_len = sizeof( respcookie );
2761 cookie.bv_val = (char *)&respcookie;
2762
2763 } else {
2764 respcookie = ( PagedResultsCookie )0;
2765 BER_BVSTR( &cookie, "" );
2766 }
2767
2768 op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
2769 op->o_conn->c_pagedresults_state.ps_count =
2770 ((PagedResultsState *)op->o_pagedresults_state)->ps_count +
2771 rs->sr_nentries;
2772
2773 /* return size of 0 -- no estimate */
2774 ber_printf( ber, "{iO}", 0, &cookie );
2775
2776 if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
2777 goto done;
2778 }
2779
2780 ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
2781 ctrls[0]->ldctl_iscritical = 0;
2782
2783 rs->sr_ctrls = ctrls;
2784 rs->sr_err = LDAP_SUCCESS;
2785 send_ldap_result( op, rs );
2786 rs->sr_ctrls = NULL;
2787
2788 done:
2789 (void) ber_free_buf( ber );
2790 }
2791 #endif /* ! BACKSQL_ARBITRARY_KEY */
2792