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