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