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