• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/dsdb/samdb/ldb_modules/
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