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