LDB:rdn name module - change counters to "unsigned" where appropriate
[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         if (ares->error != LDB_SUCCESS) {
74                 return ldb_module_done(ac->req, ares->controls,
75                                         ares->response, ares->error);
76         }
77
78         if (ares->type != LDB_REPLY_DONE) {
79                 return ldb_module_done(ac->req, NULL, NULL,
80                                         LDB_ERR_OPERATIONS_ERROR);
81         }
82
83         return ldb_module_done(ac->req, ares->controls,
84                                         ares->response, LDB_SUCCESS);
85 }
86
87 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
88 {
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;
95         const char *rdn_name;
96         struct ldb_val rdn_val;
97         unsigned int i;
98         int ret;
99
100         ldb = ldb_module_get_ctx(module);
101
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);
105         }
106
107         ac = talloc_zero(req, struct rename_context);
108         if (ac == NULL) {
109                 return LDB_ERR_OPERATIONS_ERROR;
110         }
111
112         ac->module = module;
113         ac->req = req;
114
115         msg = ldb_msg_copy_shallow(req, req->op.add.message);
116         if (msg == NULL) {
117                 return LDB_ERR_OPERATIONS_ERROR;
118         }
119
120         rdn_name = ldb_dn_get_rdn_name(msg->dn);
121         if (rdn_name == NULL) {
122                 return LDB_ERR_OPERATIONS_ERROR;
123         }
124         
125         rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
126         
127         /* Perhaps someone above us tried to set this? */
128         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
129                 attribute->num_values = 0;
130         }
131
132         if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
133                 return LDB_ERR_OPERATIONS_ERROR;
134         }
135
136         attribute = rdn_name_find_attribute(msg, rdn_name);
137
138         if (!attribute) {
139                 if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
140                         return LDB_ERR_OPERATIONS_ERROR;
141                 }
142         } else {
143                 a = ldb_schema_attribute_by_name(ldb, rdn_name);
144
145                 for (i = 0; i < attribute->num_values; i++) {
146                         ret = a->syntax->comparison_fn(ldb, msg,
147                                         &rdn_val, &attribute->values[i]);
148                         if (ret == 0) {
149                                 /* overwrite so it matches in case */
150                                 attribute->values[i] = rdn_val;
151                                 break;
152                         }
153                 }
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);
164                         }
165                         ldb_set_errstring(ldb, rdn_errstring);
166                         /* Match AD's error here */
167                         return LDB_ERR_INVALID_DN_SYNTAX;
168                 }
169         }
170
171         ret = ldb_build_add_req(&down_req, ldb, req,
172                                 msg,
173                                 req->controls,
174                                 ac, rdn_name_add_callback,
175                                 req);
176         if (ret != LDB_SUCCESS) {
177                 return ret;
178         }
179
180         talloc_steal(down_req, msg);
181
182         /* go on with the call chain */
183         return ldb_next_request(module, down_req);
184 }
185
186 static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
187 {
188         struct rename_context *ac;
189
190         ac = talloc_get_type(req->context, struct rename_context);
191
192         if (!ares) {
193                 return ldb_module_done(ac->req, NULL, NULL,
194                                         LDB_ERR_OPERATIONS_ERROR);
195         }
196         if (ares->error != LDB_SUCCESS) {
197                 return ldb_module_done(ac->req, ares->controls,
198                                         ares->response, ares->error);
199         }
200
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);
205         }
206
207         /* send saved controls eventually */
208         return ldb_module_done(ac->req, ac->ares->controls,
209                                 ac->ares->response, LDB_SUCCESS);
210 }
211
212 static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
213 {
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;
220         int ret;
221
222         ac = talloc_get_type(req->context, struct rename_context);
223         ldb = ldb_module_get_ctx(ac->module);
224
225         if (!ares) {
226                 goto error;
227         }
228         if (ares->error != LDB_SUCCESS) {
229                 return ldb_module_done(ac->req, ares->controls,
230                                         ares->response, ares->error);
231         }
232
233         /* the only supported reply right now is a LDB_REPLY_DONE */
234         if (ares->type != LDB_REPLY_DONE) {
235                 goto error;
236         }
237
238         /* save reply for caller */
239         ac->ares = talloc_steal(ac, ares);
240
241         msg = ldb_msg_new(ac);
242         if (msg == NULL) {
243                 goto error;
244         }
245         msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
246         if (msg->dn == NULL) {
247                 goto error;
248         }
249         rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
250         if (rdn_name == NULL) {
251                 goto error;
252         }
253         
254         rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn));
255         
256         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
257                 goto error;
258         }
259         if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
260                 goto error;
261         }
262         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
263                 goto error;
264         }
265         if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
266                 goto error;
267         }
268
269         ret = ldb_build_mod_req(&mod_req, ldb,
270                                 ac, msg, NULL,
271                                 ac, rdn_modify_callback,
272                                 req);
273         if (ret != LDB_SUCCESS) {
274                 return ldb_module_done(ac->req, NULL, NULL, ret);
275         }
276         talloc_steal(mod_req, msg);
277
278         /* go on with the call chain */
279         return ldb_next_request(ac->module, mod_req);
280
281 error:
282         return ldb_module_done(ac->req, NULL, NULL,
283                                                  LDB_ERR_OPERATIONS_ERROR);
284 }
285
286 static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
287 {
288         struct ldb_context *ldb;
289         struct rename_context *ac;
290         struct ldb_request *down_req;
291         int ret;
292
293         ldb = ldb_module_get_ctx(module);
294
295         /* do not manipulate our control entries */
296         if (ldb_dn_is_special(req->op.rename.newdn)) {
297                 return ldb_next_request(module, req);
298         }
299
300         ac = talloc_zero(req, struct rename_context);
301         if (ac == NULL) {
302                 return LDB_ERR_OPERATIONS_ERROR;
303         }
304
305         ac->module = module;
306         ac->req = req;
307
308         ret = ldb_build_rename_req(&down_req,
309                                    ldb,
310                                    ac,
311                                    req->op.rename.olddn,
312                                    req->op.rename.newdn,
313                                    req->controls,
314                                    ac,
315                                    rdn_rename_callback,
316                                    req);
317
318         if (ret != LDB_SUCCESS) {
319                 return ret;
320         }
321
322         /* rename first, modify "name" if rename is ok */
323         return ldb_next_request(module, down_req);
324 }
325
326 static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
327 {
328         struct ldb_context *ldb;
329
330         ldb = ldb_module_get_ctx(module);
331
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);
335         }
336
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;
341         }
342
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;
347         }
348
349         /* All OK, they kept their fingers out of the special attributes */
350         return ldb_next_request(module, req);
351 }
352
353 const struct ldb_module_ops ldb_rdn_name_module_ops = {
354         .name              = "rdn_name",
355         .add               = rdn_name_add,
356         .modify            = rdn_name_modify,
357         .rename            = rdn_name_rename
358 };