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