r12608: Remove some unused #include lines.
[abartlet/samba.git/.git] / source4 / ldap_server / ldap_simple_ldb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP server SIMPLE LDB implementation
4    Copyright (C) Stefan Metzmacher 2004
5    Copyright (C) Simo Sorce 2004
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "ldap_server/ldap_server.h"
24 #include "lib/ldb/include/ldb_errors.h"
25 #include "dsdb/samdb/samdb.h"
26
27 #define VALID_DN_SYNTAX(dn,i) do {\
28         if (!(dn)) {\
29                 return NT_STATUS_NO_MEMORY;\
30         } else if ((dn)->comp_num < (i)) {\
31                 result = LDAP_INVALID_DN_SYNTAX;\
32                 errstr = "Invalid DN (" #i " components needed for '" #dn "')";\
33                 goto reply;\
34         }\
35 } while(0)
36
37
38 /*
39   map an error code from ldb to ldap
40 */
41 static int sldb_map_error(struct ldapsrv_partition *partition, int ldb_ret,
42                           const char **errstr)
43 {
44         struct ldb_context *samdb = talloc_get_type(partition->private, 
45                                                     struct ldb_context);
46         *errstr = ldb_errstring(samdb);
47
48         /* its 1:1 for now */
49         return ldb_ret;
50 }
51
52 /*
53   connect to the sam database
54 */
55 NTSTATUS sldb_Init(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn) 
56 {
57         TALLOC_CTX *mem_ctx = talloc_new(partition);
58         struct ldb_context *ldb;
59         ldb = samdb_connect(mem_ctx, conn->session_info);
60         if (ldb == NULL) {
61                 talloc_free(mem_ctx);
62                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
63         }
64         talloc_steal(partition, ldb);
65         partition->private = ldb;
66         talloc_free(mem_ctx);
67         return NT_STATUS_OK;
68 }
69
70 /*
71   Re-connect to the ldb after a bind (this does not handle the bind
72   itself, but just notes the change in credentials)
73 */
74 NTSTATUS sldb_Bind(struct ldapsrv_partition *partition, struct ldapsrv_connection *conn) 
75 {
76         struct ldb_context *samdb = partition->private;
77         NTSTATUS status;
78         status = sldb_Init(partition, conn);
79         if (NT_STATUS_IS_OK(status)) {
80                 /* don't leak the old LDB */
81                 talloc_free(samdb);
82         }
83         return status;
84 }
85
86 static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
87                             struct ldap_SearchRequest *r)
88 {
89         void *local_ctx;
90         struct ldb_dn *basedn;
91         struct ldap_Result *done;
92         struct ldap_SearchResEntry *ent;
93         struct ldapsrv_reply *ent_r, *done_r;
94         int result = LDAP_SUCCESS;
95         struct ldb_context *samdb;
96         struct ldb_result *res = NULL;
97         int i, j, y, ret;
98         int success_limit = 1;
99         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
100         const char **attrs = NULL;
101         const char *errstr = NULL;
102         struct ldb_request lreq;
103
104         local_ctx = talloc_named(call, 0, "sldb_Search local memory context");
105         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
106
107         samdb = talloc_get_type(partition->private, struct ldb_context);
108
109         basedn = ldb_dn_explode(local_ctx, r->basedn);
110         VALID_DN_SYNTAX(basedn, 0);
111
112         DEBUG(10, ("sldb_Search: basedn: [%s]\n", r->basedn));
113         DEBUG(10, ("sldb_Search: filter: [%s]\n", ldb_filter_from_tree(call, r->tree)));
114
115         switch (r->scope) {
116                 case LDAP_SEARCH_SCOPE_BASE:
117                         DEBUG(10,("sldb_Search: scope: [BASE]\n"));
118                         scope = LDB_SCOPE_BASE;
119                         success_limit = 0;
120                         break;
121                 case LDAP_SEARCH_SCOPE_SINGLE:
122                         DEBUG(10,("sldb_Search: scope: [ONE]\n"));
123                         scope = LDB_SCOPE_ONELEVEL;
124                         success_limit = 0;
125                         break;
126                 case LDAP_SEARCH_SCOPE_SUB:
127                         DEBUG(10,("sldb_Search: scope: [SUB]\n"));
128                         scope = LDB_SCOPE_SUBTREE;
129                         success_limit = 0;
130                         break;
131         }
132
133         if (r->num_attributes >= 1) {
134                 attrs = talloc_array(samdb, const char *, r->num_attributes+1);
135                 NT_STATUS_HAVE_NO_MEMORY(attrs);
136
137                 for (i=0; i < r->num_attributes; i++) {
138                         DEBUG(10,("sldb_Search: attrs: [%s]\n",r->attributes[i]));
139                         attrs[i] = r->attributes[i];
140                 }
141                 attrs[i] = NULL;
142         }
143
144         DEBUG(5,("ldb_request dn=%s filter=%s\n", 
145                  r->basedn, ldb_filter_from_tree(call, r->tree)));
146
147         ZERO_STRUCT(lreq);
148         lreq.operation = LDB_REQ_SEARCH;
149         lreq.op.search.base = basedn;
150         lreq.op.search.scope = scope;
151         lreq.op.search.tree = r->tree;
152         lreq.op.search.attrs = attrs;
153
154         ret = ldb_request(samdb, &lreq);
155
156         res = talloc_steal(samdb, lreq.op.search.res);
157
158         if (ret == LDB_SUCCESS) {
159                 for (i = 0; i < res->count; i++) {
160                         ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
161                         NT_STATUS_HAVE_NO_MEMORY(ent_r);
162
163                         ent = &ent_r->msg->r.SearchResultEntry;
164                         ent->dn = ldb_dn_linearize(ent_r, res->msgs[i]->dn);
165                         ent->num_attributes = 0;
166                         ent->attributes = NULL;
167                         if (res->msgs[i]->num_elements == 0) {
168                                 goto queue_reply;
169                         }
170                         ent->num_attributes = res->msgs[i]->num_elements;
171                         ent->attributes = talloc_array(ent_r, struct ldb_message_element, ent->num_attributes);
172                         NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
173                         for (j=0; j < ent->num_attributes; j++) {
174                                 ent->attributes[j].name = talloc_steal(ent->attributes, res->msgs[i]->elements[j].name);
175                                 ent->attributes[j].num_values = 0;
176                                 ent->attributes[j].values = NULL;
177                                 if (r->attributesonly && (res->msgs[i]->elements[j].num_values == 0)) {
178                                         continue;
179                                 }
180                                 ent->attributes[j].num_values = res->msgs[i]->elements[j].num_values;
181                                 ent->attributes[j].values = talloc_array(ent->attributes,
182                                                                 DATA_BLOB, ent->attributes[j].num_values);
183                                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
184                                 for (y=0; y < ent->attributes[j].num_values; y++) {
185                                         ent->attributes[j].values[y].length = res->msgs[i]->elements[j].values[y].length;
186                                         ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
187                                                                                 res->msgs[i]->elements[j].values[y].data);
188                                 }
189                         }
190 queue_reply:
191                         ldapsrv_queue_reply(call, ent_r);
192                 }
193         }
194
195 reply:
196         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
197         NT_STATUS_HAVE_NO_MEMORY(done_r);
198
199         if (ret == LDB_SUCCESS) {
200                 if (res->count >= success_limit) {
201                         DEBUG(10,("sldb_Search: results: [%d]\n", res->count));
202                         result = LDAP_SUCCESS;
203                         errstr = NULL;
204                 } else if (res->count == 0) {
205                         DEBUG(10,("sldb_Search: no results\n"));
206                         result = LDAP_NO_SUCH_OBJECT;
207                         errstr = ldb_errstring(samdb);
208                 }
209         } else {
210                 DEBUG(10,("sldb_Search: error\n"));
211                 result = ret;
212                 errstr = ldb_errstring(samdb);
213         }
214
215         done = &done_r->msg->r.SearchResultDone;
216         done->dn = NULL;
217         done->resultcode = result;
218         done->errormessage = (errstr?talloc_strdup(done_r, errstr):NULL);
219         done->referral = NULL;
220
221         talloc_free(local_ctx);
222
223         ldapsrv_queue_reply(call, done_r);
224         return NT_STATUS_OK;
225 }
226
227 static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
228                          struct ldap_AddRequest *r)
229 {
230         void *local_ctx;
231         struct ldb_dn *dn;
232         struct ldap_Result *add_result;
233         struct ldapsrv_reply *add_reply;
234         int ldb_ret;
235         struct ldb_context *samdb;
236         struct ldb_message *msg = NULL;
237         int result = LDAP_SUCCESS;
238         const char *errstr = NULL;
239         int i,j;
240
241         local_ctx = talloc_named(call, 0, "sldb_Add local memory context");
242         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
243
244         samdb = talloc_get_type(partition->private, struct ldb_context);
245
246         dn = ldb_dn_explode(local_ctx, r->dn);
247         VALID_DN_SYNTAX(dn,1);
248
249         DEBUG(10, ("sldb_add: dn: [%s]\n", r->dn));
250
251         msg = talloc(local_ctx, struct ldb_message);
252         NT_STATUS_HAVE_NO_MEMORY(msg);
253
254         msg->dn = dn;
255         msg->private_data = NULL;
256         msg->num_elements = 0;
257         msg->elements = NULL;
258
259         if (r->num_attributes > 0) {
260                 msg->num_elements = r->num_attributes;
261                 msg->elements = talloc_array(msg, struct ldb_message_element, msg->num_elements);
262                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
263
264                 for (i=0; i < msg->num_elements; i++) {
265                         msg->elements[i].name = discard_const_p(char, r->attributes[i].name);
266                         msg->elements[i].flags = 0;
267                         msg->elements[i].num_values = 0;
268                         msg->elements[i].values = NULL;
269                         
270                         if (r->attributes[i].num_values > 0) {
271                                 msg->elements[i].num_values = r->attributes[i].num_values;
272                                 msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values);
273                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
274
275                                 for (j=0; j < msg->elements[i].num_values; j++) {
276                                         if (!(r->attributes[i].values[j].length > 0)) {
277                                                 result = LDAP_OTHER;
278                                                 errstr = "Empty attribute values are not allowed";
279                                                 goto reply;
280                                         }
281                                         msg->elements[i].values[j].length = r->attributes[i].values[j].length;
282                                         msg->elements[i].values[j].data = r->attributes[i].values[j].data;                      
283                                 }
284                         } else {
285                                 result = LDAP_OTHER;
286                                 errstr = "No attribute values are not allowed";
287                                 goto reply;
288                         }
289                 }
290         } else {
291                 result = LDAP_OTHER;
292                 errstr = "No attributes are not allowed";
293                 goto reply;
294         }
295
296 reply:
297         add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
298         NT_STATUS_HAVE_NO_MEMORY(add_reply);
299
300         if (result == LDAP_SUCCESS) {
301                 ldb_ret = ldb_add(samdb, msg);
302                 result = sldb_map_error(partition, ldb_ret, &errstr);
303         }
304
305         add_result = &add_reply->msg->r.AddResponse;
306         add_result->dn = NULL;
307         add_result->resultcode = result;
308         add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL);
309         add_result->referral = NULL;
310
311         talloc_free(local_ctx);
312
313         ldapsrv_queue_reply(call, add_reply);
314         return NT_STATUS_OK;
315 }
316
317 static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
318                                      struct ldap_DelRequest *r)
319 {
320         void *local_ctx;
321         struct ldb_dn *dn;
322         struct ldap_Result *del_result;
323         struct ldapsrv_reply *del_reply;
324         int ldb_ret;
325         struct ldb_context *samdb;
326         const char *errstr = NULL;
327         int result = LDAP_SUCCESS;
328
329         local_ctx = talloc_named(call, 0, "sldb_Del local memory context");
330         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
331
332         samdb = talloc_get_type(partition->private, struct ldb_context);
333
334         dn = ldb_dn_explode(local_ctx, r->dn);
335         VALID_DN_SYNTAX(dn,1);
336
337         DEBUG(10, ("sldb_Del: dn: [%s]\n", r->dn));
338
339 reply:
340         del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
341         NT_STATUS_HAVE_NO_MEMORY(del_reply);
342
343         if (result == LDAP_SUCCESS) {
344                 ldb_ret = ldb_delete(samdb, dn);
345                 result = sldb_map_error(partition, ldb_ret, &errstr);
346         }
347
348         del_result = &del_reply->msg->r.DelResponse;
349         del_result->dn = NULL;
350         del_result->resultcode = result;
351         del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL);
352         del_result->referral = NULL;
353
354         talloc_free(local_ctx);
355
356         ldapsrv_queue_reply(call, del_reply);
357         return NT_STATUS_OK;
358 }
359
360 static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
361                                      struct ldap_ModifyRequest *r)
362 {
363         void *local_ctx;
364         struct ldb_dn *dn;
365         struct ldap_Result *modify_result;
366         struct ldapsrv_reply *modify_reply;
367         int ldb_ret;
368         struct ldb_context *samdb;
369         struct ldb_message *msg = NULL;
370         int result = LDAP_SUCCESS;
371         const char *errstr = NULL;
372         int i,j;
373
374         local_ctx = talloc_named(call, 0, "sldb_Modify local memory context");
375         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
376
377         samdb = talloc_get_type(partition->private, struct ldb_context);
378
379         dn = ldb_dn_explode(local_ctx, r->dn);
380         VALID_DN_SYNTAX(dn, 1);
381
382         DEBUG(10, ("sldb_modify: dn: [%s]\n", r->dn));
383
384         msg = talloc(local_ctx, struct ldb_message);
385         NT_STATUS_HAVE_NO_MEMORY(msg);
386
387         msg->dn = dn;
388         msg->private_data = NULL;
389         msg->num_elements = 0;
390         msg->elements = NULL;
391
392         if (r->num_mods > 0) {
393                 msg->num_elements = r->num_mods;
394                 msg->elements = talloc_array(msg, struct ldb_message_element, r->num_mods);
395                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
396
397                 for (i=0; i < msg->num_elements; i++) {
398                         msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name);
399                         msg->elements[i].num_values = 0;
400                         msg->elements[i].values = NULL;
401
402                         switch (r->mods[i].type) {
403                         default:
404                                 result = LDAP_PROTOCOL_ERROR;
405                                 errstr = "Invalid LDAP_MODIFY_* type";
406                                 goto reply;
407                         case LDAP_MODIFY_ADD:
408                                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
409                                 break;
410                         case LDAP_MODIFY_DELETE:
411                                 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
412                                 break;
413                         case LDAP_MODIFY_REPLACE:
414                                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
415                                 break;
416                         }
417
418                         msg->elements[i].num_values = r->mods[i].attrib.num_values;
419                         if (msg->elements[i].num_values > 0) {
420                                 msg->elements[i].values = talloc_array(msg, struct ldb_val, msg->elements[i].num_values);
421                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
422
423                                 for (j=0; j < msg->elements[i].num_values; j++) {
424                                         if (!(r->mods[i].attrib.values[j].length > 0)) {
425                                                 result = LDAP_OTHER;
426                                                 errstr = "Empty attribute values are not allowed";
427                                                 goto reply;
428                                         }
429                                         msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length;
430                                         msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data;                     
431                                 }
432                         }
433                 }
434         } else {
435                 result = LDAP_OTHER;
436                 errstr = "No mods are not allowed";
437                 goto reply;
438         }
439
440 reply:
441         modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
442         NT_STATUS_HAVE_NO_MEMORY(modify_reply);
443
444         if (result == LDAP_SUCCESS) {
445                 ldb_ret = ldb_modify(samdb, msg);
446                 result = sldb_map_error(partition, ldb_ret, &errstr);
447         }
448
449         modify_result = &modify_reply->msg->r.AddResponse;
450         modify_result->dn = NULL;
451         modify_result->resultcode = result;
452         modify_result->errormessage = (errstr?talloc_strdup(modify_reply,errstr):NULL);
453         modify_result->referral = NULL;
454
455         talloc_free(local_ctx);
456
457         ldapsrv_queue_reply(call, modify_reply);
458         return NT_STATUS_OK;
459 }
460
461 static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
462                                      struct ldap_CompareRequest *r)
463 {
464         void *local_ctx;
465         struct ldb_dn *dn;
466         struct ldap_Result *compare;
467         struct ldapsrv_reply *compare_r;
468         int result = LDAP_SUCCESS;
469         struct ldb_context *samdb;
470         struct ldb_result *res = NULL;
471         const char *attrs[1];
472         const char *errstr = NULL;
473         const char *filter = NULL;
474         int ret;
475
476         local_ctx = talloc_named(call, 0, "sldb_Compare local_memory_context");
477         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
478
479         samdb = talloc_get_type(partition->private, struct ldb_context);
480
481         dn = ldb_dn_explode(local_ctx, r->dn);
482         VALID_DN_SYNTAX(dn, 1);
483
484         DEBUG(10, ("sldb_Compare: dn: [%s]\n", r->dn));
485         filter = talloc_asprintf(local_ctx, "(%s=%*s)", r->attribute, 
486                                  (int)r->value.length, r->value.data);
487         NT_STATUS_HAVE_NO_MEMORY(filter);
488
489         DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter));
490
491         attrs[0] = NULL;
492
493 reply:
494         compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
495         NT_STATUS_HAVE_NO_MEMORY(compare_r);
496
497         if (result == LDAP_SUCCESS) {
498                 ret = ldb_search(samdb, dn, LDB_SCOPE_BASE, filter, attrs, &res);
499                 talloc_steal(samdb, res);
500                 if (ret != LDB_SUCCESS) {
501                         result = LDAP_OTHER;
502                         errstr = ldb_errstring(samdb);
503                         DEBUG(10,("sldb_Compare: error: %s\n", errstr));
504                 } else if (res->count == 0) {
505                         DEBUG(10,("sldb_Compare: doesn't matched\n"));
506                         result = LDAP_COMPARE_FALSE;
507                         errstr = NULL;
508                 } else if (res->count == 1) {
509                         DEBUG(10,("sldb_Compare: matched\n"));
510                         result = LDAP_COMPARE_TRUE;
511                         errstr = NULL;
512                 } else if (res->count > 1) {
513                         result = LDAP_OTHER;
514                         errstr = "too many objects match";
515                         DEBUG(10,("sldb_Compare: %d results: %s\n", res->count, errstr));
516                 }
517         }
518
519         compare = &compare_r->msg->r.CompareResponse;
520         compare->dn = NULL;
521         compare->resultcode = result;
522         compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL);
523         compare->referral = NULL;
524
525         talloc_free(local_ctx);
526
527         ldapsrv_queue_reply(call, compare_r);
528         return NT_STATUS_OK;
529 }
530
531 static NTSTATUS sldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyDNRequest *r)
532 {
533         void *local_ctx;
534         struct ldb_dn *olddn, *newdn, *newrdn;
535         struct ldb_dn *parentdn = NULL;
536         struct ldap_Result *modifydn;
537         struct ldapsrv_reply *modifydn_r;
538         int ldb_ret;
539         struct ldb_context *samdb;
540         const char *errstr = NULL;
541         int result = LDAP_SUCCESS;
542
543         local_ctx = talloc_named(call, 0, "sldb_ModifyDN local memory context");
544         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
545
546         samdb = talloc_get_type(partition->private, struct ldb_context);
547
548         olddn = ldb_dn_explode(local_ctx, r->dn);
549         VALID_DN_SYNTAX(olddn, 2);
550
551         newrdn = ldb_dn_explode(local_ctx, r->newrdn);
552         VALID_DN_SYNTAX(newrdn, 1);
553
554         DEBUG(10, ("sldb_ModifyDN: olddn: [%s]\n", r->dn));
555         DEBUG(10, ("sldb_ModifyDN: newrdn: [%s]\n", r->newrdn));
556
557         /* we can't handle the rename if we should not remove the old dn */
558         if (!r->deleteolddn) {
559                 result = LDAP_UNWILLING_TO_PERFORM;
560                 errstr = "Old RDN must be deleted";
561                 goto reply;
562         }
563
564         if (newrdn->comp_num > 1) {
565                 result = LDAP_NAMING_VIOLATION;
566                 errstr = "Error new RDN invalid";
567                 goto reply;
568         }
569
570         if (r->newsuperior) {
571                 parentdn = ldb_dn_explode(local_ctx, r->newsuperior);
572                 VALID_DN_SYNTAX(parentdn, 0);
573                 DEBUG(10, ("sldb_ModifyDN: newsuperior: [%s]\n", r->newsuperior));
574                 
575                 if (parentdn->comp_num < 1) {
576                         result = LDAP_AFFECTS_MULTIPLE_DSAS;
577                         errstr = "Error new Superior DN invalid";
578                         goto reply;
579                 }
580         }
581
582         if (!parentdn) {
583                 parentdn = ldb_dn_get_parent(local_ctx, olddn);
584                 NT_STATUS_HAVE_NO_MEMORY(parentdn);
585         }
586
587         newdn = ldb_dn_make_child(local_ctx, ldb_dn_get_rdn(local_ctx, newrdn), parentdn);
588         NT_STATUS_HAVE_NO_MEMORY(newdn);
589
590 reply:
591         modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse);
592         NT_STATUS_HAVE_NO_MEMORY(modifydn_r);
593
594         if (result == LDAP_SUCCESS) {
595                 ldb_ret = ldb_rename(samdb, olddn, newdn);
596                 result = sldb_map_error(partition, ldb_ret, &errstr);
597         }
598
599         modifydn = &modifydn_r->msg->r.ModifyDNResponse;
600         modifydn->dn = NULL;
601         modifydn->resultcode = result;
602         modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL);
603         modifydn->referral = NULL;
604
605         talloc_free(local_ctx);
606
607         ldapsrv_queue_reply(call, modifydn_r);
608         return NT_STATUS_OK;
609 }
610
611 static const struct ldapsrv_partition_ops sldb_ops = {
612         .Init           = sldb_Init,
613         .Bind           = sldb_Bind,
614         .Search         = sldb_Search,
615         .Add            = sldb_Add,
616         .Del            = sldb_Del,
617         .Modify         = sldb_Modify,
618         .Compare        = sldb_Compare,
619         .ModifyDN       = sldb_ModifyDN
620 };
621
622 const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void)
623 {
624         return &sldb_ops;
625 }