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