/* 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 #ifdef LDAP_CACHING static struct berval bv_queryid_any = BER_BVC( "(queryid=*)" ); static int merge_func ( Operation *op, SlapReply *rs ); void add_func ( Operation *op, SlapReply *rs ); static Attribute* add_attribute(AttributeDescription *ad, Entry* e, BerVarray value_array ); static int get_size_func ( Operation *op, SlapReply *rs ); 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; } /* quick hack: call the right callback */ static int add_merge_func( Operation *op, SlapReply *rs ) { switch ( rs->sr_type ) { case REP_SEARCH: add_func( op, rs ); break; case REP_RESULT: merge_func( op, rs ); break; } return 0; } int merge_entry( Operation *op, SlapReply *rs, struct berval* query_uuid, struct exception* result ) { struct entry_info info; struct berval normdn; struct berval prettydn; Operation op_tmp = *op; slap_callback cb = { add_merge_func, NULL }; Filter* filter = str2filter( bv_queryid_any.bv_val ); dnPrettyNormal(0, &rs->sr_entry->e_name, &prettydn, &normdn, op->o_tmpmemctx); free(rs->sr_entry->e_name.bv_val); rs->sr_entry->e_name = prettydn; if (rs->sr_entry->e_nname.bv_val) free(rs->sr_entry->e_nname.bv_val); rs->sr_entry->e_nname = normdn; info.entry = rs->sr_entry; info.uuid = query_uuid; info.size_init = 0; info.size_final = 0; info.added = 0; info.glue_be = op->o_bd; info.err = SUCCESS; cb.sc_private = &info; op_tmp.o_tag = LDAP_REQ_SEARCH; op_tmp.o_protocol = LDAP_VERSION3; op_tmp.o_callback = &cb; op_tmp.o_caching_on = 1; op_tmp.o_time = slap_get_time(); op_tmp.o_do_not_cache = 1; op_tmp.o_req_dn = rs->sr_entry->e_name; op_tmp.o_req_ndn = rs->sr_entry->e_nname; op_tmp.ors_scope = LDAP_SCOPE_BASE; op_tmp.ors_deref = LDAP_DEREF_NEVER; op_tmp.ors_slimit = 1; op_tmp.ors_tlimit = 0; op_tmp.ors_filter = filter; op_tmp.ors_filterstr = bv_queryid_any; op_tmp.ors_attrs = NULL; op_tmp.ors_attrsonly = 0; op->o_bd->be_search( &op_tmp, rs ); result->type = info.err; if ( result->type == SUCCESS ) result->rc = info.added; else result->rc = 0; return ( info.size_final - info.size_init ); } static int merge_func ( Operation *op, SlapReply *rs ) { Backend *be; char *new_attr_name; Attribute *a_new, *a; int i = 0; int rc = 0; int count; struct timeval time; /* time */ long timediff; /* time */ struct entry_info *info = op->o_callback->sc_private; Filter *filter = str2filter( bv_queryid_any.bv_val ); Entry *entry = info->entry; struct berval *uuid = info->uuid; Modifications *modhead = NULL; Modifications *mod; Modifications **modtail = &modhead; AttributeDescription *a_new_desc; const char *text = NULL; Operation op_tmp = *op; info->err = SUCCESS; be = select_backend(&entry->e_nname, 0, 0); info->size_init = get_entry_size(rs->sr_entry, 0, 0); a_new = entry->e_attrs; while (a_new != NULL) { a_new_desc = a_new->a_desc; mod = (Modifications *) malloc( sizeof(Modifications) ); mod->sml_op = LDAP_MOD_REPLACE; ber_dupbv(&mod->sml_type, &a_new_desc->ad_cname); for (count = 0; a_new->a_vals[count].bv_val; count++) ; mod->sml_bvalues = (struct berval*) malloc( (count+1) * sizeof( struct berval) ); for (i=0; i < count; i++) { ber_dupbv(mod->sml_bvalues+i, a_new->a_vals+i); } mod->sml_bvalues[count].bv_val = 0; mod->sml_bvalues[count].bv_len = 0; mod->sml_desc = NULL; slap_bv2ad(&mod->sml_type, &mod->sml_desc, &text); mod->sml_next =NULL; *modtail = mod; modtail = &mod->sml_next; a_new = a_new->a_next; } /* add query UUID to queryid attribute */ mod = (Modifications *) ch_malloc( sizeof(Modifications) ); mod->sml_op = LDAP_MOD_ADD; mod->sml_desc = slap_schema.si_ad_queryid; ber_dupbv(&mod->sml_type, &mod->sml_desc->ad_cname); mod->sml_bvalues = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) ); ber_dupbv( mod->sml_bvalues, uuid ); mod->sml_bvalues[1].bv_val = NULL; mod->sml_bvalues[1].bv_len = 0; *modtail = mod; mod->sml_next = NULL; /* Apply changes */ op_tmp.o_req_dn = entry->e_name; op_tmp.o_req_ndn = entry->e_nname; op_tmp.orm_modlist = modhead; if (be->be_modify(op, rs ) != 0 ) { /* FIXME: cleanup ? */ info->err = MERGE_ERR; return 0; } /* compute the size of the entry */ op_tmp.o_callback->sc_response = get_size_func; op_tmp.ors_scope = LDAP_SCOPE_BASE; op_tmp.ors_deref = LDAP_DEREF_NEVER; op_tmp.ors_slimit = 1; op_tmp.ors_tlimit = 0; op_tmp.ors_filter = filter; op_tmp.ors_filterstr = bv_queryid_any; op_tmp.ors_attrs = NULL; op_tmp.ors_attrsonly = 0; if (be->be_search( &op_tmp, rs ) != 0) { info->err = GET_SIZE_ERR; } return 0; } void add_func ( Operation *op, SlapReply *rs ) { struct entry_info *info = op->o_callback->sc_private; Entry *entry = info->entry; struct berval *uuid = info->uuid; Backend *be; BerVarray value_array; Entry *e; Attribute *a; struct timeval time; /* time */ long timediff; /* time */ Operation op_tmp = *op; /* * new entry, construct an entry with * the projected attributes */ if (rs->sr_nentries) return; be = select_backend(&entry->e_nname, 0, 0); e = (Entry*)malloc(sizeof(Entry)); ber_dupbv(&e->e_name,&entry->e_name); ber_dupbv(&e->e_nname,&entry->e_nname); e->e_private = 0; e->e_attrs = 0; e->e_bv.bv_val = 0; /* add queryid attribute */ value_array = (struct berval *)malloc(2 * sizeof( struct berval) ); ber_dupbv(value_array, uuid); value_array[1].bv_val = NULL; value_array[1].bv_len = 0; a = add_attribute(slap_schema.si_ad_queryid, e, value_array); /* append the attribute list from the fetched entry */ a->a_next = entry->e_attrs; entry->e_attrs = NULL; info->size_final = get_entry_size(e, 0, NULL); op_tmp.o_bd = be; op_tmp.ora_e = e; if ( be->be_add( &op_tmp, rs ) == 0 ) { info->added = 1; be_entry_release_w( &op_tmp, e ); } else { info->err = MERGE_ERR; } } 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 get_size_func ( Operation *op, SlapReply *rs ) { struct entry_info *info = op->o_callback->sc_private; struct exception result; if ( rs->sr_type == REP_SEARCH ) { result.type = info->err; info->size_final = get_entry_size(rs->sr_entry, info->size_init, &result); } return 0; } #endif /* LDAP_CACHING */