1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1998-2011 The OpenLDAP Foundation. 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 the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15/* Portions Copyright (c) 1995 Regents of the University of Michigan. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms are permitted 19 * provided that this notice is preserved and that due credit is given 20 * to the University of Michigan at Ann Arbor. The name of the University 21 * may not be used to endorse or promote products derived from this 22 * software without specific prior written permission. This software 23 * is provided ``as is'' without express or implied warranty. 24 */ 25 26#include "portable.h" 27 28#include <stdio.h> 29 30#include <ac/string.h> 31#include <ac/socket.h> 32 33#include "slap.h" 34 35#include "lutil.h" 36 37int 38do_delete( 39 Operation *op, 40 SlapReply *rs ) 41{ 42 struct berval dn = BER_BVNULL; 43 44 Debug( LDAP_DEBUG_TRACE, "%s do_delete\n", 45 op->o_log_prefix, 0, 0 ); 46 /* 47 * Parse the delete request. It looks like this: 48 * 49 * DelRequest := DistinguishedName 50 */ 51 52 if ( ber_scanf( op->o_ber, "m", &dn ) == LBER_ERROR ) { 53 Debug( LDAP_DEBUG_ANY, "%s do_delete: ber_scanf failed\n", 54 op->o_log_prefix, 0, 0 ); 55 send_ldap_discon( op, rs, LDAP_PROTOCOL_ERROR, "decoding error" ); 56 return SLAPD_DISCONNECT; 57 } 58 59 if( get_ctrls( op, rs, 1 ) != LDAP_SUCCESS ) { 60 Debug( LDAP_DEBUG_ANY, "%s do_delete: get_ctrls failed\n", 61 op->o_log_prefix, 0, 0 ); 62 goto cleanup; 63 } 64 65 rs->sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, 66 op->o_tmpmemctx ); 67 if( rs->sr_err != LDAP_SUCCESS ) { 68 Debug( LDAP_DEBUG_ANY, "%s do_delete: invalid dn (%s)\n", 69 op->o_log_prefix, dn.bv_val, 0 ); 70 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" ); 71 goto cleanup; 72 } 73 74 Statslog( LDAP_DEBUG_STATS, "%s DEL dn=\"%s\"\n", 75 op->o_log_prefix, op->o_req_dn.bv_val, 0, 0, 0 ); 76 77 if( op->o_req_ndn.bv_len == 0 ) { 78 Debug( LDAP_DEBUG_ANY, "%s do_delete: root dse!\n", 79 op->o_log_prefix, 0, 0 ); 80 /* protocolError would likely be a more appropriate error */ 81 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 82 "cannot delete the root DSE" ); 83 goto cleanup; 84 85 } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { 86 Debug( LDAP_DEBUG_ANY, "%s do_delete: subschema subentry!\n", 87 op->o_log_prefix, 0, 0 ); 88 /* protocolError would likely be a more appropriate error */ 89 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 90 "cannot delete the root DSE" ); 91 goto cleanup; 92 } 93 94 op->o_bd = frontendDB; 95 rs->sr_err = frontendDB->be_delete( op, rs ); 96 97#ifdef LDAP_X_TXN 98 if( rs->sr_err == LDAP_X_TXN_SPECIFY_OKAY ) { 99 /* skip cleanup */ 100 return rs->sr_err; 101 } 102#endif 103 104cleanup:; 105 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx ); 106 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx ); 107 return rs->sr_err; 108} 109 110int 111fe_op_delete( Operation *op, SlapReply *rs ) 112{ 113 struct berval pdn = BER_BVNULL; 114 BackendDB *op_be, *bd = op->o_bd; 115 116 /* 117 * We could be serving multiple database backends. Select the 118 * appropriate one, or send a referral to our "referral server" 119 * if we don't hold it. 120 */ 121 op->o_bd = select_backend( &op->o_req_ndn, 1 ); 122 if ( op->o_bd == NULL ) { 123 op->o_bd = bd; 124 rs->sr_ref = referral_rewrite( default_referral, 125 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 126 127 if (!rs->sr_ref) rs->sr_ref = default_referral; 128 if ( rs->sr_ref != NULL ) { 129 rs->sr_err = LDAP_REFERRAL; 130 send_ldap_result( op, rs ); 131 132 if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); 133 } else { 134 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 135 "no global superior knowledge" ); 136 } 137 goto cleanup; 138 } 139 140 /* If we've got a glued backend, check the real backend */ 141 op_be = op->o_bd; 142 if ( SLAP_GLUE_INSTANCE( op->o_bd )) { 143 op->o_bd = select_backend( &op->o_req_ndn, 0 ); 144 } 145 146 /* check restrictions */ 147 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { 148 send_ldap_result( op, rs ); 149 goto cleanup; 150 } 151 152 /* check for referrals */ 153 if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { 154 goto cleanup; 155 } 156 157 /* 158 * do the delete if 1 && (2 || 3) 159 * 1) there is a delete function implemented in this backend; 160 * 2) this backend is master for what it holds; 161 * 3) it's a replica and the dn supplied is the update_ndn. 162 */ 163 if ( op->o_bd->be_delete ) { 164 /* do the update here */ 165 int repl_user = be_isupdate( op ); 166 if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { 167 struct berval org_req_dn = BER_BVNULL; 168 struct berval org_req_ndn = BER_BVNULL; 169 struct berval org_dn = BER_BVNULL; 170 struct berval org_ndn = BER_BVNULL; 171 int org_managedsait; 172 173 op->o_bd = op_be; 174 op->o_bd->be_delete( op, rs ); 175 176 org_req_dn = op->o_req_dn; 177 org_req_ndn = op->o_req_ndn; 178 org_dn = op->o_dn; 179 org_ndn = op->o_ndn; 180 org_managedsait = get_manageDSAit( op ); 181 op->o_dn = op->o_bd->be_rootdn; 182 op->o_ndn = op->o_bd->be_rootndn; 183 op->o_managedsait = SLAP_CONTROL_NONCRITICAL; 184 185 while ( rs->sr_err == LDAP_SUCCESS && 186 op->o_delete_glue_parent ) 187 { 188 op->o_delete_glue_parent = 0; 189 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) { 190 slap_callback cb = { NULL, NULL, NULL, NULL }; 191 cb.sc_response = slap_null_cb; 192 dnParent( &op->o_req_ndn, &pdn ); 193 op->o_req_dn = pdn; 194 op->o_req_ndn = pdn; 195 op->o_callback = &cb; 196 op->o_bd->be_delete( op, rs ); 197 } else { 198 break; 199 } 200 } 201 202 op->o_managedsait = org_managedsait; 203 op->o_dn = org_dn; 204 op->o_ndn = org_ndn; 205 op->o_req_dn = org_req_dn; 206 op->o_req_ndn = org_req_ndn; 207 op->o_delete_glue_parent = 0; 208 209 } else { 210 BerVarray defref = op->o_bd->be_update_refs 211 ? op->o_bd->be_update_refs : default_referral; 212 213 if ( defref != NULL ) { 214 rs->sr_ref = referral_rewrite( defref, 215 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 216 if (!rs->sr_ref) rs->sr_ref = defref; 217 rs->sr_err = LDAP_REFERRAL; 218 send_ldap_result( op, rs ); 219 220 if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref ); 221 222 } else { 223 send_ldap_error( op, rs, 224 LDAP_UNWILLING_TO_PERFORM, 225 "shadow context; no update referral" ); 226 } 227 } 228 229 } else { 230 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 231 "operation not supported within namingContext" ); 232 } 233 234cleanup:; 235 op->o_bd = bd; 236 return rs->sr_err; 237} 238