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