2 Unix SMB/CIFS implementation.
3 LDAP server SIMPLE LDB implementation
4 Copyright (C) Stefan Metzmacher 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /* TODO: samdb_context is not a pulblic struct */
24 struct samdb_context {
25 struct ldb_context *ldb;
26 struct samdb_context **static_ptr;
30 #define ALLOC_CHECK(ptr) do {\
32 return NT_STATUS_NO_MEMORY;\
38 fix the DN removing unneded non-significative spaces
39 this function ASSUME the string is talloced
41 static char *sldb_fix_dn(const char *dn)
43 char *new_dn, *n, *current;
46 /* alloc enough room to host the whole dn as multibyte string */
47 new_dn = talloc(dn, strlen(dn) + 1);
49 DEBUG(0, ("sldb_fix_dn: Out of memory!"));
54 while (dn[i] != '\0') {
55 /* it is legal to check for ascii chars in utf-8 as it is
56 * guaranted to never contain ascii chars (up to 0x7F) as part
57 * of a multibyte sequence */
61 if (dn[i] == ',' || dn[i] == '=') {
62 /* skip spaces after ',' or '=' */
63 for (++i; dn[i] == ' '; i++) ;
68 /* check if there's a ',' after these spaces */
69 for (k = i; dn[k] == ' '; k++) ;
75 /* fill the dest buffer with the spaces */
76 for (; dn[i] == ' '; i++, j++) {
91 static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
92 struct ldap_SearchRequest *r)
95 struct ldap_Result *done;
96 struct ldap_SearchResEntry *ent;
97 struct ldapsrv_reply *ent_r, *done_r;
99 struct samdb_context *samdb;
100 struct ldb_message **res;
102 struct ldb_context *ldb;
103 enum ldb_scope scope = LDB_SCOPE_DEFAULT;
104 const char **attrs = NULL;
108 samdb = samdb_connect(call);
110 basedn = sldb_fix_dn(r->basedn);
111 if (basedn == NULL) {
112 return NT_STATUS_NO_MEMORY;
115 DEBUG(10, ("sldb_Search: basedn: [%s]\n", basedn));
116 DEBUG(10, ("sldb_Search: filter: [%s]\n", r->filter));
119 case LDAP_SEARCH_SCOPE_BASE:
120 DEBUG(10,("sldb_Search: scope: [BASE]\n"));
121 scope = LDB_SCOPE_BASE;
123 case LDAP_SEARCH_SCOPE_SINGLE:
124 DEBUG(10,("sldb_Search: scope: [ONE]\n"));
125 scope = LDB_SCOPE_ONELEVEL;
127 case LDAP_SEARCH_SCOPE_SUB:
128 DEBUG(10,("sldb_Search: scope: [SUB]\n"));
129 scope = LDB_SCOPE_SUBTREE;
133 if (r->num_attributes >= 1) {
134 attrs = talloc_array_p(samdb, const char *, r->num_attributes+1);
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];
144 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
145 count = ldb_search(ldb, basedn, scope, r->filter, attrs, &res);
147 for (i=0; i < count; i++) {
148 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
151 ent = &ent_r->msg.r.SearchResultEntry;
152 ent->dn = talloc_steal(ent_r, res[i]->dn);
153 ent->num_attributes = 0;
154 ent->attributes = NULL;
155 if (res[i]->num_elements == 0) {
158 ent->num_attributes = res[i]->num_elements;
159 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
160 ALLOC_CHECK(ent->attributes);
161 for (j=0; j < ent->num_attributes; j++) {
162 ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
163 ent->attributes[j].num_values = 0;
164 ent->attributes[j].values = NULL;
165 if (r->attributesonly && (res[i]->elements[j].num_values == 0)) {
168 ent->attributes[j].num_values = res[i]->elements[j].num_values;
169 ent->attributes[j].values = talloc_array_p(ent->attributes,
170 DATA_BLOB, ent->attributes[j].num_values);
171 ALLOC_CHECK(ent->attributes[j].values);
172 for (y=0; y < ent->attributes[j].num_values; y++) {
173 ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
174 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
175 res[i]->elements[j].values[y].data);
179 status = ldapsrv_queue_reply(call, ent_r);
180 if (!NT_STATUS_IS_OK(status)) {
185 done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
189 DEBUG(10,("sldb_Search: results: [%d]\n",count));
192 } else if (count == 0) {
193 DEBUG(10,("sldb_Search: no results\n"));
195 errstr = talloc_strdup(done_r, ldb_errstring(ldb));
196 } else if (count == -1) {
197 DEBUG(10,("sldb_Search: error\n"));
199 errstr = talloc_strdup(done_r, ldb_errstring(ldb));
202 done = &done_r->msg.r.SearchResultDone;
203 done->resultcode = result;
205 done->errormessage = errstr;
206 done->referral = NULL;
210 return ldapsrv_queue_reply(call, done_r);
213 static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
214 struct ldap_AddRequest *r)
216 struct ldap_Result *add_result;
217 struct ldapsrv_reply *add_reply;
219 struct samdb_context *samdb;
220 struct ldb_context *ldb;
222 struct ldb_message *msg;
223 int result = LDAP_SUCCESS;
224 const char *errstr = NULL;
227 samdb = samdb_connect(call);
229 dn = sldb_fix_dn(r->dn);
231 return NT_STATUS_NO_MEMORY;
234 DEBUG(10, ("sldb_add: dn: [%s]\n", dn));
236 msg = talloc_p(samdb, struct ldb_message);
239 msg->dn = discard_const_p(char, dn);
240 msg->private_data = NULL;
241 msg->num_elements = 0;
242 msg->elements = NULL;
244 if (r->num_attributes > 0) {
245 msg->num_elements = r->num_attributes;
246 msg->elements = talloc_array_p(msg, struct ldb_message_element, msg->num_elements);
247 ALLOC_CHECK(msg->elements);
249 for (i=0; i < msg->num_elements; i++) {
250 msg->elements[i].name = discard_const_p(char, r->attributes[i].name);
251 msg->elements[i].flags = 0;
252 msg->elements[i].num_values = 0;
253 msg->elements[i].values = NULL;
255 if (r->attributes[i].num_values > 0) {
256 msg->elements[i].num_values = r->attributes[i].num_values;
257 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
258 ALLOC_CHECK(msg->elements[i].values);
260 for (j=0; j < msg->elements[i].num_values; j++) {
261 if (!(r->attributes[i].values[j].length > 0)) {
265 msg->elements[i].values[j].length = r->attributes[i].values[j].length;
266 msg->elements[i].values[j].data = r->attributes[i].values[j].data;
280 add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
281 ALLOC_CHECK(add_reply);
283 add_result = &add_reply->msg.r.AddResponse;
284 add_result->dn = talloc_steal(add_reply, dn);
286 if (result == LDAP_SUCCESS) {
287 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
288 ldb_ret = ldb_add(ldb, msg);
290 result = LDAP_SUCCESS;
293 /* currently we have no way to tell if there was an internal ldb error
294 * or if the object was not found, return the most probable error
297 errstr = talloc_strdup(add_reply, ldb_errstring(ldb));
300 errstr = talloc_strdup(add_reply,"invalid input data");
303 add_result->resultcode = result;
304 add_result->errormessage = errstr;
305 add_result->referral = NULL;
309 return ldapsrv_queue_reply(call, add_reply);
312 static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
313 struct ldap_DelRequest *r)
315 struct ldap_Result *del_result;
316 struct ldapsrv_reply *del_reply;
318 struct samdb_context *samdb;
319 struct ldb_context *ldb;
321 const char *errstr = NULL;
322 int result = LDAP_SUCCESS;
324 samdb = samdb_connect(call);
326 dn = sldb_fix_dn(r->dn);
328 return NT_STATUS_NO_MEMORY;
331 DEBUG(10, ("sldb_Del: dn: [%s]\n", dn));
333 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
334 ldb_ret = ldb_delete(ldb, dn);
336 errstr = ldb_errstring(ldb);
338 del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
339 ALLOC_CHECK(del_reply);
341 del_result = &del_reply->msg.r.DelResponse;
342 del_result->dn = talloc_steal(del_reply, dn);
345 result = LDAP_SUCCESS;
348 /* currently we have no way to tell if there was an internal ldb error
349 * or if the object was not found, return the most probable error
351 result = LDAP_NO_SUCH_OBJECT;
352 errstr = talloc_strdup(del_reply, ldb_errstring(ldb));
355 del_result->resultcode = result;
356 del_result->errormessage = errstr;
357 del_result->referral = NULL;
361 return ldapsrv_queue_reply(call, del_reply);
364 static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
365 struct ldap_ModifyRequest *r)
367 struct ldap_Result *modify_result;
368 struct ldapsrv_reply *modify_reply;
370 struct samdb_context *samdb;
371 struct ldb_context *ldb;
373 struct ldb_message *msg;
374 int result = LDAP_SUCCESS;
375 const char *errstr = NULL;
378 samdb = samdb_connect(call);
380 dn = sldb_fix_dn(r->dn);
382 return NT_STATUS_NO_MEMORY;
385 DEBUG(10, ("sldb_modify: dn: [%s]\n", dn));
387 msg = talloc_p(samdb, struct ldb_message);
390 msg->dn = discard_const_p(char, dn);
391 msg->private_data = NULL;
392 msg->num_elements = 0;
393 msg->elements = NULL;
395 if (r->num_mods > 0) {
396 msg->num_elements = r->num_mods;
397 msg->elements = talloc_array_p(msg, struct ldb_message_element, r->num_mods);
398 ALLOC_CHECK(msg->elements);
400 for (i=0; i < msg->num_elements; i++) {
401 msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name);
402 msg->elements[i].num_values = 0;
403 msg->elements[i].values = NULL;
405 switch (r->mods[i].type) {
409 case LDAP_MODIFY_ADD:
410 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
412 case LDAP_MODIFY_DELETE:
413 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
415 case LDAP_MODIFY_REPLACE:
416 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
420 if (r->mods[i].attrib.num_values > 0) {
421 msg->elements[i].num_values = r->mods[i].attrib.num_values;
422 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
423 ALLOC_CHECK(msg->elements[i].values);
425 for (j=0; j < msg->elements[i].num_values; j++) {
426 if (!(r->mods[i].attrib.values[j].length > 0)) {
430 msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length;
431 msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data;
434 /* TODO: test what we should do here
436 * LDAP_MODIFY_DELETE is ok to pass here
447 modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
448 ALLOC_CHECK(modify_reply);
450 modify_result = &modify_reply->msg.r.AddResponse;
451 modify_result->dn = talloc_steal(modify_reply, dn);
453 if (result == LDAP_SUCCESS) {
454 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
455 ldb_ret = ldb_modify(ldb, msg);
457 result = LDAP_SUCCESS;
460 /* currently we have no way to tell if there was an internal ldb error
461 * or if the object was not found, return the most probable error
464 errstr = talloc_strdup(modify_reply, ldb_errstring(ldb));
467 errstr = talloc_strdup(modify_reply,"invalid input data");
470 modify_result->resultcode = result;
471 modify_result->errormessage = errstr;
472 modify_result->referral = NULL;
476 return ldapsrv_queue_reply(call, modify_reply);
479 static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
480 struct ldap_CompareRequest *r)
482 struct ldap_Result *compare;
483 struct ldapsrv_reply *compare_r;
485 struct samdb_context *samdb;
486 struct ldb_message **res;
487 struct ldb_context *ldb;
488 const char *attrs[1];
494 samdb = samdb_connect(call);
496 dn = sldb_fix_dn(r->dn);
498 return NT_STATUS_NO_MEMORY;
501 DEBUG(10, ("sldb_Compare: dn: [%s]\n", dn));
502 filter = talloc_asprintf(samdb, "(%s=%*s)", r->attribute, r->value.length, r->value.data);
504 DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter));
508 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
509 count = ldb_search(ldb, dn, LDB_SCOPE_BASE, filter, attrs, &res);
511 compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
512 ALLOC_CHECK(compare_r);
515 DEBUG(10,("sldb_Compare: matched\n"));
518 } else if (count == 0) {
520 errstr = talloc_strdup(compare_r, ldb_errstring(ldb));
521 DEBUG(10,("sldb_Compare: no results: %s\n", errstr));
522 } else if (count > 1) {
524 errstr = talloc_strdup(compare_r, "too many objects match");
525 DEBUG(10,("sldb_Compare: %d results: %s\n", count, errstr));
526 } else if (count == -1) {
528 errstr = talloc_strdup(compare_r, ldb_errstring(ldb));
529 DEBUG(10,("sldb_Compare: error: %s\n", errstr));
532 compare = &compare_r->msg.r.CompareResponse;
533 compare->resultcode = result;
535 compare->errormessage = errstr;
536 compare->referral = NULL;
540 return ldapsrv_queue_reply(call, compare_r);
543 static const struct ldapsrv_partition_ops sldb_ops = {
544 .Search = sldb_Search,
547 .Modify = sldb_Modify,
548 .Compare = sldb_Compare
551 const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void)