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