]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Merge in recent changes to HEAD
[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 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 = !BER_BVISNULL( &op->o_bd->be_update_ndn );
454                         char    textbuf[ SLAP_TEXT_BUFLEN ];
455                         size_t  textlen = sizeof( textbuf );
456
457                         rc = slap_mods_check( modlist, &text, 
458                                 textbuf, textlen, NULL );
459                         if ( rc != LDAP_SUCCESS) {
460                                 goto cleanup;
461                         }
462
463                         if ( !update ) {
464                                 rc = slap_mods_no_user_mod_check( op, modlist,
465                                         &text, textbuf, textlen );
466                                 if ( rc != LDAP_SUCCESS) {
467                                         goto cleanup;
468                                 }
469                         }
470
471                         if ( !repl_user ) {
472                                 rc = slap_mods_opattrs( op, modlist, modtail,
473                                         &text, textbuf, textlen, 1 );
474                                 if ( rc != LDAP_SUCCESS) {
475                                         goto cleanup;
476                                 }
477                         }
478
479                         rc = slap_mods2entry( modlist, &pEntry, repl_user,
480                                               0, &text, textbuf, textlen );
481                         if (rc != LDAP_SUCCESS) {
482                                 goto cleanup;
483                         }
484
485                 } else {
486                         rc = LDAP_REFERRAL;
487                 }
488         }
489
490 cleanup:;
491         if ( dn.bv_val )
492                 slapi_ch_free( (void **)&dn.bv_val );
493         if ( modlist != NULL )
494                 slap_mods_free( modlist );
495         if ( rc != LDAP_SUCCESS ) {
496                 if ( pEntry != NULL ) {
497                         slapi_entry_free( pEntry );
498                 }
499                 pEntry = NULL;
500         }
501
502         return( pEntry );
503 }
504
505 /* Function : slapi_delete_internal
506  *
507  * Description : Plugin functions call this routine to delete an entry 
508  *               in the backend directly
509  * Return values : LDAP_SUCCESS
510  *                 LDAP_PARAM_ERROR
511  *                 LDAP_NO_MEMORY
512  *                 LDAP_OTHER
513  *                 LDAP_UNWILLING_TO_PERFORM
514 */
515 Slapi_PBlock *
516 slapi_delete_internal(
517         char *ldn, 
518         LDAPControl **controls, 
519         int log_change )
520 {
521 #ifdef LDAP_SLAPI
522         Connection              *pConn = NULL;
523         Operation               *op = NULL;
524         Slapi_PBlock            *pPB = NULL;
525         SlapReply               rs = { REP_RESULT };
526         struct berval           dn = BER_BVNULL;
527
528         int                     manageDsaIt = SLAP_CONTROL_NONE;
529         int                     isCritical;
530
531         if ( ldn == NULL ) {
532                 rs.sr_err = LDAP_PARAM_ERROR; 
533                 goto cleanup;
534         }
535
536         pConn = slapi_int_init_connection( NULL, LDAP_REQ_DELETE );
537         if (pConn == NULL) {
538                 rs.sr_err = LDAP_NO_MEMORY;
539                 goto cleanup;
540         }
541
542         op = (Operation *)pConn->c_pending_ops.stqh_first;
543         pPB = (Slapi_PBlock *)op->o_pb;
544         op->o_ctrls = controls;
545
546         dn.bv_val = slapi_ch_strdup(ldn);
547         dn.bv_len = strlen(ldn);
548         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
549         if ( rs.sr_err != LDAP_SUCCESS )
550                 goto cleanup;
551
552         if ( slapi_control_present( controls, 
553                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical) ) {
554                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 
555         }
556
557         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
558         if ( op->o_bd == NULL ) {
559                 rs.sr_err = LDAP_PARTIAL_RESULTS;
560                 goto cleanup;
561         }
562
563         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
564         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
565
566         if ( op->o_bd->be_delete ) {
567                 int repl_user = be_isupdate( op );
568                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
569                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
570                         if ( log_change ) op->o_callback = &cb;
571                         if ( (*op->o_bd->be_delete)( op, &rs ) ) {
572                                 rs.sr_err = LDAP_OTHER;
573                         }
574                 } else {
575                         rs.sr_err = LDAP_REFERRAL;
576                 }
577         } else {
578                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
579         }
580
581 cleanup:
582         if ( pPB != NULL ) {
583                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
584         }
585         if ( dn.bv_val ) {
586                 slapi_ch_free( (void **)&dn.bv_val );
587         }
588
589         slapi_int_connection_destroy( &pConn );
590
591         return pPB;
592 #else
593         return NULL;
594 #endif /* LDAP_SLAPI */
595 }
596
597 #ifdef LDAP_SLAPI
598 static Slapi_PBlock * 
599 slapi_int_add_entry_locked(
600         Connection *pConn,
601         Slapi_Entry **e, 
602         LDAPControl **controls, 
603         int log_changes ) 
604 {
605         Operation               *op = NULL;
606         Slapi_PBlock            *pPB = NULL;
607
608         int                     manageDsaIt = SLAP_CONTROL_NONE;
609         int                     isCritical;
610         SlapReply               rs = { REP_RESULT };
611
612         if ( *e == NULL ) {
613                 rs.sr_err = LDAP_PARAM_ERROR;
614                 goto cleanup;
615         }
616
617         if ( slapi_control_present( controls, LDAP_CONTROL_MANAGEDSAIT,
618                                 NULL, &isCritical ) ) {
619                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL; 
620         }
621
622         op = (Operation *)pConn->c_pending_ops.stqh_first;
623         pPB = (Slapi_PBlock *)op->o_pb;
624         op->o_ctrls = controls;
625
626         op->o_bd = select_backend( &((*e)->e_nname), manageDsaIt, 1 );
627         if ( op->o_bd == NULL ) {
628                 rs.sr_err = LDAP_PARTIAL_RESULTS;
629                 goto cleanup;
630         }
631
632         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
633         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
634         op->oq_add.rs_e = *e;
635
636         if ( op->o_bd->be_add ) {
637                 int repl_user = be_isupdate( op );
638                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
639                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
640                         if ( log_changes ) op->o_callback = &cb;
641                         if ( (*op->o_bd->be_add)( op, &rs ) == 0 ) {
642                                 be_entry_release_w( op, *e );
643                                 *e = NULL;
644                         }
645                 } else {
646                         rs.sr_err = LDAP_REFERRAL;
647                 }
648         } else {
649                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
650         }
651
652 cleanup:
653         if ( pPB != NULL ) {
654                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
655         }
656
657         return( pPB );
658 }
659 #endif /* LDAP_SLAPI */
660
661 Slapi_PBlock * 
662 slapi_add_entry_internal(
663         Slapi_Entry *e, 
664         LDAPControl **controls, 
665         int log_changes ) 
666 {
667 #ifdef LDAP_SLAPI
668         Slapi_PBlock            *pb = NULL;
669         Slapi_Entry             *entry = NULL;
670         Connection              *pConn = NULL;
671
672         pConn = slapi_int_init_connection( NULL, LDAP_REQ_ADD );
673         if ( pConn == NULL ) {
674                 return NULL;
675         }
676
677         /*
678          * We make a copy to avoid an entry that may be freed later
679          * by the caller being placed in the cache.
680          */
681         entry = slapi_entry_dup( e );
682         pb = slapi_int_add_entry_locked( pConn, &entry, controls, log_changes );
683         if ( entry != NULL ) {
684                 slapi_entry_free( entry );
685         }
686
687         slapi_int_connection_destroy( &pConn );
688
689         return pb;
690 #else
691         return NULL;
692 #endif
693 }
694
695 Slapi_PBlock *
696 slapi_add_internal(
697         char *dn, 
698         LDAPMod **mods, 
699         LDAPControl **controls, 
700         int log_changes  ) 
701 {
702 #ifdef LDAP_SLAPI
703         LDAPMod                 *pMod = NULL;
704         Connection              *pConn = NULL;
705         Slapi_PBlock            *pb = NULL;
706         Entry                   *pEntry = NULL;
707         int                     i, rc = LDAP_SUCCESS;
708
709         if ( mods == NULL || *mods == NULL || dn == NULL || *dn == '\0' ) {
710                 rc = LDAP_PARAM_ERROR ;
711         }
712
713         if ( rc == LDAP_SUCCESS ) {
714                 for ( i = 0, pMod = mods[0]; pMod != NULL; pMod = mods[++i] ) {
715                         if ( (pMod->mod_op & LDAP_MOD_OP ) != LDAP_MOD_ADD ) {
716                                 rc = LDAP_OTHER;
717                                 break;
718                         }
719                 }
720         }
721
722         if ( rc == LDAP_SUCCESS ) {
723                 pConn = slapi_int_init_connection( NULL, LDAP_REQ_ADD );
724                 if ( pConn != NULL ) {
725                         pEntry = slapi_int_ldapmod_to_entry( pConn, dn, mods );
726                         if ( pEntry == NULL ) {
727                                 rc = LDAP_OTHER;
728                         }
729                 }
730         }
731
732         if ( rc != LDAP_SUCCESS ) {
733                 pb = slapi_pblock_new();
734                 slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rc );
735         } else {
736                 pb = slapi_int_add_entry_locked( pConn, &pEntry, controls, log_changes );
737         }
738
739         if ( pEntry != NULL ) {
740                 slapi_entry_free( pEntry );
741         }
742
743         slapi_int_connection_destroy( &pConn );
744
745         return pb;
746 #else
747         return NULL;
748 #endif /* LDAP_SLAPI */
749 }
750
751 /* Function : slapi_modrdn_internal
752  *
753  * Description : Plugin functions call this routine to modify the rdn 
754  *                               of an entry in the backend directly
755  * Return values : LDAP_SUCCESS
756  *                 LDAP_PARAM_ERROR
757  *                 LDAP_NO_MEMORY
758  *                 LDAP_OTHER
759  *                 LDAP_UNWILLING_TO_PERFORM
760  *
761  * NOTE: This function does not support the "newSuperior" option from LDAP V3.
762  */
763 Slapi_PBlock *
764 slapi_modrdn_internal(
765         char *olddn, 
766         char *lnewrdn, 
767         int deloldrdn, 
768         LDAPControl **controls, 
769         int log_change )
770 {
771 #ifdef LDAP_SLAPI
772         struct berval           dn = BER_BVNULL;
773         struct berval           newrdn = BER_BVNULL;
774         Connection              *pConn = NULL;
775         Operation               *op = NULL;
776         Slapi_PBlock            *pPB = NULL;
777         int                     manageDsaIt = SLAP_CONTROL_NONE;
778         int                     isCritical;
779         SlapReply               rs = { REP_RESULT };
780
781         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODRDN );
782         if ( pConn == NULL) {
783                 rs.sr_err = LDAP_NO_MEMORY;
784                 goto cleanup;
785         }
786
787         op = (Operation *)pConn->c_pending_ops.stqh_first;
788         pPB = (Slapi_PBlock *)op->o_pb;
789         op->o_ctrls = controls;
790
791         if ( slapi_control_present( controls, 
792                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
793                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
794         }
795
796         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
797         if ( op->o_bd == NULL ) {
798                 rs.sr_err =  LDAP_PARTIAL_RESULTS;
799                 goto cleanup;
800         }
801
802         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
803         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
804
805         dn.bv_val = slapi_ch_strdup( olddn );
806         dn.bv_len = strlen( olddn );
807
808         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
809         if ( rs.sr_err != LDAP_SUCCESS ) {
810                 goto cleanup;
811         }
812
813         if ( op->o_req_dn.bv_len == 0 ) {
814                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
815                 goto cleanup;
816         }
817
818         newrdn.bv_val = slapi_ch_strdup( lnewrdn );
819         newrdn.bv_len = strlen( lnewrdn );
820
821         rs.sr_err = dnPrettyNormal( NULL, &newrdn, &op->oq_modrdn.rs_newrdn, &op->oq_modrdn.rs_nnewrdn, NULL );
822         if ( rs.sr_err != LDAP_SUCCESS ) {
823                 goto cleanup;
824         }
825
826         if ( rdn_validate( &op->oq_modrdn.rs_nnewrdn ) != LDAP_SUCCESS ) {
827                 goto cleanup;
828         }
829
830         op->oq_modrdn.rs_newSup = NULL;
831         op->oq_modrdn.rs_nnewSup = NULL;
832         op->oq_modrdn.rs_deleteoldrdn = deloldrdn;
833
834         if ( op->o_bd->be_modrdn ) {
835                 int repl_user = be_isupdate( op );
836                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
837                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
838                         if ( log_change ) op->o_callback = &cb;
839                         if ( (*op->o_bd->be_modrdn)( op, &rs ) ) {
840                                 rs.sr_err = LDAP_OTHER;
841                         }
842                 } else {
843                         rs.sr_err = LDAP_REFERRAL;
844                 }
845         } else {
846                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
847         }
848
849 cleanup:
850
851         if ( pPB != NULL ) {
852                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
853         }
854         
855         if ( dn.bv_val )
856                 slapi_ch_free( (void **)&dn.bv_val );
857
858         if ( newrdn.bv_val )
859                 slapi_ch_free( (void **)&newrdn.bv_val );
860         if ( op->oq_modrdn.rs_newrdn.bv_val )
861                 slapi_ch_free( (void **)&op->oq_modrdn.rs_newrdn.bv_val );
862         if ( op->oq_modrdn.rs_nnewrdn.bv_val )
863                 slapi_ch_free( (void **)&op->oq_modrdn.rs_nnewrdn.bv_val );
864
865         slapi_int_connection_destroy( &pConn );
866
867         return pPB;
868 #else
869         return NULL;
870 #endif /* LDAP_SLAPI */
871 }
872
873 /* Function : slapi_modify_internal
874  *
875  * Description: Plugin functions call this routine to modify an entry 
876  *                              in the backend directly
877  * Return values : LDAP_SUCCESS
878  *                 LDAP_PARAM_ERROR
879  *                 LDAP_NO_MEMORY
880  *                 LDAP_OTHER
881  *                 LDAP_UNWILLING_TO_PERFORM
882 */
883 Slapi_PBlock *
884 slapi_modify_internal(
885         char *ldn,      
886         LDAPMod **mods, 
887         LDAPControl **controls, 
888         int log_change )
889 {
890 #ifdef LDAP_SLAPI
891         int                     i;
892         Connection              *pConn = NULL;
893         Operation               *op = NULL;
894         Slapi_PBlock            *pPB = NULL;
895
896         struct berval dn = BER_BVNULL;
897
898         int                     manageDsaIt = SLAP_CONTROL_NONE;
899         int                     isCritical;
900         struct berval           *bv;
901         LDAPMod                 *pMod;
902
903         Modifications           *modlist = NULL;
904         Modifications           **modtail = &modlist;
905         Modifications           tmp;
906
907         SlapReply               rs = { REP_RESULT };
908
909         if ( mods == NULL || *mods == NULL || ldn == NULL ) {
910                 rs.sr_err = LDAP_PARAM_ERROR ;
911                 goto cleanup;
912         }
913
914         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODIFY );
915         if ( pConn == NULL ) {
916                 rs.sr_err = LDAP_NO_MEMORY;
917                 goto cleanup;
918         }
919
920         op = (Operation *)pConn->c_pending_ops.stqh_first;
921         pPB = (Slapi_PBlock *)op->o_pb;
922         op->o_ctrls = controls;
923
924         dn.bv_val = slapi_ch_strdup( ldn );
925         dn.bv_len = strlen( ldn );
926         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
927         if ( rs.sr_err != LDAP_SUCCESS ) {
928                 goto cleanup;
929         }
930
931         if ( slapi_control_present( controls, 
932                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
933                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
934         }
935
936         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
937         if ( op->o_bd == NULL ) {
938                 rs.sr_err = LDAP_PARTIAL_RESULTS;
939                 goto cleanup;
940         }
941
942         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
943         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
944
945         for ( i = 0, pMod = mods[0];
946                 rs.sr_err == LDAP_SUCCESS && pMod != NULL; 
947                 pMod = mods[++i] )
948         {
949                 Modifications *mod;
950
951                 if ( (pMod->mod_op & LDAP_MOD_BVALUES) != 0 ) {
952                         /*
953                          * attr values are in berval format
954                          * convert an array of pointers to bervals
955                          * to an array of bervals
956                          */
957                         rs.sr_err = bvptr2obj_copy( pMod->mod_bvalues, &bv );
958                         if ( rs.sr_err != LDAP_SUCCESS )
959                                 goto cleanup;
960                         tmp.sml_type.bv_val = pMod->mod_type;
961                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
962                         tmp.sml_values = bv;
963                         tmp.sml_nvalues = NULL;
964
965                         mod  = (Modifications *)ch_malloc( sizeof(Modifications) );
966
967                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
968                         mod->sml_next = NULL;
969                         mod->sml_desc = NULL;
970                         mod->sml_type = tmp.sml_type;
971                         mod->sml_values = tmp.sml_values;
972                         mod->sml_nvalues = tmp.sml_nvalues;
973                 } else { 
974                         rs.sr_err = values2obj_copy( pMod->mod_values, &bv );
975                         if ( rs.sr_err != LDAP_SUCCESS )
976                                 goto cleanup;
977                         tmp.sml_type.bv_val = pMod->mod_type;
978                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
979                         tmp.sml_values = bv;
980                         tmp.sml_nvalues = NULL;
981
982                         mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
983
984                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
985                         mod->sml_next = NULL;
986                         mod->sml_desc = NULL;
987                         mod->sml_type = tmp.sml_type;
988                         mod->sml_values = tmp.sml_values;
989                         mod->sml_nvalues = tmp.sml_nvalues;
990                 }
991                 *modtail = mod;
992                 modtail = &mod->sml_next;
993
994                 switch( pMod->mod_op & LDAP_MOD_OP ) {
995                 case LDAP_MOD_ADD:
996                 if ( mod->sml_values == NULL ) {
997                         rs.sr_err = LDAP_PROTOCOL_ERROR;
998                         goto cleanup;
999                 }
1000
1001                 /* fall through */
1002                 case LDAP_MOD_DELETE:
1003                 case LDAP_MOD_REPLACE:
1004                 case LDAP_MOD_INCREMENT:
1005                 break;
1006
1007                 default:
1008                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1009                         goto cleanup;
1010                 }
1011         } 
1012         *modtail = NULL;
1013
1014         if ( op->o_req_ndn.bv_len == 0 ) {
1015                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1016                 goto cleanup;
1017         }
1018
1019         op->oq_modify.rs_modlist = modlist;
1020
1021         if ( op->o_bd->be_modify ) {
1022                 int repl_user = be_isupdate( op );
1023                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
1024                         int             update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
1025                         const char      *text = NULL;
1026                         char            textbuf[ SLAP_TEXT_BUFLEN ];
1027                         size_t          textlen = sizeof( textbuf );
1028                         slap_callback   cb = { NULL, slap_replog_cb, NULL, NULL };
1029
1030                         rs.sr_err = slap_mods_check( modlist,
1031                                 &text, textbuf, textlen, NULL );
1032                         if ( rs.sr_err != LDAP_SUCCESS ) {
1033                                 goto cleanup;
1034                         }
1035
1036                         if ( !update ) {
1037                                 rs.sr_err = slap_mods_no_user_mod_check( op, modlist,
1038                                         &text, textbuf, textlen );
1039                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1040                                         goto cleanup;
1041                                 }
1042                         }
1043
1044                         if ( !repl_user ) {
1045                                 rs.sr_err = slap_mods_opattrs( op, modlist,
1046                                                 modtail, &text, textbuf, 
1047                                                 textlen, 1 );
1048                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1049                                         goto cleanup;
1050                                 }
1051                         }
1052                         if ( log_change ) op->o_callback = &cb;
1053                         if ( (*op->o_bd->be_modify)( op, &rs ) ) {
1054                                 rs.sr_err = LDAP_OTHER;
1055                         }
1056                 } else {
1057                         rs.sr_err = LDAP_REFERRAL;
1058                 }
1059         } else {
1060                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1061         }
1062
1063 cleanup:
1064
1065         if ( pPB != NULL ) 
1066                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1067
1068         if ( dn.bv_val )
1069                 slapi_ch_free( (void **)&dn.bv_val );
1070
1071         if ( modlist != NULL )
1072                 slap_mods_free( modlist );
1073
1074         slapi_int_connection_destroy( &pConn );
1075
1076         return pPB;
1077 #else
1078         return NULL;
1079 #endif /* LDAP_SLAPI */
1080 }
1081
1082 Slapi_PBlock *
1083 slapi_search_internal(
1084         char *ldn, 
1085         int scope, 
1086         char *filStr, 
1087         LDAPControl **controls, 
1088         char **attrs, 
1089         int attrsonly ) 
1090 {       
1091 #ifdef LDAP_SLAPI
1092         Connection              *c;
1093         Operation               *op = NULL;
1094         Slapi_PBlock            *pPB = NULL;            
1095         struct berval           dn = BER_BVNULL;
1096         Filter                  *filter=NULL;
1097         struct berval           fstr = BER_BVNULL;
1098         AttributeName           *an = NULL;
1099         const char              *text = NULL;
1100
1101         int                     manageDsaIt = SLAP_CONTROL_NONE; 
1102         int                     isCritical;
1103         int                     i;
1104
1105         SlapReply               rs = { REP_RESULT };
1106
1107         c = slapi_int_init_connection( NULL, LDAP_REQ_SEARCH );
1108         if ( c == NULL ) {
1109                 rs.sr_err = LDAP_NO_MEMORY;
1110                 goto cleanup;
1111         }
1112
1113         op = (Operation *)c->c_pending_ops.stqh_first;
1114         pPB = (Slapi_PBlock *)op->o_pb;
1115         op->o_ctrls = controls;
1116
1117         if ( ldn != NULL ) {
1118                 dn.bv_val = slapi_ch_strdup(ldn);
1119                 dn.bv_len = strlen(ldn);
1120         }
1121
1122         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
1123         if ( rs.sr_err != LDAP_SUCCESS ) {
1124                 goto cleanup;
1125         }
1126
1127         if ( scope != LDAP_SCOPE_BASE && 
1128                         scope != LDAP_SCOPE_ONELEVEL && 
1129                         scope != LDAP_SCOPE_SUBTREE ) {
1130                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1131                 goto cleanup;
1132         }
1133
1134         filter = slapi_str2filter(filStr);
1135         if ( filter == NULL ) {
1136                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1137                 goto cleanup;
1138         }
1139
1140         filter2bv( filter, &fstr );
1141
1142         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
1143                 ; /* count the number of attributes */
1144         }
1145
1146         if (i > 0) {
1147                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
1148                 for (i = 0; attrs[i] != 0; i++) {
1149                         an[i].an_desc = NULL;
1150                         an[i].an_oc = NULL;
1151                         an[i].an_oc_exclude = 0;
1152                         an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
1153                         an[i].an_name.bv_len = strlen(attrs[i]);
1154                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
1155                 }
1156                 an[i].an_name.bv_val = NULL;
1157         }
1158
1159         memset( &rs, 0, sizeof(rs) );
1160         rs.sr_type = REP_RESULT;
1161         rs.sr_err = LDAP_SUCCESS;
1162         rs.sr_entry = NULL; /* paranoia */
1163
1164         if ( scope == LDAP_SCOPE_BASE ) {
1165                 rs.sr_entry = NULL;
1166
1167                 if ( op->o_req_ndn.bv_len == 0 ) {
1168                         rs.sr_err = root_dse_info( c, &rs.sr_entry, &rs.sr_text );
1169                 }
1170
1171                 if( rs.sr_err != LDAP_SUCCESS ) {
1172                         send_ldap_result( op, &rs );
1173                         goto cleanup;
1174                 } else if ( rs.sr_entry != NULL ) {
1175                         rs.sr_err = test_filter( op, rs.sr_entry, filter );
1176
1177                         if ( rs.sr_err == LDAP_COMPARE_TRUE ) {
1178                                 rs.sr_type = REP_SEARCH;
1179                                 rs.sr_err = LDAP_SUCCESS;
1180                                 rs.sr_attrs = an;
1181                                 rs.sr_operational_attrs = NULL;
1182                                 rs.sr_flags = REP_ENTRY_MODIFIABLE;
1183
1184                                 send_search_entry( op, &rs );
1185                         }
1186
1187                         entry_free( rs.sr_entry );
1188
1189                         rs.sr_type = REP_RESULT;
1190                         rs.sr_err = LDAP_SUCCESS;
1191
1192                         send_ldap_result( op, &rs );
1193
1194                         goto cleanup;
1195                 }
1196         }
1197
1198         if ( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
1199                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
1200                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
1201
1202                 ber_dupbv( &op->o_req_dn, &default_search_base );
1203                 ber_dupbv( &op->o_req_ndn, &default_search_nbase );
1204         }
1205
1206         if ( slapi_control_present( controls,
1207                         LDAP_CONTROL_MANAGEDSAIT, NULL, &isCritical ) ) {
1208                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
1209         }
1210
1211         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
1212         if ( op->o_bd == NULL ) {
1213                 if ( manageDsaIt > SLAP_CONTROL_NONE  ) {
1214                         rs.sr_err = LDAP_NO_SUCH_OBJECT;
1215                 } else {
1216                         rs.sr_err = LDAP_PARTIAL_RESULTS;
1217                 }
1218                 goto cleanup;
1219         } 
1220
1221         op->o_dn = c->c_dn = op->o_bd->be_rootdn;
1222         op->o_ndn = c->c_ndn = op->o_bd->be_rootndn;
1223
1224         op->oq_search.rs_scope = scope;
1225         op->oq_search.rs_deref = 0;
1226         op->oq_search.rs_slimit = SLAP_NO_LIMIT;
1227         op->oq_search.rs_tlimit = SLAP_NO_LIMIT;
1228         op->oq_search.rs_attrsonly = attrsonly;
1229         op->oq_search.rs_attrs = an;
1230         op->oq_search.rs_filter = filter;
1231         op->oq_search.rs_filterstr = fstr;
1232
1233         if ( op->o_bd->be_search ) {
1234                 if ( (*op->o_bd->be_search)( op, &rs ) != 0 ) {
1235                         rs.sr_err = LDAP_OTHER;
1236                 }
1237         } else {
1238                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1239         }
1240
1241 cleanup:
1242
1243         if ( pPB != NULL )
1244                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1245
1246         if ( dn.bv_val )
1247                 slapi_ch_free( (void **)&dn.bv_val );
1248         if ( filter )
1249                 slapi_filter_free( filter, 1 );
1250         if ( fstr.bv_val )
1251                 slapi_ch_free( (void **)&fstr.bv_val );
1252         if ( an != NULL )
1253                 slapi_ch_free( (void **)&an );
1254
1255         slapi_int_connection_destroy( &c );
1256
1257         return pPB;
1258 #else
1259         return NULL;
1260 #endif /* LDAP_SLAPI */
1261 }
1262