]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/modrdn.c
ITS#8845 Recognise control-exop compatibility
[openldap] / servers / slapd / back-asyncmeta / modrdn.c
1 /* modrdn.c - modrdn request handler for back-syncmeta */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2016-2018 The OpenLDAP Foundation.
6  * Portions Copyright 2016 Symas Corporation.
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
18 /* ACKNOWLEDGEMENTS:
19  * This work was developed by Symas Corporation
20  * based on back-meta module for inclusion in OpenLDAP Software.
21  * This work was sponsored by Ericsson. */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29
30 #include "slap.h"
31 #include "../back-ldap/back-ldap.h"
32 #include "back-asyncmeta.h"
33 #include "../../../libraries/liblber/lber-int.h"
34 #include "../../../libraries/libldap/ldap-int.h"
35
36 meta_search_candidate_t
37 asyncmeta_back_modrdn_start(Operation *op,
38                             SlapReply *rs,
39                             a_metaconn_t *mc,
40                             bm_context_t *bc,
41                             int candidate)
42 {
43         a_dncookie      dc;
44         a_metainfo_t    *mi = mc->mc_info;
45         a_metatarget_t  *mt = mi->mi_targets[ candidate ];
46         struct berval   mdn = BER_BVNULL,
47                 mnewSuperior = BER_BVNULL,
48                 newrdn = BER_BVNULL;
49         int rc = 0, nretries = 1;
50         LDAPControl     **ctrls = NULL;
51         meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
52         BerElement *ber = NULL;
53         a_metasingleconn_t      *msc = &mc->mc_conns[ candidate ];
54         SlapReply               *candidates = bc->candidates;
55         ber_int_t       msgid;
56
57         dc.target = mt;
58         dc.conn = op->o_conn;
59         dc.rs = rs;
60
61         if ( op->orr_newSup ) {
62
63                 /*
64                  * NOTE: the newParent, if defined, must be on the
65                  * same target as the entry to be renamed.  This check
66                  * has been anticipated in meta_back_getconn()
67                  */
68                 /*
69                  * FIXME: one possibility is to delete the entry
70                  * from one target and add it to the other;
71                  * unfortunately we'd need write access to both,
72                  * which is nearly impossible; for administration
73                  * needs, the rootdn of the metadirectory could
74                  * be mapped to an administrative account on each
75                  * target (the binddn?); we'll see.
76                  */
77                 /*
78                  * NOTE: we need to port the identity assertion
79                  * feature from back-ldap
80                  */
81
82                 /* needs LDAPv3 */
83                 switch ( mt->mt_version ) {
84                 case LDAP_VERSION3:
85                         break;
86
87                 case 0:
88                         if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
89                                 break;
90                         }
91                         /* fall thru */
92
93                 default:
94                         /* op->o_protocol cannot be anything but LDAPv3,
95                          * otherwise wouldn't be here */
96                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
97                         retcode = META_SEARCH_ERR;
98                         goto done;
99                 }
100
101                 /*
102                  * Rewrite the new superior, if defined and required
103                  */
104                 dc.ctx = "newSuperiorDN";
105                 if ( asyncmeta_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
106                         rs->sr_err = LDAP_OTHER;
107                         retcode = META_SEARCH_ERR;
108                         goto done;
109                 }
110         }
111
112         /*
113          * Rewrite the modrdn dn, if required
114          */
115         dc.ctx = "modrDN";
116         if ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
117                 rs->sr_err = LDAP_OTHER;
118                 retcode = META_SEARCH_ERR;
119                 goto done;
120         }
121
122         /* NOTE: we need to copy the newRDN in case it was formed
123          * from a DN by simply changing the length (ITS#5397) */
124         newrdn = op->orr_newrdn;
125         if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) {
126                 ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx );
127         }
128 retry:;
129         ctrls = op->o_ctrls;
130         if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
131         {
132                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
133                 retcode = META_SEARCH_ERR;
134                 goto done;
135         }
136
137         ber = ldap_build_moddn_req( msc->msc_ld, mdn.bv_val, newrdn.bv_val,
138                         mnewSuperior.bv_val, op->orr_deleteoldrdn, ctrls, NULL, &msgid);
139         if (ber) {
140                 candidates[ candidate ].sr_msgid = msgid;
141                 rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODRDN,
142                                                 mdn.bv_val, ber, msgid );
143                 if (rc == msgid)
144                         rc = LDAP_SUCCESS;
145                 else
146                         rc = LDAP_SERVER_DOWN;
147
148                 switch ( rc ) {
149                 case LDAP_SUCCESS:
150                         retcode = META_SEARCH_CANDIDATE;
151                         asyncmeta_set_msc_time(msc);
152                         break;
153
154                 case LDAP_SERVER_DOWN:
155                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
156                         asyncmeta_clear_one_msc(NULL, mc, candidate);
157                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
158                         if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
159                                 nretries = 0;
160                                 /* if the identity changed, there might be need to re-authz */
161                                 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
162                                 goto retry;
163                         }
164
165                 default:
166                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
167                         retcode = META_SEARCH_ERR;
168                 }
169         }
170
171 done:
172         (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
173
174         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
175                 free( mdn.bv_val );
176                 BER_BVZERO( &mdn );
177         }
178
179         if ( !BER_BVISNULL( &mnewSuperior )
180                         && mnewSuperior.bv_val != op->orr_newSup->bv_val )
181         {
182                 free( mnewSuperior.bv_val );
183                 BER_BVZERO( &mnewSuperior );
184         }
185
186         if ( newrdn.bv_val != op->orr_newrdn.bv_val ) {
187                 op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx );
188         }
189
190 doreturn:;
191         Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modrdn_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
192         return retcode;
193 }
194
195 int
196 asyncmeta_back_modrdn( Operation *op, SlapReply *rs )
197 {
198         a_metainfo_t    *mi = ( a_metainfo_t * )op->o_bd->be_private;
199         a_metatarget_t  *mt;
200         a_metaconn_t    *mc;
201         int             rc, candidate = -1;
202         OperationBuffer opbuf;
203         bm_context_t *bc;
204         SlapReply *candidates;
205         slap_callback *cb = op->o_callback;
206
207         Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modrdn: %s\n",
208               op->o_req_dn.bv_val, 0, 0 );
209
210         asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
211         if (bc == NULL) {
212                 rs->sr_err = LDAP_OTHER;
213                 asyncmeta_sender_error(op, rs, cb);
214                 return rs->sr_err;
215         }
216
217         candidates = bc->candidates;
218         mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
219         if ( !mc || rs->sr_err != LDAP_SUCCESS) {
220                 asyncmeta_sender_error(op, rs, cb);
221                 asyncmeta_clear_bm_context(bc);
222                 return rs->sr_err;
223         }
224
225         mt = mi->mi_targets[ candidate ];
226         bc->timeout = mt->mt_timeout[ SLAP_OP_MODRDN ];
227         bc->retrying = LDAP_BACK_RETRYING;
228         bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
229         bc->stoptime = op->o_time + bc->timeout;
230
231         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
232         rc = asyncmeta_add_message_queue(mc, bc);
233         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
234
235         if (rc != LDAP_SUCCESS) {
236                 rs->sr_err = LDAP_BUSY;
237                 rs->sr_text = "Maximum pending ops limit exceeded";
238                 asyncmeta_clear_bm_context(bc);
239                 asyncmeta_sender_error(op, rs, cb);
240                 goto finish;
241         }
242
243         rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
244         switch (rc)
245         {
246         case META_SEARCH_CANDIDATE:
247                 /* target is already bound, just send the request */
248                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn:  "
249                        "cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
250
251                 rc = asyncmeta_back_modrdn_start( op, rs, mc, bc, candidate);
252                 if (rc == META_SEARCH_ERR) {
253                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
254                         asyncmeta_drop_bc(mc, bc);
255                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
256                         asyncmeta_sender_error(op, rs, cb);
257                         asyncmeta_clear_bm_context(bc);
258                         goto finish;
259
260                 }
261                         break;
262         case META_SEARCH_NOT_CANDIDATE:
263                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NOT_CANDIDATE "
264                        "cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
265                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
266                 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
267                 asyncmeta_drop_bc(mc, bc);
268                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
269                 asyncmeta_sender_error(op, rs, cb);
270                 asyncmeta_clear_bm_context(bc);
271                 goto finish;
272
273         case META_SEARCH_NEED_BIND:
274         case META_SEARCH_CONNECTING:
275                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: NEED_BIND "
276                        "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
277                 rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
278                 if (rc == META_SEARCH_ERR) {
279                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
280                         asyncmeta_drop_bc(mc, bc);
281                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
282                         asyncmeta_sender_error(op, rs, cb);
283                         asyncmeta_clear_bm_context(bc);
284                         goto finish;
285                 }
286                 break;
287         case META_SEARCH_BINDING:
288                         Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: BINDING "
289                                "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
290                         /* Todo add the context to the message queue but do not send the request
291                            the receiver must send this when we are done binding */
292                         /* question - how would do receiver know to which targets??? */
293                         break;
294
295         case META_SEARCH_ERR:
296                         Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modrdn: ERR "
297                                "cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
298                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
299                         candidates[ candidate ].sr_type = REP_RESULT;
300                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
301                         asyncmeta_drop_bc(mc, bc);
302                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
303                         asyncmeta_sender_error(op, rs, cb);
304                         asyncmeta_clear_bm_context(bc);
305                         goto finish;
306                 default:
307                         assert( 0 );
308                         break;
309                 }
310         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
311         asyncmeta_start_one_listener(mc, candidates, bc, candidate);
312         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
313 finish:
314         return rs->sr_err;
315 }