]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Always exclude subordinates from top-level ops so glue overlay can
[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-2004 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 internal_result_v3(
45         Operation       *op, 
46         SlapReply       *rs )
47 {
48 #ifdef notdef
49         /* XXX needs review after internal API change */
50         /* rs->sr_nentries appears to always be 0 */
51         if (op->o_tag == LDAP_REQ_SEARCH)
52                 slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
53                         SLAPI_NENTRIES, (void *)rs->sr_nentries );
54 #endif
55
56         return;
57 }
58
59 static int
60 internal_search_entry(
61         Operation       *op,
62         SlapReply       *rs )
63 {
64         int nentries = 0, len = 0, i = 0;
65         Slapi_Entry **head = NULL, **tp;
66         Slapi_Entry *entry;
67
68         entry = slapi_entry_dup( rs->sr_entry );
69         if ( entry == NULL ) {
70                 return 1;
71         }
72
73         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
74                         SLAPI_NENTRIES, &nentries );
75         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
76                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &head );
77         
78         i = nentries + 1;
79         if ( nentries == 0 ) {
80                 tp = (Slapi_Entry **)slapi_ch_malloc( 2 * sizeof(Slapi_Entry *) );
81                 if ( tp == NULL ) {
82                         slapi_entry_free( entry );
83                         return 1;
84                 }
85
86                 tp[ 0 ] = entry;
87         } else {
88                 tp = (Slapi_Entry **)slapi_ch_realloc( (char *)head,
89                                 sizeof(Slapi_Entry *) * ( i + 1 ) );
90                 if ( tp == NULL ) {
91                         slapi_entry_free( entry );
92                         return 1;
93                 }
94                 tp[ i - 1 ] = entry;
95         }
96         tp[ i ] = NULL;
97                   
98         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
99                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, (void *)tp );
100         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
101                         SLAPI_NENTRIES, (void *)i );
102
103         return LDAP_SUCCESS;
104 }
105
106 static void
107 internal_result_ext(
108         Operation       *op,    
109         SlapReply       *sr )
110 {
111         return;
112 }
113
114 static int
115 internal_search_reference(
116         Operation       *op,    
117         SlapReply       *sr )
118 {
119         return LDAP_SUCCESS;
120 }
121
122 Connection *
123 slapi_int_init_connection(
124         char *DN, 
125         int OpType ) 
126
127         Connection *pConn;
128         ber_len_t max = sockbuf_max_incoming;
129
130         pConn = (Connection *) slapi_ch_calloc(1, sizeof(Connection));
131         if (pConn == NULL) {
132                 return (Connection *)NULL;
133         }
134
135         LDAP_STAILQ_INIT( &pConn->c_pending_ops );
136
137         pConn->c_pending_ops.stqh_first =
138                 (Operation *) slapi_ch_calloc( 1, sizeof(Operation) );
139         if ( pConn->c_pending_ops.stqh_first == NULL ) { 
140                 slapi_ch_free( (void **)&pConn );
141                 return (Connection *)NULL;
142         }
143
144         pConn->c_pending_ops.stqh_first->o_pb = 
145                 (Slapi_PBlock *) slapi_pblock_new();
146         if ( pConn->c_pending_ops.stqh_first->o_pb == NULL ) {
147                 slapi_ch_free( (void **)&pConn->c_pending_ops.stqh_first );
148                 slapi_ch_free( (void **)&pConn );
149                 return (Connection *)NULL;
150         }
151
152         /* connection object */
153         pConn->c_authmech.bv_val = NULL;
154         pConn->c_authmech.bv_len = 0;
155         pConn->c_dn.bv_val = NULL;
156         pConn->c_dn.bv_len = 0;
157         pConn->c_ndn.bv_val = NULL;
158         pConn->c_ndn.bv_len = 0;
159
160         pConn->c_listener = &slap_unknown_listener;
161         ber_dupbv( &pConn->c_peer_domain, (struct berval *)&slap_unknown_bv );
162         ber_dupbv( &pConn->c_peer_name, (struct berval *)&slap_unknown_bv );
163
164         LDAP_STAILQ_INIT( &pConn->c_ops );
165
166         pConn->c_sasl_bind_mech.bv_val = NULL;
167         pConn->c_sasl_bind_mech.bv_len = 0;
168         pConn->c_sasl_authctx = NULL;
169         pConn->c_sasl_sockctx = NULL;
170         pConn->c_sasl_extra = NULL;
171
172         pConn->c_sb = ber_sockbuf_alloc( );
173
174         ber_sockbuf_ctrl( pConn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
175
176         pConn->c_currentber = NULL;
177
178         /* should check status of thread calls */
179         ldap_pvt_thread_mutex_init( &pConn->c_mutex );
180         ldap_pvt_thread_mutex_init( &pConn->c_write_mutex );
181         ldap_pvt_thread_cond_init( &pConn->c_write_cv );
182
183         ldap_pvt_thread_mutex_lock( &pConn->c_mutex );
184
185         pConn->c_n_ops_received = 0;
186         pConn->c_n_ops_executing = 0;
187         pConn->c_n_ops_pending = 0;
188         pConn->c_n_ops_completed = 0;
189
190         pConn->c_n_get = 0;
191         pConn->c_n_read = 0;
192         pConn->c_n_write = 0;
193
194         pConn->c_protocol = LDAP_VERSION3; 
195
196         pConn->c_activitytime = pConn->c_starttime = slap_get_time();
197
198         /*
199          * A real connection ID is required, because syncrepl associates
200          * pending CSNs with unique ( connection, operation ) tuples.
201          * Setting a fake connection ID will cause slap_get_commit_csn()
202          * to return a stale value.
203          */
204         connection_assign_nextid( pConn );
205
206         pConn->c_conn_state  = 0x01;    /* SLAP_C_ACTIVE */
207         pConn->c_struct_state = 0x02;   /* SLAP_C_USED */
208
209         pConn->c_ssf = pConn->c_transport_ssf = 0;
210         pConn->c_tls_ssf = 0;
211
212         backend_connection_init( pConn );
213
214         pConn->c_send_ldap_result = internal_result_v3;
215         pConn->c_send_search_entry = internal_search_entry;
216         pConn->c_send_ldap_extended = internal_result_ext;
217         pConn->c_send_search_reference = internal_search_reference;
218
219         /* operation object */
220         pConn->c_pending_ops.stqh_first->o_tag = OpType;
221         pConn->c_pending_ops.stqh_first->o_protocol = LDAP_VERSION3; 
222         pConn->c_pending_ops.stqh_first->o_authmech.bv_val = NULL; 
223         pConn->c_pending_ops.stqh_first->o_authmech.bv_len = 0; 
224         pConn->c_pending_ops.stqh_first->o_time = slap_get_time();
225         pConn->c_pending_ops.stqh_first->o_do_not_cache = 1;
226         pConn->c_pending_ops.stqh_first->o_threadctx = ldap_pvt_thread_pool_context();
227         pConn->c_pending_ops.stqh_first->o_tmpmemctx = NULL;
228         pConn->c_pending_ops.stqh_first->o_tmpmfuncs = &ch_mfuncs;
229         pConn->c_pending_ops.stqh_first->o_conn = pConn;
230         pConn->c_pending_ops.stqh_first->o_connid = pConn->c_connid;
231
232         ldap_pvt_thread_mutex_unlock( &pConn->c_mutex );
233
234         return pConn;
235 }
236
237 void slapi_int_connection_destroy( Connection **pConn )
238 {
239         Connection *conn = *pConn;
240         Operation *op;
241
242         if ( pConn == NULL ) {
243                 return;
244         }
245
246         op = (Operation *)conn->c_pending_ops.stqh_first;
247
248         slap_graduate_commit_csn( op );
249
250         if ( op->o_req_dn.bv_val != NULL ) {
251                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
252         }
253         if ( op->o_req_ndn.bv_val != NULL ) {
254                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
255         }
256
257         if ( conn->c_sb != NULL ) {
258                 ber_sockbuf_free( conn->c_sb );
259         }
260         if ( op != NULL ) {
261                 slapi_ch_free( (void **)&op );
262         }
263         slapi_ch_free( (void **)pConn );
264 }
265
266 /*
267  * Function : values2obj
268  * Convert an array of strings into a BerVarray.
269  * the strings.
270  */
271 static int
272 values2obj_copy(
273         char **ppValue,
274         BerVarray *bvobj )
275 {
276         int i;
277         BerVarray tmpberval;
278
279         if ( ppValue == NULL ) {
280                 *bvobj = NULL;
281                 return LDAP_SUCCESS;
282         }
283
284         for ( i = 0; ppValue[i] != NULL; i++ )
285                 ; /* EMPTY */
286
287         tmpberval = (BerVarray)slapi_ch_malloc( (i+1) * (sizeof(struct berval)) );
288         if ( tmpberval == NULL ) {
289                 return LDAP_NO_MEMORY;
290         }
291         for ( i = 0; ppValue[i] != NULL; i++ ) {
292                 size_t len = strlen( ppValue[i] );
293
294                 tmpberval[i].bv_val = slapi_ch_malloc( len + 1 );
295                 AC_MEMCPY( tmpberval[i].bv_val, ppValue[i], len + 1 );
296                 tmpberval[i].bv_len = len;
297         }
298         tmpberval[i].bv_val = NULL;
299         tmpberval[i].bv_len = 0;
300
301         *bvobj = tmpberval;
302
303         return LDAP_SUCCESS;
304 }
305
306 static int
307 bvptr2obj_copy(
308         struct berval   **bvptr, 
309         BerVarray       *bvobj )
310 {
311         int             i;
312         BerVarray       tmpberval;
313
314         if ( bvptr == NULL ) {
315                 *bvobj = NULL;
316                 return LDAP_SUCCESS;
317         }
318
319         for ( i = 0; bvptr[i] != NULL; i++ )
320                 ; /* EMPTY */
321
322         tmpberval = (BerVarray)slapi_ch_malloc( (i + 1) * sizeof(struct berval));
323         if ( tmpberval == NULL ) {
324                 return LDAP_NO_MEMORY;
325         } 
326
327         for ( i = 0; bvptr[i] != NULL; i++ ) {
328                 tmpberval[i].bv_val = slapi_ch_malloc( bvptr[i]->bv_len );
329                 tmpberval[i].bv_len = bvptr[i]->bv_len;
330                 AC_MEMCPY( tmpberval[i].bv_val, bvptr[i]->bv_val, bvptr[i]->bv_len );
331         }
332
333         tmpberval[i].bv_val = NULL;
334         tmpberval[i].bv_len = 0;
335
336         *bvobj = tmpberval;
337
338         return LDAP_SUCCESS;
339 }
340
341 /*
342  * Function : slapi_int_ldapmod_to_entry 
343  * convert a dn plus an array of LDAPMod struct ptrs to an entry structure
344  * with a link list of the correspondent attributes.
345  * Return value : LDAP_SUCCESS
346  *                LDAP_NO_MEMORY
347  *                LDAP_OTHER
348 */
349 static Entry *
350 slapi_int_ldapmod_to_entry(
351         Connection *pConn,
352         char *ldn, 
353         LDAPMod **mods )
354 {
355         struct berval           dn = BER_BVNULL;
356         Entry                   *pEntry=NULL;
357         LDAPMod                 *pMod;
358         struct berval           *bv;
359         Operation               *op;
360
361         Modifications           *modlist = NULL;
362         Modifications           **modtail = &modlist;
363         Modifications           tmp;
364
365         int                     rc = LDAP_SUCCESS;
366         int                     i;
367
368         const char              *text = NULL;
369
370         op = (Operation *)pConn->c_pending_ops.stqh_first;
371
372         pEntry = (Entry *) ch_calloc( 1, sizeof(Entry) );
373         if ( pEntry == NULL) {
374                 rc = LDAP_NO_MEMORY;
375                 goto cleanup;
376         } 
377
378         dn.bv_val = slapi_ch_strdup(ldn);
379         dn.bv_len = strlen(ldn);
380
381         rc = dnPrettyNormal( NULL, &dn, &pEntry->e_name, &pEntry->e_nname, NULL );
382         if ( rc != LDAP_SUCCESS ) {
383                 goto cleanup;
384         }
385
386         if ( rc == LDAP_SUCCESS ) {
387                 for ( i = 0, pMod = mods[0]; rc == LDAP_SUCCESS && pMod != NULL; pMod = mods[++i]) {
388                         Modifications *mod;
389
390                         if ( (pMod->mod_op & LDAP_MOD_BVALUES) != 0 ) {
391                                 /*
392                                  * Convert an array of pointers to bervals to
393                                  * an array of bervals. Note that we need to copy the
394                                  * values too, as the slap_mods_check() will free the
395                                  * original values after prettying; the modifications
396                                  * being passed in may not have been allocated on the
397                                  * heap.
398                                  */
399                                 rc = bvptr2obj_copy( pMod->mod_bvalues, &bv );
400                                 if ( rc != LDAP_SUCCESS ) goto cleanup;
401                                 tmp.sml_type.bv_val = pMod->mod_type;
402                                 tmp.sml_type.bv_len = strlen( pMod->mod_type );
403                                 tmp.sml_values = bv;
404                                 tmp.sml_nvalues = NULL;
405                 
406                                 mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
407
408                                 mod->sml_op = LDAP_MOD_ADD;
409                                 mod->sml_next = NULL;
410                                 mod->sml_desc = NULL;
411                                 mod->sml_type = tmp.sml_type;
412                                 mod->sml_values = tmp.sml_values;
413                                 mod->sml_nvalues = tmp.sml_nvalues;
414
415                                 *modtail = mod;
416                                 modtail = &mod->sml_next;
417
418                         } else {
419                                 /* attr values are in string format, need to be converted */
420                                 /* to an array of bervals */ 
421                                 if ( pMod->mod_values == NULL ) {
422                                         rc = LDAP_OTHER;
423                                 } else {
424                                         rc = values2obj_copy( pMod->mod_values, &bv );
425                                         if ( rc != LDAP_SUCCESS ) goto cleanup;
426                                         tmp.sml_type.bv_val = pMod->mod_type;
427                                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
428                                         tmp.sml_values = bv;
429                                         tmp.sml_nvalues = NULL;
430                 
431                                         mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
432
433                                         mod->sml_op = LDAP_MOD_ADD;
434                                         mod->sml_next = NULL;
435                                         mod->sml_desc = NULL;
436                                         mod->sml_type = tmp.sml_type;
437                                         mod->sml_values = tmp.sml_values;
438                                         mod->sml_nvalues = tmp.sml_nvalues;
439
440                                         *modtail = mod;
441                                         modtail = &mod->sml_next;
442                                 }
443                         }
444                 } /* for each LDAPMod */
445         }
446
447         op->o_bd = select_backend( &pEntry->e_nname, 0, 0 );
448         if ( op->o_bd == NULL ) {
449                 rc = LDAP_PARTIAL_RESULTS;
450         } else {
451                 int repl_user = be_isupdate_dn( op->o_bd, &op->o_bd->be_rootdn );
452                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
453                         int update = op->o_bd->be_update_ndn.bv_len;
454                         char textbuf[SLAP_TEXT_BUFLEN];
455                         size_t textlen = sizeof textbuf;
456
457                         rc = slap_mods_check( modlist, update, &text, 
458                                         textbuf, textlen, NULL );
459                         if ( rc != LDAP_SUCCESS) {
460                                 goto cleanup;
461                         }
462
463                         if ( !repl_user ) {
464                                 rc = slap_mods_opattrs( op,
465                                                 modlist, modtail, &text, 
466                                                 textbuf, textlen, 1 );
467                                 if ( rc != LDAP_SUCCESS) {
468                                         goto cleanup;
469                                 }
470                         }
471
472                         rc = slap_mods2entry( modlist, &pEntry, repl_user,
473                                               0, &text, textbuf, textlen );
474                         if (rc != LDAP_SUCCESS) {
475                                 goto cleanup;
476                         }
477
478                 } else {
479                         rc = LDAP_REFERRAL;
480                 }
481         }
482
483 cleanup:
484
485         if ( dn.bv_val )
486                 slapi_ch_free( (void **)&dn.bv_val );
487         if ( modlist != NULL )
488                 slap_mods_free( modlist );
489         if ( rc != LDAP_SUCCESS ) {
490                 if ( pEntry != NULL ) {
491                         slapi_entry_free( pEntry );
492                 }
493                 pEntry = NULL;
494         }
495
496         return( pEntry );
497 }
498
499 /* Function : slapi_delete_internal
500  *
501  * Description : Plugin functions call this routine to delete an entry 
502  *               in the backend directly
503  * Return values : LDAP_SUCCESS
504  *                 LDAP_PARAM_ERROR
505  *                 LDAP_NO_MEMORY
506  *                 LDAP_OTHER
507  *                 LDAP_UNWILLING_TO_PERFORM
508 */
509 Slapi_PBlock *
510 slapi_delete_internal(
511         char *ldn, 
512         LDAPControl **controls, 
513         int log_change )
514 {
515 #ifdef LDAP_SLAPI
516         Connection              *pConn = NULL;
517         Operation               *op = NULL;
518         Slapi_PBlock            *pPB = NULL;
519         SlapReply               rs = { REP_RESULT };
520         struct berval           dn = BER_BVNULL;
521
522         int                     manageDsaIt = SLAP_CONTROL_NONE;
523         int                     isCritical;
524
525         if ( ldn == NULL ) {
526                 rs.sr_err = LDAP_PARAM_ERROR; 
527                 goto cleanup;
528         }
529
530         pConn = slapi_int_init_connection( NULL, LDAP_REQ_DELETE );
531         if (pConn == NULL) {
532                 rs.sr_err = LDAP_NO_MEMORY;
533                 goto cleanup;
534         }
535
536         op = (Operation *)pConn->c_pending_ops.stqh_first;
537         pPB = (Slapi_PBlock *)op->o_pb;
538         op->o_ctrls = controls;
539
540         dn.bv_val = slapi_ch_strdup(ldn);
541         dn.bv_len = strlen(ldn);
542         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
543         if ( rs.sr_err != LDAP_SUCCESS )
544                 goto cleanup;
545
546         if ( slapi_control_present( controls, 
547                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical) ) {
548                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 
549         }
550
551         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
552         if ( op->o_bd == NULL ) {
553                 rs.sr_err = LDAP_PARTIAL_RESULTS;
554                 goto cleanup;
555         }
556
557         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
558         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
559
560         if ( op->o_bd->be_delete ) {
561                 int repl_user = be_isupdate( op );
562                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
563                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
564                         if ( log_change ) op->o_callback = &cb;
565                         if ( (*op->o_bd->be_delete)( op, &rs ) ) {
566                                 rs.sr_err = LDAP_OTHER;
567                         }
568                 } else {
569                         rs.sr_err = LDAP_REFERRAL;
570                 }
571         } else {
572                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
573         }
574
575 cleanup:
576         if ( pPB != NULL ) {
577                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
578         }
579         if ( dn.bv_val ) {
580                 slapi_ch_free( (void **)&dn.bv_val );
581         }
582
583         slapi_int_connection_destroy( &pConn );
584
585         return pPB;
586 #else
587         return NULL;
588 #endif /* LDAP_SLAPI */
589 }
590
591 #ifdef LDAP_SLAPI
592 static Slapi_PBlock * 
593 slapi_int_add_entry_locked(
594         Connection *pConn,
595         Slapi_Entry **e, 
596         LDAPControl **controls, 
597         int log_changes ) 
598 {
599         Operation               *op = NULL;
600         Slapi_PBlock            *pPB = NULL;
601
602         int                     manageDsaIt = SLAP_CONTROL_NONE;
603         int                     isCritical;
604         SlapReply               rs = { REP_RESULT };
605
606         if ( *e == NULL ) {
607                 rs.sr_err = LDAP_PARAM_ERROR;
608                 goto cleanup;
609         }
610
611         if ( slapi_control_present( controls, LDAP_CONTROL_MANAGEDSAIT,
612                                 NULL, &isCritical ) ) {
613                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 
614         }
615
616         op = (Operation *)pConn->c_pending_ops.stqh_first;
617         pPB = (Slapi_PBlock *)op->o_pb;
618         op->o_ctrls = controls;
619
620         op->o_bd = select_backend( &((*e)->e_nname), manageDsaIt, 1 );
621         if ( op->o_bd == NULL ) {
622                 rs.sr_err = LDAP_PARTIAL_RESULTS;
623                 goto cleanup;
624         }
625
626         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
627         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
628         op->oq_add.rs_e = *e;
629
630         if ( op->o_bd->be_add ) {
631                 int repl_user = be_isupdate( op );
632                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
633                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
634                         if ( log_changes ) op->o_callback = &cb;
635                         if ( (*op->o_bd->be_add)( op, &rs ) == 0 ) {
636                                 be_entry_release_w( op, *e );
637                                 *e = NULL;
638                         }
639                 } else {
640                         rs.sr_err = LDAP_REFERRAL;
641                 }
642         } else {
643                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
644         }
645
646 cleanup:
647         if ( pPB != NULL ) {
648                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
649         }
650
651         return( pPB );
652 }
653 #endif /* LDAP_SLAPI */
654
655 Slapi_PBlock * 
656 slapi_add_entry_internal(
657         Slapi_Entry *e, 
658         LDAPControl **controls, 
659         int log_changes ) 
660 {
661 #ifdef LDAP_SLAPI
662         Slapi_PBlock            *pb = NULL;
663         Slapi_Entry             *entry = NULL;
664         Connection              *pConn = NULL;
665
666         pConn = slapi_int_init_connection( NULL, LDAP_REQ_ADD );
667         if ( pConn == NULL ) {
668                 return NULL;
669         }
670
671         /*
672          * We make a copy to avoid an entry that may be freed later
673          * by the caller being placed in the cache.
674          */
675         entry = slapi_entry_dup( e );
676         pb = slapi_int_add_entry_locked( pConn, &entry, controls, log_changes );
677         if ( entry != NULL ) {
678                 slapi_entry_free( entry );
679         }
680
681         slapi_int_connection_destroy( &pConn );
682
683         return pb;
684 #else
685         return NULL;
686 #endif
687 }
688
689 Slapi_PBlock *
690 slapi_add_internal(
691         char *dn, 
692         LDAPMod **mods, 
693         LDAPControl **controls, 
694         int log_changes  ) 
695 {
696 #ifdef LDAP_SLAPI
697         LDAPMod                 *pMod = NULL;
698         Connection              *pConn = NULL;
699         Slapi_PBlock            *pb = NULL;
700         Entry                   *pEntry = NULL;
701         int                     i, rc = LDAP_SUCCESS;
702
703         if ( mods == NULL || *mods == NULL || dn == NULL || *dn == '\0' ) {
704                 rc = LDAP_PARAM_ERROR ;
705         }
706
707         if ( rc == LDAP_SUCCESS ) {
708                 for ( i = 0, pMod = mods[0]; pMod != NULL; pMod = mods[++i] ) {
709                         if ( (pMod->mod_op & LDAP_MOD_OP ) != LDAP_MOD_ADD ) {
710                                 rc = LDAP_OTHER;
711                                 break;
712                         }
713                 }
714         }
715
716         if ( rc == LDAP_SUCCESS ) {
717                 pConn = slapi_int_init_connection( NULL, LDAP_REQ_ADD );
718                 if ( pConn != NULL ) {
719                         pEntry = slapi_int_ldapmod_to_entry( pConn, dn, mods );
720                         if ( pEntry == NULL ) {
721                                 rc = LDAP_OTHER;
722                         }
723                 }
724         }
725
726         if ( rc != LDAP_SUCCESS ) {
727                 pb = slapi_pblock_new();
728                 slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rc );
729         } else {
730                 pb = slapi_int_add_entry_locked( pConn, &pEntry, controls, log_changes );
731         }
732
733         if ( pEntry != NULL ) {
734                 slapi_entry_free( pEntry );
735         }
736
737         slapi_int_connection_destroy( &pConn );
738
739         return pb;
740 #else
741         return NULL;
742 #endif /* LDAP_SLAPI */
743 }
744
745 /* Function : slapi_modrdn_internal
746  *
747  * Description : Plugin functions call this routine to modify the rdn 
748  *                               of an entry in the backend directly
749  * Return values : LDAP_SUCCESS
750  *                 LDAP_PARAM_ERROR
751  *                 LDAP_NO_MEMORY
752  *                 LDAP_OTHER
753  *                 LDAP_UNWILLING_TO_PERFORM
754  *
755  * NOTE: This function does not support the "newSuperior" option from LDAP V3.
756  */
757 Slapi_PBlock *
758 slapi_modrdn_internal(
759         char *olddn, 
760         char *lnewrdn, 
761         int deloldrdn, 
762         LDAPControl **controls, 
763         int log_change )
764 {
765 #ifdef LDAP_SLAPI
766         struct berval           dn = BER_BVNULL;
767         struct berval           newrdn = BER_BVNULL;
768         Connection              *pConn = NULL;
769         Operation               *op = NULL;
770         Slapi_PBlock            *pPB = NULL;
771         int                     manageDsaIt = SLAP_CONTROL_NONE;
772         int                     isCritical;
773         SlapReply               rs = { REP_RESULT };
774
775         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODRDN );
776         if ( pConn == NULL) {
777                 rs.sr_err = LDAP_NO_MEMORY;
778                 goto cleanup;
779         }
780
781         op = (Operation *)pConn->c_pending_ops.stqh_first;
782         pPB = (Slapi_PBlock *)op->o_pb;
783         op->o_ctrls = controls;
784
785         if ( slapi_control_present( controls, 
786                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
787                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
788         }
789
790         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
791         if ( op->o_bd == NULL ) {
792                 rs.sr_err =  LDAP_PARTIAL_RESULTS;
793                 goto cleanup;
794         }
795
796         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
797         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
798
799         dn.bv_val = slapi_ch_strdup( olddn );
800         dn.bv_len = strlen( olddn );
801
802         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
803         if ( rs.sr_err != LDAP_SUCCESS ) {
804                 goto cleanup;
805         }
806
807         if ( op->o_req_dn.bv_len == 0 ) {
808                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
809                 goto cleanup;
810         }
811
812         newrdn.bv_val = slapi_ch_strdup( lnewrdn );
813         newrdn.bv_len = strlen( lnewrdn );
814
815         rs.sr_err = dnPrettyNormal( NULL, &newrdn, &op->oq_modrdn.rs_newrdn, &op->oq_modrdn.rs_nnewrdn, NULL );
816         if ( rs.sr_err != LDAP_SUCCESS ) {
817                 goto cleanup;
818         }
819
820         if ( rdn_validate( &op->oq_modrdn.rs_nnewrdn ) != LDAP_SUCCESS ) {
821                 goto cleanup;
822         }
823
824         op->oq_modrdn.rs_newSup = NULL;
825         op->oq_modrdn.rs_nnewSup = NULL;
826         op->oq_modrdn.rs_deleteoldrdn = deloldrdn;
827
828         if ( op->o_bd->be_modrdn ) {
829                 int repl_user = be_isupdate( op );
830                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
831                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
832                         if ( log_change ) op->o_callback = &cb;
833                         if ( (*op->o_bd->be_modrdn)( op, &rs ) ) {
834                                 rs.sr_err = LDAP_OTHER;
835                         }
836                 } else {
837                         rs.sr_err = LDAP_REFERRAL;
838                 }
839         } else {
840                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
841         }
842
843 cleanup:
844
845         if ( pPB != NULL ) {
846                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
847         }
848         
849         if ( dn.bv_val )
850                 slapi_ch_free( (void **)&dn.bv_val );
851
852         if ( newrdn.bv_val )
853                 slapi_ch_free( (void **)&newrdn.bv_val );
854         if ( op->oq_modrdn.rs_newrdn.bv_val )
855                 slapi_ch_free( (void **)&op->oq_modrdn.rs_newrdn.bv_val );
856         if ( op->oq_modrdn.rs_nnewrdn.bv_val )
857                 slapi_ch_free( (void **)&op->oq_modrdn.rs_nnewrdn.bv_val );
858
859         slapi_int_connection_destroy( &pConn );
860
861         return pPB;
862 #else
863         return NULL;
864 #endif /* LDAP_SLAPI */
865 }
866
867 /* Function : slapi_modify_internal
868  *
869  * Description: Plugin functions call this routine to modify an entry 
870  *                              in the backend directly
871  * Return values : LDAP_SUCCESS
872  *                 LDAP_PARAM_ERROR
873  *                 LDAP_NO_MEMORY
874  *                 LDAP_OTHER
875  *                 LDAP_UNWILLING_TO_PERFORM
876 */
877 Slapi_PBlock *
878 slapi_modify_internal(
879         char *ldn,      
880         LDAPMod **mods, 
881         LDAPControl **controls, 
882         int log_change )
883 {
884 #ifdef LDAP_SLAPI
885         int                     i;
886         Connection              *pConn = NULL;
887         Operation               *op = NULL;
888         Slapi_PBlock            *pPB = NULL;
889
890         struct berval dn = BER_BVNULL;
891
892         int                     manageDsaIt = SLAP_CONTROL_NONE;
893         int                     isCritical;
894         struct berval           *bv;
895         LDAPMod                 *pMod;
896
897         Modifications           *modlist = NULL;
898         Modifications           **modtail = &modlist;
899         Modifications           tmp;
900
901         SlapReply               rs = { REP_RESULT };
902
903         if ( mods == NULL || *mods == NULL || ldn == NULL ) {
904                 rs.sr_err = LDAP_PARAM_ERROR ;
905                 goto cleanup;
906         }
907
908         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODIFY );
909         if ( pConn == NULL ) {
910                 rs.sr_err = LDAP_NO_MEMORY;
911                 goto cleanup;
912         }
913
914         op = (Operation *)pConn->c_pending_ops.stqh_first;
915         pPB = (Slapi_PBlock *)op->o_pb;
916         op->o_ctrls = controls;
917
918         dn.bv_val = slapi_ch_strdup( ldn );
919         dn.bv_len = strlen( ldn );
920         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
921         if ( rs.sr_err != LDAP_SUCCESS ) {
922                 goto cleanup;
923         }
924
925         if ( slapi_control_present( controls, 
926                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
927                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
928         }
929
930         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
931         if ( op->o_bd == NULL ) {
932                 rs.sr_err = LDAP_PARTIAL_RESULTS;
933                 goto cleanup;
934         }
935
936         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
937         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
938
939         for ( i = 0, pMod = mods[0];
940                 rs.sr_err == LDAP_SUCCESS && pMod != NULL; 
941                 pMod = mods[++i] )
942         {
943                 Modifications *mod;
944
945                 if ( (pMod->mod_op & LDAP_MOD_BVALUES) != 0 ) {
946                         /*
947                          * attr values are in berval format
948                          * convert an array of pointers to bervals
949                          * to an array of bervals
950                          */
951                         rs.sr_err = bvptr2obj_copy( pMod->mod_bvalues, &bv );
952                         if ( rs.sr_err != LDAP_SUCCESS )
953                                 goto cleanup;
954                         tmp.sml_type.bv_val = pMod->mod_type;
955                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
956                         tmp.sml_values = bv;
957                         tmp.sml_nvalues = NULL;
958
959                         mod  = (Modifications *)ch_malloc( sizeof(Modifications) );
960
961                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
962                         mod->sml_next = NULL;
963                         mod->sml_desc = NULL;
964                         mod->sml_type = tmp.sml_type;
965                         mod->sml_values = tmp.sml_values;
966                         mod->sml_nvalues = tmp.sml_nvalues;
967                 } else { 
968                         rs.sr_err = values2obj_copy( pMod->mod_values, &bv );
969                         if ( rs.sr_err != LDAP_SUCCESS )
970                                 goto cleanup;
971                         tmp.sml_type.bv_val = pMod->mod_type;
972                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
973                         tmp.sml_values = bv;
974                         tmp.sml_nvalues = NULL;
975
976                         mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
977
978                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
979                         mod->sml_next = NULL;
980                         mod->sml_desc = NULL;
981                         mod->sml_type = tmp.sml_type;
982                         mod->sml_values = tmp.sml_values;
983                         mod->sml_nvalues = tmp.sml_nvalues;
984                 }
985                 *modtail = mod;
986                 modtail = &mod->sml_next;
987
988                 switch( pMod->mod_op & LDAP_MOD_OP ) {
989                 case LDAP_MOD_ADD:
990                 if ( mod->sml_values == NULL ) {
991                         rs.sr_err = LDAP_PROTOCOL_ERROR;
992                         goto cleanup;
993                 }
994
995                 /* fall through */
996                 case LDAP_MOD_DELETE:
997                 case LDAP_MOD_REPLACE:
998                 break;
999
1000                 default:
1001                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1002                         goto cleanup;
1003                 }
1004         } 
1005         *modtail = NULL;
1006
1007         if ( op->o_req_ndn.bv_len == 0 ) {
1008                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1009                 goto cleanup;
1010         }
1011
1012         op->oq_modify.rs_modlist = modlist;
1013
1014         if ( op->o_bd->be_modify ) {
1015                 int repl_user = be_isupdate( op );
1016                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
1017                         int update = op->o_bd->be_update_ndn.bv_len;
1018                         const char *text = NULL;
1019                         char textbuf[SLAP_TEXT_BUFLEN];
1020                         size_t textlen = sizeof( textbuf );
1021                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
1022
1023                         rs.sr_err = slap_mods_check( modlist, update,
1024                                         &text, textbuf, textlen, NULL );
1025                         if ( rs.sr_err != LDAP_SUCCESS ) {
1026                                 goto cleanup;
1027                         }
1028
1029                         if ( !repl_user ) {
1030                                 rs.sr_err = slap_mods_opattrs( op, modlist,
1031                                                 modtail, &text, textbuf, 
1032                                                 textlen, 1 );
1033                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1034                                         goto cleanup;
1035                                 }
1036                         }
1037                         if ( log_change ) op->o_callback = &cb;
1038                         if ( (*op->o_bd->be_modify)( op, &rs ) ) {
1039                                 rs.sr_err = LDAP_OTHER;
1040                         }
1041                 } else {
1042                         rs.sr_err = LDAP_REFERRAL;
1043                 }
1044         } else {
1045                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1046         }
1047
1048 cleanup:
1049
1050         if ( pPB != NULL ) 
1051                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1052
1053         if ( dn.bv_val )
1054                 slapi_ch_free( (void **)&dn.bv_val );
1055
1056         if ( modlist != NULL )
1057                 slap_mods_free( modlist );
1058
1059         slapi_int_connection_destroy( &pConn );
1060
1061         return pPB;
1062 #else
1063         return NULL;
1064 #endif /* LDAP_SLAPI */
1065 }
1066
1067 Slapi_PBlock *
1068 slapi_search_internal(
1069         char *ldn, 
1070         int scope, 
1071         char *filStr, 
1072         LDAPControl **controls, 
1073         char **attrs, 
1074         int attrsonly ) 
1075 {       
1076 #ifdef LDAP_SLAPI
1077         Connection              *c;
1078         Operation               *op = NULL;
1079         Slapi_PBlock            *pPB = NULL;            
1080         struct berval           dn = BER_BVNULL;
1081         Filter                  *filter=NULL;
1082         struct berval           fstr = BER_BVNULL;
1083         AttributeName           *an = NULL;
1084         const char              *text = NULL;
1085
1086         int                     manageDsaIt = SLAP_CONTROL_NONE; 
1087         int                     isCritical;
1088         int                     i;
1089
1090         SlapReply               rs = { REP_RESULT };
1091
1092         c = slapi_int_init_connection( NULL, LDAP_REQ_SEARCH );
1093         if ( c == NULL ) {
1094                 rs.sr_err = LDAP_NO_MEMORY;
1095                 goto cleanup;
1096         }
1097
1098         op = (Operation *)c->c_pending_ops.stqh_first;
1099         pPB = (Slapi_PBlock *)op->o_pb;
1100         op->o_ctrls = controls;
1101
1102         if ( ldn != NULL ) {
1103                 dn.bv_val = slapi_ch_strdup(ldn);
1104                 dn.bv_len = strlen(ldn);
1105         }
1106
1107         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
1108         if ( rs.sr_err != LDAP_SUCCESS ) {
1109                 goto cleanup;
1110         }
1111
1112         if ( scope != LDAP_SCOPE_BASE && 
1113                         scope != LDAP_SCOPE_ONELEVEL && 
1114                         scope != LDAP_SCOPE_SUBTREE ) {
1115                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1116                 goto cleanup;
1117         }
1118
1119         filter = slapi_str2filter(filStr);
1120         if ( filter == NULL ) {
1121                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1122                 goto cleanup;
1123         }
1124
1125         filter2bv( filter, &fstr );
1126
1127         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
1128                 ; /* count the number of attributes */
1129         }
1130
1131         if (i > 0) {
1132                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
1133                 for (i = 0; attrs[i] != 0; i++) {
1134                         an[i].an_desc = NULL;
1135                         an[i].an_oc = NULL;
1136                         an[i].an_oc_exclude = 0;
1137                         an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
1138                         an[i].an_name.bv_len = strlen(attrs[i]);
1139                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
1140                 }
1141                 an[i].an_name.bv_val = NULL;
1142         }
1143
1144         memset( &rs, 0, sizeof(rs) );
1145         rs.sr_type = REP_RESULT;
1146         rs.sr_err = LDAP_SUCCESS;
1147         rs.sr_entry = NULL; /* paranoia */
1148
1149         if ( scope == LDAP_SCOPE_BASE ) {
1150                 rs.sr_entry = NULL;
1151
1152                 if ( op->o_req_ndn.bv_len == 0 ) {
1153                         rs.sr_err = root_dse_info( c, &rs.sr_entry, &rs.sr_text );
1154                 }
1155
1156                 if( rs.sr_err != LDAP_SUCCESS ) {
1157                         send_ldap_result( op, &rs );
1158                         goto cleanup;
1159                 } else if ( rs.sr_entry != NULL ) {
1160                         rs.sr_err = test_filter( op, rs.sr_entry, filter );
1161
1162                         if ( rs.sr_err == LDAP_COMPARE_TRUE ) {
1163                                 rs.sr_type = REP_SEARCH;
1164                                 rs.sr_err = LDAP_SUCCESS;
1165                                 rs.sr_attrs = an;
1166                                 rs.sr_operational_attrs = NULL;
1167                                 rs.sr_flags = REP_ENTRY_MODIFIABLE;
1168
1169                                 send_search_entry( op, &rs );
1170                         }
1171
1172                         entry_free( rs.sr_entry );
1173
1174                         rs.sr_type = REP_RESULT;
1175                         rs.sr_err = LDAP_SUCCESS;
1176
1177                         send_ldap_result( op, &rs );
1178
1179                         goto cleanup;
1180                 }
1181         }
1182
1183         if ( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
1184                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
1185                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
1186
1187                 ber_dupbv( &op->o_req_dn, &default_search_base );
1188                 ber_dupbv( &op->o_req_ndn, &default_search_nbase );
1189         }
1190
1191         if ( slapi_control_present( controls,
1192                         LDAP_CONTROL_MANAGEDSAIT, NULL, &isCritical ) ) {
1193                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
1194         }
1195
1196         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
1197         if ( op->o_bd == NULL ) {
1198                 if ( manageDsaIt > SLAP_CONTROL_NONE  ) {
1199                         rs.sr_err = LDAP_NO_SUCH_OBJECT;
1200                 } else {
1201                         rs.sr_err = LDAP_PARTIAL_RESULTS;
1202                 }
1203                 goto cleanup;
1204         } 
1205
1206         op->o_dn = c->c_dn = op->o_bd->be_rootdn;
1207         op->o_ndn = c->c_ndn = op->o_bd->be_rootndn;
1208
1209         op->oq_search.rs_scope = scope;
1210         op->oq_search.rs_deref = 0;
1211         op->oq_search.rs_slimit = SLAP_NO_LIMIT;
1212         op->oq_search.rs_tlimit = SLAP_NO_LIMIT;
1213         op->oq_search.rs_attrsonly = attrsonly;
1214         op->oq_search.rs_attrs = an;
1215         op->oq_search.rs_filter = filter;
1216         op->oq_search.rs_filterstr = fstr;
1217
1218         if ( op->o_bd->be_search ) {
1219                 if ( (*op->o_bd->be_search)( op, &rs ) != 0 ) {
1220                         rs.sr_err = LDAP_OTHER;
1221                 }
1222         } else {
1223                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1224         }
1225
1226 cleanup:
1227
1228         if ( pPB != NULL )
1229                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1230
1231         if ( dn.bv_val )
1232                 slapi_ch_free( (void **)&dn.bv_val );
1233         if ( filter )
1234                 slapi_filter_free( filter, 1 );
1235         if ( fstr.bv_val )
1236                 slapi_ch_free( (void **)&fstr.bv_val );
1237         if ( an != NULL )
1238                 slapi_ch_free( (void **)&an );
1239
1240         slapi_int_connection_destroy( &c );
1241
1242         return pPB;
1243 #else
1244         return NULL;
1245 #endif /* LDAP_SLAPI */
1246 }
1247