/* Copyright (c) 2003 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ #include "portable.h" #include #include #include #include #include "slap.h" #include "ldif.h" #include "../back-ldap/back-ldap.h" #include "back-meta.h" #include "ldap_pvt.h" #undef ldap_debug /* silence a warning in ldap-int.h */ #include "ldap_log.h" #include "../../../libraries/libldap/ldap-int.h" #include static struct berval bv_queryid_any = BER_BVC( "(queryid=*)" ); static Attribute* add_attribute(AttributeDescription *ad, Entry* e, BerVarray value_array ); static int null_response ( Operation *op, SlapReply *rs ); static int normalize_values( Attribute* attr ); struct entry_info { int size_init; int size_final; int added; Entry* entry; struct berval* uuid; struct timeval tv; /* time */ enum type_of_result err; Backend* glue_be; }; int get_entry_size( Entry* e, int size_init, struct exception* result ) { Attribute *a; struct berval bv; int i; int tmplen; int size=0; if ( result ) result->type = SUCCESS; if ( e->e_dn != NULL ) { tmplen = strlen( e->e_dn ); size = LDIF_SIZE_NEEDED( 2, tmplen ); } for ( a = e->e_attrs; a != NULL; a = a->a_next ) { for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { bv = a->a_vals[i]; tmplen = a->a_desc->ad_cname.bv_len; size += LDIF_SIZE_NEEDED( tmplen, bv.bv_len); } } if ((size < size_init) && result) { result->type = SIZE_ERR; } return size; } int merge_entry( Operation *op, SlapReply *rs, struct berval* query_uuid, struct exception* result ) { struct entry_info info; int rc; Modifications* modlist = NULL; const char* text = NULL; BerVarray value_array; Attribute *uuid_attr, *attr; Entry *e; SlapReply sreply = {REP_RESULT}; Operation op_tmp = *op; slap_callback cb; sreply.sr_entry = NULL; sreply.sr_nentries = 0; e = ( Entry * ) ch_calloc( 1, sizeof( Entry )); dnPrettyNormal(0, &rs->sr_entry->e_name, &e->e_name, &e->e_nname, op->o_tmpmemctx); e->e_private = NULL; e->e_attrs = NULL; e->e_bv.bv_val = NULL; /* add queryid attribute */ value_array = (struct berval *)malloc(2 * sizeof( struct berval) ); ber_dupbv(value_array, query_uuid); value_array[1].bv_val = NULL; value_array[1].bv_len = 0; uuid_attr = add_attribute(slap_schema.si_ad_queryid, e, value_array); /* append the attribute list from the fetched entry */ uuid_attr->a_next = rs->sr_entry->e_attrs; rs->sr_entry->e_attrs = NULL; for ( attr = e->e_attrs; attr; attr = attr->a_next ) { if ( normalize_values( attr ) ) { info.err = MERGE_ERR; result->rc = info.err; return 0; } } info.entry = e; info.uuid = query_uuid; info.size_init = get_entry_size( rs->sr_entry, 0, 0 ); info.size_final = 0; info.added = 0; info.glue_be = op->o_bd; info.err = SUCCESS; cb.sc_private = &info; cb.sc_response = null_response; op_tmp.o_tag = LDAP_REQ_ADD; op_tmp.o_protocol = LDAP_VERSION3; op_tmp.o_callback = &cb; op_tmp.o_time = slap_get_time(); op_tmp.o_do_not_cache = 1; op_tmp.ora_e = e; op_tmp.o_req_dn = e->e_name; op_tmp.o_req_ndn = e->e_nname; rc = op->o_bd->be_add( &op_tmp, &sreply ); if ( rc != LDAP_SUCCESS ) { if ( rc == LDAP_ALREADY_EXISTS ) { slap_entry2mods( e, &modlist, &text ); op_tmp.o_tag = LDAP_REQ_MODIFY; op_tmp.orm_modlist = modlist; op_tmp.o_req_dn = e->e_name; op_tmp.o_req_ndn = e->e_nname; rc = op->o_bd->be_modify( &op_tmp, &sreply ); result->rc = info.added; } else if ( rc == LDAP_REFERRAL || rc == LDAP_NO_SUCH_OBJECT ) { slap_entry2mods( e, &modlist, &text ); syncrepl_add_glue( NULL, NULL, &op_tmp, e, modlist, 0, NULL, NULL ); result->rc = info.added; } else { result->rc = 0; } if ( modlist != NULL ) slap_mods_free( modlist ); } else { info.size_init = 0; result->rc = info.added; be_entry_release_w( &op_tmp, e ); } if ( result->rc ) info.size_final = get_entry_size( e, info.size_init, result ); else info.size_final = info.size_init; return ( info.size_final - info.size_init ); } static Attribute* add_attribute(AttributeDescription *ad, Entry* e, BerVarray value_array) { Attribute* new_attr, *last_attr; const char* text; if (e->e_attrs == NULL) last_attr = NULL; else for (last_attr = e->e_attrs; last_attr->a_next; last_attr = last_attr->a_next) ; new_attr = (Attribute*)malloc(sizeof(Attribute)); if (last_attr) last_attr->a_next = new_attr; else e->e_attrs = new_attr; new_attr->a_next = NULL; new_attr->a_desc = NULL; new_attr->a_vals = value_array; new_attr->a_desc = ad; return new_attr; } static int null_response ( Operation *op, SlapReply *rs ) { return 0; } static int normalize_values( Attribute* attr ) { int nvals, rc, i; if (attr->a_vals == NULL) { attr->a_nvals = NULL; return 0; } for ( nvals = 0; attr->a_vals[nvals].bv_val; nvals++ ) ; attr->a_nvals = (struct berval*)ch_malloc((nvals+1)*sizeof(struct berval)); if ( attr->a_desc->ad_type->sat_equality && attr->a_desc->ad_type->sat_equality->smr_normalize ) { for ( i = 0; i < nvals; i++ ) { rc = attr->a_desc->ad_type->sat_equality->smr_normalize( 0, attr->a_desc->ad_type->sat_syntax, attr->a_desc->ad_type->sat_equality, &attr->a_vals[i], &attr->a_nvals[i], NULL ); if ( rc ) { #ifdef NEW_LOGGING LDAP_LOG( OPERATION, DETAIL1, "Error in normalizing attribute %s value %d (%d)\n", attr->a_desc->ad_cname.bv_val, i, rc ); #else Debug( LDAP_DEBUG_ANY, "Error in normalizing attribute %s value %d (%d)\n", attr->a_desc->ad_cname.bv_val, i, rc ); #endif return rc; } } } else { for ( i = 0; i < nvals; i++ ) { ber_dupbv( &attr->a_nvals[i], &attr->a_vals[i] ); } } attr->a_nvals[i].bv_val = NULL; attr->a_nvals[i].bv_len = 0; return LDAP_SUCCESS; }