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.
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 {\
36 return NT_STATUS_NO_MEMORY;\
40 #define VALID_DN_SYNTAX(dn,i) do {\
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 "')";\
50 static NTSTATUS
sldb_Search(struct ldapsrv_partition
*partition
, struct ldapsrv_call
*call
,
51 struct ldap_SearchRequest
*r
)
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
);
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
));
80 case LDAP_SEARCH_SCOPE_BASE
:
81 DEBUG(10,("sldb_Search: scope: [BASE]\n"));
82 scope
= LDB_SCOPE_BASE
;
84 case LDAP_SEARCH_SCOPE_SINGLE
:
85 DEBUG(10,("sldb_Search: scope: [ONE]\n"));
86 scope
= LDB_SCOPE_ONELEVEL
;
88 case LDAP_SEARCH_SCOPE_SUB
:
89 DEBUG(10,("sldb_Search: scope: [SUB]\n"));
90 scope
= LDB_SCOPE_SUBTREE
;
94 if (r
->num_attributes
>= 1) {
95 attrs
= talloc_array_p(samdb
, const char *, r
->num_attributes
+1);
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
];
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
);
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) {
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)) {
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
);
140 status
= ldapsrv_queue_reply(call
, ent_r
);
141 if (!NT_STATUS_IS_OK(status
)) {
147 done_r
= ldapsrv_init_reply(call
, LDAP_TAG_SearchResultDone
);
150 if (result
== LDAP_SUCCESS
) {
152 DEBUG(10,("sldb_Search: results: [%d]\n",count
));
153 result
= LDAP_SUCCESS
;
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"));
162 errstr
= ldb_errstring(samdb
->ldb
);
166 done
= &done_r
->msg
.r
.SearchResultDone
;
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
)
182 struct ldap_Result
*add_result
;
183 struct ldapsrv_reply
*add_reply
;
185 struct samdb_context
*samdb
;
186 struct ldb_message
*msg
= NULL
;
187 int result
= LDAP_SUCCESS
;
188 const char *errstr
= NULL
;
191 local_ctx
= talloc_named(call
, 0, "sldb_Add local memory context");
192 ALLOC_CHECK(local_ctx
);
194 samdb
= samdb_connect(local_ctx
);
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
);
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)) {
229 errstr
= "Empty attribute values are not allowed";
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
;
237 errstr
= "No attribute values are not allowed";
243 errstr
= "No attributes are not allowed";
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
);
254 result
= LDAP_SUCCESS
;
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
)
281 struct ldap_Result
*del_result
;
282 struct ldapsrv_reply
*del_reply
;
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
);
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
));
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
);
306 result
= LDAP_SUCCESS
;
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
)
333 struct ldap_Result
*modify_result
;
334 struct ldapsrv_reply
*modify_reply
;
336 struct samdb_context
*samdb
;
337 struct ldb_message
*msg
= NULL
;
338 int result
= LDAP_SUCCESS
;
339 const char *errstr
= NULL
;
342 local_ctx
= talloc_named(call
, 0, "sldb_Modify local memory context");
343 ALLOC_CHECK(local_ctx
);
345 samdb
= samdb_connect(local_ctx
);
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
);
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
) {
373 result
= LDAP_PROTOCOL_ERROR
;
374 errstr
= "Invalid LDAP_MODIFY_* type";
376 case LDAP_MODIFY_ADD
:
377 msg
->elements
[i
].flags
= LDB_FLAG_MOD_ADD
;
379 case LDAP_MODIFY_DELETE
:
380 msg
->elements
[i
].flags
= LDB_FLAG_MOD_DELETE
;
382 case LDAP_MODIFY_REPLACE
:
383 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
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)) {
395 errstr
= "Empty attribute values are not allowed";
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
;
405 errstr
= "No mods are not allowed";
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
);
416 result
= LDAP_SUCCESS
;
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
)
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
;
453 local_ctx
= talloc_named(call
, 0, "sldb_Compare local_memory_context");
454 ALLOC_CHECK(local_ctx
);
456 samdb
= samdb_connect(local_ctx
);
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
);
466 DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter
));
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
);
478 DEBUG(10,("sldb_Compare: matched\n"));
479 result
= LDAP_COMPARE_TRUE
;
481 } else if (count
== 0) {
482 DEBUG(10,("sldb_Compare: doesn't matched\n"));
483 result
= LDAP_COMPARE_FALSE
;
485 } else if (count
> 1) {
487 errstr
= "too many objects match";
488 DEBUG(10,("sldb_Compare: %d results: %s\n", count
, errstr
));
489 } else if (count
== -1) {
491 errstr
= ldb_errstring(samdb
->ldb
);
492 DEBUG(10,("sldb_Compare: error: %s\n", errstr
));
496 compare
= &compare_r
->msg
.r
.CompareResponse
;
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
)
510 struct ldap_dn
*olddn
, *newrdn
, *newsuperior
;
511 struct ldap_Result
*modifydn
;
512 struct ldapsrv_reply
*modifydn_r
;
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
);
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";
542 if (newrdn
->comp_num
> 1) {
543 result
= LDAP_NAMING_VIOLATION
;
544 errstr
= "Error new RDN invalid";
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";
558 parentdn
= newsuperior
->dn
;
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
);
572 newdn
= talloc_asprintf(local_ctx
, "%s,%s", newrdn
->dn
, parentdn
);
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
);
582 result
= LDAP_SUCCESS
;
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
;
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
,
608 .Modify
= sldb_Modify
,
609 .Compare
= sldb_Compare
,
610 .ModifyDN
= sldb_ModifyDN
613 const struct ldapsrv_partition_ops
*ldapsrv_get_sldb_partition_ops(void)