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