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