]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modrdn.c
Add missing semicolon.
[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 = ch_strdup( np_dn );
174                 (void) dn_normalize_case( np_ndn );
175
176                 /* newSuperior == oldParent?, if so ==> ERROR */
177
178                 /* newSuperior == entry being moved?, if so ==> ERROR */
179
180                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
181
182                 if( (np = bdb2i_dn2entry_w( be, np_ndn, &matched )) == NULL) {
183
184                         Debug( LDAP_DEBUG_TRACE,
185                                "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
186                                np_ndn, 0, 0);
187                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
188                                 NULL, NULL, NULL, NULL );
189                         goto return_results;
190                 }
191
192                 Debug( LDAP_DEBUG_TRACE,
193                        "ldbm_back_modrdn: wr to new parent OK np=%p, id=%d\n",
194                        np, np->e_id, 0 );
195             
196                 /* check newSuperior for "children" acl */
197                 if ( !access_allowed( be, conn, op, np, "children", NULL,
198                                       ACL_WRITE ) )
199                 {
200                         Debug( LDAP_DEBUG_TRACE,
201                                "ldbm_back_modrdn: no wr to newSup children\n",
202                                0, 0, 0 );
203                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
204                                 NULL, NULL, NULL, NULL );
205                         goto return_results;
206                 }
207
208                 Debug( LDAP_DEBUG_TRACE,
209                        "ldbm_back_modrdn: wr to new parent's children OK\n",
210                        0, 0 , 0 );
211
212
213                 new_parent_dn = np_dn;
214
215         }
216         
217         /* Build target dn and make sure target entry doesn't exist already. */
218
219         build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); 
220
221
222         new_ndn = ch_strdup( new_dn );
223         (void) dn_normalize_case( new_ndn );
224
225         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
226                new_ndn, 0, 0 );
227
228         if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
229                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS,
230                         NULL, NULL, NULL, NULL );
231                 goto return_results;
232         }
233
234         /* check for abandon */
235         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
236         if ( op->o_abandon ) {
237                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
238                 goto return_results;
239         }
240         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
241
242         /* delete old one */
243         if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
244                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
245                         NULL, NULL, NULL, NULL );
246                 goto return_results;
247         }
248
249         (void) bdb2i_cache_delete_entry( &li->li_cache, e );
250         free( e->e_dn );
251         free( e->e_ndn );
252         e->e_dn = new_dn;
253         e->e_ndn = new_ndn;
254
255
256         /* add new one */
257         if ( bdb2i_dn2id_add( be,  e->e_ndn, e->e_id ) != 0 ) {
258                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
259                         NULL, NULL, NULL, NULL );
260                 goto return_results;
261         }
262
263         /* Get attribute type and attribute value of our new rdn, we will
264          * need to add that to our new entry
265          */
266
267         if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
268             
269                 Debug( LDAP_DEBUG_TRACE,
270                        "ldbm_back_modrdn: can't figure out type of newrdn\n",
271                        0, 0, 0 );
272                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
273                         NULL, NULL, NULL, NULL );
274                 goto return_results;            
275
276         }
277
278         if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
279             
280                 Debug( LDAP_DEBUG_TRACE,
281                        "ldbm_back_modrdn: can't figure out val of newrdn\n",
282                        0, 0, 0 );
283                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
284                         NULL, NULL, NULL, NULL );
285                 goto return_results;            
286
287         }
288
289         Debug( LDAP_DEBUG_TRACE,
290                "ldbm_back_modrdn: new_rdn_val=%s, new_rdn_type=%s\n",
291                new_rdn_val, new_rdn_type, 0 );
292
293         /* Retrieve the old rdn from the entry's dn */
294
295         if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
296
297                 Debug( LDAP_DEBUG_TRACE,
298                        "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
299                        0, 0, 0 );
300                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
301                         NULL, NULL, NULL, NULL );
302                 goto return_results;            
303
304         }
305
306         if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
307             
308                 Debug( LDAP_DEBUG_TRACE,
309                        "ldbm_back_modrdn: can't figure out the old_rdn type\n",
310                        0, 0, 0 );
311                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
312                         NULL, NULL, NULL, NULL );
313                 goto return_results;            
314                 
315         }
316         
317         if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
318
319             /* Not a big deal but we may say something */
320             Debug( LDAP_DEBUG_TRACE,
321                    "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
322                    old_rdn_type, new_rdn_type, 0 );
323             
324         }               
325
326 #ifdef DNS_DN
327         if ( dn_type( old_rdn ) == DN_X500 ) {
328 #endif
329
330                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
331                        0, 0, 0 );
332
333                 /* Add new attribute value to the entry.
334                  */
335
336                 add_bvals[0] = &add_bv;         /* Array of bervals */
337                 add_bvals[1] = NULL;
338
339                 add_bv.bv_val = new_rdn_val;
340                 add_bv.bv_len = strlen(new_rdn_val);
341                 
342                 mod[0].ml_type = new_rdn_type;  
343                 mod[0].ml_bvalues = add_bvals;
344                 mod[0].ml_op = LDAP_MOD_SOFTADD;
345                 mod[0].ml_next = NULL;
346                 
347                 Debug( LDAP_DEBUG_TRACE,
348                        "ldbm_back_modrdn: adding new rdn attr val =%s\n",
349                        new_rdn_val, 0, 0 );
350                 
351                 /* Remove old rdn value if required */
352
353                 if (deleteoldrdn) {
354
355                         del_bvals[0] = &del_bv;         /* Array of bervals */
356                         del_bvals[1] = NULL;
357                         /* Get value of old rdn */
358         
359                         if ((old_rdn_val = rdn_attr_value( old_rdn ))
360                             == NULL) {
361                             
362                                 Debug( LDAP_DEBUG_TRACE,
363                                        "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
364                                        0, 0, 0 );
365                                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
366                                         NULL, NULL, NULL, NULL );
367                                 goto return_results;            
368
369
370                         }
371
372                         /* Remove old value of rdn as an attribute. */
373                     
374                         del_bv.bv_val = old_rdn_val;
375                         del_bv.bv_len = strlen(old_rdn_val);
376                         
377                         mod[0].ml_next = &mod[1];
378                         mod[1].ml_type = old_rdn_type;  
379                         mod[1].ml_bvalues = del_bvals;
380                         mod[1].ml_op = LDAP_MOD_DELETE;
381                         mod[1].ml_next = NULL;
382
383
384                         Debug( LDAP_DEBUG_TRACE,
385                                "ldbm_back_modrdn: removing old_rdn_val=%s\n",
386                                old_rdn_val, 0, 0 );
387                 
388                 }/* if (deleteoldrdn) */
389
390 #ifdef DNS_DN
391         } else {
392             
393
394                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
395                        0, 0, 0 );
396                 /* XXXV3: not sure of what to do here */
397                 Debug( LDAP_DEBUG_TRACE,
398                        "ldbm_back_modrdn: not fully implemented...\n",
399                        0, 0, 0 );  
400
401         }
402 #endif
403
404         /* modify memory copy of entry */
405         if ( bdb2i_back_modify_internal( be, conn, op, dn, &mod[0], e )
406              != 0 ) {
407             
408                 goto return_results;
409                         
410         }
411         
412         (void) bdb2i_cache_update_entry( &li->li_cache, e );
413
414         /* NOTE: after this you must not free new_dn or new_ndn!
415          * They are used by cache.
416          */
417
418         /* id2entry index */
419         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
420                 entry_free( e );
421                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
422                         NULL, NULL, NULL, NULL );
423                 goto return_results_after;
424         }
425
426         send_ldap_result( conn, op, LDAP_SUCCESS,
427                 NULL, NULL, NULL, NULL );
428         rc = 0;
429         goto return_results_after;      
430
431 return_results:
432         if( new_dn != NULL ) free( new_dn );
433         if( new_ndn != NULL ) free( new_ndn );
434
435 return_results_after:
436         /* NOTE:
437          * new_dn and new_ndn are not deallocated because they are used by
438          * the cache entry.
439          */
440         if( p_dn != NULL ) free( p_dn );
441         if( p_ndn != NULL ) free( p_ndn );
442
443         /* LDAP v2 supporting correct attribute handling. */
444         if( new_rdn_type != NULL ) free(new_rdn_type);
445         if( new_rdn_val != NULL ) free(new_rdn_val);
446         if( old_rdn != NULL ) free(old_rdn);
447         if( old_rdn_type != NULL ) free(old_rdn_type);
448         if( old_rdn_val != NULL ) free(old_rdn_val);
449
450         /* LDAP v3 Support */
451         if ( np_dn != NULL ) free( np_dn );
452         if ( np_ndn != NULL ) free( np_ndn );
453
454         if( p != NULL ) {
455                 /* free parent and writer lock */
456                 bdb2i_cache_return_entry_w( &li->li_cache, p );
457
458         }
459
460         /* free entry and writer lock */
461         bdb2i_cache_return_entry_w( &li->li_cache, e );
462         return( rc );
463 }
464
465
466 int
467 bdb2_back_modrdn(
468     BackendDB   *be,
469     Connection  *conn,
470     Operation   *op,
471     char        *dn,
472     char        *newrdn,
473     int         deleteoldrdn,
474     char        *newSuperior
475 )
476 {
477         DB_LOCK         lock;
478         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
479         struct timeval  time1;
480         int             ret;
481
482         bdb2i_start_timing( be->bd_info, &time1 );
483
484         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
485                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
486                         NULL, NULL, NULL, NULL );
487                 return( -1 );
488
489         }
490
491         ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
492                                         newrdn, deleteoldrdn,
493                                         newSuperior );
494
495         (void) bdb2i_leave_backend_w( lock );
496         bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op );
497
498         return( ret );
499 }
500
501