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