r2754: Change sldb_trim_dn() to be sldb_fix_dn() as we are not really trimming.
[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
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, *n, *current;
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_ldb_alloc, 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_ldb_alloc, 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_ldb_alloc, samdb);
334         ldb_ret = ldb_delete(ldb, dn);
335
336         errstr = ldb_errstring(ldb);
337
338         del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
339         ALLOC_CHECK(del_reply);
340
341         del_result = &del_reply->msg.r.DelResponse;
342         del_result->dn = talloc_steal(del_reply, dn);
343
344         if (ldb_ret == 0) {
345                 result = LDAP_SUCCESS;
346                 errstr = NULL;
347         } else {
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
350                  */
351                 result = LDAP_NO_SUCH_OBJECT;
352                 errstr = talloc_strdup(del_reply, ldb_errstring(ldb));
353         }
354
355         del_result->resultcode = result;
356         del_result->errormessage = errstr;
357         del_result->referral = NULL;
358
359         talloc_free(samdb);
360
361         return ldapsrv_queue_reply(call, del_reply);
362 }
363
364 static NTSTATUS sldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
365                                      struct ldap_ModifyRequest *r)
366 {
367         struct ldap_Result *modify_result;
368         struct ldapsrv_reply *modify_reply;
369         int ldb_ret;
370         struct samdb_context *samdb;
371         struct ldb_context *ldb;
372         const char *dn;
373         struct ldb_message *msg;
374         int result = LDAP_SUCCESS;
375         const char *errstr = NULL;
376         int i,j;
377
378         samdb = samdb_connect(call);
379         ldb = samdb->ldb;
380         dn = sldb_fix_dn(r->dn);
381         if (dn == NULL) {
382                 return NT_STATUS_NO_MEMORY;
383         }
384
385         DEBUG(10, ("sldb_modify: dn: [%s]\n", dn));
386
387         msg = talloc_p(samdb, struct ldb_message);
388         ALLOC_CHECK(msg);
389
390         msg->dn = discard_const_p(char, dn);
391         msg->private_data = NULL;
392         msg->num_elements = 0;
393         msg->elements = NULL;
394
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);
399
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;
404
405                         switch (r->mods[i].type) {
406                         default:
407                                 result = 2;
408                                 goto invalid_input;
409                         case LDAP_MODIFY_ADD:
410                                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
411                                 break;
412                         case LDAP_MODIFY_DELETE:
413                                 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
414                                 break;
415                         case LDAP_MODIFY_REPLACE:
416                                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
417                                 break;
418                         }
419
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);
424
425                                 for (j=0; j < msg->elements[i].num_values; j++) {
426                                         if (!(r->mods[i].attrib.values[j].length > 0)) {
427                                                 result = 80;
428                                                 goto invalid_input;
429                                         }
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;                     
432                                 }
433                         } else {
434                                 /* TODO: test what we should do here 
435                                  *
436                                  *       LDAP_MODIFY_DELETE is ok to pass here
437                                  */
438                         }
439                 }
440         } else {
441                 result = 80;
442                 goto invalid_input;
443         }
444
445 invalid_input:
446
447         modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
448         ALLOC_CHECK(modify_reply);
449
450         modify_result = &modify_reply->msg.r.AddResponse;
451         modify_result->dn = talloc_steal(modify_reply, dn);
452
453         if (result == LDAP_SUCCESS) {
454                 ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
455                 ldb_ret = ldb_modify(ldb, msg);
456                 if (ldb_ret == 0) {
457                         result = LDAP_SUCCESS;
458                         errstr = NULL;
459                 } else {
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
462                          */
463                         result = 1;
464                         errstr = talloc_strdup(modify_reply, ldb_errstring(ldb));
465                 }
466         } else {
467                 errstr = talloc_strdup(modify_reply,"invalid input data");
468         }
469
470         modify_result->resultcode = result;
471         modify_result->errormessage = errstr;
472         modify_result->referral = NULL;
473
474         talloc_free(samdb);
475
476         return ldapsrv_queue_reply(call, modify_reply);
477 }
478
479 static NTSTATUS sldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
480                                      struct ldap_CompareRequest *r)
481 {
482         struct ldap_Result *compare;
483         struct ldapsrv_reply *compare_r;
484         int result = 80;
485         struct samdb_context *samdb;
486         struct ldb_message **res;
487         struct ldb_context *ldb;
488         const char *attrs[1];
489         const char *errstr;
490         const char *dn;
491         const char *filter;
492         int count;
493
494         samdb = samdb_connect(call);
495         ldb = samdb->ldb;
496         dn = sldb_fix_dn(r->dn);
497         if (dn == NULL) {
498                 return NT_STATUS_NO_MEMORY;
499         }
500
501         DEBUG(10, ("sldb_Compare: dn: [%s]\n", dn));
502         filter = talloc_asprintf(samdb, "(%s=%*s)", r->attribute, r->value.length, r->value.data);
503         ALLOC_CHECK(filter);
504         DEBUGADD(10, ("sldb_Compare: attribute: [%s]\n", filter));
505
506         attrs[0] = NULL;
507
508         ldb_set_alloc(ldb, talloc_ldb_alloc, samdb);
509         count = ldb_search(ldb, dn, LDB_SCOPE_BASE, filter, attrs, &res);
510
511         compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
512         ALLOC_CHECK(compare_r);
513
514         if (count == 1) {
515                 DEBUG(10,("sldb_Compare: matched\n"));
516                 result = 0;
517                 errstr = NULL;
518         } else if (count == 0) {
519                 result = 32;
520                 errstr = talloc_strdup(compare_r, ldb_errstring(ldb));
521                 DEBUG(10,("sldb_Compare: no results: %s\n", errstr));
522         } else if (count > 1) {
523                 result = 80;
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) {
527                 result = 1;
528                 errstr = talloc_strdup(compare_r, ldb_errstring(ldb));
529                 DEBUG(10,("sldb_Compare: error: %s\n", errstr));
530         }
531
532         compare = &compare_r->msg.r.CompareResponse;
533         compare->resultcode = result;
534         compare->dn = NULL;
535         compare->errormessage = errstr;
536         compare->referral = NULL;
537
538         talloc_free(samdb);
539
540         return ldapsrv_queue_reply(call, compare_r);
541 }
542
543 static const struct ldapsrv_partition_ops sldb_ops = {
544         .Search         = sldb_Search,
545         .Add            = sldb_Add,
546         .Del            = sldb_Del,
547         .Modify         = sldb_Modify,
548         .Compare        = sldb_Compare
549 };
550
551 const struct ldapsrv_partition_ops *ldapsrv_get_sldb_partition_ops(void)
552 {
553         return &sldb_ops;
554 }