]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/slapi_ops.c
Harmonize bvptr2obj_copy() with values2obj_copy() - ie. don't fail if NULL
[openldap] / servers / slapd / slapi / slapi_ops.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2002-2004 The OpenLDAP Foundation.
5  * Portions Copyright 1997,2002-2003 IBM Corporation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by IBM Corporation for use in
18  * IBM products and subsequently ported to OpenLDAP Software by
19  * Steve Omrani.  Additional significant contributors include:
20  *   Luke Howard
21  */
22
23 #include "portable.h"
24
25 #include <ac/string.h>
26 #include <ac/stdarg.h>
27 #include <ac/ctype.h>
28 #include <ac/unistd.h>
29
30 #include <slap.h>
31 #include <lber_pvt.h>
32 #include <slapi.h>
33
34 /*
35  * use a fake listener when faking a connection,
36  * so it can be used in ACLs
37  */
38 static struct slap_listener slap_unknown_listener = {
39         BER_BVC("unknown"),     /* FIXME: use a URI form? (e.g. slapi://) */
40         BER_BVC("UNKNOWN")
41 };
42
43 static void
44 internal_result_v3(
45         Operation       *op, 
46         SlapReply       *rs )
47 {
48 #ifdef notdef
49         /* XXX needs review after internal API change */
50         /* rs->sr_nentries appears to always be 0 */
51         if (op->o_tag == LDAP_REQ_SEARCH)
52                 slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
53                         SLAPI_NENTRIES, (void *)rs->sr_nentries );
54 #endif
55
56         return;
57 }
58
59 static int
60 internal_search_entry(
61         Operation       *op,
62         SlapReply       *rs )
63 {
64         int nentries = 0, len = 0, i = 0;
65         Slapi_Entry **head = NULL, **tp;
66         Slapi_Entry *entry;
67
68         entry = slapi_entry_dup( rs->sr_entry );
69         if ( entry == NULL ) {
70                 return 1;
71         }
72
73         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
74                         SLAPI_NENTRIES, &nentries );
75         slapi_pblock_get( (Slapi_PBlock *)op->o_pb,
76                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &head );
77         
78         i = nentries + 1;
79         if ( nentries == 0 ) {
80                 tp = (Slapi_Entry **)slapi_ch_malloc( 2 * sizeof(Slapi_Entry *) );
81                 if ( tp == NULL ) {
82                         slapi_entry_free( entry );
83                         return 1;
84                 }
85
86                 tp[ 0 ] = entry;
87         } else {
88                 tp = (Slapi_Entry **)slapi_ch_realloc( (char *)head,
89                                 sizeof(Slapi_Entry *) * ( i + 1 ) );
90                 if ( tp == NULL ) {
91                         slapi_entry_free( entry );
92                         return 1;
93                 }
94                 tp[ i - 1 ] = entry;
95         }
96         tp[ i ] = NULL;
97                   
98         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
99                         SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, (void *)tp );
100         slapi_pblock_set( (Slapi_PBlock *)op->o_pb,
101                         SLAPI_NENTRIES, (void *)i );
102
103         return LDAP_SUCCESS;
104 }
105
106 static void
107 internal_result_ext(
108         Operation       *op,    
109         SlapReply       *sr )
110 {
111         return;
112 }
113
114 static int
115 internal_search_reference(
116         Operation       *op,    
117         SlapReply       *sr )
118 {
119         return LDAP_SUCCESS;
120 }
121
122 Connection *
123 slapi_int_init_connection(
124         char *DN, 
125         int OpType ) 
126
127         Connection *pConn, *c;
128         ber_len_t max = sockbuf_max_incoming;
129
130         pConn = (Connection *) slapi_ch_calloc(1, sizeof(Connection));
131         if (pConn == NULL) {
132                 return (Connection *)NULL;
133         }
134
135         LDAP_STAILQ_INIT( &pConn->c_pending_ops );
136
137         pConn->c_pending_ops.stqh_first =
138                 (Operation *) slapi_ch_calloc( 1, sizeof(Operation) );
139         if ( pConn->c_pending_ops.stqh_first == NULL ) { 
140                 slapi_ch_free( (void **)&pConn );
141                 return (Connection *)NULL;
142         }
143
144         pConn->c_pending_ops.stqh_first->o_pb = 
145                 (Slapi_PBlock *) slapi_pblock_new();
146         if ( pConn->c_pending_ops.stqh_first->o_pb == NULL ) {
147                 slapi_ch_free( (void **)&pConn->c_pending_ops.stqh_first );
148                 slapi_ch_free( (void **)&pConn );
149                 return (Connection *)NULL;
150         }
151
152         c = pConn;
153
154         /* operation object */
155         c->c_pending_ops.stqh_first->o_tag = OpType;
156         c->c_pending_ops.stqh_first->o_protocol = LDAP_VERSION3; 
157         c->c_pending_ops.stqh_first->o_authmech.bv_val = NULL; 
158         c->c_pending_ops.stqh_first->o_authmech.bv_len = 0; 
159         c->c_pending_ops.stqh_first->o_time = slap_get_time();
160         c->c_pending_ops.stqh_first->o_do_not_cache = 1;
161         c->c_pending_ops.stqh_first->o_threadctx = ldap_pvt_thread_pool_context();
162         c->c_pending_ops.stqh_first->o_tmpmemctx = NULL;
163         c->c_pending_ops.stqh_first->o_tmpmfuncs = &ch_mfuncs;
164         c->c_pending_ops.stqh_first->o_conn = c;
165
166         /* connection object */
167         c->c_authmech.bv_val = NULL;
168         c->c_authmech.bv_len = 0;
169         c->c_dn.bv_val = NULL;
170         c->c_dn.bv_len = 0;
171         c->c_ndn.bv_val = NULL;
172         c->c_ndn.bv_len = 0;
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 void slapi_int_connection_destroy( 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_copy(
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                 ; /* EMPTY */
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                 size_t len = strlen( ppValue[i] );
282
283                 tmpberval[i].bv_val = slapi_ch_malloc( len + 1 );
284                 AC_MEMCPY( tmpberval[i].bv_val, ppValue[i], len + 1 );
285                 tmpberval[i].bv_len = len;
286         }
287         tmpberval[i].bv_val = NULL;
288         tmpberval[i].bv_len = 0;
289
290         *bvobj = tmpberval;
291
292         return LDAP_SUCCESS;
293 }
294
295 static int
296 bvptr2obj_copy(
297         struct berval   **bvptr, 
298         BerVarray       *bvobj )
299 {
300         int             i;
301         BerVarray       tmpberval;
302
303         if ( bvptr == NULL ) {
304                 *bvobj = NULL;
305                 return LDAP_SUCCESS;
306         }
307
308         for ( i = 0; bvptr[i] != NULL; i++ )
309                 ; /* EMPTY */
310
311         tmpberval = (BerVarray)slapi_ch_malloc( (i + 1) * sizeof(struct berval));
312         if ( tmpberval == NULL ) {
313                 return LDAP_NO_MEMORY;
314         } 
315
316         for ( i = 0; bvptr[i] != NULL; i++ ) {
317                 tmpberval[i].bv_val = slapi_ch_malloc( bvptr[i]->bv_len );
318                 tmpberval[i].bv_len = bvptr[i]->bv_len;
319                 AC_MEMCPY( tmpberval[i].bv_val, bvptr[i]->bv_val, bvptr[i]->bv_len );
320         }
321
322         tmpberval[i].bv_val = NULL;
323         tmpberval[i].bv_len = 0;
324
325         *bvobj = tmpberval;
326
327         return LDAP_SUCCESS;
328 }
329
330 /*
331  * Function : slapi_int_ldapmod_to_entry 
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 static Entry *
339 slapi_int_ldapmod_to_entry(
340         char *ldn, 
341         LDAPMod **mods )
342 {
343         struct berval           dn = BER_BVNULL;
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_values = 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_values = tmp.sml_values;
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_values = 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_values = tmp.sml_values;
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_dn( 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 = BER_BVNULL;
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 = slapi_int_init_connection( 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 );
559                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
560                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
561                         if ( log_change ) op->o_callback = &cb;
562                         if ( (*op->o_bd->be_delete)( op, &rs ) ) {
563                                 rs.sr_err = LDAP_OTHER;
564                         }
565                 } else {
566                         rs.sr_err = LDAP_REFERRAL;
567                 }
568         } else {
569                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
570         }
571
572 cleanup:
573         if ( pPB != NULL ) {
574                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
575         }
576         if ( dn.bv_val ) {
577                 slapi_ch_free( (void **)&dn.bv_val );
578         }
579         if ( pConn != NULL ) {
580                 pSavePB = pPB;
581         }
582
583         slapi_int_connection_destroy( &pConn );
584
585         return (pSavePB);
586 #else
587         return NULL;
588 #endif /* LDAP_SLAPI */
589 }
590
591 #ifdef LDAP_SLAPI
592 static Slapi_PBlock * 
593 slapi_int_add_entry_locked(
594         Slapi_Entry **e, 
595         LDAPControl **controls, 
596         int log_changes ) 
597 {
598         Connection              *pConn = NULL;
599         Operation               *op = NULL;
600         Slapi_PBlock            *pPB = NULL, *pSavePB = NULL;
601
602         int                     manageDsaIt = 0;
603         int                     isCritical;
604         SlapReply               rs = { REP_RESULT };
605
606         if ( *e == NULL ) {
607                 rs.sr_err = LDAP_PARAM_ERROR;
608                 goto cleanup;
609         }
610         
611         pConn = slapi_int_init_connection( NULL, LDAP_REQ_ADD );
612         if ( pConn == NULL ) {
613                 rs.sr_err = LDAP_NO_MEMORY;
614                 goto cleanup;
615         }
616
617         if ( slapi_control_present( controls, LDAP_CONTROL_MANAGEDSAIT,
618                                 NULL, &isCritical ) ) {
619                 manageDsaIt = 1; 
620         }
621
622         op = (Operation *)pConn->c_pending_ops.stqh_first;
623         pPB = (Slapi_PBlock *)op->o_pb;
624         op->o_ctrls = controls;
625
626         op->o_bd = select_backend( &((*e)->e_nname), manageDsaIt, 0 );
627         if ( op->o_bd == NULL ) {
628                 rs.sr_err = LDAP_PARTIAL_RESULTS;
629                 goto cleanup;
630         }
631
632         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
633         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
634         op->oq_add.rs_e = *e;
635
636         if ( op->o_bd->be_add ) {
637                 int repl_user = be_isupdate( op );
638                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
639                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
640                         if ( log_changes ) op->o_callback = &cb;
641                         if ( (*op->o_bd->be_add)( op, &rs ) == 0 ) {
642                                 be_entry_release_w( op, *e );
643                                 *e = NULL;
644                         }
645                 } else {
646                         rs.sr_err = LDAP_REFERRAL;
647                 }
648         } else {
649                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
650         }
651
652 cleanup:
653
654         if ( pPB != NULL ) {
655                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
656         }
657
658         if ( pConn != NULL ) {
659                 pSavePB = pPB;
660         }
661
662         slapi_int_connection_destroy( &pConn );
663
664         return( pSavePB );
665 }
666 #endif /* LDAP_SLAPI */
667
668 Slapi_PBlock * 
669 slapi_add_entry_internal(
670         Slapi_Entry *e, 
671         LDAPControl **controls, 
672         int log_changes ) 
673 {
674 #ifdef LDAP_SLAPI
675         Slapi_PBlock *pb;
676         Slapi_Entry *entry;
677
678         /*
679          * We make a copy to avoid an entry that may be freed later
680          * by the caller being placed in the cache.
681          */
682         entry = slapi_entry_dup( e );
683         pb = slapi_int_add_entry_locked( &entry, controls, log_changes );
684         if ( entry != NULL ) {
685                 slapi_entry_free( entry );
686         }
687         return pb;
688 #else
689         return NULL;
690 #endif
691 }
692
693 Slapi_PBlock *
694 slapi_add_internal(
695         char *dn, 
696         LDAPMod **mods, 
697         LDAPControl **controls, 
698         int log_changes  ) 
699 {
700 #ifdef LDAP_SLAPI
701         LDAPMod                 *pMod = NULL;
702         Slapi_PBlock            *pb = NULL;
703         Entry                   *pEntry = NULL;
704         int                     i, rc = LDAP_SUCCESS;
705
706         if ( mods == NULL || *mods == NULL || dn == NULL || *dn == '\0' ) {
707                 rc = LDAP_PARAM_ERROR ;
708         }
709
710         if ( rc == LDAP_SUCCESS ) {
711                 for ( i = 0, pMod = mods[0]; pMod != NULL; pMod = mods[++i] ) {
712                         if ( (pMod->mod_op & LDAP_MOD_OP ) != LDAP_MOD_ADD ) {
713                                 rc = LDAP_OTHER;
714                                 break;
715                         }
716                 }
717         }
718
719         if ( rc == LDAP_SUCCESS ) {
720                 pEntry = slapi_int_ldapmod_to_entry( dn, mods );
721                 if ( pEntry == NULL ) {
722                         rc = LDAP_OTHER;
723                 }
724         }
725
726         if ( rc != LDAP_SUCCESS ) {
727                 pb = slapi_pblock_new();
728                 slapi_pblock_set( pb, SLAPI_PLUGIN_INTOP_RESULT, (void *)rc );
729         } else {
730                 pb = slapi_int_add_entry_locked( &pEntry, controls, log_changes );
731         }
732
733         if ( pEntry != NULL ) {
734                 slapi_entry_free(pEntry);
735         }
736
737         return(pb);
738 #else
739         return NULL;
740 #endif /* LDAP_SLAPI */
741 }
742
743 /* Function : slapi_modrdn_internal
744  *
745  * Description : Plugin functions call this routine to modify the rdn 
746  *                               of an entry in the backend directly
747  * Return values : LDAP_SUCCESS
748  *                 LDAP_PARAM_ERROR
749  *                 LDAP_NO_MEMORY
750  *                 LDAP_OTHER
751  *                 LDAP_UNWILLING_TO_PERFORM
752  *
753  * NOTE: This function does not support the "newSuperior" option from LDAP V3.
754  */
755 Slapi_PBlock *
756 slapi_modrdn_internal(
757         char *olddn, 
758         char *lnewrdn, 
759         int deloldrdn, 
760         LDAPControl **controls, 
761         int log_change )
762 {
763 #ifdef LDAP_SLAPI
764         struct berval           dn = BER_BVNULL;
765         struct berval           newrdn = BER_BVNULL;
766         Connection              *pConn = NULL;
767         Operation               *op = NULL;
768         Slapi_PBlock            *pPB = NULL;
769         Slapi_PBlock            *pSavePB = NULL;
770         int                     manageDsaIt = 0;
771         int                     isCritical;
772         SlapReply               rs = { REP_RESULT };
773
774         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODRDN);
775         if ( pConn == NULL) {
776                 rs.sr_err = LDAP_NO_MEMORY;
777                 goto cleanup;
778         }
779
780         op = (Operation *)pConn->c_pending_ops.stqh_first;
781         pPB = (Slapi_PBlock *)op->o_pb;
782         op->o_ctrls = controls;
783
784         if ( slapi_control_present( controls, 
785                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
786                 manageDsaIt = 1;
787         }
788
789         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
790         if ( op->o_bd == NULL ) {
791                 rs.sr_err =  LDAP_PARTIAL_RESULTS;
792                 goto cleanup;
793         }
794
795         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
796         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
797
798         dn.bv_val = slapi_ch_strdup( olddn );
799         dn.bv_len = strlen( olddn );
800
801         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
802         if ( rs.sr_err != LDAP_SUCCESS ) {
803                 goto cleanup;
804         }
805
806         if ( op->o_req_dn.bv_len == 0 ) {
807                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
808                 goto cleanup;
809         }
810
811         newrdn.bv_val = slapi_ch_strdup( lnewrdn );
812         newrdn.bv_len = strlen( lnewrdn );
813
814         rs.sr_err = dnPrettyNormal( NULL, &newrdn, &op->oq_modrdn.rs_newrdn, &op->oq_modrdn.rs_nnewrdn, NULL );
815         if ( rs.sr_err != LDAP_SUCCESS ) {
816                 goto cleanup;
817         }
818
819         if ( rdn_validate( &op->oq_modrdn.rs_nnewrdn ) != LDAP_SUCCESS ) {
820                 goto cleanup;
821         }
822
823         op->oq_modrdn.rs_newSup = NULL;
824         op->oq_modrdn.rs_nnewSup = NULL;
825         op->oq_modrdn.rs_deleteoldrdn = deloldrdn;
826
827         if ( op->o_bd->be_modrdn ) {
828                 int repl_user = be_isupdate( op );
829                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
830                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
831                         if ( log_change ) op->o_callback = &cb;
832                         if ( (*op->o_bd->be_modrdn)( op, &rs ) ) {
833                                 rs.sr_err = LDAP_OTHER;
834                         }
835                 } else {
836                         rs.sr_err = LDAP_REFERRAL;
837                 }
838         } else {
839                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
840         }
841
842 cleanup:
843
844         if ( pPB != NULL ) {
845                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
846         }
847         
848         if ( dn.bv_val )
849                 slapi_ch_free( (void **)&dn.bv_val );
850
851         if ( newrdn.bv_val )
852                 slapi_ch_free( (void **)&newrdn.bv_val );
853         if ( op->oq_modrdn.rs_newrdn.bv_val )
854                 slapi_ch_free( (void **)&op->oq_modrdn.rs_newrdn.bv_val );
855         if ( op->oq_modrdn.rs_nnewrdn.bv_val )
856                 slapi_ch_free( (void **)&op->oq_modrdn.rs_nnewrdn.bv_val );
857
858         if ( pConn != NULL ) {
859                 pSavePB = pPB;
860         }
861
862         slapi_int_connection_destroy( &pConn );
863
864         return( pSavePB );
865 #else
866         return NULL;
867 #endif /* LDAP_SLAPI */
868 }
869
870 /* Function : slapi_modify_internal
871  *
872  * Description: Plugin functions call this routine to modify an entry 
873  *                              in the backend directly
874  * Return values : LDAP_SUCCESS
875  *                 LDAP_PARAM_ERROR
876  *                 LDAP_NO_MEMORY
877  *                 LDAP_OTHER
878  *                 LDAP_UNWILLING_TO_PERFORM
879 */
880 Slapi_PBlock *
881 slapi_modify_internal(
882         char *ldn,      
883         LDAPMod **mods, 
884         LDAPControl **controls, 
885         int log_change )
886 {
887 #ifdef LDAP_SLAPI
888         int                     i;
889         Connection              *pConn = NULL;
890         Operation               *op = NULL;
891         Slapi_PBlock            *pPB = NULL;
892         Slapi_PBlock            *pSavePB = NULL;
893
894         struct berval dn = BER_BVNULL;
895
896         int                     manageDsaIt = 0;
897         int                     isCritical;
898         struct berval           *bv;
899         LDAPMod                 *pMod;
900
901         Modifications           *modlist = NULL;
902         Modifications           **modtail = &modlist;
903         Modifications           tmp;
904
905         SlapReply               rs = { REP_RESULT };
906
907         if ( mods == NULL || *mods == NULL || ldn == NULL ) {
908                 rs.sr_err = LDAP_PARAM_ERROR ;
909                 goto cleanup;
910         }
911
912         pConn = slapi_int_init_connection( NULL,  LDAP_REQ_MODIFY );
913         if ( pConn == NULL ) {
914                 rs.sr_err = LDAP_NO_MEMORY;
915                 goto cleanup;
916         }
917
918         op = (Operation *)pConn->c_pending_ops.stqh_first;
919         pPB = (Slapi_PBlock *)op->o_pb;
920         op->o_ctrls = controls;
921
922         dn.bv_val = slapi_ch_strdup( ldn );
923         dn.bv_len = strlen( ldn );
924         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
925         if ( rs.sr_err != LDAP_SUCCESS ) {
926                 goto cleanup;
927         }
928
929         if ( slapi_control_present( controls, 
930                         SLAPI_CONTROL_MANAGEDSAIT_OID, NULL, &isCritical ) ) {
931                 manageDsaIt = 1;
932         }
933
934         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
935         if ( op->o_bd == NULL ) {
936                 rs.sr_err = LDAP_PARTIAL_RESULTS;
937                 goto cleanup;
938         }
939
940         op->o_dn = pConn->c_dn = op->o_bd->be_rootdn;
941         op->o_ndn = pConn->c_ndn = op->o_bd->be_rootndn;
942
943         for ( i = 0, pMod = mods[0];
944                 rs.sr_err == LDAP_SUCCESS && pMod != NULL; 
945                 pMod = mods[++i] )
946         {
947                 Modifications *mod;
948
949                 if ( (pMod->mod_op & LDAP_MOD_BVALUES) != 0 ) {
950                         /*
951                          * attr values are in berval format
952                          * convert an array of pointers to bervals
953                          * to an array of bervals
954                          */
955                         rs.sr_err = bvptr2obj_copy( pMod->mod_bvalues, &bv );
956                         if ( rs.sr_err != LDAP_SUCCESS )
957                                 goto cleanup;
958                         tmp.sml_type.bv_val = pMod->mod_type;
959                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
960                         tmp.sml_values = bv;
961                         tmp.sml_nvalues = NULL;
962
963                         mod  = (Modifications *)ch_malloc( sizeof(Modifications) );
964
965                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
966                         mod->sml_next = NULL;
967                         mod->sml_desc = NULL;
968                         mod->sml_type = tmp.sml_type;
969                         mod->sml_values = tmp.sml_values;
970                         mod->sml_nvalues = tmp.sml_nvalues;
971                 } else { 
972                         rs.sr_err = values2obj_copy( pMod->mod_values, &bv );
973                         if ( rs.sr_err != LDAP_SUCCESS )
974                                 goto cleanup;
975                         tmp.sml_type.bv_val = pMod->mod_type;
976                         tmp.sml_type.bv_len = strlen( pMod->mod_type );
977                         tmp.sml_values = bv;
978                         tmp.sml_nvalues = NULL;
979
980                         mod  = (Modifications *) ch_malloc( sizeof(Modifications) );
981
982                         mod->sml_op = pMod->mod_op & LDAP_MOD_OP;
983                         mod->sml_next = NULL;
984                         mod->sml_desc = NULL;
985                         mod->sml_type = tmp.sml_type;
986                         mod->sml_values = tmp.sml_values;
987                         mod->sml_nvalues = tmp.sml_nvalues;
988                 }
989                 *modtail = mod;
990                 modtail = &mod->sml_next;
991
992                 switch( pMod->mod_op & LDAP_MOD_OP ) {
993                 case LDAP_MOD_ADD:
994                 if ( mod->sml_values == NULL ) {
995                         rs.sr_err = LDAP_PROTOCOL_ERROR;
996                         goto cleanup;
997                 }
998
999                 /* fall through */
1000                 case LDAP_MOD_DELETE:
1001                 case LDAP_MOD_REPLACE:
1002                 break;
1003
1004                 default:
1005                         rs.sr_err = LDAP_PROTOCOL_ERROR;
1006                         goto cleanup;
1007                 }
1008         } 
1009         *modtail = NULL;
1010
1011         if ( op->o_req_ndn.bv_len == 0 ) {
1012                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1013                 goto cleanup;
1014         }
1015
1016         op->oq_modify.rs_modlist = modlist;
1017
1018         if ( op->o_bd->be_modify ) {
1019                 int repl_user = be_isupdate( op );
1020                 if ( !op->o_bd->be_update_ndn.bv_len || repl_user ) {
1021                         int update = op->o_bd->be_update_ndn.bv_len;
1022                         const char *text = NULL;
1023                         char textbuf[SLAP_TEXT_BUFLEN];
1024                         size_t textlen = sizeof( textbuf );
1025                         slap_callback cb = { NULL, slap_replog_cb, NULL, NULL };
1026
1027                         rs.sr_err = slap_mods_check( modlist, update,
1028                                         &text, textbuf, textlen, NULL );
1029                         if ( rs.sr_err != LDAP_SUCCESS ) {
1030                                 goto cleanup;
1031                         }
1032
1033                         if ( !repl_user ) {
1034                                 rs.sr_err = slap_mods_opattrs( op, modlist,
1035                                                 modtail, &text, textbuf, 
1036                                                 textlen );
1037                                 if ( rs.sr_err != LDAP_SUCCESS ) {
1038                                         goto cleanup;
1039                                 }
1040                         }
1041                         if ( log_change ) op->o_callback = &cb;
1042                         if ( (*op->o_bd->be_modify)( op, &rs ) ) {
1043                                 rs.sr_err = LDAP_OTHER;
1044                         }
1045                 } else {
1046                         rs.sr_err = LDAP_REFERRAL;
1047                 }
1048         } else {
1049                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1050         }
1051
1052 cleanup:
1053
1054         if ( pPB != NULL ) 
1055                 slapi_pblock_set( pPB, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1056
1057         if ( dn.bv_val )
1058                 slapi_ch_free( (void **)&dn.bv_val );
1059
1060         if ( modlist != NULL )
1061                 slap_mods_free( modlist );
1062
1063         if ( pConn != NULL ) {
1064                 pSavePB = pPB;
1065         }
1066
1067         slapi_int_connection_destroy( &pConn );
1068
1069         return ( pSavePB );
1070 #else
1071         return NULL;
1072 #endif /* LDAP_SLAPI */
1073 }
1074
1075 Slapi_PBlock *
1076 slapi_search_internal(
1077         char *ldn, 
1078         int scope, 
1079         char *filStr, 
1080         LDAPControl **controls, 
1081         char **attrs, 
1082         int attrsonly ) 
1083 {       
1084 #ifdef LDAP_SLAPI
1085         Connection              *c;
1086         Operation               *op = NULL;
1087         Slapi_PBlock            *ptr = NULL;            
1088         Slapi_PBlock            *pSavePB = NULL;                
1089         struct berval           dn = BER_BVNULL;
1090         Filter                  *filter=NULL;
1091         struct berval           fstr = BER_BVNULL;
1092         AttributeName           *an = NULL;
1093         const char              *text = NULL;
1094
1095         int                     manageDsaIt = 0; 
1096         int                     isCritical;
1097         int                     i;
1098
1099         SlapReply               rs = { REP_RESULT };
1100
1101         c = slapi_int_init_connection( NULL, LDAP_REQ_SEARCH );
1102         if ( c == NULL ) {
1103                 rs.sr_err = LDAP_NO_MEMORY;
1104                 goto cleanup;
1105         }
1106
1107         op = (Operation *)c->c_pending_ops.stqh_first;
1108         ptr = (Slapi_PBlock *)op->o_pb;
1109         op->o_ctrls = controls;
1110
1111         if ( ldn != NULL ) {
1112                 dn.bv_val = slapi_ch_strdup(ldn);
1113                 dn.bv_len = strlen(ldn);
1114         }
1115
1116         rs.sr_err = dnPrettyNormal( NULL, &dn, &op->o_req_dn, &op->o_req_ndn, NULL );
1117         if ( rs.sr_err != LDAP_SUCCESS ) {
1118                 goto cleanup;
1119         }
1120
1121         if ( scope != LDAP_SCOPE_BASE && 
1122                         scope != LDAP_SCOPE_ONELEVEL && 
1123                         scope != LDAP_SCOPE_SUBTREE ) {
1124                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1125                 goto cleanup;
1126         }
1127
1128         filter = slapi_str2filter(filStr);
1129         if ( filter == NULL ) {
1130                 rs.sr_err = LDAP_PROTOCOL_ERROR;
1131                 goto cleanup;
1132         }
1133
1134         filter2bv( filter, &fstr );
1135
1136         for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
1137                 ; /* count the number of attributes */
1138         }
1139
1140         if (i > 0) {
1141                 an = (AttributeName *)slapi_ch_calloc( (i + 1), sizeof(AttributeName) );
1142                 for (i = 0; attrs[i] != 0; i++) {
1143                         an[i].an_desc = NULL;
1144                         an[i].an_oc = NULL;
1145                         an[i].an_oc_exclude = 0;
1146                         an[i].an_name.bv_val = slapi_ch_strdup(attrs[i]);
1147                         an[i].an_name.bv_len = strlen(attrs[i]);
1148                         slap_bv2ad( &an[i].an_name, &an[i].an_desc, &text );
1149                 }
1150                 an[i].an_name.bv_val = NULL;
1151         }
1152
1153         memset( &rs, 0, sizeof(rs) );
1154         rs.sr_type = REP_RESULT;
1155         rs.sr_err = LDAP_SUCCESS;
1156         rs.sr_entry = NULL; /* paranoia */
1157
1158         if ( scope == LDAP_SCOPE_BASE ) {
1159                 rs.sr_entry = NULL;
1160
1161                 if ( op->o_req_ndn.bv_len == 0 ) {
1162                         rs.sr_err = root_dse_info( c, &rs.sr_entry, &rs.sr_text );
1163                 }
1164
1165                 if( rs.sr_err != LDAP_SUCCESS ) {
1166                         send_ldap_result( op, &rs );
1167                         goto cleanup;
1168                 } else if ( rs.sr_entry != NULL ) {
1169                         rs.sr_err = test_filter( op, rs.sr_entry, filter );
1170
1171                         if ( rs.sr_err == LDAP_COMPARE_TRUE ) {
1172                                 rs.sr_type = REP_SEARCH;
1173                                 rs.sr_err = LDAP_SUCCESS;
1174                                 rs.sr_attrs = an;
1175                                 rs.sr_operational_attrs = NULL;
1176                                 rs.sr_flags = REP_ENTRY_MODIFIABLE;
1177
1178                                 send_search_entry( op, &rs );
1179                         }
1180
1181                         entry_free( rs.sr_entry );
1182
1183                         rs.sr_type = REP_RESULT;
1184                         rs.sr_err = LDAP_SUCCESS;
1185
1186                         send_ldap_result( op, &rs );
1187
1188                         goto cleanup;
1189                 }
1190         }
1191
1192         if ( !op->o_req_ndn.bv_len && default_search_nbase.bv_len ) {
1193                 slapi_ch_free( (void **)&op->o_req_dn.bv_val );
1194                 slapi_ch_free( (void **)&op->o_req_ndn.bv_val );
1195
1196                 ber_dupbv( &op->o_req_dn, &default_search_base );
1197                 ber_dupbv( &op->o_req_ndn, &default_search_nbase );
1198         }
1199
1200         if ( slapi_control_present( controls,
1201                         LDAP_CONTROL_MANAGEDSAIT, NULL, &isCritical ) ) {
1202                 manageDsaIt = 1;
1203         }
1204
1205         op->o_bd = select_backend( &op->o_req_ndn, manageDsaIt, 0 );
1206         if ( op->o_bd == NULL ) {
1207                 if ( manageDsaIt == 1 ) {
1208                         rs.sr_err = LDAP_NO_SUCH_OBJECT;
1209                 } else {
1210                         rs.sr_err = LDAP_PARTIAL_RESULTS;
1211                 }
1212                 goto cleanup;
1213         } 
1214
1215         op->o_dn = c->c_dn = op->o_bd->be_rootdn;
1216         op->o_ndn = c->c_ndn = op->o_bd->be_rootndn;
1217
1218         op->oq_search.rs_scope = scope;
1219         op->oq_search.rs_deref = 0;
1220         op->oq_search.rs_slimit = SLAP_NO_LIMIT;
1221         op->oq_search.rs_tlimit = SLAP_NO_LIMIT;
1222         op->oq_search.rs_attrsonly = attrsonly;
1223         op->oq_search.rs_attrs = an;
1224         op->oq_search.rs_filter = filter;
1225         op->oq_search.rs_filterstr = fstr;
1226
1227         if ( op->o_bd->be_search ) {
1228                 if ( (*op->o_bd->be_search)( op, &rs ) != 0 ) {
1229                         rs.sr_err = LDAP_OTHER;
1230                 }
1231         } else {
1232                 rs.sr_err = LDAP_UNWILLING_TO_PERFORM;
1233         }
1234
1235 cleanup:
1236
1237         if ( ptr != NULL )
1238                 slapi_pblock_set( ptr, SLAPI_PLUGIN_INTOP_RESULT, (void *)rs.sr_err );
1239
1240         if ( dn.bv_val )
1241                 slapi_ch_free( (void **)&dn.bv_val );
1242         if ( filter )
1243                 slapi_filter_free( filter, 1 );
1244         if ( fstr.bv_val )
1245                 slapi_ch_free( (void **)&fstr.bv_val );
1246         if ( an != NULL )
1247                 slapi_ch_free( (void **)&an );
1248
1249         if ( c != NULL ) {
1250                 pSavePB = ptr;
1251         }
1252
1253         slapi_int_connection_destroy( &c );
1254
1255         return( pSavePB );
1256 #else
1257         return NULL;
1258 #endif /* LDAP_SLAPI */
1259 }
1260