2 * Copyright (c) 2003 by International Business Machines, Inc.
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
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.
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
25 * The original copyright statements follow.
26 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
27 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
29 * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
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.
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:
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
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.
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
54 * 4. This notice may not be removed or altered.
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.
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.
67 * The original copyright statement follows.
69 * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
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:
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.
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.
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
87 * 4. This notice may not be removed or altered.
94 #include <ac/socket.h>
95 #include <ac/string.h>
100 #include "../back-ldap/back-ldap.h"
101 #include "back-meta.h"
102 #include "ldap_pvt.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 #include <sys/time.h>
115 struct exception* result
124 static struct metaconn*
130 struct berval* nbase,
131 struct exception* result
136 AttributeName** newattrs,
137 AttributeName* attrs,
138 AttributeName* filter_attrs
145 int* msgid, Backend* be,
146 AttributeName* attrs,
150 Entry*** entry_array,
153 struct exception* result
160 struct metasingleconn* lsc,
164 struct exception* result
169 struct rewrite_info* info,
170 const char* rewriteContext,
174 struct exception* result
179 AttributeName* attrs,
186 AttributeName* attrs_in,
196 struct exception* result
202 struct berval* tempstr,
220 AttributeName* attrs,
226 meta_back_cache_search(
231 struct berval *nbase,
237 struct berval *filterstr,
238 AttributeName *attributes,
242 struct metainfo *li = ( struct metainfo * )be->be_private;
244 struct metasingleconn *lsc;
245 cache_manager* cm = li->cm;
246 query_manager* qm = cm->qm;
250 int count, rc = 0, *msgid = NULL;
255 int i = -1, last = 0, candidates = 0, op_type;
257 struct berval mfilter;
258 struct berval *cachebase = NULL;
259 struct berval *ncachebase = NULL;
260 struct berval cache_suffix;
261 struct berval tempstr = {0, 0};
263 AttributeName *filter_attrs = NULL;
264 AttributeName *new_attrs = NULL;
265 AttributeName *attrs = NULL;
268 Entry **entry_array = NULL;
273 int template_id = -1;
281 struct exception result[1];
283 Filter* filter = str2filter(filterstr->bv_val);
284 slap_callback cb = {NULL, NULL, cache_back_sentry, NULL};
289 for ( count=0; attributes[ count ].an_name.bv_val; count++ )
291 attrs = (AttributeName*)malloc( ( count + 1 ) *
292 sizeof(AttributeName));
293 for ( count=0; attributes[ count ].an_name.bv_val; count++ ) {
294 ber_dupbv(&attrs[ count ].an_name,
295 &attributes[ count ].an_name);
296 attrs[count].an_desc = attributes[count].an_desc;
298 attrs[ count ].an_name.bv_val = NULL;
299 attrs[ count ].an_name.bv_len = 0;
302 result->type = SUCCESS;
304 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
307 LDAP_LOG( BACK_META, DETAIL1, "Threads++ = %d\n", cm->threads, 0, 0 );
308 #else /* !NEW_LOGGING */
309 Debug( LDAP_DEBUG_ANY, "Threads++ = %d\n", cm->threads, 0, 0 );
310 #endif /* !NEW_LOGGING */
311 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
313 filter2template(filter, &tempstr, &filter_attrs, &fattr_cnt, result);
314 if (result->type != SUCCESS)
318 LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
319 tempstr.bv_val, 0, 0 );
320 #else /* !NEW_LOGGING */
321 Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
322 tempstr.bv_val, 0, 0 );
323 #endif /* !NEW_LOGGING */
324 curr_limit = cm->num_entries_limit ;
327 attr_set = get_attr_set(attrs, qm, cm->numattrsets);
329 query.filter = filter;
334 /* check for query containment */
336 for (i=0; i<cm->numtemplates; i++) {
337 /* find if template i can potentially answer tempstr */
338 if (!is_temp_answerable(attr_set, &tempstr, qm, i))
340 if (attr_set == qm->templates[i].attr_set_index) {
345 LDAP_LOG( BACK_META, DETAIL2,
346 "Entering QC, querystr = %s\n",
347 filterstr->bv_val, 0, 0 );
348 #else /* !NEW_LOGGING */
349 Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
350 filterstr->bv_val, 0, 0 );
351 #endif /* !NEW_LOGGING */
352 answerable = (*(qm->qcfunc))(qm, &query, i);
361 LDAP_LOG( BACK_META, DETAIL1, "QUERY ANSWERABLE\n", 0, 0, 0 );
362 #else /* !NEW_LOGGING */
363 Debug( LDAP_DEBUG_ANY, "QUERY ANSWERABLE\n", 0, 0, 0 );
364 #endif /* !NEW_LOGGING */
365 rewriteSession(li->rwinfo, "cacheBase", nbase->bv_val,
366 conn, &cbase, result);
367 if (result->type != SUCCESS) {
368 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
371 cachebase = ber_str2bv(cbase, strlen(cbase), 0, NULL);
372 dnNormalize(NULL, cachebase, &ncachebase);
374 op->o_caching_on = 1;
375 op->o_callback = &cb;
376 li->glue_be->be_search(li->glue_be, conn, op, cachebase,
377 ncachebase, scope, deref, slimit, tlimit,
378 filter, filterstr, attrs, attrsonly);
380 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
383 LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
385 #else /* !NEW_LOGGING */
386 Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
387 #endif /* !NEW_LOGGING */
389 if ( scope == LDAP_SCOPE_BASE ) {
390 op_type = META_OP_REQUIRE_SINGLE;
392 op_type = META_OP_ALLOW_MULTIPLE;
395 lc = metaConnect(li, conn, op, op_type, nbase, result);
397 if (result->type != SUCCESS)
400 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
401 if (cm->num_cached_queries >= cm->max_queries) {
404 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
408 LDAP_LOG( BACK_META, DETAIL1,
409 "QUERY TEMPLATE CACHEABLE\n",
411 #else /* !NEW_LOGGING */
412 Debug( LDAP_DEBUG_ANY, "QUERY TEMPLATE CACHEABLE\n",
414 #endif /* !NEW_LOGGING */
415 add_filter_attrs(&new_attrs, attrs, filter_attrs);
423 * Array of message id of each target
425 msgid = ch_calloc( sizeof( int ), li->ntargets );
426 if ( msgid == NULL ) {
427 result->type = CONN_ERR;
432 if (slimit > 0 && (slimit <= cm->num_entries_limit))
433 slimit = cm->num_entries_limit;
440 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
441 char *realbase = ( char * )base->bv_val;
442 int realscope = scope;
444 char *mapped_filter, **mapped_attrs;
446 /* FIXME: Check for more than one targets */
447 if ( meta_back_is_candidate(
448 &li->targets[i]->suffix, nbase ))
449 lsc->candidate = META_CANDIDATE;
451 if ( lsc->candidate != META_CANDIDATE )
455 ldap_set_option( lsc->ld, LDAP_OPT_DEREF,
458 if ( tlimit != -1 ) {
459 ldap_set_option( lsc->ld, LDAP_OPT_TIMELIMIT,
462 if ( slimit != -1 ) {
463 ldap_set_option( lsc->ld, LDAP_OPT_SIZELIMIT,
468 * modifies the base according to the scope, if required
470 suffixlen = li->targets[ i ]->suffix.bv_len;
471 if ( suffixlen > nbase->bv_len ) {
473 case LDAP_SCOPE_SUBTREE:
475 * make the target suffix the new base
476 * FIXME: this is very forgiving,
477 * because illegal bases may be turned
478 * into the suffix of the target.
481 &li->targets[ i ]->suffix,
484 li->targets[i]->suffix.bv_val;
487 * this target is no longer
496 case LDAP_SCOPE_ONELEVEL:
497 if ( is_one_level_rdn(
498 li->targets[ i ]->suffix.bv_val,
499 suffixlen - nbase->bv_len - 1 )
501 &li->targets[ i ]->suffix,
504 * if there is exactly one
505 * level, make the target suffix
506 * the new base, and make scope
510 li->targets[i]->suffix.bv_val;
511 realscope = LDAP_SCOPE_BASE;
513 } /* else continue with the next case */
514 case LDAP_SCOPE_BASE:
516 * this target is no longer candidate
518 lsc->candidate = META_NOT_CANDIDATE;
524 * Rewrite the search base, if required
527 rewriteSession(li->targets[i]->rwinfo, "searchBase",
528 realbase, conn, &mbase, result);
530 if (result->type != SUCCESS)
533 if ( mbase == NULL ) {
538 * Rewrite the search filter, if required
540 rewriteSession( li->targets[i]->rwinfo, "searchFilter",
541 filterstr->bv_val, conn,
542 &mfilter.bv_val, result);
543 if (result->type != SUCCESS)
546 if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ]
548 mfilter.bv_len = strlen( mfilter.bv_val );
550 if ( mfilter.bv_val != NULL ) {
551 free( mfilter.bv_val );
553 mfilter = *filterstr;
557 * Maps attributes in filter
559 mapped_filter = ldap_back_map_filter(
560 &li->targets[i]->at_map,
561 &li->targets[i]->oc_map, &mfilter, 0 );
562 if ( mapped_filter == NULL ) {
563 mapped_filter = ( char * )mfilter.bv_val;
565 if ( mfilter.bv_val != filterstr->bv_val ) {
566 free( mfilter.bv_val );
569 mfilter.bv_val = NULL;
573 * Maps required attributes
575 mapped_attrs = ldap_back_map_attrs(
576 &li->targets[ i ]->at_map,
578 if ( mapped_attrs == NULL && new_attrs) {
580 new_attrs[ count ].an_name.bv_val;
583 mapped_attrs = ch_malloc( ( count + 1 ) *
586 new_attrs[ count ].an_name.bv_val;
588 mapped_attrs[ count ] =
589 new_attrs[count].an_name.bv_val;
591 mapped_attrs[ count ] = NULL;
597 msgid[ i ] = ldap_search( lsc->ld, mbase, realscope,
598 mapped_filter, mapped_attrs,
600 if ( msgid[ i ] == -1 ) {
601 lsc->candidate = META_NOT_CANDIDATE;
605 if ( mapped_attrs ) {
606 free( mapped_attrs );
610 if ( mapped_filter != filterstr->bv_val ) {
611 free( mapped_filter );
612 mapped_filter = NULL;
615 if ( mbase != realbase ) {
623 num_entries = handleLdapResult(lc, op, msgid, be, attrs,
624 attrsonly, candidates, cacheable, &entry_array,
625 curr_limit, slimit, result);
627 if (result->type != SUCCESS)
629 if (cacheable && (num_entries <= curr_limit)) {
631 LDAP_LOG( BACK_META, DETAIL1,
632 "QUERY CACHEABLE\n", 0, 0, 0 );
633 #else /* !NEW_LOGGING */
634 Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
635 #endif /* !NEW_LOGGING */
636 uuid = cache_entries(entry_array, cm, li->glue_be,
639 LDAP_LOG( BACK_META, DETAIL1,
640 "Added query %s UUID %s ENTRIES %d\n",
641 filterstr->bv_val, uuid, num_entries );
642 #else /* !NEW_LOGGING */
643 Debug( LDAP_DEBUG_ANY,
644 "Added query %s UUID %s ENTRIES %d\n",
645 filterstr->bv_val, uuid, num_entries );
646 #endif /* !NEW_LOGGING */
648 if (result->type != SUCCESS)
650 (*(qm->addfunc))(qm, &query, template_id, uuid, result);
651 if (result->type != SUCCESS)
659 switch (result->type) {
665 LDAP_LOG( BACK_META, DETAIL1,
666 "Invalid template error\n", 0, 0, 0 );
667 #else /* !NEW_LOGGING */
668 Debug( LDAP_DEBUG_ANY, "Invalid template error\n",
670 #endif /* !NEW_LOGGING */
675 LDAP_LOG( BACK_META, DETAIL1,
676 "Could not connect to a remote server\n",
678 #else /* !NEW_LOGGING */
679 Debug( LDAP_DEBUG_ANY,
680 "Could not connect to a remote server\n",
682 #endif /* !NEW_LOGGING */
683 send_ldap_result(conn, op, LDAP_OTHER,
684 NULL, "Connection error",
690 LDAP_LOG( BACK_META, DETAIL1,
691 "Error in handling ldap_result\n", 0, 0, 0 );
692 #else /* !NEW_LOGGING */
693 Debug( LDAP_DEBUG_ANY,
694 "Error in handling ldap_result\n", 0, 0, 0 );
695 #endif /* !NEW_LOGGING */
699 if (result->rc == REWRITE_REGEXEC_UNWILLING) {
700 send_ldap_result( conn, op,
701 LDAP_UNWILLING_TO_PERFORM,
702 NULL, "Unwilling to perform",
705 send_ldap_result( conn, op, LDAP_OTHER,
706 NULL, "Rewrite error",
713 LDAP_LOG( BACK_META, DETAIL1,
714 "Error in merging entry \n", 0, 0, 0 );
715 #else /* !NEW_LOGGING */
716 Debug( LDAP_DEBUG_ANY,
717 "Error in merging entry \n", 0, 0, 0 );
718 #endif /* !NEW_LOGGING */
723 LDAP_LOG( BACK_META, DETAIL1,
724 "Error in removing query \n",
726 #else /* !NEW_LOGGING */
727 Debug( LDAP_DEBUG_ANY, "Error in removing query \n",
729 #endif /* !NEW_LOGGING */
735 ldap_pvt_thread_mutex_lock(&cm->consistency_mutex);
736 curr_time = slap_get_time();
737 if (curr_time - cm->consistency_time > cm->consistency_cycle_time) {
738 cm->consistency_time = curr_time;
739 consistency_check(be, li->glue_be, conn);
741 ldap_pvt_thread_mutex_unlock(&cm->consistency_mutex);
747 for (i=0; (e = entry_array[i]); i++) {
756 if (new_attrs != attrs)
763 if (tempstr.bv_val ) {
764 free(tempstr.bv_val);
766 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
769 LDAP_LOG( BACK_META, DETAIL1, "Threads-- = %d\n", cm->threads, 0, 0 );
770 #else /* !NEW_LOGGING */
771 Debug( LDAP_DEBUG_ANY, "Threads-- = %d\n", cm->threads, 0, 0 );
772 #endif /* !NEW_LOGGING */
773 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
784 struct exception* result
787 struct metainfo *li = ( struct metainfo * )be->be_private;
788 struct berval a, mapped;
790 BerElement ber = *e->lm_ber;
791 Attribute *attr, **attrp;
792 struct berval dummy = { 0, NULL };
793 struct berval *bv, bdn;
796 if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
797 result->type = CREATE_ENTRY_ERR;
800 ent = (Entry*)malloc(sizeof(Entry));
803 * Rewrite the dn of the result, if needed
805 rewriteSession( li->targets[ target ]->rwinfo, "searchResult",
806 bdn.bv_val, lc->conn, &ent->e_name.bv_val, result );
808 if (result->type != SUCCESS) {
811 if ( ent->e_name.bv_val == NULL ) {
812 ber_dupbv(&(ent->e_name), &bdn);
815 LDAP_LOG( BACK_META, DETAIL1,
816 "[rw] searchResult[%d]: \"%s\" -> \"%s\"\n",
817 target, bdn.bv_val, ent->e_name.bv_val );
818 #else /* !NEW_LOGGING */
819 Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
821 target, bdn.bv_val, ent->e_name.bv_val );
822 #endif /* !NEW_LOGGING */
823 ent->e_name.bv_len = strlen( ent->e_name.bv_val );
827 * Note: this may fail if the target host(s) schema differs
828 * from the one known to the meta, and a DN with unknown
829 * attributes is returned.
831 * FIXME: should we log anything, or delegate to dnNormalize2?
833 dnNormalize2( NULL, &ent->e_name, &ent->e_nname );
836 if ( dnNormalize2( NULL, &ent->e_name, &ent->e_nname ) != LDAP_SUCCESS ) {
837 return LDAP_INVALID_DN_SYNTAX;
844 if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
845 meta_dncache_update_entry( &li->cache, &ent->e_nname, target );
851 ent->e_bv.bv_val = 0;
853 attrp = &ent->e_attrs;
855 while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
856 ldap_back_map( &li->targets[ target ]->at_map, &a, &mapped, 1 );
857 if ( mapped.bv_val == NULL ) {
860 attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
861 if ( attr == NULL ) {
867 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) {
868 if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text )
871 LDAP_LOG( BACK_META, DETAIL1,
872 "slap_bv2undef_ad(%s): %s\n",
873 mapped.bv_val, text, 0 );
874 #else /* !NEW_LOGGING */
875 Debug( LDAP_DEBUG_ANY,
876 "slap_bv2undef_ad(%s): "
877 "%s\n%s", mapped.bv_val, text, "" );
878 #endif /* !NEW_LOGGING */
884 /* no subschemaSubentry */
885 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
890 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
891 || attr->a_vals == NULL ) {
892 attr->a_vals = &dummy;
893 } else if ( attr->a_desc == slap_schema.si_ad_objectClass ||
895 slap_schema.si_ad_structuralObjectClass) {
897 for ( last = 0; attr->a_vals[ last ].bv_val; ++last )
899 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
900 ldap_back_map( &li->targets[ target]->oc_map,
902 if ( mapped.bv_val == NULL ) {
908 *bv = attr->a_vals[ last ];
909 attr->a_vals[ last ].bv_val = NULL;
911 } else if ( mapped.bv_val != bv->bv_val ) {
913 ber_dupbv( bv, &mapped );
917 * It is necessary to try to rewrite attributes with
918 * dn syntax because they might be used in ACLs as
919 * members of groups; since ACLs are applied to the
920 * rewritten stuff, no dn-based subecj clause could
921 * be used at the ldap backend side (see
922 * http://www.OpenLDAP.org/faq/data/cache/452.html)
923 * The problem can be overcome by moving the dn-based
924 * ACLs to the target directory server, and letting
925 * everything pass thru the ldap backend.
927 } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
928 SLAPD_DN_SYNTAX ) == 0 ) {
930 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
932 rewriteSession(li->targets[ target ]->rwinfo,
933 "searchResult", bv->bv_val,
934 lc->conn, &newval, result);
935 if (result->type != SUCCESS) {
936 /* FIXME : Handle error */
937 result->type = SUCCESS;
940 if ( newval == NULL ) {
944 LDAP_LOG( BACK_META, DETAIL1,
945 "[rw] searchResult on "
946 "attr=%s: \"%s\" -> \"%s\"\n",
947 attr->a_desc->ad_type->
949 bv->bv_val, newval );
950 #else /* !NEW_LOGGING */
951 Debug( LDAP_DEBUG_ARGS,
952 "rw> searchResult on attr=%s:"
953 " \"%s\" -> \"%s\"\n",
954 attr->a_desc->ad_type->
956 bv->bv_val, newval );
957 #endif /* !NEW_LOGGING */
960 bv->bv_len = strlen( newval );
965 attrp = &attr->a_next;
977 if ( DN_SEPARATOR( rdn[ from ] ) ) {
984 static struct metaconn*
990 struct berval* nbase,
991 struct exception* result)
994 result->type = SUCCESS;
995 lc = meta_back_getconn( li, conn, op, op_type, nbase, NULL );
997 result->type = CONN_ERR;
1005 AttributeName** new_attrs,
1006 AttributeName* attrs,
1007 AttributeName* filter_attrs )
1009 struct berval all_user = { sizeof(LDAP_ALL_USER_ATTRIBUTES) -1,
1010 LDAP_ALL_USER_ATTRIBUTES };
1012 struct berval all_op = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES) -1,
1013 LDAP_ALL_OPERATIONAL_ATTRIBUTES};
1020 /* duplicate attrs */
1021 for (count=0; attrs[count].an_name.bv_val; count++)
1023 *new_attrs = (AttributeName*)(malloc((count+1)*sizeof(AttributeName)));
1024 for (i=0; i<count; i++) {
1026 ber_dupbv(&((*new_attrs)[i].an_name), &(attrs[i].an_name));
1028 (*new_attrs)[i].an_name = attrs[i].an_name;
1029 (*new_attrs)[i].an_desc = attrs[i].an_desc;
1031 (*new_attrs)[count].an_name.bv_val = NULL;
1032 (*new_attrs)[count].an_name.bv_len = 0;
1035 if ((*new_attrs)[0].an_name.bv_val == NULL) {
1036 *new_attrs = (AttributeName*)(malloc(2*sizeof(AttributeName)));
1037 (*new_attrs)[0].an_name.bv_val = "*";
1038 (*new_attrs)[0].an_name.bv_len = 1;
1039 (*new_attrs)[1].an_name.bv_val = NULL;
1040 (*new_attrs)[1].an_name.bv_len = 0;
1044 alluser = an_find(*new_attrs, &all_user);
1045 allop = an_find(*new_attrs, &all_op);
1048 for ( i=0; filter_attrs[i].an_name.bv_val; i++ ) {
1049 if ( an_find(*new_attrs, &filter_attrs[i].an_name ))
1051 if ( is_at_operational(filter_attrs[i].an_desc->ad_type)
1056 *new_attrs = (AttributeName*)(realloc(*new_attrs,
1057 (count+2)*sizeof(AttributeName)));
1058 (*new_attrs)[count].an_name.bv_val =
1059 filter_attrs[i].an_name.bv_val;
1060 (*new_attrs)[count].an_name.bv_len =
1061 filter_attrs[i].an_name.bv_len;
1062 (*new_attrs)[count].an_desc = filter_attrs[i].an_desc;
1063 (*new_attrs)[count+1].an_name.bv_val = NULL;
1064 (*new_attrs)[count+1].an_name.bv_len = 0;
1071 struct metaconn* lc,
1073 int* msgid, Backend* be,
1074 AttributeName* attrs,
1078 Entry*** entry_array,
1081 struct exception* result)
1084 char *match = NULL, *err = NULL, *cache_ename = NULL;
1086 int mres = LDAP_SUCCESS;
1087 int num_entries = 0, count, i, rc;
1088 struct timeval tv = {0, 0};
1089 struct metasingleconn* lsc;
1090 struct metainfo *li = ( struct metainfo * )be->be_private;
1092 result->type = SUCCESS;
1094 for ( count = 0, rc = 0; candidates > 0; ) {
1097 /* check for abandon */
1100 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
1101 if ( lsc->candidate != META_CANDIDATE ) {
1106 ldap_abandon( lsc->ld, msgid[ i ] );
1107 result->type = ABANDON_ERR;
1111 if ( slimit > 0 && num_entries == slimit ) {
1112 result->type = SLIMIT_ERR;
1116 if ((entry = get_result_entry(be, lc, lsc,
1117 msgid, i, &tv, result))) {
1118 send_search_entry( be, lc->conn, op, entry,
1119 attrs, attrsonly, NULL );
1121 (num_entries < curr_limit)) {
1122 rewriteSession( li->rwinfo,
1124 entry->e_name.bv_val,
1126 &cache_ename, result );
1127 free(entry->e_name.bv_val);
1128 if (result->type != SUCCESS) {
1131 ber_str2bv(cache_ename,
1132 strlen(cache_ename),
1134 ber_dupbv(&entry->e_nname,
1136 *entry_array = (Entry**)realloc(
1138 (( num_entries+2 ) *
1140 (*entry_array)[num_entries] = entry;
1141 (*entry_array)[num_entries+1] = NULL;
1145 } else if (result->type == REWRITING_ERR) {
1147 } else if (result->type == TIMEOUT_ERR) {
1148 result->type = SUCCESS;
1150 } else if (result->type == CREATE_ENTRY_ERR) {
1152 } else if (result->rc == -1) {
1155 sres = ldap_back_map_result(result->rc);
1156 if (mres == LDAP_SUCCESS &&
1157 sres != LDAP_SUCCESS) {
1159 ldap_get_option(lsc->ld,
1160 LDAP_OPT_ERROR_STRING, &err);
1161 ldap_get_option(lsc->ld,
1162 LDAP_OPT_MATCHED_DN, &match);
1164 lsc->candidate = META_NOT_CANDIDATE;
1166 result->type = SUCCESS;
1169 switch (result->type) {
1172 LDAP_LOG( BACK_META, DETAIL1,
1173 "ldap_result error, rc = -1\n",
1175 #else /* !NEW_LOGGING */
1176 Debug( LDAP_DEBUG_ANY, "ldap_result error, rc = -1\n",
1178 #endif /* !NEW_LOGGING */
1179 send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1180 NULL, NULL, NULL, num_entries );
1182 case CREATE_ENTRY_ERR:
1184 LDAP_LOG( BACK_META, DETAIL1,
1185 "Error in parsing result \n",
1187 #else /* !NEW_LOGGING */
1188 Debug( LDAP_DEBUG_ANY, "Error in parsing result \n",
1190 #endif /* !NEW_LOGGING */
1191 send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1192 NULL, NULL, NULL, num_entries );
1193 result->type = RESULT_ERR;
1197 LDAP_LOG( BACK_META, DETAIL1, "Size limit exceeded \n",
1199 #else /* !NEW_LOGGING */
1200 Debug( LDAP_DEBUG_ANY, "Size limit exceeded \n",
1202 #endif /* !NEW_LOGGING */
1203 send_search_result( lc->conn, op,
1204 LDAP_SIZELIMIT_EXCEEDED,
1205 NULL, NULL, NULL, NULL, num_entries );
1206 result->type = RESULT_ERR;
1210 LDAP_LOG( BACK_META, DETAIL1,
1211 "search operation abandoned \n",
1213 #else /* !NEW_LOGGING */
1214 Debug( LDAP_DEBUG_ANY, "search operation abandoned \n",
1216 #endif /* !NEW_LOGGING */
1217 result->type = RESULT_ERR;
1224 tv.tv_usec = 100000;
1225 ldap_pvt_thread_yield();
1232 send_search_result( lc->conn, op, mres, match, err,
1233 NULL, NULL, num_entries );
1241 result->type = (mres == LDAP_SUCCESS) ? SUCCESS : RESULT_ERR;
1248 struct metaconn* lc,
1249 struct metasingleconn* lsc,
1253 struct exception* result)
1256 LDAPMessage *res, *e;
1258 int sres = LDAP_SUCCESS;
1260 rc = ldap_result( lsc->ld, msgid[ i ],
1264 result->type = TIMEOUT_ERR;
1266 } else if ( rc == -1 ) {
1268 result->type = RESULT_ERR;
1270 } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1271 e = ldap_first_entry( lsc->ld, res );
1272 entry = meta_create_entry(be, lc, i, e, result);
1276 ldap_msgfree( res );
1277 result->type = SUCCESS;
1280 sres = ldap_result2error( lsc->ld,
1283 result->type = RESULT_ERR;
1290 struct rewrite_info* info,
1291 const char* rewriteContext,
1295 struct exception* result)
1297 int rc = rewrite_session(info, rewriteContext, string, cookie, base);
1298 if (rc != REWRITE_REGEXEC_OK) {
1300 result->type = REWRITING_ERR;
1302 if (strcmp(rewriteContext, "searchBase") == 0)
1304 LDAP_LOG( BACK_META, DETAIL1,
1305 "Problem in rewriting search base\n", 0, 0, 0 );
1306 #else /* !NEW_LOGGING */
1307 Debug( LDAP_DEBUG_ANY,
1308 "Problem in rewriting search base\n", 0, 0, 0 );
1309 #endif /* !NEW_LOGGING */
1310 if (strcmp(rewriteContext, "searchFilter") == 0)
1312 LDAP_LOG( BACK_META, DETAIL1,
1313 "Problem in rewriting search filter\n",
1315 #else /* !NEW_LOGGING */
1316 Debug( LDAP_DEBUG_ANY,
1317 "Problem in rewriting search filter\n",
1319 #endif /* !NEW_LOGGING */
1320 if (strcmp(rewriteContext, "searchResult") == 0)
1322 LDAP_LOG( BACK_META, DETAIL1,
1323 "Problem in rewriting DN, or DN syntax "
1324 "attributes of search result\n", 0, 0, 0 );
1325 #else /* !NEW_LOGGING */
1326 Debug( LDAP_DEBUG_ANY,
1327 "Problem in rewriting DN, or DN syntax "
1328 "attributes of search result\n", 0, 0, 0 );
1329 #endif /* !NEW_LOGGING */
1330 if (strcmp(rewriteContext, "cacheBase") == 0)
1332 LDAP_LOG( BACK_META, DETAIL1,
1333 "Problem in rewriting search base with "
1334 "cache base\n", 0, 0, 0 );
1335 #else /* !NEW_LOGGING */
1336 Debug( LDAP_DEBUG_ANY,
1337 "Problem in rewriting search base with "
1338 "cache base\n", 0, 0, 0 );
1339 #endif /* !NEW_LOGGING */
1340 if (strcmp(rewriteContext, "cacheResult") == 0)
1342 LDAP_LOG( BACK_META, DETAIL1,
1343 "Problem in rewriting DN for cached entries\n",
1345 #else /* !NEW_LOGGING */
1346 Debug( LDAP_DEBUG_ANY,
1347 "Problem in rewriting DN for cached entries\n",
1349 #endif /* !NEW_LOGGING */
1350 if (strcmp(rewriteContext, "cacheReturn") == 0)
1352 LDAP_LOG( BACK_META, DETAIL1,
1353 "Problem in rewriting DN for answerable "
1354 "entries\n", 0, 0, 0 );
1355 #else /* !NEW_LOGGING */
1356 Debug( LDAP_DEBUG_ANY,
1357 "Problem in rewriting DN for answerable "
1358 "entries\n", 0, 0, 0 );
1359 #endif /* !NEW_LOGGING */
1361 result->type = SUCCESS;
1367 AttributeName* attrs,
1372 for (i=0; i<num; i++) {
1373 if (attrscmp(attrs, qm->attr_sets[i].attrs))
1381 AttributeName* attrs_in,
1382 AttributeName* attrs)
1384 int i, count1, count2;
1385 if ((attrs_in==NULL) || (attrs==NULL))
1388 attrs_in && attrs_in[count1].an_name.bv_val != NULL;
1392 attrs && attrs[count2].an_name.bv_val != NULL;
1395 if ( count1 != count2 )
1398 for ( i=0; i<count1; i++ ) {
1399 if ( !an_find(attrs, &attrs_in[i].an_name ))
1407 Entry** entry_array,
1411 struct exception* result)
1417 struct berval query_uuid;
1418 struct berval crp_uuid;
1419 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ], *crpid;
1421 query_manager* qm = cm->qm;
1423 result->type = SUCCESS;
1424 query_uuid.bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf));
1425 query_uuid.bv_val = ch_strdup(uuidbuf);
1428 LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
1430 #else /* !NEW_LOGGING */
1431 Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
1433 #endif /* !NEW_LOGGING */
1435 for ( i=0; ( entry_array && (e=entry_array[i]) ); i++ ) {
1437 LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
1439 #else /* !NEW_LOGGING */
1440 Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
1441 #endif /* !NEW_LOGGING */
1442 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1444 LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1445 #else /* !NEW_LOGGING */
1446 Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1447 #endif /* !NEW_LOGGING */
1448 if ( cm->cache_size > (cm->thresh_hi) ) {
1449 while(cm->cache_size > (cm->thresh_lo)) {
1450 crpid = cache_replacement(qm);
1451 if (crpid == NULL) {
1452 result->type = REMOVE_ERR;
1454 strcpy(crpuuid, crpid);
1455 crp_uuid.bv_val = crpuuid;
1456 crp_uuid.bv_len = strlen(crpuuid);
1458 LDAP_LOG( BACK_META, DETAIL1,
1459 "Removing query UUID %s\n",
1461 #else /* !NEW_LOGGING */
1462 Debug( LDAP_DEBUG_ANY,
1463 "Removing query UUID %s\n",
1465 #endif /* !NEW_LOGGING */
1466 return_val = remove_query_data(be, conn,
1469 LDAP_LOG( BACK_META, DETAIL1,
1470 "QUERY REMOVED, SIZE=%d\n",
1472 #else /* !NEW_LOGGING */
1473 Debug( LDAP_DEBUG_ANY,
1474 "QUERY REMOVED, SIZE=%d\n",
1476 #endif /* !NEW_LOGGING */
1477 ldap_pvt_thread_mutex_lock(
1479 cm->total_entries -= result->rc;
1480 cm->num_cached_queries--;
1482 LDAP_LOG( BACK_META, DETAIL1,
1483 "STORED QUERIES = %d\n",
1484 cm->num_cached_queries, 0, 0 );
1485 #else /* !NEW_LOGGING */
1486 Debug( LDAP_DEBUG_ANY,
1487 "STORED QUERIES = %d\n",
1488 cm->num_cached_queries, 0, 0 );
1489 #endif /* !NEW_LOGGING */
1490 ldap_pvt_thread_mutex_unlock(
1492 cm->cache_size = (return_val >
1494 0 : (cm->cache_size-return_val);
1496 LDAP_LOG( BACK_META, DETAIL1,
1497 "QUERY REMOVED, CACHE SIZE="
1498 "%d bytes %d entries\n",
1500 cm->total_entries, 0 );
1501 #else /* !NEW_LOGGING */
1502 Debug( LDAP_DEBUG_ANY,
1503 "QUERY REMOVED, CACHE SIZE="
1504 "%d bytes %d entries\n",
1506 cm->total_entries, 0 );
1507 #endif /* !NEW_LOGGING */
1511 return_val = merge_entry(be, conn, e, &query_uuid, result);
1512 cm->cache_size += return_val;
1514 LDAP_LOG( BACK_META, DETAIL1,
1515 "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1516 cm->cache_size, 0, 0 );
1517 #else /* !NEW_LOGGING */
1518 Debug( LDAP_DEBUG_ANY,
1519 "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1520 cm->cache_size, 0, 0 );
1521 #endif /* !NEW_LOGGING */
1523 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKING REMOVE MUTEX\n",
1525 #else /* !NEW_LOGGING */
1526 Debug( LDAP_DEBUG_NONE, "UNLOCKING REMOVE MUTEX\n", 0, 0, 0 );
1527 #endif /* !NEW_LOGGING */
1528 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1530 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKED REMOVE MUTEX\n",
1532 #else /* !NEW_LOGGING */
1533 Debug( LDAP_DEBUG_NONE, "UNLOCKED REMOVE MUTEX\n", 0, 0, 0 );
1534 #endif /* !NEW_LOGGING */
1535 if (result->type != SUCCESS)
1537 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1538 cm->total_entries += result->rc;
1540 LDAP_LOG( BACK_META, DETAIL1,
1541 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1542 return_val, cm->total_entries, 0 );
1543 #else /* !NEW_LOGGING */
1544 Debug( LDAP_DEBUG_ANY,
1545 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1546 return_val, cm->total_entries, 0 );
1547 #endif /* !NEW_LOGGING */
1548 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1550 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1551 cm->num_cached_queries++;
1553 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1554 cm->num_cached_queries, 0, 0 );
1555 #else /* !NEW_LOGGING */
1556 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1557 cm->num_cached_queries, 0, 0 );
1558 #endif /* !NEW_LOGGING */
1559 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1561 return query_uuid.bv_val;
1567 struct berval* tempstr,
1575 i = qm->templates[template_id].attr_set_index;
1576 str = qm->templates[template_id].querystr;
1578 if (attr_set == i) {
1581 id_array = qm->attr_sets[attr_set].ID_array;
1583 while (*id_array != -1) {
1591 if (strcasecmp(str, tempstr->bv_val) == 0)
1597 consistency_check(Backend* be, Backend* glue_be, Connection* conn)
1599 struct metainfo *li = ( struct metainfo * )be->be_private;
1600 cache_manager* cm = li->cm;
1601 query_manager* qm = cm->qm;
1602 CachedQuery* query, *query_prev;
1605 struct exception result;
1607 QueryTemplate* templ;
1610 for (i=0; qm->templates[i].querystr; i++) {
1611 templ = qm->templates + i;
1612 query = templ->query_last;
1613 curr_time = slap_get_time();
1614 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1615 while (query && (query->expiry_time < curr_time)) {
1616 ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
1617 remove_query(qm, query);
1618 ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
1620 LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
1622 #else /* !NEW_LOGGING */
1623 Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
1625 #endif /* !NEW_LOGGING */
1626 ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
1627 remove_from_template(query, templ);
1629 LDAP_LOG( BACK_META, DETAIL1,
1630 "TEMPLATE %d QUERIES-- %d\n",
1631 i, templ->no_of_queries, 0 );
1632 #else /* !NEW_LOGGING */
1633 Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
1634 i, templ->no_of_queries, 0 );
1635 #endif /* !NEW_LOGGING */
1637 LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
1639 #else /* !NEW_LOGGING */
1640 Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
1642 #endif /* !NEW_LOGGING */
1643 ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
1644 uuid.bv_val = query->q_uuid;
1645 uuid.bv_len = strlen(query->q_uuid);
1646 return_val = remove_query_data(glue_be, conn,
1649 LDAP_LOG( BACK_META, DETAIL1,
1650 "STALE QUERY REMOVED, SIZE=%d\n",
1652 #else /* !NEW_LOGGING */
1653 Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
1655 #endif /* !NEW_LOGGING */
1656 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1657 cm->total_entries -= result.rc;
1658 cm->num_cached_queries--;
1660 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1661 cm->num_cached_queries, 0, 0 );
1662 #else /* !NEW_LOGGING */
1663 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1664 cm->num_cached_queries, 0, 0 );
1665 #endif /* !NEW_LOGGING */
1666 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1667 cm->cache_size = (return_val > cm->cache_size) ?
1668 0: (cm->cache_size-return_val);
1670 LDAP_LOG( BACK_META, DETAIL1,
1671 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1672 "entries\n", cm->cache_size,
1673 cm->total_entries, 0 );
1674 #else /* !NEW_LOGGING */
1675 Debug( LDAP_DEBUG_ANY,
1676 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1677 "entries\n", cm->cache_size,
1678 cm->total_entries, 0 );
1679 #endif /* !NEW_LOGGING */
1681 query = query->prev;
1682 free_query(query_prev);
1684 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1694 AttributeName* attrs,
1696 LDAPControl** ctrls )
1698 slap_callback* cb = op->o_callback;
1699 Backend* be = (Backend*)(cb->sc_private);
1700 struct metainfo *li = ( struct metainfo * )be->be_private;
1703 struct exception result;
1710 rewriteSession( li->rwinfo,
1711 "cacheReturn", e->e_name.bv_val, conn, &ename, &result );
1712 ber_str2bv(ename, strlen(ename), 0, &e->e_name);
1713 ber_dupbv(&e->e_nname, &e->e_name);
1715 op->o_callback = NULL;
1716 send_search_entry(be, conn, op, e, attrs, attrsonly, ctrls);
1721 op->o_callback = cb;