1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2021 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
37 int
do_delete(Operation * op,SlapReply * rs)38 do_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 );
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 );
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 );
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 );
70 send_ldap_error( op, rs, LDAP_INVALID_DN_SYNTAX, "invalid DN" );
71 goto cleanup;
72 }
73
74 Debug( LDAP_DEBUG_STATS, "%s DEL dn=\"%s\"\n",
75 op->o_log_prefix, op->o_req_dn.bv_val );
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 );
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 );
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 if ( rs->sr_err == SLAPD_ASYNCOP ) {
97 /* skip cleanup */
98 return rs->sr_err;
99 }
100
101 if( rs->sr_err == LDAP_TXN_SPECIFY_OKAY ) {
102 /* skip cleanup */
103 return rs->sr_err;
104 }
105
106 cleanup:;
107 op->o_tmpfree( op->o_req_dn.bv_val, op->o_tmpmemctx );
108 op->o_tmpfree( op->o_req_ndn.bv_val, op->o_tmpmemctx );
109 return rs->sr_err;
110 }
111
112 int
fe_op_delete(Operation * op,SlapReply * rs)113 fe_op_delete( Operation *op, SlapReply *rs )
114 {
115 struct berval pdn = BER_BVNULL;
116 BackendDB *op_be, *bd = op->o_bd;
117
118 /*
119 * We could be serving multiple database backends. Select the
120 * appropriate one, or send a referral to our "referral server"
121 * if we don't hold it.
122 */
123 op->o_bd = select_backend( &op->o_req_ndn, 1 );
124 if ( op->o_bd == NULL ) {
125 op->o_bd = bd;
126 rs->sr_ref = referral_rewrite( default_referral,
127 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
128
129 if (!rs->sr_ref) rs->sr_ref = default_referral;
130 if ( rs->sr_ref != NULL ) {
131 rs->sr_err = LDAP_REFERRAL;
132 send_ldap_result( op, rs );
133
134 if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref );
135 } else {
136 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
137 "no global superior knowledge" );
138 }
139 goto cleanup;
140 }
141
142 /* If we've got a glued backend, check the real backend */
143 op_be = op->o_bd;
144 if ( SLAP_GLUE_INSTANCE( op->o_bd )) {
145 op->o_bd = select_backend( &op->o_req_ndn, 0 );
146 }
147
148 /* check restrictions */
149 if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) {
150 send_ldap_result( op, rs );
151 goto cleanup;
152 }
153
154 /* check for referrals */
155 if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) {
156 goto cleanup;
157 }
158
159 /*
160 * do the delete if 1 && (2 || 3)
161 * 1) there is a delete function implemented in this backend;
162 * 2) this backend is the provider for what it holds;
163 * 3) it's a replica and the dn supplied is the update_ndn.
164 */
165 if ( op->o_bd->be_delete ) {
166 /* do the update here */
167 int repl_user = be_isupdate( op );
168 if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) {
169 struct berval org_req_dn = BER_BVNULL;
170 struct berval org_req_ndn = BER_BVNULL;
171 struct berval org_dn = BER_BVNULL;
172 struct berval org_ndn = BER_BVNULL;
173 int org_managedsait;
174
175 if ( op->o_txnSpec ) {
176 txn_preop( op, rs );
177 goto cleanup;
178 }
179
180 op->o_bd = op_be;
181 op->o_bd->be_delete( op, rs );
182
183 org_req_dn = op->o_req_dn;
184 org_req_ndn = op->o_req_ndn;
185 org_dn = op->o_dn;
186 org_ndn = op->o_ndn;
187 org_managedsait = get_manageDSAit( op );
188 op->o_dn = op->o_bd->be_rootdn;
189 op->o_ndn = op->o_bd->be_rootndn;
190 op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
191
192 while ( rs->sr_err == LDAP_SUCCESS &&
193 op->o_delete_glue_parent )
194 {
195 op->o_delete_glue_parent = 0;
196 if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) {
197 slap_callback cb = { NULL, NULL, NULL, NULL };
198 cb.sc_response = slap_null_cb;
199 dnParent( &op->o_req_ndn, &pdn );
200 op->o_req_dn = pdn;
201 op->o_req_ndn = pdn;
202 op->o_callback = &cb;
203 op->o_bd->be_delete( op, rs );
204 } else {
205 break;
206 }
207 }
208
209 op->o_managedsait = org_managedsait;
210 op->o_dn = org_dn;
211 op->o_ndn = org_ndn;
212 op->o_req_dn = org_req_dn;
213 op->o_req_ndn = org_req_ndn;
214 op->o_delete_glue_parent = 0;
215
216 } else {
217 BerVarray defref = op->o_bd->be_update_refs
218 ? op->o_bd->be_update_refs : default_referral;
219
220 if ( defref != NULL ) {
221 rs->sr_ref = referral_rewrite( defref,
222 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
223 if (!rs->sr_ref) rs->sr_ref = defref;
224 rs->sr_err = LDAP_REFERRAL;
225 send_ldap_result( op, rs );
226
227 if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref );
228
229 } else {
230 send_ldap_error( op, rs,
231 LDAP_UNWILLING_TO_PERFORM,
232 "shadow context; no update referral" );
233 }
234 }
235
236 } else {
237 send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM,
238 "operation not supported within namingContext" );
239 }
240
241 cleanup:;
242 op->o_bd = bd;
243 return rs->sr_err;
244 }
245