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