slapi_overlay.c revision 1.1.1.6
1/*	$NetBSD: slapi_overlay.c,v 1.1.1.6 2017/02/09 01:47:07 christos Exp $	*/
2
3/* slapi_overlay.c - SLAPI overlay */
4/* $OpenLDAP$ */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2001-2016 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18/* ACKNOWLEDGEMENTS:
19 * This work was initially developed by Luke Howard for inclusion
20 * in OpenLDAP Software.
21 */
22
23#include <sys/cdefs.h>
24__RCSID("$NetBSD: slapi_overlay.c,v 1.1.1.6 2017/02/09 01:47:07 christos Exp $");
25
26#include "portable.h"
27
28#include <stdio.h>
29
30#include <ac/string.h>
31#include <ac/socket.h>
32
33#include "slap.h"
34#include "slapi.h"
35#include "config.h"
36
37#ifdef LDAP_SLAPI
38
39static slap_overinst slapi;
40static int slapi_over_initialized = 0;
41
42static int slapi_over_response( Operation *op, SlapReply *rs );
43static int slapi_over_cleanup( Operation *op, SlapReply *rs );
44
45static Slapi_PBlock *
46slapi_over_pblock_new( Operation *op, SlapReply *rs )
47{
48	Slapi_PBlock		*pb;
49
50	pb = slapi_pblock_new();
51	pb->pb_op = op;
52	pb->pb_conn = op->o_conn;
53	pb->pb_rs = rs;
54	pb->pb_intop = 0;
55
56	PBLOCK_ASSERT_OP( pb, op->o_tag );
57
58	return pb;
59}
60
61static int
62slapi_op_internal_p( Operation *op, SlapReply *rs, slap_callback *cb )
63{
64	int			internal_op = 0;
65	Slapi_PBlock		*pb = NULL;
66	slap_callback		*pcb;
67
68	/*
69	 * Abstraction violating check for SLAPI internal operations
70	 * allows pblock to remain consistent when invoking internal
71	 * op plugins
72	 */
73	for ( pcb = op->o_callback; pcb != NULL; pcb = pcb->sc_next ) {
74		if ( pcb->sc_response == slapi_int_response ) {
75			pb = (Slapi_PBlock *)pcb->sc_private;
76			PBLOCK_ASSERT_INTOP( pb, 0 );
77			internal_op = 1;
78			break;
79		}
80	}
81
82	if ( cb != NULL ) {
83		if ( pb == NULL ) {
84			pb = slapi_over_pblock_new( op, rs );
85		}
86
87		cb->sc_response = slapi_over_response;
88		cb->sc_cleanup = slapi_over_cleanup;
89		cb->sc_private = pb;
90		cb->sc_next = op->o_callback;
91		op->o_callback = cb;
92	}
93
94	return internal_op;
95}
96
97static int
98slapi_over_compute_output(
99	computed_attr_context *c,
100	Slapi_Attr *attribute,
101	Slapi_Entry *entry
102)
103{
104	Attribute		**a;
105	AttributeDescription	*desc;
106	SlapReply		*rs;
107
108	if ( c == NULL || attribute == NULL || entry == NULL ) {
109		return 0;
110	}
111
112	rs = (SlapReply *)c->cac_private;
113
114	assert( rs->sr_entry == entry );
115
116	desc = attribute->a_desc;
117
118	if ( rs->sr_attrs == NULL ) {
119		/* All attrs request, skip operational attributes */
120		if ( is_at_operational( desc->ad_type ) ) {
121			return 0;
122		}
123	} else {
124		/* Specific attributes requested */
125		if ( is_at_operational( desc->ad_type ) ) {
126			if ( !SLAP_OPATTRS( rs->sr_attr_flags ) &&
127			     !ad_inlist( desc, rs->sr_attrs ) ) {
128				return 0;
129			}
130		} else {
131			if ( !SLAP_USERATTRS( rs->sr_attr_flags ) &&
132			     !ad_inlist( desc, rs->sr_attrs ) ) {
133				return 0;
134			}
135		}
136	}
137
138	/* XXX perhaps we should check for existing attributes and merge */
139	for ( a = &rs->sr_operational_attrs; *a != NULL; a = &(*a)->a_next )
140		;
141
142	*a = slapi_attr_dup( attribute );
143
144	return 0;
145}
146
147static int
148slapi_over_aux_operational( Operation *op, SlapReply *rs )
149{
150	/* Support for computed attribute plugins */
151	computed_attr_context    ctx;
152	AttributeName		*anp;
153
154	if ( slapi_op_internal_p( op, rs, NULL ) ) {
155		return SLAP_CB_CONTINUE;
156	}
157
158	ctx.cac_pb = slapi_over_pblock_new( op, rs );
159	ctx.cac_op = op;
160	ctx.cac_private = rs;
161
162	if ( rs->sr_entry != NULL ) {
163		/*
164		 * For each client requested attribute, call the plugins.
165		 */
166		if ( rs->sr_attrs != NULL ) {
167			for ( anp = rs->sr_attrs; anp->an_name.bv_val != NULL; anp++ ) {
168				if ( compute_evaluator( &ctx, anp->an_name.bv_val,
169					rs->sr_entry, slapi_over_compute_output ) == 1 ) {
170					break;
171				}
172			}
173		} else {
174			/*
175			 * Technically we shouldn't be returning operational attributes
176			 * when the user requested only user attributes. We'll let the
177			 * plugin decide whether to be naughty or not.
178			 */
179			compute_evaluator( &ctx, "*", rs->sr_entry, slapi_over_compute_output );
180		}
181	}
182
183	slapi_pblock_destroy( ctx.cac_pb );
184
185	return SLAP_CB_CONTINUE;
186}
187
188/*
189 * We need this function to call frontendDB (global) plugins before
190 * database plugins, if we are invoked by a slap_callback.
191 */
192static int
193slapi_over_call_plugins( Slapi_PBlock *pb, int type )
194{
195	int 			rc = 1; /* means no plugins called */
196	Operation		*op;
197
198	PBLOCK_ASSERT_OP( pb, 0 );
199	op = pb->pb_op;
200
201	if ( !be_match( op->o_bd, frontendDB ) ) {
202		rc = slapi_int_call_plugins( frontendDB, type, pb );
203	}
204	if ( rc >= 0 ) {
205		rc = slapi_int_call_plugins( op->o_bd, type, pb );
206	}
207
208	return rc;
209}
210
211static int
212slapi_over_search( Operation *op, SlapReply *rs, int type )
213{
214	int			rc;
215	Slapi_PBlock		*pb;
216
217	assert( rs->sr_type == REP_SEARCH || rs->sr_type == REP_SEARCHREF );
218
219	/* create a new pblock to not trample on result controls */
220	pb = slapi_over_pblock_new( op, rs );
221
222	rc = slapi_over_call_plugins( pb, type );
223	if ( rc >= 0 ) /* 1 means no plugins called */
224		rc = SLAP_CB_CONTINUE;
225	else
226		rc = LDAP_SUCCESS; /* confusing: don't abort, but don't send */
227
228	slapi_pblock_destroy(pb);
229
230	return rc;
231}
232
233/*
234 * Call pre- and post-result plugins
235 */
236static int
237slapi_over_result( Operation *op, SlapReply *rs, int type )
238{
239	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
240
241	assert( rs->sr_type == REP_RESULT || rs->sr_type == REP_SASL || rs->sr_type == REP_EXTENDED );
242
243	slapi_over_call_plugins( pb, type );
244
245	return SLAP_CB_CONTINUE;
246}
247
248
249static int
250slapi_op_bind_callback( Operation *op, SlapReply *rs, int prc )
251{
252	switch ( prc ) {
253	case SLAPI_BIND_SUCCESS:
254		/* Continue with backend processing */
255		break;
256	case SLAPI_BIND_FAIL:
257		/* Failure, frontend (that's us) sends result */
258		rs->sr_err = LDAP_INVALID_CREDENTIALS;
259		send_ldap_result( op, rs );
260		return rs->sr_err;
261		break;
262	case SLAPI_BIND_ANONYMOUS: /* undocumented */
263	default: /* plugin sent result or no plugins called */
264		BER_BVZERO( &op->orb_edn );
265
266		if ( rs->sr_err == LDAP_SUCCESS ) {
267			/*
268			 * Plugin will have called slapi_pblock_set(LDAP_CONN_DN) which
269			 * will have set conn->c_dn and conn->c_ndn
270			 */
271			if ( BER_BVISNULL( &op->o_conn->c_ndn ) && prc == 1 ) {
272				/* No plugins were called; continue processing */
273				return LDAP_SUCCESS;
274			}
275			ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
276			if ( !BER_BVISEMPTY( &op->o_conn->c_ndn ) ) {
277				ber_len_t max = sockbuf_max_incoming_auth;
278				ber_sockbuf_ctrl( op->o_conn->c_sb,
279					LBER_SB_OPT_SET_MAX_INCOMING, &max );
280			}
281			ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
282
283			/* log authorization identity */
284			Statslog( LDAP_DEBUG_STATS,
285				"%s BIND dn=\"%s\" mech=%s (SLAPI) ssf=0\n",
286				op->o_log_prefix,
287				BER_BVISNULL( &op->o_conn->c_dn )
288					? "<empty>" : op->o_conn->c_dn.bv_val,
289				BER_BVISNULL( &op->orb_mech )
290					? "<empty>" : op->orb_mech.bv_val, 0, 0 );
291
292			return -1;
293		}
294		break;
295	}
296
297	return rs->sr_err;
298}
299
300static int
301slapi_op_search_callback( Operation *op, SlapReply *rs, int prc )
302{
303	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
304	Filter *f = op->ors_filter;
305
306	/* check preoperation result code */
307	if ( prc < 0 ) {
308		return rs->sr_err;
309	}
310
311	rs->sr_err = LDAP_SUCCESS;
312
313	if ( pb->pb_intop == 0 &&
314	     slapi_int_call_plugins( op->o_bd, SLAPI_PLUGIN_COMPUTE_SEARCH_REWRITER_FN, pb ) == 0 ) {
315		/*
316		 * The plugin can set the SLAPI_SEARCH_FILTER.
317		 * SLAPI_SEARCH_STRFILER is not normative.
318		 */
319		if (f != op->ors_filter) {
320			op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
321			filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
322		}
323	}
324
325	return LDAP_SUCCESS;
326}
327
328struct slapi_op_info {
329	int soi_preop;			/* preoperation plugin parameter */
330	int soi_postop;			/* postoperation plugin parameter */
331	int soi_internal_preop;		/* internal preoperation plugin parameter */
332	int soi_internal_postop;	/* internal postoperation plugin parameter */
333	int (*soi_callback)(Operation *, SlapReply *, int); /* preoperation result handler */
334} slapi_op_dispatch_table[] = {
335	{
336		SLAPI_PLUGIN_PRE_BIND_FN,
337		SLAPI_PLUGIN_POST_BIND_FN,
338		SLAPI_PLUGIN_INTERNAL_PRE_BIND_FN,
339		SLAPI_PLUGIN_INTERNAL_POST_BIND_FN,
340		slapi_op_bind_callback
341	},
342	{
343		SLAPI_PLUGIN_PRE_UNBIND_FN,
344		SLAPI_PLUGIN_POST_UNBIND_FN,
345		SLAPI_PLUGIN_INTERNAL_PRE_UNBIND_FN,
346		SLAPI_PLUGIN_INTERNAL_POST_UNBIND_FN,
347		NULL
348	},
349	{
350		SLAPI_PLUGIN_PRE_SEARCH_FN,
351		SLAPI_PLUGIN_POST_SEARCH_FN,
352		SLAPI_PLUGIN_INTERNAL_PRE_SEARCH_FN,
353		SLAPI_PLUGIN_INTERNAL_POST_SEARCH_FN,
354		slapi_op_search_callback
355	},
356	{
357		SLAPI_PLUGIN_PRE_COMPARE_FN,
358		SLAPI_PLUGIN_POST_COMPARE_FN,
359		SLAPI_PLUGIN_INTERNAL_PRE_COMPARE_FN,
360		SLAPI_PLUGIN_INTERNAL_POST_COMPARE_FN,
361		NULL
362	},
363	{
364		SLAPI_PLUGIN_PRE_MODIFY_FN,
365		SLAPI_PLUGIN_POST_MODIFY_FN,
366		SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN,
367		SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN,
368		NULL
369	},
370	{
371		SLAPI_PLUGIN_PRE_MODRDN_FN,
372		SLAPI_PLUGIN_POST_MODRDN_FN,
373		SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN,
374		SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN,
375		NULL
376	},
377	{
378		SLAPI_PLUGIN_PRE_ADD_FN,
379		SLAPI_PLUGIN_POST_ADD_FN,
380		SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN,
381		SLAPI_PLUGIN_INTERNAL_POST_ADD_FN,
382		NULL
383	},
384	{
385		SLAPI_PLUGIN_PRE_DELETE_FN,
386		SLAPI_PLUGIN_POST_DELETE_FN,
387		SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN,
388		SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN,
389		NULL
390	},
391	{
392		SLAPI_PLUGIN_PRE_ABANDON_FN,
393		SLAPI_PLUGIN_POST_ABANDON_FN,
394		SLAPI_PLUGIN_INTERNAL_PRE_ABANDON_FN,
395		SLAPI_PLUGIN_INTERNAL_POST_ABANDON_FN,
396		NULL
397	},
398	{
399		0,
400		0,
401		0,
402		0,
403		NULL
404	}
405};
406
407slap_operation_t
408slapi_tag2op( ber_tag_t tag )
409{
410	slap_operation_t op;
411
412	switch ( tag ) {
413	case LDAP_REQ_BIND:
414		op = op_bind;
415		break;
416	case LDAP_REQ_ADD:
417		op = op_add;
418		break;
419	case LDAP_REQ_DELETE:
420		op = op_delete;
421		break;
422	case LDAP_REQ_MODRDN:
423		op = op_modrdn;
424		break;
425	case LDAP_REQ_MODIFY:
426		op = op_modify;
427		break;
428	case LDAP_REQ_COMPARE:
429		op = op_compare;
430		break;
431	case LDAP_REQ_SEARCH:
432		op = op_search;
433		break;
434	case LDAP_REQ_UNBIND:
435		op = op_unbind;
436		break;
437	default:
438		op = op_last;
439		break;
440	}
441
442	return op;
443}
444
445/* Add SLAPI_RESCONTROLS to rs->sr_ctrls, with care, because
446 * rs->sr_ctrls could be allocated on the stack */
447static int
448slapi_over_merge_controls( Operation *op, SlapReply *rs )
449{
450	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
451	LDAPControl		**ctrls = NULL;
452	LDAPControl		**slapi_ctrls = NULL;
453	size_t			n_slapi_ctrls = 0;
454	size_t			n_rs_ctrls = 0;
455	size_t			i;
456
457	slapi_pblock_get( pb, SLAPI_RESCONTROLS, (void **)&slapi_ctrls );
458
459	n_slapi_ctrls = slapi_int_count_controls( slapi_ctrls );
460	n_rs_ctrls = slapi_int_count_controls( rs->sr_ctrls );
461
462	if ( n_slapi_ctrls == 0 )
463		return LDAP_SUCCESS; /* no SLAPI controls */
464
465	slapi_pblock_set( pb, SLAPI_X_OLD_RESCONTROLS, (void *)rs->sr_ctrls );
466
467	ctrls = (LDAPControl **) op->o_tmpalloc(
468		( n_slapi_ctrls + n_rs_ctrls + 1 ) * sizeof(LDAPControl *),
469		op->o_tmpmemctx );
470
471	for ( i = 0; i < n_slapi_ctrls; i++ ) {
472		ctrls[i] = slapi_ctrls[i];
473	}
474	if ( rs->sr_ctrls != NULL ) {
475		for ( i = 0; i < n_rs_ctrls; i++ ) {
476			ctrls[n_slapi_ctrls + i] = rs->sr_ctrls[i];
477		}
478	}
479	ctrls[n_slapi_ctrls + n_rs_ctrls] = NULL;
480
481	rs->sr_ctrls = ctrls;
482
483	return LDAP_SUCCESS;
484}
485
486static int
487slapi_over_unmerge_controls( Operation *op, SlapReply *rs )
488{
489	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
490	LDAPControl		**rs_ctrls = NULL;
491
492	slapi_pblock_get( pb, SLAPI_X_OLD_RESCONTROLS, (void **)&rs_ctrls );
493
494	if ( rs_ctrls == NULL || rs->sr_ctrls == rs_ctrls ) {
495		/* no copying done */
496		return LDAP_SUCCESS;
497	}
498
499	op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
500	rs->sr_ctrls = rs_ctrls;
501
502	return LDAP_SUCCESS;
503}
504
505static int
506slapi_over_response( Operation *op, SlapReply *rs )
507{
508	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
509	int			rc = SLAP_CB_CONTINUE;
510
511	if ( pb->pb_intop == 0 ) {
512		switch ( rs->sr_type ) {
513		case REP_RESULT:
514		case REP_SASL:
515		case REP_EXTENDED:
516			rc = slapi_over_result( op, rs, SLAPI_PLUGIN_PRE_RESULT_FN );
517			break;
518		case REP_SEARCH:
519			rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_ENTRY_FN );
520			break;
521		case REP_SEARCHREF:
522			rc = slapi_over_search( op, rs, SLAPI_PLUGIN_PRE_REFERRAL_FN );
523			break;
524		default:
525			break;
526		}
527	}
528
529	slapi_over_merge_controls( op, rs );
530
531	return rc;
532}
533
534static int
535slapi_over_cleanup( Operation *op, SlapReply *rs )
536{
537	Slapi_PBlock		*pb = SLAPI_OPERATION_PBLOCK( op );
538	int			rc = SLAP_CB_CONTINUE;
539
540	slapi_over_unmerge_controls( op, rs );
541
542	if ( pb->pb_intop == 0 ) {
543		switch ( rs->sr_type ) {
544		case REP_RESULT:
545		case REP_SASL:
546		case REP_EXTENDED:
547			rc = slapi_over_result( op, rs, SLAPI_PLUGIN_POST_RESULT_FN );
548			break;
549		case REP_SEARCH:
550			rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_ENTRY_FN );
551			break;
552		case REP_SEARCHREF:
553			rc = slapi_over_search( op, rs, SLAPI_PLUGIN_POST_REFERRAL_FN );
554			break;
555		default:
556			break;
557		}
558	}
559
560	return rc;
561}
562
563static int
564slapi_op_func( Operation *op, SlapReply *rs )
565{
566	Slapi_PBlock		*pb;
567	slap_operation_t	which;
568	struct slapi_op_info	*opinfo;
569	int			rc;
570	slap_overinfo		*oi;
571	slap_overinst		*on;
572	slap_callback		cb;
573	int			internal_op;
574	int			preop_type, postop_type;
575	BackendDB		*be;
576
577	if ( !slapi_plugins_used )
578		return SLAP_CB_CONTINUE;
579
580	/*
581	 * Find the SLAPI operation information for this LDAP
582	 * operation; this will contain the preop and postop
583	 * plugin types, as well as optional callbacks for
584	 * setting up the SLAPI environment.
585	 */
586	which = slapi_tag2op( op->o_tag );
587	if ( which >= op_last ) {
588		/* invalid operation, but let someone else deal with it */
589		return SLAP_CB_CONTINUE;
590	}
591
592	opinfo = &slapi_op_dispatch_table[which];
593	if ( opinfo == NULL ) {
594		/* no SLAPI plugin types for this operation */
595		return SLAP_CB_CONTINUE;
596	}
597
598	internal_op = slapi_op_internal_p( op, rs, &cb );
599
600	if ( internal_op ) {
601		preop_type = opinfo->soi_internal_preop;
602		postop_type = opinfo->soi_internal_postop;
603	} else {
604		preop_type = opinfo->soi_preop;
605		postop_type = opinfo->soi_postop;
606	}
607
608	if ( preop_type == 0 ) {
609		/* no SLAPI plugin types for this operation */
610		pb = NULL;
611		rc = SLAP_CB_CONTINUE;
612		goto cleanup;
613	}
614
615	pb = SLAPI_OPERATION_PBLOCK( op );
616
617	/* cache backend so we call correct postop plugins */
618	be = pb->pb_op->o_bd;
619
620	rc = slapi_int_call_plugins( be, preop_type, pb );
621
622	/*
623	 * soi_callback is responsible for examining the result code
624	 * of the preoperation plugin and determining whether to
625	 * abort. This is needed because of special SLAPI behaviour
626	 e with bind preoperation plugins.
627	 *
628	 * The soi_callback function is also used to reset any values
629	 * returned from the preoperation plugin before calling the
630	 * backend (for the success case).
631	 */
632	if ( opinfo->soi_callback == NULL ) {
633		/* default behaviour is preop plugin can abort operation */
634		if ( rc < 0 ) {
635			rc = rs->sr_err;
636			goto cleanup;
637		}
638	} else {
639		rc = (opinfo->soi_callback)( op, rs, rc );
640		if ( rc )
641			goto cleanup;
642	}
643
644	/*
645	 * Call actual backend (or next overlay in stack). We need to
646	 * do this rather than returning SLAP_CB_CONTINUE and calling
647	 * postoperation plugins in a response handler to match the
648	 * behaviour of SLAPI in OpenLDAP 2.2, where postoperation
649	 * plugins are called after the backend has completely
650	 * finished processing the operation.
651	 */
652	on = (slap_overinst *)op->o_bd->bd_info;
653	oi = on->on_info;
654
655	rc = overlay_op_walk( op, rs, which, oi, on->on_next );
656
657	/*
658	 * Call postoperation plugins
659	 */
660	slapi_int_call_plugins( be, postop_type, pb );
661
662cleanup:
663	if ( !internal_op ) {
664		slapi_pblock_destroy(pb);
665		cb.sc_private = NULL;
666	}
667
668	op->o_callback = cb.sc_next;
669
670	return rc;
671}
672
673static int
674slapi_over_extended( Operation *op, SlapReply *rs )
675{
676	Slapi_PBlock	*pb;
677	SLAPI_FUNC	callback;
678	int		rc;
679	int		internal_op;
680	slap_callback	cb;
681
682	slapi_int_get_extop_plugin( &op->ore_reqoid, &callback );
683	if ( callback == NULL ) {
684		return SLAP_CB_CONTINUE;
685	}
686
687	internal_op = slapi_op_internal_p( op, rs, &cb );
688	if ( internal_op ) {
689		return SLAP_CB_CONTINUE;
690	}
691
692	pb = SLAPI_OPERATION_PBLOCK( op );
693
694	rc = (*callback)( pb );
695	if ( rc == SLAPI_PLUGIN_EXTENDED_SENT_RESULT ) {
696		goto cleanup;
697	} else if ( rc == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED ) {
698		rc = SLAP_CB_CONTINUE;
699		goto cleanup;
700	}
701
702	assert( rs->sr_rspoid != NULL );
703
704	send_ldap_extended( op, rs );
705
706#if 0
707	slapi_ch_free_string( (char **)&rs->sr_rspoid );
708#endif
709
710	if ( rs->sr_rspdata != NULL )
711		ber_bvfree( rs->sr_rspdata );
712
713	rc = rs->sr_err;
714
715cleanup:
716	slapi_pblock_destroy( pb );
717	op->o_callback = cb.sc_next;
718
719	return rc;
720}
721
722static int
723slapi_over_access_allowed(
724	Operation		*op,
725	Entry			*e,
726	AttributeDescription	*desc,
727	struct berval		*val,
728	slap_access_t		access,
729	AccessControlState	*state,
730	slap_mask_t		*maskp )
731{
732	int			rc;
733	Slapi_PBlock		*pb;
734	slap_callback		cb;
735	int			internal_op;
736	SlapReply		rs = { REP_RESULT };
737
738	internal_op = slapi_op_internal_p( op, &rs, &cb );
739
740	cb.sc_response = NULL;
741	cb.sc_cleanup = NULL;
742
743	pb = SLAPI_OPERATION_PBLOCK( op );
744
745	rc = slapi_int_access_allowed( op, e, desc, val, access, state );
746	if ( rc ) {
747		rc = SLAP_CB_CONTINUE;
748	}
749
750	if ( !internal_op ) {
751		slapi_pblock_destroy( pb );
752	}
753
754	op->o_callback = cb.sc_next;
755
756	return rc;
757}
758
759static int
760slapi_over_acl_group(
761	Operation		*op,
762	Entry			*target,
763	struct berval		*gr_ndn,
764	struct berval		*op_ndn,
765	ObjectClass		*group_oc,
766	AttributeDescription	*group_at )
767{
768	Slapi_Entry		*e;
769	int			rc;
770	Slapi_PBlock		*pb;
771	BackendDB		*be = op->o_bd;
772	GroupAssertion		*g;
773	SlapReply		rs = { REP_RESULT };
774
775	op->o_bd = select_backend( gr_ndn, 0 );
776
777	for ( g = op->o_groups; g; g = g->ga_next ) {
778		if ( g->ga_be != op->o_bd || g->ga_oc != group_oc ||
779			g->ga_at != group_at || g->ga_len != gr_ndn->bv_len )
780		{
781			continue;
782		}
783		if ( strcmp( g->ga_ndn, gr_ndn->bv_val ) == 0 ) {
784			break;
785		}
786	}
787	if ( g != NULL ) {
788		rc = g->ga_res;
789		goto done;
790	}
791
792	if ( target != NULL && dn_match( &target->e_nname, gr_ndn ) ) {
793		e = target;
794		rc = 0;
795	} else {
796		rc = be_entry_get_rw( op, gr_ndn, group_oc, group_at, 0, &e );
797	}
798	if ( e != NULL ) {
799		int			internal_op;
800		slap_callback		cb;
801
802		internal_op = slapi_op_internal_p( op, &rs, &cb );
803
804		cb.sc_response = NULL;
805		cb.sc_cleanup = NULL;
806
807		pb = SLAPI_OPERATION_PBLOCK( op );
808
809		slapi_pblock_set( pb, SLAPI_X_GROUP_ENTRY,        (void *)e );
810		slapi_pblock_set( pb, SLAPI_X_GROUP_OPERATION_DN, (void *)op_ndn->bv_val );
811		slapi_pblock_set( pb, SLAPI_X_GROUP_ATTRIBUTE,    (void *)group_at->ad_cname.bv_val );
812		slapi_pblock_set( pb, SLAPI_X_GROUP_TARGET_ENTRY, (void *)target );
813
814		rc = slapi_over_call_plugins( pb, SLAPI_X_PLUGIN_PRE_GROUP_FN );
815		if ( rc >= 0 ) /* 1 means no plugins called */
816			rc = SLAP_CB_CONTINUE;
817		else
818			rc = pb->pb_rs->sr_err;
819
820		slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ENTRY );
821		slapi_pblock_delete_param( pb, SLAPI_X_GROUP_OPERATION_DN );
822		slapi_pblock_delete_param( pb, SLAPI_X_GROUP_ATTRIBUTE );
823		slapi_pblock_delete_param( pb, SLAPI_X_GROUP_TARGET_ENTRY );
824
825		if ( !internal_op )
826			slapi_pblock_destroy( pb );
827
828		if ( e != target ) {
829			be_entry_release_r( op, e );
830		}
831
832		op->o_callback = cb.sc_next;
833	} else {
834		rc = LDAP_NO_SUCH_OBJECT; /* return SLAP_CB_CONTINUE for correctness? */
835	}
836
837	if ( op->o_tag != LDAP_REQ_BIND && !op->o_do_not_cache &&
838	     rc != SLAP_CB_CONTINUE ) {
839		g = op->o_tmpalloc( sizeof( GroupAssertion ) + gr_ndn->bv_len,
840			op->o_tmpmemctx );
841		g->ga_be = op->o_bd;
842		g->ga_oc = group_oc;
843		g->ga_at = group_at;
844		g->ga_res = rc;
845		g->ga_len = gr_ndn->bv_len;
846		strcpy( g->ga_ndn, gr_ndn->bv_val );
847		g->ga_next = op->o_groups;
848		op->o_groups = g;
849	}
850	/*
851	 * XXX don't call POST_GROUP_FN, I have no idea what the point of
852	 * that plugin function was anyway
853	 */
854done:
855	op->o_bd = be;
856	return rc;
857}
858
859static int
860slapi_over_db_open(
861	BackendDB	*be,
862	ConfigReply	*cr )
863{
864	Slapi_PBlock		*pb;
865	int			rc;
866
867	pb = slapi_pblock_new();
868
869	rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_START_FN, pb );
870
871	slapi_pblock_destroy( pb );
872
873	return rc;
874}
875
876static int
877slapi_over_db_close(
878	BackendDB	*be,
879	ConfigReply	*cr )
880{
881	Slapi_PBlock		*pb;
882	int			rc;
883
884	pb = slapi_pblock_new();
885
886	rc = slapi_int_call_plugins( be, SLAPI_PLUGIN_CLOSE_FN, pb );
887
888	slapi_pblock_destroy( pb );
889
890	return rc;
891}
892
893static int
894slapi_over_init()
895{
896	memset( &slapi, 0, sizeof(slapi) );
897
898	slapi.on_bi.bi_type = SLAPI_OVERLAY_NAME;
899
900	slapi.on_bi.bi_op_bind 		= slapi_op_func;
901	slapi.on_bi.bi_op_unbind	= slapi_op_func;
902	slapi.on_bi.bi_op_search	= slapi_op_func;
903	slapi.on_bi.bi_op_compare	= slapi_op_func;
904	slapi.on_bi.bi_op_modify	= slapi_op_func;
905	slapi.on_bi.bi_op_modrdn	= slapi_op_func;
906	slapi.on_bi.bi_op_add		= slapi_op_func;
907	slapi.on_bi.bi_op_delete	= slapi_op_func;
908	slapi.on_bi.bi_op_abandon	= slapi_op_func;
909	slapi.on_bi.bi_op_cancel	= slapi_op_func;
910
911	slapi.on_bi.bi_db_open		= slapi_over_db_open;
912	slapi.on_bi.bi_db_close		= slapi_over_db_close;
913
914	slapi.on_bi.bi_extended		= slapi_over_extended;
915	slapi.on_bi.bi_access_allowed	= slapi_over_access_allowed;
916	slapi.on_bi.bi_operational	= slapi_over_aux_operational;
917	slapi.on_bi.bi_acl_group	= slapi_over_acl_group;
918
919	return overlay_register( &slapi );
920}
921
922int slapi_over_is_inst( BackendDB *be )
923{
924	return overlay_is_inst( be, SLAPI_OVERLAY_NAME );
925}
926
927int slapi_over_config( BackendDB *be, ConfigReply *cr )
928{
929	if ( slapi_over_initialized == 0 ) {
930		int rc;
931
932		/* do global initializaiton */
933		ldap_pvt_thread_mutex_init( &slapi_hn_mutex );
934		ldap_pvt_thread_mutex_init( &slapi_time_mutex );
935		ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex );
936
937		if ( slapi_log_file == NULL )
938			slapi_log_file = slapi_ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
939
940		rc = slapi_int_init_object_extensions();
941		if ( rc != 0 )
942			return rc;
943
944		rc = slapi_over_init();
945		if ( rc != 0 )
946			return rc;
947
948		slapi_over_initialized = 1;
949	}
950
951	return overlay_config( be, SLAPI_OVERLAY_NAME, -1, NULL, cr );
952}
953
954#endif /* LDAP_SLAPI */
955