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