r14391: rdn_name -> async
[ira/wip.git] / source4 / lib / ldb / modules / rdn_name.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Bartlet 2005
5    Copyright (C) Simo Sorce     2006
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 2 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, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26 /*
27  *  Name: rdb_name
28  *
29  *  Component: ldb rdn name module
30  *
31  *  Description: keep a consistent name attribute on objects manpulations
32  *
33  *  Author: Andrew Bartlet
34  *
35  *  Modifications:
36  *    - made the module async
37  *      Simo Sorce Mar 2006
38  */
39
40 #include "includes.h"
41 #include "ldb/include/includes.h"
42
43 static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
44 {
45         int i;
46
47         for (i = 0; i < msg->num_elements; i++) {
48                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
49                         return &msg->elements[i];
50                 }
51         }
52
53         return NULL;
54 }
55
56 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
57 {
58         const struct ldb_message *msg = req->op.add.message;
59         struct ldb_message *msg2;
60         struct ldb_message_element *attribute;
61         struct ldb_dn_component *rdn;
62         int i, ret;
63
64         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
65
66         /* do not manipulate our control entries */
67         if (ldb_dn_is_special(msg->dn)) {
68                 return ldb_next_request(module, req);
69         }
70
71         msg2 = talloc(module, struct ldb_message);
72         if (!msg2) {
73                 return -1;
74         }
75
76         msg2->dn = msg->dn;
77         msg2->num_elements = msg->num_elements;
78         msg2->private_data = msg->private_data;
79         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
80         for (i = 0; i < msg2->num_elements; i++) {
81                 msg2->elements[i] = msg->elements[i];
82         }
83
84         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
85         if (!rdn) {
86                 talloc_free(msg2);
87                 return -1;
88         }
89         
90         /* Perhaps someone above us tried to set this? */
91         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
92                 attribute->num_values = 0;
93         }
94
95         if (ldb_msg_add_value(msg2, "name", &rdn->value) != 0) {
96                 talloc_free(msg2);
97                 return -1;
98         }
99
100         attribute = rdn_name_find_attribute(msg2, rdn->name);
101
102         if (!attribute) {
103                 if (ldb_msg_add_value(msg2, rdn->name, &rdn->value) != 0) {
104                         talloc_free(msg2);
105                         return -1;
106                 }
107         } else {
108                 const struct ldb_attrib_handler *handler
109                         = ldb_attrib_handler(module->ldb, rdn->name);
110                 for (i=0; i < attribute->num_values; i++) {
111                         if (handler->comparison_fn(module->ldb, msg2, &rdn->value, &attribute->values[i]) == 0) {
112                                 /* overwrite so it matches in case */
113                                 attribute->values[i] = rdn->value;
114                                 break;
115                         }
116                 }
117                 if (i == attribute->num_values) {
118                         ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, 
119                                       "RDN mismatch on %s: %s", 
120                                       ldb_dn_linearize(msg2, msg2->dn), rdn->name);
121                         talloc_free(msg2);
122                         return -1;
123                 }
124         }
125
126         req->op.add.message = msg2;
127         ret = ldb_next_request(module, req);
128         req->op.add.message = msg;
129
130         talloc_free(msg2);
131
132         return ret;
133 }
134
135 static int rdn_name_modify(struct ldb_module *module, struct ldb_request *req)
136 {
137         const struct ldb_message *msg = req->op.mod.message;
138         struct ldb_message *msg2;
139         struct ldb_message_element *attribute;
140         struct ldb_dn_component *rdn;
141         int ret, i;
142
143         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_modify_record\n");
144
145         /* do not manipulate our control entries */
146         if (ldb_dn_is_special(msg->dn)) {
147                 return ldb_next_request(module, req);
148         }
149
150         /* Perhaps someone above us knows better */
151         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
152                 return ldb_next_request(module, req);
153         }
154
155         msg2 = talloc(module, struct ldb_message);
156         if (!msg2) {
157                 return -1;
158         }
159
160         msg2->dn = msg->dn;
161         msg2->num_elements = msg->num_elements;
162         msg2->private_data = msg->private_data;
163         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg2->num_elements);
164         for (i = 0; i < msg2->num_elements; i++) {
165                 msg2->elements[i] = msg->elements[i];
166         }
167         
168         rdn = ldb_dn_get_rdn(msg2, msg2->dn);
169         if (!rdn) {
170                 talloc_free(msg2);
171                 return -1;
172         }
173         
174         if (ldb_msg_add_value(msg2, "name", &rdn->value) != 0) {
175                 talloc_free(msg2);
176                 return -1;
177         }
178
179         attribute = rdn_name_find_attribute(msg2, "name");
180         if (!attribute) {
181                 talloc_free(msg2);
182                 return -1;
183         }
184
185         attribute->flags = LDB_FLAG_MOD_REPLACE;
186
187         req->op.add.message = msg2;
188         ret = ldb_next_request(module, req);
189         req->op.add.message = msg;
190
191         talloc_free(msg2);
192
193         return ret;
194 }
195
196 static int rdn_name_add_async(struct ldb_module *module, struct ldb_request *req)
197 {
198         struct ldb_request *down_req;
199         struct ldb_message *msg;
200         struct ldb_message_element *attribute;
201         struct ldb_dn_component *rdn;
202         int i, ret;
203
204         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_add_record\n");
205
206         /* do not manipulate our control entries */
207         if (ldb_dn_is_special(req->op.add.message->dn)) {
208                 return ldb_next_request(module, req);
209         }
210
211         down_req = talloc(module, struct ldb_request);
212         if (down_req == NULL) {
213                 return LDB_ERR_OPERATIONS_ERROR;
214         }
215
216         msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
217         if (msg == NULL) {
218                 return LDB_ERR_OPERATIONS_ERROR;
219         }
220
221         rdn = ldb_dn_get_rdn(msg, msg->dn);
222         if (rdn == NULL) {
223                 talloc_free(down_req);
224                 return LDB_ERR_OPERATIONS_ERROR;
225         }
226         
227         /* Perhaps someone above us tried to set this? */
228         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
229                 attribute->num_values = 0;
230         }
231
232         if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) {
233                 talloc_free(down_req);
234                 return LDB_ERR_OPERATIONS_ERROR;
235         }
236
237         attribute = rdn_name_find_attribute(msg, rdn->name);
238
239         if (!attribute) {
240                 if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) {
241                         talloc_free(down_req);
242                         return LDB_ERR_OPERATIONS_ERROR;
243                 }
244         } else {
245                 const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn->name);
246
247                 for (i = 0; i < attribute->num_values; i++) {
248                         if (handler->comparison_fn(module->ldb, msg, &rdn->value, &attribute->values[i]) == 0) {
249                                 /* overwrite so it matches in case */
250                                 attribute->values[i] = rdn->value;
251                                 break;
252                         }
253                 }
254                 if (i == attribute->num_values) {
255                         ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, 
256                                       "RDN mismatch on %s: %s", 
257                                       ldb_dn_linearize(msg, msg->dn), rdn->name);
258                         talloc_free(down_req);
259                         return LDB_ERR_OPERATIONS_ERROR;
260                 }
261         }
262
263         down_req->op.add.message = msg;
264         
265         down_req->controls = req->controls;
266         down_req->creds = req->creds;
267
268         down_req->async.context = req->async.context;
269         down_req->async.callback = req->async.callback;
270         down_req->async.timeout = req->async.timeout;
271
272         /* go on with the call chain */
273         ret = ldb_next_request(module, down_req);
274
275         /* do not free down_req as the call results may be linked to it,
276          * it will be freed when the upper level request get freed */
277         if (ret == LDB_SUCCESS) {
278                 req->async.handle = down_req->async.handle;
279         }
280
281         return ret;
282 }
283
284 static int rdn_name_modify_async(struct ldb_module *module, struct ldb_request *req)
285 {
286         struct ldb_request *down_req;
287         struct ldb_message *msg;
288         struct ldb_message_element *attribute;
289         struct ldb_dn_component *rdn;
290         int ret;
291
292         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_modify_record\n");
293
294         /* do not manipulate our control entries */
295         if (ldb_dn_is_special(req->op.mod.message->dn)) {
296                 return ldb_next_request(module, req);
297         }
298
299         /* Perhaps someone above us knows better */
300         if ((attribute = rdn_name_find_attribute(req->op.mod.message, "name")) != NULL ) {
301                 return ldb_next_request(module, req);
302         }
303
304         /* FIXME: are we sure we wont to change "name" on each and every modify operation ?? */
305         down_req = talloc(module, struct ldb_request);
306         if (down_req == NULL) {
307                 return LDB_ERR_OPERATIONS_ERROR;
308         }
309
310         msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
311         if (msg == NULL) {
312                 return LDB_ERR_OPERATIONS_ERROR;
313         }
314
315         rdn = ldb_dn_get_rdn(msg, msg->dn);
316         if (rdn == NULL) {
317                 talloc_free(down_req);
318                 return LDB_ERR_OPERATIONS_ERROR;
319         }
320         
321         if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) {
322                 talloc_free(down_req);
323                 return LDB_ERR_OPERATIONS_ERROR;
324         }
325
326         attribute = rdn_name_find_attribute(msg, "name");
327         if (!attribute) {
328                 talloc_free(down_req);
329                 return LDB_ERR_OPERATIONS_ERROR;
330         }
331
332         attribute->flags = LDB_FLAG_MOD_REPLACE;
333
334         down_req->op.add.message = msg;
335         
336         down_req->controls = req->controls;
337         down_req->creds = req->creds;
338
339         down_req->async.context = req->async.context;
340         down_req->async.callback = req->async.callback;
341         down_req->async.timeout = req->async.timeout;
342
343         /* go on with the call chain */
344         ret = ldb_next_request(module, down_req);
345
346         /* do not free down_req as the call results may be linked to it,
347          * it will be freed when the upper level request get freed */
348         if (ret == LDB_SUCCESS) {
349                 req->async.handle = down_req->async.handle;
350         }
351
352         return ret;
353 }
354
355 static int rdn_name_request(struct ldb_module *module, struct ldb_request *req)
356 {
357         switch (req->operation) {
358
359         case LDB_REQ_ADD:
360                 return rdn_name_add(module, req);
361
362         case LDB_REQ_MODIFY:
363                 return rdn_name_modify(module, req);
364
365         case LDB_ASYNC_ADD:
366                 return rdn_name_add_async(module, req);
367
368         case LDB_ASYNC_MODIFY:
369                 return rdn_name_modify_async(module, req);
370
371         default:
372                 return ldb_next_request(module, req);
373
374         }
375 }
376
377 static const struct ldb_module_ops rdn_name_ops = {
378         .name              = "rdn_name",
379         .request           = rdn_name_request
380 };
381
382
383 int ldb_rdn_name_init(void)
384 {
385         return ldb_register_module(&rdn_name_ops);
386 }