1/* addpartial-overlay.c */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2004-2011 The OpenLDAP Foundation. 6 * Portions Copyright (C) 2004 Virginia Tech, David Hawes. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * http://www.OpenLDAP.org/license.html. 16 */ 17/* ACKNOLEDGEDMENTS: 18 * This work was initially developed by David Hawes of Virginia Tech 19 * for inclusion in OpenLDAP Software. 20 */ 21/* addpartial-overlay 22 * 23 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a 24 * change has actually taken place for that record, and then performs a modify 25 * request for those values that have changed (modified, added, deleted). If 26 * the record has not changed in any way, it is ignored. If the record does not 27 * exist, the record falls through to the normal add mechanism. This overlay is 28 * useful for replicating from sources that are not LDAPs where it is easier to 29 * build entire records than to determine the changes (i.e. a database). 30 */ 31 32#include "portable.h" 33#include "slap.h" 34 35static int collect_error_msg_cb( Operation *op, SlapReply *rs); 36 37static slap_overinst addpartial; 38 39/** 40 * The meat of the overlay. Search for the record, determine changes, take 41 * action or fall through. 42 */ 43static int addpartial_add( Operation *op, SlapReply *rs) 44{ 45 Operation nop = *op; 46 Entry *toAdd = NULL; 47 Entry *found = NULL; 48 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 49 int rc; 50 51 toAdd = op->oq_add.rs_e; 52 53 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n", 54 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0); 55 56 /* if the user doesn't have access, fall through to the normal ADD */ 57 if(!access_allowed(op, toAdd, slap_schema.si_ad_entry, 58 NULL, ACL_WRITE, NULL)) 59 { 60 return SLAP_CB_CONTINUE; 61 } 62 63 rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on); 64 65 if(rc != LDAP_SUCCESS) 66 { 67 Debug(LDAP_DEBUG_TRACE, 68 "%s: no entry found, falling through to normal add\n", 69 addpartial.on_bi.bi_type, 0, 0); 70 return SLAP_CB_CONTINUE; 71 } 72 else 73 { 74 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, 75 0,0); 76 77 if(found) 78 { 79 Attribute *attr = NULL; 80 Attribute *at = NULL; 81 int ret; 82 Modifications *mods = NULL; 83 Modifications **modtail = &mods; 84 Modifications *mod = NULL; 85 86 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n", 87 addpartial.on_bi.bi_type,0,0); 88 89 /* determine if the changes are in the found entry */ 90 for(attr = toAdd->e_attrs; attr; attr = attr->a_next) 91 { 92 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 93 94 at = attr_find(found->e_attrs, attr->a_desc); 95 if(!at) 96 { 97 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n", 98 addpartial.on_bi.bi_type, 99 attr->a_desc->ad_cname.bv_val,0); 100 mod = (Modifications *) ch_malloc(sizeof( 101 Modifications)); 102 mod->sml_flags = 0; 103 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 104 mod->sml_op &= LDAP_MOD_OP; 105 mod->sml_next = NULL; 106 mod->sml_desc = attr->a_desc; 107 mod->sml_type = attr->a_desc->ad_cname; 108 mod->sml_values = attr->a_vals; 109 mod->sml_nvalues = attr->a_nvals; 110 mod->sml_numvals = attr->a_numvals; 111 *modtail = mod; 112 modtail = &mod->sml_next; 113 } 114 else 115 { 116 MatchingRule *mr = attr->a_desc->ad_type->sat_equality; 117 struct berval *bv; 118 const char *text; 119 int acount , bcount; 120 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n", 121 addpartial.on_bi.bi_type, 122 attr->a_desc->ad_cname.bv_val,0); 123 124 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 125 bv++, acount++) 126 { 127 /* count num values for attr */ 128 } 129 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 130 bv++, bcount++) 131 { 132 /* count num values for attr */ 133 } 134 if(acount != bcount) 135 { 136 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n", 137 addpartial.on_bi.bi_type, 138 "replace all",0); 139 mod = (Modifications *) ch_malloc(sizeof( 140 Modifications)); 141 mod->sml_flags = 0; 142 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 143 mod->sml_op &= LDAP_MOD_OP; 144 mod->sml_next = NULL; 145 mod->sml_desc = attr->a_desc; 146 mod->sml_type = attr->a_desc->ad_cname; 147 mod->sml_values = attr->a_vals; 148 mod->sml_nvalues = attr->a_nvals; 149 mod->sml_numvals = attr->a_numvals; 150 *modtail = mod; 151 modtail = &mod->sml_next; 152 continue; 153 } 154 155 for(bv = attr->a_vals; bv->bv_val != NULL; bv++) 156 { 157 struct berval *v; 158 ret = -1; 159 160 for(v = at->a_vals; v->bv_val != NULL; v++) 161 { 162 int r; 163 if(mr && ((r = value_match(&ret, attr->a_desc, mr, 164 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, 165 bv, v, &text)) == 0)) 166 { 167 if(ret == 0) 168 break; 169 } 170 else 171 { 172 Debug(LDAP_DEBUG_TRACE, 173 "%s: \tvalue DNE, r: %d \n", 174 addpartial.on_bi.bi_type, 175 r,0); 176 ret = strcmp(bv->bv_val, v->bv_val); 177 if(ret == 0) 178 break; 179 } 180 } 181 182 if(ret == 0) 183 { 184 Debug(LDAP_DEBUG_TRACE, 185 "%s: \tvalue %s exists, ret: %d\n", 186 addpartial.on_bi.bi_type, bv->bv_val, ret); 187 } 188 else 189 { 190 Debug(LDAP_DEBUG_TRACE, 191 "%s: \tvalue %s DNE, ret: %d\n", 192 addpartial.on_bi.bi_type, bv->bv_val, ret); 193 mod = (Modifications *) ch_malloc(sizeof( 194 Modifications)); 195 mod->sml_flags = 0; 196 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 197 mod->sml_op &= LDAP_MOD_OP; 198 mod->sml_next = NULL; 199 mod->sml_desc = attr->a_desc; 200 mod->sml_type = attr->a_desc->ad_cname; 201 mod->sml_values = attr->a_vals; 202 mod->sml_nvalues = attr->a_nvals; 203 mod->sml_numvals = attr->a_numvals; 204 *modtail = mod; 205 modtail = &mod->sml_next; 206 break; 207 } 208 } 209 } 210 } 211 212 /* determine if any attributes were deleted */ 213 for(attr = found->e_attrs; attr; attr = attr->a_next) 214 { 215 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 216 217 at = NULL; 218 at = attr_find(toAdd->e_attrs, attr->a_desc); 219 if(!at) 220 { 221 Debug(LDAP_DEBUG_TRACE, 222 "%s: Attribute %s not found in new entry!!!\n", 223 addpartial.on_bi.bi_type, 224 attr->a_desc->ad_cname.bv_val, 0); 225 mod = (Modifications *) ch_malloc(sizeof( 226 Modifications)); 227 mod->sml_flags = 0; 228 mod->sml_op = LDAP_MOD_REPLACE; 229 mod->sml_next = NULL; 230 mod->sml_desc = attr->a_desc; 231 mod->sml_type = attr->a_desc->ad_cname; 232 mod->sml_values = NULL; 233 mod->sml_nvalues = NULL; 234 mod->sml_numvals = 0; 235 *modtail = mod; 236 modtail = &mod->sml_next; 237 } 238 else 239 { 240 Debug(LDAP_DEBUG_TRACE, 241 "%s: Attribute %s found in new entry\n", 242 addpartial.on_bi.bi_type, 243 at->a_desc->ad_cname.bv_val, 0); 244 } 245 } 246 247 overlay_entry_release_ov(&nop, found, 0, on); 248 249 if(mods) 250 { 251 Modifications *m = NULL; 252 Modifications *toDel; 253 int modcount; 254 slap_callback nullcb = { NULL, collect_error_msg_cb, 255 NULL, NULL }; 256 257 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", 258 addpartial.on_bi.bi_type, 0, 0); 259 260 nop.o_tag = LDAP_REQ_MODIFY; 261 nop.orm_modlist = mods; 262 nop.orm_no_opattrs = 0; 263 nop.o_callback = &nullcb; 264 nop.o_bd->bd_info = (BackendInfo *) on->on_info; 265 266 for(m = mods, modcount = 0; m; m = m->sml_next, 267 modcount++) 268 { 269 /* count number of mods */ 270 } 271 272 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n", 273 addpartial.on_bi.bi_type, modcount, 0); 274 275 if(nop.o_bd->be_modify) 276 { 277 SlapReply nrs = { REP_RESULT }; 278 rc = (nop.o_bd->be_modify)(&nop, &nrs); 279 } 280 281 if(rc == LDAP_SUCCESS) 282 { 283 Debug(LDAP_DEBUG_TRACE, 284 "%s: modify successful\n", 285 addpartial.on_bi.bi_type, 0, 0); 286 } 287 else 288 { 289 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", 290 addpartial.on_bi.bi_type, rc, 0); 291 rs->sr_err = rc; 292 if(nullcb.sc_private) 293 { 294 rs->sr_text = nullcb.sc_private; 295 } 296 } 297 298 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", 299 addpartial.on_bi.bi_type, 0, 0); 300 301 for(toDel = mods; toDel; toDel = mods) 302 { 303 mods = mods->sml_next; 304 ch_free(toDel); 305 } 306 } 307 else 308 { 309 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n", 310 addpartial.on_bi.bi_type, 0, 0); 311 } 312 } 313 else 314 { 315 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", 316 addpartial.on_bi.bi_type, 0, 0); 317 } 318 319 op->o_callback = NULL; 320 send_ldap_result( op, rs ); 321 ch_free((void *)rs->sr_text); 322 rs->sr_text = NULL; 323 324 return LDAP_SUCCESS; 325 } 326} 327 328static int collect_error_msg_cb( Operation *op, SlapReply *rs) 329{ 330 if(rs->sr_text) 331 { 332 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text); 333 } 334 335 return LDAP_SUCCESS; 336} 337 338int addpartial_init() 339{ 340 addpartial.on_bi.bi_type = "addpartial"; 341 addpartial.on_bi.bi_op_add = addpartial_add; 342 343 return (overlay_register(&addpartial)); 344} 345 346int init_module(int argc, char *argv[]) 347{ 348 return addpartial_init(); 349} 350