1 /* $NetBSD: addpartial-overlay.c,v 1.2 2020/08/11 13:15:34 christos Exp $ */ 2 3 /* addpartial-overlay.c */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2004-2020 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 <sys/cdefs.h> 35 __RCSID("$NetBSD: addpartial-overlay.c,v 1.2 2020/08/11 13:15:34 christos Exp $"); 36 37 #include "portable.h" 38 #include "slap.h" 39 40 static int collect_error_msg_cb( Operation *op, SlapReply *rs); 41 42 static slap_overinst addpartial; 43 44 /** 45 * The meat of the overlay. Search for the record, determine changes, take 46 * action or fall through. 47 */ 48 static int addpartial_add( Operation *op, SlapReply *rs) 49 { 50 Operation nop = *op; 51 Entry *toAdd = NULL; 52 Entry *found = 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 rc = overlay_entry_get_ov(&nop, &nop.o_req_ndn, NULL, NULL, 0, &found, on); 69 70 if(rc != LDAP_SUCCESS) 71 { 72 Debug(LDAP_DEBUG_TRACE, 73 "%s: no entry found, falling through to normal add\n", 74 addpartial.on_bi.bi_type, 0, 0); 75 return SLAP_CB_CONTINUE; 76 } 77 else 78 { 79 Debug(LDAP_DEBUG_TRACE, "%s: found the dn\n", addpartial.on_bi.bi_type, 80 0,0); 81 82 if(found) 83 { 84 Attribute *attr = NULL; 85 Attribute *at = NULL; 86 int ret; 87 Modifications *mods = NULL; 88 Modifications **modtail = &mods; 89 Modifications *mod = NULL; 90 91 Debug(LDAP_DEBUG_TRACE, "%s: have an entry!\n", 92 addpartial.on_bi.bi_type,0,0); 93 94 /* determine if the changes are in the found entry */ 95 for(attr = toAdd->e_attrs; attr; attr = attr->a_next) 96 { 97 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 98 99 at = attr_find(found->e_attrs, attr->a_desc); 100 if(!at) 101 { 102 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s not found!\n", 103 addpartial.on_bi.bi_type, 104 attr->a_desc->ad_cname.bv_val,0); 105 mod = (Modifications *) ch_malloc(sizeof( 106 Modifications)); 107 mod->sml_flags = 0; 108 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 109 mod->sml_op &= LDAP_MOD_OP; 110 mod->sml_next = NULL; 111 mod->sml_desc = attr->a_desc; 112 mod->sml_type = attr->a_desc->ad_cname; 113 mod->sml_values = attr->a_vals; 114 mod->sml_nvalues = attr->a_nvals; 115 mod->sml_numvals = attr->a_numvals; 116 *modtail = mod; 117 modtail = &mod->sml_next; 118 } 119 else 120 { 121 MatchingRule *mr = attr->a_desc->ad_type->sat_equality; 122 struct berval *bv; 123 const char *text; 124 int acount , bcount; 125 Debug(LDAP_DEBUG_TRACE, "%s: Attribute %s found\n", 126 addpartial.on_bi.bi_type, 127 attr->a_desc->ad_cname.bv_val,0); 128 129 for(bv = attr->a_vals, acount = 0; bv->bv_val != NULL; 130 bv++, acount++) 131 { 132 /* count num values for attr */ 133 } 134 for(bv = at->a_vals, bcount = 0; bv->bv_val != NULL; 135 bv++, bcount++) 136 { 137 /* count num values for attr */ 138 } 139 if(acount != bcount) 140 { 141 Debug(LDAP_DEBUG_TRACE, "%s: acount != bcount, %s\n", 142 addpartial.on_bi.bi_type, 143 "replace all",0); 144 mod = (Modifications *) ch_malloc(sizeof( 145 Modifications)); 146 mod->sml_flags = 0; 147 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 148 mod->sml_op &= LDAP_MOD_OP; 149 mod->sml_next = NULL; 150 mod->sml_desc = attr->a_desc; 151 mod->sml_type = attr->a_desc->ad_cname; 152 mod->sml_values = attr->a_vals; 153 mod->sml_nvalues = attr->a_nvals; 154 mod->sml_numvals = attr->a_numvals; 155 *modtail = mod; 156 modtail = &mod->sml_next; 157 continue; 158 } 159 160 for(bv = attr->a_vals; bv->bv_val != NULL; bv++) 161 { 162 struct berval *v; 163 ret = -1; 164 165 for(v = at->a_vals; v->bv_val != NULL; v++) 166 { 167 int r; 168 if(mr && ((r = value_match(&ret, attr->a_desc, mr, 169 SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, 170 bv, v, &text)) == 0)) 171 { 172 if(ret == 0) 173 break; 174 } 175 else 176 { 177 Debug(LDAP_DEBUG_TRACE, 178 "%s: \tvalue DNE, r: %d \n", 179 addpartial.on_bi.bi_type, 180 r,0); 181 ret = strcmp(bv->bv_val, v->bv_val); 182 if(ret == 0) 183 break; 184 } 185 } 186 187 if(ret == 0) 188 { 189 Debug(LDAP_DEBUG_TRACE, 190 "%s: \tvalue %s exists, ret: %d\n", 191 addpartial.on_bi.bi_type, bv->bv_val, ret); 192 } 193 else 194 { 195 Debug(LDAP_DEBUG_TRACE, 196 "%s: \tvalue %s DNE, ret: %d\n", 197 addpartial.on_bi.bi_type, bv->bv_val, ret); 198 mod = (Modifications *) ch_malloc(sizeof( 199 Modifications)); 200 mod->sml_flags = 0; 201 mod->sml_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES; 202 mod->sml_op &= LDAP_MOD_OP; 203 mod->sml_next = NULL; 204 mod->sml_desc = attr->a_desc; 205 mod->sml_type = attr->a_desc->ad_cname; 206 mod->sml_values = attr->a_vals; 207 mod->sml_nvalues = attr->a_nvals; 208 mod->sml_numvals = attr->a_numvals; 209 *modtail = mod; 210 modtail = &mod->sml_next; 211 break; 212 } 213 } 214 } 215 } 216 217 /* determine if any attributes were deleted */ 218 for(attr = found->e_attrs; attr; attr = attr->a_next) 219 { 220 if(attr->a_desc->ad_type->sat_atype.at_usage != 0) continue; 221 222 at = NULL; 223 at = attr_find(toAdd->e_attrs, attr->a_desc); 224 if(!at) 225 { 226 Debug(LDAP_DEBUG_TRACE, 227 "%s: Attribute %s not found in new entry!!!\n", 228 addpartial.on_bi.bi_type, 229 attr->a_desc->ad_cname.bv_val, 0); 230 mod = (Modifications *) ch_malloc(sizeof( 231 Modifications)); 232 mod->sml_flags = 0; 233 mod->sml_op = LDAP_MOD_REPLACE; 234 mod->sml_next = NULL; 235 mod->sml_desc = attr->a_desc; 236 mod->sml_type = attr->a_desc->ad_cname; 237 mod->sml_values = NULL; 238 mod->sml_nvalues = NULL; 239 mod->sml_numvals = 0; 240 *modtail = mod; 241 modtail = &mod->sml_next; 242 } 243 else 244 { 245 Debug(LDAP_DEBUG_TRACE, 246 "%s: Attribute %s found in new entry\n", 247 addpartial.on_bi.bi_type, 248 at->a_desc->ad_cname.bv_val, 0); 249 } 250 } 251 252 overlay_entry_release_ov(&nop, found, 0, on); 253 254 if(mods) 255 { 256 Modifications *m = NULL; 257 Modifications *toDel; 258 int modcount; 259 slap_callback nullcb = { NULL, collect_error_msg_cb, 260 NULL, NULL }; 261 262 Debug(LDAP_DEBUG_TRACE, "%s: mods to do...\n", 263 addpartial.on_bi.bi_type, 0, 0); 264 265 nop.o_tag = LDAP_REQ_MODIFY; 266 nop.orm_modlist = mods; 267 nop.orm_no_opattrs = 0; 268 nop.o_callback = &nullcb; 269 nop.o_bd->bd_info = (BackendInfo *) on->on_info; 270 271 for(m = mods, modcount = 0; m; m = m->sml_next, 272 modcount++) 273 { 274 /* count number of mods */ 275 } 276 277 Debug(LDAP_DEBUG_TRACE, "%s: number of mods: %d\n", 278 addpartial.on_bi.bi_type, modcount, 0); 279 280 if(nop.o_bd->be_modify) 281 { 282 SlapReply nrs = { REP_RESULT }; 283 rc = (nop.o_bd->be_modify)(&nop, &nrs); 284 } 285 286 if(rc == LDAP_SUCCESS) 287 { 288 Debug(LDAP_DEBUG_TRACE, 289 "%s: modify successful\n", 290 addpartial.on_bi.bi_type, 0, 0); 291 } 292 else 293 { 294 Debug(LDAP_DEBUG_TRACE, "%s: modify unsuccessful: %d\n", 295 addpartial.on_bi.bi_type, rc, 0); 296 rs->sr_err = rc; 297 if(nullcb.sc_private) 298 { 299 rs->sr_text = nullcb.sc_private; 300 } 301 } 302 303 Debug(LDAP_DEBUG_TRACE, "%s: freeing mods...\n", 304 addpartial.on_bi.bi_type, 0, 0); 305 306 for(toDel = mods; toDel; toDel = mods) 307 { 308 mods = mods->sml_next; 309 ch_free(toDel); 310 } 311 } 312 else 313 { 314 Debug(LDAP_DEBUG_TRACE, "%s: no mods to process\n", 315 addpartial.on_bi.bi_type, 0, 0); 316 } 317 } 318 else 319 { 320 Debug(LDAP_DEBUG_TRACE, "%s: no entry!\n", 321 addpartial.on_bi.bi_type, 0, 0); 322 } 323 324 op->o_callback = NULL; 325 send_ldap_result( op, rs ); 326 ch_free((void *)rs->sr_text); 327 rs->sr_text = NULL; 328 329 return LDAP_SUCCESS; 330 } 331 } 332 333 static int collect_error_msg_cb( Operation *op, SlapReply *rs) 334 { 335 if(rs->sr_text) 336 { 337 op->o_callback->sc_private = (void *) ch_strdup(rs->sr_text); 338 } 339 340 return LDAP_SUCCESS; 341 } 342 343 int addpartial_init() 344 { 345 addpartial.on_bi.bi_type = "addpartial"; 346 addpartial.on_bi.bi_op_add = addpartial_add; 347 348 return (overlay_register(&addpartial)); 349 } 350 351 int init_module(int argc, char *argv[]) 352 { 353 return addpartial_init(); 354 } 355