]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modrdn.c
expose oc_check_operational from schema.c
[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         char            *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;
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                 send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
69                 if ( matched != NULL ) {
70                         free( matched );
71                 }
72                 return( -1 );
73         }
74
75 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
76                 /* check parent for "children" acl */
77         if ( ! access_allowed( be, conn, op, e,
78                 "entry", NULL, ACL_WRITE ) )
79         {
80                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
81                         0, 0 );
82                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
83                         "", "" );
84                 goto return_results;
85         }
86 #endif
87
88         if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
89                 /* parent + rdn + separator(s) + null */
90                 if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
91                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
92                                 0, 0, 0);
93                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
94                                 "", "");
95                         goto return_results;
96                 }
97
98                 /* check parent for "children" acl */
99                 if ( ! access_allowed( be, conn, op, p,
100                         "children", NULL, ACL_WRITE ) )
101                 {
102                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
103                                 0, 0 );
104                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
105                                 "", "" );
106                         goto return_results;
107                 }
108
109                 p_dn = dn_parent( be, e->e_dn );
110
111                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: parent dn=%s\n",
112                        p_dn, 0, 0 );
113
114
115         } else {
116                 /* no parent, modrdn entry directly under root */
117                 if( ! be_isroot( be, op->o_ndn ) ) {
118                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
119                                 0, 0, 0);
120                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
121                                 "", "");
122                         goto return_results;
123                 }
124
125                 Debug( LDAP_DEBUG_TRACE,
126                        "ldbm_back_modrdn: no parent!, working on root\n",
127                        0, 0, 0 );
128
129         }
130
131         new_parent_dn = p_dn;   /* New Parent unless newSuperior given */
132
133         if ( (np_dn = newSuperior) != NULL) {
134
135
136                 Debug( LDAP_DEBUG_TRACE, 
137                        "ldbm_back_modrdn: new parent requested...\n",
138                        0, 0, 0 );
139
140                 np_ndn = dn_normalize_case( ch_strdup( np_dn ) );
141
142                 /* newSuperior == oldParent?, if so ==> ERROR */
143
144                 /* newSuperior == entry being moved?, if so ==> ERROR */
145
146                 /* Get Entry with dn=newSuperior. Does newSuperior exist? */
147
148                 if( (np = bdb2i_dn2entry_w( be, np_ndn, &matched )) == NULL) {
149
150                         Debug( LDAP_DEBUG_TRACE,
151                                "ldbm_back_modrdn: newSup(ndn=%s) not here!\n",
152                                np_ndn, 0, 0);
153                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "",
154                                           "");
155                         goto return_results;
156                 }
157
158                 Debug( LDAP_DEBUG_TRACE,
159                        "ldbm_back_modrdn: wr to new parent OK np=%p, id=%d\n",
160                        np, np->e_id, 0 );
161             
162                 /* check newSuperior for "children" acl */
163                 if ( !access_allowed( be, conn, op, np, "children", NULL,
164                                       ACL_WRITE ) )
165                 {
166                         Debug( LDAP_DEBUG_TRACE,
167                                "ldbm_back_modrdn: no wr to newSup children\n",
168                                0, 0, 0 );
169                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
170                                           "", "" );
171                         goto return_results;
172                 }
173
174                 Debug( LDAP_DEBUG_TRACE,
175                        "ldbm_back_modrdn: wr to new parent's children OK\n",
176                        0, 0 , 0 );
177
178
179                 new_parent_dn = np_dn;
180
181         }
182         
183         /* Build target dn and make sure target entry doesn't exist already. */
184
185         build_new_dn( &new_dn, e->e_dn, new_parent_dn, newrdn ); 
186
187
188         new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
189
190         Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: new ndn=%s\n",
191                new_ndn, 0, 0 );
192
193         if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
194                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
195                 goto return_results;
196         }
197
198         /* check for abandon */
199         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
200         if ( op->o_abandon ) {
201                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
202                 goto return_results;
203         }
204         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
205
206         /* delete old one */
207         if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
208                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
209                 goto return_results;
210         }
211
212         (void) bdb2i_cache_delete_entry( &li->li_cache, e );
213         free( e->e_dn );
214         free( e->e_ndn );
215         e->e_dn = new_dn;
216         e->e_ndn = new_ndn;
217
218
219         /* add new one */
220         if ( bdb2i_dn2id_add( be,  e->e_ndn, e->e_id ) != 0 ) {
221                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
222                 goto return_results;
223         }
224
225         /* Get attribute type and attribute value of our new rdn, we will
226          * need to add that to our new entry
227          */
228
229         if ( (new_rdn_type = rdn_attr_type( newrdn )) == NULL ) {
230             
231                 Debug( LDAP_DEBUG_TRACE,
232                        "ldbm_back_modrdn: can't figure out type of newrdn\n",
233                        0, 0, 0 );
234                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
235                 goto return_results;            
236
237         }
238
239         if ( (new_rdn_val = rdn_attr_value( newrdn )) == NULL ) {
240             
241                 Debug( LDAP_DEBUG_TRACE,
242                        "ldbm_back_modrdn: can't figure out val of newrdn\n",
243                        0, 0, 0 );
244                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
245                 goto return_results;            
246
247         }
248
249         Debug( LDAP_DEBUG_TRACE,
250                "ldbm_back_modrdn: new_rdn_val=%s, new_rdn_type=%s\n",
251                new_rdn_val, new_rdn_type, 0 );
252
253         /* Retrieve the old rdn from the entry's dn */
254
255         if ( (old_rdn = dn_rdn( be, dn )) == NULL ) {
256
257                 Debug( LDAP_DEBUG_TRACE,
258                        "ldbm_back_modrdn: can't figure out old_rdn from dn\n",
259                        0, 0, 0 );
260                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
261                 goto return_results;            
262
263         }
264
265         if ( (old_rdn_type = rdn_attr_type( old_rdn )) == NULL ) {
266             
267                 Debug( LDAP_DEBUG_TRACE,
268                        "ldbm_back_modrdn: can't figure out the old_rdn type\n",
269                        0, 0, 0 );
270                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
271                 goto return_results;            
272                 
273         }
274         
275         if ( strcasecmp( old_rdn_type, new_rdn_type ) != 0 ) {
276
277             /* Not a big deal but we may say something */
278             Debug( LDAP_DEBUG_TRACE,
279                    "ldbm_back_modrdn: old_rdn_type=%s, new_rdn_type=%s!\n",
280                    old_rdn_type, new_rdn_type, 0 );
281             
282         }               
283
284         if ( dn_type( old_rdn ) == DN_X500 ) {
285
286                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DN_X500\n",
287                        0, 0, 0 );
288
289                 /* Add new attribute value to the entry.
290                  */
291
292                 add_bvals[0] = &add_bv;         /* Array of bervals */
293                 add_bvals[1] = NULL;
294
295                 add_bv.bv_val = new_rdn_val;
296                 add_bv.bv_len = strlen(new_rdn_val);
297                 
298                 mod[0].ml_type = new_rdn_type;  
299                 mod[0].ml_bvalues = add_bvals;
300                 mod[0].ml_op = LDAP_MOD_SOFTADD;
301                 mod[0].ml_next = NULL;
302                 
303                 Debug( LDAP_DEBUG_TRACE,
304                        "ldbm_back_modrdn: adding new rdn attr val =%s\n",
305                        new_rdn_val, 0, 0 );
306                 
307                 /* Remove old rdn value if required */
308
309                 if (deleteoldrdn) {
310
311                         del_bvals[0] = &del_bv;         /* Array of bervals */
312                         del_bvals[1] = NULL;
313                         /* Get value of old rdn */
314         
315                         if ((old_rdn_val = rdn_attr_value( old_rdn ))
316                             == NULL) {
317                             
318                                 Debug( LDAP_DEBUG_TRACE,
319                                        "ldbm_back_modrdn: can't figure out old_rdn_val from old_rdn\n",
320                                        0, 0, 0 );
321                                 send_ldap_result( conn, op,
322                                                   LDAP_OPERATIONS_ERROR,
323                                                   "", "" );
324                                 goto return_results;            
325
326
327                         }
328
329                         /* Remove old value of rdn as an attribute. */
330                     
331                         del_bv.bv_val = old_rdn_val;
332                         del_bv.bv_len = strlen(old_rdn_val);
333                         
334                         mod[0].ml_next = &mod[1];
335                         mod[1].ml_type = old_rdn_type;  
336                         mod[1].ml_bvalues = del_bvals;
337                         mod[1].ml_op = LDAP_MOD_DELETE;
338                         mod[1].ml_next = NULL;
339
340
341                         Debug( LDAP_DEBUG_TRACE,
342                                "ldbm_back_modrdn: removing old_rdn_val=%s\n",
343                                old_rdn_val, 0, 0 );
344                 
345                 }/* if (deleteoldrdn) */
346
347         } else {
348             
349
350                 Debug( LDAP_DEBUG_TRACE, "ldbm_back_modrdn: DNS DN\n",
351                        0, 0, 0 );
352                 /* XXXV3: not sure of what to do here */
353                 Debug( LDAP_DEBUG_TRACE,
354                        "ldbm_back_modrdn: not fully implemented...\n",
355                        0, 0, 0 );  
356
357         }
358
359         /* modify memory copy of entry */
360         if ( bdb2i_back_modify_internal( be, conn, op, dn, &mod[0], e )
361              != 0 ) {
362             
363                 goto return_results;
364                         
365         }
366         
367         (void) bdb2i_cache_update_entry( &li->li_cache, e );
368
369         /* NOTE: after this you must not free new_dn or new_ndn!
370          * They are used by cache.
371          */
372
373         /* id2entry index */
374         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
375                 entry_free( e );
376                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
377                 goto return_results_after;
378         }
379
380         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
381         rc = 0;
382         goto return_results_after;      
383
384 return_results:
385         if( new_dn != NULL ) free( new_dn );
386         if( new_ndn != NULL ) free( new_ndn );
387 return_results_after:
388         /* NOTE:
389          * new_dn and new_ndn are not deallocated because they are used by
390          * the cache entry.
391          */
392         if( p_dn != NULL ) free( p_dn );
393         if( p_ndn != NULL ) free( p_ndn );
394
395         if( matched != NULL ) free( matched );
396
397         /* LDAP v2 supporting correct attribute handling. */
398         if( new_rdn_type != NULL ) free(new_rdn_type);
399         if( new_rdn_val != NULL ) free(new_rdn_val);
400         if( old_rdn != NULL ) free(old_rdn);
401         if( old_rdn_type != NULL ) free(old_rdn_type);
402         if( old_rdn_val != NULL ) free(old_rdn_val);
403
404         /* LDAP v3 Support */
405         if ( np_dn != NULL ) free( np_dn );
406         if ( np_ndn != NULL ) free( np_ndn );
407
408         if( p != NULL ) {
409                 /* free parent and writer lock */
410                 bdb2i_cache_return_entry_w( &li->li_cache, p );
411
412         }
413
414         /* free entry and writer lock */
415         bdb2i_cache_return_entry_w( &li->li_cache, e );
416         return( rc );
417 }
418
419
420 int
421 bdb2_back_modrdn(
422     BackendDB   *be,
423     Connection  *conn,
424     Operation   *op,
425     char        *dn,
426     char        *newrdn,
427     int         deleteoldrdn,
428     char        *newSuperior
429 )
430 {
431         DB_LOCK         lock;
432         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
433         struct timeval  time1;
434         int             ret;
435
436         bdb2i_start_timing( be->bd_info, &time1 );
437
438         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
439
440                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
441                 return( -1 );
442
443         }
444
445         ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
446                                         newrdn, deleteoldrdn,
447                                         newSuperior );
448
449         (void) bdb2i_leave_backend_w( lock );
450         bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op );
451
452         return( ret );
453 }
454
455