• 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/lib/ldb/modules/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Bartlett 2005
5   Copyright (C) Simo Sorce 2006-2008
6
7     ** NOTE! The following LGPL license applies to the ldb
8     ** library. This does NOT imply that all of Samba is released
9     ** under the LGPL
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25/*
26 *  Name: rdn_name
27 *
28 *  Component: ldb rdn name module
29 *
30 *  Description: keep a consistent name attribute on objects manpulations
31 *
32 *  Author: Andrew Bartlett
33 *
34 *  Modifications:
35 *    - made the module async
36 *      Simo Sorce Mar 2006
37 */
38
39#include "ldb_includes.h"
40#include "ldb_module.h"
41
42struct rename_context {
43
44	struct ldb_module *module;
45	struct ldb_request *req;
46
47	struct ldb_reply *ares;
48};
49
50static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
51{
52	int i;
53
54	for (i = 0; i < msg->num_elements; i++) {
55		if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
56			return &msg->elements[i];
57		}
58	}
59
60	return NULL;
61}
62
63static int rdn_name_add_callback(struct ldb_request *req,
64				 struct ldb_reply *ares)
65{
66	struct rename_context *ac;
67
68	ac = talloc_get_type(req->context, struct rename_context);
69
70	if (!ares) {
71		return ldb_module_done(ac->req, NULL, NULL,
72					LDB_ERR_OPERATIONS_ERROR);
73	}
74	if (ares->error != LDB_SUCCESS) {
75		return ldb_module_done(ac->req, ares->controls,
76					ares->response, ares->error);
77	}
78
79	if (ares->type != LDB_REPLY_DONE) {
80		return ldb_module_done(ac->req, NULL, NULL,
81					LDB_ERR_OPERATIONS_ERROR);
82	}
83
84	return ldb_module_done(ac->req, ares->controls,
85					ares->response, LDB_SUCCESS);
86}
87
88static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
89{
90	struct ldb_context *ldb;
91	struct ldb_request *down_req;
92	struct rename_context *ac;
93	struct ldb_message *msg;
94	struct ldb_message_element *attribute;
95	const struct ldb_schema_attribute *a;
96	const char *rdn_name;
97	struct ldb_val rdn_val;
98	int i, ret;
99
100	ldb = ldb_module_get_ctx(module);
101	ldb_debug(ldb, LDB_DEBUG_TRACE, "rdn_name_add_record");
102
103	/* do not manipulate our control entries */
104	if (ldb_dn_is_special(req->op.add.message->dn)) {
105		return ldb_next_request(module, req);
106	}
107
108	ac = talloc_zero(req, struct rename_context);
109	if (ac == NULL) {
110		return LDB_ERR_OPERATIONS_ERROR;
111	}
112
113	ac->module = module;
114	ac->req = req;
115
116	msg = ldb_msg_copy_shallow(req, req->op.add.message);
117	if (msg == NULL) {
118		return LDB_ERR_OPERATIONS_ERROR;
119	}
120
121	rdn_name = ldb_dn_get_rdn_name(msg->dn);
122	if (rdn_name == NULL) {
123		talloc_free(ac);
124		return LDB_ERR_OPERATIONS_ERROR;
125	}
126
127	rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
128
129	/* Perhaps someone above us tried to set this? */
130	if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
131		attribute->num_values = 0;
132	}
133
134	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
135		talloc_free(ac);
136		return LDB_ERR_OPERATIONS_ERROR;
137	}
138
139	attribute = rdn_name_find_attribute(msg, rdn_name);
140
141	if (!attribute) {
142		if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
143			talloc_free(ac);
144			return LDB_ERR_OPERATIONS_ERROR;
145		}
146	} else {
147		a = ldb_schema_attribute_by_name(ldb, rdn_name);
148
149		for (i = 0; i < attribute->num_values; i++) {
150			ret = a->syntax->comparison_fn(ldb, msg,
151					&rdn_val, &attribute->values[i]);
152			if (ret == 0) {
153				/* overwrite so it matches in case */
154				attribute->values[i] = rdn_val;
155				break;
156			}
157		}
158		if (i == attribute->num_values) {
159			char *rdn_errstring = talloc_asprintf(ac, "RDN mismatch on %s: %s (%.*s) should match one of:",
160							  ldb_dn_get_linearized(msg->dn), rdn_name,
161							  (int)rdn_val.length, (const char *)rdn_val.data);
162			for (i = 0; i < attribute->num_values; i++) {
163				rdn_errstring = talloc_asprintf_append(rdn_errstring, " (%.*s)",
164								       (int)attribute->values[i].length,
165								       (const char *)attribute->values[i].data);
166			}
167			ldb_debug_set(ldb, LDB_DEBUG_FATAL, "%s", rdn_errstring);
168			talloc_free(ac);
169			/* Match AD's error here */
170			return LDB_ERR_INVALID_DN_SYNTAX;
171		}
172	}
173
174	ret = ldb_build_add_req(&down_req, ldb, req,
175				msg,
176				req->controls,
177				ac, rdn_name_add_callback,
178				req);
179	if (ret != LDB_SUCCESS) {
180		return ret;
181	}
182
183	talloc_steal(down_req, msg);
184
185	/* go on with the call chain */
186	return ldb_next_request(module, down_req);
187}
188
189static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
190{
191	struct rename_context *ac;
192
193	ac = talloc_get_type(req->context, struct rename_context);
194
195	if (!ares) {
196		return ldb_module_done(ac->req, NULL, NULL,
197					LDB_ERR_OPERATIONS_ERROR);
198	}
199	if (ares->error != LDB_SUCCESS) {
200		return ldb_module_done(ac->req, ares->controls,
201					ares->response, ares->error);
202	}
203
204	/* the only supported reply right now is a LDB_REPLY_DONE */
205	if (ares->type != LDB_REPLY_DONE) {
206		return ldb_module_done(ac->req, NULL, NULL,
207					LDB_ERR_OPERATIONS_ERROR);
208	}
209
210	/* send saved controls eventually */
211	return ldb_module_done(ac->req, ac->ares->controls,
212				ac->ares->response, LDB_SUCCESS);
213}
214
215static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
216{
217	struct ldb_context *ldb;
218	struct rename_context *ac;
219	struct ldb_request *mod_req;
220	const char *rdn_name;
221	struct ldb_val rdn_val;
222	struct ldb_message *msg;
223	int ret;
224
225	ac = talloc_get_type(req->context, struct rename_context);
226	ldb = ldb_module_get_ctx(ac->module);
227
228	if (!ares) {
229		goto error;
230	}
231	if (ares->error != LDB_SUCCESS) {
232		return ldb_module_done(ac->req, ares->controls,
233					ares->response, ares->error);
234	}
235
236	/* the only supported reply right now is a LDB_REPLY_DONE */
237	if (ares->type != LDB_REPLY_DONE) {
238		goto error;
239	}
240
241	/* save reply for caller */
242	ac->ares = talloc_steal(ac, ares);
243
244	msg = ldb_msg_new(ac);
245	if (msg == NULL) {
246		goto error;
247	}
248	msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
249	if (msg->dn == NULL) {
250		goto error;
251	}
252	rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
253	if (rdn_name == NULL) {
254		goto error;
255	}
256
257	rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn));
258
259	if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
260		goto error;
261	}
262	if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
263		goto error;
264	}
265	if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
266		goto error;
267	}
268	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
269		goto error;
270	}
271
272	ret = ldb_build_mod_req(&mod_req, ldb,
273				ac, msg, NULL,
274				ac, rdn_modify_callback,
275				req);
276	if (ret != LDB_SUCCESS) {
277		return ldb_module_done(ac->req, NULL, NULL, ret);
278	}
279	talloc_steal(mod_req, msg);
280
281	/* do the mod call */
282	return ldb_request(ldb, mod_req);
283
284error:
285	return ldb_module_done(ac->req, NULL, NULL,
286						LDB_ERR_OPERATIONS_ERROR);
287}
288
289static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
290{
291	struct ldb_context *ldb;
292	struct rename_context *ac;
293	struct ldb_request *down_req;
294	int ret;
295
296	ldb = ldb_module_get_ctx(module);
297	ldb_debug(ldb, LDB_DEBUG_TRACE, "rdn_name_rename");
298
299	/* do not manipulate our control entries */
300	if (ldb_dn_is_special(req->op.rename.newdn)) {
301		return ldb_next_request(module, req);
302	}
303
304	ac = talloc_zero(req, struct rename_context);
305	if (ac == NULL) {
306		return LDB_ERR_OPERATIONS_ERROR;
307	}
308
309	ac->module = module;
310	ac->req = req;
311
312	ret = ldb_build_rename_req(&down_req,
313				   ldb,
314				   ac,
315				   req->op.rename.olddn,
316				   req->op.rename.newdn,
317				   req->controls,
318				   ac,
319				   rdn_rename_callback,
320				   req);
321
322	if (ret != LDB_SUCCESS) {
323		return LDB_ERR_OPERATIONS_ERROR;
324	}
325
326	/* rename first, modify "name" if rename is ok */
327	return ldb_next_request(module, down_req);
328}
329
330const struct ldb_module_ops ldb_rdn_name_module_ops = {
331	.name              = "rdn_name",
332	.add               = rdn_name_add,
333	.rename            = rdn_name_rename,
334};
335