1/* nops.c - Overlay to filter idempotent operations */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2008-2011 The OpenLDAP Foundation. 6 * Copyright 2008 Emmanuel Dreyfus. 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 the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17/* ACKNOWLEDGEMENTS: 18 * This work was originally developed by the Emmanuel Dreyfus for 19 * inclusion in OpenLDAP Software. 20 */ 21#include "portable.h" 22 23#ifdef SLAPD_OVER_NOPS 24 25#include <stdio.h> 26 27#include <ac/string.h> 28#include <ac/socket.h> 29 30#include "lutil.h" 31#include "slap.h" 32#include "config.h" 33 34static ConfigDriver nops_cf_gen; 35 36static int nops_cf_gen( ConfigArgs *c ) { return 0; } 37 38static void 39nops_rm_mod( Modifications **mods, Modifications *mod ) { 40 Modifications *next, *m; 41 42 next = mod->sml_next; 43 if (*mods == mod) { 44 *mods = next; 45 } else { 46 Modifications *m; 47 48 for (m = *mods; m; m = m->sml_next) { 49 if (m->sml_next == mod) { 50 m->sml_next = next; 51 break; 52 } 53 } 54 } 55 56 mod->sml_next = NULL; 57 slap_mods_free(mod, 1); 58 59 return; 60} 61 62static int 63nops_modify( Operation *op, SlapReply *rs ) 64{ 65 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; 66 Backend *be = op->o_bd; 67 Entry *target_entry = NULL; 68 Modifications *m; 69 int rc; 70 71 if ((m = op->orm_modlist) == NULL) { 72 op->o_bd->bd_info = (BackendInfo *)(on->on_info); 73 send_ldap_error(op, rs, LDAP_INVALID_SYNTAX, 74 "nops() got null orm_modlist"); 75 return(rs->sr_err); 76 } 77 78 op->o_bd = on->on_info->oi_origdb; 79 rc = be_entry_get_rw(op, &op->o_req_ndn, NULL, NULL, 0, &target_entry); 80 op->o_bd = be; 81 82 if (rc != 0 || target_entry == NULL) 83 return 0; 84 85 /* 86 * For each attribute modification, check if the 87 * modification and the old entry are the same. 88 */ 89 while (m) { 90 int i, j; 91 int found; 92 Attribute *a; 93 BerVarray bm; 94 BerVarray bt; 95 Modifications *mc; 96 97 mc = m; 98 m = m->sml_next; 99 100 /* Check only replace sub-operations */ 101 if ((mc->sml_op & LDAP_MOD_OP) != LDAP_MOD_REPLACE) 102 continue; 103 104 /* If there is no values, skip */ 105 if (((bm = mc->sml_values ) == NULL ) || (bm[0].bv_val == NULL)) 106 continue; 107 108 /* If the attribute does not exist in old entry, skip */ 109 if ((a = attr_find(target_entry->e_attrs, mc->sml_desc)) == NULL) 110 continue; 111 if ((bt = a->a_vals) == NULL) 112 continue; 113 114 /* For each value replaced, do we find it in old entry? */ 115 found = 0; 116 for (i = 0; bm[i].bv_val; i++) { 117 for (j = 0; bt[j].bv_val; j++) { 118 if (bm[i].bv_len != bt[j].bv_len) 119 continue; 120 if (memcmp(bm[i].bv_val, bt[j].bv_val, bt[j].bv_len) != 0) 121 continue; 122 123 found++; 124 break; 125 } 126 } 127 128 /* Did we find as many values as we had in old entry? */ 129 if (i != a->a_numvals || found != a->a_numvals) 130 continue; 131 132 /* This is a nop, remove it */ 133 Debug(LDAP_DEBUG_TRACE, "removing nop on %s%s%s", 134 a->a_desc->ad_cname.bv_val, "", ""); 135 136 nops_rm_mod(&op->orm_modlist, mc); 137 } 138 if (target_entry) { 139 op->o_bd = on->on_info->oi_origdb; 140 be_entry_release_r(op, target_entry); 141 op->o_bd = be; 142 } 143 144 if ((m = op->orm_modlist) == NULL) { 145 slap_callback *cb = op->o_callback; 146 147 op->o_bd->bd_info = (BackendInfo *)(on->on_info); 148 op->o_callback = NULL; 149 send_ldap_error(op, rs, LDAP_SUCCESS, ""); 150 op->o_callback = cb; 151 152 return (rs->sr_err); 153 } 154 155 return SLAP_CB_CONTINUE; 156} 157 158static slap_overinst nops_ovl; 159 160#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC 161static 162#endif 163int 164nops_initialize( void ) { 165 nops_ovl.on_bi.bi_type = "nops"; 166 nops_ovl.on_bi.bi_op_modify = nops_modify; 167 return overlay_register( &nops_ovl ); 168} 169 170#if SLAPD_OVER_NOPS == SLAPD_MOD_DYNAMIC 171int init_module(int argc, char *argv[]) { 172 return nops_initialize(); 173} 174#endif 175 176#endif /* defined(SLAPD_OVER_NOPS) */ 177 178