r4549: got rid of a lot more uses of plain talloc(), instead using
[Samba/gebeck_regimport.git] / source4 / ldap_server / ldap_simple_ldb.c
blobcdf16c99ead826228405575e1789a906b5d673fc
1 /*
2 Unix SMB/CIFS implementation.
3 LDAP server SIMPLE LDB implementation
4 Copyright (C) Stefan Metzmacher 2004
5 Copyright (C) Simo Sorce 2004
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.
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.
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.
22 #include "includes.h"
23 #include "ldap_server/ldap_server.h"
24 #include "ldap_parse.h"
25 #include "lib/ldb/include/ldb.h"
27 /* TODO: samdb_context is not a pulblic struct */
28 struct samdb_context {
29 struct ldb_context *ldb;
30 struct samdb_context **static_ptr;
34 #define ALLOC_CHECK(ptr) do {\
35 if (!(ptr)) {\
36 return NT_STATUS_NO_MEMORY;\
38 } while(0)
40 #define VALID_DN_SYNTAX(dn,i) do {\
41 if (!(dn)) {\
42 return NT_STATUS_NO_MEMORY;\
43 } else if ((dn)->comp_num < (i)) {\
44 result = LDAP_INVALID_DN_SYNTAX;\
45 errstr = "Invalid DN (" #i " components needed for '" #dn "')";\
46 goto reply;\
48 } while(0)
50 static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
51 struct ldap_SearchRequest *r)
53 NTSTATUS status;
54 void *local_ctx;
55 struct ldap_dn *basedn;
56 struct ldap_Result *done;
57 struct ldap_SearchResEntry *ent;
58 struct ldapsrv_reply *ent_r, *done_r;
59 int result = LDAP_SUCCESS;
60 struct samdb_context *samdb;
61 struct ldb_message **res = NULL;
62 int i, j, y, count = 0;
63 enum ldb_scope scope = LDB_SCOPE_DEFAULT;
64 const char **attrs = NULL;
65 const char *errstr = NULL;
67 local_ctx = talloc_named(call, 0, "sldb_Search local memory context");
68 ALLOC_CHECK(local_ctx);
70 samdb = samdb_connect(local_ctx);
71 ALLOC_CHECK(samdb);
73 basedn = ldap_parse_dn(local_ctx, r->basedn);
74 VALID_DN_SYNTAX(basedn,0);
76 DEBUG(10, ("sldb_Search: basedn: [%s]\n", basedn->dn));
77 DEBUG(10, ("sldb_Search: filter: [%s]\n", r->filter));
79 switch (r->scope) {
80 case LDAP_SEARCH_SCOPE_BASE:
81 DEBUG(10,("sldb_Search: scope: [BASE]\n"));
82 scope = LDB_SCOPE_BASE;
83 break;
84 case LDAP_SEARCH_SCOPE_SINGLE:
85 DEBUG(10,("sldb_Search: scope: [ONE]\n"));
86 scope = LDB_SCOPE_ONELEVEL;
87 break;
88 case LDAP_SEARCH_SCOPE_SUB:
89 DEBUG(10,("sldb_Search: scope: [SUB]\n"));
90 scope = LDB_SCOPE_SUBTREE;
91 break;
94 if (r->num_attributes >= 1) {
95 attrs = talloc_array_p(samdb, const char *, r->num_attributes+1);
96 ALLOC_CHECK(attrs);
98 for (i=0; i < r->num_attributes; i++) {
99 DEBUG(10,("sldb_Search: attrs: [%s]\n",r->attributes[i]));
100 attrs[i] = r->attributes[i];
102 attrs[i] = NULL;
105 count = ldb_search(samdb->ldb, basedn->dn, scope, r->filter, attrs, &res);
106 talloc_steal(samdb, res);
108 for (i=0; i < count; i++) {
109 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
110 ALLOC_CHECK(ent_r);
112 ent = &ent_r->msg.r.SearchResultEntry;
113 ent->dn = talloc_steal(ent_r, res[i]->dn);
114 ent->num_attributes = 0;
115 ent->attributes = NULL;
116 if (res[i]->num_elements == 0) {
117 goto queue_reply;
119 ent->num_attributes = res[i]->num_elements;
120 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
121 ALLOC_CHECK(ent->attributes);
122 for (j=0; j < ent->num_attributes; j++) {
123 ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
124 ent->attributes[j].num_values = 0;
125 ent->attributes[j].values = NULL;
126 if (r->attributesonly && (res[i]->elements[j].num_values == 0)) {
127 continue;
129 ent->attributes[j].num_values = res[i]->elements[j].num_values;
130 ent->attributes[j].values = talloc_array_p(ent->attributes,
131 DATA_BLOB, ent->attributes[j].num_values);
132 ALLOC_CHECK(ent->attributes[j].values);
133 for (y=0; y < ent->attributes[j].num_values; y++) {
134 ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
135 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
136 res[i]->elements[j].values[y].data);
139 queue_reply:
140 status = ldapsrv_queue_reply(call, ent_r);
141 if (!NT_STATUS_IS_OK(status)) {
142 return status;
146 reply:
147 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
148 ALLOC_CHECK(done_r);
150 if (result == LDAP_SUCCESS) {
151 if (count > 0) {
152 DEBUG(10,("sldb_Search: results: [%d]\n",count));
153 result = LDAP_SUCCESS;
154 errstr = NULL;
155 } else if (count == 0) {
156 DEBUG(10,("sldb_Search: no results\n"));
157 result = LDAP_NO_SUCH_OBJECT;
158 errstr = ldb_errstring(samdb->ldb);
159 } else if (count == -1) {
160 DEBUG(10,("sldb_Search: error\n"));
161 result = LDAP_OTHER;
162 errstr = ldb_errstring(samdb->ldb);
166 done = &done_r->msg.r.SearchResultDone;
167 done->dn = NULL;
168 done->resultcode = result;
169 done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);
170 done->referral = NULL;
172 talloc_free(local_ctx);
174 return ldapsrv_queue_reply(call, done_r);
177 static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
178 struct ldap_AddRequest *r)
180 void *local_ctx;
181 struct ldap_dn *dn;
182 struct ldap_Result *add_result;
183 struct ldapsrv_reply *add_reply;
184 int ldb_ret;
185 struct samdb_context *samdb;
186 struct ldb_message *msg = NULL;
187 int result = LDAP_SUCCESS;
188 const char *errstr = NULL;
189 int i,j;
191 local_ctx = talloc_named(call, 0, "sldb_Add local memory context");
192 ALLOC_CHECK(local_ctx);
194 samdb = samdb_connect(local_ctx);
195 ALLOC_CHECK(samdb);
197 dn = ldap_parse_dn(local_ctx, r->dn);
198 VALID_DN_SYNTAX(dn,1);
200 DEBUG(10, ("sldb_add: dn: [%s]\n", dn->dn));
202 msg = talloc_p(local_ctx, struct ldb_message);
203 ALLOC_CHECK(msg);
205 msg->dn = dn->dn;
206 msg->private_data = NULL;
207 msg->num_elements = 0;
208 msg->elements = NULL;
210 if (r->num_attributes > 0) {
211 msg->num_elements = r->num_attributes;
212 msg->elements = talloc_array_p(msg, struct ldb_message_element, msg->num_elements);
213 ALLOC_CHECK(msg->elements);
215 for (i=0; i < msg->num_elements; i++) {
216 msg->elements[i].name = discard_const_p(char, r->attributes[i].name);
217 msg->elements[i].flags = 0;
218 msg->elements[i].num_values = 0;
219 msg->elements[i].values = NULL;
221 if (r->attributes[i].num_values > 0) {
222 msg->elements[i].num_values = r->attributes[i].num_values;
223 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
224 ALLOC_CHECK(msg->elements[i].values);
226 for (j=0; j < msg->elements[i].num_values; j++) {
227 if (!(r->attributes[i].values[j].length > 0)) {
228 result = LDAP_OTHER;
229 errstr = "Empty attribute values are not allowed";
230 goto reply;
232 msg->elements[i].values[j].length = r->attributes[i].values[j].length;
233 msg->elements[i].values[j].data = r->attributes[i].values[j].data;
235 } else {
236 result = LDAP_OTHER;
237 errstr = "No attribute values are not allowed";
238 goto reply;
241 } else {
242 result = LDAP_OTHER;
243 errstr = "No attributes are not allowed";
244 goto reply;
247 reply:
248 add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
249 ALLOC_CHECK(add_reply);
251 if (result == LDAP_SUCCESS) {
252 ldb_ret = ldb_add(samdb->ldb, msg);
253 if (ldb_ret == 0) {
254 result = LDAP_SUCCESS;
255 errstr = NULL;
256 } else {
257 /* currently we have no way to tell if there was an internal ldb error
258 * or if the object was not found, return the most probable error
260 result = LDAP_OPERATIONS_ERROR;
261 errstr = ldb_errstring(samdb->ldb);
265 add_result = &add_reply->msg.r.AddResponse;
266 add_result->dn = NULL;
267 add_result->resultcode = result;
268 add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL);
269 add_result->referral = NULL;
271 talloc_free(local_ctx);
273 return ldapsrv_queue_reply(call, add_reply);
276 static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
277 struct ldap_DelRequest *r)
279 void *local_ctx;
280 struct ldap_dn *dn;
281 struct ldap_Result *del_result;
282 struct ldapsrv_reply *del_reply;
283 int ldb_ret;
284 struct samdb_context *samdb;
285 const char *errstr = NULL;
286 int result = LDAP_SUCCESS;
288 local_ctx = talloc_named(call, 0, "sldb_Del local memory context");
289 ALLOC_CHECK(local_ctx);
291 samdb = samdb_connect(local_ctx);
292 ALLOC_CHECK(samdb);
294 dn = ldap_parse_dn(local_ctx, r->dn);
295 VALID_DN_SYNTAX(dn,1);
297 DEBUG(10, ("sldb_Del: dn: [%s]\n", dn->dn));
299 reply:
300 del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
301 ALLOC_CHECK(del_reply);
303 if (result == LDAP_SUCCESS) {
304 ldb_ret = ldb_delete(samdb->ldb, dn->dn);
305 if (ldb_ret == 0) {
306 result = LDAP_SUCCESS;
307 errstr = NULL;
308 } else {
309 /* currently we have no way to tell if there was an internal ldb error
310 * or if the object was not found, return the most probable error
312 result = LDAP_NO_SUCH_OBJECT;
313 errstr = ldb_errstring(samdb->ldb);
317 del_result = &del_reply->msg.r.DelResponse;
318 del_result->dn = NULL;
319 del_result->resultcode = result;
320 del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL);
321 del_result->referral = NULL;
323 talloc_free(local_ctx);
325 return ldapsrv_queue_reply(call, del_reply);
328 static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
329 struct ldap_ModifyRequest *r)
331 void *local_ctx;
332 struct ldap_dn *dn;
333 struct ldap_Result *modify_result;
334 struct ldapsrv_reply *modify_reply;
335 int ldb_ret;
336 struct samdb_context *samdb;
337 struct ldb_message *msg = NULL;
338 int result = LDAP_SUCCESS;
339 const char *errstr = NULL;
340 int i,j;
342 local_ctx = talloc_named(call, 0, "sldb_Modify local memory context");
343 ALLOC_CHECK(local_ctx);
345 samdb = samdb_connect(local_ctx);
346 ALLOC_CHECK(samdb);
348 dn = ldap_parse_dn(local_ctx, r->dn);
349 VALID_DN_SYNTAX(dn,1);
351 DEBUG(10, ("sldb_modify: dn: [%s]\n", dn->dn));
353 msg = talloc_p(local_ctx, struct ldb_message);
354 ALLOC_CHECK(msg);
356 msg->dn = dn->dn;
357 msg->private_data = NULL;
358 msg->num_elements = 0;
359 msg->elements = NULL;
361 if (r->num_mods > 0) {
362 msg->num_elements = r->num_mods;
363 msg->elements = talloc_array_p(msg, struct ldb_message_element, r->num_mods);
364 ALLOC_CHECK(msg->elements);
366 for (i=0; i < msg->num_elements; i++) {
367 msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name);
368 msg->elements[i].num_values = 0;
369 msg->elements[i].values = NULL;
371 switch (r->mods[i].type) {
372 default:
373 result = LDAP_PROTOCOL_ERROR;
374 errstr = "Invalid LDAP_MODIFY_* type";
375 goto reply;
376 case LDAP_MODIFY_ADD:
377 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
378 break;
379 case LDAP_MODIFY_DELETE:
380 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
381 break;
382 case LDAP_MODIFY_REPLACE:
383 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
384 break;
387 msg->elements[i].num_values = r->mods[i].attrib.num_values;
388 if (msg->elements[i].num_values > 0) {
389 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
390 ALLOC_CHECK(msg->elements[i].values);
392 for (j=0; j < msg->elements[i].num_values; j++) {
393 if (!(r->mods[i].attrib.values[j].length > 0)) {
394 result = LDAP_OTHER;
395 errstr = "Empty attribute values are not allowed";
396 goto reply;
398 msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length;
399 msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data;
403 } else {
404 result = LDAP_OTHER;
405 errstr = "No mods are not allowed";
406 goto reply;
409 reply:
410 modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
411 ALLOC_CHECK(modify_reply);
413 if (result == LDAP_SUCCESS) {
414 ldb_ret = ldb_modify(samdb->ldb, msg);
415 if (ldb_ret == 0) {
416 result = LDAP_SUCCESS;
417 errstr = NULL;
418 } else {
419 /* currently we have no way to tell if there was an internal ldb error
420 * or if the object was not found, return the most probable error
422 result = LDAP_OPERATIONS_ERROR;
423 errstr = ldb_errstring(samdb->ldb);
427 modify_result = &modify_reply->msg.r.AddResponse;
428 modify_result->dn = NULL;
429 modify_result->resultcode = result;
430 modify_result->errormessage = (errstr?talloc_strdup(modify_reply,errstr):NULL);
431 modify_result->referral = NULL;
433 talloc_free(local_ctx);
435 return ldapsrv_queue_reply(call, modify_reply);
438 static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
439 struct ldap_CompareRequest *r)
441 void *local_ctx;
442 struct ldap_dn *dn;
443 struct ldap_Result *compare;
444 struct ldapsrv_reply *compare_r;
445 int result = LDAP_SUCCESS;
446 struct samdb_context *samdb;
447 struct ldb_message **res = NULL;
448 const char *attrs[1];
449 const char *errstr = NULL;
450 const char *filter = NULL;
451 int count;
453 local_ctx = talloc_named(call, 0, "sldb_Compare local_memory_context");
454 ALLOC_CHECK(local_ctx);
456 samdb = samdb_connect(local_ctx);
457 ALLOC_CHECK(samdb);
459 dn = ldap_parse_dn(local_ctx, r->dn);
460 VALID_DN_SYNTAX(dn,1);
462 DEBUG(10, ("sldb_Compare: dn: [%s]\n", dn->dn));
463 filter = talloc_asprintf(local_ctx, "(%s=%*s)", r->attribute, r->value.length, r->value.data);
464 ALLOC_CHECK(filter);
466 DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter));
468 attrs[0] = NULL;
470 reply:
471 compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
472 ALLOC_CHECK(compare_r);
474 if (result == LDAP_SUCCESS) {
475 count = ldb_search(samdb->ldb, dn->dn, LDB_SCOPE_BASE, filter, attrs, &res);
476 talloc_steal(samdb, res);
477 if (count == 1) {
478 DEBUG(10,("sldb_Compare: matched\n"));
479 result = LDAP_COMPARE_TRUE;
480 errstr = NULL;
481 } else if (count == 0) {
482 DEBUG(10,("sldb_Compare: doesn't matched\n"));
483 result = LDAP_COMPARE_FALSE;
484 errstr = NULL;
485 } else if (count > 1) {
486 result = LDAP_OTHER;
487 errstr = "too many objects match";
488 DEBUG(10,("sldb_Compare: %d results: %s\n", count, errstr));
489 } else if (count == -1) {
490 result = LDAP_OTHER;
491 errstr = ldb_errstring(samdb->ldb);
492 DEBUG(10,("sldb_Compare: error: %s\n", errstr));
496 compare = &compare_r->msg.r.CompareResponse;
497 compare->dn = NULL;
498 compare->resultcode = result;
499 compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL);
500 compare->referral = NULL;
502 talloc_free(local_ctx);
504 return ldapsrv_queue_reply(call, compare_r);
507 NTSTATUS sldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyDNRequest *r)
509 void *local_ctx;
510 struct ldap_dn *olddn, *newrdn, *newsuperior;
511 struct ldap_Result *modifydn;
512 struct ldapsrv_reply *modifydn_r;
513 int ldb_ret;
514 struct samdb_context *samdb;
515 const char *errstr = NULL;
516 int result = LDAP_SUCCESS;
517 const char *newdn = NULL;
518 char *parentdn = NULL;
520 local_ctx = talloc_named(call, 0, "sldb_ModifyDN local memory context");
521 ALLOC_CHECK(local_ctx);
523 samdb = samdb_connect(local_ctx);
524 ALLOC_CHECK(samdb);
526 olddn = ldap_parse_dn(local_ctx, r->dn);
527 VALID_DN_SYNTAX(olddn,2);
529 newrdn = ldap_parse_dn(local_ctx, r->newrdn);
530 VALID_DN_SYNTAX(newrdn,1);
532 DEBUG(10, ("sldb_ModifyDN: olddn: [%s]\n", olddn->dn));
533 DEBUG(10, ("sldb_ModifyDN: newrdn: [%s]\n", newrdn->dn));
535 /* we can't handle the rename if we should not remove the old dn */
536 if (!r->deleteolddn) {
537 result = LDAP_UNWILLING_TO_PERFORM;
538 errstr = "Old RDN must be deleted";
539 goto reply;
542 if (newrdn->comp_num > 1) {
543 result = LDAP_NAMING_VIOLATION;
544 errstr = "Error new RDN invalid";
545 goto reply;
548 if (r->newsuperior) {
549 newsuperior = ldap_parse_dn(local_ctx, r->newsuperior);
550 VALID_DN_SYNTAX(newsuperior,0);
551 DEBUG(10, ("sldb_ModifyDN: newsuperior: [%s]\n", newsuperior->dn));
553 if (newsuperior->comp_num < 1) {
554 result = LDAP_AFFECTS_MULTIPLE_DSAS;
555 errstr = "Error new Superior DN invalid";
556 goto reply;
558 parentdn = newsuperior->dn;
561 if (!parentdn) {
562 int i;
563 parentdn = talloc_strdup(local_ctx, olddn->components[1]->component);
564 ALLOC_CHECK(parentdn);
565 for(i=2; i < olddn->comp_num; i++) {
566 char *old = parentdn;
567 parentdn = talloc_asprintf(local_ctx, "%s,%s", old, olddn->components[i]->component);
568 ALLOC_CHECK(parentdn);
569 talloc_free(old);
572 newdn = talloc_asprintf(local_ctx, "%s,%s", newrdn->dn, parentdn);
573 ALLOC_CHECK(newdn);
575 reply:
576 modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse);
577 ALLOC_CHECK(modifydn_r);
579 if (result == LDAP_SUCCESS) {
580 ldb_ret = ldb_rename(samdb->ldb, olddn->dn, newdn);
581 if (ldb_ret == 0) {
582 result = LDAP_SUCCESS;
583 errstr = NULL;
584 } else {
585 /* currently we have no way to tell if there was an internal ldb error
586 * or if the object was not found, return the most probable error
588 result = LDAP_NO_SUCH_OBJECT;
589 errstr = ldb_errstring(samdb->ldb);
593 modifydn = &modifydn_r->msg.r.ModifyDNResponse;
594 modifydn->dn = NULL;
595 modifydn->resultcode = result;
596 modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL);
597 modifydn->referral = NULL;
599 talloc_free(local_ctx);
601 return ldapsrv_queue_reply(call, modifydn_r);
604 static const struct ldapsrv_partition_ops sldb_ops = {
605 .Search = sldb_Search,
606 .Add = sldb_Add,
607 .Del = sldb_Del,
608 .Modify = sldb_Modify,
609 .Compare = sldb_Compare,
610 .ModifyDN = sldb_ModifyDN
613 const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void)
615 return &sldb_ops;