]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb2/modrdn.c
Round 2 of connection management changes.
[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
46         /* get entry with writer lock */
47         if ( (e = bdb2i_dn2entry_w( be, dn, &matched )) == NULL ) {
48                 send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
49                 if ( matched != NULL ) {
50                         free( matched );
51                 }
52                 return( -1 );
53         }
54
55 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
56                 /* check parent for "children" acl */
57         if ( ! access_allowed( be, conn, op, e,
58                 "entry", NULL, ACL_WRITE ) )
59         {
60                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
61                         0, 0 );
62                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
63                         "", "" );
64                 goto return_results;
65         }
66 #endif
67
68         if ( (p_ndn = dn_parent( be, e->e_ndn )) != NULL ) {
69                 /* parent + rdn + separator(s) + null */
70                 if( (p = bdb2i_dn2entry_w( be, p_ndn, &matched )) == NULL) {
71                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
72                                 0, 0, 0);
73                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
74                                 "", "");
75                         goto return_results;
76                 }
77
78 #ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
79                 /* check parent for "children" acl */
80                 if ( ! access_allowed( be, conn, op, p,
81                         "children", NULL, ACL_WRITE ) )
82                 {
83                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
84                                 0, 0 );
85                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
86                                 "", "" );
87                         goto return_results;
88                 }
89 #endif
90
91                 p_dn = dn_parent( be, e->e_dn );
92                 new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn )
93                     + 3 );
94                 if ( dn_type( e->e_dn ) == DN_X500 ) {
95                         strcpy( new_dn, newrdn );
96                         strcat( new_dn, "," );
97                         strcat( new_dn, p_dn );
98                 } else {
99                         char *s;
100                         strcpy( new_dn, newrdn );
101                         s = strchr( newrdn, '\0' );
102                         s--;
103                         if ( *s != '.' && *s != '@' ) {
104                                 if ( (s = strpbrk( dn, ".@" )) != NULL ) {
105                                         sep[0] = *s;
106                                         sep[1] = '\0';
107                                         strcat( new_dn, sep );
108                                 }
109                         }
110                         strcat( new_dn, p_dn );
111                 }
112
113         } else {
114                 /* no parent, modrdn entry directly under root */
115                 if( ! be_isroot( be, op->o_ndn ) ) {
116                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
117                                 0, 0, 0);
118                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
119                                 "", "");
120                         goto return_results;
121                 }
122
123                 new_dn = ch_strdup( newrdn );
124         }
125
126         new_ndn = dn_normalize_case( ch_strdup( new_dn ) );
127
128         if ( (bdb2i_dn2id ( be, new_ndn ) ) != NOID ) {
129                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
130                 goto return_results;
131         }
132
133         /* check for abandon */
134         ldap_pvt_thread_mutex_lock( &op->o_abandonmutex );
135         if ( op->o_abandon ) {
136                 ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
137                 goto return_results;
138         }
139         ldap_pvt_thread_mutex_unlock( &op->o_abandonmutex );
140
141         /* add new one */
142         if ( bdb2i_dn2id_add( be, new_ndn, e->e_id ) != 0 ) {
143                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
144                 goto return_results;
145         }
146
147         /* delete old one */
148         if ( bdb2i_dn2id_delete( be, e->e_ndn ) != 0 ) {
149                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
150                 goto return_results;
151         }
152
153         (void) bdb2i_cache_delete_entry( &li->li_cache, e );
154         free( e->e_dn );
155         free( e->e_ndn );
156         e->e_dn = new_dn;
157         e->e_ndn = new_ndn;
158         (void) bdb2i_cache_update_entry( &li->li_cache, e );
159
160         /*
161          * At some point here we need to update the attribute values in
162          * the entry itself that were effected by this RDN change
163          * (respecting the value of the deleteoldrdn parameter).
164          *
165          * Since the code to do this has not yet been written, treat this
166          * omission as a (documented) bug.
167          */
168
169         /* id2entry index */
170         if ( bdb2i_id2entry_add( be, e ) != 0 ) {
171                 entry_free( e );
172                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
173                 goto return_results;
174         }
175
176         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
177         rc = 0;
178
179 return_results:
180         if( new_dn != NULL ) free( new_dn );
181         if( new_ndn != NULL ) free( new_ndn );
182         if( p_dn != NULL ) free( p_dn );
183         if( p_ndn != NULL ) free( p_ndn );
184
185         if( matched != NULL ) free( matched );
186
187         if( p != NULL ) {
188                 /* free parent and writer lock */
189                 bdb2i_cache_return_entry_w( &li->li_cache, p );
190
191         }
192
193         /* free entry and writer lock */
194         bdb2i_cache_return_entry_w( &li->li_cache, e );
195         return( rc );
196 }
197
198
199 int
200 bdb2_back_modrdn(
201     BackendDB   *be,
202     Connection  *conn,
203     Operation   *op,
204     char        *dn,
205     char        *newrdn,
206     int         deleteoldrdn,
207     char        *newSuperior
208 )
209 {
210         DB_LOCK         lock;
211         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
212         struct timeval  time1;
213         int             ret;
214
215         bdb2i_start_timing( be->bd_info, &time1 );
216
217         if ( bdb2i_enter_backend_w( &lock ) != 0 ) {
218
219                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
220                 return( -1 );
221
222         }
223
224         ret = bdb2i_back_modrdn_internal( be, conn, op, dn,
225                                         newrdn, deleteoldrdn,
226                                         newSuperior );
227
228         (void) bdb2i_leave_backend_w( lock );
229         bdb2i_stop_timing( be->bd_info, time1, "MODRDN", conn, op );
230
231         return( ret );
232 }
233
234