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