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*
128 struct berval *nbase,
129 struct exception *result
134 AttributeName** newattrs,
135 AttributeName* attrs,
136 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,
220 meta_back_cache_search(
228 struct berval *nbase,
234 struct berval *filterstr,
235 AttributeName *attributes,
239 struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
241 struct metasingleconn *lsc;
242 cache_manager* cm = li->cm;
243 query_manager* qm = cm->qm;
247 int count, rc = 0, *msgid = NULL;
252 int i = -1, last = 0, candidates = 0, op_type;
254 struct berval mfilter;
255 struct berval cachebase = { 0L, NULL };
256 struct berval ncachebase = { 0L, NULL };
257 struct berval cache_suffix;
258 struct berval tempstr = { 0L, NULL };
260 AttributeName *filter_attrs = NULL;
261 AttributeName *new_attrs = NULL;
262 AttributeName *attrs = NULL;
265 Entry **entry_array = NULL;
270 int template_id = -1;
278 struct exception result[1];
280 Filter* filter = str2filter(op->ors_filterstr.bv_val);
281 slap_callback cb = {cache_back_sentry, NULL};
283 cb.sc_private = op->o_bd;
286 for ( count=0; op->ors_attrs[ count ].an_name.bv_val; count++ )
288 attrs = (AttributeName*)malloc( ( count + 1 ) *
289 sizeof(AttributeName));
290 for ( count=0; op->ors_attrs[ count ].an_name.bv_val; count++ ) {
291 ber_dupbv(&attrs[ count ].an_name,
292 &op->ors_attrs[ count ].an_name);
293 attrs[count].an_desc = op->ors_attrs[count].an_desc;
295 attrs[ count ].an_name.bv_val = NULL;
296 attrs[ count ].an_name.bv_len = 0;
299 result->type = SUCCESS;
301 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
304 LDAP_LOG( BACK_META, DETAIL1, "Threads++ = %d\n", cm->threads, 0, 0 );
305 #else /* !NEW_LOGGING */
306 Debug( LDAP_DEBUG_ANY, "Threads++ = %d\n", cm->threads, 0, 0 );
307 #endif /* !NEW_LOGGING */
308 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
310 filter2template(filter, &tempstr, &filter_attrs, &fattr_cnt, result);
311 if (result->type != SUCCESS)
315 LDAP_LOG( BACK_META, DETAIL1, "query template of incoming query = %s\n",
316 tempstr.bv_val, 0, 0 );
317 #else /* !NEW_LOGGING */
318 Debug( LDAP_DEBUG_ANY, "query template of incoming query = %s\n",
319 tempstr.bv_val, 0, 0 );
320 #endif /* !NEW_LOGGING */
321 curr_limit = cm->num_entries_limit ;
324 attr_set = get_attr_set(attrs, qm, cm->numattrsets);
326 query.filter = filter;
328 query.base = op->o_req_dn;
329 query.scope = op->ors_scope;
331 /* check for query containment */
333 for (i=0; i<cm->numtemplates; i++) {
334 /* find if template i can potentially answer tempstr */
335 if (!is_temp_answerable(attr_set, &tempstr, qm, i))
337 if (attr_set == qm->templates[i].attr_set_index) {
342 LDAP_LOG( BACK_META, DETAIL2,
343 "Entering QC, querystr = %s\n",
344 op->ors_filterstr.bv_val, 0, 0 );
345 #else /* !NEW_LOGGING */
346 Debug( LDAP_DEBUG_NONE, "Entering QC, querystr = %s\n",
347 op->ors_filterstr.bv_val, 0, 0 );
348 #endif /* !NEW_LOGGING */
349 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", op->o_req_dn.bv_val,
365 op->o_conn, &cbase, result);
366 if (result->type != SUCCESS) {
367 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
370 if ( cbase == NULL ) {
371 cachebase = op->o_req_dn;
373 cachebase.bv_val = cbase;
374 cachebase.bv_len = strlen(cbase);
376 dnNormalize(0, NULL, NULL, &cachebase, &ncachebase,
379 /* FIXME: safe default? */
382 op_tmp.o_bd = li->glue_be;
383 op_tmp.o_req_dn = cachebase;
384 op_tmp.o_req_ndn = ncachebase;
386 op_tmp.o_caching_on = 1;
387 op_tmp.o_callback = &cb;
389 li->glue_be->be_search(op, rs);
390 ber_memfree( ncachebase.bv_val );
391 if ( cachebase.bv_val != op->o_req_dn.bv_val ) {
392 /* free only if rewritten */
393 free( cachebase.bv_val );
396 ldap_pvt_thread_rdwr_runlock(&qm->templates[i].t_rwlock);
399 LDAP_LOG( BACK_META, DETAIL1, "QUERY NOT ANSWERABLE\n",
401 #else /* !NEW_LOGGING */
402 Debug( LDAP_DEBUG_ANY, "QUERY NOT ANSWERABLE\n", 0, 0, 0 );
403 #endif /* !NEW_LOGGING */
405 if ( op->ors_scope == LDAP_SCOPE_BASE ) {
406 op_type = META_OP_REQUIRE_SINGLE;
408 op_type = META_OP_ALLOW_MULTIPLE;
411 lc = metaConnect(op, rs, op_type,
412 &op->o_req_ndn, result);
414 if (result->type != SUCCESS)
417 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
418 if (cm->num_cached_queries >= cm->max_queries) {
421 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
425 LDAP_LOG( BACK_META, DETAIL1,
426 "QUERY TEMPLATE CACHEABLE\n",
428 #else /* !NEW_LOGGING */
429 Debug( LDAP_DEBUG_ANY, "QUERY TEMPLATE CACHEABLE\n",
431 #endif /* !NEW_LOGGING */
432 add_filter_attrs(&new_attrs, attrs, filter_attrs);
440 * Array of message id of each target
442 msgid = ch_calloc( sizeof( int ), li->ntargets );
443 if ( msgid == NULL ) {
444 result->type = CONN_ERR;
449 if (slimit > 0 && (slimit <= cm->num_entries_limit))
450 slimit = cm->num_entries_limit;
457 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); ++i, ++lsc ) {
458 char *realbase = ( char * )op->o_req_dn.bv_val;
459 int realscope = op->ors_scope;
461 char *mapped_filter, **mapped_attrs;
463 /* FIXME: Check for more than one targets */
464 if ( meta_back_is_candidate(
465 &li->targets[i]->suffix,
467 lsc->candidate = META_CANDIDATE;
469 if ( lsc->candidate != META_CANDIDATE )
472 if ( op->ors_deref != -1 ) {
473 ldap_set_option( lsc->ld, LDAP_OPT_DEREF,
474 ( void * )&op->ors_deref);
476 if ( op->ors_tlimit != -1 ) {
477 ldap_set_option( lsc->ld, LDAP_OPT_TIMELIMIT,
478 ( void * )&op->ors_tlimit);
480 if ( op->ors_slimit != -1 ) {
481 ldap_set_option( lsc->ld, LDAP_OPT_SIZELIMIT,
482 ( void * )&op->ors_slimit);
486 * modifies the base according to the scope, if required
488 suffixlen = li->targets[ i ]->suffix.bv_len;
489 if ( suffixlen > op->o_req_ndn.bv_len ) {
490 switch ( op->ors_scope ) {
491 case LDAP_SCOPE_SUBTREE:
493 * make the target suffix the new base
494 * FIXME: this is very forgiving,
495 * because illegal bases may be turned
496 * into the suffix of the target.
499 &li->targets[ i ]->suffix,
502 li->targets[i]->suffix.bv_val;
505 * this target is no longer
514 case LDAP_SCOPE_ONELEVEL:
515 if ( is_one_level_rdn(
516 li->targets[ i ]->suffix.bv_val,
517 suffixlen - op->o_req_ndn.bv_len - 1 )
519 &li->targets[ i ]->suffix,
522 * if there is exactly one
523 * level, make the target suffix
524 * the new base, and make scope
528 li->targets[i]->suffix.bv_val;
529 realscope = LDAP_SCOPE_BASE;
531 } /* else continue with the next case */
533 case LDAP_SCOPE_BASE:
535 * this target is no longer candidate
537 lsc->candidate = META_NOT_CANDIDATE;
543 * Rewrite the search base, if required
546 rewriteSession(li->targets[i]->rwmap.rwm_rw,
548 realbase, op->o_conn, &mbase, result);
550 if (result->type != SUCCESS)
553 if ( mbase == NULL ) {
558 * Rewrite the search filter, if required
560 rewriteSession( li->targets[i]->rwmap.rwm_rw,
562 op->ors_filterstr.bv_val, op->o_conn,
563 &mfilter.bv_val, result);
564 if (result->type != SUCCESS)
567 if ( mfilter.bv_val != NULL && mfilter.bv_val[ 0 ]
569 mfilter.bv_len = strlen( mfilter.bv_val );
571 if ( mfilter.bv_val != NULL ) {
572 free( mfilter.bv_val );
574 mfilter = op->ors_filterstr;
579 * Maps attributes in filter
581 mapped_filter = ldap_back_map_filter(
582 &li->targets[i]->rwmap.rwm_at,
583 &li->targets[i]->rwmap.rwm_oc,
585 if ( mapped_filter == NULL ) {
586 mapped_filter = ( char * )mfilter.bv_val;
588 if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
589 free( mfilter.bv_val );
592 mfilter.bv_val = NULL;
595 mapped_filter = (char *) mfilter.bv_val;
599 * Maps required attributes
601 if ( ldap_back_map_attrs(
602 &li->targets[ i ]->rwmap.rwm_at,
603 new_attrs, 0, &mapped_attrs ) ) {
610 msgid[ i ] = ldap_search( lsc->ld, mbase, realscope,
611 mapped_filter, mapped_attrs,
613 if ( msgid[ i ] == -1 ) {
614 lsc->candidate = META_NOT_CANDIDATE;
618 if ( mapped_attrs ) {
619 free( mapped_attrs );
623 if ( mapped_filter != op->ors_filterstr.bv_val ) {
624 free( mapped_filter );
625 mapped_filter = NULL;
628 if ( mbase != realbase ) {
636 num_entries = handleLdapResult(lc, op, rs, msgid,
638 op->ors_attrsonly, candidates,
639 cacheable, &entry_array,
640 curr_limit, op->ors_slimit, result);
642 if (result->type != SUCCESS)
644 if (cacheable && (num_entries <= curr_limit)) {
645 Operation op_tmp = *op;
648 LDAP_LOG( BACK_META, DETAIL1,
649 "QUERY CACHEABLE\n", 0, 0, 0 );
650 #else /* !NEW_LOGGING */
651 Debug( LDAP_DEBUG_ANY, "QUERY CACHEABLE\n", 0, 0, 0 );
652 #endif /* !NEW_LOGGING */
653 op_tmp.o_bd = li->glue_be;
654 uuid = cache_entries(&op_tmp, rs, entry_array,
657 LDAP_LOG( BACK_META, DETAIL1,
658 "Added query %s UUID %s ENTRIES %d\n",
659 op->ors_filterstr.bv_val,
661 #else /* !NEW_LOGGING */
662 Debug( LDAP_DEBUG_ANY,
663 "Added query %s UUID %s ENTRIES %d\n",
664 op->ors_filterstr.bv_val,
666 #endif /* !NEW_LOGGING */
668 if (result->type != SUCCESS)
670 (*(qm->addfunc))(qm, &query, template_id, uuid, result);
671 if (result->type != SUCCESS)
679 switch (result->type) {
686 LDAP_LOG( BACK_META, DETAIL1,
687 "Invalid template error\n", 0, 0, 0 );
688 #else /* !NEW_LOGGING */
689 Debug( LDAP_DEBUG_ANY, "Invalid template error\n",
691 #endif /* !NEW_LOGGING */
697 LDAP_LOG( BACK_META, DETAIL1,
698 "Could not connect to a remote server\n",
700 #else /* !NEW_LOGGING */
701 Debug( LDAP_DEBUG_ANY,
702 "Could not connect to a remote server\n",
704 #endif /* !NEW_LOGGING */
705 send_ldap_error(op, rs, LDAP_OTHER,
706 "Connection error" );
712 LDAP_LOG( BACK_META, DETAIL1,
713 "Error in handling ldap_result\n", 0, 0, 0 );
714 #else /* !NEW_LOGGING */
715 Debug( LDAP_DEBUG_ANY,
716 "Error in handling ldap_result\n", 0, 0, 0 );
717 #endif /* !NEW_LOGGING */
722 if (result->rc == REWRITE_REGEXEC_UNWILLING) {
723 send_ldap_error( op, rs,
724 LDAP_UNWILLING_TO_PERFORM,
725 "Unwilling to perform" );
727 send_ldap_error( op, rs, LDAP_OTHER,
735 LDAP_LOG( BACK_META, DETAIL1,
736 "Error in merging entry \n", 0, 0, 0 );
737 #else /* !NEW_LOGGING */
738 Debug( LDAP_DEBUG_ANY,
739 "Error in merging entry \n", 0, 0, 0 );
740 #endif /* !NEW_LOGGING */
746 LDAP_LOG( BACK_META, DETAIL1,
747 "Error in removing query \n",
749 #else /* !NEW_LOGGING */
750 Debug( LDAP_DEBUG_ANY, "Error in removing query \n",
752 #endif /* !NEW_LOGGING */
760 ldap_pvt_thread_mutex_lock(&cm->consistency_mutex);
761 curr_time = slap_get_time();
762 if (curr_time - cm->consistency_time > cm->consistency_cycle_time) {
763 cm->consistency_time = curr_time;
764 consistency_check(op, rs, li->glue_be);
766 ldap_pvt_thread_mutex_unlock(&cm->consistency_mutex);
772 for (i=0; (e = entry_array[i]); i++) {
781 if (new_attrs != attrs)
788 if (tempstr.bv_val ) {
789 free(tempstr.bv_val);
791 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
794 LDAP_LOG( BACK_META, DETAIL1, "Threads-- = %d\n", cm->threads, 0, 0 );
795 #else /* !NEW_LOGGING */
796 Debug( LDAP_DEBUG_ANY, "Threads-- = %d\n", cm->threads, 0, 0 );
797 #endif /* !NEW_LOGGING */
798 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
809 struct exception* result
812 struct metainfo *li = ( struct metainfo * )be->be_private;
813 struct berval a, mapped;
815 BerElement ber = *e->lm_ber;
816 Attribute *attr, **attrp;
817 struct berval dummy = { 0, NULL };
818 struct berval *bv, bdn;
821 if ( ber_scanf( &ber, "{m{", &bdn ) == LBER_ERROR ) {
822 result->type = CREATE_ENTRY_ERR;
825 ent = (Entry*)malloc(sizeof(Entry));
828 * Rewrite the dn of the result, if needed
830 rewriteSession( li->targets[ target ]->rwmap.rwm_rw, "searchResult",
831 bdn.bv_val, lc->conn, &ent->e_name.bv_val, result );
833 if (result->type != SUCCESS) {
836 if ( ent->e_name.bv_val == NULL ) {
837 ber_dupbv(&(ent->e_name), &bdn);
840 LDAP_LOG( BACK_META, DETAIL1,
841 "[rw] searchResult[%d]: \"%s\" -> \"%s\"\n",
842 target, bdn.bv_val, ent->e_name.bv_val );
843 #else /* !NEW_LOGGING */
844 Debug( LDAP_DEBUG_ARGS, "rw> searchResult[%d]: \"%s\""
846 target, bdn.bv_val, ent->e_name.bv_val );
847 #endif /* !NEW_LOGGING */
848 ent->e_name.bv_len = strlen( ent->e_name.bv_val );
852 * Note: this may fail if the target host(s) schema differs
853 * from the one known to the meta, and a DN with unknown
854 * attributes is returned.
856 * FIXME: should we log anything, or delegate to dnNormalize?
858 dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname, NULL );
861 if ( dnNormalize( 0, NULL, NULL, &ent->e_name, &ent->e_nname )
864 return LDAP_INVALID_DN_SYNTAX;
871 if ( li->cache.ttl != META_DNCACHE_DISABLED ) {
872 meta_dncache_update_entry( &li->cache, &ent->e_nname, target );
878 ent->e_bv.bv_val = 0;
880 attrp = &ent->e_attrs;
882 while ( ber_scanf( &ber, "{m", &a ) != LBER_ERROR ) {
883 ldap_back_map( &li->targets[ target ]->rwmap.rwm_at,
885 if ( mapped.bv_val == NULL ) {
888 attr = ( Attribute * )ch_malloc( sizeof( Attribute ) );
889 if ( attr == NULL ) {
895 if ( slap_bv2ad( &mapped, &attr->a_desc, &text ) != LDAP_SUCCESS) {
896 if ( slap_bv2undef_ad( &mapped, &attr->a_desc, &text )
899 LDAP_LOG( BACK_META, DETAIL1,
900 "slap_bv2undef_ad(%s): %s\n",
901 mapped.bv_val, text, 0 );
902 #else /* !NEW_LOGGING */
903 Debug( LDAP_DEBUG_ANY,
904 "slap_bv2undef_ad(%s): "
905 "%s\n%s", mapped.bv_val, text, "" );
906 #endif /* !NEW_LOGGING */
912 /* no subschemaSubentry */
913 if ( attr->a_desc == slap_schema.si_ad_subschemaSubentry ) {
918 if ( ber_scanf( &ber, "[W]", &attr->a_vals ) == LBER_ERROR
919 || attr->a_vals == NULL ) {
920 attr->a_vals = &dummy;
921 } else if ( attr->a_desc == slap_schema.si_ad_objectClass ||
923 slap_schema.si_ad_structuralObjectClass) {
925 for ( last = 0; attr->a_vals[ last ].bv_val; ++last )
927 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
928 ldap_back_map( &li->targets[ target]->rwmap.rwm_oc,
930 if ( mapped.bv_val == NULL ) {
936 *bv = attr->a_vals[ last ];
937 attr->a_vals[ last ].bv_val = NULL;
939 } else if ( mapped.bv_val != bv->bv_val ) {
941 ber_dupbv( bv, &mapped );
945 * It is necessary to try to rewrite attributes with
946 * dn syntax because they might be used in ACLs as
947 * members of groups; since ACLs are applied to the
948 * rewritten stuff, no dn-based subecj clause could
949 * be used at the ldap backend side (see
950 * http://www.OpenLDAP.org/faq/data/cache/452.html)
951 * The problem can be overcome by moving the dn-based
952 * ACLs to the target directory server, and letting
953 * everything pass thru the ldap backend.
955 } else if ( strcmp( attr->a_desc->ad_type->sat_syntax->ssyn_oid,
956 SLAPD_DN_SYNTAX ) == 0 ) {
958 for ( i = 0, bv = attr->a_vals; bv->bv_val; bv++,i++ ) {
960 rewriteSession(li->targets[ target ]->rwmap.rwm_rw,
961 "searchResult", bv->bv_val,
962 lc->conn, &newval, result);
963 if (result->type != SUCCESS) {
964 /* FIXME : Handle error */
965 result->type = SUCCESS;
968 if ( newval == NULL ) {
972 LDAP_LOG( BACK_META, DETAIL1,
973 "[rw] searchResult on "
974 "attr=%s: \"%s\" -> \"%s\"\n",
975 attr->a_desc->ad_type->
977 bv->bv_val, newval );
978 #else /* !NEW_LOGGING */
979 Debug( LDAP_DEBUG_ARGS,
980 "rw> searchResult on attr=%s:"
981 " \"%s\" -> \"%s\"\n",
982 attr->a_desc->ad_type->
984 bv->bv_val, newval );
985 #endif /* !NEW_LOGGING */
988 bv->bv_len = strlen( newval );
993 attrp = &attr->a_next;
1005 if ( DN_SEPARATOR( rdn[ from ] ) ) {
1012 static struct metaconn*
1017 struct berval *nbase,
1018 struct exception *result)
1020 struct metaconn *lc;
1022 result->type = SUCCESS;
1023 lc = meta_back_getconn( op, rs, op_type, nbase, NULL );
1025 result->type = CONN_ERR;
1033 AttributeName** new_attrs,
1034 AttributeName* attrs,
1035 AttributeName* filter_attrs )
1037 struct berval all_user = { sizeof(LDAP_ALL_USER_ATTRIBUTES) -1,
1038 LDAP_ALL_USER_ATTRIBUTES };
1040 struct berval all_op = { sizeof(LDAP_ALL_OPERATIONAL_ATTRIBUTES) -1,
1041 LDAP_ALL_OPERATIONAL_ATTRIBUTES};
1048 /* duplicate attrs */
1049 for (count=0; attrs[count].an_name.bv_val; count++)
1051 *new_attrs = (AttributeName*)(malloc((count+1)*sizeof(AttributeName)));
1052 for (i=0; i<count; i++) {
1054 ber_dupbv(&((*new_attrs)[i].an_name), &(attrs[i].an_name));
1056 (*new_attrs)[i].an_name = attrs[i].an_name;
1057 (*new_attrs)[i].an_desc = attrs[i].an_desc;
1059 (*new_attrs)[count].an_name.bv_val = NULL;
1060 (*new_attrs)[count].an_name.bv_len = 0;
1063 if ((*new_attrs)[0].an_name.bv_val == NULL) {
1064 *new_attrs = (AttributeName*)(malloc(2*sizeof(AttributeName)));
1065 (*new_attrs)[0].an_name.bv_val = "*";
1066 (*new_attrs)[0].an_name.bv_len = 1;
1067 (*new_attrs)[1].an_name.bv_val = NULL;
1068 (*new_attrs)[1].an_name.bv_len = 0;
1072 alluser = an_find(*new_attrs, &all_user);
1073 allop = an_find(*new_attrs, &all_op);
1076 for ( i=0; filter_attrs[i].an_name.bv_val; i++ ) {
1077 if ( an_find(*new_attrs, &filter_attrs[i].an_name ))
1079 if ( is_at_operational(filter_attrs[i].an_desc->ad_type)
1084 *new_attrs = (AttributeName*)(realloc(*new_attrs,
1085 (count+2)*sizeof(AttributeName)));
1086 (*new_attrs)[count].an_name.bv_val =
1087 filter_attrs[i].an_name.bv_val;
1088 (*new_attrs)[count].an_name.bv_len =
1089 filter_attrs[i].an_name.bv_len;
1090 (*new_attrs)[count].an_desc = filter_attrs[i].an_desc;
1091 (*new_attrs)[count+1].an_name.bv_val = NULL;
1092 (*new_attrs)[count+1].an_name.bv_len = 0;
1099 struct metaconn* lc,
1102 int* msgid, Backend* be,
1103 AttributeName* attrs,
1107 Entry*** entry_array,
1110 struct exception* result)
1113 char *match = NULL, *err = NULL, *cache_ename = NULL;
1115 int mres = LDAP_SUCCESS;
1116 int num_entries = 0, count, i, rc;
1117 struct timeval tv = {0, 0};
1118 struct metasingleconn* lsc;
1119 struct metainfo *li = ( struct metainfo * )be->be_private;
1121 result->type = SUCCESS;
1123 for ( count = 0, rc = 0; candidates > 0; ) {
1126 /* check for abandon */
1129 for ( i = 0, lsc = lc->conns; !META_LAST(lsc); lsc++, i++ ) {
1130 if ( lsc->candidate != META_CANDIDATE ) {
1135 ldap_abandon( lsc->ld, msgid[ i ] );
1136 result->type = ABANDON_ERR;
1140 if ( slimit > 0 && num_entries == slimit ) {
1141 result->type = SLIMIT_ERR;
1145 if ((entry = get_result_entry(be, lc, lsc,
1146 msgid, i, &tv, result))) {
1147 rs->sr_entry = entry;
1148 send_search_entry( op, rs );
1149 rs->sr_entry = NULL;
1151 (num_entries < curr_limit)) {
1152 rewriteSession( li->rwinfo,
1154 entry->e_name.bv_val,
1156 &cache_ename, result );
1157 free(entry->e_name.bv_val);
1158 if (result->type != SUCCESS) {
1161 ber_str2bv(cache_ename,
1162 strlen(cache_ename),
1164 ber_dupbv(&entry->e_nname,
1166 *entry_array = (Entry**)realloc(
1168 (( num_entries+2 ) *
1170 (*entry_array)[num_entries] = entry;
1171 (*entry_array)[num_entries+1] = NULL;
1175 } else if (result->type == REWRITING_ERR) {
1177 } else if (result->type == TIMEOUT_ERR) {
1178 result->type = SUCCESS;
1180 } else if (result->type == CREATE_ENTRY_ERR) {
1182 } else if (result->rc == -1) {
1185 rs->sr_err = result->rc;
1186 sres = ldap_back_map_result(rs);
1187 if (mres == LDAP_SUCCESS &&
1188 sres != LDAP_SUCCESS) {
1190 ldap_get_option(lsc->ld,
1191 LDAP_OPT_ERROR_STRING, &err);
1192 ldap_get_option(lsc->ld,
1193 LDAP_OPT_MATCHED_DN, &match);
1195 lsc->candidate = META_NOT_CANDIDATE;
1197 result->type = SUCCESS;
1200 switch (result->type) {
1203 LDAP_LOG( BACK_META, DETAIL1,
1204 "ldap_result error, rc = -1\n",
1206 #else /* !NEW_LOGGING */
1207 Debug( LDAP_DEBUG_ANY, "ldap_result error, rc = -1\n",
1209 #endif /* !NEW_LOGGING */
1210 rs->sr_err = LDAP_OTHER;
1211 send_ldap_result( op, rs );
1214 case CREATE_ENTRY_ERR:
1216 LDAP_LOG( BACK_META, DETAIL1,
1217 "Error in parsing result \n",
1219 #else /* !NEW_LOGGING */
1220 Debug( LDAP_DEBUG_ANY, "Error in parsing result \n",
1222 #endif /* !NEW_LOGGING */
1223 rs->sr_err = LDAP_OTHER;
1224 send_ldap_result( op, rs );
1225 result->type = RESULT_ERR;
1230 LDAP_LOG( BACK_META, DETAIL1, "Size limit exceeded \n",
1232 #else /* !NEW_LOGGING */
1233 Debug( LDAP_DEBUG_ANY, "Size limit exceeded \n",
1235 #endif /* !NEW_LOGGING */
1236 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
1237 send_ldap_result( op, rs );
1238 result->type = RESULT_ERR;
1243 LDAP_LOG( BACK_META, DETAIL1,
1244 "search operation abandoned \n",
1246 #else /* !NEW_LOGGING */
1247 Debug( LDAP_DEBUG_ANY, "search operation abandoned \n",
1249 #endif /* !NEW_LOGGING */
1250 result->type = RESULT_ERR;
1259 tv.tv_usec = 100000;
1260 ldap_pvt_thread_yield();
1269 rs->sr_matched = match;
1271 send_ldap_result( op, rs );
1274 rs->sr_matched = NULL;
1282 result->type = (mres == LDAP_SUCCESS) ? SUCCESS : RESULT_ERR;
1289 struct metaconn* lc,
1290 struct metasingleconn* lsc,
1294 struct exception* result)
1297 LDAPMessage *res, *e;
1299 int sres = LDAP_SUCCESS;
1301 rc = ldap_result( lsc->ld, msgid[ i ],
1305 result->type = TIMEOUT_ERR;
1307 } else if ( rc == -1 ) {
1309 result->type = RESULT_ERR;
1311 } else if ( rc == LDAP_RES_SEARCH_ENTRY ) {
1312 e = ldap_first_entry( lsc->ld, res );
1313 entry = meta_create_entry(be, lc, i, e, result);
1317 ldap_msgfree( res );
1318 result->type = SUCCESS;
1321 sres = ldap_result2error( lsc->ld,
1324 result->type = RESULT_ERR;
1331 struct rewrite_info* info,
1332 const char* rewriteContext,
1336 struct exception* result)
1338 int rc = rewrite_session(info, rewriteContext, string, cookie, base);
1339 if (rc != REWRITE_REGEXEC_OK) {
1341 result->type = REWRITING_ERR;
1343 if (strcmp(rewriteContext, "searchBase") == 0)
1345 LDAP_LOG( BACK_META, DETAIL1,
1346 "Problem in rewriting search base\n", 0, 0, 0 );
1347 #else /* !NEW_LOGGING */
1348 Debug( LDAP_DEBUG_ANY,
1349 "Problem in rewriting search base\n", 0, 0, 0 );
1350 #endif /* !NEW_LOGGING */
1351 if (strcmp(rewriteContext, "searchFilter") == 0)
1353 LDAP_LOG( BACK_META, DETAIL1,
1354 "Problem in rewriting search filter\n",
1356 #else /* !NEW_LOGGING */
1357 Debug( LDAP_DEBUG_ANY,
1358 "Problem in rewriting search filter\n",
1360 #endif /* !NEW_LOGGING */
1361 if (strcmp(rewriteContext, "searchResult") == 0)
1363 LDAP_LOG( BACK_META, DETAIL1,
1364 "Problem in rewriting DN, or DN syntax "
1365 "attributes of search result\n", 0, 0, 0 );
1366 #else /* !NEW_LOGGING */
1367 Debug( LDAP_DEBUG_ANY,
1368 "Problem in rewriting DN, or DN syntax "
1369 "attributes of search result\n", 0, 0, 0 );
1370 #endif /* !NEW_LOGGING */
1371 if (strcmp(rewriteContext, "cacheBase") == 0)
1373 LDAP_LOG( BACK_META, DETAIL1,
1374 "Problem in rewriting search base with "
1375 "cache base\n", 0, 0, 0 );
1376 #else /* !NEW_LOGGING */
1377 Debug( LDAP_DEBUG_ANY,
1378 "Problem in rewriting search base with "
1379 "cache base\n", 0, 0, 0 );
1380 #endif /* !NEW_LOGGING */
1381 if (strcmp(rewriteContext, "cacheResult") == 0)
1383 LDAP_LOG( BACK_META, DETAIL1,
1384 "Problem in rewriting DN for cached entries\n",
1386 #else /* !NEW_LOGGING */
1387 Debug( LDAP_DEBUG_ANY,
1388 "Problem in rewriting DN for cached entries\n",
1390 #endif /* !NEW_LOGGING */
1391 if (strcmp(rewriteContext, "cacheReturn") == 0)
1393 LDAP_LOG( BACK_META, DETAIL1,
1394 "Problem in rewriting DN for answerable "
1395 "entries\n", 0, 0, 0 );
1396 #else /* !NEW_LOGGING */
1397 Debug( LDAP_DEBUG_ANY,
1398 "Problem in rewriting DN for answerable "
1399 "entries\n", 0, 0, 0 );
1400 #endif /* !NEW_LOGGING */
1402 result->type = SUCCESS;
1408 AttributeName* attrs,
1413 for (i=0; i<num; i++) {
1414 if (attrscmp(attrs, qm->attr_sets[i].attrs))
1422 AttributeName* attrs_in,
1423 AttributeName* attrs)
1425 int i, count1, count2;
1426 if ((attrs_in==NULL) || (attrs==NULL))
1429 attrs_in && attrs_in[count1].an_name.bv_val != NULL;
1433 attrs && attrs[count2].an_name.bv_val != NULL;
1436 if ( count1 != count2 )
1439 for ( i=0; i<count1; i++ ) {
1440 if ( !an_find(attrs, &attrs_in[i].an_name ))
1450 Entry** entry_array,
1452 struct exception* result)
1458 struct berval query_uuid;
1459 struct berval crp_uuid;
1460 char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ], *crpid;
1462 query_manager *qm = cm->qm;
1464 result->type = SUCCESS;
1465 query_uuid.bv_len = lutil_uuidstr(uuidbuf, sizeof(uuidbuf));
1466 query_uuid.bv_val = ch_strdup(uuidbuf);
1469 LDAP_LOG( BACK_META, DETAIL1, "UUID for query being added = %s\n",
1471 #else /* !NEW_LOGGING */
1472 Debug( LDAP_DEBUG_ANY, "UUID for query being added = %s\n",
1474 #endif /* !NEW_LOGGING */
1476 for ( i=0; ( entry_array && (e=entry_array[i]) ); i++ ) {
1478 LDAP_LOG( BACK_META, DETAIL2, "LOCKING REMOVE MUTEX\n",
1480 #else /* !NEW_LOGGING */
1481 Debug( LDAP_DEBUG_NONE, "LOCKING REMOVE MUTEX\n", 0, 0, 0 );
1482 #endif /* !NEW_LOGGING */
1483 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1485 LDAP_LOG( BACK_META, DETAIL2, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1486 #else /* !NEW_LOGGING */
1487 Debug( LDAP_DEBUG_NONE, "LOCKED REMOVE MUTEX\n", 0, 0, 0);
1488 #endif /* !NEW_LOGGING */
1489 if ( cm->cache_size > (cm->thresh_hi) ) {
1490 while(cm->cache_size > (cm->thresh_lo)) {
1491 crpid = cache_replacement(qm);
1492 if (crpid == NULL) {
1493 result->type = REMOVE_ERR;
1495 strcpy(crpuuid, crpid);
1496 crp_uuid.bv_val = crpuuid;
1497 crp_uuid.bv_len = strlen(crpuuid);
1499 LDAP_LOG( BACK_META, DETAIL1,
1500 "Removing query UUID %s\n",
1502 #else /* !NEW_LOGGING */
1503 Debug( LDAP_DEBUG_ANY,
1504 "Removing query UUID %s\n",
1506 #endif /* !NEW_LOGGING */
1507 return_val = remove_query_data(op, rs,
1510 LDAP_LOG( BACK_META, DETAIL1,
1511 "QUERY REMOVED, SIZE=%d\n",
1513 #else /* !NEW_LOGGING */
1514 Debug( LDAP_DEBUG_ANY,
1515 "QUERY REMOVED, SIZE=%d\n",
1517 #endif /* !NEW_LOGGING */
1518 ldap_pvt_thread_mutex_lock(
1520 cm->total_entries -= result->rc;
1521 cm->num_cached_queries--;
1523 LDAP_LOG( BACK_META, DETAIL1,
1524 "STORED QUERIES = %lu\n",
1525 cm->num_cached_queries, 0, 0 );
1526 #else /* !NEW_LOGGING */
1527 Debug( LDAP_DEBUG_ANY,
1528 "STORED QUERIES = %lu\n",
1529 cm->num_cached_queries, 0, 0 );
1530 #endif /* !NEW_LOGGING */
1531 ldap_pvt_thread_mutex_unlock(
1533 cm->cache_size = (return_val >
1535 0 : (cm->cache_size-return_val);
1537 LDAP_LOG( BACK_META, DETAIL1,
1538 "QUERY REMOVED, CACHE SIZE="
1539 "%lu bytes %d entries\n",
1541 cm->total_entries, 0 );
1542 #else /* !NEW_LOGGING */
1543 Debug( LDAP_DEBUG_ANY,
1544 "QUERY REMOVED, CACHE SIZE="
1545 "%lu bytes %d entries\n",
1547 cm->total_entries, 0 );
1548 #endif /* !NEW_LOGGING */
1554 return_val = merge_entry(op, rs, &query_uuid, result);
1555 rs->sr_entry = NULL;
1556 cm->cache_size += return_val;
1558 LDAP_LOG( BACK_META, DETAIL1,
1559 "ENTRY ADDED/MERGED, CACHE SIZE=%lu bytes\n",
1560 cm->cache_size, 0, 0 );
1561 #else /* !NEW_LOGGING */
1562 Debug( LDAP_DEBUG_ANY,
1563 "ENTRY ADDED/MERGED, CACHE SIZE=%lu bytes\n",
1564 cm->cache_size, 0, 0 );
1565 #endif /* !NEW_LOGGING */
1567 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKING REMOVE MUTEX\n",
1569 #else /* !NEW_LOGGING */
1570 Debug( LDAP_DEBUG_NONE, "UNLOCKING REMOVE MUTEX\n", 0, 0, 0 );
1571 #endif /* !NEW_LOGGING */
1572 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1574 LDAP_LOG( BACK_META, DETAIL2, "UNLOCKED REMOVE MUTEX\n",
1576 #else /* !NEW_LOGGING */
1577 Debug( LDAP_DEBUG_NONE, "UNLOCKED REMOVE MUTEX\n", 0, 0, 0 );
1578 #endif /* !NEW_LOGGING */
1579 if (result->type != SUCCESS)
1581 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1582 cm->total_entries += result->rc;
1584 LDAP_LOG( BACK_META, DETAIL1,
1585 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1586 return_val, cm->total_entries, 0 );
1587 #else /* !NEW_LOGGING */
1588 Debug( LDAP_DEBUG_ANY,
1589 "ENTRY ADDED/MERGED, SIZE=%d, CACHED ENTRIES=%d\n",
1590 return_val, cm->total_entries, 0 );
1591 #endif /* !NEW_LOGGING */
1592 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1594 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1595 cm->num_cached_queries++;
1597 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
1598 cm->num_cached_queries, 0, 0 );
1599 #else /* !NEW_LOGGING */
1600 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
1601 cm->num_cached_queries, 0, 0 );
1602 #endif /* !NEW_LOGGING */
1603 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1605 return query_uuid.bv_val;
1611 struct berval* tempstr,
1619 i = qm->templates[template_id].attr_set_index;
1620 str = qm->templates[template_id].querystr;
1622 if (attr_set == i) {
1625 id_array = qm->attr_sets[attr_set].ID_array;
1627 while (*id_array != -1) {
1635 if (strcasecmp(str, tempstr->bv_val) == 0)
1641 consistency_check(Operation *op, SlapReply *rs, Backend* glue_be)
1643 struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
1644 cache_manager* cm = li->cm;
1645 query_manager* qm = cm->qm;
1646 CachedQuery* query, *query_prev;
1649 struct exception result;
1651 QueryTemplate* templ;
1652 Backend *be = op->o_bd;
1656 for (i=0; qm->templates[i].querystr; i++) {
1657 templ = qm->templates + i;
1658 query = templ->query_last;
1659 curr_time = slap_get_time();
1660 ldap_pvt_thread_mutex_lock(&cm->remove_mutex);
1661 while (query && (query->expiry_time < curr_time)) {
1662 ldap_pvt_thread_mutex_lock(&qm->lru_mutex);
1663 remove_query(qm, query);
1664 ldap_pvt_thread_mutex_unlock(&qm->lru_mutex);
1666 LDAP_LOG( BACK_META, DETAIL1, "Lock CR index = %d\n",
1668 #else /* !NEW_LOGGING */
1669 Debug( LDAP_DEBUG_ANY, "Lock CR index = %d\n",
1671 #endif /* !NEW_LOGGING */
1672 ldap_pvt_thread_rdwr_wlock(&templ->t_rwlock);
1673 remove_from_template(query, templ);
1675 LDAP_LOG( BACK_META, DETAIL1,
1676 "TEMPLATE %d QUERIES-- %d\n",
1677 i, templ->no_of_queries, 0 );
1678 #else /* !NEW_LOGGING */
1679 Debug( LDAP_DEBUG_ANY, "TEMPLATE %d QUERIES-- %d\n",
1680 i, templ->no_of_queries, 0 );
1681 #endif /* !NEW_LOGGING */
1683 LDAP_LOG( BACK_META, DETAIL1, "Unlock CR index = %d\n",
1685 #else /* !NEW_LOGGING */
1686 Debug( LDAP_DEBUG_ANY, "Unlock CR index = %d\n",
1688 #endif /* !NEW_LOGGING */
1689 ldap_pvt_thread_rdwr_wunlock(&templ->t_rwlock);
1690 uuid.bv_val = query->q_uuid;
1691 uuid.bv_len = strlen(query->q_uuid);
1692 return_val = remove_query_data(op, rs, &uuid, &result);
1694 LDAP_LOG( BACK_META, DETAIL1,
1695 "STALE QUERY REMOVED, SIZE=%d\n",
1697 #else /* !NEW_LOGGING */
1698 Debug( LDAP_DEBUG_ANY, "STALE QUERY REMOVED, SIZE=%d\n",
1700 #endif /* !NEW_LOGGING */
1701 ldap_pvt_thread_mutex_lock(&cm->cache_mutex);
1702 cm->total_entries -= result.rc;
1703 cm->num_cached_queries--;
1705 LDAP_LOG( BACK_META, DETAIL1, "STORED QUERIES = %lu\n",
1706 cm->num_cached_queries, 0, 0 );
1707 #else /* !NEW_LOGGING */
1708 Debug( LDAP_DEBUG_ANY, "STORED QUERIES = %lu\n",
1709 cm->num_cached_queries, 0, 0 );
1710 #endif /* !NEW_LOGGING */
1711 ldap_pvt_thread_mutex_unlock(&cm->cache_mutex);
1712 cm->cache_size = (return_val > cm->cache_size) ?
1713 0: (cm->cache_size-return_val);
1715 LDAP_LOG( BACK_META, DETAIL1,
1716 "STALE QUERY REMOVED, CACHE SIZE=%lu bytes %d "
1717 "entries\n", cm->cache_size,
1718 cm->total_entries, 0 );
1719 #else /* !NEW_LOGGING */
1720 Debug( LDAP_DEBUG_ANY,
1721 "STALE QUERY REMOVED, CACHE SIZE=%lu bytes %d "
1722 "entries\n", cm->cache_size,
1723 cm->total_entries, 0 );
1724 #endif /* !NEW_LOGGING */
1726 query = query->prev;
1727 free_query(query_prev);
1729 ldap_pvt_thread_mutex_unlock(&cm->remove_mutex);
1740 slap_callback *cb = op->o_callback;
1741 struct metainfo *li = ( struct metainfo * )op->o_bd->be_private;
1744 struct exception result;
1748 dn = rs->sr_entry->e_name;
1749 ndn = rs->sr_entry->e_nname;
1751 rewriteSession( li->rwinfo, "cacheReturn",
1752 rs->sr_entry->e_name.bv_val, op->o_conn,
1754 ber_str2bv(ename, strlen(ename), 0, &rs->sr_entry->e_name);
1755 /* FIXME: should we normalize this? */
1756 ber_dupbv(&rs->sr_entry->e_nname, &rs->sr_entry->e_name);
1758 op->o_callback = NULL;
1760 send_search_entry( op, rs );
1762 rs->sr_entry->e_name = dn;
1763 rs->sr_entry->e_nname = ndn;
1765 op->o_callback = cb;