1/* $OpenLDAP$ */ 2/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 3 * 4 * Copyright 1999-2011 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 34int 35meta_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 ldap_back_send_t retrying = LDAP_BACK_RETRYING; 46 LDAPControl **ctrls = NULL; 47 struct berval newrdn = BER_BVNULL; 48 49 mc = meta_back_getconn( op, rs, &candidate, LDAP_BACK_SENDERR ); 50 if ( !mc || !meta_back_dobind( op, rs, mc, LDAP_BACK_SENDERR ) ) { 51 return rs->sr_err; 52 } 53 54 assert( mc->mc_conns[ candidate ].msc_ld != NULL ); 55 56 mt = mi->mi_targets[ candidate ]; 57 dc.target = mt; 58 dc.conn = op->o_conn; 59 dc.rs = rs; 60 61 if ( op->orr_newSup ) { 62 63 /* 64 * NOTE: the newParent, if defined, must be on the 65 * same target as the entry to be renamed. This check 66 * has been anticipated in meta_back_getconn() 67 */ 68 /* 69 * FIXME: one possibility is to delete the entry 70 * from one target and add it to the other; 71 * unfortunately we'd need write access to both, 72 * which is nearly impossible; for administration 73 * needs, the rootdn of the metadirectory could 74 * be mapped to an administrative account on each 75 * target (the binddn?); we'll see. 76 */ 77 /* 78 * NOTE: we need to port the identity assertion 79 * feature from back-ldap 80 */ 81 82 /* needs LDAPv3 */ 83 switch ( mt->mt_version ) { 84 case LDAP_VERSION3: 85 break; 86 87 case 0: 88 if ( op->o_protocol == 0 || op->o_protocol == LDAP_VERSION3 ) { 89 break; 90 } 91 /* fall thru */ 92 93 default: 94 /* op->o_protocol cannot be anything but LDAPv3, 95 * otherwise wouldn't be here */ 96 rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 97 send_ldap_result( op, rs ); 98 goto cleanup; 99 } 100 101 /* 102 * Rewrite the new superior, if defined and required 103 */ 104 dc.ctx = "newSuperiorDN"; 105 if ( ldap_back_dn_massage( &dc, op->orr_newSup, &mnewSuperior ) ) { 106 rs->sr_err = LDAP_OTHER; 107 send_ldap_result( op, rs ); 108 goto cleanup; 109 } 110 } 111 112 /* 113 * Rewrite the modrdn dn, if required 114 */ 115 dc.ctx = "modrDN"; 116 if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) { 117 rs->sr_err = LDAP_OTHER; 118 send_ldap_result( op, rs ); 119 goto cleanup; 120 } 121 122 /* NOTE: we need to copy the newRDN in case it was formed 123 * from a DN by simply changing the length (ITS#5397) */ 124 newrdn = op->orr_newrdn; 125 if ( newrdn.bv_val[ newrdn.bv_len ] != '\0' ) { 126 ber_dupbv_x( &newrdn, &op->orr_newrdn, op->o_tmpmemctx ); 127 } 128 129retry:; 130 ctrls = op->o_ctrls; 131 if ( meta_back_controls_add( op, rs, mc, candidate, &ctrls ) != LDAP_SUCCESS ) 132 { 133 send_ldap_result( op, rs ); 134 goto cleanup; 135 } 136 137 rs->sr_err = ldap_rename( mc->mc_conns[ candidate ].msc_ld, 138 mdn.bv_val, newrdn.bv_val, 139 mnewSuperior.bv_val, op->orr_deleteoldrdn, 140 ctrls, NULL, &msgid ); 141 rs->sr_err = meta_back_op_result( mc, op, rs, candidate, msgid, 142 mt->mt_timeout[ SLAP_OP_MODRDN ], ( LDAP_BACK_SENDRESULT | retrying ) ); 143 if ( rs->sr_err == LDAP_UNAVAILABLE && retrying ) { 144 retrying &= ~LDAP_BACK_RETRYING; 145 if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) { 146 /* if the identity changed, there might be need to re-authz */ 147 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); 148 goto retry; 149 } 150 } 151 152cleanup:; 153 (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls ); 154 155 if ( mdn.bv_val != op->o_req_dn.bv_val ) { 156 free( mdn.bv_val ); 157 BER_BVZERO( &mdn ); 158 } 159 160 if ( !BER_BVISNULL( &mnewSuperior ) 161 && mnewSuperior.bv_val != op->orr_newSup->bv_val ) 162 { 163 free( mnewSuperior.bv_val ); 164 BER_BVZERO( &mnewSuperior ); 165 } 166 167 if ( newrdn.bv_val != op->orr_newrdn.bv_val ) { 168 op->o_tmpfree( newrdn.bv_val, op->o_tmpmemctx ); 169 } 170 171 if ( mc ) { 172 meta_back_release_conn( mi, mc ); 173 } 174 175 return rs->sr_err; 176} 177 178