1/* $OpenLDAP$ */
2/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1999-2011 The OpenLDAP Foundation.
5 * Portions Copyright 2001-2003 Pierangelo Masarati.
6 * Portions Copyright 1999-2003 Howard Chu.
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#include "portable.h"
19
20#include <stdio.h>
21
22#include <ac/string.h>
23#include <ac/socket.h>
24
25#include "slap.h"
26#include "config.h"
27#include "../back-ldap/back-ldap.h"
28#include "back-meta.h"
29
30int
31meta_back_open(
32	BackendInfo	*bi )
33{
34	/* FIXME: need to remove the pagedResults, and likely more... */
35	bi->bi_controls = slap_known_controls;
36
37	return 0;
38}
39
40int
41meta_back_initialize(
42	BackendInfo	*bi )
43{
44	bi->bi_flags =
45#if 0
46	/* this is not (yet) set essentially because back-meta does not
47	 * directly support extended operations... */
48#ifdef LDAP_DYNAMIC_OBJECTS
49		/* this is set because all the support a proxy has to provide
50		 * is the capability to forward the refresh exop, and to
51		 * pass thru entries that contain the dynamicObject class
52		 * and the entryTtl attribute */
53		SLAP_BFLAG_DYNAMIC |
54#endif /* LDAP_DYNAMIC_OBJECTS */
55#endif
56
57		/* back-meta recognizes RFC4525 increment;
58		 * let the remote server complain, if needed (ITS#5912) */
59		SLAP_BFLAG_INCREMENT;
60
61	bi->bi_open = meta_back_open;
62	bi->bi_config = 0;
63	bi->bi_close = 0;
64	bi->bi_destroy = 0;
65
66	bi->bi_db_init = meta_back_db_init;
67	bi->bi_db_config = meta_back_db_config;
68	bi->bi_db_open = meta_back_db_open;
69	bi->bi_db_close = 0;
70	bi->bi_db_destroy = meta_back_db_destroy;
71
72	bi->bi_op_bind = meta_back_bind;
73	bi->bi_op_unbind = 0;
74	bi->bi_op_search = meta_back_search;
75	bi->bi_op_compare = meta_back_compare;
76	bi->bi_op_modify = meta_back_modify;
77	bi->bi_op_modrdn = meta_back_modrdn;
78	bi->bi_op_add = meta_back_add;
79	bi->bi_op_delete = meta_back_delete;
80	bi->bi_op_abandon = 0;
81
82	bi->bi_extended = 0;
83
84	bi->bi_chk_referrals = 0;
85
86	bi->bi_connection_init = 0;
87	bi->bi_connection_destroy = meta_back_conn_destroy;
88
89	return 0;
90}
91
92int
93meta_back_db_init(
94	Backend		*be,
95	ConfigReply	*cr)
96{
97	metainfo_t	*mi;
98	int		i;
99	BackendInfo	*bi;
100
101	bi = backend_info( "ldap" );
102	if ( !bi || !bi->bi_extra ) {
103		Debug( LDAP_DEBUG_ANY,
104			"meta_back_db_init: needs back-ldap\n",
105			0, 0, 0 );
106		return 1;
107	}
108
109	mi = ch_calloc( 1, sizeof( metainfo_t ) );
110	if ( mi == NULL ) {
111 		return -1;
112 	}
113
114	/* set default flags */
115	mi->mi_flags =
116		META_BACK_F_DEFER_ROOTDN_BIND;
117
118	/*
119	 * At present the default is no default target;
120	 * this may change
121	 */
122	mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
123	mi->mi_bind_timeout.tv_sec = 0;
124	mi->mi_bind_timeout.tv_usec = META_BIND_TIMEOUT;
125
126	mi->mi_rebind_f = meta_back_default_rebind;
127	mi->mi_urllist_f = meta_back_default_urllist;
128
129	ldap_pvt_thread_mutex_init( &mi->mi_conninfo.lai_mutex );
130	ldap_pvt_thread_mutex_init( &mi->mi_cache.mutex );
131
132	/* safe default */
133	mi->mi_nretries = META_RETRY_DEFAULT;
134	mi->mi_version = LDAP_VERSION3;
135
136	for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
137		mi->mi_conn_priv[ i ].mic_num = 0;
138		LDAP_TAILQ_INIT( &mi->mi_conn_priv[ i ].mic_priv );
139	}
140	mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
141
142	mi->mi_ldap_extra = (ldap_extra_t *)bi->bi_extra;
143
144	be->be_private = mi;
145
146	return 0;
147}
148
149int
150meta_back_db_open(
151	Backend		*be,
152	ConfigReply	*cr )
153{
154	metainfo_t	*mi = (metainfo_t *)be->be_private;
155
156	int		i,
157			not_always = 0,
158			not_always_anon_proxyauthz = 0,
159			not_always_anon_non_prescriptive = 0,
160			rc;
161
162	if ( mi->mi_ntargets == 0 ) {
163		Debug( LDAP_DEBUG_ANY,
164			"meta_back_db_open: no targets defined\n",
165			0, 0, 0 );
166		return 1;
167	}
168
169	for ( i = 0; i < mi->mi_ntargets; i++ ) {
170		slap_bindconf	sb = { BER_BVNULL };
171		metatarget_t	*mt = mi->mi_targets[ i ];
172
173		struct berval mapped;
174
175		ber_str2bv( mt->mt_uri, 0, 0, &sb.sb_uri );
176		sb.sb_version = mt->mt_version;
177		sb.sb_method = LDAP_AUTH_SIMPLE;
178		BER_BVSTR( &sb.sb_binddn, "" );
179
180		if ( META_BACK_TGT_T_F_DISCOVER( mt ) ) {
181			rc = slap_discover_feature( &sb,
182					slap_schema.si_ad_supportedFeatures->ad_cname.bv_val,
183					LDAP_FEATURE_ABSOLUTE_FILTERS );
184			if ( rc == LDAP_COMPARE_TRUE ) {
185				mt->mt_flags |= LDAP_BACK_F_T_F;
186			}
187		}
188
189		if ( META_BACK_TGT_CANCEL_DISCOVER( mt ) ) {
190			rc = slap_discover_feature( &sb,
191					slap_schema.si_ad_supportedExtension->ad_cname.bv_val,
192					LDAP_EXOP_CANCEL );
193			if ( rc == LDAP_COMPARE_TRUE ) {
194				mt->mt_flags |= LDAP_BACK_F_CANCEL_EXOP;
195			}
196		}
197
198		if ( not_always == 0 ) {
199			if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE )
200				|| mt->mt_idassert_authz != NULL )
201			{
202				not_always = 1;
203			}
204		}
205
206		if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL )
207			&& !( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
208		{
209			Debug( LDAP_DEBUG_ANY, "meta_back_db_open(%s): "
210				"target #%d inconsistent idassert configuration "
211				"(likely authz=\"*\" used with \"non-prescriptive\" flag)\n",
212				be->be_suffix[ 0 ].bv_val, i, 0 );
213			return 1;
214		}
215
216		if ( not_always_anon_proxyauthz == 0 ) {
217			if ( !( mt->mt_idassert_flags & LDAP_BACK_AUTH_AUTHZ_ALL ) )
218			{
219				not_always_anon_proxyauthz = 1;
220			}
221		}
222
223		if ( not_always_anon_non_prescriptive == 0 ) {
224			if ( ( mt->mt_idassert_flags & LDAP_BACK_AUTH_PRESCRIPTIVE ) )
225			{
226				not_always_anon_non_prescriptive = 1;
227			}
228		}
229
230		BER_BVZERO( &mapped );
231		ldap_back_map( &mt->mt_rwmap.rwm_at,
232			&slap_schema.si_ad_entryDN->ad_cname, &mapped,
233			BACKLDAP_REMAP );
234		if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
235			mt->mt_rep_flags |= REP_NO_ENTRYDN;
236		}
237
238		BER_BVZERO( &mapped );
239		ldap_back_map( &mt->mt_rwmap.rwm_at,
240			&slap_schema.si_ad_subschemaSubentry->ad_cname, &mapped,
241			BACKLDAP_REMAP );
242		if ( BER_BVISNULL( &mapped ) || mapped.bv_val[0] == '\0' ) {
243			mt->mt_rep_flags |= REP_NO_SUBSCHEMA;
244		}
245	}
246
247	if ( not_always == 0 ) {
248		mi->mi_flags |= META_BACK_F_PROXYAUTHZ_ALWAYS;
249	}
250
251	if ( not_always_anon_proxyauthz == 0 ) {
252		mi->mi_flags |= META_BACK_F_PROXYAUTHZ_ANON;
253
254	} else if ( not_always_anon_non_prescriptive == 0 ) {
255		mi->mi_flags |= META_BACK_F_PROXYAUTHZ_NOANON;
256	}
257
258	return 0;
259}
260
261/*
262 * meta_back_conn_free()
263 *
264 * actually frees a connection; the reference count must be 0,
265 * and it must not (or no longer) be in the cache.
266 */
267void
268meta_back_conn_free(
269	void 		*v_mc )
270{
271	metaconn_t		*mc = v_mc;
272	int			ntargets;
273
274	assert( mc != NULL );
275	assert( mc->mc_refcnt == 0 );
276
277	/* at least one must be present... */
278	ntargets = mc->mc_info->mi_ntargets;
279	assert( ntargets > 0 );
280
281	for ( ; ntargets--; ) {
282		(void)meta_clear_one_candidate( NULL, mc, ntargets );
283	}
284
285	if ( !BER_BVISNULL( &mc->mc_local_ndn ) ) {
286		free( mc->mc_local_ndn.bv_val );
287	}
288
289	free( mc );
290}
291
292static void
293mapping_free(
294	void		*v_mapping )
295{
296	struct ldapmapping *mapping = v_mapping;
297	ch_free( mapping->src.bv_val );
298	ch_free( mapping->dst.bv_val );
299	ch_free( mapping );
300}
301
302static void
303mapping_dst_free(
304	void		*v_mapping )
305{
306	struct ldapmapping *mapping = v_mapping;
307
308	if ( BER_BVISEMPTY( &mapping->dst ) ) {
309		mapping_free( &mapping[ -1 ] );
310	}
311}
312
313static void
314target_free(
315	metatarget_t	*mt )
316{
317	if ( mt->mt_uri ) {
318		free( mt->mt_uri );
319		ldap_pvt_thread_mutex_destroy( &mt->mt_uri_mutex );
320	}
321	if ( mt->mt_subtree ) {
322		meta_subtree_destroy( mt->mt_subtree );
323		mt->mt_subtree = NULL;
324	}
325	if ( !BER_BVISNULL( &mt->mt_psuffix ) ) {
326		free( mt->mt_psuffix.bv_val );
327	}
328	if ( !BER_BVISNULL( &mt->mt_nsuffix ) ) {
329		free( mt->mt_nsuffix.bv_val );
330	}
331	if ( !BER_BVISNULL( &mt->mt_binddn ) ) {
332		free( mt->mt_binddn.bv_val );
333	}
334	if ( !BER_BVISNULL( &mt->mt_bindpw ) ) {
335		free( mt->mt_bindpw.bv_val );
336	}
337	if ( !BER_BVISNULL( &mt->mt_idassert_authcID ) ) {
338		ch_free( mt->mt_idassert_authcID.bv_val );
339	}
340	if ( !BER_BVISNULL( &mt->mt_idassert_authcDN ) ) {
341		ch_free( mt->mt_idassert_authcDN.bv_val );
342	}
343	if ( !BER_BVISNULL( &mt->mt_idassert_passwd ) ) {
344		ch_free( mt->mt_idassert_passwd.bv_val );
345	}
346	if ( !BER_BVISNULL( &mt->mt_idassert_authzID ) ) {
347		ch_free( mt->mt_idassert_authzID.bv_val );
348	}
349	if ( !BER_BVISNULL( &mt->mt_idassert_sasl_mech ) ) {
350		ch_free( mt->mt_idassert_sasl_mech.bv_val );
351	}
352	if ( !BER_BVISNULL( &mt->mt_idassert_sasl_realm ) ) {
353		ch_free( mt->mt_idassert_sasl_realm.bv_val );
354	}
355	if ( mt->mt_idassert_authz != NULL ) {
356		ber_bvarray_free( mt->mt_idassert_authz );
357	}
358	if ( mt->mt_rwmap.rwm_rw ) {
359		rewrite_info_delete( &mt->mt_rwmap.rwm_rw );
360	}
361	avl_free( mt->mt_rwmap.rwm_oc.remap, mapping_dst_free );
362	avl_free( mt->mt_rwmap.rwm_oc.map, mapping_free );
363	avl_free( mt->mt_rwmap.rwm_at.remap, mapping_dst_free );
364	avl_free( mt->mt_rwmap.rwm_at.map, mapping_free );
365
366	free( mt );
367}
368
369int
370meta_back_db_destroy(
371	Backend		*be,
372	ConfigReply	*cr )
373{
374	metainfo_t	*mi;
375
376	if ( be->be_private ) {
377		int i;
378
379		mi = ( metainfo_t * )be->be_private;
380
381		/*
382		 * Destroy the connection tree
383		 */
384		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
385
386		if ( mi->mi_conninfo.lai_tree ) {
387			avl_free( mi->mi_conninfo.lai_tree, meta_back_conn_free );
388		}
389		for ( i = LDAP_BACK_PCONN_FIRST; i < LDAP_BACK_PCONN_LAST; i++ ) {
390			while ( !LDAP_TAILQ_EMPTY( &mi->mi_conn_priv[ i ].mic_priv ) ) {
391				metaconn_t	*mc = LDAP_TAILQ_FIRST( &mi->mi_conn_priv[ i ].mic_priv );
392
393				LDAP_TAILQ_REMOVE( &mi->mi_conn_priv[ i ].mic_priv, mc, mc_q );
394				meta_back_conn_free( mc );
395			}
396		}
397
398		/*
399		 * Destroy the per-target stuff (assuming there's at
400		 * least one ...)
401		 */
402		if ( mi->mi_targets != NULL ) {
403			for ( i = 0; i < mi->mi_ntargets; i++ ) {
404				metatarget_t	*mt = mi->mi_targets[ i ];
405
406				if ( META_BACK_TGT_QUARANTINE( mt ) ) {
407					if ( mt->mt_quarantine.ri_num != mi->mi_quarantine.ri_num )
408					{
409						mi->mi_ldap_extra->retry_info_destroy( &mt->mt_quarantine );
410					}
411
412					ldap_pvt_thread_mutex_destroy( &mt->mt_quarantine_mutex );
413				}
414
415				target_free( mt );
416			}
417
418			free( mi->mi_targets );
419		}
420
421		ldap_pvt_thread_mutex_lock( &mi->mi_cache.mutex );
422		if ( mi->mi_cache.tree ) {
423			avl_free( mi->mi_cache.tree, meta_dncache_free );
424		}
425
426		ldap_pvt_thread_mutex_unlock( &mi->mi_cache.mutex );
427		ldap_pvt_thread_mutex_destroy( &mi->mi_cache.mutex );
428
429		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
430		ldap_pvt_thread_mutex_destroy( &mi->mi_conninfo.lai_mutex );
431
432		if ( mi->mi_candidates != NULL ) {
433			ber_memfree_x( mi->mi_candidates, NULL );
434		}
435
436		if ( META_BACK_QUARANTINE( mi ) ) {
437			mi->mi_ldap_extra->retry_info_destroy( &mi->mi_quarantine );
438		}
439	}
440
441	free( be->be_private );
442	return 0;
443}
444
445#if SLAPD_META == SLAPD_MOD_DYNAMIC
446
447/* conditionally define the init_module() function */
448SLAP_BACKEND_INIT_MODULE( meta )
449
450#endif /* SLAPD_META == SLAPD_MOD_DYNAMIC */
451
452
453