r2820: complete the parsing routing with correct support for escaped chars
[ab/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    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22 #include "ldap_parse.h"
23
24 /* TODO: samdb_context is not a pulblic struct */
25 struct samdb_context {
26         struct ldb_context *ldb;
27         struct samdb_context **static_ptr;
28 };
29
30
31 #define ALLOC_CHECK(ptr) do {\
32         if (!(ptr)) {\
33                 return NT_STATUS_NO_MEMORY;\
34         }\
35 } while(0)
36
37
38 static NTSTATUS sldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
39                                      struct ldap_SearchRequest *r)
40 {
41         NTSTATUS status;
42         void *local_ctx;
43         struct ldap_dn *basedn;
44         struct ldap_Result *done;
45         struct ldap_SearchResEntry *ent;
46         struct ldapsrv_reply *ent_r, *done_r;
47         int result = 80;
48         struct samdb_context *samdb;
49         struct ldb_message **res;
50         int i, j, y, count;
51         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
52         const char **attrs = NULL;
53         const char *errstr;
54
55         local_ctx = talloc_named(call, 0, "sldb_Search local memory context");
56         ALLOC_CHECK(local_ctx);
57
58         samdb = samdb_connect(local_ctx);
59         ALLOC_CHECK(samdb);
60
61         basedn = ldap_parse_dn(local_ctx, r->basedn);
62         ALLOC_CHECK(basedn);
63
64         DEBUG(10, ("sldb_Search: basedn: [%s]\n", basedn->dn));
65         DEBUG(10, ("sldb_Search: filter: [%s]\n", r->filter));
66
67         switch (r->scope) {
68                 case LDAP_SEARCH_SCOPE_BASE:
69                         DEBUG(10,("sldb_Search: scope: [BASE]\n"));
70                         scope = LDB_SCOPE_BASE;
71                         break;
72                 case LDAP_SEARCH_SCOPE_SINGLE:
73                         DEBUG(10,("sldb_Search: scope: [ONE]\n"));
74                         scope = LDB_SCOPE_ONELEVEL;
75                         break;
76                 case LDAP_SEARCH_SCOPE_SUB:
77                         DEBUG(10,("sldb_Search: scope: [SUB]\n"));
78                         scope = LDB_SCOPE_SUBTREE;
79                         break;
80         }
81
82         if (r->num_attributes >= 1) {
83                 attrs = talloc_array_p(samdb, const char *, r->num_attributes+1);
84                 ALLOC_CHECK(attrs);
85
86                 for (i=0; i < r->num_attributes; i++) {
87                         DEBUG(10,("sldb_Search: attrs: [%s]\n",r->attributes[i]));
88                         attrs[i] = r->attributes[i];
89                 }
90                 attrs[i] = NULL;
91         }
92
93         ldb_set_alloc(samdb->ldb, talloc_realloc_fn, samdb);
94         count = ldb_search(samdb->ldb, basedn->dn, scope, r->filter, attrs, &res);
95
96         for (i=0; i < count; i++) {
97                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
98                 ALLOC_CHECK(ent_r);
99
100                 ent = &ent_r->msg.r.SearchResultEntry;
101                 ent->dn = talloc_steal(ent_r, res[i]->dn);
102                 ent->num_attributes = 0;
103                 ent->attributes = NULL;
104                 if (res[i]->num_elements == 0) {
105                         goto queue_reply;
106                 }
107                 ent->num_attributes = res[i]->num_elements;
108                 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
109                 ALLOC_CHECK(ent->attributes);
110                 for (j=0; j < ent->num_attributes; j++) {
111                         ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
112                         ent->attributes[j].num_values = 0;
113                         ent->attributes[j].values = NULL;
114                         if (r->attributesonly && (res[i]->elements[j].num_values == 0)) {
115                                 continue;
116                         }
117                         ent->attributes[j].num_values = res[i]->elements[j].num_values;
118                         ent->attributes[j].values = talloc_array_p(ent->attributes,
119                                                         DATA_BLOB, ent->attributes[j].num_values);
120                         ALLOC_CHECK(ent->attributes[j].values);
121                         for (y=0; y < ent->attributes[j].num_values; y++) {
122                                 ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
123                                 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
124                                                                         res[i]->elements[j].values[y].data);
125                         }
126                 }
127 queue_reply:
128                 status = ldapsrv_queue_reply(call, ent_r);
129                 if (!NT_STATUS_IS_OK(status)) {
130                         return status;
131                 }
132         }
133
134         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
135         ALLOC_CHECK(done_r);
136
137         if (count > 0) {
138                 DEBUG(10,("sldb_Search: results: [%d]\n",count));
139                 result = 0;
140                 errstr = NULL;
141         } else if (count == 0) {
142                 DEBUG(10,("sldb_Search: no results\n"));
143                 result = 32;
144                 errstr = talloc_strdup(done_r, ldb_errstring(samdb->ldb));
145         } else if (count == -1) {
146                 DEBUG(10,("sldb_Search: error\n"));
147                 result = 1;
148                 errstr = talloc_strdup(done_r, ldb_errstring(samdb->ldb));
149         }
150
151         done = &done_r->msg.r.SearchResultDone;
152         done->resultcode = result;
153         done->dn = NULL;
154         done->errormessage = errstr;
155         done->referral = NULL;
156
157         talloc_free(local_ctx);
158
159         return ldapsrv_queue_reply(call, done_r);
160 }
161
162 static NTSTATUS sldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
163                                      struct ldap_AddRequest *r)
164 {
165         void *local_ctx;
166         struct ldap_dn *ldn;
167         struct ldap_Result *add_result;
168         struct ldapsrv_reply *add_reply;
169         int ldb_ret;
170         struct samdb_context *samdb;
171         struct ldb_message *msg;
172         int result = LDAP_SUCCESS;
173         const char *errstr = NULL;
174         int i,j;
175
176         local_ctx = talloc_named(call, 0, "sldb_Add local memory context");
177         ALLOC_CHECK(local_ctx);
178
179         samdb = samdb_connect(local_ctx);
180         ALLOC_CHECK(samdb);
181
182         ldn = ldap_parse_dn(local_ctx, r->dn);
183         if (!ldn) {
184                 return NT_STATUS_UNSUCCESSFUL;
185         }
186
187         DEBUG(10, ("sldb_add: dn: [%s]\n", ldn->dn));
188
189         msg = talloc_p(local_ctx, struct ldb_message);
190         ALLOC_CHECK(msg);
191
192         msg->dn = ldn->dn;
193         msg->private_data = NULL;
194         msg->num_elements = 0;
195         msg->elements = NULL;
196
197         if (r->num_attributes > 0) {
198                 msg->num_elements = r->num_attributes;
199                 msg->elements = talloc_array_p(msg, struct ldb_message_element, msg->num_elements);
200                 ALLOC_CHECK(msg->elements);
201
202                 for (i=0; i < msg->num_elements; i++) {
203                         msg->elements[i].name = discard_const_p(char, r->attributes[i].name);
204                         msg->elements[i].flags = 0;
205                         msg->elements[i].num_values = 0;
206                         msg->elements[i].values = NULL;
207                         
208                         if (r->attributes[i].num_values > 0) {
209                                 msg->elements[i].num_values = r->attributes[i].num_values;
210                                 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
211                                 ALLOC_CHECK(msg->elements[i].values);
212
213                                 for (j=0; j < msg->elements[i].num_values; j++) {
214                                         if (!(r->attributes[i].values[j].length > 0)) {
215                                                 result = 80;
216                                                 goto invalid_input;
217                                         }
218                                         msg->elements[i].values[j].length = r->attributes[i].values[j].length;
219                                         msg->elements[i].values[j].data = r->attributes[i].values[j].data;                      
220                                 }
221                         } else {
222                                 result = 80;
223                                 goto invalid_input;
224                         }
225                 }
226         } else {
227                 result = 80;
228                 goto invalid_input;
229         }
230
231 invalid_input:
232
233         add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
234         ALLOC_CHECK(add_reply);
235
236         add_result = &add_reply->msg.r.AddResponse;
237         add_result->dn = talloc_steal(add_reply, ldn->dn);
238
239         if (result == LDAP_SUCCESS) {
240                 ldb_set_alloc(samdb->ldb, talloc_realloc_fn, samdb);
241                 ldb_ret = ldb_add(samdb->ldb, msg);
242                 if (ldb_ret == 0) {
243                         result = LDAP_SUCCESS;
244                         errstr = NULL;
245                 } else {
246                         /* currently we have no way to tell if there was an internal ldb error
247                          * or if the object was not found, return the most probable error
248                          */
249                         result = 1;
250                         errstr = talloc_strdup(add_reply, ldb_errstring(samdb->ldb));
251                 }
252         } else {
253                 errstr = talloc_strdup(add_reply, "invalid input data");
254         }
255
256         add_result->resultcode = result;
257         add_result->errormessage = errstr;
258         add_result->referral = NULL;
259
260         talloc_free(local_ctx);
261
262         return ldapsrv_queue_reply(call, add_reply);
263 }
264
265 static NTSTATUS sldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
266                                      struct ldap_DelRequest *r)
267 {
268         void *local_ctx;
269         struct ldap_dn *ldn;
270         struct ldap_Result *del_result;
271         struct ldapsrv_reply *del_reply;
272         int ldb_ret;
273         struct samdb_context *samdb;
274         const char *dn;
275         const char *errstr = NULL;
276         int result = LDAP_SUCCESS;
277
278         local_ctx = talloc_named(call, 0, "sldb_Del local memory context");
279         ALLOC_CHECK(local_ctx);
280
281         samdb = samdb_connect(local_ctx);
282         ldn = ldap_parse_dn(local_ctx, r->dn);
283         ALLOC_CHECK(ldn);
284
285         DEBUG(10, ("sldb_Del: dn: [%s]\n", ldn->dn));
286
287         ldb_set_alloc(samdb->ldb, talloc_realloc_fn, samdb);
288         ldb_ret = ldb_delete(samdb->ldb, ldn->dn);
289
290         del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
291         ALLOC_CHECK(del_reply);
292
293         del_result = &del_reply->msg.r.DelResponse;
294         del_result->dn = talloc_steal(del_reply, ldn->dn);
295
296         if (ldb_ret == 0) {
297                 result = LDAP_SUCCESS;
298                 errstr = NULL;
299         } else {
300                 /* currently we have no way to tell if there was an internal ldb error
301                  * or if the object was not found, return the most probable error
302                  */
303                 result = LDAP_NO_SUCH_OBJECT;
304                 errstr = talloc_strdup(del_reply, ldb_errstring(samdb->ldb));
305         }
306
307         del_result->resultcode = result;
308         del_result->errormessage = errstr;
309         del_result->referral = NULL;
310
311         talloc_free(local_ctx);
312
313         return ldapsrv_queue_reply(call, del_reply);
314 }
315
316 static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
317                                      struct ldap_ModifyRequest *r)
318 {
319         void *local_ctx;
320         struct ldap_dn *ldn;
321         struct ldap_Result *modify_result;
322         struct ldapsrv_reply *modify_reply;
323         int ldb_ret;
324         struct samdb_context *samdb;
325         struct ldb_message *msg;
326         int result = LDAP_SUCCESS;
327         const char *errstr = NULL;
328         int i,j;
329
330         local_ctx = talloc_named(call, 0, "sldb_Modify local memory context");
331         ALLOC_CHECK(local_ctx);
332
333         samdb = samdb_connect(call);
334         ALLOC_CHECK(samdb);
335
336         ldn = ldap_parse_dn(local_ctx, r->dn);
337         ALLOC_CHECK(ldn);
338
339         DEBUG(10, ("sldb_modify: dn: [%s]\n", ldn->dn));
340
341         msg = talloc_p(local_ctx, struct ldb_message);
342         ALLOC_CHECK(msg);
343
344         msg->dn = ldn->dn;
345         msg->private_data = NULL;
346         msg->num_elements = 0;
347         msg->elements = NULL;
348
349         if (r->num_mods > 0) {
350                 msg->num_elements = r->num_mods;
351                 msg->elements = talloc_array_p(msg, struct ldb_message_element, r->num_mods);
352                 ALLOC_CHECK(msg->elements);
353
354                 for (i=0; i < msg->num_elements; i++) {
355                         msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name);
356                         msg->elements[i].num_values = 0;
357                         msg->elements[i].values = NULL;
358
359                         switch (r->mods[i].type) {
360                         default:
361                                 result = 2;
362                                 goto invalid_input;
363                         case LDAP_MODIFY_ADD:
364                                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
365                                 break;
366                         case LDAP_MODIFY_DELETE:
367                                 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
368                                 break;
369                         case LDAP_MODIFY_REPLACE:
370                                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
371                                 break;
372                         }
373
374                         if (r->mods[i].attrib.num_values > 0) {
375                                 msg->elements[i].num_values = r->mods[i].attrib.num_values;
376                                 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
377                                 ALLOC_CHECK(msg->elements[i].values);
378
379                                 for (j=0; j < msg->elements[i].num_values; j++) {
380                                         if (!(r->mods[i].attrib.values[j].length > 0)) {
381                                                 result = 80;
382                                                 goto invalid_input;
383                                         }
384                                         msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length;
385                                         msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data;                     
386                                 }
387                         } else {
388                                 /* TODO: test what we should do here 
389                                  *
390                                  *       LDAP_MODIFY_DELETE is ok to pass here
391                                  */
392                         }
393                 }
394         } else {
395                 result = 80;
396                 goto invalid_input;
397         }
398
399 invalid_input:
400
401         modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
402         ALLOC_CHECK(modify_reply);
403
404         modify_result = &modify_reply->msg.r.AddResponse;
405         modify_result->dn = talloc_steal(modify_reply, ldn->dn);
406
407         if (result == LDAP_SUCCESS) {
408                 ldb_set_alloc(samdb->ldb, talloc_realloc_fn, samdb);
409                 ldb_ret = ldb_modify(samdb->ldb, msg);
410                 if (ldb_ret == 0) {
411                         result = LDAP_SUCCESS;
412                         errstr = NULL;
413                 } else {
414                         /* currently we have no way to tell if there was an internal ldb error
415                          * or if the object was not found, return the most probable error
416                          */
417                         result = 1;
418                         errstr = talloc_strdup(modify_reply, ldb_errstring(samdb->ldb));
419                 }
420         } else {
421                 errstr = talloc_strdup(modify_reply, "invalid input data");
422         }
423
424         modify_result->resultcode = result;
425         modify_result->errormessage = errstr;
426         modify_result->referral = NULL;
427
428         talloc_free(local_ctx);
429
430         return ldapsrv_queue_reply(call, modify_reply);
431 }
432
433 static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
434                                      struct ldap_CompareRequest *r)
435 {
436         void *local_ctx;
437         struct ldap_dn *ldn;
438         struct ldap_Result *compare;
439         struct ldapsrv_reply *compare_r;
440         int result = 80;
441         struct samdb_context *samdb;
442         struct ldb_message **res;
443         struct ldb_context *ldb;
444         const char *attrs[1];
445         const char *errstr;
446         const char *dn;
447         const char *filter;
448         int count;
449
450         local_ctx = talloc_named(call, 0, "sldb_Compare local_memory_context");
451         ALLOC_CHECK(local_ctx);
452
453         samdb = samdb_connect(local_ctx);
454         ALLOC_CHECK(samdb);
455
456         ldn = ldap_parse_dn(local_ctx, r->dn);
457         ALLOC_CHECK(ldn);
458
459         DEBUG(10, ("sldb_Compare: dn: [%s]\n", ldn->dn));
460         filter = talloc_asprintf(local_ctx, "(%s=%*s)", r->attribute, r->value.length, r->value.data);
461         ALLOC_CHECK(filter);
462
463         DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter));
464
465         attrs[0] = NULL;
466
467         ldb_set_alloc(samdb->ldb, talloc_realloc_fn, samdb);
468         count = ldb_search(samdb->ldb, dn, LDB_SCOPE_BASE, filter, attrs, &res);
469
470         compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
471         ALLOC_CHECK(compare_r);
472
473         if (count == 1) {
474                 DEBUG(10,("sldb_Compare: matched\n"));
475                 result = 0;
476                 errstr = NULL;
477         } else if (count == 0) {
478                 result = 32;
479                 errstr = talloc_strdup(compare_r, ldb_errstring(samdb->ldb));
480                 DEBUG(10,("sldb_Compare: no results: %s\n", errstr));
481         } else if (count > 1) {
482                 result = 80;
483                 errstr = talloc_strdup(compare_r, "too many objects match");
484                 DEBUG(10,("sldb_Compare: %d results: %s\n", count, errstr));
485         } else if (count == -1) {
486                 result = 1;
487                 errstr = talloc_strdup(compare_r, ldb_errstring(samdb->ldb));
488                 DEBUG(10,("sldb_Compare: error: %s\n", errstr));
489         }
490
491         compare = &compare_r->msg.r.CompareResponse;
492         compare->resultcode = result;
493         compare->dn = NULL;
494         compare->errormessage = errstr;
495         compare->referral = NULL;
496
497         talloc_free(local_ctx);
498
499         return ldapsrv_queue_reply(call, compare_r);
500 }
501
502 static const struct ldapsrv_partition_ops sldb_ops = {
503         .Search         = sldb_Search,
504         .Add            = sldb_Add,
505         .Del            = sldb_Del,
506         .Modify         = sldb_Modify,
507         .Compare        = sldb_Compare
508 };
509
510 const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void)
511 {
512         return &sldb_ops;
513 }