]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldbm/modrdn.c
Import ACL/parent locking changes from devel but define
[openldap] / servers / slapd / back-ldbm / modrdn.c
1 /* modrdn.c - ldbm backend modrdn routine */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/string.h>
8 #include <ac/socket.h>
9
10 #include "slap.h"
11 #include "back-ldbm.h"
12 #include "proto-back-ldbm.h"
13
14 int
15 ldbm_back_modrdn(
16     Backend     *be,
17     Connection  *conn,
18     Operation   *op,
19     char        *dn,
20     char        *newrdn,
21     int         deleteoldrdn
22 )
23 {
24         struct ldbminfo *li = (struct ldbminfo *) be->be_private;
25         char            *matched = NULL;
26         char            *pdn = NULL, *newdn = NULL;
27         char            sep[2];
28         Entry           *e, *p = NULL;
29         int                     rootlock = 0;
30         int                     rc = -1;
31
32         /* get entry with writer lock */
33         if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
34                 send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
35                 if ( matched != NULL ) {
36                         free( matched );
37                 }
38                 return( -1 );
39         }
40
41 #define SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL 1
42 #ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
43                 /* check parent for "children" acl */
44         if ( ! access_allowed( be, conn, op, e, "entry", NULL,
45                 op->o_dn, ACL_WRITE ) )
46         {
47                 Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
48                         0, 0 );
49                 send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
50                         "", "" );
51                 goto return_results;
52         }
53 #endif
54
55         if ( (pdn = dn_parent( be, dn )) != NULL ) {
56                 /* parent + rdn + separator(s) + null */
57                 if( (p = dn2entry_w( be, pdn, &matched )) == NULL) {
58                         Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
59                                 0, 0, 0);
60                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
61                                 "", "");
62                         goto return_results;
63                 }
64
65 #ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
66                 /* check parent for "children" acl */
67                 if ( ! access_allowed( be, conn, op, p, "children", NULL,
68                         op->o_dn, ACL_WRITE ) )
69                 {
70                         Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
71                                 0, 0 );
72                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
73                                 "", "" );
74                         goto return_results;
75                 }
76 #endif
77
78                 newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn )
79                     + 3 );
80                 if ( dn_type( dn ) == DN_X500 ) {
81                         strcpy( newdn, newrdn );
82                         strcat( newdn, ", " );
83                         strcat( newdn, pdn );
84                 } else {
85                         char *s;
86                         strcpy( newdn, newrdn );
87                         s = strchr( newrdn, '\0' );
88                         s--;
89                         if ( *s != '.' && *s != '@' ) {
90                                 if ( (s = strpbrk( dn, ".@" )) != NULL ) {
91                                         sep[0] = *s;
92                                         sep[1] = '\0';
93                                         strcat( newdn, sep );
94                                 }
95                         }
96                         strcat( newdn, pdn );
97                 }
98         } else {
99                 /* no parent, modrdn entry directly under root */
100                 if( ! be_isroot( be, op->o_dn ) ) {
101                         Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
102                                 0, 0, 0);
103                         send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
104                                 "", "");
105                         goto return_results;
106                 }
107
108                 pthread_mutex_lock(&li->li_root_mutex);
109                 rootlock = 1;
110
111                 newdn = ch_strdup( newrdn );
112         }
113
114         (void) dn_normalize( newdn );
115
116         if ( (dn2id ( be, newdn ) ) != NOID ) {
117                 send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
118                 goto return_results;
119         }
120
121         /* check for abandon */
122         pthread_mutex_lock( &op->o_abandonmutex );
123         if ( op->o_abandon ) {
124                 pthread_mutex_unlock( &op->o_abandonmutex );
125                 goto return_results;
126         }
127         pthread_mutex_unlock( &op->o_abandonmutex );
128
129         /* add new one */
130         if ( dn2id_add( be, newdn, e->e_id ) != 0 ) {
131                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
132                 goto return_results;
133         }
134
135         /* delete old one */
136         if ( dn2id_delete( be, dn ) != 0 ) {
137                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
138                 goto return_results;
139         }
140
141         (void) cache_delete_entry( &li->li_cache, e );
142         free( e->e_dn );
143         e->e_dn = newdn;
144
145         /* XXX
146          * At some point here we need to update the attribute values in
147          * the entry itself that were effected by this RDN change
148          * (respecting the value of the deleteoldrdn parameter).
149          *
150          * Since the code to do this has not yet been written, treat this
151          * omission as a (documented) bug.
152          */
153
154         /* id2entry index */
155         if ( id2entry_add( be, e ) != 0 ) {
156                 entry_free( e );
157                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
158                 goto return_results;
159         }
160
161         send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
162         rc = 0;
163
164 return_results:
165         if( newdn != NULL ) free( newdn );
166         if( pdn != NULL ) free( pdn );
167         if( matched != NULL ) free( matched );
168
169         if( p != NULL ) {
170                 /* free parent and writer lock */
171                 cache_return_entry_w( &li->li_cache, p );
172
173         } else if ( rootlock ) {
174                 /* release root writer lock */
175                 pthread_mutex_unlock(&li->li_root_mutex);
176         }
177
178         /* free entry and writer lock */
179         cache_return_entry_w( &li->li_cache, e );
180         return( rc );
181 }