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