]> git.sur5r.net Git - openldap/blob - servers/slapd/search.c
LCUP primitive routines removed
[openldap] / servers / slapd / search.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* Portions
7  * Copyright (c) 1995 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/string.h>
23 #include <ac/socket.h>
24
25 #include "ldap_pvt.h"
26 #include "lutil.h"
27 #include "slap.h"
28
29 #ifdef LDAP_SLAPI
30 #include "slapi.h"
31 static char **anlist2charray( Operation *op, AttributeName *an );
32 static void initSearchPlugin( Operation *op, char **attrs, int managedsait );
33 static int doPreSearchPluginFNs( Operation *op );
34 static int doSearchRewriteFNs( Operation *op );
35 static void doPostSearchPluginFNs( Operation *op );
36 #endif /* LDAPI_SLAPI */
37
38 int
39 do_search(
40     Operation   *op,    /* info about the op to which we're responding */
41     SlapReply   *rs     /* all the response data we'll send */
42 ) {
43         struct berval base = { 0, NULL };
44         ber_len_t       siz, off, i;
45         int                     manageDSAit;
46         int                     be_manageDSAit;
47 #ifdef LDAP_SLAPI
48         char            **attrs = NULL;
49 #endif
50
51 #ifdef NEW_LOGGING
52         LDAP_LOG( OPERATION, ENTRY, "do_search: conn %d\n", op->o_connid, 0, 0 );
53 #else
54         Debug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
55 #endif
56
57         /*
58          * Parse the search request.  It looks like this:
59          *
60          *      SearchRequest := [APPLICATION 3] SEQUENCE {
61          *              baseObject      DistinguishedName,
62          *              scope           ENUMERATED {
63          *                      baseObject      (0),
64          *                      singleLevel     (1),
65          *                      wholeSubtree    (2)
66          *              },
67          *              derefAliases    ENUMERATED {
68          *                      neverDerefaliases       (0),
69          *                      derefInSearching        (1),
70          *                      derefFindingBaseObj     (2),
71          *                      alwaysDerefAliases      (3)
72          *              },
73          *              sizelimit       INTEGER (0 .. 65535),
74          *              timelimit       INTEGER (0 .. 65535),
75          *              attrsOnly       BOOLEAN,
76          *              filter          Filter,
77          *              attributes      SEQUENCE OF AttributeType
78          *      }
79          */
80
81         /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
82         if ( ber_scanf( op->o_ber, "{miiiib" /*}*/,
83                 &base, &op->ors_scope, &op->ors_deref, &op->ors_slimit,
84             &op->ors_tlimit, &op->ors_attrsonly ) == LBER_ERROR )
85         {
86                 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" );
87                 rs->sr_err = SLAPD_DISCONNECT;
88                 goto return_results;
89         }
90
91         switch( op->ors_scope ) {
92         case LDAP_SCOPE_BASE:
93         case LDAP_SCOPE_ONELEVEL:
94         case LDAP_SCOPE_SUBTREE:
95                 break;
96         default:
97                 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid scope" );
98                 goto return_results;
99         }
100
101         switch( op->ors_deref ) {
102         case LDAP_DEREF_NEVER:
103         case LDAP_DEREF_FINDING:
104         case LDAP_DEREF_SEARCHING:
105         case LDAP_DEREF_ALWAYS:
106                 break;
107         default:
108                 send_ldap_error( op, rs, LDAP_PROTOCOL_ERROR, "invalid deref" );
109                 goto return_results;
110         }
111
112         rs->sr_err = dnPrettyNormal( NULL, &base, &op->o_req_dn, &op->o_req_ndn, op->o_tmpmemctx );
113         if( rs->sr_err != LDAP_SUCCESS ) {
114 #ifdef NEW_LOGGING
115                 LDAP_LOG( OPERATION, ERR, 
116                         "do_search: conn %d  invalid dn (%s)\n",
117                         op->o_connid, base.bv_val, 0 );
118 #else
119                 Debug( LDAP_DEBUG_ANY,
120                         "do_search: invalid dn (%s)\n", base.bv_val, 0, 0 );
121 #endif
122                 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
123                 goto return_results;
124         }
125
126 #ifdef NEW_LOGGING
127         LDAP_LOG( OPERATION, ARGS, "SRCH \"%s\" %d %d",
128                 base.bv_val, op->ors_scope, op->ors_deref );
129         LDAP_LOG( OPERATION, ARGS, "    %d %d %d\n",
130                 op->ors_slimit, op->ors_tlimit, op->ors_attrsonly);
131 #else
132         Debug( LDAP_DEBUG_ARGS, "SRCH \"%s\" %d %d",
133                 base.bv_val, op->ors_scope, op->ors_deref );
134         Debug( LDAP_DEBUG_ARGS, "    %d %d %d\n",
135                 op->ors_slimit, op->ors_tlimit, op->ors_attrsonly);
136 #endif
137
138         /* filter - returns a "normalized" version */
139         rs->sr_err = get_filter( op, op->o_ber, &op->ors_filter, &rs->sr_text );
140         if( rs->sr_err != LDAP_SUCCESS ) {
141                 if( rs->sr_err == SLAPD_DISCONNECT ) {
142                         rs->sr_err = LDAP_PROTOCOL_ERROR;
143                         send_ldap_disconnect( op, rs );
144                 } else {
145                         send_ldap_result( op, rs );
146                 }
147                 goto return_results;
148         }
149         filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
150
151 #ifdef NEW_LOGGING
152         LDAP_LOG( OPERATION, ARGS, 
153                 "do_search: conn %d     filter: %s\n", 
154                 op->o_connid, op->ors_filterstr.bv_len ? op->ors_filterstr.bv_val : "empty", 0 );
155 #else
156         Debug( LDAP_DEBUG_ARGS, "    filter: %s\n",
157                 op->ors_filterstr.bv_len ? op->ors_filterstr.bv_val : "empty", 0, 0 );
158 #endif
159
160         /* attributes */
161         siz = sizeof(AttributeName);
162         off = 0;
163         if ( ber_scanf( op->o_ber, "{M}}", &op->ors_attrs, &siz, off ) == LBER_ERROR ) {
164                 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding attrs error" );
165                 rs->sr_err = SLAPD_DISCONNECT;
166                 goto return_results;
167         }
168         for ( i=0; i<siz; i++ ) {
169                 const char *dummy;      /* ignore msgs from bv2ad */
170                 op->ors_attrs[i].an_desc = NULL;
171                 op->ors_attrs[i].an_oc = NULL;
172                 slap_bv2ad(&op->ors_attrs[i].an_name, &op->ors_attrs[i].an_desc, &dummy);
173         }
174
175         if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) {
176 #ifdef NEW_LOGGING
177                 LDAP_LOG( OPERATION, INFO, 
178                         "do_search: conn %d  get_ctrls failed (%d)\n",
179                         op->o_connid, rs->sr_err, 0 );
180 #else
181                 Debug( LDAP_DEBUG_ANY, "do_search: get_ctrls failed\n", 0, 0, 0 );
182 #endif
183
184                 goto return_results;
185         }
186
187 #ifdef NEW_LOGGING
188         LDAP_LOG( OPERATION, ARGS, 
189                 "do_search: conn %d     attrs:", op->o_connid, 0, 0 );
190 #else
191         Debug( LDAP_DEBUG_ARGS, "    attrs:", 0, 0, 0 );
192 #endif
193
194         if ( siz != 0 ) {
195                 for ( i = 0; i<siz; i++ ) {
196 #ifdef NEW_LOGGING
197                         LDAP_LOG( OPERATION, ARGS, 
198                                 "do_search: %s", op->ors_attrs[i].an_name.bv_val, 0, 0 );
199 #else
200                         Debug( LDAP_DEBUG_ARGS, " %s", op->ors_attrs[i].an_name.bv_val, 0, 0 );
201 #endif
202                 }
203         }
204
205 #ifdef NEW_LOGGING
206         LDAP_LOG( OPERATION, ARGS, "\n" , 0, 0, 0 );
207 #else
208         Debug( LDAP_DEBUG_ARGS, "\n", 0, 0, 0 );
209 #endif
210
211         if ( StatslogTest( LDAP_DEBUG_STATS ) ) {
212                 char abuf[BUFSIZ/2], *ptr = abuf;
213                 int len = 0, alen;
214
215                 sprintf(abuf, "scope=%d deref=%d", op->ors_scope, op->ors_deref);
216                 Statslog( LDAP_DEBUG_STATS,
217                         "conn=%lu op=%lu SRCH base=\"%s\" %s filter=\"%s\"\n",
218                         op->o_connid, op->o_opid, op->o_req_dn.bv_val, abuf,
219                         op->ors_filterstr.bv_val );
220
221                 for ( i = 0; i<siz; i++ ) {
222                         alen = op->ors_attrs[i].an_name.bv_len;
223                         if (alen >= sizeof(abuf)) {
224                                 alen = sizeof(abuf)-1;
225                         }
226                         if (len && (len + 1 + alen >= sizeof(abuf))) {
227                                 Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu SRCH attr=%s\n",
228                                     op->o_connid, op->o_opid, abuf, 0, 0 );
229                                 len = 0;
230                                 ptr = abuf;
231                         }
232                         if (len) {
233                                 *ptr++ = ' ';
234                                 len++;
235                         }
236                         ptr = lutil_strncopy(ptr, op->ors_attrs[i].an_name.bv_val, alen);
237                         len += alen;
238                         *ptr = '\0';
239                 }
240                 if (len) {
241                         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu SRCH attr=%s\n",
242                                 op->o_connid, op->o_opid, abuf, 0, 0 );
243                 }
244         }
245
246         manageDSAit = get_manageDSAit( op );
247
248         if ( op->ors_scope == LDAP_SCOPE_BASE ) {
249                 Entry *entry = NULL;
250
251                 if ( op->o_req_ndn.bv_len == 0 ) {
252 #ifdef LDAP_CONNECTIONLESS
253                         /* Ignore LDAPv2 CLDAP Root DSE queries */
254                         if (op->o_protocol == LDAP_VERSION2 && op->o_conn->c_is_udp) {
255                                 goto return_results;
256                         }
257 #endif
258                         /* check restrictions */
259                         if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
260                                 send_ldap_result( op, rs );
261                                 goto return_results;
262                         }
263
264 #ifdef LDAP_SLAPI
265                         attrs = anlist2charray( op, op->ors_attrs );
266                         initSearchPlugin( op, attrs, manageDSAit );
267                         rs->sr_err = doPreSearchPluginFNs( op );
268                         if ( rs->sr_err == LDAP_SUCCESS ) {
269                                 doSearchRewriteFNs( op );
270 #endif /* LDAP_SLAPI */
271                         rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text );
272 #ifdef LDAP_SLAPI
273                         }
274 #endif /* LDAP_SLAPI */
275
276                 } else if ( bvmatch( &op->o_req_ndn, &global_schemandn ) ) {
277                         /* check restrictions */
278                         if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
279                                 send_ldap_result( op, rs );
280                                 goto return_results;
281                         }
282
283 #ifdef LDAP_SLAPI
284                         attrs = anlist2charray( op, op->ors_attrs );
285                         initSearchPlugin( op, attrs, manageDSAit );
286                         rs->sr_err = doPreSearchPluginFNs( op );
287                         if ( rs->sr_err == LDAP_SUCCESS ) {
288                                 doSearchRewriteFNs( op );
289 #endif /* LDAP_SLAPI */
290                         rs->sr_err = schema_info( &entry, &rs->sr_text );
291 #ifdef LDAP_SLAPI
292                         }
293 #endif /* LDAP_SLAPI */
294                 }
295
296                 if( rs->sr_err != LDAP_SUCCESS ) {
297                         send_ldap_result( op, rs );
298 #ifdef LDAP_SLAPI
299                         doPostSearchPluginFNs( op );
300 #endif /* LDAP_SLAPI */
301                         goto return_results;
302
303                 } else if ( entry != NULL ) {
304                         rs->sr_err = test_filter( op, entry, op->ors_filter );
305
306                         if( rs->sr_err == LDAP_COMPARE_TRUE ) {
307                                 rs->sr_entry = entry;
308                                 rs->sr_attrs = op->ors_attrs;
309                                 send_search_entry( op, rs );
310                                 rs->sr_entry = NULL;
311                         }
312                         entry_free( entry );
313
314                         rs->sr_err = LDAP_SUCCESS;
315                         send_ldap_result( op, rs );
316 #ifdef LDAP_SLAPI
317                         doPostSearchPluginFNs( op );
318 #endif /* LDAP_SLAPI */
319                         goto return_results;
320                 }
321         }
322
323         if( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
324                 sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
325                 sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
326
327                 ber_dupbv_x( &op->o_req_dn, &default_search_base, op->o_tmpmemctx );
328                 ber_dupbv_x( &op->o_req_ndn, &default_search_nbase, op->o_tmpmemctx );
329         }
330
331         /*
332          * We could be serving multiple database backends.  Select the
333          * appropriate one, or send a referral to our "referral server"
334          * if we don't hold it.
335          */
336
337         /* Sync control overrides manageDSAit */
338
339         if ( manageDSAit != SLAP_NO_CONTROL ) {
340 #ifdef LDAP_SYNC
341                 if ( op->o_sync_mode & SLAP_SYNC_REFRESH ) {
342                         be_manageDSAit = SLAP_NO_CONTROL;
343                 } else
344 #endif
345                 {
346                         be_manageDSAit = manageDSAit;
347                 }
348         } else {
349                 be_manageDSAit = manageDSAit;
350         }
351
352         if ( (op->o_bd = select_backend( &op->o_req_ndn, be_manageDSAit, 1 )) == NULL ) {
353                 rs->sr_ref = referral_rewrite( default_referral,
354                         NULL, &op->o_req_dn, op->ors_scope );
355
356                 if (!rs->sr_ref) rs->sr_ref = default_referral;
357                 rs->sr_err = LDAP_REFERRAL;
358                 send_ldap_result( op, rs );
359
360                 if (rs->sr_ref != default_referral)
361                 ber_bvarray_free( rs->sr_ref );
362                 rs->sr_ref = NULL;
363                 goto return_results;
364         }
365
366         /* check restrictions */
367         if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
368                 send_ldap_result( op, rs );
369                 goto return_results;
370         }
371
372         /* check for referrals */
373         if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
374                 goto return_results;
375         }
376
377 #ifdef LDAP_SLAPI
378         attrs = anlist2charray( op, op->ors_attrs );
379         initSearchPlugin( op, attrs, manageDSAit );
380         rs->sr_err = doPreSearchPluginFNs( op );
381         if ( rs->sr_err != LDAP_SUCCESS ) {
382                 goto return_results;
383         }
384
385         doSearchRewriteFNs( op );
386 #endif /* LDAP_SLAPI */
387
388         /* actually do the search and send the result(s) */
389         if ( op->o_bd->be_search ) {
390                 (op->o_bd->be_search)( op, rs );
391         } else {
392                 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
393                         "operation not supported within namingContext" );
394         }
395
396 #ifdef LDAP_SLAPI
397         doPostSearchPluginFNs( op );
398 #endif /* LDAP_SLAPI */
399
400 return_results:;
401
402 #ifdef LDAP_SYNC
403         if ( ( op->o_sync_mode & SLAP_SYNC_PERSIST ) )
404                 return rs->sr_err;
405 #endif
406
407         if( op->o_req_dn.bv_val != NULL) sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx );
408         if( op->o_req_ndn.bv_val != NULL) sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
409
410         if( op->ors_filterstr.bv_val != NULL) op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
411         if( op->ors_filter != NULL) filter_free_x( op, op->ors_filter );
412         if( op->ors_attrs != NULL ) op->o_tmpfree( op->ors_attrs, op->o_tmpmemctx );
413 #ifdef LDAP_SLAPI
414         if( attrs != NULL) op->o_tmpfree( attrs, op->o_tmpmemctx );
415 #endif /* LDAP_SLAPI */
416
417         return rs->sr_err;
418 }
419
420 #ifdef LDAP_SLAPI
421
422 static char **anlist2charray( Operation *op, AttributeName *an )
423 {
424         char **attrs;
425         int i;
426
427         if ( an != NULL ) {
428                 for ( i = 0; an[i].an_name.bv_val != NULL; i++ )
429                         ;
430                 attrs = (char **)op->o_tmpalloc( (i + 1) * sizeof(char *), op->o_tmpmemctx );
431                 for ( i = 0; an[i].an_name.bv_val != NULL; i++ ) {
432                         attrs[i] = an[i].an_name.bv_val;
433                 }
434                 attrs[i] = NULL;
435         } else {
436                 attrs = NULL;
437         }
438
439         return attrs;
440 }
441
442 static void initSearchPlugin( Operation *op,
443         char **attrs, int managedsait )
444 {
445         slapi_x_pblock_set_operation( op->o_pb, op );
446         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_TARGET, (void *)op->o_req_dn.bv_val );
447         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_SCOPE, (void *)op->ors_scope );
448         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_DEREF, (void *)op->ors_deref );
449         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_SIZELIMIT, (void *)op->ors_slimit );
450         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_TIMELIMIT, (void *)op->ors_tlimit );
451         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_FILTER, (void *)op->ors_filter );
452         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_STRFILTER, (void *)op->ors_filterstr.bv_val );
453         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_ATTRS, (void *)attrs );
454         slapi_pblock_set( op->o_pb, SLAPI_SEARCH_ATTRSONLY, (void *)op->ors_attrsonly );
455         slapi_pblock_set( op->o_pb, SLAPI_MANAGEDSAIT, (void *)managedsait );
456 }
457
458 static int doPreSearchPluginFNs( Operation *op )
459 {
460         int rc;
461
462         rc = doPluginFNs( op->o_bd, SLAPI_PLUGIN_PRE_SEARCH_FN, op->o_pb );
463         if ( rc < 0 ) {
464                 /*
465                  * A preoperation plugin failure will abort the
466                  * entire operation.
467                  */
468 #ifdef NEW_LOGGING
469                 LDAP_LOG( OPERATION, INFO, "doPreSearchPluginFNs: search preoperation plugin "
470                                 "returned %d\n", rc, 0, 0 );
471 #else
472                 Debug(LDAP_DEBUG_TRACE, "doPreSearchPluginFNs: search preoperation plugin "
473                                 "returned %d.\n", rc, 0, 0);
474 #endif
475                 if ( ( slapi_pblock_get( op->o_pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0 ) ||
476                      rc == LDAP_SUCCESS ) {
477                         rc = LDAP_OTHER;
478                 }
479         } else {
480                 rc = LDAP_SUCCESS;
481         }
482
483         return rc;
484 }
485
486 static int doSearchRewriteFNs( Operation *op )
487 {
488         if ( doPluginFNs( op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, op->o_pb ) == 0 ) {
489                 int rc;
490
491                 /*
492                  * The plugin can set the SLAPI_SEARCH_FILTER.
493                  * SLAPI_SEARCH_STRFILER is not normative.
494                  */
495                 slapi_pblock_get( op->o_pb, SLAPI_SEARCH_FILTER, (void *)&op->ors_filter );
496                 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
497                 filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
498
499                 /*
500                  * Also permit other search parameters to be reset. One thing
501                  * this doesn't (yet) deal with is plugins that change a root
502                  * DSE search to a non-root DSE search...
503                  */
504                 slapi_pblock_get( op->o_pb, SLAPI_SEARCH_TARGET, (void **)&op->o_req_dn.bv_val );
505                 op->o_req_dn.bv_len = strlen( op->o_req_dn.bv_val );
506
507                 if( op->o_req_ndn.bv_val != NULL) {
508                         sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx );
509                 }
510                 rc = dnNormalize( 0, NULL, NULL, &op->o_req_dn, &op->o_req_ndn,
511                         op->o_tmpmemctx );
512                 if ( rc != LDAP_SUCCESS ) {
513                         return rc;
514                 }
515
516                 slapi_pblock_get( op->o_pb, SLAPI_SEARCH_SCOPE, (void **)&op->ors_scope );
517                 slapi_pblock_get( op->o_pb, SLAPI_SEARCH_DEREF, (void **)&op->ors_deref );
518
519 #ifdef NEW_LOGGING
520                 LDAP_LOG( OPERATION, ARGS, 
521                         "doSearchRewriteFNs: after compute_rewrite_search filter: %s\n", 
522                         op->ors_filterstr.bv_len ? op->ors_filterstr.bv_val : "empty", 0, 0 );
523 #else
524                 Debug( LDAP_DEBUG_ARGS, "    after compute_rewrite_search filter: %s\n",
525                         op->ors_filterstr.bv_len ? op->ors_filterstr.bv_val : "empty", 0, 0 );
526 #endif
527         }
528
529         return LDAP_SUCCESS;
530 }
531
532 static void doPostSearchPluginFNs( Operation *op )
533 {
534         if ( doPluginFNs( op->o_bd, SLAPI_PLUGIN_POST_SEARCH_FN, op->o_pb ) < 0 ) {
535 #ifdef NEW_LOGGING
536                 LDAP_LOG( OPERATION, INFO, "doPostSearchPluginFNs: search postoperation plugins "
537                                 "failed\n", 0, 0, 0 );
538 #else
539                 Debug(LDAP_DEBUG_TRACE, "doPostSearchPluginFNs: search postoperation plugins "
540                                 "failed.\n", 0, 0, 0);
541 #endif
542         }
543 }
544
545 void dummy(void)
546 {
547         /*
548          * XXX slapi_search_internal() was no getting pulled
549          * in; all manner of linker flags failed to link it.
550          * FIXME
551          */
552         slapi_search_internal( NULL, 0, NULL, NULL, NULL, 0 );
553 }
554 #endif /* LDAP_SLAPI */
555