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
39 #include "ldb_includes.h"
40 #include "ldb_module.h"
42 struct rename_context
{
43 struct ldb_module
*module
;
44 struct ldb_request
*req
;
46 struct ldb_reply
*ares
;
49 static struct ldb_message_element
*rdn_name_find_attribute(const struct ldb_message
*msg
, const char *name
)
53 for (i
= 0; i
< msg
->num_elements
; i
++) {
54 if (ldb_attr_cmp(name
, msg
->elements
[i
].name
) == 0) {
55 return &msg
->elements
[i
];
62 static int rdn_name_add_callback(struct ldb_request
*req
,
63 struct ldb_reply
*ares
)
65 struct rename_context
*ac
;
67 ac
= talloc_get_type(req
->context
, struct rename_context
);
70 return ldb_module_done(ac
->req
, NULL
, NULL
,
71 LDB_ERR_OPERATIONS_ERROR
);
73 if (ares
->error
!= LDB_SUCCESS
) {
74 return ldb_module_done(ac
->req
, ares
->controls
,
75 ares
->response
, ares
->error
);
78 if (ares
->type
!= LDB_REPLY_DONE
) {
79 return ldb_module_done(ac
->req
, NULL
, NULL
,
80 LDB_ERR_OPERATIONS_ERROR
);
83 return ldb_module_done(ac
->req
, ares
->controls
,
84 ares
->response
, LDB_SUCCESS
);
87 static int rdn_name_add(struct ldb_module
*module
, struct ldb_request
*req
)
89 struct ldb_context
*ldb
;
90 struct ldb_request
*down_req
;
91 struct rename_context
*ac
;
92 struct ldb_message
*msg
;
93 struct ldb_message_element
*attribute
;
94 const struct ldb_schema_attribute
*a
;
96 struct ldb_val rdn_val
;
100 ldb
= ldb_module_get_ctx(module
);
102 /* do not manipulate our control entries */
103 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) {
104 return ldb_next_request(module
, req
);
107 ac
= talloc_zero(req
, struct rename_context
);
109 return LDB_ERR_OPERATIONS_ERROR
;
115 msg
= ldb_msg_copy_shallow(req
, req
->op
.add
.message
);
117 return LDB_ERR_OPERATIONS_ERROR
;
120 rdn_name
= ldb_dn_get_rdn_name(msg
->dn
);
121 if (rdn_name
== NULL
) {
122 return LDB_ERR_OPERATIONS_ERROR
;
125 rdn_val
= ldb_val_dup(msg
, ldb_dn_get_rdn_val(msg
->dn
));
127 /* Perhaps someone above us tried to set this? */
128 if ((attribute
= rdn_name_find_attribute(msg
, "name")) != NULL
) {
129 attribute
->num_values
= 0;
132 if (ldb_msg_add_value(msg
, "name", &rdn_val
, NULL
) != 0) {
133 return LDB_ERR_OPERATIONS_ERROR
;
136 attribute
= rdn_name_find_attribute(msg
, rdn_name
);
139 if (ldb_msg_add_value(msg
, rdn_name
, &rdn_val
, NULL
) != 0) {
140 return LDB_ERR_OPERATIONS_ERROR
;
143 a
= ldb_schema_attribute_by_name(ldb
, rdn_name
);
145 for (i
= 0; i
< attribute
->num_values
; i
++) {
146 ret
= a
->syntax
->comparison_fn(ldb
, msg
,
147 &rdn_val
, &attribute
->values
[i
]);
149 /* overwrite so it matches in case */
150 attribute
->values
[i
] = rdn_val
;
154 if (i
== attribute
->num_values
) {
155 char *rdn_errstring
= talloc_asprintf(ac
,
156 "RDN mismatch on %s: %s (%.*s) should match one of:",
157 ldb_dn_get_linearized(msg
->dn
), rdn_name
,
158 (int)rdn_val
.length
, (const char *)rdn_val
.data
);
159 for (i
= 0; i
< attribute
->num_values
; i
++) {
160 rdn_errstring
= talloc_asprintf_append(
161 rdn_errstring
, " (%.*s)",
162 (int)attribute
->values
[i
].length
,
163 (const char *)attribute
->values
[i
].data
);
165 ldb_set_errstring(ldb
, rdn_errstring
);
166 /* Match AD's error here */
167 return LDB_ERR_INVALID_DN_SYNTAX
;
171 ret
= ldb_build_add_req(&down_req
, ldb
, req
,
174 ac
, rdn_name_add_callback
,
176 if (ret
!= LDB_SUCCESS
) {
180 talloc_steal(down_req
, msg
);
182 /* go on with the call chain */
183 return ldb_next_request(module
, down_req
);
186 static int rdn_modify_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
188 struct rename_context
*ac
;
190 ac
= talloc_get_type(req
->context
, struct rename_context
);
193 return ldb_module_done(ac
->req
, NULL
, NULL
,
194 LDB_ERR_OPERATIONS_ERROR
);
196 if (ares
->error
!= LDB_SUCCESS
) {
197 return ldb_module_done(ac
->req
, ares
->controls
,
198 ares
->response
, ares
->error
);
201 /* the only supported reply right now is a LDB_REPLY_DONE */
202 if (ares
->type
!= LDB_REPLY_DONE
) {
203 return ldb_module_done(ac
->req
, NULL
, NULL
,
204 LDB_ERR_OPERATIONS_ERROR
);
207 /* send saved controls eventually */
208 return ldb_module_done(ac
->req
, ac
->ares
->controls
,
209 ac
->ares
->response
, LDB_SUCCESS
);
212 static int rdn_rename_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
214 struct ldb_context
*ldb
;
215 struct rename_context
*ac
;
216 struct ldb_request
*mod_req
;
217 const char *rdn_name
;
218 struct ldb_val rdn_val
;
219 struct ldb_message
*msg
;
222 ac
= talloc_get_type(req
->context
, struct rename_context
);
223 ldb
= ldb_module_get_ctx(ac
->module
);
228 if (ares
->error
!= LDB_SUCCESS
) {
229 return ldb_module_done(ac
->req
, ares
->controls
,
230 ares
->response
, ares
->error
);
233 /* the only supported reply right now is a LDB_REPLY_DONE */
234 if (ares
->type
!= LDB_REPLY_DONE
) {
238 /* save reply for caller */
239 ac
->ares
= talloc_steal(ac
, ares
);
241 msg
= ldb_msg_new(ac
);
245 msg
->dn
= ldb_dn_copy(msg
, ac
->req
->op
.rename
.newdn
);
246 if (msg
->dn
== NULL
) {
249 rdn_name
= ldb_dn_get_rdn_name(ac
->req
->op
.rename
.newdn
);
250 if (rdn_name
== NULL
) {
254 rdn_val
= ldb_val_dup(msg
, ldb_dn_get_rdn_val(ac
->req
->op
.rename
.newdn
));
256 if (ldb_msg_add_empty(msg
, rdn_name
, LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
259 if (ldb_msg_add_value(msg
, rdn_name
, &rdn_val
, NULL
) != 0) {
262 if (ldb_msg_add_empty(msg
, "name", LDB_FLAG_MOD_REPLACE
, NULL
) != 0) {
265 if (ldb_msg_add_value(msg
, "name", &rdn_val
, NULL
) != 0) {
269 ret
= ldb_build_mod_req(&mod_req
, ldb
,
271 ac
, rdn_modify_callback
,
273 if (ret
!= LDB_SUCCESS
) {
274 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
276 talloc_steal(mod_req
, msg
);
278 /* go on with the call chain */
279 return ldb_next_request(ac
->module
, mod_req
);
282 return ldb_module_done(ac
->req
, NULL
, NULL
,
283 LDB_ERR_OPERATIONS_ERROR
);
286 static int rdn_name_rename(struct ldb_module
*module
, struct ldb_request
*req
)
288 struct ldb_context
*ldb
;
289 struct rename_context
*ac
;
290 struct ldb_request
*down_req
;
293 ldb
= ldb_module_get_ctx(module
);
295 /* do not manipulate our control entries */
296 if (ldb_dn_is_special(req
->op
.rename
.newdn
)) {
297 return ldb_next_request(module
, req
);
300 ac
= talloc_zero(req
, struct rename_context
);
302 return LDB_ERR_OPERATIONS_ERROR
;
308 ret
= ldb_build_rename_req(&down_req
,
311 req
->op
.rename
.olddn
,
312 req
->op
.rename
.newdn
,
318 if (ret
!= LDB_SUCCESS
) {
322 /* rename first, modify "name" if rename is ok */
323 return ldb_next_request(module
, down_req
);
326 static int rdn_name_modify(struct ldb_module
*module
, struct ldb_request
*req
)
328 struct ldb_context
*ldb
;
330 ldb
= ldb_module_get_ctx(module
);
332 /* do not manipulate our control entries */
333 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
334 return ldb_next_request(module
, req
);
337 if (ldb_msg_find_element(req
->op
.mod
.message
, "name")) {
338 ldb_asprintf_errstring(ldb
, "Modify of 'name' on %s not permitted, must use 'rename' operation instead",
339 ldb_dn_get_linearized(req
->op
.mod
.message
->dn
));
340 return LDB_ERR_NOT_ALLOWED_ON_RDN
;
343 if (ldb_msg_find_element(req
->op
.mod
.message
, ldb_dn_get_rdn_name(req
->op
.mod
.message
->dn
))) {
344 ldb_asprintf_errstring(ldb
, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead",
345 ldb_dn_get_rdn_name(req
->op
.mod
.message
->dn
), ldb_dn_get_linearized(req
->op
.mod
.message
->dn
));
346 return LDB_ERR_NOT_ALLOWED_ON_RDN
;
349 /* All OK, they kept their fingers out of the special attributes */
350 return ldb_next_request(module
, req
);
353 const struct ldb_module_ops ldb_rdn_name_module_ops
= {
356 .modify
= rdn_name_modify
,
357 .rename
= rdn_name_rename