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