]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Cleanup of SLAPI internal operation code; use frontendDB rather than
[openldap] / servers / slapd / slapi / slapi_ops.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2002-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1997,2002-2003 IBM Corporation.
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 IBM Corporation for use in
18  * IBM products and subsequently ported to OpenLDAP Software by
19  * Steve Omrani.  Additional significant contributors include:
20  *   Luke Howard
21  */
22
23 #include "portable.h"
24
25 #include <ac/string.h>
26 #include <ac/stdarg.h>
27 #include <ac/ctype.h>
28 #include <ac/unistd.h>
29
30 #include <slap.h>
31 #include <lber_pvt.h>
32 #include <slapi.h>
33
34 /*
35  * use a fake listener when faking a connection,
36  * so it can be used in ACLs
37  */
38 static struct slap_listener slap_unknown_listener = {
39         BER_BVC("unknown"),     /* FIXME: use a URI form? (e.g. slapi://) */
40         BER_BVC("UNKNOWN")
41 };
42
43 static void
44 slapi_int_mods_free( Modifications *ml )
45 {
46         Modifications           *next;
47
48         for ( ; ml != NULL; ml = next ) {
49                 next = ml->sml_next;
50
51                 /* Don't free unnormalized values */
52                 if ( ml->sml_nvalues != NULL ) {
53                         ber_bvarray_free( ml->sml_nvalues );
54                         ml->sml_nvalues = NULL;
55                 }
56                 slapi_ch_free((void **)&ml->sml_values);
57                 slapi_ch_free((void **)&ml);
58         }
59 }
60
61 static int
62 slapi_int_result(
63         Operation       *op, 
64         SlapReply       *rs )
65 {
66         LDAPControl             **controls = NULL;
67         size_t                  i;
68         plugin_result_callback  prc = NULL;
69         void                    *callback_data = NULL;
70         Slapi_PBlock            *pb = SLAPI_OPERATION_PBLOCK( op );
71
72         assert( pb != NULL );   
73
74         slapi_pblock_get( pb, SLAPI_RESCONTROLS,             (void **)&controls );
75         slapi_pblock_get( pb, SLAPI_X_INTOP_RESULT_CALLBACK, (void **)&prc );
76         slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA,   &callback_data );
77
78         assert( controls == NULL );
79
80         /* Copy these before they go out of scope */
81         if ( rs->sr_ctrls != NULL ) {
82                 for ( i = 0; rs->sr_ctrls[i] != NULL; i++ )
83                         ;
84
85                 controls = (LDAPControl **)slapi_ch_calloc( i + 1,
86                         sizeof(LDAPControl ));
87
88                 for ( i = 0; rs->sr_ctrls[i] != NULL; i++ )
89                         controls[i] = slapi_dup_control( rs->sr_ctrls[i] );
90
91                 controls[i] = NULL;
92         }
93
94         slapi_pblock_set( pb, SLAPI_RESCONTROLS,         (void *)controls );
95         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs->sr_err );
96
97         if ( prc != NULL ) {
98                 (*prc)( rs->sr_err, callback_data );
99         }
100
101         return LDAP_SUCCESS;
102 }
103
104 static int
105 slapi_int_search_entry(
106         Operation       *op,
107         SlapReply       *rs )
108 {
109         plugin_search_entry_callback    psec = NULL;
110         void                            *callback_data = NULL;
111         Slapi_PBlock                    *pb = SLAPI_OPERATION_PBLOCK( op );
112         int                             rc = SLAP_CB_CONTINUE;
113
114         assert( pb != NULL );
115
116         slapi_pblock_get( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK, (void **)&psec );
117         slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA,         &callback_data );
118
119         if ( psec != NULL ) {
120                 rc = (*psec)( rs->sr_entry, callback_data );
121         }
122
123         return LDAP_SUCCESS;
124 }
125
126 static int
127 slapi_int_search_reference(
128         Operation       *op,    
129         SlapReply       *rs )
130 {
131         int                             i, rc = LDAP_SUCCESS;
132         plugin_referral_entry_callback  prec = NULL;
133         void                            *callback_data = NULL;
134         Slapi_PBlock                    *pb = SLAPI_OPERATION_PBLOCK( op );
135
136         assert( pb != NULL );
137
138         slapi_pblock_get( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK, (void **)&prec );
139         slapi_pblock_get( pb, SLAPI_X_INTOP_CALLBACK_DATA,           &callback_data );
140
141         if ( prec != NULL ) {
142                 for ( i = 0; rs->sr_ref[i].bv_val != NULL; i++ ) {
143                         rc = (*prec)( rs->sr_ref[i].bv_val, callback_data );
144                         if ( rc != LDAP_SUCCESS ) {
145                                 break;
146                         }
147                 }
148         }
149
150         return rc;
151 }
152
153 int
154 slapi_int_response( Slapi_Operation *op, SlapReply *rs )
155 {
156         int                             rc;
157
158         switch ( rs->sr_type ) {
159         case REP_RESULT:
160                 rc = slapi_int_result( op, rs );
161                 break;
162         case REP_SEARCH:
163                 rc = slapi_int_search_entry( op, rs );
164                 break;
165         case REP_SEARCHREF:
166                 rc = slapi_int_search_reference( op, rs );
167                 break;
168         default:
169                 rc = LDAP_OTHER;
170                 break;
171         }
172
173         assert( rc != SLAP_CB_CONTINUE );
174
175         return rc;
176 }
177
178 static int
179 slapi_int_get_ctrls( Operation *op, SlapReply *rs, LDAPControl **controls )
180 {
181         LDAPControl             **c;
182         int                     rc;
183
184         op->o_ctrls = controls;
185         if ( op->o_ctrls == NULL ) {
186                 return LDAP_SUCCESS;
187         }
188
189         for ( c = op->o_ctrls; *c != NULL; c++ ) {
190                 rc = slap_parse_ctrl( op, rs, *c, &rs->sr_text );
191                 if ( rc != LDAP_SUCCESS )
192                         break;
193         }
194
195         return rc;
196 }
197
198 /*
199  * To allow plugins to forward frontend requests to internal operations,
200  * the internal operation and connection structures should import as
201  * much state as practicable from the supplied parameter block.
202  */
203
204 /*
205  * Select the backend to be used for an internal operation, either
206  * from the operation target DN or from the parameter block.
207  */
208 static int
209 slapi_int_pblock_get_backend( Slapi_PBlock *pb, Operation *op )
210 {
211         int                     manageDsaIt = 0, isCritical;
212         LDAPControl             **controls = NULL;
213         BackendDB               *be_op;
214
215         slapi_pblock_get( pb, SLAPI_REQCONTROLS, (void **)&controls );
216
217         slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, (void **)&manageDsaIt );
218         if ( manageDsaIt != 0 )
219                 manageDsaIt = SLAP_CONTROL_CRITICAL;
220         else if ( slapi_control_present( controls, SLAPI_CONTROL_MANAGEDSAIT_OID,
221                     NULL, &isCritical ))
222                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
223
224         /* let caller force a specific backend */
225         slapi_pblock_get( pb, SLAPI_BACKEND, (void **)&be_op );
226         if ( be_op == NULL ) {
227                 be_op = select_backend( &op->o_req_ndn, 0, 0 );
228                 slapi_pblock_set( pb, SLAPI_BACKEND, (void *)be_op );
229         }
230
231         op->o_bd = frontendDB; /* but we actually use frontend DB */
232
233         return LDAP_SUCCESS;
234 }
235
236 static int
237 slapi_int_pblock_get_connection( Slapi_PBlock *pb, Operation *op )
238 {
239         char                    *connDn = NULL;
240         Connection              *conn = op->o_conn;
241
242         slapi_pblock_get( pb, SLAPI_X_CONN_SSF, (void **)&conn->c_ssf );
243         slapi_pblock_get( pb, SLAPI_X_CONN_SASL_CONTEXT, (void **)&conn->c_sasl_authctx );
244
245         if ( slapi_pblock_get( pb, SLAPI_CONN_DN, (void **)&connDn ) != 0
246                         || connDn == NULL )
247         {
248                 /* default to operation DN */
249                 conn->c_ndn = op->o_ndn;
250                 conn->c_dn = op->o_ndn;
251
252         } else {
253                 /* NB: conn DN must be normalized */
254                 ber_str2bv( connDn, 0, 0, &conn->c_ndn );
255                 conn->c_dn = conn->c_ndn;
256         }
257
258         return LDAP_SUCCESS;
259 }
260
261 static int
262 slapi_int_pblock_get_operation( Slapi_PBlock *pb, Operation *op, SlapReply *rs )
263 {
264         int                     isRoot = 0;
265         int                     isUpdateDn = 0;
266         char                    *requestorDn = NULL;
267         struct berval           targetDn = BER_BVNULL;
268         LDAPControl             **controls;
269         int                     rc;
270         BackendDB               *be_op;
271
272         /* All internal operations must specify a target DN */
273         slapi_pblock_get( pb, SLAPI_TARGET_DN, (void **)&targetDn.bv_val );
274         if ( targetDn.bv_val == NULL) {
275                 return LDAP_PARAM_ERROR; 
276         }
277         targetDn.bv_len = strlen( targetDn.bv_val );
278
279         rc = dnPrettyNormal( NULL, &targetDn, &op->o_req_dn, &op->o_req_ndn, NULL );
280         if ( rc != LDAP_SUCCESS ) {
281                 return rc;
282         }
283
284         rc = slapi_int_pblock_get_backend( pb, op );
285         if ( rc != LDAP_SUCCESS ) {
286                 return rc;
287         }
288
289         slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, (void **)&isRoot );
290         slapi_pblock_get( pb, SLAPI_REQUESTOR_ISUPDATEDN, (void **)&isUpdateDn );
291         /* NB: requestor DN must be normalized */
292         slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, (void **)&requestorDn );
293         slapi_pblock_get( pb, SLAPI_BACKEND, (void **)&be_op );
294
295         /* Default authorization identity for internal operations is root DN */
296         if ( isRoot || requestorDn == NULL ) {
297                 assert( be_op != NULL );
298                 op->o_dn = be_op->be_rootdn;
299                 op->o_ndn = be_op->be_rootndn;
300                 isRoot = 1;
301         } else {
302                 ber_str2bv( requestorDn, 0, 0, &op->o_ndn );
303                 op->o_dn = op->o_ndn;
304         }
305
306         slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, (void *)isRoot );
307
308         rc = slapi_int_pblock_get_connection( pb, op );
309         if ( rc != LDAP_SUCCESS ) {
310                 return rc;
311         }
312
313         slapi_pblock_get( pb, SLAPI_REQCONTROLS, (void **)&controls );
314         rc = slapi_int_get_ctrls( op, rs, controls );
315         if ( rc != LDAP_SUCCESS ) {
316                 return rs->sr_err;
317         }
318
319         return LDAP_SUCCESS;
320 }
321
322 int
323 slapi_int_connection_init( Slapi_PBlock *pb,
324         SlapReply *rs,
325         int OpType,
326         Connection **pConn )
327 {
328         Connection              *conn;
329         Operation               *op;
330         ber_len_t               max = sockbuf_max_incoming;
331         int                     rc;
332
333         conn = (Connection *) slapi_ch_calloc( 1, sizeof(Connection) );
334
335         LDAP_STAILQ_INIT( &conn->c_pending_ops );
336
337         op = (Operation *) slapi_ch_calloc( 1, OPERATION_BUFFER_SIZE );
338         op->o_hdr = (Opheader *)(op + 1);
339         op->o_hdr->oh_extensions = NULL;
340         op->o_controls = (void **)(op->o_hdr + 1);
341
342         op->o_callback = (slap_callback *) slapi_ch_calloc( 1, sizeof(slap_callback) );
343         op->o_callback->sc_response = slapi_int_response;
344         op->o_callback->sc_cleanup = NULL;
345         op->o_callback->sc_private = pb;
346         op->o_callback->sc_next = NULL;
347
348         conn->c_pending_ops.stqh_first = op;
349
350         /* connection object authorization information */
351         conn->c_authtype = LDAP_AUTH_NONE;
352         BER_BVZERO( &conn->c_authmech );
353         BER_BVZERO( &conn->c_dn );
354         BER_BVZERO( &conn->c_ndn );
355
356         conn->c_listener = &slap_unknown_listener;
357         ber_dupbv( &conn->c_peer_domain, (struct berval *)&slap_unknown_bv );
358         ber_dupbv( &conn->c_peer_name, (struct berval *)&slap_unknown_bv );
359
360         LDAP_STAILQ_INIT( &conn->c_ops );
361
362         BER_BVZERO( &conn->c_sasl_bind_mech );
363         conn->c_sasl_authctx = NULL;
364         conn->c_sasl_sockctx = NULL;
365         conn->c_sasl_extra = NULL;
366
367         conn->c_sb = ber_sockbuf_alloc( );
368
369         ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
370
371         conn->c_currentber = NULL;
372
373         /* should check status of thread calls */
374         ldap_pvt_thread_mutex_init( &conn->c_mutex );
375         ldap_pvt_thread_mutex_init( &conn->c_write_mutex );
376         ldap_pvt_thread_cond_init( &conn->c_write_cv );
377
378         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
379
380         conn->c_n_ops_received = 0;
381         conn->c_n_ops_executing = 0;
382         conn->c_n_ops_pending = 0;
383         conn->c_n_ops_completed = 0;
384
385         conn->c_n_get = 0;
386         conn->c_n_read = 0;
387         conn->c_n_write = 0;
388
389         conn->c_protocol = LDAP_VERSION3; 
390
391         conn->c_activitytime = conn->c_starttime = slap_get_time();
392
393         /*
394          * A real connection ID is required, because syncrepl associates
395          * pending CSNs with unique ( connection, operation ) tuples.
396          * Setting a fake connection ID will cause slap_get_commit_csn()
397          * to return a stale value.
398          */
399         connection_assign_nextid( conn );
400
401         conn->c_conn_state  = 0x01;     /* SLAP_C_ACTIVE */
402         conn->c_struct_state = 0x02;    /* SLAP_C_USED */
403
404         conn->c_ssf = conn->c_transport_ssf = 0;
405         conn->c_tls_ssf = 0;
406
407         backend_connection_init( conn );
408
409         conn->c_send_ldap_result = slap_send_ldap_result;
410         conn->c_send_search_entry = slap_send_search_entry;
411         conn->c_send_ldap_extended = slap_send_ldap_extended;
412         conn->c_send_search_reference = slap_send_search_reference;
413
414         /* operation object */
415         op->o_tag = OpType;
416         op->o_protocol = LDAP_VERSION3; 
417         BER_BVZERO( &op->o_authmech );
418         op->o_time = slap_get_time();
419         op->o_do_not_cache = 1;
420         op->o_threadctx = ldap_pvt_thread_pool_context();
421         op->o_tmpmemctx = NULL;
422         op->o_tmpmfuncs = &ch_mfuncs;
423         op->o_conn = conn;
424         op->o_connid = conn->c_connid;
425
426         rc = slapi_int_pblock_get_operation( pb, op, rs );
427
428         slapi_pblock_set( pb, SLAPI_OPERATION, op );
429         slapi_pblock_set( pb, SLAPI_CONNECTION, conn );
430
431         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
432
433         if ( rc != LDAP_SUCCESS ) {
434                 slapi_int_connection_destroy( &conn );
435                 return rc;
436         }
437
438         *pConn = conn;
439
440         return LDAP_SUCCESS;
441 }
442
443 void slapi_int_connection_destroy( Connection **pConn )
444 {
445         Connection              *conn = *pConn;
446         Operation               *op;
447         Slapi_PBlock            *pb;
448
449         if ( conn == NULL ) {
450                 return;
451         }
452
453         op = (Operation *)conn->c_pending_ops.stqh_first;
454         pb = SLAPI_OPERATION_PBLOCK( op );
455
456         slap_graduate_commit_csn( op );
457
458         slapi_ch_free_string( &op->o_req_dn.bv_val );
459         slapi_ch_free_string( &op->o_req_ndn.bv_val );
460         slapi_ch_free( (void **)&op->o_callback );
461
462         if ( conn->c_sb != NULL ) {
463                 ber_sockbuf_free( conn->c_sb );
464         }
465
466         slapi_pblock_set( pb, SLAPI_OPERATION,  NULL );
467         slapi_pblock_set( pb, SLAPI_CONNECTION, NULL );
468
469         slapi_ch_free( (void **)&op );
470         slapi_ch_free( (void **)pConn );
471 }
472
473 int
474 slapi_delete_internal_pb( Slapi_PBlock *pb )
475 {
476 #ifdef LDAP_SLAPI
477         Connection              *conn = NULL;
478         Operation               *op = NULL;
479
480         SlapReply               rs = { REP_RESULT };
481
482         if ( pb == NULL ) {
483                 return -1;
484         }
485
486         rs.sr_err = slapi_int_connection_init( pb, &rs, LDAP_REQ_DELETE, &conn );
487         if ( rs.sr_err != LDAP_SUCCESS ) {
488                 slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
489                 return 0;
490         }
491
492         op = conn->c_pending_ops.stqh_first;
493         rs.sr_err = frontendDB->be_delete( op, &rs );
494
495         slapi_int_connection_destroy( &conn );
496
497         return 0;
498 #else
499         return -1;
500 #endif /* LDAP_SLAPI */
501 }
502
503 int
504 slapi_add_internal_pb( Slapi_PBlock *pb )
505 {
506 #ifdef LDAP_SLAPI
507         Connection              *conn = NULL;
508         Slapi_Entry             *entry = NULL;
509         char                    *dn = NULL;
510         LDAPMod                 **mods = NULL;
511         Operation               *op = NULL;
512         char                    textbuf[ SLAP_TEXT_BUFLEN ];
513         size_t                  textlen = sizeof( textbuf );
514
515         SlapReply               rs = { REP_RESULT };
516
517         if ( pb == NULL ) {
518                 return -1;
519         }
520
521         slapi_pblock_get( pb, SLAPI_ADD_ENTRY,     (void **)&entry );
522         slapi_pblock_get( pb, SLAPI_ADD_TARGET,    (void **)&dn );
523         slapi_pblock_get( pb, SLAPI_MODIFY_MODS,   (void **)&mods );
524
525         if ( entry != NULL ) {
526                 if ( dn != NULL ) {
527                         rs.sr_err = LDAP_PARAM_ERROR;
528                         goto cleanup;
529                 }
530
531                 dn = slapi_entry_get_dn( entry );
532                 slapi_pblock_set( pb, SLAPI_ADD_TARGET, dn );
533         } else if ( mods == NULL || dn == NULL ) {
534                 rs.sr_err = LDAP_PARAM_ERROR;
535                 goto cleanup;
536         }
537
538         rs.sr_err = slapi_int_connection_init( pb, &rs, LDAP_REQ_ADD, &conn );
539         if ( rs.sr_err != LDAP_SUCCESS ) {
540                 goto cleanup;
541         }
542
543         op = (Operation *)conn->c_pending_ops.stqh_first;
544         op->ora_e = NULL;
545         op->ora_modlist = NULL;
546
547         /*
548          * The caller can specify a new entry, or a target DN and set
549          * of modifications, but not both.
550          */
551         op->ora_e = (Entry *)slapi_ch_calloc( 1, sizeof(*entry) );
552         ber_dupbv( &op->ora_e->e_name,  &op->o_req_dn );
553         ber_dupbv( &op->ora_e->e_nname, &op->o_req_ndn );
554
555         if ( mods != NULL ) {
556                 /* Entry just contains name; attributes are in modlist */
557                 op->ora_modlist = slapi_int_ldapmods2modifications( mods );
558                 if ( op->ora_modlist == NULL ) {
559                         rs.sr_err = LDAP_PROTOCOL_ERROR;
560                         goto cleanup;
561                 }
562         } else {
563                 rs.sr_err = slap_entry2mods( entry, &op->ora_modlist,
564                         &rs.sr_text, textbuf, textlen );
565                 if ( rs.sr_err != LDAP_SUCCESS )
566                         goto cleanup;
567         }
568
569         rs.sr_err = slap_mods_check( op->ora_modlist, &rs.sr_text,
570                 textbuf, textlen, NULL );
571         if ( rs.sr_err != LDAP_SUCCESS ) {
572                 goto cleanup;
573         }
574
575         rs.sr_err = frontendDB->be_add( op, &rs );
576         if ( rs.sr_err == 0 ) {
577                 if ( op->ora_e != NULL && op->o_private != NULL ) {
578                         BackendDB       *bd = op->o_bd;
579
580                         /* could we use SLAPI_BACKEND instead? */
581                         op->o_bd = (BackendDB *)op->o_private;
582                         op->o_private = NULL;
583                         be_entry_release_w( op, op->ora_e );
584                         op->ora_e = NULL;
585                         op->o_bd = bd;
586                         op->o_private = NULL;
587                 }
588         }
589
590 cleanup:
591         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
592
593         slapi_entry_free( op->ora_e );
594         slapi_int_mods_free( op->ora_modlist );
595         slapi_int_connection_destroy( &conn );
596
597         return 0;
598 #else
599         return -1;
600 #endif /* LDAP_SLAPI */
601 }
602
603 int
604 slapi_modrdn_internal_pb( Slapi_PBlock *pb )
605 {
606 #ifdef LDAP_SLAPI
607         struct berval           newrdn = BER_BVNULL;
608         struct berval           newsupdn = BER_BVNULL;
609         struct berval           newSuperiorPretty = BER_BVNULL;
610         struct berval           newSuperiorNormalized = BER_BVNULL;
611         Connection              *conn = NULL;
612         Operation               *op = NULL;
613
614         char                    *lnewrdn;
615         char                    *newsuperior;
616         int                     deloldrdn;
617
618         SlapReply               rs = { REP_RESULT };
619
620         if ( pb == NULL ) {
621                 return -1;
622         }
623
624         slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN,      (void **)&lnewrdn );
625         slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, (void **)&newsuperior );
626         slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN,   (void **)&deloldrdn );
627
628         rs.sr_err = slapi_int_connection_init( pb, &rs, LDAP_REQ_MODRDN, &conn );
629         if ( rs.sr_err != LDAP_SUCCESS ) {
630                 goto cleanup;
631         }
632
633         op = (Operation *)conn->c_pending_ops.stqh_first;
634
635         if ( op->o_req_dn.bv_len == 0 ) {
636                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
637                 goto cleanup;
638         }
639
640         newrdn.bv_val = lnewrdn;
641         newrdn.bv_len = strlen( lnewrdn );
642
643         rs.sr_err = dnPrettyNormal( NULL, &newrdn, &op->orr_newrdn, &op->orr_nnewrdn, NULL );
644         if ( rs.sr_err != LDAP_SUCCESS ) {
645                 goto cleanup;
646         }
647
648         if ( rdn_validate( &op->orr_nnewrdn ) != LDAP_SUCCESS ) {
649                 goto cleanup;
650         }
651
652         if ( newsuperior != NULL ) {
653                 newsupdn.bv_val = (char *)newsuperior;
654                 newsupdn.bv_len = strlen( newsuperior );
655
656                 rs.sr_err = dnPrettyNormal( NULL, &newsupdn, &newSuperiorPretty, &newSuperiorNormalized, NULL );
657                 if ( rs.sr_err != LDAP_SUCCESS )
658                         goto cleanup;
659
660                 op->orr_newSup = &newSuperiorPretty;
661                 op->orr_nnewSup = &newSuperiorNormalized;
662         } else {
663                 op->orr_newSup = NULL;
664                 op->orr_nnewSup = NULL;
665         }
666
667         op->orr_deleteoldrdn = deloldrdn;
668
669         rs.sr_err = frontendDB->be_modrdn( op, &rs );
670
671 cleanup:
672         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
673
674         slapi_ch_free_string( &op->orr_newrdn.bv_val );
675         slapi_ch_free_string( &op->orr_nnewrdn.bv_val );
676         slapi_ch_free_string( &newSuperiorPretty.bv_val );
677         slapi_ch_free_string( &newSuperiorNormalized.bv_val );
678
679         slapi_int_connection_destroy( &conn );
680
681         return 0;
682 #else
683         return -1;
684 #endif /* LDAP_SLAPI */
685 }
686
687 int
688 slapi_modify_internal_pb( Slapi_PBlock *pb )
689 {
690 #ifdef LDAP_SLAPI
691         Connection              *conn = NULL;
692         Operation               *op = NULL;
693         LDAPMod                 **mods = NULL;
694         char                    textbuf[ SLAP_TEXT_BUFLEN ];
695         size_t                  textlen = sizeof( textbuf );
696
697         SlapReply               rs = { REP_RESULT };
698
699         if ( pb == NULL ) {
700                 return -1;
701         }
702
703         slapi_pblock_get( pb, SLAPI_MODIFY_MODS, (void **)&mods );
704
705         if ( mods == NULL ) {
706                 rs.sr_err = LDAP_PARAM_ERROR ;
707                 goto cleanup;
708         }
709
710         rs.sr_err = slapi_int_connection_init( pb, &rs, LDAP_REQ_MODIFY, &conn );
711         if ( rs.sr_err != LDAP_SUCCESS ) {
712                 goto cleanup;
713         }
714
715         op = (Operation *)conn->c_pending_ops.stqh_first;
716
717         if ( op->o_req_ndn.bv_len == 0 ) {
718                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
719                 goto cleanup;
720         }
721
722         op->orm_modlist = slapi_int_ldapmods2modifications( mods );
723
724         rs.sr_err = slap_mods_check( op->orm_modlist, &rs.sr_text,
725                 textbuf, textlen, NULL );
726         if ( rs.sr_err != LDAP_SUCCESS ) {
727                 goto cleanup;
728         }
729
730         rs.sr_err = frontendDB->be_modify( op, &rs );
731
732 cleanup:
733         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
734
735         slapi_int_mods_free( op->orm_modlist );
736         slapi_int_connection_destroy( &conn );
737
738         return 0;
739 #else
740         return -1;
741 #endif /* LDAP_SLAPI */
742 }
743
744 #ifdef LDAP_SLAPI
745 static int
746 slapi_int_search_entry_callback( Slapi_Entry *entry, void *callback_data )
747 {
748         int             nentries = 0, i = 0;
749         Slapi_Entry     **head = NULL, **tp;
750         Slapi_PBlock    *pb = (Slapi_PBlock *)callback_data;
751
752         entry = slapi_entry_dup( entry );
753         if ( entry == NULL ) {
754                 return 1;
755         }
756
757         slapi_pblock_get( pb, SLAPI_NENTRIES, &nentries );
758         slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &head );
759         
760         i = nentries + 1;
761         if ( nentries == 0 ) {
762                 tp = (Slapi_Entry **)slapi_ch_malloc( 2 * sizeof(Slapi_Entry *) );
763                 if ( tp == NULL ) {
764                         slapi_entry_free( entry );
765                         return 1;
766                 }
767
768                 tp[ 0 ] = entry;
769         } else {
770                 tp = (Slapi_Entry **)slapi_ch_realloc( (char *)head,
771                                 sizeof(Slapi_Entry *) * ( i + 1 ) );
772                 if ( tp == NULL ) {
773                         slapi_entry_free( entry );
774                         return 1;
775                 }
776                 tp[ i - 1 ] = entry;
777         }
778         tp[ i ] = NULL;
779                   
780         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, (void *)tp );
781         slapi_pblock_set( pb, SLAPI_NENTRIES, (void *)i );
782
783         return LDAP_SUCCESS;
784 }
785 #endif /* LDAP_SLAPI */
786
787 int
788 slapi_search_internal_pb( Slapi_PBlock *pb )
789 {
790 #ifdef LDAP_SLAPI
791         return slapi_search_internal_callback_pb( pb,
792                 (void *)pb,
793                 NULL,
794                 slapi_int_search_entry_callback,
795                 NULL );
796 #else
797         return -1;
798 #endif
799 }
800
801 int
802 slapi_search_internal_callback_pb( Slapi_PBlock *pb,
803         void *callback_data,
804         plugin_result_callback prc,
805         plugin_search_entry_callback psec,
806         plugin_referral_entry_callback prec )
807 {
808 #ifdef LDAP_SLAPI
809         Connection              *conn = NULL;
810         Operation               *op = NULL;
811         Filter                  *filter = NULL;
812         struct berval           fstr = BER_BVNULL;
813         AttributeName           *an = NULL;
814         const char              *text = NULL;
815
816         int                     scope = LDAP_SCOPE_BASE;
817         char                    *filStr = NULL;
818         char                    **attrs = NULL;
819         int                     attrsonly = 0;
820         int                     freeFilter = 0;
821         int                     i;
822
823         SlapReply               rs = { REP_RESULT };
824
825         if ( pb == NULL ) {
826                 return -1;
827         }
828
829         slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE,     (void **)&scope );
830         slapi_pblock_get( pb, SLAPI_SEARCH_FILTER,    (void **)&filter );
831         slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, (void **)&filStr );
832         slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS,     (void **)&attrs );
833         slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, (void **)&attrsonly );
834
835         rs.sr_err = slapi_int_connection_init( pb, &rs, LDAP_REQ_SEARCH, &conn );
836         if ( rs.sr_err != LDAP_SUCCESS ) {
837                 goto cleanup;
838         }
839
840         /* search callback and arguments */
841         slapi_pblock_set( pb, SLAPI_X_INTOP_RESULT_CALLBACK,         (void *)prc );
842         slapi_pblock_set( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK,   (void *)psec );
843         slapi_pblock_set( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK, (void *)prec );
844         slapi_pblock_set( pb, SLAPI_X_INTOP_CALLBACK_DATA,           (void *)callback_data );
845
846         op = (Operation *)conn->c_pending_ops.stqh_first;
847
848         switch ( scope ) {
849                 case LDAP_SCOPE_BASE:
850                 case LDAP_SCOPE_ONELEVEL:
851                 case LDAP_SCOPE_SUBTREE:
852 #ifdef LDAP_SCOPE_SUBORDINATE
853                 case LDAP_SCOPE_SUBORDINATE:
854 #endif
855                         break;
856                 default:
857                         rs.sr_err = LDAP_PROTOCOL_ERROR;
858                         goto cleanup;
859         }
860
861         if ( filter == NULL ) {
862                 if ( filStr == NULL ) {
863                         rs.sr_err = LDAP_PARAM_ERROR;
864                         goto cleanup;
865                 }
866
867                 filter = slapi_str2filter( filStr );
868                 if ( filter == NULL ) {
869                         rs.sr_err = LDAP_PROTOCOL_ERROR;
870                         goto cleanup;
871                 }
872
873                 freeFilter = 1;
874         }
875
876         filter2bv( filter, &fstr );
877
878         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
879                 ; /* count the number of attributes */
880         }
881
882         if ( i > 0 ) {
883                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
884                 for (i = 0; attrs[i] != 0; i++) {
885                         an[i].an_desc = NULL;
886                         an[i].an_oc = NULL;
887                         an[i].an_oc_exclude = 0;
888                         an[i].an_name.bv_val = attrs[i];
889                         an[i].an_name.bv_len = strlen(attrs[i]);
890                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
891                 }
892                 an[i].an_name.bv_val = NULL;
893         }
894
895         rs.sr_type = REP_RESULT;
896         rs.sr_err = LDAP_SUCCESS;
897         rs.sr_entry = NULL; /* paranoia */
898         op->ors_scope = scope;
899         op->ors_deref = 0;
900         op->ors_slimit = SLAP_NO_LIMIT;
901         op->ors_tlimit = SLAP_NO_LIMIT;
902         op->ors_attrsonly = attrsonly;
903         op->ors_attrs = an;
904         op->ors_filter = filter;
905         op->ors_filterstr = fstr;
906
907         rs.sr_err = frontendDB->be_search( op, &rs );
908
909 cleanup:
910         slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT,            (void *)rs.sr_err );
911         slapi_pblock_set( pb, SLAPI_X_INTOP_RESULT_CALLBACK,         NULL );
912         slapi_pblock_set( pb, SLAPI_X_INTOP_SEARCH_ENTRY_CALLBACK,   NULL );
913         slapi_pblock_set( pb, SLAPI_X_INTOP_REFERRAL_ENTRY_CALLBACK, NULL );
914         slapi_pblock_set( pb, SLAPI_X_INTOP_CALLBACK_DATA,           NULL );
915
916         if ( freeFilter && filter != NULL )
917                 slapi_filter_free( filter, 1 );
918         slapi_ch_free_string( &fstr.bv_val );
919         slapi_ch_free( (void **)&an );
920
921         slapi_int_connection_destroy( &conn );
922
923         return 0;
924 #else
925         return -1;
926 #endif /* LDAP_SLAPI */
927 }
928
929 /* Wrappers for old API */
930
931 void
932 slapi_search_internal_set_pb( Slapi_PBlock *pb,
933         const char *base,
934         int scope,
935         const char *filter,
936         char **attrs,
937         int attrsonly,
938         LDAPControl **controls,
939         const char *uniqueid,
940         Slapi_ComponentId *plugin_identity,
941         int operation_flags )
942 {
943 #ifdef LDAP_SLAPI
944         slapi_pblock_set( pb, SLAPI_SEARCH_TARGET,    (void *)base );
945         slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE,     (void *)scope );
946         slapi_pblock_set( pb, SLAPI_SEARCH_FILTER,     NULL );
947         slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, (void *)filter );
948         slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS,     (void *)attrs );
949         slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, (void *)attrsonly );
950         slapi_pblock_set( pb, SLAPI_REQCONTROLS,      (void *)controls );
951         slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID,  (void *)uniqueid );
952         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY,  (void *)plugin_identity );
953         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,    (void *)operation_flags );
954 #endif /* LDAP_SLAPI */
955 }
956
957 Slapi_PBlock *
958 slapi_search_internal(
959         char *ldn, 
960         int scope, 
961         char *filStr, 
962         LDAPControl **controls, 
963         char **attrs, 
964         int attrsonly ) 
965 {
966 #ifdef LDAP_SLAPI
967         Slapi_PBlock *pb;
968
969         pb = slapi_pblock_new();
970         if ( pb == NULL ) {
971                 return NULL;
972         }
973
974         slapi_search_internal_set_pb( pb, ldn, scope, filStr, attrs, attrsonly,
975                 controls, NULL, NULL, 0 );
976
977         slapi_search_internal_pb( pb );
978
979         return pb;
980 #else
981         return NULL;
982 #endif /* LDAP_SLAPI */
983 }
984
985 void
986 slapi_modify_internal_set_pb( Slapi_PBlock *pb,
987         const char *dn,
988         LDAPMod **mods,
989         LDAPControl **controls,
990         const char *uniqueid,
991         Slapi_ComponentId *plugin_identity,
992         int operation_flags )
993 {
994 #ifdef LDAP_SLAPI
995         slapi_pblock_set( pb, SLAPI_MODIFY_TARGET,   (void *)dn );
996         slapi_pblock_set( pb, SLAPI_MODIFY_MODS,     (void *)mods );
997         slapi_pblock_set( pb, SLAPI_REQCONTROLS,     (void *)controls );
998         slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid );
999         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity );
1000         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,   (void *)operation_flags );
1001 #endif /* LDAP_SLAPI */
1002 }
1003
1004 /* Function : slapi_modify_internal
1005  *
1006  * Description: Plugin functions call this routine to modify an entry 
1007  *                              in the backend directly
1008  * Return values : LDAP_SUCCESS
1009  *                 LDAP_PARAM_ERROR
1010  *                 LDAP_NO_MEMORY
1011  *                 LDAP_OTHER
1012  *                 LDAP_UNWILLING_TO_PERFORM
1013 */
1014 Slapi_PBlock *
1015 slapi_modify_internal(
1016         char *ldn,      
1017         LDAPMod **mods, 
1018         LDAPControl **controls, 
1019         int log_change )
1020 {
1021 #ifdef LDAP_SLAPI
1022         Slapi_PBlock *pb;
1023
1024         pb = slapi_pblock_new();
1025         if ( pb == NULL ) {
1026                 return NULL;
1027         }
1028
1029         slapi_modify_internal_set_pb( pb, ldn, mods, controls, NULL, NULL,
1030                 log_change ? SLAPI_OP_FLAG_LOG_CHANGE : 0 );
1031
1032         slapi_modify_internal_pb( pb );
1033
1034         return pb;
1035 #else
1036         return NULL;
1037 #endif /* LDAP_SLAPI */
1038 }
1039
1040 int
1041 slapi_add_internal_set_pb( Slapi_PBlock *pb,
1042         const char *dn,
1043         LDAPMod **attrs,
1044         LDAPControl **controls,
1045         Slapi_ComponentId *plugin_identity,
1046         int operation_flags )
1047 {
1048 #ifdef LDAP_SLAPI
1049         slapi_pblock_set( pb, SLAPI_ADD_TARGET,      (void *)dn );
1050         slapi_pblock_set( pb, SLAPI_MODIFY_MODS,     (void *)attrs );
1051         slapi_pblock_set( pb, SLAPI_REQCONTROLS,     (void *)controls );
1052         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity );
1053         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,   (void *)operation_flags );
1054
1055         return 0;
1056 #else
1057         return -1;
1058 #endif /* LDAP_SLAPI */
1059 }
1060
1061 Slapi_PBlock *
1062 slapi_add_internal(
1063         char * dn,
1064         LDAPMod **attrs,
1065         LDAPControl **controls,
1066         int log_changes )
1067 {
1068 #ifdef LDAP_SLAPI
1069         Slapi_PBlock *pb;
1070
1071         pb = slapi_pblock_new();
1072         if ( pb == NULL )
1073                 return NULL;
1074
1075         slapi_add_internal_set_pb( pb, dn, attrs, controls, NULL,
1076                 log_changes ? SLAPI_OP_FLAG_LOG_CHANGE : 0 );
1077         
1078         slapi_add_internal_pb( pb );
1079
1080         return pb;
1081 #else
1082         return NULL;
1083 #endif /* LDAP_SLAPI */
1084 }
1085
1086 void
1087 slapi_add_entry_internal_set_pb( Slapi_PBlock *pb,
1088         Slapi_Entry *e,
1089         LDAPControl **controls,
1090         Slapi_ComponentId *plugin_identity,
1091         int operation_flags )
1092 {
1093 #ifdef LDAP_SLAPI
1094         slapi_pblock_set( pb, SLAPI_ADD_ENTRY,       (void *)e );
1095         slapi_pblock_set( pb, SLAPI_REQCONTROLS,     (void *)controls );
1096         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity );
1097         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,   (void *)operation_flags );
1098 #endif /* LDAP_SLAPI */
1099 }
1100
1101 Slapi_PBlock * 
1102 slapi_add_entry_internal(
1103         Slapi_Entry *e, 
1104         LDAPControl **controls, 
1105         int log_changes )
1106 {
1107 #ifdef LDAP_SLAPI
1108         Slapi_PBlock *pb;
1109
1110         pb = slapi_pblock_new();
1111         if ( pb == NULL )
1112                 return NULL;
1113
1114         slapi_add_entry_internal_set_pb( pb, e, controls, NULL,
1115                 log_changes ? SLAPI_OP_FLAG_LOG_CHANGE : 0 );
1116         
1117         slapi_add_internal_pb( pb );
1118
1119         return pb;
1120 #else
1121         return NULL;
1122 #endif /* LDAP_SLAPI */
1123 }
1124
1125 void
1126 slapi_rename_internal_set_pb( Slapi_PBlock *pb,
1127         const char *olddn,
1128         const char *newrdn,
1129         const char *newsuperior,
1130         int deloldrdn,
1131         LDAPControl **controls,
1132         const char *uniqueid,
1133         Slapi_ComponentId *plugin_identity,
1134         int operation_flags )
1135 {
1136 #ifdef LDAP_SLAPI
1137         slapi_pblock_set( pb, SLAPI_MODRDN_TARGET,      (void *)olddn );
1138         slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN,      (void *)newrdn );
1139         slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR, (void *)newsuperior );
1140         slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN,   (void *)deloldrdn );
1141         slapi_pblock_set( pb, SLAPI_REQCONTROLS,        (void *)controls );
1142         slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID,    (void *)uniqueid );
1143         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY,    (void *)plugin_identity );
1144         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,      (void *)operation_flags );
1145 #endif /* LDAP_SLAPI */
1146 }
1147
1148 /* Function : slapi_modrdn_internal
1149  *
1150  * Description : Plugin functions call this routine to modify the rdn 
1151  *                               of an entry in the backend directly
1152  * Return values : LDAP_SUCCESS
1153  *                 LDAP_PARAM_ERROR
1154  *                 LDAP_NO_MEMORY
1155  *                 LDAP_OTHER
1156  *                 LDAP_UNWILLING_TO_PERFORM
1157  *
1158  * NOTE: This function does not support the "newSuperior" option from LDAP V3.
1159  */
1160 Slapi_PBlock *
1161 slapi_modrdn_internal(
1162         char *olddn, 
1163         char *lnewrdn, 
1164         int deloldrdn, 
1165         LDAPControl **controls, 
1166         int log_change )
1167 {
1168 #ifdef LDAP_SLAPI
1169         Slapi_PBlock *pb;
1170
1171         pb = slapi_pblock_new();
1172         if ( pb == NULL ) {
1173                 return NULL;
1174         }
1175
1176         slapi_rename_internal_set_pb( pb, olddn, lnewrdn, NULL,
1177                 deloldrdn, controls, NULL, NULL,
1178                 log_change ? SLAPI_OP_FLAG_LOG_CHANGE : 0 );
1179
1180         slapi_modrdn_internal_pb( pb );
1181
1182         return pb;
1183 #else
1184         return NULL;
1185 #endif /* LDAP_SLAPI */
1186 }
1187
1188 void
1189 slapi_delete_internal_set_pb( Slapi_PBlock *pb,
1190         const char *dn,
1191         LDAPControl **controls,
1192         const char *uniqueid,
1193         Slapi_ComponentId *plugin_identity,
1194         int operation_flags )
1195 {
1196 #ifdef LDAP_SLAPI
1197         slapi_pblock_set( pb, SLAPI_TARGET_DN,       (void *)dn );
1198         slapi_pblock_set( pb, SLAPI_REQCONTROLS,     (void *)controls );
1199         slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, (void *)uniqueid );
1200         slapi_pblock_set( pb, SLAPI_PLUGIN_IDENTITY, (void *)plugin_identity );
1201         slapi_pblock_set( pb, SLAPI_X_INTOP_FLAGS,   (void *)operation_flags );
1202 #endif /* LDAP_SLAPI */
1203 }
1204
1205 /* Function : slapi_delete_internal
1206  *
1207  * Description : Plugin functions call this routine to delete an entry 
1208  *               in the backend directly
1209  * Return values : LDAP_SUCCESS
1210  *                 LDAP_PARAM_ERROR
1211  *                 LDAP_NO_MEMORY
1212  *                 LDAP_OTHER
1213  *                 LDAP_UNWILLING_TO_PERFORM
1214 */
1215 Slapi_PBlock *
1216 slapi_delete_internal(
1217         char *ldn, 
1218         LDAPControl **controls, 
1219         int log_change )
1220 {
1221 #ifdef LDAP_SLAPI
1222         Slapi_PBlock *pb;
1223
1224         pb = slapi_pblock_new();
1225         if ( pb == NULL )
1226                 return NULL;
1227
1228         slapi_delete_internal_set_pb( pb, ldn, controls, NULL, NULL,
1229                 log_change ? SLAPI_OP_FLAG_LOG_CHANGE : 0 );
1230
1231         slapi_delete_internal_pb( pb );
1232
1233         return pb;
1234 #else
1235         return NULL;
1236 #endif /* LDAP_SLAPI */
1237 }
1238