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