]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Modifications must be copied before calling slap_mods_check() because
[openldap] / servers / slapd / slapi / slapi_ops.c
1 /*
2  * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  */
5 /*
6  *  Copyright IBM Corp. 1997,2002
7  *  Use of this source code is subject to the terms of The OpenLDAP Public 
8  *  License (version 2.7 or later).
9  *  No trademarks of the IBM Corporation are to be used to identify, endorse 
10  *  or promote  any products derived from this code without the prior 
11  *  written consent of IBM 
12  */
13 /*
14  * Portions (C) Copyright PADL Software Pty Ltd. 2003
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that this notice is preserved
17  * and that due credit is given to PADL Software Pty Ltd. This software
18  * is provided ``as is'' without express or implied warranty.
19  */
20
21 #include "portable.h"
22
23 #include <ac/string.h>
24 #include <ac/stdarg.h>
25 #include <ac/ctype.h>
26 #include <ac/unistd.h>
27
28 #include <slap.h>
29 #include <lber_pvt.h>
30 #include <slapi.h>
31
32 /*
33  * use a fake listener when faking a connection,
34  * so it can be used in ACLs
35  */
36 static struct slap_listener slap_unknown_listener = {
37         BER_BVC("unknown"),     /* FIXME: use a URI form? (e.g. slapi://) */
38         BER_BVC("UNKNOWN")
39 };
40
41 static void
42 internal_result_v3(
43         Operation       *op, 
44         SlapReply       *rs )
45 {
46 #ifdef notdef
47         /* XXX needs review after internal API change */
48         /* rs->sr_nentries appears to always be 0 */
49         if (op->o_tag == LDAP_REQ_SEARCH)
50                 slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
51                         SLAPI_NENTRIES, (void *)rs->sr_nentries );
52 #endif
53
54         return;
55 }
56
57 static int
58 internal_search_entry(
59         Operation       *op,
60         SlapReply       *rs )
61 {
62         char *ent2str = NULL;
63         int nentries = 0, len = 0, i = 0;
64         Slapi_Entry **head = NULL, **tp;
65         
66         ent2str = slapi_entry2str( rs->sr_entry, &len );
67         if ( ent2str == NULL ) {
68                 return 1;
69         }
70
71         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
72                         SLAPI_NENTRIES, &nentries );
73         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
74                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &head );
75         
76         i = nentries + 1;
77         if ( nentries == 0 ) {
78                 tp = (Slapi_Entry **)slapi_ch_malloc( 2 * sizeof(Slapi_Entry *) );
79                 if ( tp == NULL ) {
80                         return 1;
81                 }
82
83                 tp[ 0 ] = (Slapi_Entry *)str2entry( ent2str );
84                 if ( tp[ 0 ] == NULL ) { 
85                         return 1;
86                 }
87
88         } else {
89                 tp = (Slapi_Entry **)slapi_ch_realloc( (char *)head,
90                                 sizeof(Slapi_Entry *) * ( i + 1 ) );
91                 if ( tp == NULL ) {
92                         return 1;
93                 }
94                 tp[ i - 1 ] = (Slapi_Entry *)str2entry( ent2str );
95                 if ( tp[ i - 1 ] == NULL ) { 
96                         return 1;
97                 }
98         }
99         tp[ i ] = NULL;
100                   
101         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
102                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, (void *)tp );
103         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
104                         SLAPI_NENTRIES, (void *)i );
105
106         return LDAP_SUCCESS;
107 }
108
109 static void
110 internal_result_ext(
111         Operation       *op,    
112         SlapReply       *sr )
113 {
114         return;
115 }
116
117 static int
118 internal_search_reference(
119         Operation       *op,    
120         SlapReply       *sr )
121 {
122         return LDAP_SUCCESS;
123 }
124
125 static Connection *
126 slapiConnectionInit(
127         char *DN, 
128         int OpType ) 
129
130         Connection *pConn, *c;
131         ber_len_t max = sockbuf_max_incoming;
132
133         pConn = (Connection *) slapi_ch_calloc(1, sizeof(Connection));
134         if (pConn == NULL) {
135                 return (Connection *)NULL;
136         }
137
138         LDAP_STAILQ_INIT( &pConn->c_pending_ops );
139
140         pConn->c_pending_ops.stqh_first =
141                 (Operation *) slapi_ch_calloc( 1, sizeof(Operation) );
142         if ( pConn->c_pending_ops.stqh_first == NULL ) { 
143                 slapi_ch_free( (void **)&pConn );
144                 return (Connection *)NULL;
145         }
146
147         pConn->c_pending_ops.stqh_first->o_pb = 
148                 (Slapi_PBlock *) slapi_pblock_new();
149         if ( pConn->c_pending_ops.stqh_first->o_pb == NULL ) {
150                 slapi_ch_free( (void **)&pConn->c_pending_ops.stqh_first );
151                 slapi_ch_free( (void **)&pConn );
152                 return (Connection *)NULL;
153         }
154
155         c = pConn;
156
157         /* operation object */
158         c->c_pending_ops.stqh_first->o_tag = OpType;
159         c->c_pending_ops.stqh_first->o_protocol = LDAP_VERSION3; 
160         c->c_pending_ops.stqh_first->o_authmech.bv_val = NULL; 
161         c->c_pending_ops.stqh_first->o_authmech.bv_len = 0; 
162         c->c_pending_ops.stqh_first->o_time = slap_get_time();
163         c->c_pending_ops.stqh_first->o_do_not_cache = 1;
164         c->c_pending_ops.stqh_first->o_threadctx = ldap_pvt_thread_pool_context();
165         c->c_pending_ops.stqh_first->o_tmpmemctx = NULL;
166         c->c_pending_ops.stqh_first->o_tmpmfuncs = &ch_mfuncs;
167         c->c_pending_ops.stqh_first->o_conn = c;
168
169         /* connection object */
170         c->c_authmech.bv_val = NULL;
171         c->c_authmech.bv_len = 0;
172         c->c_dn.bv_val = NULL;
173         c->c_dn.bv_len = 0;
174         c->c_ndn.bv_val = NULL;
175         c->c_ndn.bv_len = 0;
176         c->c_groups = NULL;
177
178         c->c_listener = &slap_unknown_listener;
179         ber_dupbv( &c->c_peer_domain, (struct berval *)&slap_unknown_bv );
180         ber_dupbv( &c->c_peer_name, (struct berval *)&slap_unknown_bv );
181
182         LDAP_STAILQ_INIT( &c->c_ops );
183
184         c->c_sasl_bind_mech.bv_val = NULL;
185         c->c_sasl_bind_mech.bv_len = 0;
186         c->c_sasl_authctx = NULL;
187         c->c_sasl_sockctx = NULL;
188         c->c_sasl_extra = NULL;
189
190         c->c_sb = ber_sockbuf_alloc( );
191
192         ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &max );
193
194         c->c_currentber = NULL;
195
196         /* should check status of thread calls */
197         ldap_pvt_thread_mutex_init( &c->c_mutex );
198         ldap_pvt_thread_mutex_init( &c->c_write_mutex );
199         ldap_pvt_thread_cond_init( &c->c_write_cv );
200
201         c->c_n_ops_received = 0;
202         c->c_n_ops_executing = 0;
203         c->c_n_ops_pending = 0;
204         c->c_n_ops_completed = 0;
205
206         c->c_n_get = 0;
207         c->c_n_read = 0;
208         c->c_n_write = 0;
209
210         c->c_protocol = LDAP_VERSION3; 
211
212         c->c_activitytime = c->c_starttime = slap_get_time();
213
214         c->c_connid = 0;
215
216         c->c_conn_state  = 0x01;        /* SLAP_C_ACTIVE */
217         c->c_struct_state = 0x02;       /* SLAP_C_USED */
218
219         c->c_ssf = c->c_transport_ssf = 0;
220         c->c_tls_ssf = 0;
221
222         backend_connection_init( c );
223
224         pConn->c_send_ldap_result = internal_result_v3;
225         pConn->c_send_search_entry = internal_search_entry;
226         pConn->c_send_ldap_extended = internal_result_ext;
227         pConn->c_send_search_reference = internal_search_reference;
228
229         return pConn;
230 }
231
232 static void slapiConnectionDestroy( Connection **pConn )
233 {
234         Connection *conn = *pConn;
235         Operation *op;
236
237         if ( pConn == NULL ) {
238                 return;
239         }
240
241         op = (Operation *)conn->c_pending_ops.stqh_first;
242
243         if ( op->o_req_dn.bv_val != NULL ) {
244                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
245         }
246         if ( op->o_req_ndn.bv_val != NULL ) {
247                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
248         }
249
250         if ( conn->c_sb != NULL ) {
251                 ber_sockbuf_free( conn->c_sb );
252         }
253         if ( op != NULL ) {
254                 slapi_ch_free( (void **)&op );
255         }
256         slapi_ch_free( (void **)pConn );
257 }
258
259 /*
260  * Function : values2obj
261  * Convert an array of strings into a BerVarray.
262  * the strings.
263  */
264 static int
265 values2obj_copy(
266         char **ppValue,
267         BerVarray *bvobj )
268 {
269         int i;
270         BerVarray tmpberval;
271
272         if ( ppValue == NULL ) {
273                 *bvobj = NULL;
274                 return LDAP_SUCCESS;
275         }
276
277         for ( i = 0; ppValue[i] != NULL; i++ )
278                 ;
279
280         tmpberval = (BerVarray)slapi_ch_malloc( (i+1) * (sizeof(struct berval)) );
281         if ( tmpberval == NULL ) {
282                 return LDAP_NO_MEMORY;
283         }
284         for ( i = 0; ppValue[i] != NULL; i++ ) {
285                 size_t len = strlen( ppValue[i] );
286
287                 tmpberval[i].bv_val = slapi_ch_malloc( len + 1 );
288                 AC_MEMCPY( tmpberval[i].bv_val, ppValue[i], len + 1 );
289                 tmpberval[i].bv_len = len;
290         }
291         tmpberval[i].bv_val = NULL;
292         tmpberval[i].bv_len = 0;
293
294         *bvobj = tmpberval;
295
296         return LDAP_SUCCESS;
297 }
298
299 static int
300 bvptr2obj_copy(
301         struct berval   **bvptr, 
302         BerVarray       *bvobj )
303 {
304         int             rc = LDAP_SUCCESS;
305         int             i;
306         BerVarray       tmpberval;
307
308         if ( bvptr == NULL || *bvptr == NULL ) {
309                 return LDAP_OTHER;
310         }
311
312         for ( i = 0; bvptr != NULL && bvptr[i] != NULL; i++ ) {
313                 ; /* EMPTY */
314         }
315
316         tmpberval = (BerVarray)slapi_ch_malloc( (i + 1)*sizeof(struct berval));
317         if ( tmpberval == NULL ) {
318                 return LDAP_NO_MEMORY;
319         } 
320
321         for ( i = 0; bvptr[i] != NULL; i++ ) {
322                 tmpberval[i].bv_val = slapi_ch_malloc( bvptr[i]->bv_len );
323                 tmpberval[i].bv_len = bvptr[i]->bv_len;
324                 AC_MEMCPY( tmpberval[i].bv_val, bvptr[i]->bv_val, bvptr[i]->bv_len );
325         }
326         tmpberval[i].bv_val = NULL;
327         tmpberval[i].bv_len = 0;
328
329         if ( rc == LDAP_SUCCESS ) {
330                 *bvobj = tmpberval;
331         }
332
333         return rc;
334 }
335
336 /*
337  * Function : LDAPModToEntry 
338  * convert a dn plus an array of LDAPMod struct ptrs to an entry structure
339  * with a link list of the correspondent attributes.
340  * Return value : LDAP_SUCCESS
341  *                LDAP_NO_MEMORY
342  *                LDAP_OTHER
343 */
344 Entry *
345 LDAPModToEntry(
346         char *ldn, 
347         LDAPMod **mods )
348 {
349         struct berval           dn = { 0, NULL };
350         Entry                   *pEntry=NULL;
351         LDAPMod                 *pMod;
352         struct berval           *bv;
353         Operation               *op;
354
355         Modifications           *modlist = NULL;
356         Modifications           **modtail = &modlist;
357         Modifications           tmp;
358
359         int                     rc = LDAP_SUCCESS;
360         int                     i;
361
362         const char              *text = NULL;
363
364
365         op = (Operation *) slapi_ch_calloc(1, sizeof(Operation));
366         if ( op == NULL) {
367                 rc = LDAP_NO_MEMORY;
368                 goto cleanup;
369         }  
370         op->o_tag = LDAP_REQ_ADD;
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_bvalues = 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_bvalues = tmp.sml_bvalues;
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_bvalues = 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_bvalues = tmp.sml_bvalues;
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( op->o_bd, &op->o_bd->be_rootdn );
452                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
453                         int update = op->o_bd->be_update_ndn.bv_len;
454                         char textbuf[SLAP_TEXT_BUFLEN];
455                         size_t textlen = sizeof textbuf;
456
457                         rc = slap_mods_check( modlist, update, &text, 
458                                         textbuf, textlen, NULL );
459                         if ( rc != LDAP_SUCCESS) {
460                                 goto cleanup;
461                         }
462
463                         if ( !repl_user ) {
464                                 rc = slap_mods_opattrs( op,
465                                                 modlist, modtail, &text, 
466                                                 textbuf, textlen );
467                                 if ( rc != LDAP_SUCCESS) {
468                                         goto cleanup;
469                                 }
470                         }
471
472                         rc = slap_mods2entry( modlist, &pEntry, repl_user,
473                                               0, &text, textbuf, textlen );
474                         if (rc != LDAP_SUCCESS) {
475                                 goto cleanup;
476                         }
477
478                 } else {
479                         rc = LDAP_REFERRAL;
480                 }
481         }
482
483 cleanup:
484
485         if ( dn.bv_val )
486                 slapi_ch_free( (void **)&dn.bv_val );
487         if ( op )
488                 slapi_ch_free( (void **)&op );
489         if ( modlist != NULL )
490                 slap_mods_free( modlist );
491         if ( rc != LDAP_SUCCESS ) {
492                 if ( pEntry != NULL ) {
493                         slapi_entry_free( pEntry );
494                 }
495                 pEntry = NULL;
496         }
497
498         return( pEntry );
499 }
500
501 /* Function : slapi_delete_internal
502  *
503  * Description : Plugin functions call this routine to delete an entry 
504  *               in the backend directly
505  * Return values : LDAP_SUCCESS
506  *                 LDAP_PARAM_ERROR
507  *                 LDAP_NO_MEMORY
508  *                 LDAP_OTHER
509  *                 LDAP_UNWILLING_TO_PERFORM
510 */
511 Slapi_PBlock *
512 slapi_delete_internal(
513         char *ldn, 
514         LDAPControl **controls, 
515         int log_change )
516 {
517 #ifdef LDAP_SLAPI
518         Connection              *pConn = NULL;
519         Operation               *op = NULL;
520         Slapi_PBlock            *pPB = NULL;
521         Slapi_PBlock            *pSavePB = NULL;
522         SlapReply               rs = { REP_RESULT };
523         struct berval           dn = { 0, NULL };
524
525         int                     manageDsaIt = 0;
526         int                     isCritical;
527
528         if ( ldn == NULL ) {
529                 rs.sr_err = LDAP_PARAM_ERROR; 
530                 goto cleanup;
531         }
532
533         pConn = slapiConnectionInit( NULL, LDAP_REQ_DELETE );
534         if (pConn == NULL) {
535                 rs.sr_err = LDAP_NO_MEMORY;
536                 goto cleanup;
537         }
538
539         op = (Operation *)pConn->c_pending_ops.stqh_first;
540         pPB = (Slapi_PBlock *)op->o_pb;
541         op->o_ctrls = controls;
542
543         dn.bv_val = slapi_ch_strdup(ldn);
544         dn.bv_len = strlen(ldn);
545         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
546         if ( rs.sr_err != LDAP_SUCCESS )
547                 goto cleanup;
548
549         if ( slapi_control_present( controls, 
550                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical) ) {
551                 manageDsaIt = 1; 
552         }
553
554         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
555         if ( op->o_bd == NULL ) {
556                 rs.sr_err = LDAP_PARTIAL_RESULTS;
557                 goto cleanup;
558         }
559
560         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
561         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
562
563         if ( op->o_bd->be_delete ) {
564                 int repl_user = be_isupdate( op->o_bd, &op->o_ndn );
565                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
566                         if ( (*op->o_bd->be_delete)( op, &rs ) == 0 ) {
567                                 if ( log_change ) {
568                                         replog( op );
569                                 }
570                         } else {
571                                 rs.sr_err = LDAP_OTHER;
572                         }
573                 } else {
574                         rs.sr_err = LDAP_REFERRAL;
575                 }
576         } else {
577                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
578         }
579
580 cleanup:
581         if ( pPB != NULL ) {
582                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
583         }
584         if ( dn.bv_val ) {
585                 slapi_ch_free( (void **)&dn.bv_val );
586         }
587         if ( pConn != NULL ) {
588                 pSavePB = pPB;
589         }
590
591         slapiConnectionDestroy( &pConn );
592
593         return (pSavePB);
594 #else
595         return NULL;
596 #endif /* LDAP_SLAPI */
597 }
598
599 #ifdef LDAP_SLAPI
600 static Slapi_PBlock * 
601 slapi_add_entry_internal_locked(
602         Slapi_Entry **e, 
603         LDAPControl **controls, 
604         int log_changes ) 
605 {
606         Connection              *pConn = NULL;
607         Operation               *op = NULL;
608         Slapi_PBlock            *pPB = NULL, *pSavePB = NULL;
609
610         int                     manageDsaIt = 0;
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         pConn = slapiConnectionInit( NULL, LDAP_REQ_ADD );
620         if ( pConn == NULL ) {
621                 rs.sr_err = LDAP_NO_MEMORY;
622                 goto cleanup;
623         }
624
625         if ( slapi_control_present( controls, LDAP_CONTROL_MANAGEDSAIT,
626                                 NULL, &isCritical ) ) {
627                 manageDsaIt = 1; 
628         }
629
630         op = (Operation *)pConn->c_pending_ops.stqh_first;
631         pPB = (Slapi_PBlock *)op->o_pb;
632         op->o_ctrls = controls;
633
634         op->o_bd = select_backend( &((*e)->e_nname), manageDsaIt, 0 );
635         if ( op->o_bd == NULL ) {
636                 rs.sr_err = LDAP_PARTIAL_RESULTS;
637                 goto cleanup;
638         }
639
640         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
641         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
642         op->oq_add.rs_e = *e;
643
644         if ( op->o_bd->be_add ) {
645                 int repl_user = be_isupdate( op->o_bd, &op->o_ndn );
646                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
647                         if ( (*op->o_bd->be_add)( op, &rs ) == 0 ) {
648                                 if ( log_changes ) {
649                                         replog( op );
650                                 }
651                                 be_entry_release_w( op, *e );
652                                 *e = NULL;
653                         }
654                 } else {
655                         rs.sr_err = LDAP_REFERRAL;
656                 }
657         } else {
658                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
659         }
660
661 cleanup:
662
663         if ( pPB != NULL ) {
664                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
665         }
666
667         if ( pConn != NULL ) {
668                 pSavePB = pPB;
669         }
670
671         slapiConnectionDestroy( &pConn );
672
673         return( pSavePB );
674 }
675 #endif /* LDAP_SLAPI */
676
677 Slapi_PBlock * 
678 slapi_add_entry_internal(
679         Slapi_Entry *e, 
680         LDAPControl **controls, 
681         int log_changes ) 
682 {
683 #ifdef LDAP_SLAPI
684         Slapi_PBlock *pb;
685         Slapi_Entry *entry;
686
687         /*
688          * We make a copy to avoid an entry that may be freed later
689          * by the caller being placed in the cache.
690          */
691         entry = slapi_entry_dup( e );
692         pb = slapi_add_entry_internal_locked( &entry, controls, log_changes );
693         if ( entry != NULL ) {
694                 slapi_entry_free( entry );
695         }
696         return pb;
697 #else
698         return NULL;
699 #endif
700 }
701
702 Slapi_PBlock *
703 slapi_add_internal(
704         char *dn, 
705         LDAPMod **mods, 
706         LDAPControl **controls, 
707         int log_changes  ) 
708 {
709 #ifdef LDAP_SLAPI
710         LDAPMod                 *pMod = NULL;
711         Slapi_PBlock            *pb = NULL;
712         Entry                   *pEntry = NULL;
713         int                     i, rc = LDAP_SUCCESS;
714
715         if ( mods == NULL || *mods == NULL || dn == NULL || *dn == '\0' ) {
716                 rc = LDAP_PARAM_ERROR ;
717         }
718
719         if ( rc == LDAP_SUCCESS ) {
720                 for ( i = 0, pMod = mods[0]; pMod != NULL; pMod = mods[++i] ) {
721                         if ( (pMod->mod_op & ~LDAP_MOD_BVALUES) != LDAP_MOD_ADD ) {
722                                 rc = LDAP_OTHER;
723                                 break;
724                         }
725                 }
726         }
727
728         if ( rc == LDAP_SUCCESS ) {
729                 pEntry = LDAPModToEntry( dn, mods );
730                 if ( pEntry == NULL ) {
731                         rc = LDAP_OTHER;
732                 }
733         }
734
735         if ( rc != LDAP_SUCCESS ) {
736                 pb = slapi_pblock_new();
737                 slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rc );
738         } else {
739                 pb = slapi_add_entry_internal_locked( &pEntry, controls, log_changes );
740         }
741
742         if ( pEntry != NULL ) {
743                 slapi_entry_free(pEntry);
744         }
745
746         return(pb);
747 #else
748         return NULL;
749 #endif /* LDAP_SLAPI */
750 }
751
752 /* Function : slapi_modrdn_internal
753  *
754  * Description : Plugin functions call this routine to modify the rdn 
755  *                               of an entry in the backend directly
756  * Return values : LDAP_SUCCESS
757  *                 LDAP_PARAM_ERROR
758  *                 LDAP_NO_MEMORY
759  *                 LDAP_OTHER
760  *                 LDAP_UNWILLING_TO_PERFORM
761  *
762  * NOTE: This function does not support the "newSuperior" option from LDAP V3.
763  */
764 Slapi_PBlock *
765 slapi_modrdn_internal(
766         char *olddn, 
767         char *lnewrdn, 
768         int deloldrdn, 
769         LDAPControl **controls, 
770         int log_change )
771 {
772 #ifdef LDAP_SLAPI
773         struct berval           dn = { 0, NULL };
774         struct berval           newrdn = { 0, NULL };
775         Connection              *pConn = NULL;
776         Operation               *op = NULL;
777         Slapi_PBlock            *pPB = NULL;
778         Slapi_PBlock            *pSavePB = NULL;
779         int                     manageDsaIt = 0;
780         int                     isCritical;
781         SlapReply               rs = { REP_RESULT };
782
783         pConn = slapiConnectionInit( 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 = 1;
796         }
797
798         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
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 ( rdnValidate( &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->o_bd, &op->o_ndn );
838                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
839                         if ( (*op->o_bd->be_modrdn)( op, &rs ) == 0 ) {
840                                 if ( log_change ) {
841                                         replog( op );
842                                 }
843                         } else {
844                                 rs.sr_err = LDAP_OTHER;
845                         }
846                 } else {
847                         rs.sr_err = LDAP_REFERRAL;
848                 }
849         } else {
850                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
851         }
852
853 cleanup:
854
855         if ( pPB != NULL ) {
856                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
857         }
858         
859         if ( dn.bv_val )
860                 slapi_ch_free( (void **)&dn.bv_val );
861
862         if ( newrdn.bv_val )
863                 slapi_ch_free( (void **)&newrdn.bv_val );
864         if ( op->oq_modrdn.rs_newrdn.bv_val )
865                 slapi_ch_free( (void **)&op->oq_modrdn.rs_newrdn.bv_val );
866         if ( op->oq_modrdn.rs_nnewrdn.bv_val )
867                 slapi_ch_free( (void **)&op->oq_modrdn.rs_nnewrdn.bv_val );
868
869         if ( pConn != NULL ) {
870                 pSavePB = pPB;
871         }
872
873         slapiConnectionDestroy( &pConn );
874
875         return( pSavePB );
876 #else
877         return NULL;
878 #endif /* LDAP_SLAPI */
879 }
880
881 /* Function : slapi_modify_internal
882  *
883  * Description: Plugin functions call this routine to modify an entry 
884  *                              in the backend directly
885  * Return values : LDAP_SUCCESS
886  *                 LDAP_PARAM_ERROR
887  *                 LDAP_NO_MEMORY
888  *                 LDAP_OTHER
889  *                 LDAP_UNWILLING_TO_PERFORM
890 */
891 Slapi_PBlock *
892 slapi_modify_internal(
893         char *ldn,      
894         LDAPMod **mods, 
895         LDAPControl **controls, 
896         int log_change )
897 {
898 #ifdef LDAP_SLAPI
899         int                     i;
900         Connection              *pConn = NULL;
901         Operation               *op = NULL;
902         Slapi_PBlock            *pPB = NULL;
903         Slapi_PBlock            *pSavePB = NULL;
904
905         struct berval dn = { 0, NULL };
906
907         int                     manageDsaIt = 0;
908         int                     isCritical;
909         struct berval           *bv;
910         LDAPMod                 *pMod;
911
912         Modifications           *modlist = NULL;
913         Modifications           **modtail = &modlist;
914         Modifications           tmp;
915
916         SlapReply               rs = { REP_RESULT };
917
918         if ( mods == NULL || *mods == NULL || ldn == NULL ) {
919                 rs.sr_err = LDAP_PARAM_ERROR ;
920                 goto cleanup;
921         }
922
923         pConn = slapiConnectionInit( NULL,  LDAP_REQ_MODIFY );
924         if ( pConn == NULL ) {
925                 rs.sr_err = LDAP_NO_MEMORY;
926                 goto cleanup;
927         }
928
929         op = (Operation *)pConn->c_pending_ops.stqh_first;
930         pPB = (Slapi_PBlock *)op->o_pb;
931         op->o_ctrls = controls;
932
933         dn.bv_val = slapi_ch_strdup( ldn );
934         dn.bv_len = strlen( ldn );
935         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
936         if ( rs.sr_err != LDAP_SUCCESS ) {
937                 goto cleanup;
938         }
939
940         if ( slapi_control_present( controls, 
941                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
942                 manageDsaIt = 1;
943         }
944
945         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
946         if ( op->o_bd == NULL ) {
947                 rs.sr_err = LDAP_PARTIAL_RESULTS;
948                 goto cleanup;
949         }
950
951         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
952         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
953
954         for ( i = 0, pMod = mods[0];
955                 rs.sr_err == LDAP_SUCCESS && pMod != NULL; 
956                 pMod = mods[++i] )
957         {
958                 Modifications *mod;
959
960                 if ( (pMod->mod_op & LDAP_MOD_BVALUES) != 0 ) {
961                         /*
962                          * attr values are in berval format
963                          * convert an array of pointers to bervals
964                          * to an array of bervals
965                          */
966                         rs.sr_err = bvptr2obj_copy( pMod->mod_bvalues, &bv );
967                         if ( rs.sr_err != LDAP_SUCCESS )
968                                 goto cleanup;
969                         tmp.sml_type.bv_val = pMod->mod_type;
970                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
971                         tmp.sml_bvalues = bv;
972                         tmp.sml_nvalues = NULL;
973
974                         mod  = (Modifications *)ch_malloc( sizeof(Modifications) );
975
976                         mod->sml_op = pMod->mod_op;
977                         mod->sml_next = NULL;
978                         mod->sml_desc = NULL;
979                         mod->sml_type = tmp.sml_type;
980                         mod->sml_bvalues = tmp.sml_bvalues;
981                         mod->sml_nvalues = tmp.sml_nvalues;
982                 } else { 
983                         rs.sr_err = values2obj_copy( pMod->mod_values, &bv );
984                         if ( rs.sr_err != LDAP_SUCCESS )
985                                 goto cleanup;
986                         tmp.sml_type.bv_val = pMod->mod_type;
987                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
988                         tmp.sml_bvalues = bv;
989                         tmp.sml_nvalues = NULL;
990
991                         mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
992
993                         mod->sml_op = pMod->mod_op;
994                         mod->sml_next = NULL;
995                         mod->sml_desc = NULL;
996                         mod->sml_type = tmp.sml_type;
997                         mod->sml_bvalues = tmp.sml_bvalues;
998                         mod->sml_nvalues = tmp.sml_nvalues;
999                 }
1000                 *modtail = mod;
1001                 modtail = &mod->sml_next;
1002
1003                 switch( pMod->mod_op ) {
1004                 case LDAP_MOD_ADD:
1005                 if ( mod->sml_bvalues == NULL ) {
1006                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1007                         goto cleanup;
1008                 }
1009
1010                 /* fall through */
1011                 case LDAP_MOD_DELETE:
1012                 case LDAP_MOD_REPLACE:
1013                 break;
1014
1015                 default:
1016                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1017                         goto cleanup;
1018                 }
1019         } 
1020         *modtail = NULL;
1021
1022         if ( op->o_req_ndn.bv_len == 0 ) {
1023                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1024                 goto cleanup;
1025         }
1026
1027         op->oq_modify.rs_modlist = modlist;
1028
1029         if ( op->o_bd->be_modify ) {
1030                 int repl_user = be_isupdate( op->o_bd, &op->o_ndn );
1031                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
1032                         int update = op->o_bd->be_update_ndn.bv_len;
1033                         const char *text = NULL;
1034                         char textbuf[SLAP_TEXT_BUFLEN];
1035                         size_t textlen = sizeof( textbuf );
1036
1037                         rs.sr_err = slap_mods_check( modlist, update,
1038                                         &text, textbuf, textlen, NULL );
1039                         if ( rs.sr_err != LDAP_SUCCESS ) {
1040                                 goto cleanup;
1041                         }
1042
1043                         if ( !repl_user ) {
1044                                 rs.sr_err = slap_mods_opattrs( op, modlist,
1045                                                 modtail, &text, textbuf, 
1046                                                 textlen );
1047                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1048                                         goto cleanup;
1049                                 }
1050                         }
1051                         if ( (*op->o_bd->be_modify)( op, &rs ) == 0 ) {
1052                                 if ( log_change ) {
1053                                         replog( op );
1054                                 }
1055                         } else {
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         if ( pConn != NULL ) {
1077                 pSavePB = pPB;
1078         }
1079
1080         slapiConnectionDestroy( &pConn );
1081
1082         return ( pSavePB );
1083 #else
1084         return NULL;
1085 #endif /* LDAP_SLAPI */
1086 }
1087
1088 Slapi_PBlock *
1089 slapi_search_internal_bind(
1090         char *bindDN, 
1091         char *ldn, 
1092         int scope, 
1093         char *filStr, 
1094         LDAPControl **controls, 
1095         char **attrs, 
1096         int attrsonly ) 
1097 {       
1098 #ifdef LDAP_SLAPI
1099         Connection              *c;
1100         Operation               *op = NULL;
1101         Slapi_PBlock            *ptr = NULL;            
1102         Slapi_PBlock            *pSavePB = NULL;                
1103         struct berval           dn = { 0, NULL };
1104         Filter                  *filter=NULL;
1105         struct berval           fstr = { 0, NULL };
1106         AttributeName           *an = NULL;
1107         const char              *text = NULL;
1108
1109         int                     manageDsaIt = 0; 
1110         int                     isCritical;
1111         int                     i;
1112
1113         SlapReply               rs = { REP_RESULT };
1114
1115         c = slapiConnectionInit( NULL, LDAP_REQ_SEARCH );
1116         if ( c == NULL ) {
1117                 rs.sr_err = LDAP_NO_MEMORY;
1118                 goto cleanup;
1119         }
1120
1121         op = (Operation *)c->c_pending_ops.stqh_first;
1122         ptr = (Slapi_PBlock *)op->o_pb;
1123         op->o_ctrls = controls;
1124
1125         if ( ldn != NULL ) {
1126                 dn.bv_val = slapi_ch_strdup(ldn);
1127                 dn.bv_len = strlen(ldn);
1128         }
1129
1130         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
1131         if ( rs.sr_err != LDAP_SUCCESS ) {
1132                 goto cleanup;
1133         }
1134
1135         if ( scope != LDAP_SCOPE_BASE && 
1136                         scope != LDAP_SCOPE_ONELEVEL && 
1137                         scope != LDAP_SCOPE_SUBTREE ) {
1138                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1139                 goto cleanup;
1140         }
1141
1142         filter = slapi_str2filter(filStr);
1143         if ( filter == NULL ) {
1144                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1145                 goto cleanup;
1146         }
1147
1148         filter2bv( filter, &fstr );
1149
1150         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
1151                 ; /* count the number of attributes */
1152         }
1153
1154         if (i > 0) {
1155                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
1156                 for (i = 0; attrs[i] != 0; i++) {
1157                         an[i].an_desc = NULL;
1158                         an[i].an_oc = NULL;
1159                         an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
1160                         an[i].an_name.bv_len = strlen(attrs[i]);
1161                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
1162                 }
1163                 an[i].an_name.bv_val = NULL;
1164         }
1165
1166         memset( &rs, 0, sizeof(rs) );
1167         rs.sr_type = REP_RESULT;
1168         rs.sr_err = LDAP_SUCCESS;
1169         rs.sr_entry = NULL; /* paranoia */
1170
1171         if ( scope == LDAP_SCOPE_BASE ) {
1172                 rs.sr_entry = NULL;
1173
1174                 if ( op->o_req_ndn.bv_len == 0 ) {
1175                         rs.sr_err = root_dse_info( c, &rs.sr_entry, &rs.sr_text );
1176                 }
1177
1178                 if( rs.sr_err != LDAP_SUCCESS ) {
1179                         send_ldap_result( op, &rs );
1180                         goto cleanup;
1181                 } else if ( rs.sr_entry != NULL ) {
1182                         rs.sr_err = test_filter( op, rs.sr_entry, filter );
1183
1184                         if ( rs.sr_err == LDAP_COMPARE_TRUE ) {
1185                                 rs.sr_type = REP_SEARCH;
1186                                 rs.sr_err = LDAP_SUCCESS;
1187                                 rs.sr_attrs = an;
1188
1189                                 send_search_entry( op, &rs );
1190                         }
1191
1192                         entry_free( rs.sr_entry );
1193
1194                         rs.sr_type = REP_RESULT;
1195                         rs.sr_err = LDAP_SUCCESS;
1196
1197                         send_ldap_result( op, &rs );
1198
1199                         goto cleanup;
1200                 }
1201         }
1202
1203         if ( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
1204                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
1205                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
1206
1207                 ber_dupbv( &op->o_req_dn, &default_search_base );
1208                 ber_dupbv( &op->o_req_ndn, &default_search_nbase );
1209         }
1210
1211         if ( slapi_control_present( controls,
1212                         LDAP_CONTROL_MANAGEDSAIT, NULL, &isCritical ) ) {
1213                 manageDsaIt = 1;
1214         }
1215
1216         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
1217         if ( op->o_bd == NULL ) {
1218                 if ( manageDsaIt == 1 ) {
1219                         rs.sr_err = LDAP_NO_SUCH_OBJECT;
1220                 } else {
1221                         rs.sr_err = LDAP_PARTIAL_RESULTS;
1222                 }
1223                 goto cleanup;
1224         } 
1225
1226         op->o_dn = c->c_dn = op->o_bd->be_rootdn;
1227         op->o_ndn = c->c_ndn = op->o_bd->be_rootndn;
1228
1229         op->oq_search.rs_scope = scope;
1230         op->oq_search.rs_deref = 0;
1231         op->oq_search.rs_slimit = LDAP_NO_LIMIT;
1232         op->oq_search.rs_tlimit = LDAP_NO_LIMIT;
1233         op->oq_search.rs_attrsonly = attrsonly;
1234         op->oq_search.rs_attrs = an;
1235         op->oq_search.rs_filter = filter;
1236         op->oq_search.rs_filterstr = fstr;
1237
1238         if ( op->o_bd->be_search ) {
1239                 if ( (*op->o_bd->be_search)( op, &rs ) != 0 ) {
1240                         rs.sr_err = LDAP_OTHER;
1241                 }
1242         } else {
1243                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1244         }
1245
1246 cleanup:
1247
1248         if ( ptr != NULL )
1249                 slapi_pblock_set( ptr, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1250
1251         if ( dn.bv_val )
1252                 slapi_ch_free( (void **)&dn.bv_val );
1253         if ( filter )
1254                 slapi_filter_free( filter, 1 );
1255         if ( fstr.bv_val )
1256                 slapi_ch_free( (void **)&fstr.bv_val );
1257         if ( an != NULL )
1258                 slapi_ch_free( (void **)&an );
1259
1260         if ( c != NULL ) {
1261                 pSavePB = ptr;
1262         }
1263
1264         slapiConnectionDestroy( &c );
1265
1266         return( pSavePB );
1267 #else
1268         return NULL;
1269 #endif /* LDAP_SLAPI */
1270 }
1271
1272 Slapi_PBlock * 
1273 slapi_search_internal(
1274         char *base,
1275         int scope,
1276         char *filStr, 
1277         LDAPControl **controls,
1278         char **attrs,
1279         int attrsonly ) 
1280 {
1281 #ifdef LDAP_SLAPI
1282         return slapi_search_internal_bind( NULL, base, scope, filStr,
1283                         controls, attrs, attrsonly );
1284 #else
1285         return NULL;
1286 #endif /* LDAP_SLAPI */
1287 }
1288