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