selftest: remove samba3.rpc.spoolss.*printserver.openprinter_badnamelist from flapping
[Samba.git] / lib / ldb / modules / rdn_name.c
blob50b63aee133cf3cbb142f8fe57e18e227761ea00
1 /*
2 ldb database library
4 Copyright (C) Andrew Bartlett 2005-2009
5 Copyright (C) Simo Sorce 2006-2008
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
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.
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.
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/>.
26 * Name: rdn_name
28 * Component: ldb rdn name module
30 * Description: keep a consistent name attribute on objects manpulations
32 * Author: Andrew Bartlett
34 * Modifications:
35 * - made the module async
36 * Simo Sorce Mar 2006
39 #include "replace.h"
40 #include "system/filesys.h"
41 #include "system/time.h"
42 #include "ldb_module.h"
44 struct rename_context {
45 struct ldb_module *module;
46 struct ldb_request *req;
48 struct ldb_reply *ares;
51 static int rdn_name_add_callback(struct ldb_request *req,
52 struct ldb_reply *ares)
54 struct rename_context *ac;
56 ac = talloc_get_type(req->context, struct rename_context);
58 if (!ares) {
59 return ldb_module_done(ac->req, NULL, NULL,
60 LDB_ERR_OPERATIONS_ERROR);
63 if (ares->type == LDB_REPLY_REFERRAL) {
64 return ldb_module_send_referral(ac->req, ares->referral);
67 if (ares->error != LDB_SUCCESS) {
68 return ldb_module_done(ac->req, ares->controls,
69 ares->response, ares->error);
72 if (ares->type != LDB_REPLY_DONE) {
73 return ldb_module_done(ac->req, NULL, NULL,
74 LDB_ERR_OPERATIONS_ERROR);
77 return ldb_module_done(ac->req, ares->controls,
78 ares->response, LDB_SUCCESS);
81 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
83 struct ldb_context *ldb;
84 struct ldb_request *down_req;
85 struct rename_context *ac;
86 struct ldb_message *msg;
87 struct ldb_message_element *attribute;
88 const struct ldb_schema_attribute *a;
89 const char *rdn_name;
90 const struct ldb_val *rdn_val_p;
91 struct ldb_val rdn_val;
92 unsigned int i;
93 int ret;
95 ldb = ldb_module_get_ctx(module);
97 /* do not manipulate our control entries */
98 if (ldb_dn_is_special(req->op.add.message->dn)) {
99 return ldb_next_request(module, req);
102 ac = talloc_zero(req, struct rename_context);
103 if (ac == NULL) {
104 return LDB_ERR_OPERATIONS_ERROR;
107 ac->module = module;
108 ac->req = req;
110 msg = ldb_msg_copy_shallow(req, req->op.add.message);
111 if (msg == NULL) {
112 return LDB_ERR_OPERATIONS_ERROR;
115 rdn_name = ldb_dn_get_rdn_name(msg->dn);
116 if (rdn_name == NULL) {
117 return LDB_ERR_OPERATIONS_ERROR;
120 rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
121 if (rdn_val_p == NULL) {
122 return LDB_ERR_OPERATIONS_ERROR;
124 if (rdn_val_p->length == 0) {
125 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
126 ldb_dn_get_linearized(req->op.add.message->dn));
127 return LDB_ERR_INVALID_DN_SYNTAX;
129 rdn_val = ldb_val_dup(msg, rdn_val_p);
131 /* Perhaps someone above us tried to set this? Then ignore it */
132 ldb_msg_remove_attr(msg, "name");
134 ret = ldb_msg_add_value(msg, "name", &rdn_val, NULL);
135 if (ret != LDB_SUCCESS) {
136 return ret;
139 a = ldb_schema_attribute_by_name(ldb, rdn_name);
140 if (a == NULL) {
141 return LDB_ERR_OPERATIONS_ERROR;
144 attribute = ldb_msg_find_element(msg, rdn_name);
145 if (!attribute) {
146 /* add entry with normalised RDN information if possible */
147 if (a->name != NULL) {
148 ret = ldb_msg_add_value(msg, a->name, &rdn_val, NULL);
149 } else {
150 ret = ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL);
152 if (ret != LDB_SUCCESS) {
153 return ret;
155 } else {
156 /* normalise attribute name if possible */
157 if (a->name != NULL) {
158 attribute->name = a->name;
160 /* normalise attribute value */
161 for (i = 0; i < attribute->num_values; i++) {
162 bool matched;
163 if (a->syntax->operator_fn) {
164 ret = a->syntax->operator_fn(ldb, LDB_OP_EQUALITY, a,
165 &rdn_val, &attribute->values[i], &matched);
166 if (ret != LDB_SUCCESS) return ret;
167 } else {
168 matched = (a->syntax->comparison_fn(ldb, msg,
169 &rdn_val, &attribute->values[i]) == 0);
171 if (matched) {
172 /* overwrite so it matches in case */
173 attribute->values[i] = rdn_val;
174 break;
177 if (i == attribute->num_values) {
178 char *rdn_errstring = talloc_asprintf(ac,
179 "RDN mismatch on %s: %s (%.*s) should match one of:",
180 ldb_dn_get_linearized(msg->dn), rdn_name,
181 (int)rdn_val.length, (const char *)rdn_val.data);
182 for (i = 0; i < attribute->num_values; i++) {
183 rdn_errstring = talloc_asprintf_append(
184 rdn_errstring, " (%.*s)",
185 (int)attribute->values[i].length,
186 (const char *)attribute->values[i].data);
188 ldb_set_errstring(ldb, rdn_errstring);
189 /* Match AD's error here */
190 return LDB_ERR_INVALID_DN_SYNTAX;
194 ret = ldb_build_add_req(&down_req, ldb, req,
195 msg,
196 req->controls,
197 ac, rdn_name_add_callback,
198 req);
199 if (ret != LDB_SUCCESS) {
200 return ret;
203 talloc_steal(down_req, msg);
205 /* go on with the call chain */
206 return ldb_next_request(module, down_req);
209 static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
211 struct rename_context *ac;
213 ac = talloc_get_type(req->context, struct rename_context);
215 if (!ares) {
216 return ldb_module_done(ac->req, NULL, NULL,
217 LDB_ERR_OPERATIONS_ERROR);
220 if (ares->type == LDB_REPLY_REFERRAL) {
221 return ldb_module_send_referral(ac->req, ares->referral);
224 if (ares->error != LDB_SUCCESS) {
225 return ldb_module_done(ac->req, ares->controls,
226 ares->response, ares->error);
229 /* the only supported reply right now is a LDB_REPLY_DONE */
230 if (ares->type != LDB_REPLY_DONE) {
231 return ldb_module_done(ac->req, NULL, NULL,
232 LDB_ERR_OPERATIONS_ERROR);
235 /* send saved controls eventually */
236 return ldb_module_done(ac->req, ac->ares->controls,
237 ac->ares->response, LDB_SUCCESS);
240 static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
242 struct ldb_context *ldb;
243 struct rename_context *ac;
244 struct ldb_request *mod_req;
245 const char *rdn_name;
246 const struct ldb_val *rdn_val_p;
247 struct ldb_val rdn_val;
248 struct ldb_message *msg;
249 int ret;
251 ac = talloc_get_type(req->context, struct rename_context);
252 ldb = ldb_module_get_ctx(ac->module);
254 if (!ares) {
255 goto error;
258 if (ares->type == LDB_REPLY_REFERRAL) {
259 return ldb_module_send_referral(ac->req, ares->referral);
262 if (ares->error != LDB_SUCCESS) {
263 return ldb_module_done(ac->req, ares->controls,
264 ares->response, ares->error);
267 /* the only supported reply right now is a LDB_REPLY_DONE */
268 if (ares->type != LDB_REPLY_DONE) {
269 goto error;
272 /* save reply for caller */
273 ac->ares = talloc_steal(ac, ares);
275 msg = ldb_msg_new(ac);
276 if (msg == NULL) {
277 goto error;
279 msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
280 if (msg->dn == NULL) {
281 goto error;
284 rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
285 if (rdn_name == NULL) {
286 goto error;
289 rdn_val_p = ldb_dn_get_rdn_val(msg->dn);
290 if (rdn_val_p == NULL) {
291 goto error;
293 if (rdn_val_p->length == 0) {
294 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
295 ldb_dn_get_linearized(req->op.rename.olddn));
296 return ldb_module_done(ac->req, NULL, NULL,
297 LDB_ERR_NAMING_VIOLATION);
299 rdn_val = ldb_val_dup(msg, rdn_val_p);
301 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
302 goto error;
304 if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
305 goto error;
307 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
308 goto error;
310 if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
311 goto error;
314 ret = ldb_build_mod_req(&mod_req, ldb,
315 ac, msg, NULL,
316 ac, rdn_modify_callback,
317 req);
318 if (ret != LDB_SUCCESS) {
319 return ldb_module_done(ac->req, NULL, NULL, ret);
321 talloc_steal(mod_req, msg);
323 /* go on with the call chain */
324 return ldb_next_request(ac->module, mod_req);
326 error:
327 return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
330 static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
332 struct ldb_context *ldb;
333 struct rename_context *ac;
334 struct ldb_request *down_req;
335 int ret;
337 ldb = ldb_module_get_ctx(module);
339 /* do not manipulate our control entries */
340 if (ldb_dn_is_special(req->op.rename.newdn)) {
341 return ldb_next_request(module, req);
344 ac = talloc_zero(req, struct rename_context);
345 if (ac == NULL) {
346 return LDB_ERR_OPERATIONS_ERROR;
349 ac->module = module;
350 ac->req = req;
352 ret = ldb_build_rename_req(&down_req,
353 ldb,
355 req->op.rename.olddn,
356 req->op.rename.newdn,
357 req->controls,
359 rdn_rename_callback,
360 req);
362 if (ret != LDB_SUCCESS) {
363 return ret;
366 /* rename first, modify "name" if rename is ok */
367 return ldb_next_request(module, down_req);
370 static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
372 struct ldb_context *ldb;
373 const struct ldb_val *rdn_val_p;
375 ldb = ldb_module_get_ctx(module);
377 /* do not manipulate our control entries */
378 if (ldb_dn_is_special(req->op.mod.message->dn)) {
379 return ldb_next_request(module, req);
382 rdn_val_p = ldb_dn_get_rdn_val(req->op.mod.message->dn);
383 if (rdn_val_p == NULL) {
384 return LDB_ERR_OPERATIONS_ERROR;
386 if (rdn_val_p->length == 0) {
387 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
388 ldb_dn_get_linearized(req->op.mod.message->dn));
389 return LDB_ERR_INVALID_DN_SYNTAX;
392 if (ldb_msg_find_element(req->op.mod.message, "distinguishedName")) {
393 ldb_asprintf_errstring(ldb, "Modify of 'distinguishedName' on %s not permitted, must use 'rename' operation instead",
394 ldb_dn_get_linearized(req->op.mod.message->dn));
395 return LDB_ERR_CONSTRAINT_VIOLATION;
398 if (ldb_msg_find_element(req->op.mod.message, "name")) {
399 ldb_asprintf_errstring(ldb, "Modify of 'name' on %s not permitted, must use 'rename' operation instead",
400 ldb_dn_get_linearized(req->op.mod.message->dn));
401 return LDB_ERR_NOT_ALLOWED_ON_RDN;
404 if (ldb_msg_find_element(req->op.mod.message, ldb_dn_get_rdn_name(req->op.mod.message->dn))) {
405 ldb_asprintf_errstring(ldb, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead",
406 ldb_dn_get_rdn_name(req->op.mod.message->dn), ldb_dn_get_linearized(req->op.mod.message->dn));
407 return LDB_ERR_NOT_ALLOWED_ON_RDN;
410 /* All OK, they kept their fingers out of the special attributes */
411 return ldb_next_request(module, req);
414 static int rdn_name_search(struct ldb_module *module, struct ldb_request *req)
416 struct ldb_context *ldb;
417 const char *rdn_name;
418 const struct ldb_val *rdn_val_p;
420 ldb = ldb_module_get_ctx(module);
422 /* do not manipulate our control entries */
423 if (ldb_dn_is_special(req->op.search.base)) {
424 return ldb_next_request(module, req);
427 rdn_name = ldb_dn_get_rdn_name(req->op.search.base);
428 rdn_val_p = ldb_dn_get_rdn_val(req->op.search.base);
429 if ((rdn_name != NULL) && (rdn_val_p == NULL)) {
430 return LDB_ERR_OPERATIONS_ERROR;
432 if ((rdn_val_p != NULL) && (rdn_val_p->length == 0)) {
433 ldb_asprintf_errstring(ldb, "Empty RDN value on %s not permitted!",
434 ldb_dn_get_linearized(req->op.search.base));
435 return LDB_ERR_INVALID_DN_SYNTAX;
438 return ldb_next_request(module, req);
441 static const struct ldb_module_ops ldb_rdn_name_module_ops = {
442 .name = "rdn_name",
443 .add = rdn_name_add,
444 .modify = rdn_name_modify,
445 .rename = rdn_name_rename,
446 .search = rdn_name_search
449 int ldb_rdn_name_init(const char *version)
451 LDB_MODULE_CHECK_VERSION(version);
452 return ldb_register_module(&ldb_rdn_name_module_ops);