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