s4/rodc: Fix the callbacks up the stack to handle referrals on modify requests
[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
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
42 struct rename_context {
43         struct ldb_module *module;
44         struct ldb_request *req;
45
46         struct ldb_reply *ares;
47 };
48
49 static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
50 {
51         unsigned int i;
52
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];
56                 }
57         }
58
59         return NULL;
60 }
61
62 static int rdn_name_add_callback(struct ldb_request *req,
63                                  struct ldb_reply *ares)
64 {
65         struct rename_context *ac;
66
67         ac = talloc_get_type(req->context, struct rename_context);
68
69         if (!ares) {
70                 return ldb_module_done(ac->req, NULL, NULL,
71                                         LDB_ERR_OPERATIONS_ERROR);
72         }
73
74         if (ares->type == LDB_REPLY_REFERRAL) {
75                 return ldb_module_send_referral(ac->req, ares->referral);
76         }
77
78         if (ares->error != LDB_SUCCESS) {
79                 return ldb_module_done(ac->req, ares->controls,
80                                         ares->response, ares->error);
81         }
82
83         if (ares->type != LDB_REPLY_DONE) {
84                 return ldb_module_done(ac->req, NULL, NULL,
85                                         LDB_ERR_OPERATIONS_ERROR);
86         }
87
88         return ldb_module_done(ac->req, ares->controls,
89                                         ares->response, LDB_SUCCESS);
90 }
91
92 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
93 {
94         struct ldb_context *ldb;
95         struct ldb_request *down_req;
96         struct rename_context *ac;
97         struct ldb_message *msg;
98         struct ldb_message_element *attribute;
99         const struct ldb_schema_attribute *a;
100         const char *rdn_name;
101         struct ldb_val rdn_val;
102         unsigned int i;
103         int ret;
104
105         ldb = ldb_module_get_ctx(module);
106
107         /* do not manipulate our control entries */
108         if (ldb_dn_is_special(req->op.add.message->dn)) {
109                 return ldb_next_request(module, req);
110         }
111
112         ac = talloc_zero(req, struct rename_context);
113         if (ac == NULL) {
114                 return LDB_ERR_OPERATIONS_ERROR;
115         }
116
117         ac->module = module;
118         ac->req = req;
119
120         msg = ldb_msg_copy_shallow(req, req->op.add.message);
121         if (msg == NULL) {
122                 return LDB_ERR_OPERATIONS_ERROR;
123         }
124
125         rdn_name = ldb_dn_get_rdn_name(msg->dn);
126         if (rdn_name == NULL) {
127                 return LDB_ERR_OPERATIONS_ERROR;
128         }
129         
130         rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
131         
132         /* Perhaps someone above us tried to set this? */
133         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
134                 attribute->num_values = 0;
135         }
136
137         if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
138                 return LDB_ERR_OPERATIONS_ERROR;
139         }
140
141         attribute = rdn_name_find_attribute(msg, rdn_name);
142
143         if (!attribute) {
144                 if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
145                         return LDB_ERR_OPERATIONS_ERROR;
146                 }
147         } else {
148                 a = ldb_schema_attribute_by_name(ldb, rdn_name);
149
150                 for (i = 0; i < attribute->num_values; i++) {
151                         ret = a->syntax->comparison_fn(ldb, msg,
152                                         &rdn_val, &attribute->values[i]);
153                         if (ret == 0) {
154                                 /* overwrite so it matches in case */
155                                 attribute->values[i] = rdn_val;
156                                 break;
157                         }
158                 }
159                 if (i == attribute->num_values) {
160                         char *rdn_errstring = talloc_asprintf(ac,
161                                 "RDN mismatch on %s: %s (%.*s) should match one of:", 
162                                 ldb_dn_get_linearized(msg->dn), rdn_name, 
163                                 (int)rdn_val.length, (const char *)rdn_val.data);
164                         for (i = 0; i < attribute->num_values; i++) {
165                                 rdn_errstring = talloc_asprintf_append(
166                                         rdn_errstring, " (%.*s)",
167                                         (int)attribute->values[i].length, 
168                                         (const char *)attribute->values[i].data);
169                         }
170                         ldb_set_errstring(ldb, rdn_errstring);
171                         /* Match AD's error here */
172                         return LDB_ERR_INVALID_DN_SYNTAX;
173                 }
174         }
175
176         ret = ldb_build_add_req(&down_req, ldb, req,
177                                 msg,
178                                 req->controls,
179                                 ac, rdn_name_add_callback,
180                                 req);
181         if (ret != LDB_SUCCESS) {
182                 return ret;
183         }
184
185         talloc_steal(down_req, msg);
186
187         /* go on with the call chain */
188         return ldb_next_request(module, down_req);
189 }
190
191 static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
192 {
193         struct rename_context *ac;
194
195         ac = talloc_get_type(req->context, struct rename_context);
196
197         if (!ares) {
198                 return ldb_module_done(ac->req, NULL, NULL,
199                                         LDB_ERR_OPERATIONS_ERROR);
200         }
201
202         if (ares->type == LDB_REPLY_REFERRAL) {
203                 return ldb_module_send_referral(ac->req, ares->referral);
204         }
205
206         if (ares->error != LDB_SUCCESS) {
207                 return ldb_module_done(ac->req, ares->controls,
208                                         ares->response, ares->error);
209         }
210
211         /* the only supported reply right now is a LDB_REPLY_DONE */
212         if (ares->type != LDB_REPLY_DONE) {
213                 return ldb_module_done(ac->req, NULL, NULL,
214                                         LDB_ERR_OPERATIONS_ERROR);
215         }
216
217         /* send saved controls eventually */
218         return ldb_module_done(ac->req, ac->ares->controls,
219                                 ac->ares->response, LDB_SUCCESS);
220 }
221
222 static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
223 {
224         struct ldb_context *ldb;
225         struct rename_context *ac;
226         struct ldb_request *mod_req;
227         const char *rdn_name;
228         struct ldb_val rdn_val;
229         struct ldb_message *msg;
230         int ret;
231
232         ac = talloc_get_type(req->context, struct rename_context);
233         ldb = ldb_module_get_ctx(ac->module);
234
235         if (!ares) {
236                 goto error;
237         }
238
239         if (ares->type == LDB_REPLY_REFERRAL) {
240                 return ldb_module_send_referral(ac->req, ares->referral);
241         }
242
243         if (ares->error != LDB_SUCCESS) {
244                 return ldb_module_done(ac->req, ares->controls,
245                                         ares->response, ares->error);
246         }
247
248         /* the only supported reply right now is a LDB_REPLY_DONE */
249         if (ares->type != LDB_REPLY_DONE) {
250                 goto error;
251         }
252
253         /* save reply for caller */
254         ac->ares = talloc_steal(ac, ares);
255
256         msg = ldb_msg_new(ac);
257         if (msg == NULL) {
258                 goto error;
259         }
260         msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
261         if (msg->dn == NULL) {
262                 goto error;
263         }
264         rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
265         if (rdn_name == NULL) {
266                 goto error;
267         }
268         
269         rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn));
270         
271         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
272                 goto error;
273         }
274         if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
275                 goto error;
276         }
277         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
278                 goto error;
279         }
280         if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
281                 goto error;
282         }
283
284         ret = ldb_build_mod_req(&mod_req, ldb,
285                                 ac, msg, NULL,
286                                 ac, rdn_modify_callback,
287                                 req);
288         if (ret != LDB_SUCCESS) {
289                 return ldb_module_done(ac->req, NULL, NULL, ret);
290         }
291         talloc_steal(mod_req, msg);
292
293         /* go on with the call chain */
294         return ldb_next_request(ac->module, mod_req);
295
296 error:
297         return ldb_module_done(ac->req, NULL, NULL,
298                                                  LDB_ERR_OPERATIONS_ERROR);
299 }
300
301 static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
302 {
303         struct ldb_context *ldb;
304         struct rename_context *ac;
305         struct ldb_request *down_req;
306         int ret;
307
308         ldb = ldb_module_get_ctx(module);
309
310         /* do not manipulate our control entries */
311         if (ldb_dn_is_special(req->op.rename.newdn)) {
312                 return ldb_next_request(module, req);
313         }
314
315         ac = talloc_zero(req, struct rename_context);
316         if (ac == NULL) {
317                 return LDB_ERR_OPERATIONS_ERROR;
318         }
319
320         ac->module = module;
321         ac->req = req;
322
323         ret = ldb_build_rename_req(&down_req,
324                                    ldb,
325                                    ac,
326                                    req->op.rename.olddn,
327                                    req->op.rename.newdn,
328                                    req->controls,
329                                    ac,
330                                    rdn_rename_callback,
331                                    req);
332
333         if (ret != LDB_SUCCESS) {
334                 return ret;
335         }
336
337         /* rename first, modify "name" if rename is ok */
338         return ldb_next_request(module, down_req);
339 }
340
341 static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
342 {
343         struct ldb_context *ldb;
344
345         ldb = ldb_module_get_ctx(module);
346
347         /* do not manipulate our control entries */
348         if (ldb_dn_is_special(req->op.mod.message->dn)) {
349                 return ldb_next_request(module, req);
350         }
351
352         if (ldb_msg_find_element(req->op.mod.message, "name")) {
353                 ldb_asprintf_errstring(ldb, "Modify of 'name' on %s not permitted, must use 'rename' operation instead",
354                                        ldb_dn_get_linearized(req->op.mod.message->dn));
355                 return LDB_ERR_NOT_ALLOWED_ON_RDN;
356         }
357
358         if (ldb_msg_find_element(req->op.mod.message, ldb_dn_get_rdn_name(req->op.mod.message->dn))) {
359                 ldb_asprintf_errstring(ldb, "Modify of RDN '%s' on %s not permitted, must use 'rename' operation instead",
360                                        ldb_dn_get_rdn_name(req->op.mod.message->dn), ldb_dn_get_linearized(req->op.mod.message->dn));
361                 return LDB_ERR_NOT_ALLOWED_ON_RDN;
362         }
363
364         /* All OK, they kept their fingers out of the special attributes */
365         return ldb_next_request(module, req);
366 }
367
368 const struct ldb_module_ops ldb_rdn_name_module_ops = {
369         .name              = "rdn_name",
370         .add               = rdn_name_add,
371         .modify            = rdn_name_modify,
372         .rename            = rdn_name_rename
373 };