]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/cache-search.c
remove dnNormalize2
[openldap] / servers / slapd / back-meta / cache-search.c
1 /*
2  * Copyright (c) 2003 by International Business Machines, Inc.
3  *
4  * International Business Machines, Inc. (hereinafter called IBM) grants
5  * permission under its copyrights to use, copy, modify, and distribute this
6  * Software with or without fee, provided that the above copyright notice and
7  * all paragraphs of this notice appear in all copies, and that the name of IBM
8  * not be used in connection with the marketing of any product incorporating
9  * the Software or modifications thereof, without specific, written prior
10  * permission.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
13  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14  * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
15  * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
17  * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
18  *
19  * 
20  * This software is based on the backends back-ldap and back-meta, implemented
21  * by Howard Chu <hyc@highlandsun.com>, Mark Valence
22  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
23  * contributors. 
24  *
25  * The original copyright statements follow. 
26  * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
27  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
28  *
29  * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
30  *
31  * This work has been developed to fulfill the requirements
32  * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
33  * to the OpenLDAP Foundation in the hope that it may be useful
34  * to the Open Source community, but WITHOUT ANY WARRANTY.
35  *
36  * Permission is granted to anyone to use this software for any purpose
37  * on any computer system, and to alter it and redistribute it, subject
38  * to the following restrictions:
39  *
40  * 1. The author and SysNet s.n.c. are not responsible for the consequences
41  *    of use of this software, no matter how awful, even if they arise from 
42  *    flaws in it.
43  *
44  * 2. The origin of this software must not be misrepresented, either by
45  *    explicit claim or by omission.  Since few users ever read sources,
46  *    credits should appear in the documentation.
47  *
48  * 3. Altered versions must be plainly marked as such, and must not be
49  *    misrepresented as being the original software.  Since few users
50  *    ever read sources, credits should appear in the documentation.
51  *    SysNet s.n.c. cannot be responsible for the consequences of the
52  *    alterations.
53  *
54  * 4. This notice may not be removed or altered.
55  *
56  *
57  * This software is based on the backend back-ldap, implemented
58  * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
59  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
60  * contributors. The contribution of the original software to the present
61  * implementation is acknowledged in this copyright statement.
62  *
63  * A special acknowledgement goes to Howard for the overall architecture
64  * (and for borrowing large pieces of code), and to Mark, who implemented
65  * from scratch the attribute/objectclass mapping.
66  *
67  * The original copyright statement follows.
68  *
69  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
70  *
71  * Permission is granted to anyone to use this software for any purpose
72  * on any computer system, and to alter it and redistribute it, subject
73  * to the following restrictions:
74  *
75  * 1. The author is not responsible for the consequences of use of this
76  *    software, no matter how awful, even if they arise from flaws in it.
77  *
78  * 2. The origin of this software must not be misrepresented, either by
79  *    explicit claim or by omission.  Since few users ever read sources,
80  *    credits should appear in the documentation.
81  *
82  * 3. Altered versions must be plainly marked as such, and must not be
83  *    misrepresented as being the original software.  Since few users
84  *    ever read sources, credits should appear in the
85  *    documentation.
86  *
87  * 4. This notice may not be removed or altered.
88  *                
89  */
90 #include "portable.h"
91
92 #include <stdio.h>
93
94 #include <ac/socket.h>
95 #include <ac/string.h>
96 #include <ac/time.h>
97
98 #include "ldap_pvt.h"
99 #include "lutil.h"
100 #include "slap.h"
101 #include "../back-ldap/back-ldap.h"
102 #include "back-meta.h"
103 #undef ldap_debug       /* silence a warning in ldap-int.h */
104 #include "ldap_log.h"
105 #include "../../../libraries/libldap/ldap-int.h"
106
107 #ifdef LDAP_CACHING 
108 static Entry* 
109 meta_create_entry(
110         Backend         *be,
111         struct metaconn *lc,
112         int             target,
113         LDAPMessage     *e,
114         struct exception* result
115 ); 
116
117 static int
118 is_one_level_rdn(
119         const char      *rdn,
120         int             from
121 );
122
123 static struct metaconn*  
124 metaConnect(
125         struct metainfo* li, 
126         Connection* conn, 
127         Operation* op, 
128         int op_type, 
129         struct berval* nbase, 
130         struct exception* result 
131 );
132
133 static void
134 add_filter_attrs(
135         AttributeName** newattrs, 
136         AttributeName* attrs, 
137         AttributeName* filter_attrs
138 );
139
140 static int 
141 handleLdapResult(
142         struct metaconn* lc, 
143         Operation* op, 
144         int* msgid, Backend* be, 
145         AttributeName* attrs, 
146         int attrsonly, 
147         int candidates, 
148         int cacheable, 
149         Entry*** entry_array, 
150         int curr_limit, 
151         int slimit,
152         struct exception* result
153 );
154
155 static Entry* 
156 get_result_entry(
157         Backend* be,
158         struct metaconn* lc, 
159         struct metasingleconn* lsc, 
160         int* msgid,
161         int i, 
162         struct timeval* tv, 
163         struct exception* result
164 ); 
165
166 static void
167 rewriteSession(
168         struct rewrite_info* info, 
169         const char* rewriteContext, 
170         const char* string, 
171         const void* cookie,  
172         char** base, 
173         struct exception* result
174 );
175
176 static int 
177 get_attr_set(
178         AttributeName* attrs, 
179         query_manager* qm, 
180         int num
181 );
182
183 static int 
184 attrscmp(
185         AttributeName* attrs_in, 
186         AttributeName* attrs
187 );
188
189 static char* 
190 cache_entries(
191         Entry** entry_array, 
192         cache_manager* cm, 
193         Backend* be, 
194         Connection* conn, 
195         struct exception* result
196 ); 
197
198 static int 
199 is_temp_answerable(
200         int attr_set, 
201         struct berval* tempstr, 
202         query_manager* qm, 
203         int template_id
204 );
205
206 static void
207 consistency_check(
208         Backend* be,
209         Backend* glue_be, 
210         Connection* conn
211 ); 
212
213 static int
214 cache_back_sentry(
215         Backend* be, 
216         Connection* conn,
217         Operation* op, 
218         Entry* e, 
219         AttributeName* attrs, 
220         int attrsonly, 
221         LDAPControl** ctrls
222 );
223
224 int
225 meta_back_cache_search(
226         Backend         *be,
227         Connection      *conn,
228         Operation       *op,
229         struct berval   *base,
230         struct berval   *nbase,
231         int             scope,
232         int             deref,
233         int             slimit,
234         int             tlimit,
235         Filter          *filt,
236         struct berval   *filterstr,
237         AttributeName   *attributes,
238         int             attrsonly
239 )
240 {
241         struct metainfo         *li = ( struct metainfo * )be->be_private;
242         struct metaconn         *lc;
243         struct metasingleconn   *lsc;
244         cache_manager*          cm = li->cm; 
245         query_manager*          qm = cm->qm; 
246
247         time_t                  curr_time; 
248
249         int count, rc = 0, *msgid = NULL; 
250         char *mbase = NULL;
251         char *cbase = NULL; 
252         char *uuid; 
253             
254         int i = -1, last = 0, candidates = 0, op_type;
255
256         struct berval   mfilter;
257         struct berval   cachebase = { 0L, NULL };  
258         struct berval   ncachebase = { 0L, NULL };  
259         struct berval   cache_suffix; 
260         struct berval   tempstr = { 0L, NULL }; 
261
262         AttributeName   *filter_attrs = NULL; 
263         AttributeName   *new_attrs = NULL; 
264         AttributeName   *attrs = NULL; 
265
266         Entry           *e;
267         Entry           **entry_array = NULL;
268
269         Query           query; 
270
271         int             attr_set = -1; 
272         int             template_id = -1; 
273         int             answerable = 0; 
274         int             cacheable = 0; 
275         int             num_entries = 0;
276         int             curr_limit;
277         int             fattr_cnt=0; 
278
279    
280         struct exception result[1]; 
281
282         Filter* filter = str2filter(filterstr->bv_val); 
283         slap_callback cb = {NULL, NULL, cache_back_sentry, NULL}; 
284
285         cb.sc_private = be; 
286
287         if (attributes) {
288                 for ( count=0; attributes[ count ].an_name.bv_val; count++ )
289                         ;
290                 attrs = (AttributeName*)malloc( ( count + 1 ) *
291                                                 sizeof(AttributeName));
292                 for ( count=0; attributes[ count ].an_name.bv_val; count++ ) {
293                         ber_dupbv(&attrs[ count ].an_name,
294                                                 &attributes[ count ].an_name);
295                         attrs[count].an_desc = attributes[count].an_desc; 
296                 }
297                 attrs[ count ].an_name.bv_val = NULL;
298                 attrs[ count ].an_name.bv_len = 0;
299         }
300
301         result->type = SUCCESS; 
302         result->rc = 0; 
303         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
304         cm->threads++; 
305 #ifdef NEW_LOGGING
306         LDAP_LOG( BACK_META, DETAIL1, "Threads++ = %d\n", cm->threads, 0, 0 );
307 #else /* !NEW_LOGGING */
308         Debug( LDAP_DEBUG_ANY, "Threads++ = %d\n", cm->threads, 0, 0 );
309 #endif /* !NEW_LOGGING */
310         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
311     
312         filter2template(filter, &tempstr, &filter_attrs, &fattr_cnt, result);  
313         if (result->type != SUCCESS) 
314                 goto Catch; 
315
316 #ifdef NEW_LOGGING
317         LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
318                                         tempstr.bv_val, 0, 0 );
319 #else /* !NEW_LOGGING */
320         Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
321                                         tempstr.bv_val, 0, 0 );
322 #endif /* !NEW_LOGGING */
323         curr_limit = cm->num_entries_limit ;
324
325         /* find attr set */     
326         attr_set = get_attr_set(attrs, qm, cm->numattrsets); 
327     
328         query.filter = filter; 
329         query.attrs = attrs; 
330         query.base = *base; 
331         query.scope = scope; 
332
333         /* check for query containment */
334         if (attr_set > -1) {
335                 for (i=0; i<cm->numtemplates; i++) {
336                         /* find if template i can potentially answer tempstr */
337                         if (!is_temp_answerable(attr_set, &tempstr, qm, i)) 
338                                 continue; 
339                         if (attr_set == qm->templates[i].attr_set_index) {
340                                 cacheable = 1; 
341                                 template_id = i; 
342                         }
343 #ifdef NEW_LOGGING
344                         LDAP_LOG( BACK_META, DETAIL2,
345                                         "Entering QC, querystr = %s\n",
346                                         filterstr->bv_val, 0, 0 );
347 #else /* !NEW_LOGGING */
348                         Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
349                                                 filterstr->bv_val, 0, 0 );
350 #endif /* !NEW_LOGGING */
351                         answerable = (*(qm->qcfunc))(qm, &query, i);
352
353                         if (answerable)
354                                 break;
355                 }
356         }
357
358         if (answerable) {
359 #ifdef NEW_LOGGING
360                 LDAP_LOG( BACK_META, DETAIL1, "QUERY ANSWERABLE\n", 0, 0, 0 );
361 #else /* !NEW_LOGGING */
362                 Debug( LDAP_DEBUG_ANY, "QUERY ANSWERABLE\n", 0, 0, 0 );
363 #endif /* !NEW_LOGGING */
364                 rewriteSession(li->rwinfo, "cacheBase", base->bv_val,
365                                         conn, &cbase, result); 
366                 if (result->type != SUCCESS) { 
367                         ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock); 
368                         goto Catch; 
369                 }
370                 if ( cbase == NULL ) {
371                         cachebase = *base;
372                 } else {
373                         cachebase.bv_val = cbase;
374                         cachebase.bv_len = strlen(cbase);
375                 }
376                 dnNormalize(NULL, &cachebase, &ncachebase); 
377         
378                 op->o_caching_on = 1;   
379                 op->o_callback = &cb; 
380                 li->glue_be->be_search(li->glue_be, conn, op, &cachebase,
381                                 &ncachebase, scope, deref, slimit, tlimit,
382                                 filter, filterstr, attrs, attrsonly);
383                 ber_memfree( ncachebase.bv_val );
384                 if ( cachebase.bv_val != base->bv_val ) {
385                         /* free only if rewritten */
386                         free( cachebase.bv_val );
387                 }
388
389                 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock); 
390         } else {
391 #ifdef NEW_LOGGING
392                 LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
393                                         0, 0, 0 );
394 #else /* !NEW_LOGGING */
395                 Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
396 #endif /* !NEW_LOGGING */
397
398                 if ( scope == LDAP_SCOPE_BASE ) {
399                         op_type = META_OP_REQUIRE_SINGLE;
400                 } else {
401                         op_type = META_OP_ALLOW_MULTIPLE;
402                 }
403
404                 lc = metaConnect(li, conn, op, op_type, nbase, result);
405
406                 if (result->type != SUCCESS) 
407                         goto Catch; 
408
409                 ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
410                 if (cm->num_cached_queries >= cm->max_queries) {
411                         cacheable = 0; 
412                 }
413                 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
414                 
415                 if (cacheable) {
416 #ifdef NEW_LOGGING
417                         LDAP_LOG( BACK_META, DETAIL1,
418                                         "QUERY TEMPLATE CACHEABLE\n",
419                                         0, 0, 0);
420 #else /* !NEW_LOGGING */
421                         Debug( LDAP_DEBUG_ANY, "QUERY TEMPLATE CACHEABLE\n",
422                                         0, 0, 0);
423 #endif /* !NEW_LOGGING */
424                         add_filter_attrs(&new_attrs, attrs, filter_attrs);
425                 } else {
426                         new_attrs = attrs; 
427                 }
428
429                 free(filter_attrs); 
430         
431                 /*
432                  * Array of message id of each target
433                  */
434                 msgid = ch_calloc( sizeof( int ), li->ntargets );
435                 if ( msgid == NULL ) {
436                         result->type = CONN_ERR; 
437                         goto Catch; 
438                 }
439
440                 /*
441                 if (slimit > 0 &&  (slimit <= cm->num_entries_limit))  
442                         slimit = cm->num_entries_limit; 
443                 */
444
445                 /*
446                  * Inits searches
447                  */
448
449                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
450                         char    *realbase = ( char * )base->bv_val;
451                         int     realscope = scope;
452                         ber_len_t suffixlen;
453                         char    *mapped_filter, **mapped_attrs;
454
455                         /* FIXME: Check for more than one targets */
456                         if ( meta_back_is_candidate(
457                                         &li->targets[i]->suffix, nbase ))
458                                 lsc->candidate = META_CANDIDATE; 
459
460                         if ( lsc->candidate != META_CANDIDATE ) 
461                                 continue;
462
463                         if ( deref != -1 ) {
464                                 ldap_set_option( lsc->ld, LDAP_OPT_DEREF,
465                                                 ( void * )&deref);
466                         }
467                         if ( tlimit != -1 ) {
468                                 ldap_set_option( lsc->ld, LDAP_OPT_TIMELIMIT,
469                                                 ( void * )&tlimit);
470                         }
471                         if ( slimit != -1 ) {
472                                 ldap_set_option( lsc->ld, LDAP_OPT_SIZELIMIT,
473                                                 ( void * )&slimit);
474                         }
475
476                         /*
477                          * modifies the base according to the scope, if required
478                          */
479                         suffixlen = li->targets[ i ]->suffix.bv_len;
480                         if ( suffixlen > nbase->bv_len ) {
481                                 switch ( scope ) {
482                                 case LDAP_SCOPE_SUBTREE:
483                                         /*
484                                          * make the target suffix the new base
485                                          * FIXME: this is very forgiving,
486                                          * because illegal bases may be turned
487                                          * into the suffix of the target.
488                                          */
489                                         if ( dnIsSuffix(
490                                                 &li->targets[ i ]->suffix,
491                                                 nbase ) ) {
492                                                 realbase =
493                                                 li->targets[i]->suffix.bv_val;
494                                         } else {
495                                                 /*
496                                                  * this target is no longer
497                                                  * candidate
498                                                  */
499                                                 lsc->candidate =
500                                                         META_NOT_CANDIDATE;
501                                                 continue;
502                                         }
503                                         break;
504
505                                 case LDAP_SCOPE_ONELEVEL:
506                                         if ( is_one_level_rdn(
507                                                 li->targets[ i ]->suffix.bv_val,
508                                                 suffixlen - nbase->bv_len - 1 )
509                                                 && dnIsSuffix(
510                                                 &li->targets[ i ]->suffix,
511                                                 nbase ) ) {
512                                                 /*
513                                                  * if there is exactly one
514                                                  * level, make the target suffix
515                                                  * the new base, and make scope
516                                                  * "base"
517                                                  */
518                                                 realbase =
519                                                 li->targets[i]->suffix.bv_val;
520                                                 realscope = LDAP_SCOPE_BASE;
521                                                 break;
522                                         } /* else continue with the next case */
523                                 case LDAP_SCOPE_BASE:
524                                         /*
525                                          * this target is no longer candidate
526                                          */
527                                         lsc->candidate = META_NOT_CANDIDATE;
528                                         continue;
529                                 }
530                         }
531
532                         /*
533                          * Rewrite the search base, if required
534                          */
535
536                         rewriteSession(li->targets[i]->rwinfo, "searchBase",
537                                         realbase, conn, &mbase, result); 
538
539                         if (result->type != SUCCESS)
540                                 goto Catch; 
541
542                         if ( mbase == NULL ) {
543                                 mbase = realbase;
544                         }
545
546                         /*
547                          * Rewrite the search filter, if required
548                          */
549                         rewriteSession( li->targets[i]->rwinfo, "searchFilter",
550                                         filterstr->bv_val, conn,
551                                         &mfilter.bv_val, result);
552                         if (result->type != SUCCESS) 
553                                 goto Catch; 
554
555                         if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ]
556                                                                 != '\0') {
557                                 mfilter.bv_len = strlen( mfilter.bv_val );
558                         } else {
559                                 if ( mfilter.bv_val != NULL ) {
560                                         free( mfilter.bv_val );
561                                 }
562                                 mfilter = *filterstr;
563                         }
564
565                         /*
566                          * Maps attributes in filter
567                          */
568                         mapped_filter = ldap_back_map_filter(
569                                         &li->targets[i]->at_map,
570                                         &li->targets[i]->oc_map, &mfilter, 0 );
571                         if ( mapped_filter == NULL ) {
572                                 mapped_filter = ( char * )mfilter.bv_val;
573                         } else {
574                                 if ( mfilter.bv_val != filterstr->bv_val ) {
575                                         free( mfilter.bv_val );
576                                 }
577                         }
578                         mfilter.bv_val = NULL;
579                         mfilter.bv_len = 0;
580
581                         /*
582                          * Maps required attributes
583                          */
584                         mapped_attrs = ldap_back_map_attrs(
585                                         &li->targets[ i ]->at_map,
586                                         new_attrs, 0 );
587                         if ( mapped_attrs == NULL && new_attrs) {
588                                 for ( count=0;
589                                       new_attrs[ count ].an_name.bv_val;
590                                       count++)
591                                         ;
592                                 mapped_attrs = ch_malloc( ( count + 1 ) *
593                                                         sizeof(char *));
594                                 for ( count=0;
595                                       new_attrs[ count ].an_name.bv_val;
596                                       count++ ) {
597                                         mapped_attrs[ count ] =
598                                                 new_attrs[count].an_name.bv_val;
599                                 }
600                                 mapped_attrs[ count ] = NULL;
601                         }
602
603                         /*
604                          * Starts the search
605                          */
606                         msgid[ i ] = ldap_search( lsc->ld, mbase, realscope,
607                                                 mapped_filter, mapped_attrs,
608                                                 attrsonly ); 
609                         if ( msgid[ i ] == -1 ) {
610                                 lsc->candidate = META_NOT_CANDIDATE;
611                                 continue;
612                         }
613
614                         if ( mapped_attrs ) {
615                                 free( mapped_attrs );
616                                 mapped_attrs = NULL;
617                         }
618
619                         if ( mapped_filter != filterstr->bv_val ) {
620                                 free( mapped_filter );
621                                 mapped_filter = NULL;
622                         }
623
624                         if ( mbase != realbase ) {
625                                 free( mbase );
626                                 mbase = NULL;
627                         }
628
629                         ++candidates;
630                 }
631
632                 num_entries = handleLdapResult(lc, op, msgid, be, attrs,
633                                 attrsonly, candidates, cacheable, &entry_array,
634                                 curr_limit, slimit, result); 
635
636                 if (result->type != SUCCESS) 
637                         goto Catch; 
638                 if (cacheable && (num_entries <= curr_limit)) {
639 #ifdef NEW_LOGGING
640                         LDAP_LOG( BACK_META, DETAIL1,
641                                         "QUERY CACHEABLE\n", 0, 0, 0 );
642 #else /* !NEW_LOGGING */
643                         Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
644 #endif /* !NEW_LOGGING */
645                         uuid = cache_entries(entry_array, cm, li->glue_be,
646                                                         conn, result); 
647 #ifdef NEW_LOGGING
648                         LDAP_LOG( BACK_META, DETAIL1,
649                                         "Added query %s UUID %s ENTRIES %d\n",
650                                         filterstr->bv_val, uuid, num_entries );
651 #else /* !NEW_LOGGING */
652                         Debug( LDAP_DEBUG_ANY,
653                                         "Added query %s UUID %s ENTRIES %d\n",
654                                         filterstr->bv_val, uuid, num_entries );
655 #endif /* !NEW_LOGGING */
656             
657                         if (result->type != SUCCESS) 
658                                 goto Catch; 
659                         (*(qm->addfunc))(qm, &query, template_id, uuid, result); 
660                         if (result->type != SUCCESS) 
661                                 goto Catch; 
662                         filter = 0; 
663                         attrs = 0; 
664                 }
665         }
666
667 Catch:;
668         switch (result->type) {
669                 case SUCCESS: 
670                         rc=0; 
671                         break; 
672                 case FILTER_ERR: 
673 #ifdef NEW_LOGGING
674                         LDAP_LOG( BACK_META, DETAIL1,
675                                         "Invalid template error\n", 0, 0, 0 );
676 #else /* !NEW_LOGGING */
677                         Debug( LDAP_DEBUG_ANY, "Invalid template error\n",
678                                         0, 0, 0 );
679 #endif /* !NEW_LOGGING */
680                         break; 
681                 case CONN_ERR: 
682                         rc = -1; 
683 #ifdef NEW_LOGGING
684                         LDAP_LOG( BACK_META, DETAIL1,
685                                 "Could not connect to a remote server\n",
686                                 0, 0, 0 );
687 #else /* !NEW_LOGGING */
688                         Debug( LDAP_DEBUG_ANY,
689                                 "Could not connect to a remote server\n",
690                                 0, 0, 0 );
691 #endif /* !NEW_LOGGING */
692                         send_ldap_result(conn, op, LDAP_OTHER,  
693                                         NULL, "Connection error",
694                                         NULL, NULL );
695                         break; 
696                 case RESULT_ERR: 
697                         rc = -1; 
698 #ifdef NEW_LOGGING
699                         LDAP_LOG( BACK_META, DETAIL1,
700                                 "Error in handling ldap_result\n", 0, 0, 0 );
701 #else /* !NEW_LOGGING */
702                         Debug( LDAP_DEBUG_ANY,
703                                 "Error in handling ldap_result\n", 0, 0, 0 );
704 #endif /* !NEW_LOGGING */
705                         break; 
706                 case REWRITING_ERR: 
707                         rc = -1; 
708                         if (result->rc == REWRITE_REGEXEC_UNWILLING) {
709                                 send_ldap_result( conn, op,
710                                                 LDAP_UNWILLING_TO_PERFORM,
711                                                 NULL, "Unwilling to perform",
712                                                 NULL, NULL );
713                         } else {
714                                 send_ldap_result( conn, op, LDAP_OTHER,
715                                                 NULL, "Rewrite error",
716                                                 NULL, NULL );
717                         }
718                         break; 
719                 case MERGE_ERR: 
720                         rc = -1; 
721 #ifdef NEW_LOGGING
722                         LDAP_LOG( BACK_META, DETAIL1,
723                                 "Error in merging entry \n", 0, 0, 0 );
724 #else /* !NEW_LOGGING */
725                         Debug( LDAP_DEBUG_ANY,
726                                 "Error in merging entry \n", 0, 0, 0 );
727 #endif /* !NEW_LOGGING */
728                         break; 
729                 case REMOVE_ERR: 
730                         rc = -1; 
731 #ifdef NEW_LOGGING
732                         LDAP_LOG( BACK_META, DETAIL1,
733                                         "Error in removing query \n",
734                                         0, 0, 0 );
735 #else /* !NEW_LOGGING */
736                         Debug( LDAP_DEBUG_ANY, "Error in removing query \n",
737                                         0, 0, 0 );
738 #endif /* !NEW_LOGGING */
739                         break; 
740                 default:
741                         /* assert(0); */
742                         break;
743         }
744
745         ldap_pvt_thread_mutex_lock(&cm->consistency_mutex); 
746         curr_time = slap_get_time(); 
747         if (curr_time - cm->consistency_time > cm->consistency_cycle_time) {
748                 cm->consistency_time = curr_time; 
749                 consistency_check(be, li->glue_be, conn); 
750         }       
751         ldap_pvt_thread_mutex_unlock(&cm->consistency_mutex); 
752
753         if ( msgid ) {
754                 ch_free( msgid );
755         }
756         if (entry_array)  {
757                 for (i=0; (e = entry_array[i]); i++) {
758                         entry_free(e); 
759                 }
760                 free(entry_array);
761         }
762         if (filter) 
763                 filter_free(filter);
764
765         if (new_attrs) {
766                 if (new_attrs != attrs) 
767                         free(new_attrs); 
768         }
769
770         if (attrs)
771                 free(attrs); 
772
773         if (tempstr.bv_val ) {
774                 free(tempstr.bv_val);
775         }
776         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
777         cm->threads--; 
778 #ifdef NEW_LOGGING
779         LDAP_LOG( BACK_META, DETAIL1, "Threads-- = %d\n", cm->threads, 0, 0 ); 
780 #else /* !NEW_LOGGING */
781         Debug( LDAP_DEBUG_ANY, "Threads-- = %d\n", cm->threads, 0, 0 ); 
782 #endif /* !NEW_LOGGING */
783         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
784         return rc;
785 }
786
787
788 static Entry* 
789 meta_create_entry (
790         Backend                 *be,
791         struct metaconn         *lc,
792         int                     target,
793         LDAPMessage             *e,
794         struct exception*       result
795 )
796 {
797         struct metainfo         *li = ( struct metainfo * )be->be_private;
798         struct berval           a, mapped;
799         Entry*                  ent;
800         BerElement              ber = *e->lm_ber;
801         Attribute               *attr, **attrp;
802         struct berval           dummy = { 0, NULL };
803         struct berval           *bv, bdn;
804         const char              *text;
805         char*                   ename = NULL; 
806         if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
807                 result->type = CREATE_ENTRY_ERR;        
808                 return NULL; 
809         }
810         ent = (Entry*)malloc(sizeof(Entry)); 
811
812         /*
813          * Rewrite the dn of the result, if needed
814          */
815         rewriteSession( li->targets[ target ]->rwinfo, "searchResult",
816                         bdn.bv_val, lc->conn, &ent->e_name.bv_val, result );  
817
818         if (result->type != SUCCESS) {
819                 return NULL; 
820         }
821         if ( ent->e_name.bv_val == NULL ) {
822                 ber_dupbv(&(ent->e_name), &bdn);
823         } else {
824 #ifdef NEW_LOGGING
825                 LDAP_LOG( BACK_META, DETAIL1,
826                         "[rw] searchResult[%d]: \"%s\" -> \"%s\"\n",
827                         target, bdn.bv_val, ent->e_name.bv_val );
828 #else /* !NEW_LOGGING */
829                 Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
830                         " -> \"%s\"\n",
831                         target, bdn.bv_val, ent->e_name.bv_val );
832 #endif /* !NEW_LOGGING */
833                 ent->e_name.bv_len = strlen( ent->e_name.bv_val );
834         }
835                 
836         /*
837          * Note: this may fail if the target host(s) schema differs
838          * from the one known to the meta, and a DN with unknown
839          * attributes is returned.
840          * 
841          * FIXME: should we log anything, or delegate to dnNormalize?
842          */
843         dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname ); 
844
845         /*
846         if ( dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname )
847                 != LDAP_SUCCESS )
848         {
849                 return LDAP_INVALID_DN_SYNTAX;
850         }
851         */
852
853         /*
854          * cache dn
855          */
856         if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
857                 meta_dncache_update_entry( &li->cache, &ent->e_nname, target );
858         }
859
860         ent->e_id = 0;
861         ent->e_attrs = 0;
862         ent->e_private = 0;
863         ent->e_bv.bv_val = 0; 
864
865         attrp = &ent->e_attrs;
866
867         while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
868                 ldap_back_map( &li->targets[ target ]->at_map, &a, &mapped, 1 );
869                 if ( mapped.bv_val == NULL ) {
870                         continue;
871                 }
872                 attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
873                 if ( attr == NULL ) {
874                         continue;
875                 }
876                 attr->a_flags = 0;
877                 attr->a_next = 0;
878                 attr->a_desc = NULL;
879                 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) {
880                         if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text ) 
881                                         != LDAP_SUCCESS) {
882 #ifdef NEW_LOGGING
883                                 LDAP_LOG( BACK_META, DETAIL1,
884                                         "slap_bv2undef_ad(%s): %s\n",
885                                         mapped.bv_val, text, 0 );
886 #else /* !NEW_LOGGING */
887                                 Debug( LDAP_DEBUG_ANY,
888                                         "slap_bv2undef_ad(%s): "
889                                         "%s\n%s", mapped.bv_val, text, "" );
890 #endif /* !NEW_LOGGING */
891                                 ch_free( attr );
892                                 continue;
893                         }
894                 }
895
896                 /* no subschemaSubentry */
897                 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
898                         ch_free(attr);
899                         continue;
900                 }
901
902                 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR 
903                                 || attr->a_vals == NULL ) {
904                         attr->a_vals = &dummy;
905                 } else if ( attr->a_desc == slap_schema.si_ad_objectClass ||
906                                 attr->a_desc ==
907                                 slap_schema.si_ad_structuralObjectClass) {
908                         int i, last;
909                         for ( last = 0; attr->a_vals[ last ].bv_val; ++last )
910                                 ;
911                         for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
912                                 ldap_back_map( &li->targets[ target]->oc_map,
913                                                 bv, &mapped, 1 );
914                                 if ( mapped.bv_val == NULL ) {
915                                         free( bv->bv_val );
916                                         bv->bv_val = NULL;
917                                         if ( --last < 0 ) {
918                                                 break;
919                                         }
920                                         *bv = attr->a_vals[ last ];
921                                         attr->a_vals[ last ].bv_val = NULL;
922                                         i--;
923                                 } else if ( mapped.bv_val != bv->bv_val ) {
924                                         free( bv->bv_val );
925                                         ber_dupbv( bv, &mapped );
926                                 }
927                         }
928                 /*
929                  * It is necessary to try to rewrite attributes with
930                  * dn syntax because they might be used in ACLs as
931                  * members of groups; since ACLs are applied to the
932                  * rewritten stuff, no dn-based subecj clause could
933                  * be used at the ldap backend side (see
934                  * http://www.OpenLDAP.org/faq/data/cache/452.html)
935                  * The problem can be overcome by moving the dn-based
936                  * ACLs to the target directory server, and letting
937                  * everything pass thru the ldap backend.
938                  */
939                 } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
940                                 SLAPD_DN_SYNTAX ) == 0 ) {
941                         int i;
942                         for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
943                                 char *newval;
944                                 rewriteSession(li->targets[ target ]->rwinfo,
945                                                 "searchResult", bv->bv_val,
946                                                 lc->conn, &newval, result); 
947                                 if (result->type != SUCCESS) {
948                                         /* FIXME : Handle error */
949                                         result->type = SUCCESS; 
950                                 } else {
951                                         /* left as is */
952                                         if ( newval == NULL ) {
953                                                 break;
954                                         }
955 #ifdef NEW_LOGGING
956                                         LDAP_LOG( BACK_META, DETAIL1,
957                                                 "[rw] searchResult on "
958                                                 "attr=%s: \"%s\" -> \"%s\"\n",
959                                                 attr->a_desc->ad_type->
960                                                 sat_cname.bv_val,
961                                                 bv->bv_val, newval );
962 #else /* !NEW_LOGGING */
963                                         Debug( LDAP_DEBUG_ARGS,
964                                                 "rw> searchResult on attr=%s:"
965                                                 " \"%s\" -> \"%s\"\n",
966                                                 attr->a_desc->ad_type->
967                                                 sat_cname.bv_val,
968                                                 bv->bv_val, newval );
969 #endif /* !NEW_LOGGING */
970                                         free( bv->bv_val );
971                                         bv->bv_val = newval;
972                                         bv->bv_len = strlen( newval );
973                                 }
974                         }
975                 }
976                 *attrp = attr;
977                 attrp = &attr->a_next;
978         }
979         return ent; 
980 }
981
982 static int
983 is_one_level_rdn(
984         const char      *rdn,
985         int             from
986 )
987 {
988         for ( ; from--; ) {
989                 if ( DN_SEPARATOR( rdn[ from ] ) ) {
990                         return 0;
991                 }
992         }
993         return 1;
994 }
995
996 static struct metaconn*  
997 metaConnect(
998         struct metainfo* li, 
999         Connection* conn, 
1000         Operation* op, 
1001         int op_type, 
1002         struct berval* nbase, 
1003         struct exception* result)
1004 {
1005         struct metaconn* lc; 
1006         result->type = SUCCESS; 
1007         lc = meta_back_getconn( conn, op, op_type, nbase, NULL );
1008         if (!lc) {
1009                 result->type = CONN_ERR; 
1010                 return 0; 
1011         }
1012         return lc; 
1013 }
1014
1015 static void
1016 add_filter_attrs(
1017         AttributeName** new_attrs, 
1018         AttributeName* attrs, 
1019         AttributeName* filter_attrs )
1020 {
1021         struct berval all_user = { sizeof(LDAP_ALL_USER_ATTRIBUTES) -1,
1022                                    LDAP_ALL_USER_ATTRIBUTES };
1023
1024         struct berval all_op = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES) -1,
1025                                         LDAP_ALL_OPERATIONAL_ATTRIBUTES}; 
1026
1027         int alluser = 0; 
1028         int allop = 0; 
1029         int i; 
1030         int count; 
1031
1032         /* duplicate attrs */
1033         for (count=0; attrs[count].an_name.bv_val; count++) 
1034                 ;
1035         *new_attrs =  (AttributeName*)(malloc((count+1)*sizeof(AttributeName))); 
1036         for (i=0; i<count; i++) {
1037                 /*
1038                 ber_dupbv(&((*new_attrs)[i].an_name), &(attrs[i].an_name)); 
1039                 */
1040                 (*new_attrs)[i].an_name = attrs[i].an_name; 
1041                 (*new_attrs)[i].an_desc = attrs[i].an_desc;  
1042         }
1043         (*new_attrs)[count].an_name.bv_val = NULL; 
1044         (*new_attrs)[count].an_name.bv_len = 0; 
1045
1046
1047         if ((*new_attrs)[0].an_name.bv_val == NULL) {
1048                 *new_attrs = (AttributeName*)(malloc(2*sizeof(AttributeName))); 
1049                 (*new_attrs)[0].an_name.bv_val = "*"; 
1050                 (*new_attrs)[0].an_name.bv_len = 1; 
1051                 (*new_attrs)[1].an_name.bv_val = NULL; 
1052                 (*new_attrs)[1].an_name.bv_len = 0; 
1053                 alluser = 1; 
1054                 count = 1; 
1055         } else {
1056                 alluser = an_find(*new_attrs, &all_user); 
1057                 allop = an_find(*new_attrs, &all_op); 
1058         }
1059
1060         for ( i=0; filter_attrs[i].an_name.bv_val; i++ ) {
1061                 if ( an_find(*new_attrs, &filter_attrs[i].an_name ))
1062                         continue; 
1063                 if ( is_at_operational(filter_attrs[i].an_desc->ad_type)
1064                                                 && allop )
1065                         continue; 
1066                 else if (alluser) 
1067                         continue; 
1068                 *new_attrs = (AttributeName*)(realloc(*new_attrs,
1069                                         (count+2)*sizeof(AttributeName))); 
1070                 (*new_attrs)[count].an_name.bv_val =
1071                                 filter_attrs[i].an_name.bv_val; 
1072                 (*new_attrs)[count].an_name.bv_len =
1073                                 filter_attrs[i].an_name.bv_len; 
1074                 (*new_attrs)[count].an_desc = filter_attrs[i].an_desc; 
1075                 (*new_attrs)[count+1].an_name.bv_val = NULL; 
1076                 (*new_attrs)[count+1].an_name.bv_len = 0; 
1077                 count++; 
1078         }
1079 }
1080
1081 static int 
1082 handleLdapResult(
1083         struct metaconn* lc,
1084         Operation* op, 
1085         int* msgid, Backend* be, 
1086         AttributeName* attrs, 
1087         int attrsonly, 
1088         int candidates, 
1089         int cacheable, 
1090         Entry*** entry_array, 
1091         int curr_limit, 
1092         int slimit,
1093         struct exception* result)
1094 {
1095         Entry  *entry;
1096         char *match = NULL, *err = NULL, *cache_ename = NULL;
1097         int sres; 
1098         int mres = LDAP_SUCCESS; 
1099         int num_entries = 0, count, i, rc;     
1100         struct timeval tv = {0, 0}; 
1101         struct metasingleconn* lsc; 
1102         struct metainfo         *li = ( struct metainfo * )be->be_private;
1103         result->rc = 0; 
1104         result->type = SUCCESS; 
1105
1106         for ( count = 0, rc = 0; candidates > 0; ) {
1107                 int ab, gotit = 0;
1108
1109                 /* check for abandon */
1110                 ab = op->o_abandon;
1111
1112                 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
1113                         if ( lsc->candidate != META_CANDIDATE ) {
1114                                 continue;
1115                         }
1116
1117                         if ( ab ) {
1118                                 ldap_abandon( lsc->ld, msgid[ i ] );
1119                                 result->type = ABANDON_ERR;
1120                                 break; 
1121                         }
1122
1123                         if ( slimit > 0 && num_entries == slimit ) {
1124                                 result->type = SLIMIT_ERR; 
1125                                 break; 
1126                         }
1127
1128                         if ((entry = get_result_entry(be, lc, lsc,
1129                                                 msgid, i, &tv, result))) { 
1130                                 send_search_entry( be, lc->conn, op, entry,
1131                                                 attrs, attrsonly, NULL );
1132                                 if ((cacheable) &&
1133                                                 (num_entries < curr_limit))  {
1134                                         rewriteSession( li->rwinfo,
1135                                                         "cacheResult",
1136                                                         entry->e_name.bv_val,
1137                                                         lc->conn,
1138                                                         &cache_ename, result );  
1139                                         free(entry->e_name.bv_val); 
1140                                         if (result->type != SUCCESS) {
1141                                                 return 0; 
1142                                         }
1143                                         ber_str2bv(cache_ename,
1144                                                 strlen(cache_ename),
1145                                                 0, &entry->e_name); 
1146                                         ber_dupbv(&entry->e_nname,
1147                                                 &entry->e_name); 
1148                                         *entry_array = (Entry**)realloc(
1149                                                         *entry_array,
1150                                                         (( num_entries+2 ) *
1151                                                          sizeof( Entry* )));
1152                                         (*entry_array)[num_entries] = entry;    
1153                                         (*entry_array)[num_entries+1] = NULL;
1154                                 }
1155                                 num_entries++; 
1156                                 gotit = 1; 
1157                         } else if (result->type == REWRITING_ERR) {
1158                                 return 0; 
1159                         } else if (result->type == TIMEOUT_ERR) {
1160                                 result->type = SUCCESS; 
1161                                 continue;  
1162                         } else if (result->type == CREATE_ENTRY_ERR) {
1163                                 break; 
1164                         } else if (result->rc == -1) {
1165                                 break; 
1166                         } else {
1167                                 sres = ldap_back_map_result(result->rc);
1168                                 if (mres == LDAP_SUCCESS &&
1169                                                 sres != LDAP_SUCCESS) {
1170                                         mres = sres; 
1171                                         ldap_get_option(lsc->ld,
1172                                                 LDAP_OPT_ERROR_STRING, &err);
1173                                         ldap_get_option(lsc->ld,
1174                                                 LDAP_OPT_MATCHED_DN, &match);
1175                                 }
1176                                 lsc->candidate = META_NOT_CANDIDATE; 
1177                                 candidates--; 
1178                                 result->type = SUCCESS; 
1179                         }
1180                 }
1181                 switch (result->type) {
1182                 case RESULT_ERR: 
1183 #ifdef NEW_LOGGING
1184                         LDAP_LOG( BACK_META, DETAIL1,
1185                                         "ldap_result error, rc = -1\n",
1186                                         0, 0, 0 );
1187 #else /* !NEW_LOGGING */
1188                         Debug( LDAP_DEBUG_ANY, "ldap_result error, rc = -1\n",
1189                                         0, 0, 0 );
1190 #endif /* !NEW_LOGGING */
1191                         send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1192                                         NULL, NULL, NULL, num_entries );
1193                         return 0; 
1194                 case CREATE_ENTRY_ERR: 
1195 #ifdef NEW_LOGGING
1196                         LDAP_LOG( BACK_META, DETAIL1,
1197                                         "Error in parsing result \n",
1198                                         0, 0, 0 );
1199 #else /* !NEW_LOGGING */
1200                         Debug( LDAP_DEBUG_ANY, "Error in parsing result \n",
1201                                         0, 0, 0 );
1202 #endif /* !NEW_LOGGING */
1203                         send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1204                                         NULL, NULL, NULL, num_entries );
1205                         result->type = RESULT_ERR; 
1206                         return 0; 
1207                 case SLIMIT_ERR: 
1208 #ifdef NEW_LOGGING
1209                         LDAP_LOG( BACK_META, DETAIL1, "Size limit exceeded \n",
1210                                         0, 0, 0 );
1211 #else /* !NEW_LOGGING */
1212                         Debug( LDAP_DEBUG_ANY, "Size limit exceeded \n",
1213                                         0, 0, 0 );
1214 #endif /* !NEW_LOGGING */
1215                         send_search_result( lc->conn, op,
1216                                         LDAP_SIZELIMIT_EXCEEDED,
1217                                         NULL, NULL, NULL, NULL, num_entries );
1218                         result->type = RESULT_ERR; 
1219                         return 0; 
1220                 case ABANDON_ERR: 
1221 #ifdef NEW_LOGGING
1222                         LDAP_LOG( BACK_META, DETAIL1,
1223                                         "search operation abandoned \n",
1224                                         0, 0, 0 );
1225 #else /* !NEW_LOGGING */
1226                         Debug( LDAP_DEBUG_ANY, "search operation abandoned \n",
1227                                         0, 0, 0 );
1228 #endif /* !NEW_LOGGING */
1229                         result->type = RESULT_ERR; 
1230                         return 0; 
1231                 default:
1232                         /* assert( 0 ); */
1233                         break;
1234                 }
1235                 if ( gotit == 0 ) {
1236                         tv.tv_sec = 0;
1237                         tv.tv_usec = 100000;
1238                         ldap_pvt_thread_yield();
1239                 } else {
1240                         tv.tv_sec = 0;
1241                         tv.tv_usec = 0;
1242                 }
1243         }
1244
1245         send_search_result( lc->conn, op, mres, match, err,
1246                                 NULL, NULL, num_entries );
1247
1248         if (err) 
1249                 free(err); 
1250
1251         if (match) 
1252                 free(match); 
1253     
1254         result->type = (mres == LDAP_SUCCESS) ? SUCCESS : RESULT_ERR; 
1255         return num_entries; 
1256 }
1257
1258 static Entry* 
1259 get_result_entry(
1260         Backend* be, 
1261         struct metaconn* lc, 
1262         struct metasingleconn* lsc, 
1263         int* msgid,
1264         int i, 
1265         struct timeval* tv, 
1266         struct exception* result)
1267 {
1268         Entry* entry; 
1269         LDAPMessage     *res, *e; 
1270         int rc; 
1271         int sres = LDAP_SUCCESS; 
1272
1273         rc = ldap_result( lsc->ld, msgid[ i ],
1274                         0, tv, &res );
1275
1276         if ( rc == 0 ) {
1277                 result->type = TIMEOUT_ERR; 
1278                 return NULL; 
1279         } else if ( rc == -1 ) {
1280                 result->rc = -1; 
1281                 result->type = RESULT_ERR; 
1282                 return NULL; 
1283         } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1284                 e = ldap_first_entry( lsc->ld, res );
1285                 entry = meta_create_entry(be, lc, i, e, result);  
1286                 if (!entry) {
1287                         return NULL; 
1288                 }    
1289                 ldap_msgfree( res );
1290                 result->type = SUCCESS; 
1291                 return entry; 
1292         } else {
1293                 sres = ldap_result2error( lsc->ld,
1294                                 res, 1 );
1295                 result->rc = sres; 
1296                 result->type = RESULT_ERR; 
1297                 return NULL; 
1298         }
1299 }       
1300
1301 static void
1302 rewriteSession(
1303         struct rewrite_info* info, 
1304         const char* rewriteContext, 
1305         const char* string, 
1306         const void* cookie,  
1307         char** base, 
1308         struct exception* result)
1309 {
1310         int rc = rewrite_session(info, rewriteContext, string, cookie, base); 
1311         if (rc != REWRITE_REGEXEC_OK) {
1312                 result->rc = rc; 
1313                 result->type = REWRITING_ERR; 
1314
1315                 if (strcmp(rewriteContext, "searchBase") == 0) 
1316 #ifdef NEW_LOGGING
1317                         LDAP_LOG( BACK_META, DETAIL1,
1318                                 "Problem in rewriting search base\n", 0, 0, 0 );
1319 #else /* !NEW_LOGGING */
1320                         Debug( LDAP_DEBUG_ANY,
1321                                 "Problem in rewriting search base\n", 0, 0, 0 );
1322 #endif /* !NEW_LOGGING */
1323                 if (strcmp(rewriteContext, "searchFilter") == 0) 
1324 #ifdef NEW_LOGGING
1325                         LDAP_LOG( BACK_META, DETAIL1,
1326                                 "Problem in rewriting search filter\n",
1327                                 0, 0, 0 );
1328 #else /* !NEW_LOGGING */
1329                         Debug( LDAP_DEBUG_ANY,
1330                                 "Problem in rewriting search filter\n",
1331                                 0, 0, 0 );
1332 #endif /* !NEW_LOGGING */
1333                 if (strcmp(rewriteContext, "searchResult") == 0) 
1334 #ifdef NEW_LOGGING
1335                         LDAP_LOG( BACK_META, DETAIL1,
1336                                 "Problem in rewriting DN, or DN syntax "
1337                                 "attributes of search result\n", 0, 0, 0 );
1338 #else /* !NEW_LOGGING */
1339                         Debug( LDAP_DEBUG_ANY,
1340                                 "Problem in rewriting DN, or DN syntax "
1341                                 "attributes of search result\n", 0, 0, 0 );
1342 #endif /* !NEW_LOGGING */
1343                 if (strcmp(rewriteContext, "cacheBase") == 0) 
1344 #ifdef NEW_LOGGING
1345                         LDAP_LOG( BACK_META, DETAIL1,
1346                                 "Problem in rewriting search base with "
1347                                 "cache base\n", 0, 0, 0 );
1348 #else /* !NEW_LOGGING */
1349                         Debug( LDAP_DEBUG_ANY,
1350                                 "Problem in rewriting search base with "
1351                                 "cache base\n", 0, 0, 0 );
1352 #endif /* !NEW_LOGGING */
1353                 if (strcmp(rewriteContext, "cacheResult") == 0) 
1354 #ifdef NEW_LOGGING
1355                         LDAP_LOG( BACK_META, DETAIL1,
1356                                 "Problem in rewriting DN for cached entries\n",
1357                                 0, 0, 0 );
1358 #else /* !NEW_LOGGING */
1359                         Debug( LDAP_DEBUG_ANY,
1360                                 "Problem in rewriting DN for cached entries\n",
1361                                 0, 0, 0 );
1362 #endif /* !NEW_LOGGING */
1363                 if (strcmp(rewriteContext, "cacheReturn") == 0) 
1364 #ifdef NEW_LOGGING
1365                         LDAP_LOG( BACK_META, DETAIL1,
1366                                 "Problem in rewriting DN for answerable "
1367                                 "entries\n", 0, 0, 0 );
1368 #else /* !NEW_LOGGING */
1369                         Debug( LDAP_DEBUG_ANY,
1370                                 "Problem in rewriting DN for answerable "
1371                                 "entries\n", 0, 0, 0 );
1372 #endif /* !NEW_LOGGING */
1373         } else {
1374                 result->type = SUCCESS;
1375         }
1376 }
1377
1378 static int 
1379 get_attr_set(
1380         AttributeName* attrs, 
1381         query_manager* qm, 
1382         int num )
1383 {
1384         int i; 
1385         for (i=0; i<num; i++) {
1386                 if (attrscmp(attrs, qm->attr_sets[i].attrs)) 
1387                         return i;
1388         }
1389         return -1; 
1390 }
1391
1392 static int 
1393 attrscmp(
1394         AttributeName* attrs_in, 
1395         AttributeName* attrs)
1396 {
1397         int i, count1, count2; 
1398         if ((attrs_in==NULL) || (attrs==NULL)) 
1399                 return 1; 
1400         for ( count1=0;
1401               attrs_in && attrs_in[count1].an_name.bv_val != NULL;
1402               count1++ )
1403                 ;
1404         for ( count2=0;
1405               attrs && attrs[count2].an_name.bv_val != NULL;
1406               count2++) 
1407                 ;
1408         if ( count1 != count2 )
1409                 return 0; 
1410
1411         for ( i=0; i<count1; i++ ) {
1412                 if ( !an_find(attrs, &attrs_in[i].an_name ))
1413                         return 0; 
1414         }
1415         return 1; 
1416 }
1417
1418 static char* 
1419 cache_entries(
1420         Entry** entry_array, 
1421         cache_manager* cm, 
1422         Backend* be, 
1423         Connection* conn, 
1424         struct exception* result)
1425 {
1426         int i; 
1427         int return_val; 
1428         int cache_size; 
1429         Entry* e; 
1430         struct berval query_uuid; 
1431         struct berval crp_uuid; 
1432         char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ], *crpid; 
1433         char crpuuid[40]; 
1434         query_manager* qm = cm->qm;
1435     
1436         result->type = SUCCESS; 
1437         query_uuid.bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf)); 
1438         query_uuid.bv_val = ch_strdup(uuidbuf);
1439
1440 #ifdef NEW_LOGGING
1441         LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
1442                         uuidbuf, 0, 0 );
1443 #else /* !NEW_LOGGING */
1444         Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
1445                         uuidbuf, 0, 0 );
1446 #endif /* !NEW_LOGGING */
1447         
1448         for ( i=0; ( entry_array && (e=entry_array[i]) ); i++ ) {
1449 #ifdef NEW_LOGGING
1450                 LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
1451                                 0, 0, 0 );
1452 #else /* !NEW_LOGGING */
1453                 Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
1454 #endif /* !NEW_LOGGING */
1455                 ldap_pvt_thread_mutex_lock(&cm->remove_mutex); 
1456 #ifdef NEW_LOGGING
1457                 LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1458 #else /* !NEW_LOGGING */
1459                 Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1460 #endif /* !NEW_LOGGING */
1461                 if ( cm->cache_size > (cm->thresh_hi) ) {
1462                         while(cm->cache_size > (cm->thresh_lo)) {
1463                                 crpid = cache_replacement(qm);
1464                                 if (crpid == NULL) {
1465                                         result->type = REMOVE_ERR; 
1466                                 } else {
1467                                         strcpy(crpuuid, crpid); 
1468                                         crp_uuid.bv_val = crpuuid; 
1469                                         crp_uuid.bv_len = strlen(crpuuid); 
1470 #ifdef NEW_LOGGING
1471                                         LDAP_LOG( BACK_META, DETAIL1,
1472                                                 "Removing query UUID %s\n",
1473                                                 crpuuid, 0, 0 );
1474 #else /* !NEW_LOGGING */
1475                                         Debug( LDAP_DEBUG_ANY,
1476                                                 "Removing query UUID %s\n",
1477                                                 crpuuid, 0, 0 );
1478 #endif /* !NEW_LOGGING */
1479                                         return_val = remove_query_data(be, conn,
1480                                                         &crp_uuid, result); 
1481 #ifdef NEW_LOGGING
1482                                         LDAP_LOG( BACK_META, DETAIL1,
1483                                                 "QUERY REMOVED, SIZE=%d\n",
1484                                                 return_val, 0, 0);
1485 #else /* !NEW_LOGGING */
1486                                         Debug( LDAP_DEBUG_ANY,
1487                                                 "QUERY REMOVED, SIZE=%d\n",
1488                                                 return_val, 0, 0);
1489 #endif /* !NEW_LOGGING */
1490                                         ldap_pvt_thread_mutex_lock(
1491                                                         &cm->cache_mutex ); 
1492                                         cm->total_entries -= result->rc; 
1493                                         cm->num_cached_queries--; 
1494 #ifdef NEW_LOGGING
1495                                         LDAP_LOG( BACK_META, DETAIL1,
1496                                                 "STORED QUERIES = %lu\n",
1497                                                 cm->num_cached_queries, 0, 0 );
1498 #else /* !NEW_LOGGING */
1499                                         Debug( LDAP_DEBUG_ANY,
1500                                                 "STORED QUERIES = %lu\n",
1501                                                 cm->num_cached_queries, 0, 0 );
1502 #endif /* !NEW_LOGGING */
1503                                         ldap_pvt_thread_mutex_unlock(
1504                                                         &cm->cache_mutex );
1505                                         cm->cache_size = (return_val >
1506                                                 cm->cache_size) ?
1507                                                 0 : (cm->cache_size-return_val);
1508 #ifdef NEW_LOGGING
1509                                         LDAP_LOG( BACK_META, DETAIL1,
1510                                                 "QUERY REMOVED, CACHE SIZE="
1511                                                 "%lu bytes %d entries\n",
1512                                                 cm->cache_size,
1513                                                 cm->total_entries, 0 );
1514 #else /* !NEW_LOGGING */
1515                                         Debug( LDAP_DEBUG_ANY,
1516                                                 "QUERY REMOVED, CACHE SIZE="
1517                                                 "%lu bytes %d entries\n",
1518                                                 cm->cache_size,
1519                                                 cm->total_entries, 0 );
1520 #endif /* !NEW_LOGGING */
1521                                 }
1522                         }
1523                 }
1524                 return_val = merge_entry(be, conn, e, &query_uuid, result);
1525                 cm->cache_size += return_val;
1526 #ifdef NEW_LOGGING
1527                 LDAP_LOG( BACK_META, DETAIL1,
1528                         "ENTRY ADDED/MERGED, CACHE SIZE=%lu bytes\n",
1529                         cm->cache_size, 0, 0 );
1530 #else /* !NEW_LOGGING */
1531                 Debug( LDAP_DEBUG_ANY,
1532                         "ENTRY ADDED/MERGED, CACHE SIZE=%lu bytes\n",
1533                         cm->cache_size, 0, 0 );
1534 #endif /* !NEW_LOGGING */
1535 #ifdef NEW_LOGGING
1536                 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKING REMOVE MUTEX\n",
1537                                 0, 0, 0 );
1538 #else /* !NEW_LOGGING */
1539                 Debug( LDAP_DEBUG_NONE, "UNLOCKING REMOVE MUTEX\n", 0, 0, 0 );
1540 #endif /* !NEW_LOGGING */
1541                 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex); 
1542 #ifdef NEW_LOGGING
1543                 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKED REMOVE MUTEX\n",
1544                                 0, 0, 0 );
1545 #else /* !NEW_LOGGING */
1546                 Debug( LDAP_DEBUG_NONE, "UNLOCKED REMOVE MUTEX\n", 0, 0, 0 );
1547 #endif /* !NEW_LOGGING */
1548                 if (result->type != SUCCESS) 
1549                         return 0; 
1550                 ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1551                 cm->total_entries += result->rc; 
1552 #ifdef NEW_LOGGING
1553                 LDAP_LOG( BACK_META, DETAIL1,
1554                         "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1555                         return_val, cm->total_entries, 0 );
1556 #else /* !NEW_LOGGING */
1557                 Debug( LDAP_DEBUG_ANY,
1558                         "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1559                         return_val, cm->total_entries, 0 );
1560 #endif /* !NEW_LOGGING */
1561                 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1562         }
1563         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1564         cm->num_cached_queries++; 
1565 #ifdef NEW_LOGGING
1566         LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
1567                         cm->num_cached_queries, 0, 0 );
1568 #else /* !NEW_LOGGING */
1569         Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
1570                         cm->num_cached_queries, 0, 0 );
1571 #endif /* !NEW_LOGGING */
1572         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1573
1574         return query_uuid.bv_val; 
1575 }
1576
1577 static int 
1578 is_temp_answerable(
1579         int attr_set, 
1580         struct berval* tempstr, 
1581         query_manager* qm, 
1582         int template_id )
1583 {
1584         int i; 
1585         int* id_array; 
1586         char* str;
1587         int result = 0; 
1588         i = qm->templates[template_id].attr_set_index; 
1589         str = qm->templates[template_id].querystr; 
1590
1591         if (attr_set == i) {
1592                 result = 1; 
1593         } else { 
1594                 id_array = qm->attr_sets[attr_set].ID_array;    
1595
1596                 while (*id_array != -1) {
1597                         if (*id_array == i) 
1598                                 result = 1; 
1599                         id_array++; 
1600                 }
1601         }
1602         if (!result) 
1603                 return 0; 
1604         if (strcasecmp(str, tempstr->bv_val) == 0)  
1605                 return 1; 
1606         return 0; 
1607 }
1608
1609 static void 
1610 consistency_check(Backend* be, Backend* glue_be, Connection* conn)
1611 {
1612         struct metainfo *li = ( struct metainfo * )be->be_private;
1613         cache_manager*  cm = li->cm; 
1614         query_manager* qm = cm->qm; 
1615         CachedQuery* query, *query_prev; 
1616         time_t curr_time; 
1617         struct berval uuid;  
1618         struct exception result; 
1619         int i, return_val; 
1620         QueryTemplate* templ; 
1621     
1622       
1623         for (i=0; qm->templates[i].querystr; i++) {
1624                 templ = qm->templates + i; 
1625                 query = templ->query_last; 
1626                 curr_time = slap_get_time(); 
1627                 ldap_pvt_thread_mutex_lock(&cm->remove_mutex); 
1628                 while (query && (query->expiry_time < curr_time)) {
1629                         ldap_pvt_thread_mutex_lock(&qm->lru_mutex); 
1630                         remove_query(qm, query); 
1631                         ldap_pvt_thread_mutex_unlock(&qm->lru_mutex); 
1632 #ifdef NEW_LOGGING
1633                         LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
1634                                         i, 0, 0 );
1635 #else /* !NEW_LOGGING */
1636                         Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
1637                                         i, 0, 0 );
1638 #endif /* !NEW_LOGGING */
1639                         ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);  
1640                         remove_from_template(query, templ); 
1641 #ifdef NEW_LOGGING
1642                         LDAP_LOG( BACK_META, DETAIL1,
1643                                         "TEMPLATE %d QUERIES-- %d\n",
1644                                         i, templ->no_of_queries, 0 );
1645 #else /* !NEW_LOGGING */
1646                         Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
1647                                         i, templ->no_of_queries, 0 );
1648 #endif /* !NEW_LOGGING */
1649 #ifdef NEW_LOGGING
1650                         LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
1651                                         i, 0, 0 );
1652 #else /* !NEW_LOGGING */
1653                         Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
1654                                         i, 0, 0 );
1655 #endif /* !NEW_LOGGING */
1656                         ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);  
1657                         uuid.bv_val = query->q_uuid; 
1658                         uuid.bv_len = strlen(query->q_uuid); 
1659                         return_val = remove_query_data(glue_be, conn,
1660                                                 &uuid, &result); 
1661 #ifdef NEW_LOGGING
1662                         LDAP_LOG( BACK_META, DETAIL1,
1663                                         "STALE QUERY REMOVED, SIZE=%d\n",
1664                                         return_val, 0, 0 );
1665 #else /* !NEW_LOGGING */
1666                         Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
1667                                                 return_val, 0, 0 );
1668 #endif /* !NEW_LOGGING */
1669                         ldap_pvt_thread_mutex_lock(&cm->cache_mutex); 
1670                         cm->total_entries -= result.rc; 
1671                         cm->num_cached_queries--; 
1672 #ifdef NEW_LOGGING
1673                         LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
1674                                         cm->num_cached_queries, 0, 0 );
1675 #else /* !NEW_LOGGING */
1676                         Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
1677                                         cm->num_cached_queries, 0, 0 );
1678 #endif /* !NEW_LOGGING */
1679                         ldap_pvt_thread_mutex_unlock(&cm->cache_mutex); 
1680                         cm->cache_size = (return_val > cm->cache_size) ?
1681                                                 0: (cm->cache_size-return_val);
1682 #ifdef NEW_LOGGING
1683                         LDAP_LOG( BACK_META, DETAIL1,
1684                                 "STALE QUERY REMOVED, CACHE SIZE=%lu bytes %d "
1685                                 "entries\n", cm->cache_size,
1686                                 cm->total_entries, 0 );
1687 #else /* !NEW_LOGGING */
1688                         Debug( LDAP_DEBUG_ANY,
1689                                 "STALE QUERY REMOVED, CACHE SIZE=%lu bytes %d "
1690                                 "entries\n", cm->cache_size,
1691                                 cm->total_entries, 0 );
1692 #endif /* !NEW_LOGGING */
1693                         query_prev = query; 
1694                         query = query->prev; 
1695                         free_query(query_prev); 
1696                 }
1697                 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex); 
1698         }
1699 }
1700
1701 static int
1702 cache_back_sentry(
1703         Backend* glue_be, 
1704         Connection* conn,
1705         Operation* op, 
1706         Entry* e, 
1707         AttributeName* attrs, 
1708         int attrsonly, 
1709         LDAPControl** ctrls )
1710
1711         slap_callback* cb = op->o_callback; 
1712         Backend* be = (Backend*)(cb->sc_private); 
1713         struct metainfo *li = ( struct metainfo * )be->be_private;
1714  
1715         char* ename = NULL; 
1716         struct exception result; 
1717         struct berval dn; 
1718         struct berval ndn; 
1719
1720         dn = e->e_name; 
1721         ndn = e->e_nname; 
1722
1723         rewriteSession( li->rwinfo,
1724                 "cacheReturn", e->e_name.bv_val, conn, &ename, &result );  
1725         ber_str2bv(ename, strlen(ename), 0, &e->e_name); 
1726         ber_dupbv(&e->e_nname, &e->e_name); 
1727
1728         op->o_callback = NULL; 
1729         send_search_entry(be, conn, op, e, attrs, attrsonly, ctrls); 
1730  
1731         e->e_name = dn; 
1732         e->e_nname = ndn; 
1733
1734         op->o_callback = cb; 
1735         return 0;  
1736 }
1737 #endif