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