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