1/* 2 ldb database library 3 4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006-2007 5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21/* 22 * Name: ldb 23 * 24 * Component: ldb subtree rename module 25 * 26 * Description: Rename a subtree in LDB 27 * 28 * Author: Andrew Bartlett 29 */ 30 31#include "ldb_module.h" 32 33struct subren_msg_store { 34 struct subren_msg_store *next; 35 struct ldb_dn *olddn; 36 struct ldb_dn *newdn; 37}; 38 39struct subtree_rename_context { 40 struct ldb_module *module; 41 struct ldb_request *req; 42 43 struct subren_msg_store *list; 44 struct subren_msg_store *current; 45}; 46 47static struct subtree_rename_context *subren_ctx_init(struct ldb_module *module, 48 struct ldb_request *req) 49{ 50 struct ldb_context *ldb; 51 struct subtree_rename_context *ac; 52 53 ldb = ldb_module_get_ctx(module); 54 55 ac = talloc_zero(req, struct subtree_rename_context); 56 if (ac == NULL) { 57 ldb_oom(ldb); 58 return NULL; 59 } 60 61 ac->module = module; 62 ac->req = req; 63 64 return ac; 65} 66 67static int subtree_rename_next_request(struct subtree_rename_context *ac); 68 69static int subtree_rename_callback(struct ldb_request *req, 70 struct ldb_reply *ares) 71{ 72 struct ldb_context *ldb; 73 struct subtree_rename_context *ac; 74 int ret; 75 76 ac = talloc_get_type(req->context, struct subtree_rename_context); 77 ldb = ldb_module_get_ctx(ac->module); 78 79 if (!ares) { 80 return ldb_module_done(ac->req, NULL, NULL, 81 LDB_ERR_OPERATIONS_ERROR); 82 } 83 84 if (ares->error != LDB_SUCCESS) { 85 return ldb_module_done(ac->req, ares->controls, 86 ares->response, ares->error); 87 } 88 89 if (ares->type != LDB_REPLY_DONE) { 90 ldb_set_errstring(ldb, "Invalid reply type!\n"); 91 return ldb_module_done(ac->req, NULL, NULL, 92 LDB_ERR_OPERATIONS_ERROR); 93 } 94 95 if (ac->current == NULL) { 96 /* this was the last one */ 97 return ldb_module_done(ac->req, ares->controls, 98 ares->response, LDB_SUCCESS); 99 } 100 101 ret = subtree_rename_next_request(ac); 102 if (ret != LDB_SUCCESS) { 103 return ldb_module_done(ac->req, NULL, NULL, ret); 104 } 105 106 talloc_free(ares); 107 return LDB_SUCCESS; 108} 109 110static int subtree_rename_next_request(struct subtree_rename_context *ac) 111{ 112 struct ldb_context *ldb; 113 struct ldb_request *req; 114 int ret; 115 116 ldb = ldb_module_get_ctx(ac->module); 117 118 if (ac->current == NULL) { 119 return LDB_ERR_OPERATIONS_ERROR; 120 } 121 122 ret = ldb_build_rename_req(&req, ldb, ac->current, 123 ac->current->olddn, 124 ac->current->newdn, 125 ac->req->controls, 126 ac, subtree_rename_callback, 127 ac->req); 128 if (ret != LDB_SUCCESS) { 129 return ret; 130 } 131 132 ac->current = ac->current->next; 133 134 return ldb_next_request(ac->module, req); 135} 136 137static int subtree_rename_search_callback(struct ldb_request *req, 138 struct ldb_reply *ares) 139{ 140 struct subren_msg_store *store; 141 struct subtree_rename_context *ac; 142 int ret; 143 144 ac = talloc_get_type(req->context, struct subtree_rename_context); 145 146 if (!ares || !ac->current) { 147 return ldb_module_done(ac->req, NULL, NULL, 148 LDB_ERR_OPERATIONS_ERROR); 149 } 150 if (ares->error != LDB_SUCCESS) { 151 return ldb_module_done(ac->req, ares->controls, 152 ares->response, ares->error); 153 } 154 155 switch (ares->type) { 156 case LDB_REPLY_ENTRY: 157 158 if (ldb_dn_compare(ares->message->dn, ac->list->olddn) == 0) { 159 /* this was already stored by the 160 * subtree_rename_search() */ 161 talloc_free(ares); 162 return LDB_SUCCESS; 163 } 164 165 store = talloc_zero(ac, struct subren_msg_store); 166 if (store == NULL) { 167 return ldb_module_done(ac->req, NULL, NULL, 168 LDB_ERR_OPERATIONS_ERROR); 169 } 170 ac->current->next = store; 171 ac->current = store; 172 173 /* the first list element contains the base for the rename */ 174 store->olddn = talloc_steal(store, ares->message->dn); 175 store->newdn = ldb_dn_copy(store, store->olddn); 176 177 if ( ! ldb_dn_remove_base_components(store->newdn, 178 ldb_dn_get_comp_num(ac->list->olddn))) { 179 return ldb_module_done(ac->req, NULL, NULL, 180 LDB_ERR_OPERATIONS_ERROR); 181 } 182 183 if ( ! ldb_dn_add_base(store->newdn, ac->list->newdn)) { 184 return ldb_module_done(ac->req, NULL, NULL, 185 LDB_ERR_OPERATIONS_ERROR); 186 } 187 188 break; 189 190 case LDB_REPLY_REFERRAL: 191 /* ignore */ 192 break; 193 194 case LDB_REPLY_DONE: 195 196 /* rewind ac->current */ 197 ac->current = ac->list; 198 199 /* All dns set up, start with the first one */ 200 ret = subtree_rename_next_request(ac); 201 202 if (ret != LDB_SUCCESS) { 203 return ldb_module_done(ac->req, NULL, NULL, ret); 204 } 205 break; 206 } 207 208 talloc_free(ares); 209 return LDB_SUCCESS; 210} 211 212/* rename */ 213static int subtree_rename(struct ldb_module *module, struct ldb_request *req) 214{ 215 struct ldb_context *ldb; 216 static const char *attrs[2] = { "distinguishedName", NULL }; 217 struct ldb_request *search_req; 218 struct subtree_rename_context *ac; 219 int ret; 220 if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */ 221 return ldb_next_request(module, req); 222 } 223 224 ldb = ldb_module_get_ctx(module); 225 226 /* This gets complex: We need to: 227 - Do a search for all entires under this entry 228 - Wait for these results to appear 229 - In the callback for each result, issue a modify request 230 - That will include this rename, we hope 231 - Wait for each modify result 232 - Regain our sainity 233 */ 234 235 ac = subren_ctx_init(module, req); 236 if (!ac) { 237 return LDB_ERR_OPERATIONS_ERROR; 238 } 239 240 /* add this entry as the first to do */ 241 ac->current = talloc_zero(ac, struct subren_msg_store); 242 if (ac->current == NULL) { 243 return LDB_ERR_OPERATIONS_ERROR; 244 } 245 ac->current->olddn = req->op.rename.olddn; 246 ac->current->newdn = req->op.rename.newdn; 247 ac->list = ac->current; 248 249 ret = ldb_build_search_req(&search_req, ldb, ac, 250 req->op.rename.olddn, 251 LDB_SCOPE_SUBTREE, 252 "(objectClass=*)", 253 attrs, 254 NULL, 255 ac, 256 subtree_rename_search_callback, 257 req); 258 if (ret != LDB_SUCCESS) { 259 return ret; 260 } 261 262 return ldb_next_request(module, search_req); 263} 264 265const struct ldb_module_ops ldb_subtree_rename_module_ops = { 266 .name = "subtree_rename", 267 .rename = subtree_rename, 268}; 269