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