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>
101 #include "../back-ldap/back-ldap.h"
102 #include "back-meta.h"
103 #undef ldap_debug /* silence a warning in ldap-int.h */
104 #include "ldap_log.h"
105 #include "../../../libraries/libldap/ldap-int.h"
114 struct exception* result
123 static struct metaconn*
129 struct berval* nbase,
130 struct exception* result
135 AttributeName** newattrs,
136 AttributeName* attrs,
137 AttributeName* filter_attrs
144 int* msgid, Backend* be,
145 AttributeName* attrs,
149 Entry*** entry_array,
152 struct exception* result
159 struct metasingleconn* lsc,
163 struct exception* result
168 struct rewrite_info* info,
169 const char* rewriteContext,
173 struct exception* result
178 AttributeName* attrs,
185 AttributeName* attrs_in,
195 struct exception* result
201 struct berval* tempstr,
219 AttributeName* attrs,
225 meta_back_cache_search(
230 struct berval *nbase,
236 struct berval *filterstr,
237 AttributeName *attributes,
241 struct metainfo *li = ( struct metainfo * )be->be_private;
243 struct metasingleconn *lsc;
244 cache_manager* cm = li->cm;
245 query_manager* qm = cm->qm;
249 int count, rc = 0, *msgid = NULL;
254 int i = -1, last = 0, candidates = 0, op_type;
256 struct berval mfilter;
257 struct berval cachebase = { 0L, NULL };
258 struct berval ncachebase = { 0L, NULL };
259 struct berval cache_suffix;
260 struct berval tempstr = { 0L, NULL };
262 AttributeName *filter_attrs = NULL;
263 AttributeName *new_attrs = NULL;
264 AttributeName *attrs = NULL;
267 Entry **entry_array = NULL;
272 int template_id = -1;
280 struct exception result[1];
282 Filter* filter = str2filter(filterstr->bv_val);
283 slap_callback cb = {NULL, NULL, cache_back_sentry, NULL};
288 for ( count=0; attributes[ count ].an_name.bv_val; count++ )
290 attrs = (AttributeName*)malloc( ( count + 1 ) *
291 sizeof(AttributeName));
292 for ( count=0; attributes[ count ].an_name.bv_val; count++ ) {
293 ber_dupbv(&attrs[ count ].an_name,
294 &attributes[ count ].an_name);
295 attrs[count].an_desc = attributes[count].an_desc;
297 attrs[ count ].an_name.bv_val = NULL;
298 attrs[ count ].an_name.bv_len = 0;
301 result->type = SUCCESS;
303 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
306 LDAP_LOG( BACK_META, DETAIL1, "Threads++ = %d\n", cm->threads, 0, 0 );
307 #else /* !NEW_LOGGING */
308 Debug( LDAP_DEBUG_ANY, "Threads++ = %d\n", cm->threads, 0, 0 );
309 #endif /* !NEW_LOGGING */
310 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
312 filter2template(filter, &tempstr, &filter_attrs, &fattr_cnt, result);
313 if (result->type != SUCCESS)
317 LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
318 tempstr.bv_val, 0, 0 );
319 #else /* !NEW_LOGGING */
320 Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
321 tempstr.bv_val, 0, 0 );
322 #endif /* !NEW_LOGGING */
323 curr_limit = cm->num_entries_limit ;
326 attr_set = get_attr_set(attrs, qm, cm->numattrsets);
328 query.filter = filter;
333 /* check for query containment */
335 for (i=0; i<cm->numtemplates; i++) {
336 /* find if template i can potentially answer tempstr */
337 if (!is_temp_answerable(attr_set, &tempstr, qm, i))
339 if (attr_set == qm->templates[i].attr_set_index) {
344 LDAP_LOG( BACK_META, DETAIL2,
345 "Entering QC, querystr = %s\n",
346 filterstr->bv_val, 0, 0 );
347 #else /* !NEW_LOGGING */
348 Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
349 filterstr->bv_val, 0, 0 );
350 #endif /* !NEW_LOGGING */
351 answerable = (*(qm->qcfunc))(qm, &query, i);
360 LDAP_LOG( BACK_META, DETAIL1, "QUERY ANSWERABLE\n", 0, 0, 0 );
361 #else /* !NEW_LOGGING */
362 Debug( LDAP_DEBUG_ANY, "QUERY ANSWERABLE\n", 0, 0, 0 );
363 #endif /* !NEW_LOGGING */
364 rewriteSession(li->rwinfo, "cacheBase", base->bv_val,
365 conn, &cbase, result);
366 if (result->type != SUCCESS) {
367 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
370 if ( cbase == NULL ) {
373 cachebase.bv_val = cbase;
374 cachebase.bv_len = strlen(cbase);
376 dnNormalize(NULL, &cachebase, &ncachebase);
378 op->o_caching_on = 1;
379 op->o_callback = &cb;
380 li->glue_be->be_search(li->glue_be, conn, op, &cachebase,
381 &ncachebase, scope, deref, slimit, tlimit,
382 filter, filterstr, attrs, attrsonly);
383 ber_memfree( ncachebase.bv_val );
384 if ( cachebase.bv_val != base->bv_val ) {
385 /* free only if rewritten */
386 free( cachebase.bv_val );
389 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
392 LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
394 #else /* !NEW_LOGGING */
395 Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
396 #endif /* !NEW_LOGGING */
398 if ( scope == LDAP_SCOPE_BASE ) {
399 op_type = META_OP_REQUIRE_SINGLE;
401 op_type = META_OP_ALLOW_MULTIPLE;
404 lc = metaConnect(li, conn, op, op_type, nbase, result);
406 if (result->type != SUCCESS)
409 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
410 if (cm->num_cached_queries >= cm->max_queries) {
413 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
417 LDAP_LOG( BACK_META, DETAIL1,
418 "QUERY TEMPLATE CACHEABLE\n",
420 #else /* !NEW_LOGGING */
421 Debug( LDAP_DEBUG_ANY, "QUERY TEMPLATE CACHEABLE\n",
423 #endif /* !NEW_LOGGING */
424 add_filter_attrs(&new_attrs, attrs, filter_attrs);
432 * Array of message id of each target
434 msgid = ch_calloc( sizeof( int ), li->ntargets );
435 if ( msgid == NULL ) {
436 result->type = CONN_ERR;
441 if (slimit > 0 && (slimit <= cm->num_entries_limit))
442 slimit = cm->num_entries_limit;
449 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
450 char *realbase = ( char * )base->bv_val;
451 int realscope = scope;
453 char *mapped_filter, **mapped_attrs;
455 /* FIXME: Check for more than one targets */
456 if ( meta_back_is_candidate(
457 &li->targets[i]->suffix, nbase ))
458 lsc->candidate = META_CANDIDATE;
460 if ( lsc->candidate != META_CANDIDATE )
464 ldap_set_option( lsc->ld, LDAP_OPT_DEREF,
467 if ( tlimit != -1 ) {
468 ldap_set_option( lsc->ld, LDAP_OPT_TIMELIMIT,
471 if ( slimit != -1 ) {
472 ldap_set_option( lsc->ld, LDAP_OPT_SIZELIMIT,
477 * modifies the base according to the scope, if required
479 suffixlen = li->targets[ i ]->suffix.bv_len;
480 if ( suffixlen > nbase->bv_len ) {
482 case LDAP_SCOPE_SUBTREE:
484 * make the target suffix the new base
485 * FIXME: this is very forgiving,
486 * because illegal bases may be turned
487 * into the suffix of the target.
490 &li->targets[ i ]->suffix,
493 li->targets[i]->suffix.bv_val;
496 * this target is no longer
505 case LDAP_SCOPE_ONELEVEL:
506 if ( is_one_level_rdn(
507 li->targets[ i ]->suffix.bv_val,
508 suffixlen - nbase->bv_len - 1 )
510 &li->targets[ i ]->suffix,
513 * if there is exactly one
514 * level, make the target suffix
515 * the new base, and make scope
519 li->targets[i]->suffix.bv_val;
520 realscope = LDAP_SCOPE_BASE;
522 } /* else continue with the next case */
523 case LDAP_SCOPE_BASE:
525 * this target is no longer candidate
527 lsc->candidate = META_NOT_CANDIDATE;
533 * Rewrite the search base, if required
536 rewriteSession(li->targets[i]->rwinfo, "searchBase",
537 realbase, conn, &mbase, result);
539 if (result->type != SUCCESS)
542 if ( mbase == NULL ) {
547 * Rewrite the search filter, if required
549 rewriteSession( li->targets[i]->rwinfo, "searchFilter",
550 filterstr->bv_val, conn,
551 &mfilter.bv_val, result);
552 if (result->type != SUCCESS)
555 if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ]
557 mfilter.bv_len = strlen( mfilter.bv_val );
559 if ( mfilter.bv_val != NULL ) {
560 free( mfilter.bv_val );
562 mfilter = *filterstr;
566 * Maps attributes in filter
568 mapped_filter = ldap_back_map_filter(
569 &li->targets[i]->at_map,
570 &li->targets[i]->oc_map, &mfilter, 0 );
571 if ( mapped_filter == NULL ) {
572 mapped_filter = ( char * )mfilter.bv_val;
574 if ( mfilter.bv_val != filterstr->bv_val ) {
575 free( mfilter.bv_val );
578 mfilter.bv_val = NULL;
582 * Maps required attributes
584 mapped_attrs = ldap_back_map_attrs(
585 &li->targets[ i ]->at_map,
587 if ( mapped_attrs == NULL && new_attrs) {
589 new_attrs[ count ].an_name.bv_val;
592 mapped_attrs = ch_malloc( ( count + 1 ) *
595 new_attrs[ count ].an_name.bv_val;
597 mapped_attrs[ count ] =
598 new_attrs[count].an_name.bv_val;
600 mapped_attrs[ count ] = NULL;
606 msgid[ i ] = ldap_search( lsc->ld, mbase, realscope,
607 mapped_filter, mapped_attrs,
609 if ( msgid[ i ] == -1 ) {
610 lsc->candidate = META_NOT_CANDIDATE;
614 if ( mapped_attrs ) {
615 free( mapped_attrs );
619 if ( mapped_filter != filterstr->bv_val ) {
620 free( mapped_filter );
621 mapped_filter = NULL;
624 if ( mbase != realbase ) {
632 num_entries = handleLdapResult(lc, op, msgid, be, attrs,
633 attrsonly, candidates, cacheable, &entry_array,
634 curr_limit, slimit, result);
636 if (result->type != SUCCESS)
638 if (cacheable && (num_entries <= curr_limit)) {
640 LDAP_LOG( BACK_META, DETAIL1,
641 "QUERY CACHEABLE\n", 0, 0, 0 );
642 #else /* !NEW_LOGGING */
643 Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
644 #endif /* !NEW_LOGGING */
645 uuid = cache_entries(entry_array, cm, li->glue_be,
648 LDAP_LOG( BACK_META, DETAIL1,
649 "Added query %s UUID %s ENTRIES %d\n",
650 filterstr->bv_val, uuid, num_entries );
651 #else /* !NEW_LOGGING */
652 Debug( LDAP_DEBUG_ANY,
653 "Added query %s UUID %s ENTRIES %d\n",
654 filterstr->bv_val, uuid, num_entries );
655 #endif /* !NEW_LOGGING */
657 if (result->type != SUCCESS)
659 (*(qm->addfunc))(qm, &query, template_id, uuid, result);
660 if (result->type != SUCCESS)
668 switch (result->type) {
674 LDAP_LOG( BACK_META, DETAIL1,
675 "Invalid template error\n", 0, 0, 0 );
676 #else /* !NEW_LOGGING */
677 Debug( LDAP_DEBUG_ANY, "Invalid template error\n",
679 #endif /* !NEW_LOGGING */
684 LDAP_LOG( BACK_META, DETAIL1,
685 "Could not connect to a remote server\n",
687 #else /* !NEW_LOGGING */
688 Debug( LDAP_DEBUG_ANY,
689 "Could not connect to a remote server\n",
691 #endif /* !NEW_LOGGING */
692 send_ldap_result(conn, op, LDAP_OTHER,
693 NULL, "Connection error",
699 LDAP_LOG( BACK_META, DETAIL1,
700 "Error in handling ldap_result\n", 0, 0, 0 );
701 #else /* !NEW_LOGGING */
702 Debug( LDAP_DEBUG_ANY,
703 "Error in handling ldap_result\n", 0, 0, 0 );
704 #endif /* !NEW_LOGGING */
708 if (result->rc == REWRITE_REGEXEC_UNWILLING) {
709 send_ldap_result( conn, op,
710 LDAP_UNWILLING_TO_PERFORM,
711 NULL, "Unwilling to perform",
714 send_ldap_result( conn, op, LDAP_OTHER,
715 NULL, "Rewrite error",
722 LDAP_LOG( BACK_META, DETAIL1,
723 "Error in merging entry \n", 0, 0, 0 );
724 #else /* !NEW_LOGGING */
725 Debug( LDAP_DEBUG_ANY,
726 "Error in merging entry \n", 0, 0, 0 );
727 #endif /* !NEW_LOGGING */
732 LDAP_LOG( BACK_META, DETAIL1,
733 "Error in removing query \n",
735 #else /* !NEW_LOGGING */
736 Debug( LDAP_DEBUG_ANY, "Error in removing query \n",
738 #endif /* !NEW_LOGGING */
745 ldap_pvt_thread_mutex_lock(&cm->consistency_mutex);
746 curr_time = slap_get_time();
747 if (curr_time - cm->consistency_time > cm->consistency_cycle_time) {
748 cm->consistency_time = curr_time;
749 consistency_check(be, li->glue_be, conn);
751 ldap_pvt_thread_mutex_unlock(&cm->consistency_mutex);
757 for (i=0; (e = entry_array[i]); i++) {
766 if (new_attrs != attrs)
773 if (tempstr.bv_val ) {
774 free(tempstr.bv_val);
776 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
779 LDAP_LOG( BACK_META, DETAIL1, "Threads-- = %d\n", cm->threads, 0, 0 );
780 #else /* !NEW_LOGGING */
781 Debug( LDAP_DEBUG_ANY, "Threads-- = %d\n", cm->threads, 0, 0 );
782 #endif /* !NEW_LOGGING */
783 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
794 struct exception* result
797 struct metainfo *li = ( struct metainfo * )be->be_private;
798 struct berval a, mapped;
800 BerElement ber = *e->lm_ber;
801 Attribute *attr, **attrp;
802 struct berval dummy = { 0, NULL };
803 struct berval *bv, bdn;
806 if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
807 result->type = CREATE_ENTRY_ERR;
810 ent = (Entry*)malloc(sizeof(Entry));
813 * Rewrite the dn of the result, if needed
815 rewriteSession( li->targets[ target ]->rwinfo, "searchResult",
816 bdn.bv_val, lc->conn, &ent->e_name.bv_val, result );
818 if (result->type != SUCCESS) {
821 if ( ent->e_name.bv_val == NULL ) {
822 ber_dupbv(&(ent->e_name), &bdn);
825 LDAP_LOG( BACK_META, DETAIL1,
826 "[rw] searchResult[%d]: \"%s\" -> \"%s\"\n",
827 target, bdn.bv_val, ent->e_name.bv_val );
828 #else /* !NEW_LOGGING */
829 Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
831 target, bdn.bv_val, ent->e_name.bv_val );
832 #endif /* !NEW_LOGGING */
833 ent->e_name.bv_len = strlen( ent->e_name.bv_val );
837 * Note: this may fail if the target host(s) schema differs
838 * from the one known to the meta, and a DN with unknown
839 * attributes is returned.
841 * FIXME: should we log anything, or delegate to dnNormalize2?
843 dnNormalize2( NULL, &ent->e_name, &ent->e_nname );
846 if ( dnNormalize2( NULL, &ent->e_name, &ent->e_nname ) != LDAP_SUCCESS ) {
847 return LDAP_INVALID_DN_SYNTAX;
854 if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
855 meta_dncache_update_entry( &li->cache, &ent->e_nname, target );
861 ent->e_bv.bv_val = 0;
863 attrp = &ent->e_attrs;
865 while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
866 ldap_back_map( &li->targets[ target ]->at_map, &a, &mapped, 1 );
867 if ( mapped.bv_val == NULL ) {
870 attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
871 if ( attr == NULL ) {
877 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) {
878 if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text )
881 LDAP_LOG( BACK_META, DETAIL1,
882 "slap_bv2undef_ad(%s): %s\n",
883 mapped.bv_val, text, 0 );
884 #else /* !NEW_LOGGING */
885 Debug( LDAP_DEBUG_ANY,
886 "slap_bv2undef_ad(%s): "
887 "%s\n%s", mapped.bv_val, text, "" );
888 #endif /* !NEW_LOGGING */
894 /* no subschemaSubentry */
895 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
900 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
901 || attr->a_vals == NULL ) {
902 attr->a_vals = &dummy;
903 } else if ( attr->a_desc == slap_schema.si_ad_objectClass ||
905 slap_schema.si_ad_structuralObjectClass) {
907 for ( last = 0; attr->a_vals[ last ].bv_val; ++last )
909 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
910 ldap_back_map( &li->targets[ target]->oc_map,
912 if ( mapped.bv_val == NULL ) {
918 *bv = attr->a_vals[ last ];
919 attr->a_vals[ last ].bv_val = NULL;
921 } else if ( mapped.bv_val != bv->bv_val ) {
923 ber_dupbv( bv, &mapped );
927 * It is necessary to try to rewrite attributes with
928 * dn syntax because they might be used in ACLs as
929 * members of groups; since ACLs are applied to the
930 * rewritten stuff, no dn-based subecj clause could
931 * be used at the ldap backend side (see
932 * http://www.OpenLDAP.org/faq/data/cache/452.html)
933 * The problem can be overcome by moving the dn-based
934 * ACLs to the target directory server, and letting
935 * everything pass thru the ldap backend.
937 } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
938 SLAPD_DN_SYNTAX ) == 0 ) {
940 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
942 rewriteSession(li->targets[ target ]->rwinfo,
943 "searchResult", bv->bv_val,
944 lc->conn, &newval, result);
945 if (result->type != SUCCESS) {
946 /* FIXME : Handle error */
947 result->type = SUCCESS;
950 if ( newval == NULL ) {
954 LDAP_LOG( BACK_META, DETAIL1,
955 "[rw] searchResult on "
956 "attr=%s: \"%s\" -> \"%s\"\n",
957 attr->a_desc->ad_type->
959 bv->bv_val, newval );
960 #else /* !NEW_LOGGING */
961 Debug( LDAP_DEBUG_ARGS,
962 "rw> searchResult on attr=%s:"
963 " \"%s\" -> \"%s\"\n",
964 attr->a_desc->ad_type->
966 bv->bv_val, newval );
967 #endif /* !NEW_LOGGING */
970 bv->bv_len = strlen( newval );
975 attrp = &attr->a_next;
987 if ( DN_SEPARATOR( rdn[ from ] ) ) {
994 static struct metaconn*
1000 struct berval* nbase,
1001 struct exception* result)
1003 struct metaconn* lc;
1004 result->type = SUCCESS;
1005 lc = meta_back_getconn( li, conn, op, op_type, nbase, NULL );
1007 result->type = CONN_ERR;
1015 AttributeName** new_attrs,
1016 AttributeName* attrs,
1017 AttributeName* filter_attrs )
1019 struct berval all_user = { sizeof(LDAP_ALL_USER_ATTRIBUTES) -1,
1020 LDAP_ALL_USER_ATTRIBUTES };
1022 struct berval all_op = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES) -1,
1023 LDAP_ALL_OPERATIONAL_ATTRIBUTES};
1030 /* duplicate attrs */
1031 for (count=0; attrs[count].an_name.bv_val; count++)
1033 *new_attrs = (AttributeName*)(malloc((count+1)*sizeof(AttributeName)));
1034 for (i=0; i<count; i++) {
1036 ber_dupbv(&((*new_attrs)[i].an_name), &(attrs[i].an_name));
1038 (*new_attrs)[i].an_name = attrs[i].an_name;
1039 (*new_attrs)[i].an_desc = attrs[i].an_desc;
1041 (*new_attrs)[count].an_name.bv_val = NULL;
1042 (*new_attrs)[count].an_name.bv_len = 0;
1045 if ((*new_attrs)[0].an_name.bv_val == NULL) {
1046 *new_attrs = (AttributeName*)(malloc(2*sizeof(AttributeName)));
1047 (*new_attrs)[0].an_name.bv_val = "*";
1048 (*new_attrs)[0].an_name.bv_len = 1;
1049 (*new_attrs)[1].an_name.bv_val = NULL;
1050 (*new_attrs)[1].an_name.bv_len = 0;
1054 alluser = an_find(*new_attrs, &all_user);
1055 allop = an_find(*new_attrs, &all_op);
1058 for ( i=0; filter_attrs[i].an_name.bv_val; i++ ) {
1059 if ( an_find(*new_attrs, &filter_attrs[i].an_name ))
1061 if ( is_at_operational(filter_attrs[i].an_desc->ad_type)
1066 *new_attrs = (AttributeName*)(realloc(*new_attrs,
1067 (count+2)*sizeof(AttributeName)));
1068 (*new_attrs)[count].an_name.bv_val =
1069 filter_attrs[i].an_name.bv_val;
1070 (*new_attrs)[count].an_name.bv_len =
1071 filter_attrs[i].an_name.bv_len;
1072 (*new_attrs)[count].an_desc = filter_attrs[i].an_desc;
1073 (*new_attrs)[count+1].an_name.bv_val = NULL;
1074 (*new_attrs)[count+1].an_name.bv_len = 0;
1081 struct metaconn* lc,
1083 int* msgid, Backend* be,
1084 AttributeName* attrs,
1088 Entry*** entry_array,
1091 struct exception* result)
1094 char *match = NULL, *err = NULL, *cache_ename = NULL;
1096 int mres = LDAP_SUCCESS;
1097 int num_entries = 0, count, i, rc;
1098 struct timeval tv = {0, 0};
1099 struct metasingleconn* lsc;
1100 struct metainfo *li = ( struct metainfo * )be->be_private;
1102 result->type = SUCCESS;
1104 for ( count = 0, rc = 0; candidates > 0; ) {
1107 /* check for abandon */
1110 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
1111 if ( lsc->candidate != META_CANDIDATE ) {
1116 ldap_abandon( lsc->ld, msgid[ i ] );
1117 result->type = ABANDON_ERR;
1121 if ( slimit > 0 && num_entries == slimit ) {
1122 result->type = SLIMIT_ERR;
1126 if ((entry = get_result_entry(be, lc, lsc,
1127 msgid, i, &tv, result))) {
1128 send_search_entry( be, lc->conn, op, entry,
1129 attrs, attrsonly, NULL );
1131 (num_entries < curr_limit)) {
1132 rewriteSession( li->rwinfo,
1134 entry->e_name.bv_val,
1136 &cache_ename, result );
1137 free(entry->e_name.bv_val);
1138 if (result->type != SUCCESS) {
1141 ber_str2bv(cache_ename,
1142 strlen(cache_ename),
1144 ber_dupbv(&entry->e_nname,
1146 *entry_array = (Entry**)realloc(
1148 (( num_entries+2 ) *
1150 (*entry_array)[num_entries] = entry;
1151 (*entry_array)[num_entries+1] = NULL;
1155 } else if (result->type == REWRITING_ERR) {
1157 } else if (result->type == TIMEOUT_ERR) {
1158 result->type = SUCCESS;
1160 } else if (result->type == CREATE_ENTRY_ERR) {
1162 } else if (result->rc == -1) {
1165 sres = ldap_back_map_result(result->rc);
1166 if (mres == LDAP_SUCCESS &&
1167 sres != LDAP_SUCCESS) {
1169 ldap_get_option(lsc->ld,
1170 LDAP_OPT_ERROR_STRING, &err);
1171 ldap_get_option(lsc->ld,
1172 LDAP_OPT_MATCHED_DN, &match);
1174 lsc->candidate = META_NOT_CANDIDATE;
1176 result->type = SUCCESS;
1179 switch (result->type) {
1182 LDAP_LOG( BACK_META, DETAIL1,
1183 "ldap_result error, rc = -1\n",
1185 #else /* !NEW_LOGGING */
1186 Debug( LDAP_DEBUG_ANY, "ldap_result error, rc = -1\n",
1188 #endif /* !NEW_LOGGING */
1189 send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1190 NULL, NULL, NULL, num_entries );
1192 case CREATE_ENTRY_ERR:
1194 LDAP_LOG( BACK_META, DETAIL1,
1195 "Error in parsing result \n",
1197 #else /* !NEW_LOGGING */
1198 Debug( LDAP_DEBUG_ANY, "Error in parsing result \n",
1200 #endif /* !NEW_LOGGING */
1201 send_search_result( lc->conn, op, LDAP_OTHER, NULL,
1202 NULL, NULL, NULL, num_entries );
1203 result->type = RESULT_ERR;
1207 LDAP_LOG( BACK_META, DETAIL1, "Size limit exceeded \n",
1209 #else /* !NEW_LOGGING */
1210 Debug( LDAP_DEBUG_ANY, "Size limit exceeded \n",
1212 #endif /* !NEW_LOGGING */
1213 send_search_result( lc->conn, op,
1214 LDAP_SIZELIMIT_EXCEEDED,
1215 NULL, NULL, NULL, NULL, num_entries );
1216 result->type = RESULT_ERR;
1220 LDAP_LOG( BACK_META, DETAIL1,
1221 "search operation abandoned \n",
1223 #else /* !NEW_LOGGING */
1224 Debug( LDAP_DEBUG_ANY, "search operation abandoned \n",
1226 #endif /* !NEW_LOGGING */
1227 result->type = RESULT_ERR;
1235 tv.tv_usec = 100000;
1236 ldap_pvt_thread_yield();
1243 send_search_result( lc->conn, op, mres, match, err,
1244 NULL, NULL, num_entries );
1252 result->type = (mres == LDAP_SUCCESS) ? SUCCESS : RESULT_ERR;
1259 struct metaconn* lc,
1260 struct metasingleconn* lsc,
1264 struct exception* result)
1267 LDAPMessage *res, *e;
1269 int sres = LDAP_SUCCESS;
1271 rc = ldap_result( lsc->ld, msgid[ i ],
1275 result->type = TIMEOUT_ERR;
1277 } else if ( rc == -1 ) {
1279 result->type = RESULT_ERR;
1281 } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1282 e = ldap_first_entry( lsc->ld, res );
1283 entry = meta_create_entry(be, lc, i, e, result);
1287 ldap_msgfree( res );
1288 result->type = SUCCESS;
1291 sres = ldap_result2error( lsc->ld,
1294 result->type = RESULT_ERR;
1301 struct rewrite_info* info,
1302 const char* rewriteContext,
1306 struct exception* result)
1308 int rc = rewrite_session(info, rewriteContext, string, cookie, base);
1309 if (rc != REWRITE_REGEXEC_OK) {
1311 result->type = REWRITING_ERR;
1313 if (strcmp(rewriteContext, "searchBase") == 0)
1315 LDAP_LOG( BACK_META, DETAIL1,
1316 "Problem in rewriting search base\n", 0, 0, 0 );
1317 #else /* !NEW_LOGGING */
1318 Debug( LDAP_DEBUG_ANY,
1319 "Problem in rewriting search base\n", 0, 0, 0 );
1320 #endif /* !NEW_LOGGING */
1321 if (strcmp(rewriteContext, "searchFilter") == 0)
1323 LDAP_LOG( BACK_META, DETAIL1,
1324 "Problem in rewriting search filter\n",
1326 #else /* !NEW_LOGGING */
1327 Debug( LDAP_DEBUG_ANY,
1328 "Problem in rewriting search filter\n",
1330 #endif /* !NEW_LOGGING */
1331 if (strcmp(rewriteContext, "searchResult") == 0)
1333 LDAP_LOG( BACK_META, DETAIL1,
1334 "Problem in rewriting DN, or DN syntax "
1335 "attributes of search result\n", 0, 0, 0 );
1336 #else /* !NEW_LOGGING */
1337 Debug( LDAP_DEBUG_ANY,
1338 "Problem in rewriting DN, or DN syntax "
1339 "attributes of search result\n", 0, 0, 0 );
1340 #endif /* !NEW_LOGGING */
1341 if (strcmp(rewriteContext, "cacheBase") == 0)
1343 LDAP_LOG( BACK_META, DETAIL1,
1344 "Problem in rewriting search base with "
1345 "cache base\n", 0, 0, 0 );
1346 #else /* !NEW_LOGGING */
1347 Debug( LDAP_DEBUG_ANY,
1348 "Problem in rewriting search base with "
1349 "cache base\n", 0, 0, 0 );
1350 #endif /* !NEW_LOGGING */
1351 if (strcmp(rewriteContext, "cacheResult") == 0)
1353 LDAP_LOG( BACK_META, DETAIL1,
1354 "Problem in rewriting DN for cached entries\n",
1356 #else /* !NEW_LOGGING */
1357 Debug( LDAP_DEBUG_ANY,
1358 "Problem in rewriting DN for cached entries\n",
1360 #endif /* !NEW_LOGGING */
1361 if (strcmp(rewriteContext, "cacheReturn") == 0)
1363 LDAP_LOG( BACK_META, DETAIL1,
1364 "Problem in rewriting DN for answerable "
1365 "entries\n", 0, 0, 0 );
1366 #else /* !NEW_LOGGING */
1367 Debug( LDAP_DEBUG_ANY,
1368 "Problem in rewriting DN for answerable "
1369 "entries\n", 0, 0, 0 );
1370 #endif /* !NEW_LOGGING */
1372 result->type = SUCCESS;
1378 AttributeName* attrs,
1383 for (i=0; i<num; i++) {
1384 if (attrscmp(attrs, qm->attr_sets[i].attrs))
1392 AttributeName* attrs_in,
1393 AttributeName* attrs)
1395 int i, count1, count2;
1396 if ((attrs_in==NULL) || (attrs==NULL))
1399 attrs_in && attrs_in[count1].an_name.bv_val != NULL;
1403 attrs && attrs[count2].an_name.bv_val != NULL;
1406 if ( count1 != count2 )
1409 for ( i=0; i<count1; i++ ) {
1410 if ( !an_find(attrs, &attrs_in[i].an_name ))
1418 Entry** entry_array,
1422 struct exception* result)
1428 struct berval query_uuid;
1429 struct berval crp_uuid;
1430 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ], *crpid;
1432 query_manager* qm = cm->qm;
1434 result->type = SUCCESS;
1435 query_uuid.bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf));
1436 query_uuid.bv_val = ch_strdup(uuidbuf);
1439 LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
1441 #else /* !NEW_LOGGING */
1442 Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
1444 #endif /* !NEW_LOGGING */
1446 for ( i=0; ( entry_array && (e=entry_array[i]) ); i++ ) {
1448 LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
1450 #else /* !NEW_LOGGING */
1451 Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
1452 #endif /* !NEW_LOGGING */
1453 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1455 LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1456 #else /* !NEW_LOGGING */
1457 Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1458 #endif /* !NEW_LOGGING */
1459 if ( cm->cache_size > (cm->thresh_hi) ) {
1460 while(cm->cache_size > (cm->thresh_lo)) {
1461 crpid = cache_replacement(qm);
1462 if (crpid == NULL) {
1463 result->type = REMOVE_ERR;
1465 strcpy(crpuuid, crpid);
1466 crp_uuid.bv_val = crpuuid;
1467 crp_uuid.bv_len = strlen(crpuuid);
1469 LDAP_LOG( BACK_META, DETAIL1,
1470 "Removing query UUID %s\n",
1472 #else /* !NEW_LOGGING */
1473 Debug( LDAP_DEBUG_ANY,
1474 "Removing query UUID %s\n",
1476 #endif /* !NEW_LOGGING */
1477 return_val = remove_query_data(be, conn,
1480 LDAP_LOG( BACK_META, DETAIL1,
1481 "QUERY REMOVED, SIZE=%d\n",
1483 #else /* !NEW_LOGGING */
1484 Debug( LDAP_DEBUG_ANY,
1485 "QUERY REMOVED, SIZE=%d\n",
1487 #endif /* !NEW_LOGGING */
1488 ldap_pvt_thread_mutex_lock(
1490 cm->total_entries -= result->rc;
1491 cm->num_cached_queries--;
1493 LDAP_LOG( BACK_META, DETAIL1,
1494 "STORED QUERIES = %d\n",
1495 cm->num_cached_queries, 0, 0 );
1496 #else /* !NEW_LOGGING */
1497 Debug( LDAP_DEBUG_ANY,
1498 "STORED QUERIES = %d\n",
1499 cm->num_cached_queries, 0, 0 );
1500 #endif /* !NEW_LOGGING */
1501 ldap_pvt_thread_mutex_unlock(
1503 cm->cache_size = (return_val >
1505 0 : (cm->cache_size-return_val);
1507 LDAP_LOG( BACK_META, DETAIL1,
1508 "QUERY REMOVED, CACHE SIZE="
1509 "%d bytes %d entries\n",
1511 cm->total_entries, 0 );
1512 #else /* !NEW_LOGGING */
1513 Debug( LDAP_DEBUG_ANY,
1514 "QUERY REMOVED, CACHE SIZE="
1515 "%d bytes %d entries\n",
1517 cm->total_entries, 0 );
1518 #endif /* !NEW_LOGGING */
1522 return_val = merge_entry(be, conn, e, &query_uuid, result);
1523 cm->cache_size += return_val;
1525 LDAP_LOG( BACK_META, DETAIL1,
1526 "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1527 cm->cache_size, 0, 0 );
1528 #else /* !NEW_LOGGING */
1529 Debug( LDAP_DEBUG_ANY,
1530 "ENTRY ADDED/MERGED, CACHE SIZE=%d bytes\n",
1531 cm->cache_size, 0, 0 );
1532 #endif /* !NEW_LOGGING */
1534 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKING REMOVE MUTEX\n",
1536 #else /* !NEW_LOGGING */
1537 Debug( LDAP_DEBUG_NONE, "UNLOCKING REMOVE MUTEX\n", 0, 0, 0 );
1538 #endif /* !NEW_LOGGING */
1539 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1541 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKED REMOVE MUTEX\n",
1543 #else /* !NEW_LOGGING */
1544 Debug( LDAP_DEBUG_NONE, "UNLOCKED REMOVE MUTEX\n", 0, 0, 0 );
1545 #endif /* !NEW_LOGGING */
1546 if (result->type != SUCCESS)
1548 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1549 cm->total_entries += result->rc;
1551 LDAP_LOG( BACK_META, DETAIL1,
1552 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1553 return_val, cm->total_entries, 0 );
1554 #else /* !NEW_LOGGING */
1555 Debug( LDAP_DEBUG_ANY,
1556 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1557 return_val, cm->total_entries, 0 );
1558 #endif /* !NEW_LOGGING */
1559 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1561 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1562 cm->num_cached_queries++;
1564 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1565 cm->num_cached_queries, 0, 0 );
1566 #else /* !NEW_LOGGING */
1567 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1568 cm->num_cached_queries, 0, 0 );
1569 #endif /* !NEW_LOGGING */
1570 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1572 return query_uuid.bv_val;
1578 struct berval* tempstr,
1586 i = qm->templates[template_id].attr_set_index;
1587 str = qm->templates[template_id].querystr;
1589 if (attr_set == i) {
1592 id_array = qm->attr_sets[attr_set].ID_array;
1594 while (*id_array != -1) {
1602 if (strcasecmp(str, tempstr->bv_val) == 0)
1608 consistency_check(Backend* be, Backend* glue_be, Connection* conn)
1610 struct metainfo *li = ( struct metainfo * )be->be_private;
1611 cache_manager* cm = li->cm;
1612 query_manager* qm = cm->qm;
1613 CachedQuery* query, *query_prev;
1616 struct exception result;
1618 QueryTemplate* templ;
1621 for (i=0; qm->templates[i].querystr; i++) {
1622 templ = qm->templates + i;
1623 query = templ->query_last;
1624 curr_time = slap_get_time();
1625 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1626 while (query && (query->expiry_time < curr_time)) {
1627 ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
1628 remove_query(qm, query);
1629 ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
1631 LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
1633 #else /* !NEW_LOGGING */
1634 Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
1636 #endif /* !NEW_LOGGING */
1637 ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
1638 remove_from_template(query, templ);
1640 LDAP_LOG( BACK_META, DETAIL1,
1641 "TEMPLATE %d QUERIES-- %d\n",
1642 i, templ->no_of_queries, 0 );
1643 #else /* !NEW_LOGGING */
1644 Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
1645 i, templ->no_of_queries, 0 );
1646 #endif /* !NEW_LOGGING */
1648 LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
1650 #else /* !NEW_LOGGING */
1651 Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
1653 #endif /* !NEW_LOGGING */
1654 ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
1655 uuid.bv_val = query->q_uuid;
1656 uuid.bv_len = strlen(query->q_uuid);
1657 return_val = remove_query_data(glue_be, conn,
1660 LDAP_LOG( BACK_META, DETAIL1,
1661 "STALE QUERY REMOVED, SIZE=%d\n",
1663 #else /* !NEW_LOGGING */
1664 Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
1666 #endif /* !NEW_LOGGING */
1667 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1668 cm->total_entries -= result.rc;
1669 cm->num_cached_queries--;
1671 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %d\n",
1672 cm->num_cached_queries, 0, 0 );
1673 #else /* !NEW_LOGGING */
1674 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %d\n",
1675 cm->num_cached_queries, 0, 0 );
1676 #endif /* !NEW_LOGGING */
1677 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1678 cm->cache_size = (return_val > cm->cache_size) ?
1679 0: (cm->cache_size-return_val);
1681 LDAP_LOG( BACK_META, DETAIL1,
1682 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1683 "entries\n", cm->cache_size,
1684 cm->total_entries, 0 );
1685 #else /* !NEW_LOGGING */
1686 Debug( LDAP_DEBUG_ANY,
1687 "STALE QUERY REMOVED, CACHE SIZE=%d bytes %d "
1688 "entries\n", cm->cache_size,
1689 cm->total_entries, 0 );
1690 #endif /* !NEW_LOGGING */
1692 query = query->prev;
1693 free_query(query_prev);
1695 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1705 AttributeName* attrs,
1707 LDAPControl** ctrls )
1709 slap_callback* cb = op->o_callback;
1710 Backend* be = (Backend*)(cb->sc_private);
1711 struct metainfo *li = ( struct metainfo * )be->be_private;
1714 struct exception result;
1721 rewriteSession( li->rwinfo,
1722 "cacheReturn", e->e_name.bv_val, conn, &ename, &result );
1723 ber_str2bv(ename, strlen(ename), 0, &e->e_name);
1724 ber_dupbv(&e->e_nname, &e->e_name);
1726 op->o_callback = NULL;
1727 send_search_entry(be, conn, op, e, attrs, attrsonly, ctrls);
1732 op->o_callback = cb;