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