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