]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Support LDAP_MOD_INCREMENT in slapi_modify_internal()
[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                 case LDAP_MOD_INCREMENT:
1007                 break;
1008
1009                 default:
1010                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1011                         goto cleanup;
1012                 }
1013         } 
1014         *modtail = NULL;
1015
1016         if ( op->o_req_ndn.bv_len == 0 ) {
1017                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1018                 goto cleanup;
1019         }
1020
1021         op->oq_modify.rs_modlist = modlist;
1022
1023         if ( op->o_bd->be_modify ) {
1024                 int repl_user = be_isupdate( op );
1025                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
1026                         int             update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn );
1027                         const char      *text = NULL;
1028                         char            textbuf[ SLAP_TEXT_BUFLEN ];
1029                         size_t          textlen = sizeof( textbuf );
1030                         slap_callback   cb = { NULL, slap_replog_cb, NULL, NULL };
1031
1032                         rs.sr_err = slap_mods_check( modlist,
1033                                         &text, textbuf, textlen, NULL );
1034                         if ( rs.sr_err != LDAP_SUCCESS ) {
1035                                 goto cleanup;
1036                         }
1037
1038                         if ( !update ) {
1039                                 rs.sr_err = slap_mods_no_update_check( modlist,
1040                                                 &text, textbuf, textlen );
1041                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1042                                         goto cleanup;
1043                                 }
1044                         }
1045
1046                         if ( !repl_user ) {
1047                                 rs.sr_err = slap_mods_opattrs( op, modlist,
1048                                                 modtail, &text, textbuf, 
1049                                                 textlen, 1 );
1050                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1051                                         goto cleanup;
1052                                 }
1053                         }
1054                         if ( log_change ) op->o_callback = &cb;
1055                         if ( (*op->o_bd->be_modify)( op, &rs ) ) {
1056                                 rs.sr_err = LDAP_OTHER;
1057                         }
1058                 } else {
1059                         rs.sr_err = LDAP_REFERRAL;
1060                 }
1061         } else {
1062                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1063         }
1064
1065 cleanup:
1066
1067         if ( pPB != NULL ) 
1068                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1069
1070         if ( dn.bv_val )
1071                 slapi_ch_free( (void **)&dn.bv_val );
1072
1073         if ( modlist != NULL )
1074                 slap_mods_free( modlist );
1075
1076         slapi_int_connection_destroy( &pConn );
1077
1078         return pPB;
1079 #else
1080         return NULL;
1081 #endif /* LDAP_SLAPI */
1082 }
1083
1084 Slapi_PBlock *
1085 slapi_search_internal(
1086         char *ldn, 
1087         int scope, 
1088         char *filStr, 
1089         LDAPControl **controls, 
1090         char **attrs, 
1091         int attrsonly ) 
1092 {       
1093 #ifdef LDAP_SLAPI
1094         Connection              *c;
1095         Operation               *op = NULL;
1096         Slapi_PBlock            *pPB = NULL;            
1097         struct berval           dn = BER_BVNULL;
1098         Filter                  *filter=NULL;
1099         struct berval           fstr = BER_BVNULL;
1100         AttributeName           *an = NULL;
1101         const char              *text = NULL;
1102
1103         int                     manageDsaIt = SLAP_CONTROL_NONE; 
1104         int                     isCritical;
1105         int                     i;
1106
1107         SlapReply               rs = { REP_RESULT };
1108
1109         c = slapi_int_init_connection( NULL, LDAP_REQ_SEARCH );
1110         if ( c == NULL ) {
1111                 rs.sr_err = LDAP_NO_MEMORY;
1112                 goto cleanup;
1113         }
1114
1115         op = (Operation *)c->c_pending_ops.stqh_first;
1116         pPB = (Slapi_PBlock *)op->o_pb;
1117         op->o_ctrls = controls;
1118
1119         if ( ldn != NULL ) {
1120                 dn.bv_val = slapi_ch_strdup(ldn);
1121                 dn.bv_len = strlen(ldn);
1122         }
1123
1124         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
1125         if ( rs.sr_err != LDAP_SUCCESS ) {
1126                 goto cleanup;
1127         }
1128
1129         if ( scope != LDAP_SCOPE_BASE && 
1130                         scope != LDAP_SCOPE_ONELEVEL && 
1131                         scope != LDAP_SCOPE_SUBTREE ) {
1132                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1133                 goto cleanup;
1134         }
1135
1136         filter = slapi_str2filter(filStr);
1137         if ( filter == NULL ) {
1138                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1139                 goto cleanup;
1140         }
1141
1142         filter2bv( filter, &fstr );
1143
1144         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
1145                 ; /* count the number of attributes */
1146         }
1147
1148         if (i > 0) {
1149                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
1150                 for (i = 0; attrs[i] != 0; i++) {
1151                         an[i].an_desc = NULL;
1152                         an[i].an_oc = NULL;
1153                         an[i].an_oc_exclude = 0;
1154                         an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
1155                         an[i].an_name.bv_len = strlen(attrs[i]);
1156                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
1157                 }
1158                 an[i].an_name.bv_val = NULL;
1159         }
1160
1161         memset( &rs, 0, sizeof(rs) );
1162         rs.sr_type = REP_RESULT;
1163         rs.sr_err = LDAP_SUCCESS;
1164         rs.sr_entry = NULL; /* paranoia */
1165
1166         if ( scope == LDAP_SCOPE_BASE ) {
1167                 rs.sr_entry = NULL;
1168
1169                 if ( op->o_req_ndn.bv_len == 0 ) {
1170                         rs.sr_err = root_dse_info( c, &rs.sr_entry, &rs.sr_text );
1171                 }
1172
1173                 if( rs.sr_err != LDAP_SUCCESS ) {
1174                         send_ldap_result( op, &rs );
1175                         goto cleanup;
1176                 } else if ( rs.sr_entry != NULL ) {
1177                         rs.sr_err = test_filter( op, rs.sr_entry, filter );
1178
1179                         if ( rs.sr_err == LDAP_COMPARE_TRUE ) {
1180                                 rs.sr_type = REP_SEARCH;
1181                                 rs.sr_err = LDAP_SUCCESS;
1182                                 rs.sr_attrs = an;
1183                                 rs.sr_operational_attrs = NULL;
1184                                 rs.sr_flags = REP_ENTRY_MODIFIABLE;
1185
1186                                 send_search_entry( op, &rs );
1187                         }
1188
1189                         entry_free( rs.sr_entry );
1190
1191                         rs.sr_type = REP_RESULT;
1192                         rs.sr_err = LDAP_SUCCESS;
1193
1194                         send_ldap_result( op, &rs );
1195
1196                         goto cleanup;
1197                 }
1198         }
1199
1200         if ( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
1201                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
1202                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
1203
1204                 ber_dupbv( &op->o_req_dn, &default_search_base );
1205                 ber_dupbv( &op->o_req_ndn, &default_search_nbase );
1206         }
1207
1208         if ( slapi_control_present( controls,
1209                         LDAP_CONTROL_MANAGEDSAIT, NULL, &isCritical ) ) {
1210                 manageDsaIt = isCritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
1211         }
1212
1213         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 1 );
1214         if ( op->o_bd == NULL ) {
1215                 if ( manageDsaIt > SLAP_CONTROL_NONE  ) {
1216                         rs.sr_err = LDAP_NO_SUCH_OBJECT;
1217                 } else {
1218                         rs.sr_err = LDAP_PARTIAL_RESULTS;
1219                 }
1220                 goto cleanup;
1221         } 
1222
1223         op->o_dn = c->c_dn = op->o_bd->be_rootdn;
1224         op->o_ndn = c->c_ndn = op->o_bd->be_rootndn;
1225
1226         op->oq_search.rs_scope = scope;
1227         op->oq_search.rs_deref = 0;
1228         op->oq_search.rs_slimit = SLAP_NO_LIMIT;
1229         op->oq_search.rs_tlimit = SLAP_NO_LIMIT;
1230         op->oq_search.rs_attrsonly = attrsonly;
1231         op->oq_search.rs_attrs = an;
1232         op->oq_search.rs_filter = filter;
1233         op->oq_search.rs_filterstr = fstr;
1234
1235         if ( op->o_bd->be_search ) {
1236                 if ( (*op->o_bd->be_search)( op, &rs ) != 0 ) {
1237                         rs.sr_err = LDAP_OTHER;
1238                 }
1239         } else {
1240                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1241         }
1242
1243 cleanup:
1244
1245         if ( pPB != NULL )
1246                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1247
1248         if ( dn.bv_val )
1249                 slapi_ch_free( (void **)&dn.bv_val );
1250         if ( filter )
1251                 slapi_filter_free( filter, 1 );
1252         if ( fstr.bv_val )
1253                 slapi_ch_free( (void **)&fstr.bv_val );
1254         if ( an != NULL )
1255                 slapi_ch_free( (void **)&an );
1256
1257         slapi_int_connection_destroy( &c );
1258
1259         return pPB;
1260 #else
1261         return NULL;
1262 #endif /* LDAP_SLAPI */
1263 }
1264