modrdn.c 4.23 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* modrdn.c - ldbm backend modrdn routine */

3
4
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
#include <stdio.h>
6
7
8
9

#include <ac/string.h>
#include <ac/socket.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
11
#include "slap.h"
#include "back-ldbm.h"
12
#include "proto-back-ldbm.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
13
14
15
16
17
18
19
20
21
22
23
24

int
ldbm_back_modrdn(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
    char	*dn,
    char	*newrdn,
    int		deleteoldrdn
)
{
	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
25
26
	char		*matched = NULL;
	char		*pdn = NULL, *newdn = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
27
	char		sep[2];
28
29
30
	Entry		*e, *p = NULL;
	int			rootlock = 0;
	int			rc = -1;
31
32
33

	/* get entry with writer lock */
	if ( (e = dn2entry_w( be, dn, &matched )) == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
36
37
38
39
40
		send_ldap_result( conn, op, LDAP_NO_SUCH_OBJECT, matched, "" );
		if ( matched != NULL ) {
			free( matched );
		}
		return( -1 );
	}

41
42
43
44
45
46
47
48
49
50
51
52
53
#ifdef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
		/* check parent for "children" acl */
	if ( ! access_allowed( be, conn, op, e, "entry", NULL,
		op->o_dn, ACL_WRITE ) )
	{
		Debug( LDAP_DEBUG_TRACE, "no access to entry\n", 0,
			0, 0 );
		send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
			"", "" );
		goto return_results;
	}
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
54
55
	if ( (pdn = dn_parent( be, dn )) != NULL ) {
		/* parent + rdn + separator(s) + null */
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
		if( (p = dn2entry_w( be, pdn, &matched )) == NULL) {
			Debug( LDAP_DEBUG_TRACE, "parent does not exist\n",
				0, 0, 0);
			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
				"", "");
			goto return_results;
		}

#ifndef SLAPD_CHILD_MODIFICATION_WITH_ENTRY_ACL
		/* check parent for "children" acl */
		if ( ! access_allowed( be, conn, op, p, "children", NULL,
			op->o_dn, ACL_WRITE ) )
		{
			Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,
				0, 0 );
			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
				"", "" );
			goto return_results;
		}
#endif

Kurt Zeilenga's avatar
Kurt Zeilenga committed
77
78
79
80
81
82
83
		newdn = (char *) ch_malloc( strlen( pdn ) + strlen( newrdn )
		    + 3 );
		if ( dn_type( dn ) == DN_X500 ) {
			strcpy( newdn, newrdn );
			strcat( newdn, ", " );
			strcat( newdn, pdn );
		} else {
84
			char *s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
85
			strcpy( newdn, newrdn );
86
87
88
89
90
			s = strchr( newrdn, '\0' );
			s--;
			if ( *s != '.' && *s != '@' ) {
				if ( (s = strpbrk( dn, ".@" )) != NULL ) {
					sep[0] = *s;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
91
92
93
94
95
96
97
					sep[1] = '\0';
					strcat( newdn, sep );
				}
			}
			strcat( newdn, pdn );
		}
	} else {
98
99
100
101
102
103
104
105
106
107
108
109
		/* no parent, modrdn entry directly under root */
		if( ! be_isroot( be, op->o_dn ) ) {
			Debug( LDAP_DEBUG_TRACE, "no parent & not root\n",
				0, 0, 0);
			send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
				"", "");
			goto return_results;
		}

		pthread_mutex_lock(&li->li_root_mutex);
		rootlock = 1;

110
		newdn = ch_strdup( newrdn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
111
	}
112

Kurt Zeilenga's avatar
Kurt Zeilenga committed
113
114
	(void) dn_normalize( newdn );

115
	if ( (dn2id ( be, newdn ) ) != NOID ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
116
		send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, NULL, NULL );
117
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
118
119
120
121
122
123
	}

	/* check for abandon */
	pthread_mutex_lock( &op->o_abandonmutex );
	if ( op->o_abandon ) {
		pthread_mutex_unlock( &op->o_abandonmutex );
124
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
126
127
128
129
130
	}
	pthread_mutex_unlock( &op->o_abandonmutex );

	/* add new one */
	if ( dn2id_add( be, newdn, e->e_id ) != 0 ) {
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
131
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
132
133
134
135
136
	}

	/* delete old one */
	if ( dn2id_delete( be, dn ) != 0 ) {
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL, NULL );
137
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
	}

	(void) cache_delete_entry( &li->li_cache, e );
	free( e->e_dn );
	e->e_dn = newdn;

	/* XXX
	 * At some point here we need to update the attribute values in
	 * the entry itself that were effected by this RDN change
	 * (respecting the value of the deleteoldrdn parameter).
	 *
	 * Since the code to do this has not yet been written, treat this
	 * omission as a (documented) bug.
	 */

	/* id2entry index */
	if ( id2entry_add( be, e ) != 0 ) {
		entry_free( e );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", "" );
157
		goto return_results;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
158
	}
159

Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
	send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
161
162
163
164
165
166
	rc = 0;

return_results:
	if( newdn != NULL ) free( newdn );
	if( pdn != NULL ) free( pdn );
	if( matched != NULL ) free( matched );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
167

168
169
170
	if( p != NULL ) {
		/* free parent and writer lock */
		cache_return_entry_w( &li->li_cache, p );
171
	}
172

173
	if ( rootlock ) {
174
175
176
		/* release root writer lock */
		pthread_mutex_unlock(&li->li_root_mutex);
	}
177
178
179

	/* free entry and writer lock */
	cache_return_entry_w( &li->li_cache, e );
180
	return( rc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
181
}