]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modrdn.c
Fix maxDeref directive
[openldap] / servers / slapd / back-bdb2 / modrdn.c
1 /* modrdn.c - bdb2 backend modrdn routine */
2
3 /*
4  * LDAP v3 newSuperior support.
5  *
6  * Copyright 1999, Juan C. Gomez, All rights reserved.
7  * This software is not subject to any license of Silicon Graphics 
8  * Inc. or Purdue University.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * without restriction or fee of any kind as long as this notice
12  * is preserved.
13  *
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19
20 #include <ac/string.h>
21 #include <ac/socket.h>
22
23 #include "slap.h"
24 #include "back-bdb2.h"
25 #include "proto-back-bdb2.h"
26
27 static int
28 bdb2i_back_modrdn_internal(
29     BackendDB   *be,
30     Connection  *conn,
31     Operation   *op,
32     char        *dn,
33     char        *newrdn,
34     int         deleteoldrdn,
35     char        *newSuperior
36 )
37 {
38         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
39         Entry           *matched = NULL;
40         char            *p_dn = NULL, *p_ndn = NULL;
41         char            *new_dn = NULL, *new_ndn = NULL;
42         char            sep[2];
43         Entry           *e, *p = NULL;
44         int                     rc = -1, manageDSAit;
45         /* Added to support LDAP v2 correctly (deleteoldrdn thing) */
46         char            *new_rdn_val = NULL;    /* Val of new rdn */
47         char            *new_rdn_type = NULL;   /* Type of new rdn */
48         char            *old_rdn;               /* Old rdn's attr type & val */
49         char            *old_rdn_type = NULL;   /* Type of old rdn attr. */
50         char            *old_rdn_val = NULL;    /* Old rdn attribute value */
51         struct berval   add_bv;                 /* Stores new rdn att */
52         struct berval   *add_bvals[2];          /* Stores new rdn att */
53         struct berval   del_bv;                 /* Stores old rdn att */
54         struct berval   *del_bvals[2];          /* Stores old rdn att */
55         LDAPModList     mod[2];                 /* Used to delete old rdn */
56         /* Added to support newSuperior */ 
57         Entry           *np = NULL;     /* newSuperior Entry */
58         char            *np_dn = NULL;  /* newSuperior dn */
59         char            *np_ndn = NULL; /* newSuperior ndn */
60         char            *new_parent_dn = NULL;  /* np_dn, p_dn, or NULL */
61
62         Debug( LDAP_DEBUG_TRACE, "==>ldbm_back_modrdn(newSuperior=%s)\n",
63                (newSuperior ? newSuperior : "NULL"),
64                0, 0 );
65
66         /* get entry with writer lock */
67         if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
68                 char *matched_dn = NULL;
69                 struct berval **refs = NULL;
70
71                 if ( matched != NULL ) {
72                         matched_dn = ch_strdup( matched->e_dn );
73                         refs = is_entry_referral( matched )
74                                 ? get_entry_referrals( be, conn, op, matched )
75                                 : NULL;
76                         bdb2i_cache_return_entry_r( &li->li_cache, matched );
77                 } else {
78                         refs = default_referral;
79                 }
80
81                 send_ldap_result( conn, op, LDAP_REFERRAL,
82                         matched_dn, NULL, refs, NULL );
83
84                 if( matched != NULL ) {
85                         ber_bvecfree( refs );
86                         free( matched_dn );
87                 }
88
89                 return( -1 );
90         }
91
92         if (!manageDSAit && is_entry_referral( e ) ) {
93                 /* entry is a referral, don't allow add */
94                 struct berval **refs = get_entry_referrals( be,
95                         conn, op, e );
96
97                 Debug( LDAP_DEBUG_TRACE, "entry is referral\n", 0,
98                         0, 0 );
99
100                 send_ldap_result( conn, op, LDAP_REFERRAL,
101                         e->e_dn, NULL, refs, NULL );
102
103                 ber_bvecfree( refs );
104
105                 goto return_results;
106         }
107
108 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
109                 /* check parent for "children" acl */
110         if ( ! access_allowed( be, conn, op, e,
111                 "entry", NULL, ACL_WRITE ) )
112         {
113                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
114                         0, 0 );
115                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
116                         NULL, NULL, NULL, NULL );
117                 goto return_results;
118         }
119 #endif
120
121         if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
122                 /* parent + rdn + separator(s) + null */
123                 if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
124                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
125                                 0, 0, 0);
126                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
127                                 NULL, NULL, NULL, NULL );
128                         goto return_results;
129                 }
130
131                 /* check parent for "children" acl */
132                 if ( ! access_allowed( be, conn, op, p,
133                         "children", NULL, ACL_WRITE ) )
134                 {
135                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
136                                 0, 0 );
137                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
138                                 NULL, NULL, NULL, NULL );
139                         goto return_results;
140                 }
141
142                 p_dn = dn_parent( be, e->e_dn );
143
144                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
145                        p_dn, 0, 0 );
146
147
148         } else {
149                 /* no parent, modrdn entry directly under root */
150                 if( ! be_isroot( be, op->o_ndn ) ) {
151                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
152                                 0, 0, 0);
153                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
154                                 NULL, NULL, NULL, NULL );
155                         goto return_results;
156                 }
157
158                 Debug( LDAP_DEBUG_TRACE,
159                        "ldbm_back_modrdn: no parent!, working on root\n",
160                        0, 0, 0 );
161
162         }
163
164         new_parent_dn = p_dn;   /* New Parent unless newSuperior given */
165
166         if ( (np_dn = newSuperior) != NULL) {
167
168
169                 Debug( LDAP_DEBUG_TRACE, 
170                        "ldbm_back_modrdn: new parent requested...\n",
171                        0, 0, 0 );
172
173                 np_ndn = dn_normalize_case( ch_strdup( np_dn ) );
174
175                 /* newSuperior == oldParent?, if so ==> ERROR */
176
177                 /* newSuperior == entry being moved?, if so ==> ERROR */
178
179                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
180
181                 if( (np = bdb2i_dn2entry_w( be, np_ndn, &matched )) == NULL) {
182
183                         Debug( LDAP_DEBUG_TRACE,
184                                "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
185                                np_ndn, 0, 0);
186                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
187                                 NULL, NULL, NULL, NULL );
188                         goto return_results;
189                 }
190
191                 Debug( LDAP_DEBUG_TRACE,
192                        "ldbm_back_modrdn: wr to new parent OK np=%p, id=%d\n",
193                        np, np->e_id, 0 );
194             
195                 /* check newSuperior for "children" acl */
196                 if ( !access_allowed( be, conn, op, np, "children", NULL,
197                                       ACL_WRITE ) )
198                 {
199                         Debug( LDAP_DEBUG_TRACE,
200                                "ldbm_back_modrdn: no wr to newSup children\n",
201                                0, 0, 0 );
202                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
203                                 NULL, NULL, NULL, NULL );
204                         goto return_results;
205                 }
206
207                 Debug( LDAP_DEBUG_TRACE,
208                        "ldbm_back_modrdn: wr to new parent's children OK\n",
209                        0, 0 , 0 );
210
211
212                 new_parent_dn = np_dn;
213
214         }
215         
216         /* Build target dn and make sure target entry doesn't exist already. */
217
218         build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); 
219
220
221         new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
222
223         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
224                new_ndn, 0, 0 );
225
226         if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
227                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
228                         NULL, NULL, NULL, NULL );
229                 goto return_results;
230         }
231
232         /* check for abandon */
233         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
234         if ( op->o_abandon ) {
235                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
236                 goto return_results;
237         }
238         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
239
240         /* delete old one */
241         if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
242                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
243                         NULL, NULL, NULL, NULL );
244                 goto return_results;
245         }
246
247         (void) bdb2i_cache_delete_entry( &li->li_cache, e );
248         free( e->e_dn );
249         free( e->e_ndn );
250         e->e_dn = new_dn;
251         e->e_ndn = new_ndn;
252
253
254         /* add new one */
255         if ( bdb2i_dn2id_add( be,  e->e_ndn, e->e_id ) != 0 ) {
256                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
257                         NULL, NULL, NULL, NULL );
258                 goto return_results;
259         }
260
261         /* Get attribute type and attribute value of our new rdn, we will
262          * need to add that to our new entry
263          */
264
265         if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
266             
267                 Debug( LDAP_DEBUG_TRACE,
268                        "ldbm_back_modrdn: can't figure out type of newrdn\n",
269                        0, 0, 0 );
270                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
271                         NULL, NULL, NULL, NULL );
272                 goto return_results;            
273
274         }
275
276         if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
277             
278                 Debug( LDAP_DEBUG_TRACE,
279                        "ldbm_back_modrdn: can't figure out val of newrdn\n",
280                        0, 0, 0 );
281                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
282                         NULL, NULL, NULL, NULL );
283                 goto return_results;            
284
285         }
286
287         Debug( LDAP_DEBUG_TRACE,
288                "ldbm_back_modrdn: new_rdn_val=%s, new_rdn_type=%s\n",
289                new_rdn_val, new_rdn_type, 0 );
290
291         /* Retrieve the old rdn from the entry's dn */
292
293         if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
294
295                 Debug( LDAP_DEBUG_TRACE,
296                        "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
297                        0, 0, 0 );
298                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
299                         NULL, NULL, NULL, NULL );
300                 goto return_results;            
301
302         }
303
304         if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
305             
306                 Debug( LDAP_DEBUG_TRACE,
307                        "ldbm_back_modrdn: can't figure out the old_rdn type\n",
308                        0, 0, 0 );
309                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
310                         NULL, NULL, NULL, NULL );
311                 goto return_results;            
312                 
313         }
314         
315         if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
316
317             /* Not a big deal but we may say something */
318             Debug( LDAP_DEBUG_TRACE,
319                    "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
320                    old_rdn_type, new_rdn_type, 0 );
321             
322         }               
323
324         if ( dn_type( old_rdn ) == DN_X500 ) {
325
326                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
327                        0, 0, 0 );
328
329                 /* Add new attribute value to the entry.
330                  */
331
332                 add_bvals[0] = &add_bv;         /* Array of bervals */
333                 add_bvals[1] = NULL;
334
335                 add_bv.bv_val = new_rdn_val;
336                 add_bv.bv_len = strlen(new_rdn_val);
337                 
338                 mod[0].ml_type = new_rdn_type;  
339                 mod[0].ml_bvalues = add_bvals;
340                 mod[0].ml_op = LDAP_MOD_SOFTADD;
341                 mod[0].ml_next = NULL;
342                 
343                 Debug( LDAP_DEBUG_TRACE,
344                        "ldbm_back_modrdn: adding new rdn attr val =%s\n",
345                        new_rdn_val, 0, 0 );
346                 
347                 /* Remove old rdn value if required */
348
349                 if (deleteoldrdn) {
350
351                         del_bvals[0] = &del_bv;         /* Array of bervals */
352                         del_bvals[1] = NULL;
353                         /* Get value of old rdn */
354         
355                         if ((old_rdn_val = rdn_attr_value( old_rdn ))
356                             == NULL) {
357                             
358                                 Debug( LDAP_DEBUG_TRACE,
359                                        "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
360                                        0, 0, 0 );
361                                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
362                                         NULL, NULL, NULL, NULL );
363                                 goto return_results;            
364
365
366                         }
367
368                         /* Remove old value of rdn as an attribute. */
369                     
370                         del_bv.bv_val = old_rdn_val;
371                         del_bv.bv_len = strlen(old_rdn_val);
372                         
373                         mod[0].ml_next = &mod[1];
374                         mod[1].ml_type = old_rdn_type;  
375                         mod[1].ml_bvalues = del_bvals;
376                         mod[1].ml_op = LDAP_MOD_DELETE;
377                         mod[1].ml_next = NULL;
378
379
380                         Debug( LDAP_DEBUG_TRACE,
381                                "ldbm_back_modrdn: removing old_rdn_val=%s\n",
382                                old_rdn_val, 0, 0 );
383                 
384                 }/* if (deleteoldrdn) */
385
386         } else {
387             
388
389                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
390                        0, 0, 0 );
391                 /* XXXV3: not sure of what to do here */
392                 Debug( LDAP_DEBUG_TRACE,
393                        "ldbm_back_modrdn: not fully implemented...\n",
394                        0, 0, 0 );  
395
396         }
397
398         /* modify memory copy of entry */
399         if ( bdb2i_back_modify_internal( be, conn, op, dn, &mod[0], e )
400              != 0 ) {
401             
402                 goto return_results;
403                         
404         }
405         
406         (void) bdb2i_cache_update_entry( &li->li_cache, e );
407
408         /* NOTE: after this you must not free new_dn or new_ndn!
409          * They are used by cache.
410          */
411
412         /* id2entry index */
413         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
414                 entry_free( e );
415                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
416                         NULL, NULL, NULL, NULL );
417                 goto return_results_after;
418         }
419
420         send_ldap_result( conn, op, LDAP_SUCCESS,
421                 NULL, NULL, NULL, NULL );
422         rc = 0;
423         goto return_results_after;      
424
425 return_results:
426         if( new_dn != NULL ) free( new_dn );
427         if( new_ndn != NULL ) free( new_ndn );
428
429 return_results_after:
430         /* NOTE:
431          * new_dn and new_ndn are not deallocated because they are used by
432          * the cache entry.
433          */
434         if( p_dn != NULL ) free( p_dn );
435         if( p_ndn != NULL ) free( p_ndn );
436
437         /* LDAP v2 supporting correct attribute handling. */
438         if( new_rdn_type != NULL ) free(new_rdn_type);
439         if( new_rdn_val != NULL ) free(new_rdn_val);
440         if( old_rdn != NULL ) free(old_rdn);
441         if( old_rdn_type != NULL ) free(old_rdn_type);
442         if( old_rdn_val != NULL ) free(old_rdn_val);
443
444         /* LDAP v3 Support */
445         if ( np_dn != NULL ) free( np_dn );
446         if ( np_ndn != NULL ) free( np_ndn );
447
448         if( p != NULL ) {
449                 /* free parent and writer lock */
450                 bdb2i_cache_return_entry_w( &li->li_cache, p );
451
452         }
453
454         /* free entry and writer lock */
455         bdb2i_cache_return_entry_w( &li->li_cache, e );
456         return( rc );
457 }
458
459
460 int
461 bdb2_back_modrdn(
462     BackendDB   *be,
463     Connection  *conn,
464     Operation   *op,
465     char        *dn,
466     char        *newrdn,
467     int         deleteoldrdn,
468     char        *newSuperior
469 )
470 {
471         DB_LOCK         lock;
472         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
473         struct timeval  time1;
474         int             ret;
475
476         bdb2i_start_timing( be->bd_info, &time1 );
477
478         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
479                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
480                         NULL, NULL, NULL, NULL );
481                 return( -1 );
482
483         }
484
485         ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
486                                         newrdn, deleteoldrdn,
487                                         newSuperior );
488
489         (void) bdb2i_leave_backend_w( lock );
490         bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op );
491
492         return( ret );
493 }
494
495