]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/modrdn.c
Happy new year! (belated)
[openldap] / servers / slapd / back-meta / modrdn.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2008 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26
27 #include <ac/socket.h>
28 #include <ac/string.h>
29
30 #include "slap.h"
31 #include "../back-ldap/back-ldap.h"
32 #include "back-meta.h"
33
34 int
35 meta_back_modrdn( Operation *op, SlapReply *rs )
36 {
37         metainfo_t      *mi = ( metainfo_t * )op->o_bd->be_private;
38         metatarget_t    *mt;
39         metaconn_t      *mc;
40         int             candidate = -1;
41         struct berval   mdn = BER_BVNULL,
42                         mnewSuperior = BER_BVNULL;
43         dncookie        dc;
44         int             msgid;
45         int             do_retry = 1;
46         LDAPControl     **ctrls = NULL;
47
48         mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR );
49         if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) {
50                 return rs->sr_err;
51         }
52
53         assert( mc->mc_conns[ candidate ].msc_ld != NULL );
54
55         mt = mi->mi_targets[ candidate ];
56         dc.target = mt;
57         dc.conn = op->o_conn;
58         dc.rs = rs;
59
60         if ( op->orr_newSup ) {
61
62                 /*
63                  * NOTE: the newParent, if defined, must be on the 
64                  * same target as the entry to be renamed.  This check
65                  * has been anticipated in meta_back_getconn()
66                  */
67                 /*
68                  * FIXME: one possibility is to delete the entry
69                  * from one target and add it to the other;
70                  * unfortunately we'd need write access to both,
71                  * which is nearly impossible; for administration
72                  * needs, the rootdn of the metadirectory could
73                  * be mapped to an administrative account on each
74                  * target (the binddn?); we'll see.
75                  */
76                 /*
77                  * NOTE: we need to port the identity assertion
78                  * feature from back-ldap
79                  */
80
81                 /* needs LDAPv3 */
82                 switch ( mt->mt_version ) {
83                 case LDAP_VERSION3:
84                         break;
85
86                 case 0:
87                         if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) {
88                                 break;
89                         }
90                         /* fall thru */
91
92                 default:
93                         /* op->o_protocol cannot be anything but LDAPv3,
94                          * otherwise wouldn't be here */
95                         rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
96                         send_ldap_result( op, rs );
97                         goto cleanup;
98                 }
99                 
100                 /*
101                  * Rewrite the new superior, if defined and required
102                  */
103                 dc.ctx = "newSuperiorDN";
104                 if ( ldap_back_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) {
105                         rs->sr_err = LDAP_OTHER;
106                         send_ldap_result( op, rs );
107                         goto cleanup;
108                 }
109         }
110
111         /*
112          * Rewrite the modrdn dn, if required
113          */
114         dc.ctx = "modrDN";
115         if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
116                 rs->sr_err = LDAP_OTHER;
117                 send_ldap_result( op, rs );
118                 goto cleanup;
119         }
120
121 retry:;
122         ctrls = op->o_ctrls;
123         if ( ldap_back_proxy_authz_ctrl( &mc->mc_conns[ candidate ].msc_bound_ndn,
124                 mt->mt_version, &mt->mt_idassert, op, rs, &ctrls ) != LDAP_SUCCESS )
125         {
126                 send_ldap_result( op, rs );
127                 goto cleanup;
128         }
129
130         rs->sr_err = ldap_rename( mc->mc_conns[ candidate ].msc_ld,
131                         mdn.bv_val, op->orr_newrdn.bv_val,
132                         mnewSuperior.bv_val, op->orr_deleteoldrdn,
133                         ctrls, NULL, &msgid );
134         rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid,
135                 mt->mt_timeout[ SLAP_OP_MODRDN ], LDAP_BACK_SENDRESULT );
136         if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
137                 do_retry = 0;
138                 if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
139                         /* if the identity changed, there might be need to re-authz */
140                         (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
141                         goto retry;
142                 }
143         }
144
145 cleanup:;
146         (void)ldap_back_proxy_authz_ctrl_free( op, &ctrls );
147
148         if ( mdn.bv_val != op->o_req_dn.bv_val ) {
149                 free( mdn.bv_val );
150                 BER_BVZERO( &mdn );
151         }
152         
153         if ( !BER_BVISNULL( &mnewSuperior )
154                         && mnewSuperior.bv_val != op->orr_newSup->bv_val )
155         {
156                 free( mnewSuperior.bv_val );
157                 BER_BVZERO( &mnewSuperior );
158         }
159
160         if ( mc ) {
161                 meta_back_release_conn( mi, mc );
162         }
163
164         return rs->sr_err;
165 }
166