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