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