]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/modify.c
Happy New Year
[openldap] / servers / slapd / back-asyncmeta / modify.c
1 /* modify.c - modify request handler for back-asyncmeta */
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/string.h>
28 #include <ac/socket.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_modify_start(Operation *op,
38                             SlapReply *rs,
39                             a_metaconn_t *mc,
40                             bm_context_t *bc,
41                             int candidate)
42 {
43         int             i, isupdate, rc = 0, nretries = 1;
44         a_dncookie      dc;
45         a_metainfo_t    *mi = mc->mc_info;
46         a_metatarget_t  *mt = mi->mi_targets[ candidate ];
47         LDAPMod         **modv = NULL;
48         LDAPMod         *mods = NULL;
49         struct berval mdn;
50         Modifications   *ml;
51         struct berval   mapped;
52         meta_search_candidate_t retcode = META_SEARCH_CANDIDATE;
53                 BerElement *ber = NULL;
54         a_metasingleconn_t      *msc = &mc->mc_conns[ candidate ];
55         SlapReply               *candidates = bc->candidates;
56         ber_int_t       msgid;
57         LDAPControl             **ctrls = NULL;
58
59         /*
60          * Rewrite the modify dn, if needed
61          */
62         dc.target = mt;
63         dc.conn = op->o_conn;
64         dc.rs = rs;
65         dc.ctx = "modifyDN";
66
67         switch ( asyncmeta_dn_massage( &dc, &op->o_req_dn, &mdn ) )
68         {
69         case LDAP_SUCCESS:
70                 break;
71         case LDAP_UNWILLING_TO_PERFORM:
72                 rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
73                 rs->sr_text = "Operation not allowed";
74                 retcode = META_SEARCH_ERR;
75                 goto doreturn;
76         default:
77                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
78                 retcode = META_SEARCH_NOT_CANDIDATE;
79                 goto doreturn;
80         }
81
82         for ( i = 0, ml = op->orm_modlist; ml; i++ ,ml = ml->sml_next )
83                 ;
84
85         mods = ch_malloc( sizeof( LDAPMod )*i );
86         if ( mods == NULL ) {
87                 rs->sr_err = LDAP_OTHER;
88                 retcode = META_SEARCH_ERR;
89                 goto doreturn;
90         }
91         modv = ( LDAPMod ** )ch_malloc( ( i + 1 )*sizeof( LDAPMod * ) );
92         if ( modv == NULL ) {
93                 rs->sr_err = LDAP_OTHER;
94                 retcode = META_SEARCH_ERR;
95                 goto doreturn;
96         }
97
98         dc.ctx = "modifyAttrDN";
99         isupdate = be_shadow_update( op );
100         for ( i = 0, ml = op->orm_modlist; ml; ml = ml->sml_next ) {
101                 int     j, is_oc = 0;
102
103                 if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod  )
104                 {
105                         continue;
106                 }
107
108                 if ( ml->sml_desc == slap_schema.si_ad_objectClass
109                                 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
110                 {
111                         is_oc = 1;
112                         mapped = ml->sml_desc->ad_cname;
113
114                 } else {
115                         asyncmeta_map( &mt->mt_rwmap.rwm_at,
116                                         &ml->sml_desc->ad_cname, &mapped,
117                                         BACKLDAP_MAP );
118                         if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
119                                 continue;
120                         }
121                 }
122
123                 modv[ i ] = &mods[ i ];
124                 mods[ i ].mod_op = ml->sml_op | LDAP_MOD_BVALUES;
125                 mods[ i ].mod_type = mapped.bv_val;
126
127                 /*
128                  * FIXME: dn-valued attrs should be rewritten
129                  * to allow their use in ACLs at the back-ldap
130                  * level.
131                  */
132                 if ( ml->sml_values != NULL ) {
133                         if ( is_oc ) {
134                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
135                                         ;
136                                 mods[ i ].mod_bvalues =
137                                         (struct berval **)ch_malloc( ( j + 1 ) *
138                                         sizeof( struct berval * ) );
139                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); ) {
140                                         struct ldapmapping      *mapping;
141
142                                         asyncmeta_mapping( &mt->mt_rwmap.rwm_oc,
143                                                         &ml->sml_values[ j ], &mapping, BACKLDAP_MAP );
144
145                                         if ( mapping == NULL ) {
146                                                 if ( mt->mt_rwmap.rwm_oc.drop_missing ) {
147                                                         continue;
148                                                 }
149                                                 mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
150
151                                         } else {
152                                                 mods[ i ].mod_bvalues[ j ] = &mapping->dst;
153                                         }
154                                         j++;
155                                 }
156                                 mods[ i ].mod_bvalues[ j ] = NULL;
157
158                         } else {
159                                 if ( ml->sml_desc->ad_type->sat_syntax ==
160                                                 slap_schema.si_syn_distinguishedName )
161                                 {
162                                         ( void )asyncmeta_dnattr_rewrite( &dc, ml->sml_values );
163                                         if ( ml->sml_values == NULL ) {
164                                                 continue;
165                                         }
166                                 }
167
168                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ )
169                                         ;
170                                 mods[ i ].mod_bvalues =
171                                         (struct berval **)ch_malloc( ( j + 1 ) *
172                                         sizeof( struct berval * ) );
173                                 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
174                                         mods[ i ].mod_bvalues[ j ] = &ml->sml_values[ j ];
175                                 }
176                                 mods[ i ].mod_bvalues[ j ] = NULL;
177                         }
178
179                 } else {
180                         mods[ i ].mod_bvalues = NULL;
181                 }
182
183                 i++;
184         }
185         modv[ i ] = 0;
186
187 retry:;
188         ctrls = op->o_ctrls;
189         if ( asyncmeta_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS )
190         {
191                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
192                 retcode = META_SEARCH_ERR;
193                 goto done;
194         }
195
196         ber = ldap_build_modify_req( msc->msc_ld, mdn.bv_val, modv, ctrls, NULL, &msgid);
197         if (ber) {
198                 candidates[ candidate ].sr_msgid = msgid;
199                 rc = ldap_send_initial_request( msc->msc_ld, LDAP_REQ_MODIFY,
200                                                 mdn.bv_val, ber, msgid );
201                 if (rc == msgid)
202                         rc = LDAP_SUCCESS;
203                 else
204                         rc = LDAP_SERVER_DOWN;
205
206                 switch ( rc ) {
207                 case LDAP_SUCCESS:
208                         retcode = META_SEARCH_CANDIDATE;
209                         asyncmeta_set_msc_time(msc);
210                         break;
211
212                 case LDAP_SERVER_DOWN:
213                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
214                         asyncmeta_clear_one_msc(NULL, mc, candidate);
215                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
216                         if ( nretries && asyncmeta_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND ) ) {
217                                 nretries = 0;
218                                 /* if the identity changed, there might be need to re-authz */
219                                 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
220                                 goto retry;
221                         }
222
223                 default:
224                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
225                         retcode = META_SEARCH_ERR;
226                 }
227         }
228
229 done:
230         (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
231
232         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
233                 free( mdn.bv_val );
234                 BER_BVZERO( &mdn );
235         }
236         if ( modv != NULL ) {
237                 for ( i = 0; modv[ i ]; i++ ) {
238                         free( modv[ i ]->mod_bvalues );
239                 }
240         }
241         free( mods );
242         free( modv );
243
244 doreturn:;
245         Debug( LDAP_DEBUG_TRACE, "%s <<< asyncmeta_back_modify_start[%p]=%d\n", op->o_log_prefix, msc, candidates[candidate].sr_msgid );
246         return retcode;
247 }
248
249 int
250 asyncmeta_back_modify( Operation *op, SlapReply *rs )
251 {
252         a_metainfo_t    *mi = ( a_metainfo_t * )op->o_bd->be_private;
253         a_metatarget_t  *mt;
254         a_metaconn_t    *mc;
255         int             rc, candidate = -1;
256         OperationBuffer opbuf;
257         bm_context_t *bc;
258         SlapReply *candidates;
259         slap_callback *cb = op->o_callback;
260
261         Debug(LDAP_DEBUG_ARGS, "==> asyncmeta_back_modify: %s\n",
262               op->o_req_dn.bv_val, 0, 0 );
263
264         asyncmeta_new_bm_context(op, rs, &bc, mi->mi_ntargets );
265         if (bc == NULL) {
266                 rs->sr_err = LDAP_OTHER;
267                 asyncmeta_sender_error(op, rs, cb);
268                 return rs->sr_err;
269         }
270
271         candidates = bc->candidates;
272         mc = asyncmeta_getconn( op, rs, candidates, &candidate, LDAP_BACK_DONTSEND, 0);
273         if ( !mc || rs->sr_err != LDAP_SUCCESS) {
274                 asyncmeta_sender_error(op, rs, cb);
275                 asyncmeta_clear_bm_context(bc);
276                 return rs->sr_err;
277         }
278
279         mt = mi->mi_targets[ candidate ];
280         bc->timeout = mt->mt_timeout[ SLAP_OP_MODIFY ];
281         bc->retrying = LDAP_BACK_RETRYING;
282         bc->sendok = ( LDAP_BACK_SENDRESULT | bc->retrying );
283         bc->stoptime = op->o_time + bc->timeout;
284
285         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
286         rc = asyncmeta_add_message_queue(mc, bc);
287         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
288
289         if (rc != LDAP_SUCCESS) {
290                 rs->sr_err = LDAP_BUSY;
291                 rs->sr_text = "Maximum pending ops limit exceeded";
292                 asyncmeta_clear_bm_context(bc);
293                 asyncmeta_sender_error(op, rs, cb);
294                 goto finish;
295         }
296
297         rc = asyncmeta_dobind_init_with_retry(op, rs, bc, mc, candidate);
298         switch (rc)
299         {
300         case META_SEARCH_CANDIDATE:
301                 /* target is already bound, just send the request */
302                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify:  "
303                        "cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
304
305                 rc = asyncmeta_back_modify_start( op, rs, mc, bc, candidate);
306                 if (rc == META_SEARCH_ERR) {
307                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
308                         asyncmeta_drop_bc(mc, bc);
309                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
310                         asyncmeta_sender_error(op, rs, cb);
311                         asyncmeta_clear_bm_context(bc);
312                         goto finish;
313
314                 }
315                         break;
316         case META_SEARCH_NOT_CANDIDATE:
317                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NOT_CANDIDATE "
318                        "cnd=\"%ld\"\n", op->o_log_prefix, candidate , 0);
319                 candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
320                 ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
321                 asyncmeta_drop_bc(mc, bc);
322                 ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
323                 asyncmeta_sender_error(op, rs, cb);
324                 asyncmeta_clear_bm_context(bc);
325                 goto finish;
326
327         case META_SEARCH_NEED_BIND:
328         case META_SEARCH_CONNECTING:
329                 Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: NEED_BIND "
330                        "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
331                 rc = asyncmeta_dobind_init(op, rs, bc, mc, candidate);
332                 if (rc == META_SEARCH_ERR) {
333                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
334                         asyncmeta_drop_bc(mc, bc);
335                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
336                         asyncmeta_sender_error(op, rs, cb);
337                         asyncmeta_clear_bm_context(bc);
338                         goto finish;
339                 }
340                 break;
341         case META_SEARCH_BINDING:
342                         Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: BINDING "
343                                "cnd=\"%ld\" %p\n", op->o_log_prefix, candidate , &mc->mc_conns[candidate]);
344                         /* Todo add the context to the message queue but do not send the request
345                            the receiver must send this when we are done binding */
346                         /* question - how would do receiver know to which targets??? */
347                         break;
348
349         case META_SEARCH_ERR:
350                         Debug( LDAP_DEBUG_TRACE, "%s asyncmeta_back_modify: ERR "
351                                "cnd=\"%ldd\"\n", op->o_log_prefix, candidate , 0);
352                         candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
353                         candidates[ candidate ].sr_type = REP_RESULT;
354                         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
355                         asyncmeta_drop_bc(mc, bc);
356                         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
357                         asyncmeta_sender_error(op, rs, cb);
358                         asyncmeta_clear_bm_context(bc);
359                         goto finish;
360                 default:
361                         assert( 0 );
362                         break;
363                 }
364         ldap_pvt_thread_mutex_lock( &mc->mc_om_mutex);
365         asyncmeta_start_one_listener(mc, candidates, bc, candidate);
366         ldap_pvt_thread_mutex_unlock( &mc->mc_om_mutex);
367 finish:
368         return rs->sr_err;
369 }