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