]> git.sur5r.net Git - openldap/blob - servers/slapd/back-asyncmeta/init.c
ITS#8845 Recognise control-exop compatibility
[openldap] / servers / slapd / back-asyncmeta / init.c
1 /* init.c - initialization of a back-asyncmeta database */
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 "config.h"
32 #include "../back-ldap/back-ldap.h"
33 #include "back-asyncmeta.h"
34
35 int
36 asyncmeta_back_open(
37         BackendInfo     *bi )
38 {
39         /* FIXME: need to remove the pagedResults, and likely more... */
40         bi->bi_controls = slap_known_controls;
41
42         return 0;
43 }
44
45 int
46 asyncmeta_back_initialize(
47         BackendInfo     *bi )
48 {
49         bi->bi_flags =
50 #if 0
51         /* this is not (yet) set essentially because back-meta does not
52          * directly support extended operations... */
53 #ifdef LDAP_DYNAMIC_OBJECTS
54                 /* this is set because all the support a proxy has to provide
55                  * is the capability to forward the refresh exop, and to
56                  * pass thru entries that contain the dynamicObject class
57                  * and the entryTtl attribute */
58                 SLAP_BFLAG_DYNAMIC |
59 #endif /* LDAP_DYNAMIC_OBJECTS */
60 #endif
61
62                 /* back-meta recognizes RFC4525 increment;
63                  * let the remote server complain, if needed (ITS#5912) */
64                 SLAP_BFLAG_INCREMENT;
65
66         bi->bi_open = asyncmeta_back_open;
67         bi->bi_config = 0;
68         bi->bi_close = 0;
69         bi->bi_destroy = 0;
70
71         bi->bi_db_init = asyncmeta_back_db_init;
72         bi->bi_db_config = config_generic_wrapper;
73         bi->bi_db_open = asyncmeta_back_db_open;
74         bi->bi_db_close = asyncmeta_back_db_close;
75         bi->bi_db_destroy = asyncmeta_back_db_destroy;
76
77         bi->bi_op_bind = asyncmeta_back_bind;
78         bi->bi_op_unbind = 0;
79         bi->bi_op_search = asyncmeta_back_search;
80         bi->bi_op_compare = asyncmeta_back_compare;
81         bi->bi_op_modify = asyncmeta_back_modify;
82         bi->bi_op_modrdn = asyncmeta_back_modrdn;
83         bi->bi_op_add = asyncmeta_back_add;
84         bi->bi_op_delete = asyncmeta_back_delete;
85         bi->bi_op_abandon = 0;
86
87         bi->bi_extended = 0;
88
89         bi->bi_chk_referrals = 0;
90
91         bi->bi_connection_init = 0;
92         bi->bi_connection_destroy = asyncmeta_back_conn_destroy;
93
94         return asyncmeta_back_init_cf( bi );
95 }
96
97 int
98 asyncmeta_back_db_init(
99         Backend         *be,
100         ConfigReply     *cr)
101 {
102         a_metainfo_t    *mi;
103         int             i;
104         BackendInfo     *bi;
105
106         bi = backend_info( "ldap" );
107         if ( !bi || !bi->bi_extra ) {
108                 Debug( LDAP_DEBUG_ANY,
109                         "asyncmeta_back_db_init: needs back-ldap\n",
110                         0, 0, 0 );
111                 return 1;
112         }
113
114         mi = ch_calloc( 1, sizeof( a_metainfo_t ) );
115         if ( mi == NULL ) {
116                 return -1;
117         }
118
119         /* set default flags */
120         mi->mi_flags =
121                 META_BACK_F_DEFER_ROOTDN_BIND
122                 | META_BACK_F_PROXYAUTHZ_ALWAYS
123                 | META_BACK_F_PROXYAUTHZ_ANON
124                 | META_BACK_F_PROXYAUTHZ_NOANON;
125
126         /*
127          * At present the default is no default target;
128          * this may change
129          */
130         mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
131         mi->mi_bind_timeout.tv_sec = 0;
132         mi->mi_bind_timeout.tv_usec = META_BIND_TIMEOUT;
133
134         mi->mi_rebind_f = asyncmeta_back_default_rebind;
135         mi->mi_urllist_f = asyncmeta_back_default_urllist;
136
137         ldap_pvt_thread_mutex_init( &mi->mi_cache.mutex );
138
139         /* safe default */
140         mi->mi_nretries = META_RETRY_DEFAULT;
141         mi->mi_version = LDAP_VERSION3;
142
143         for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
144                 mi->mi_conn_priv[ i ].mic_num = 0;
145                 LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
146         }
147         mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
148
149         mi->mi_ldap_extra = (ldap_extra_t *)bi->bi_extra;
150         ldap_pvt_thread_mutex_init( &mi->mi_mc_mutex);
151
152         be->be_private = mi;
153         be->be_cf_ocs = be->bd_info->bi_cf_ocs;
154
155         return 0;
156 }
157
158 int
159 asyncmeta_target_finish(
160         a_metainfo_t *mi,
161         a_metatarget_t *mt,
162         const char *log,
163         char *msg,
164         size_t msize
165 )
166 {
167         slap_bindconf   sb = { BER_BVNULL };
168         struct berval mapped;
169         int rc;
170         int msc_num, i;
171
172         ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri );
173         sb.sb_version = mt->mt_version;
174         sb.sb_method = LDAP_AUTH_SIMPLE;
175         BER_BVSTR( &sb.sb_binddn, "" );
176
177         if ( META_BACK_TGT_T_F_DISCOVER( mt ) ) {
178                 rc = slap_discover_feature( &sb,
179                                 slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
180                                 LDAP_FEATURE_ABSOLUTE_FILTERS );
181                 if ( rc == LDAP_COMPARE_TRUE ) {
182                         mt->mt_flags |= LDAP_BACK_F_T_F;
183                 }
184         }
185
186         if ( META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
187                 rc = slap_discover_feature( &sb,
188                                 slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
189                                 LDAP_EXOP_CANCEL );
190                 if ( rc == LDAP_COMPARE_TRUE ) {
191                         mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP;
192                 }
193         }
194
195         if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )
196                 || mt->mt_idassert_authz != NULL )
197         {
198                 mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_ALWAYS;
199         }
200
201         if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
202                 && !( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
203         {
204                 snprintf( msg, msize,
205                         "%s: inconsistent idassert configuration "
206                         "(likely authz=\"*\" used with \"non-prescriptive\" flag)",
207                         log );
208                 Debug( LDAP_DEBUG_ANY, "%s (target %s)\n",
209                         msg, mt->mt_uri, 0 );
210                 return 1;
211         }
212
213         if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
214         {
215                 mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_ANON;
216         }
217
218         if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
219         {
220                 mi->mi_flags &= ~META_BACK_F_PROXYAUTHZ_NOANON;
221         }
222
223         BER_BVZERO( &mapped );
224         asyncmeta_map( &mt->mt_rwmap.rwm_at,
225                 &slap_schema.si_ad_entryDN->ad_cname, &mapped,
226                 BACKLDAP_REMAP );
227         if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
228                 mt->mt_rep_flags |= REP_NO_ENTRYDN;
229         }
230
231         BER_BVZERO( &mapped );
232         asyncmeta_map( &mt->mt_rwmap.rwm_at,
233                 &slap_schema.si_ad_subschemaSubentry->ad_cname, &mapped,
234                 BACKLDAP_REMAP );
235         if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
236                 mt->mt_rep_flags |= REP_NO_SUBSCHEMA;
237         }
238         return 0;
239 }
240
241 int
242 asyncmeta_back_db_open(
243         Backend         *be,
244         ConfigReply     *cr )
245 {
246         a_metainfo_t    *mi = (a_metainfo_t *)be->be_private;
247
248         char msg[SLAP_TEXT_BUFLEN];
249
250         int             i, rc;
251
252         if ( mi->mi_ntargets == 0 ) {
253                 /* Dynamically added, nothing to check here until
254                  * some targets get added
255                  */
256                 if ( slapMode & SLAP_SERVER_RUNNING )
257                         return 0;
258
259                 Debug( LDAP_DEBUG_ANY,
260                         "asyncmeta_back_db_open: no targets defined\n",
261                         0, 0, 0 );
262                 return 1;
263         }
264         mi->mi_num_conns = 0;
265         for ( i = 0; i < mi->mi_ntargets; i++ ) {
266                 a_metatarget_t  *mt = mi->mi_targets[ i ];
267                 if ( asyncmeta_target_finish( mi, mt,
268                         "asyncmeta_back_db_open", msg, sizeof( msg )))
269                         return 1;
270         }
271         mi->mi_num_conns = (mi->mi_max_target_conns == 0) ? META_BACK_CFG_MAX_TARGET_CONNS : mi->mi_max_target_conns;
272         assert(mi->mi_num_conns > 0);
273         mi->mi_conns = ch_calloc( mi->mi_num_conns, sizeof( a_metaconn_t ));
274         for (i = 0; i < mi->mi_num_conns; i++) {
275                 a_metaconn_t *mc = &mi->mi_conns[i];
276                 ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
277                 mc->mc_authz_target = META_BOUND_NONE;
278                 mc->mc_conns = ch_calloc( mi->mi_ntargets, sizeof( a_metasingleconn_t ));
279                 mc->mc_info = mi;
280         }
281
282         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
283         mi->mi_task = ldap_pvt_runqueue_insert( &slapd_rq, 0,
284                 asyncmeta_timeout_loop, mi, "asyncmeta_timeout_loop", be->be_suffix[0].bv_val );
285         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
286         return 0;
287 }
288
289 /*
290  * asyncmeta_back_conn_free()
291  *
292  * actually frees a connection; the reference count must be 0,
293  * and it must not (or no longer) be in the cache.
294  */
295 void
296 asyncmeta_back_conn_free(
297         void            *v_mc )
298 {
299         a_metaconn_t            *mc = v_mc;
300
301         assert( mc != NULL );
302         ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
303         free( mc );
304 }
305
306 static void
307 mapping_free(
308         void            *v_mapping )
309 {
310         struct ldapmapping *mapping = v_mapping;
311         ch_free( mapping->src.bv_val );
312         ch_free( mapping->dst.bv_val );
313         ch_free( mapping );
314 }
315
316 static void
317 mapping_dst_free(
318         void            *v_mapping )
319 {
320         struct ldapmapping *mapping = v_mapping;
321
322         if ( BER_BVISEMPTY( &mapping->dst ) ) {
323                 mapping_free( &mapping[ -1 ] );
324         }
325 }
326
327 void
328 asyncmeta_back_map_free( struct ldapmap *lm )
329 {
330         avl_free( lm->remap, mapping_dst_free );
331         avl_free( lm->map, mapping_free );
332         lm->remap = NULL;
333         lm->map = NULL;
334 }
335
336 static void
337 asyncmeta_back_stop_miconns( a_metainfo_t *mi )
338 {
339
340         /*Todo do any other mc cleanup here if necessary*/
341 }
342
343 static void
344 asyncmeta_back_clear_miconns( a_metainfo_t *mi )
345 {
346         int i, j;
347         a_metaconn_t *mc;
348         for (i = 0; i < mi->mi_num_conns; i++) {
349                 mc = &mi->mi_conns[i];
350                 /* todo clear the message queue */
351                 for (j = 0; j < mi->mi_ntargets; j ++) {
352                         asyncmeta_clear_one_msc(NULL, mc, j);
353                 }
354                 free(mc->mc_conns);
355                 ldap_pvt_thread_mutex_destroy( &mc->mc_om_mutex );
356         }
357         free(mi->mi_conns);
358 }
359
360 static void
361 asyncmeta_target_free(
362         a_metatarget_t  *mt )
363 {
364         if ( mt->mt_uri ) {
365                 free( mt->mt_uri );
366                 ldap_pvt_thread_mutex_destroy( &mt->mt_uri_mutex );
367         }
368         if ( mt->mt_subtree ) {
369                 asyncmeta_subtree_destroy( mt->mt_subtree );
370                 mt->mt_subtree = NULL;
371         }
372         if ( mt->mt_filter ) {
373                 asyncmeta_filter_destroy( mt->mt_filter );
374                 mt->mt_filter = NULL;
375         }
376         if ( !BER_BVISNULL( &mt->mt_psuffix ) ) {
377                 free( mt->mt_psuffix.bv_val );
378         }
379         if ( !BER_BVISNULL( &mt->mt_nsuffix ) ) {
380                 free( mt->mt_nsuffix.bv_val );
381         }
382         if ( !BER_BVISNULL( &mt->mt_binddn ) ) {
383                 free( mt->mt_binddn.bv_val );
384         }
385         if ( !BER_BVISNULL( &mt->mt_bindpw ) ) {
386                 free( mt->mt_bindpw.bv_val );
387         }
388         if ( !BER_BVISNULL( &mt->mt_idassert_authcID ) ) {
389                 ch_free( mt->mt_idassert_authcID.bv_val );
390         }
391         if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
392                 ch_free( mt->mt_idassert_authcDN.bv_val );
393         }
394         if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
395                 ch_free( mt->mt_idassert_passwd.bv_val );
396         }
397         if ( !BER_BVISNULL( &mt->mt_idassert_authzID ) ) {
398                 ch_free( mt->mt_idassert_authzID.bv_val );
399         }
400         if ( !BER_BVISNULL( &mt->mt_idassert_sasl_mech ) ) {
401                 ch_free( mt->mt_idassert_sasl_mech.bv_val );
402         }
403         if ( !BER_BVISNULL( &mt->mt_idassert_sasl_realm ) ) {
404                 ch_free( mt->mt_idassert_sasl_realm.bv_val );
405         }
406         if ( mt->mt_idassert_authz != NULL ) {
407                 ber_bvarray_free( mt->mt_idassert_authz );
408         }
409         if ( mt->mt_rwmap.rwm_rw ) {
410                 rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
411                 if ( mt->mt_rwmap.rwm_bva_rewrite )
412                         ber_bvarray_free( mt->mt_rwmap.rwm_bva_rewrite );
413         }
414         asyncmeta_back_map_free( &mt->mt_rwmap.rwm_oc );
415         asyncmeta_back_map_free( &mt->mt_rwmap.rwm_at );
416         ber_bvarray_free( mt->mt_rwmap.rwm_bva_map );
417         free( mt );
418 }
419
420 int
421 asyncmeta_back_db_close(
422         Backend         *be,
423         ConfigReply     *cr )
424 {
425         a_metainfo_t    *mi;
426
427         if ( be->be_private ) {
428                 int i;
429
430                 mi = ( a_metainfo_t * )be->be_private;
431                 if ( mi->mi_task != NULL ) {
432                         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
433                         if ( ldap_pvt_runqueue_isrunning( &slapd_rq, mi->mi_task )) {
434                                 ldap_pvt_runqueue_stoptask( &slapd_rq,  mi->mi_task);
435                         }
436                         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
437                         mi->mi_task = NULL;
438                 }
439                 ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
440                 asyncmeta_back_stop_miconns( mi );
441                 ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
442         }
443 }
444
445 int
446 asyncmeta_back_db_destroy(
447         Backend         *be,
448         ConfigReply     *cr )
449 {
450         a_metainfo_t    *mi;
451
452         if ( be->be_private ) {
453                 int i;
454
455                 mi = ( a_metainfo_t * )be->be_private;
456                 /*
457                  * Destroy the per-target stuff (assuming there's at
458                  * least one ...)
459                  */
460                 if ( mi->mi_targets != NULL ) {
461                         for ( i = 0; i < mi->mi_ntargets; i++ ) {
462                                 a_metatarget_t  *mt = mi->mi_targets[ i ];
463
464                                 if ( META_BACK_TGT_QUARANTINE( mt ) ) {
465                                         if ( mt->mt_quarantine.ri_num != mi->mi_quarantine.ri_num )
466                                         {
467                                                 mi->mi_ldap_extra->retry_info_destroy( &mt->mt_quarantine );
468                                         }
469
470                                         ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
471                                 }
472
473                                 asyncmeta_target_free( mt );
474                         }
475
476                         free( mi->mi_targets );
477                 }
478
479                 ldap_pvt_thread_mutex_lock( &mi->mi_cache.mutex );
480                 if ( mi->mi_cache.tree ) {
481                         avl_free( mi->mi_cache.tree, asyncmeta_dncache_free );
482                 }
483
484                 ldap_pvt_thread_mutex_unlock( &mi->mi_cache.mutex );
485                 ldap_pvt_thread_mutex_destroy( &mi->mi_cache.mutex );
486
487                 if ( mi->mi_candidates != NULL ) {
488                         ber_memfree_x( mi->mi_candidates, NULL );
489                 }
490
491                 if ( META_BACK_QUARANTINE( mi ) ) {
492                         mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine );
493                 }
494         }
495         ldap_pvt_thread_mutex_lock( &mi->mi_mc_mutex );
496         asyncmeta_back_clear_miconns(mi);
497         ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
498         ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
499
500         free( be->be_private );
501         return 0;
502 }
503
504 #if SLAPD_ASYNCMETA == SLAPD_MOD_DYNAMIC
505
506 /* conditionally define the init_module() function */
507 SLAP_BACKEND_INIT_MODULE( asyncmeta )
508
509 #endif /* SLAPD_ASYNCMETA == SLAPD_MOD_DYNAMIC */