]> git.sur5r.net Git - openldap/blob - servers/slapd/search.c
First round of imports from HEAD
[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( 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, alen;
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                         alen = an[i].an_name.bv_len;
239                         if (alen >= sizeof(abuf)) {
240                                 alen = sizeof(abuf)-1;
241                         }
242                         if (len && (len + 1 + alen >= sizeof(abuf))) {
243                                 Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu SRCH attr=%s\n",
244                                     op->o_connid, op->o_opid, abuf, 0, 0 );
245                                 len = 0;
246                                 ptr = abuf;
247                         }
248                         if (len) {
249                                 *ptr++ = ' ';
250                                 len++;
251                         }
252                         ptr = lutil_strncopy(ptr, an[i].an_name.bv_val, alen);
253                         len += alen;
254                         *ptr = '\0';
255                 }
256                 if (len) {
257                         Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu SRCH attr=%s\n",
258                                 op->o_connid, op->o_opid, abuf, 0, 0 );
259                 }
260         }
261
262         manageDSAit = get_manageDSAit( op );
263
264         if ( scope == LDAP_SCOPE_BASE ) {
265                 Entry *entry = NULL;
266
267                 if ( nbase.bv_len == 0 ) {
268 #ifdef LDAP_CONNECTIONLESS
269                         /* Ignore LDAPv2 CLDAP Root DSE queries */
270                         if (op->o_protocol == LDAP_VERSION2 && conn->c_is_udp) {
271                                 goto return_results;
272                         }
273 #endif
274                         /* check restrictions */
275                         rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ;
276                         if( rc != LDAP_SUCCESS ) {
277                                 send_ldap_result( conn, op, rc,
278                                         NULL, text, NULL, NULL );
279                                 goto return_results;
280                         }
281
282 #ifdef LDAP_SLAPI
283                         attrs = anlist2charray( an );
284                         pb = initSearchPlugin( NULL, conn, op, &nbase, scope,
285                                 deref, sizelimit, timelimit, filter, &fstr,
286                                 attrs, attrsonly, manageDSAit );
287                         rc = doPreSearchPluginFNs( NULL, pb );
288                         if ( rc == LDAP_SUCCESS ) {
289                                 doSearchRewriteFNs( NULL, pb, &filter, &fstr );
290 #endif /* LDAP_SLAPI */
291                         rc = root_dse_info( conn, &entry, &text );
292 #ifdef LDAP_SLAPI
293                         }
294 #endif /* LDAP_SLAPI */
295
296                 } else if ( bvmatch( &nbase, &global_schemandn ) ) {
297                         /* check restrictions */
298                         rc = backend_check_restrictions( NULL, conn, op, NULL, &text ) ;
299                         if( rc != LDAP_SUCCESS ) {
300                                 send_ldap_result( conn, op, rc,
301                                         NULL, text, NULL, NULL );
302                                 goto return_results;
303                         }
304
305 #ifdef LDAP_SLAPI
306                         attrs = anlist2charray( an );
307                         pb = initSearchPlugin( NULL, conn, op, &nbase, scope,
308                                 deref, sizelimit, timelimit, filter, &fstr,
309                                 attrs, attrsonly, manageDSAit );
310                         rc = doPreSearchPluginFNs( NULL, pb );
311                         if ( rc == LDAP_SUCCESS ) {
312                                 doSearchRewriteFNs( NULL, pb, &filter, &fstr );
313 #endif /* LDAP_SLAPI */
314                         rc = schema_info( &entry, &text );
315 #ifdef LDAP_SLAPI
316                         }
317 #endif /* LDAP_SLAPI */
318                 }
319
320                 if( rc != LDAP_SUCCESS ) {
321                         send_ldap_result( conn, op, rc,
322                                 NULL, text, NULL, NULL );
323 #ifdef LDAP_SLAPI
324                         doPostSearchPluginFNs( NULL, pb );
325 #endif /* LDAP_SLAPI */
326                         goto return_results;
327
328                 } else if ( entry != NULL ) {
329                         rc = test_filter( NULL, conn, op,
330                                 entry, filter );
331
332                         if( rc == LDAP_COMPARE_TRUE ) {
333                                 send_search_entry( NULL, conn, op,
334                                         entry, an, attrsonly, NULL );
335                         }
336                         entry_free( entry );
337
338                         send_ldap_result( conn, op, LDAP_SUCCESS,
339                                 NULL, NULL, NULL, NULL );
340 #ifdef LDAP_SLAPI
341                         doPostSearchPluginFNs( NULL, pb );
342 #endif /* LDAP_SLAPI */
343                         goto return_results;
344                 }
345         }
346
347         if( !nbase.bv_len && default_search_nbase.bv_len ) {
348                 ch_free( pbase.bv_val );
349                 ch_free( nbase.bv_val );
350
351                 ber_dupbv( &pbase, &default_search_base );
352                 ber_dupbv( &nbase, &default_search_nbase );
353         }
354
355         /*
356          * We could be serving multiple database backends.  Select the
357          * appropriate one, or send a referral to our "referral server"
358          * if we don't hold it.
359          */
360         if ( (be = select_backend( &nbase, manageDSAit, 1 )) == NULL ) {
361                 BerVarray ref = referral_rewrite( default_referral,
362                         NULL, &pbase, scope );
363
364                 send_ldap_result( conn, op, rc = LDAP_REFERRAL,
365                         NULL, NULL, ref ? ref : default_referral, NULL );
366
367                 ber_bvarray_free( ref );
368                 goto return_results;
369         }
370
371         /* check restrictions */
372         rc = backend_check_restrictions( be, conn, op, NULL, &text ) ;
373         if( rc != LDAP_SUCCESS ) {
374                 send_ldap_result( conn, op, rc,
375                         NULL, text, NULL, NULL );
376                 goto return_results;
377         }
378
379         /* check for referrals */
380         rc = backend_check_referrals( be, conn, op, &pbase, &nbase );
381         if ( rc != LDAP_SUCCESS ) {
382                 goto return_results;
383         }
384
385         /* deref the base if needed */
386         suffix_alias( be, &nbase );
387
388 #ifdef LDAP_SLAPI
389         attrs = anlist2charray( an );
390         pb = initSearchPlugin( be, conn, op, &pbase,
391                 scope, deref, sizelimit,
392                 timelimit, filter, &fstr, attrs, attrsonly,
393                 manageDSAit );
394         rc = doPreSearchPluginFNs( be, pb );
395         if ( rc != LDAP_SUCCESS ) {
396                 goto return_results;
397         }
398
399         doSearchRewriteFNs( be, pb, &filter, &fstr );
400 #endif /* LDAP_SLAPI */
401
402         /* actually do the search and send the result(s) */
403         if ( be->be_search ) {
404                 (*be->be_search)( be, conn, op, &pbase, &nbase,
405                         scope, deref, sizelimit,
406                         timelimit, filter, &fstr, an, attrsonly );
407         } else {
408                 send_ldap_result( conn, op, rc = LDAP_UNWILLING_TO_PERFORM,
409                         NULL, "operation not supported within namingContext",
410                         NULL, NULL );
411         }
412
413 #ifdef LDAP_SLAPI
414         doPostSearchPluginFNs( be, pb );
415 #endif /* LDAP_SLAPI */
416
417 return_results:;
418
419 #ifdef LDAP_CLIENT_UPDATE
420         if ( ( op->o_clientupdate_type & SLAP_LCUP_PERSIST ) )
421                 return rc;
422 #endif
423 #if defined(LDAP_CLIENT_UPDATE) && defined(LDAP_SYNC)
424         else
425 #endif
426 #ifdef LDAP_SYNC
427         if ( ( op->o_sync_mode & SLAP_SYNC_PERSIST ) )
428                 return rc;
429 #endif
430
431         if( pbase.bv_val != NULL) free( pbase.bv_val );
432         if( nbase.bv_val != NULL) free( nbase.bv_val );
433
434         if( fstr.bv_val != NULL) free( fstr.bv_val );
435         if( filter != NULL) filter_free( filter );
436         if( an != NULL ) free( an );
437 #ifdef LDAP_SLAPI
438         if( attrs != NULL) ch_free( attrs );
439 #endif /* LDAP_SLAPI */
440
441         return rc;
442 }
443
444 #ifdef LDAP_SLAPI
445
446 static char **anlist2charray( AttributeName *an )
447 {
448         char **attrs;
449         int i;
450
451         if ( an != NULL ) {
452                 for ( i = 0; an[i].an_name.bv_val != NULL; i++ )
453                         ;
454                 attrs = (char **)ch_malloc( (i + 1) * sizeof(char *) );
455                 for ( i = 0; an[i].an_name.bv_val != NULL; i++ ) {
456                         attrs[i] = an[i].an_name.bv_val;
457                 }
458                 attrs[i] = NULL;
459         } else {
460                 attrs = NULL;
461         }
462
463         return attrs;
464 }
465
466 static Slapi_PBlock *initSearchPlugin( Backend *be, Connection *conn, Operation *op,
467         struct berval *base, int scope, int deref, int sizelimit,
468         int timelimit, Filter *filter, struct berval *fstr,
469         char **attrs, int attrsonly, int managedsait )
470 {
471         Slapi_PBlock *pb;
472
473         pb = op->o_pb;
474
475         slapi_x_backend_set_pb( pb, be );
476         slapi_x_connection_set_pb( pb, conn );
477         slapi_x_operation_set_pb( pb, op );
478         slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, (void *)base->bv_val );
479         slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, (void *)scope );
480         slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, (void *)deref );
481         slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, (void *)sizelimit );
482         slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, (void *)timelimit );
483         slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, (void *)filter );
484         slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, (void *)fstr->bv_val );
485         slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, (void *)attrs );
486         slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, (void *)attrsonly );
487         slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, (void *)managedsait );
488
489         return pb;
490 }
491
492 static int doPreSearchPluginFNs( Backend *be, Slapi_PBlock *pb )
493 {
494         int rc;
495
496         rc = doPluginFNs( be, SLAPI_PLUGIN_PRE_SEARCH_FN, pb );
497         if ( rc != 0 ) {
498                 /*
499                  * A preoperation plugin failure will abort the
500                  * entire operation.
501                  */
502 #ifdef NEW_LOGGING
503                 LDAP_LOG( OPERATION, INFO, "doPreSearchPluginFNs: search preoperation plugin "
504                                 "returned %d\n", rc, 0, 0 );
505 #else
506                 Debug(LDAP_DEBUG_TRACE, "doPreSearchPluginFNs: search preoperation plugin "
507                                 "returned %d.\n", rc, 0, 0);
508 #endif
509                 if ( slapi_pblock_get( pb, SLAPI_RESULT_CODE, (void *)&rc ) != 0)
510                         rc = LDAP_OTHER;
511         } else {
512                 rc = LDAP_SUCCESS;
513         }
514
515         return rc;
516 }
517
518 static int doSearchRewriteFNs( Backend *be, Slapi_PBlock *pb, Filter **filter, struct berval *fstr )
519 {
520         if ( doPluginFNs( be, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ) == 0 ) {
521                 /*
522                  * The plugin can set the SLAPI_SEARCH_FILTER.
523                  * SLAPI_SEARCH_STRFILER is not normative.
524                  */
525                 slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, (void *)filter);
526                 ch_free( fstr->bv_val );
527                 filter2bv( *filter, fstr );
528 #ifdef NEW_LOGGING
529                 LDAP_LOG( OPERATION, ARGS, 
530                         "doSearchRewriteFNs: after compute_rewrite_search filter: %s\n", 
531                         fstr->bv_len ? fstr->bv_val : "empty", 0, 0 );
532 #else
533                 Debug( LDAP_DEBUG_ARGS, "    after compute_rewrite_search filter: %s\n",
534                         fstr->bv_len ? fstr->bv_val : "empty", 0, 0 );
535 #endif
536         }
537
538         return LDAP_SUCCESS;
539 }
540
541 static void doPostSearchPluginFNs( Backend *be, Slapi_PBlock *pb )
542 {
543         if ( doPluginFNs( be, SLAPI_PLUGIN_POST_SEARCH_FN, pb ) != 0 ) {
544 #ifdef NEW_LOGGING
545                 LDAP_LOG( OPERATION, INFO, "doPostSearchPluginFNs: search postoperation plugins "
546                                 "failed\n", 0, 0, 0 );
547 #else
548                 Debug(LDAP_DEBUG_TRACE, "doPostSearchPluginFNs: search postoperation plugins "
549                                 "failed.\n", 0, 0, 0);
550 #endif
551         }
552 }
553
554 void dummy(void)
555 {
556         /*
557          * XXX slapi_search_internal() was no getting pulled
558          * in; all manner of linker flags failed to link it.
559          * FIXME
560          */
561         slapi_search_internal( NULL, 0, NULL, NULL, NULL, 0 );
562 }
563 #endif /* LDAP_SLAPI */
564