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
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/>.
28 * Component: ldb rdn name module
30 * Description: keep a consistent name attribute on objects manpulations
32 * Author: Andrew Bartlett
35 * - made the module async
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
);
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
;
90 const struct ldb_val
*rdn_val_p
;
91 struct ldb_val rdn_val
;
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
);
104 return LDB_ERR_OPERATIONS_ERROR
;
110 msg
= ldb_msg_copy_shallow(req
, req
->op
.add
.message
);
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
) {
139 a
= ldb_schema_attribute_by_name(ldb
, rdn_name
);
141 return LDB_ERR_OPERATIONS_ERROR
;
144 attribute
= ldb_msg_find_element(msg
, rdn_name
);
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
);
150 ret
= ldb_msg_add_value(msg
, rdn_name
, &rdn_val
, NULL
);
152 if (ret
!= LDB_SUCCESS
) {
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
++) {
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
;
168 matched
= (a
->syntax
->comparison_fn(ldb
, msg
,
169 &rdn_val
, &attribute
->values
[i
]) == 0);
172 /* overwrite so it matches in case */
173 attribute
->values
[i
] = rdn_val
;
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
,
197 ac
, rdn_name_add_callback
,
199 if (ret
!= LDB_SUCCESS
) {
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
);
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
;
251 ac
= talloc_get_type(req
->context
, struct rename_context
);
252 ldb
= ldb_module_get_ctx(ac
->module
);
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
) {
272 /* save reply for caller */
273 ac
->ares
= talloc_steal(ac
, ares
);
275 msg
= ldb_msg_new(ac
);
279 msg
->dn
= ldb_dn_copy(msg
, ac
->req
->op
.rename
.newdn
);
280 if (msg
->dn
== NULL
) {
284 rdn_name
= ldb_dn_get_rdn_name(ac
->req
->op
.rename
.newdn
);
285 if (rdn_name
== NULL
) {
289 rdn_val_p
= ldb_dn_get_rdn_val(msg
->dn
);
290 if (rdn_val_p
== NULL
) {
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) {
304 if (ldb_msg_add_value(msg
, rdn_name
, &rdn_val
, NULL
) != 0) {
307 if (ldb_msg_add_empty(msg
, "name", LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
310 if (ldb_msg_add_value(msg
, "name", &rdn_val
, NULL
) != 0) {
314 ret
= ldb_build_mod_req(&mod_req
, ldb
,
316 ac
, rdn_modify_callback
,
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
);
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
;
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
);
346 return LDB_ERR_OPERATIONS_ERROR
;
352 ret
= ldb_build_rename_req(&down_req
,
355 req
->op
.rename
.olddn
,
356 req
->op
.rename
.newdn
,
362 if (ret
!= LDB_SUCCESS
) {
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
= {
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
);