1 /** 2 * $Id: addpartial-overlay.c,v 1.1.1.1 2008/05/22 14:20:36 lukem Exp $ 3 * 4 * Copyright (C) 2004 Virginia Tech, David Hawes. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * http://www.OpenLDAP.org/license.html. 14 * 15 * SEE LICENSE FOR MORE INFORMATION 16 * 17 * Author: David H. Hawes, Jr. 18 * Email: dhawes@vt.edu 19 * Version: $Revision: 1.1.1.1 $ 20 * Updated: $Date: 2008/05/22 14:20:36 $ 21 * 22 * addpartial-overlay 23 * 24 * This is an OpenLDAP overlay that intercepts ADD requests, determines if a 25 * change has actually taken place for that record, and then performs a modify 26 * request for those values that have changed (modified, added, deleted). If 27 * the record has not changed in any way, it is ignored. If the record does not 28 * exist, the record falls through to the normal add mechanism. This overlay is 29 * useful for replicating from sources that are not LDAPs where it is easier to 30 * build entire records than to determine the changes (i.e. a database). 31 */ 32 33 #include "portable.h" 34 #include "slap.h" 35 36 static int addpartial_search_cb( Operation *op, SlapReply *rs); 37 static int collect_error_msg_cb( Operation *op, SlapReply *rs); 38 39 static slap_overinst addpartial; 40 41 /** 42 * The meat of the overlay. Search for the record, determine changes, take 43 * action or fall through. 44 */ 45 static int addpartial_add( Operation *op, SlapReply *rs) 46 { 47 Operation nop = *op; 48 SlapReply nrs = { REP_RESULT }; 49 Filter *filter = NULL; 50 Entry *toAdd = NULL; 51 struct berval fstr = BER_BVNULL; 52 slap_callback cb = { NULL, addpartial_search_cb, NULL, NULL }; 53 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 54 int rc; 55 56 toAdd = op->oq_add.rs_e; 57 58 Debug(LDAP_DEBUG_TRACE, "%s: toAdd->e_nname.bv_val: %s\n", 59 addpartial.on_bi.bi_type, toAdd->e_nname.bv_val,0); 60 61 /* if the user doesn't have access, fall through to the normal ADD */ 62 if(!access_allowed(op, toAdd, slap_schema.si_ad_entry, 63 NULL, ACL_WRITE, NULL)) 64 { 65 return SLAP_CB_CONTINUE; 66 } 67 68 rs->sr_text = NULL; 69 70 nop.o_callback = &cb; 71 op->o_bd->bd_info = (BackendInfo *) on->on_info; 72 nop.o_tag = LDAP_REQ_SEARCH; 73 nop.o_ctrls = NULL; 74 75 filter = str2filter("(objectclass=*)"); 76 filter2bv(filter, &fstr); 77 78 nop.ors_scope = LDAP_SCOPE_BASE; 79 nop.ors_deref = LDAP_DEREF_NEVER; 80 nop.ors_slimit = -1;//SLAP_NO_LIMIT; 81 nop.ors_tlimit = -1;//SLAP_NO_LIMIT; 82 nop.ors_attrsonly = 0; 83 nop.ors_attrs = slap_anlist_no_attrs; 84 nop.ors_filter = filter; 85 nop.ors_filterstr = fstr; 86 87 memset(&nrs, 0, sizeof(nrs)); 88 nrs.sr_type = REP_RESULT; 89 nrs.sr_err = LDAP_SUCCESS; 90 nrs.sr_entry = NULL; 91 nrs.sr_flags |= REP_ENTRY_MUSTBEFREED; 92 nrs.sr_text = NULL; 93 94 Debug(LDAP_DEBUG_TRACE, "%s: performing search\n", addpartial.on_bi.bi_type, 95 0,0); 96 97 if(nop.o_bd->be_search) 98 { 99 rc = nop.o_bd->be_search(&nop, &nrs); 100 Debug(LDAP_DEBUG_TRACE, "%s: search performed\n", 101 addpartial.on_bi.bi_type,0,0); 102 } 103 else 104 { 105 Debug(LDAP_DEBUG_TRACE, "%s: backend missing search function\n", 106 addpartial.on_bi.bi_type,0,0); 107 } 108 109 if(filter) 110 filter_free(filter); 111 if(fstr.bv_val) 112 ch_free(fstr.bv_val); 113 114 if(rc != LDAP_SUCCESS) 115 return SLAP_CB_CONTINUE; 116 else 117 { 118 Entry *found = NULL; 119 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, 120 0,0); 121 found = (Entry *) cb.sc_private; 122 123 if(found) 124 { 125 Attribute *attr = NULL; 126 Attribute *at = NULL; 127 int ret; 128 Modifications *mods = NULL; 129 Modifications **modtail = &mods; 130 Modifications *mod = NULL; 131 132 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n", 133 addpartial.on_bi.bi_type,0,0); 134 135 /* determine if the changes are in the found entry */ 136 for(attr = toAdd->e_attrs; attr; attr = attr->a_next) 137 { 138 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 139 140 at = attr_find(found->e_attrs, attr->a_desc); 141 if(!at) 142 { 143 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n", 144 addpartial.on_bi.bi_type, 145 attr->a_desc->ad_cname.bv_val,0); 146 mod = (Modifications *) ch_malloc(sizeof( 147 Modifications)); 148 mod->sml_flags = 0; 149 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 150 mod->sml_op &= LDAP_MOD_OP; 151 mod->sml_next = NULL; 152 mod->sml_desc = attr->a_desc; 153 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val; 154 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 155 mod->sml_values = attr->a_vals; 156 mod->sml_nvalues = attr->a_nvals; 157 mod->sml_numvals = attr->a_numvals; 158 *modtail = mod; 159 modtail = &mod->sml_next; 160 } 161 else 162 { 163 MatchingRule *mr = attr->a_desc->ad_type->sat_equality; 164 struct berval *bv; 165 const char *text; 166 int acount , bcount; 167 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n", 168 addpartial.on_bi.bi_type, 169 attr->a_desc->ad_cname.bv_val,0); 170 171 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 172 bv++, acount++) 173 { 174 /* count num values for attr */ 175 } 176 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 177 bv++, bcount++) 178 { 179 /* count num values for attr */ 180 } 181 if(acount != bcount) 182 { 183 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n", 184 addpartial.on_bi.bi_type, 185 "replace all",0); 186 mod = (Modifications *) ch_malloc(sizeof( 187 Modifications)); 188 mod->sml_flags = 0; 189 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 190 mod->sml_op &= LDAP_MOD_OP; 191 mod->sml_next = NULL; 192 mod->sml_desc = attr->a_desc; 193 mod->sml_type.bv_val = attr->a_desc->ad_cname.bv_val; 194 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 195 mod->sml_values = attr->a_vals; 196 mod->sml_nvalues = attr->a_nvals; 197 mod->sml_numvals = attr->a_numvals; 198 *modtail = mod; 199 modtail = &mod->sml_next; 200 continue; 201 } 202 203 for(bv = attr->a_vals; bv->bv_val != NULL; bv++) 204 { 205 struct berval *v; 206 ret = -1; 207 208 for(v = at->a_vals; v->bv_val != NULL; v++) 209 { 210 int r; 211 if(mr && ((r = value_match(&ret, attr->a_desc, mr, 212 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, 213 bv, v, &text)) == 0)) 214 { 215 if(ret == 0) 216 break; 217 } 218 else 219 { 220 Debug(LDAP_DEBUG_TRACE, 221 "%s: \tvalue DNE, r: %d \n", 222 addpartial.on_bi.bi_type, 223 r,0); 224 ret = strcmp(bv->bv_val, v->bv_val); 225 if(ret == 0) 226 break; 227 } 228 } 229 230 if(ret == 0) 231 { 232 Debug(LDAP_DEBUG_TRACE, 233 "%s: \tvalue %s exists, ret: %d\n", 234 addpartial.on_bi.bi_type, bv->bv_val, ret); 235 } 236 else 237 { 238 Debug(LDAP_DEBUG_TRACE, 239 "%s: \tvalue %s DNE, ret: %d\n", 240 addpartial.on_bi.bi_type, bv->bv_val, ret); 241 mod = (Modifications *) ch_malloc(sizeof( 242 Modifications)); 243 mod->sml_flags = 0; 244 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 245 mod->sml_op &= LDAP_MOD_OP; 246 mod->sml_next = NULL; 247 mod->sml_desc = attr->a_desc; 248 mod->sml_type.bv_val = 249 attr->a_desc->ad_cname.bv_val; 250 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 251 mod->sml_values = attr->a_vals; 252 mod->sml_nvalues = attr->a_nvals; 253 mod->sml_numvals = attr->a_numvals; 254 *modtail = mod; 255 modtail = &mod->sml_next; 256 break; 257 } 258 } 259 } 260 } 261 262 /* determine if any attributes were deleted */ 263 for(attr = found->e_attrs; attr; attr = attr->a_next) 264 { 265 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 266 267 at = NULL; 268 at = attr_find(toAdd->e_attrs, attr->a_desc); 269 if(!at) 270 { 271 Debug(LDAP_DEBUG_TRACE, 272 "%s: Attribute %s not found in new entry!!!\n", 273 addpartial.on_bi.bi_type, 274 attr->a_desc->ad_cname.bv_val, 0); 275 mod = (Modifications *) ch_malloc(sizeof( 276 Modifications)); 277 mod->sml_flags = 0; 278 mod->sml_op = LDAP_MOD_REPLACE; 279 mod->sml_next = NULL; 280 mod->sml_desc = attr->a_desc; 281 mod->sml_type.bv_val = 282 attr->a_desc->ad_cname.bv_val; 283 mod->sml_type.bv_len = strlen(mod->sml_type.bv_val); 284 mod->sml_values = NULL; 285 mod->sml_nvalues = NULL; 286 mod->sml_numvals = 0; 287 *modtail = mod; 288 modtail = &mod->sml_next; 289 } 290 else 291 { 292 Debug(LDAP_DEBUG_TRACE, 293 "%s: Attribute %s found in new entry\n", 294 addpartial.on_bi.bi_type, 295 at->a_desc->ad_cname.bv_val, 0); 296 } 297 } 298 299 if(mods) 300 { 301 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", 302 addpartial.on_bi.bi_type, 0, 0); 303 if(nop.o_bd->be_modify) 304 { 305 Modifications *m = NULL; 306 int modcount; 307 slap_callback nullcb = { NULL, collect_error_msg_cb, 308 NULL, NULL }; 309 char textbuf[SLAP_TEXT_BUFLEN]; 310 size_t textlen = sizeof textbuf; 311 312 memset(&nrs, 0, sizeof(nrs)); 313 nrs.sr_type = REP_RESULT; 314 nrs.sr_err = LDAP_SUCCESS; 315 nrs.sr_entry = NULL; 316 nrs.sr_text = NULL; 317 318 nop.o_tag = LDAP_REQ_MODIFY; 319 nop.orm_modlist = mods; 320 nop.o_callback = &nullcb; 321 nop.o_bd->bd_info = (BackendInfo *) on->on_info; 322 323 for(m = mods, modcount = 0; m; m = m->sml_next, 324 modcount++) 325 { 326 /* count number of mods */ 327 } 328 329 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n", 330 addpartial.on_bi.bi_type, modcount, 0); 331 332 rc = (nop.o_bd->be_modify)(&nop, &nrs); 333 334 if(rc == LDAP_SUCCESS) 335 { 336 Debug(LDAP_DEBUG_TRACE, 337 "%s: modify successful\n", 338 addpartial.on_bi.bi_type, 0, 0); 339 } 340 else 341 { 342 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", 343 addpartial.on_bi.bi_type, rc, 0); 344 rs->sr_err = rc; 345 if(nrs.sr_text) 346 { 347 rs->sr_text = nullcb.sc_private; 348 } 349 } 350 351 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", 352 addpartial.on_bi.bi_type, 0, 0); 353 354 if(mods != NULL) 355 { 356 Modifications *toDel; 357 358 for(toDel = mods; toDel; toDel = mods) 359 { 360 mods = mods->sml_next; 361 ch_free(toDel); 362 } 363 } 364 } 365 } 366 else 367 { 368 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n", 369 addpartial.on_bi.bi_type, 0, 0); 370 } 371 372 if(found != NULL) 373 entry_free(found); 374 } 375 else 376 { 377 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", 378 addpartial.on_bi.bi_type, 0, 0); 379 } 380 381 op->o_callback = NULL; 382 send_ldap_result( op, rs ); 383 ch_free((void *)rs->sr_text); 384 rs->sr_text = NULL; 385 386 return LDAP_SUCCESS; 387 } 388 } 389 390 static int addpartial_search_cb( Operation *op, SlapReply *rs) 391 { 392 Entry *entry = NULL; 393 394 if(rs->sr_type != REP_SEARCH) return 0; 395 396 Debug(LDAP_DEBUG_TRACE, "%s: addpartial_search_cb\n", 397 addpartial.on_bi.bi_type, 0, 0); 398 399 if(rs->sr_entry) 400 { 401 Debug(LDAP_DEBUG_TRACE, "%s: dn found: %s\n", 402 addpartial.on_bi.bi_type, rs->sr_entry->e_nname.bv_val, 0); 403 entry = rs->sr_entry; 404 op->o_callback->sc_private = (void *) entry_dup(entry); 405 } 406 407 return 0; 408 } 409 410 static int collect_error_msg_cb( Operation *op, SlapReply *rs) 411 { 412 if(rs->sr_text) 413 { 414 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text); 415 } 416 417 return LDAP_SUCCESS; 418 } 419 420 int addpartial_init() 421 { 422 addpartial.on_bi.bi_type = "addpartial"; 423 addpartial.on_bi.bi_op_add = addpartial_add; 424 425 return (overlay_register(&addpartial)); 426 } 427 428 int init_module(int argc, char *argv[]) 429 { 430 return addpartial_init(); 431 } 432