r15944: rename LDB_ASYNC_ADD -> LDB_ADD, LDB_ASYNC_MODIFY -> LDB_MODIFY, etc...
[jelmer/samba4-debian.git] / source / 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         struct ldb_request *down_req;
59         struct ldb_message *msg;
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(req->op.add.message->dn)) {
68                 return ldb_next_request(module, req);
69         }
70
71         down_req = talloc(req, struct ldb_request);
72         if (down_req == NULL) {
73                 return LDB_ERR_OPERATIONS_ERROR;
74         }
75
76         *down_req = *req;
77
78         down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
79         if (msg == NULL) {
80                 return LDB_ERR_OPERATIONS_ERROR;
81         }
82
83         rdn = ldb_dn_get_rdn(msg, msg->dn);
84         if (rdn == NULL) {
85                 talloc_free(down_req);
86                 return LDB_ERR_OPERATIONS_ERROR;
87         }
88         
89         /* Perhaps someone above us tried to set this? */
90         if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
91                 attribute->num_values = 0;
92         }
93
94         if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) {
95                 talloc_free(down_req);
96                 return LDB_ERR_OPERATIONS_ERROR;
97         }
98
99         attribute = rdn_name_find_attribute(msg, rdn->name);
100
101         if (!attribute) {
102                 if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) {
103                         talloc_free(down_req);
104                         return LDB_ERR_OPERATIONS_ERROR;
105                 }
106         } else {
107                 const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, rdn->name);
108
109                 for (i = 0; i < attribute->num_values; i++) {
110                         if (handler->comparison_fn(module->ldb, msg, &rdn->value, &attribute->values[i]) == 0) {
111                                 /* overwrite so it matches in case */
112                                 attribute->values[i] = rdn->value;
113                                 break;
114                         }
115                 }
116                 if (i == attribute->num_values) {
117                         ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, 
118                                       "RDN mismatch on %s: %s", 
119                                       ldb_dn_linearize(msg, msg->dn), rdn->name);
120                         talloc_free(down_req);
121                         return LDB_ERR_OPERATIONS_ERROR;
122                 }
123         }
124
125         /* go on with the call chain */
126         ret = ldb_next_request(module, down_req);
127
128         /* do not free down_req as the call results may be linked to it,
129          * it will be freed when the upper level request get freed */
130         if (ret == LDB_SUCCESS) {
131                 req->async.handle = down_req->async.handle;
132         }
133
134         return ret;
135 }
136
137 struct rename_async_context {
138
139         enum {RENAME_RENAME, RENAME_MODIFY} step;
140         struct ldb_request *orig_req;
141         struct ldb_request *down_req;
142         struct ldb_request *mod_req;
143 };
144
145 static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
146 {
147         struct ldb_async_handle *h;
148         struct rename_async_context *ac;
149
150         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
151
152         /* do not manipulate our control entries */
153         if (ldb_dn_is_special(req->op.rename.newdn)) {
154                 return ldb_next_request(module, req);
155         }
156
157         h = talloc_zero(req, struct ldb_async_handle);
158         if (h == NULL) {
159                 return LDB_ERR_OPERATIONS_ERROR;
160         }
161
162         h->module = module;
163
164         ac = talloc_zero(h, struct rename_async_context);
165         if (ac == NULL) {
166                 return LDB_ERR_OPERATIONS_ERROR;
167         }
168
169         h->private_data = (void *)ac;
170
171         h->state = LDB_ASYNC_INIT;
172         h->status = LDB_SUCCESS;
173
174         ac->orig_req = req;
175         ac->down_req = talloc(req, struct ldb_request);
176         if (ac->down_req == NULL) {
177                 return LDB_ERR_OPERATIONS_ERROR;
178         }
179
180         *(ac->down_req) = *req;
181
182         ac->step = RENAME_RENAME;
183
184         req->async.handle = h;
185
186         /* rename first, modify "name" if rename is ok */
187         return ldb_next_request(module, ac->down_req);
188 }
189
190 static int rdn_name_rename_do_mod(struct ldb_async_handle *h) {
191
192         struct rename_async_context *ac;
193         struct ldb_dn_component *rdn;
194         struct ldb_message *msg;
195
196         ac = talloc_get_type(h->private_data, struct rename_async_context);
197
198         rdn = ldb_dn_get_rdn(ac, ac->orig_req->op.rename.newdn);
199         if (rdn == NULL) {
200                 return LDB_ERR_OPERATIONS_ERROR;
201         }
202         
203         ac->mod_req = talloc_zero(ac, struct ldb_request);
204
205         ac->mod_req->operation = LDB_MODIFY;
206         ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
207         if (msg == NULL) {
208                 return LDB_ERR_OPERATIONS_ERROR;
209         }
210
211         msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn);
212         if (msg->dn == NULL) {
213                 return LDB_ERR_OPERATIONS_ERROR;
214         }
215
216         if (ldb_msg_add_empty(msg, rdn->name, LDB_FLAG_MOD_REPLACE) != 0) {
217                 return LDB_ERR_OPERATIONS_ERROR;
218         }
219         if (ldb_msg_add_value(msg, rdn->name, &rdn->value) != 0) {
220                 return LDB_ERR_OPERATIONS_ERROR;
221         }
222         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE) != 0) {
223                 return LDB_ERR_OPERATIONS_ERROR;
224         }
225         if (ldb_msg_add_value(msg, "name", &rdn->value) != 0) {
226                 return LDB_ERR_OPERATIONS_ERROR;
227         }
228
229         ac->mod_req->async.timeout = ac->orig_req->async.timeout;
230
231         ac->step = RENAME_MODIFY;
232
233         /* do the mod call */
234         return ldb_request(h->module->ldb, ac->mod_req);
235 }
236
237 static int rename_async_wait(struct ldb_async_handle *handle)
238 {
239         struct rename_async_context *ac;
240         int ret;
241     
242         if (!handle || !handle->private_data) {
243                 return LDB_ERR_OPERATIONS_ERROR;
244         }
245
246         if (handle->state == LDB_ASYNC_DONE) {
247                 return handle->status;
248         }
249
250         handle->state = LDB_ASYNC_PENDING;
251         handle->status = LDB_SUCCESS;
252
253         ac = talloc_get_type(handle->private_data, struct rename_async_context);
254
255         switch(ac->step) {
256         case RENAME_RENAME:
257                 ret = ldb_async_wait(ac->down_req->async.handle, LDB_WAIT_NONE);
258                 if (ret != LDB_SUCCESS) {
259                         handle->status = ret;
260                         goto done;
261                 }
262                 if (ac->down_req->async.handle->status != LDB_SUCCESS) {
263                         handle->status = ac->down_req->async.handle->status;
264                         goto done;
265                 }
266
267                 if (ac->down_req->async.handle->state != LDB_ASYNC_DONE) {
268                         return LDB_SUCCESS;
269                 }
270
271                 /* rename operation done */
272                 return rdn_name_rename_do_mod(handle);
273
274         case RENAME_MODIFY:
275                 ret = ldb_async_wait(ac->mod_req->async.handle, LDB_WAIT_NONE);
276                 if (ret != LDB_SUCCESS) {
277                         handle->status = ret;
278                         goto done;
279                 }
280                 if (ac->mod_req->async.handle->status != LDB_SUCCESS) {
281                         handle->status = ac->mod_req->async.handle->status;
282                         goto done;
283                 }
284
285                 if (ac->mod_req->async.handle->state != LDB_ASYNC_DONE) {
286                         return LDB_SUCCESS;
287                 }
288
289                 break;
290
291         default:
292                 ret = LDB_ERR_OPERATIONS_ERROR;
293                 goto done;
294         }
295
296         ret = LDB_SUCCESS;
297
298 done:
299         handle->state = LDB_ASYNC_DONE;
300         return ret;
301 }
302
303 static int rename_async_wait_all(struct ldb_async_handle *handle) {
304
305         int ret;
306
307         while (handle->state != LDB_ASYNC_DONE) {
308                 ret = rename_async_wait(handle);
309                 if (ret != LDB_SUCCESS) {
310                         return ret;
311                 }
312         }
313
314         return handle->status;
315 }
316
317 static int rdn_name_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
318 {
319         if (type == LDB_WAIT_ALL) {
320                 return rename_async_wait_all(handle);
321         } else {
322                 return rename_async_wait(handle);
323         }
324 }
325
326 static const struct ldb_module_ops rdn_name_ops = {
327         .name              = "rdn_name",
328         .add               = rdn_name_add,
329         .rename            = rdn_name_rename,
330         .async_wait        = rdn_name_async_wait
331 };
332
333
334 int ldb_rdn_name_init(void)
335 {
336         return ldb_register_module(&rdn_name_ops);
337 }