09c8f28277e703c9844029209dc0b8f39a5abc85
[jelmer/samba4-debian.git] / source / ldap_server / ldap_hacked_ldb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP server HACKED LDB implementation to hopefully get a DsGetNCChanges() request from a
4    w2k3 box
5
6    Copyright (C) Stefan Metzmacher 2004-2005
7    Copyright (C) Simo Sorce 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "dynconfig.h"
26 #include "ldap_server/ldap_server.h"
27 #include "ldap_parse.h"
28 #include "lib/ldb/include/ldb.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30
31
32 #define VALID_DN_SYNTAX(dn,i) do {\
33         if (!(dn)) {\
34                 return NT_STATUS_NO_MEMORY;\
35         } else if ((dn)->comp_num < (i)) {\
36                 result = LDAP_INVALID_DN_SYNTAX;\
37                 errstr = "Invalid DN (" #i " components needed for '" #dn "')";\
38                 goto reply;\
39         }\
40 } while(0)
41
42 #define ATTR_BLOB_CONST(val) data_blob_talloc(mem_ctx, val, sizeof(val)-1)
43
44 #define ATTR_SINGLE_NOVAL(ctx, attr, blob, num, nam) do { \
45         attr->name = talloc_strdup(ctx, nam);\
46         NT_STATUS_HAVE_NO_MEMORY(attr->name);\
47         attr->num_values = num; \
48         attr->values = blob;\
49 } while(0)                               
50
51
52 static NTSTATUS convert_values(TALLOC_CTX *mem_ctx,
53                                struct ldb_message_element *elem,
54                                struct ldap_attribute *attrs,
55                                struct ldb_wrap *samdb,
56                                const char **dn,
57                                struct ldap_SearchRequest *r)
58 {
59         NTSTATUS status;
60         DEBUG(10, ("convert_values for %s\n", attrs[0].name));
61
62         attrs->name = talloc_steal(mem_ctx, elem->name);
63         attrs->values[0].length = elem->values[0].length;
64         attrs->values[0].data = talloc_steal(mem_ctx, elem->values[0].data);
65
66         if (strcasecmp(attrs->name, "objectGUID") == 0 ||
67             strcasecmp(attrs->name, "invacationID") == 0)
68         {
69                 struct GUID guid;
70                 DATA_BLOB blob;
71
72                 status = GUID_from_string((const char *)elem->values[0].data, &guid);
73                 NT_STATUS_NOT_OK_RETURN(status);
74
75                 status = ndr_push_struct_blob(&blob, mem_ctx, &guid,
76                               (ndr_push_flags_fn_t)ndr_push_GUID);
77                 NT_STATUS_NOT_OK_RETURN(status);
78
79                 attrs->values[0].length = blob.length;
80                 attrs->values[0].data = talloc_steal(mem_ctx, blob.data);
81         }
82
83         if (strcasecmp(attrs->name, "objectSID") == 0)
84         {
85                 struct dom_sid *sid;
86                 DATA_BLOB blob;
87
88                 sid = dom_sid_parse_talloc(mem_ctx, (const char *)elem->values[0].data);
89                 NT_STATUS_HAVE_NO_MEMORY(sid);
90
91                 status = ndr_push_struct_blob(&blob, mem_ctx, sid,
92                               (ndr_push_flags_fn_t)ndr_push_dom_sid);
93                 NT_STATUS_NOT_OK_RETURN(status);
94
95                 attrs->values[0].length = blob.length;
96                 attrs->values[0].data = talloc_steal(mem_ctx, blob.data);
97         }
98
99         if (strcasecmp(attrs->name, "ncname") == 0)
100         {
101                 char *filter = talloc_strdup(mem_ctx, r->filter);
102                 struct ldb_message **res = NULL;
103                 int count;
104                 const char *dom_dn;
105                 const char *dom_filter;
106
107                 const char *dom_sid_str;
108                 struct dom_sid *dom_sid;
109                 DATA_BLOB dom_sid_blob;
110                 const char *dom_sid_hex;
111
112                 const char *dom_guid_str;
113                 struct GUID dom_guid;
114                 DATA_BLOB dom_guid_blob;
115                 const char *dom_guid_hex;
116
117                 const char *nc_filter;
118                 const char *nc_guid_str;
119                 struct GUID nc_guid;
120                 DATA_BLOB nc_guid_blob;
121                 char *nc_guid_hex;
122                 const char *ncname;
123
124                 const char *s_attrs[] = {"objectGUID", "objectSid", NULL};
125                 char *p2;
126
127                 nc_filter = talloc_asprintf(mem_ctx, "(dn=%s)", *dn);
128 DEBUG(0, (__location__": convert_values(ncname): nc dn = '%s'\n", nc_filter));
129
130                 
131                 /* first the NC stuff */
132                 count = ldb_search(samdb->ldb, "", LDB_SCOPE_BASE, nc_filter, s_attrs, &res);
133                 if (count != 1) {
134                         DEBUG(0, (__location__": convert_values(ncname): nc_count: %d \n", count));
135                         return NT_STATUS_FOOBAR;
136                 }
137 DEBUG(0, (__location__": convert_values(ncname): nc_res '%s'\n", res[0]->dn));
138                 nc_guid_str = samdb_result_string(res[0], "objectGUID", NULL);
139
140                 status = GUID_from_string(nc_guid_str, &nc_guid);
141
142                 status = ndr_push_struct_blob(&nc_guid_blob, mem_ctx, &nc_guid,
143                               (ndr_push_flags_fn_t)ndr_push_GUID);
144
145                 nc_guid_hex = data_blob_hex_string(mem_ctx, &nc_guid_blob);
146
147                 /* overwrite the dn of the search result */
148                 *dn = talloc_asprintf(mem_ctx, "<GUID=%s>;%s", nc_guid_hex, *dn);
149 DEBUG(0, (__location__": convert_values(ncname): dn='%s'\n",*dn));
150                 /* now the domain stuff */
151
152                 dom_dn = strchr(filter, '=');
153                 dom_dn++;
154
155                 p2 = strchr(filter, ')');
156                 *p2 ='\0';
157
158                 dom_filter = talloc_asprintf(mem_ctx, "(dn=%s)", dom_dn);
159 DEBUG(0, (__location__": convert_values(ncname): dom dn = '%s'\n", dom_filter));
160                 count = ldb_search(samdb->ldb, "", LDB_SCOPE_BASE, dom_filter, s_attrs, &res);
161                 if (count != 1) {
162                         DEBUG(0, (__location__": convert_values(ncname): dom_count: %d \n", count));
163                         return NT_STATUS_OK;
164                 }
165
166                 dom_guid_str = samdb_result_string(res[0], "objectGUID", NULL);
167
168                 status = GUID_from_string(dom_guid_str, &dom_guid);
169
170                 status = ndr_push_struct_blob(&dom_guid_blob, mem_ctx, &dom_guid,
171                               (ndr_push_flags_fn_t)ndr_push_GUID);
172
173                 dom_guid_hex = data_blob_hex_string(mem_ctx, &dom_guid_blob);
174
175                 dom_sid_str = samdb_result_string(res[0], "objectSid", NULL);
176
177                 dom_sid = dom_sid_parse_talloc(mem_ctx, dom_sid_str);
178
179                 status = ndr_push_struct_blob(&dom_sid_blob, mem_ctx, dom_sid,
180                               (ndr_push_flags_fn_t)ndr_push_dom_sid);
181
182                 dom_sid_hex = data_blob_hex_string(mem_ctx, &dom_sid_blob);
183
184                 ncname = talloc_asprintf(mem_ctx, "<GUID=%s>;<SID=%s>;%s",
185                                         dom_guid_hex, dom_sid_hex, dom_dn);
186 DEBUG(0, (__location__": convert_values(ncname): ncname='%s'\n",ncname));
187
188                 attrs->values[0].length = strlen(ncname);
189                 attrs->values[0].data = talloc_steal(mem_ctx, ncname);
190 DEBUG(0, (__location__": convert_values(ncname): end ok\n"));
191         }
192
193         return NT_STATUS_OK;
194 }
195
196 static NTSTATUS hacked_wellknown_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
197                                      struct ldap_SearchRequest *r)
198 {
199         NTSTATUS status;
200         void *local_ctx;
201         struct ldap_SearchResEntry *ent;
202         struct ldap_Result *done;
203         struct ldapsrv_reply *ent_r, *done_r;
204         int count;
205         const char *dn_prefix;
206         const char *wkdn;
207         char *p, *p2;
208         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
209         char *basedn_str;
210
211         local_ctx = talloc_named(call, 0, "hacked_wellknown_Search local memory context");
212         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
213
214         switch (r->scope) {
215                 case LDAP_SEARCH_SCOPE_BASE:
216                         scope = LDB_SCOPE_BASE;
217                         break;
218                 default:
219                         return NT_STATUS_NOT_IMPLEMENTED;
220         }
221
222 #define WKGUID_prefix "<WKGUID="
223         if (strncasecmp(WKGUID_prefix, r->basedn, strlen(WKGUID_prefix)) != 0) {
224                 return NT_STATUS_NOT_IMPLEMENTED;
225         }
226
227         basedn_str = talloc_strdup(call, r->basedn);
228
229 #define WKGUID_Infrastructure "<WKGUID=2FBAC1870ADE11D297C400C04FD8D5CD,"
230 #define WKGUID_Infrastructure_DN "CN=Infrastructure,"
231         if (strncasecmp(WKGUID_Infrastructure, r->basedn, strlen(WKGUID_Infrastructure)) == 0) {
232                 dn_prefix = WKGUID_Infrastructure_DN;
233         } else
234 #define WKGUID_Domain_Controllers "<WKGUID=A361B2FFFFD211D1AA4B00C04FD7D83A,"
235 #define WKGUID_Domain_Controllers_DN "OU=Domain Controllers,"   
236         if (strncasecmp(WKGUID_Domain_Controllers, r->basedn, strlen(WKGUID_Domain_Controllers)) == 0) {
237                 dn_prefix = WKGUID_Domain_Controllers_DN;
238         } else {
239                 DEBUG(0,("UKNOWN dn '%s'\n", basedn_str));
240                 return NT_STATUS_NOT_IMPLEMENTED;
241         }
242
243         p = strchr(basedn_str, ',');
244         p++;
245
246         p2 = strchr(basedn_str, '>');
247         *p2 ='\0';
248
249         wkdn = talloc_asprintf(call, "%s%s", dn_prefix, p);
250
251         count = 1;
252         ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
253         NT_STATUS_HAVE_NO_MEMORY(ent_r);
254
255         ent = &ent_r->msg.r.SearchResultEntry;
256         ent->dn = talloc_steal(ent_r, wkdn);
257         DEBUG(0,("hacked result [0] dn: %s\n", ent->dn));
258         ent->num_attributes = 0;
259         ent->attributes = NULL;
260
261         status = ldapsrv_queue_reply(call, ent_r);
262         if (!NT_STATUS_IS_OK(status)) {
263                 return status;
264         }
265
266         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
267         NT_STATUS_HAVE_NO_MEMORY(done_r);
268
269         DEBUG(10,("hacked_Search: results: [%d]\n",count));
270
271         done = &done_r->msg.r.SearchResultDone;
272         done->dn = NULL;
273         done->resultcode = LDAP_SUCCESS;
274         done->errormessage = NULL;
275         done->referral = NULL;
276
277         talloc_free(local_ctx);
278
279         return ldapsrv_queue_reply(call, done_r);
280 }
281
282 static NTSTATUS hacked_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
283                                      struct ldap_SearchRequest *r, struct ldb_wrap *samdb)
284 {
285         NTSTATUS status;
286         void *local_ctx;
287         struct ldap_SearchResEntry *ent;
288         struct ldap_Result *done;
289         struct ldb_message **res = NULL;
290         int result = LDAP_SUCCESS;
291         struct ldapsrv_reply *ent_r, *done_r;
292         const char *errstr = NULL;
293         int count, j, y, i;
294         const char **attrs = NULL;
295         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
296         struct ldap_dn *basedn;
297         const char *basedn_str;
298
299         local_ctx = talloc_named(call, 0, "hacked_Search local memory context");
300         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
301
302         basedn = ldap_parse_dn(local_ctx, r->basedn);
303         if (!basedn) {
304                 basedn_str = r->basedn;
305         } else {
306                 basedn_str = basedn->dn;
307         }
308
309         switch (r->scope) {
310                 case LDAP_SEARCH_SCOPE_BASE:
311                         DEBUG(10,("hldb_Search: scope: [BASE]\n"));
312                         scope = LDB_SCOPE_BASE;
313                         break;
314                 case LDAP_SEARCH_SCOPE_SINGLE:
315                         DEBUG(10,("hldb_Search: scope: [ONE]\n"));
316                         scope = LDB_SCOPE_ONELEVEL;
317                         break;
318                 case LDAP_SEARCH_SCOPE_SUB:
319                         DEBUG(10,("hldb_Search: scope: [SUB]\n"));
320                         scope = LDB_SCOPE_SUBTREE;
321                         break;
322         }
323
324         if (r->num_attributes >= 1) {
325                 attrs = talloc_array_p(samdb, const char *, r->num_attributes+1);
326                 NT_STATUS_HAVE_NO_MEMORY(attrs);
327
328                 for (j=0; j < r->num_attributes; j++) {
329                         DEBUG(10,("hacked_Search: attrs: [%s]\n",r->attributes[j]));
330                         attrs[j] = r->attributes[j];
331                 }
332                 attrs[j] = NULL;
333         }
334 DEBUG(0,("hacked basedn: %s\n", basedn_str));
335 DEBUGADD(0,("hacked filter: %s\n", r->filter));
336         count = ldb_search(samdb->ldb, basedn_str, scope, r->filter, attrs, &res);
337         talloc_steal(samdb, res);
338
339         if (count < 1) {
340                 DEBUG(0,("hacked not found\n"));
341                 return NT_STATUS_NOT_IMPLEMENTED;
342         }
343
344         if (scope == LDAP_SEARCH_SCOPE_BASE) {
345                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
346                 NT_STATUS_HAVE_NO_MEMORY(ent_r);
347
348                 ent = &ent_r->msg.r.SearchResultEntry;
349                 ent->dn = talloc_steal(ent_r, res[0]->dn);
350                 DEBUG(0,("hacked result [0] dn: %s\n", ent->dn));
351                 ent->num_attributes = 0;
352                 ent->attributes = NULL;
353                 if (res[0]->num_elements == 0) {
354                         goto queue_reply;
355                 }
356                 ent->num_attributes = res[0]->num_elements;
357                 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
358                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
359                 for (j=0; j < ent->num_attributes; j++) {
360                         ent->attributes[j].name = talloc_steal(ent->attributes, res[0]->elements[j].name);
361                         ent->attributes[j].num_values = 0;
362                         ent->attributes[j].values = NULL;
363                         ent->attributes[j].num_values = res[0]->elements[j].num_values;
364                         if (ent->attributes[j].num_values == 1) {
365                                 ent->attributes[j].values = talloc_array_p(ent->attributes,
366                                                                 DATA_BLOB, ent->attributes[j].num_values);
367                                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
368                                 status = convert_values(ent_r,
369                                                         &(res[0]->elements[j]),
370                                                         &(ent->attributes[j]),
371                                                         samdb, &ent->dn, r);
372                                 if (!NT_STATUS_IS_OK(status)) {
373                                         return status;
374                                 }
375                         } else {
376                                 ent->attributes[j].values = talloc_array_p(ent->attributes,
377                                                                 DATA_BLOB, ent->attributes[j].num_values);
378                                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
379                                 for (y=0; y < ent->attributes[j].num_values; y++) {
380                                         ent->attributes[j].values[y].length = res[0]->elements[j].values[y].length;
381                                         ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
382                                                                                 res[0]->elements[j].values[y].data);
383                                 }
384                         }
385                 }
386 queue_reply:
387                 status = ldapsrv_queue_reply(call, ent_r);
388                 if (!NT_STATUS_IS_OK(status)) {
389                         return status;
390                 }
391         } else {
392                 for (i=0; i < count; i++) {
393                         ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
394                         NT_STATUS_HAVE_NO_MEMORY(ent_r);
395
396                         ent = &ent_r->msg.r.SearchResultEntry;
397                         ent->dn = talloc_steal(ent_r, res[i]->dn);
398                         DEBUG(0,("hacked result [%d] dn: %s\n", i, ent->dn));
399                         ent->num_attributes = 0;
400                         ent->attributes = NULL;
401                         if (res[i]->num_elements == 0) {
402                                 goto queue_reply2;
403                         }
404                         ent->num_attributes = res[i]->num_elements;
405                         ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
406                         NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
407                         for (j=0; j < ent->num_attributes; j++) {
408                                 ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
409                                 ent->attributes[j].num_values = 0;
410                                 ent->attributes[j].values = NULL;
411                                 if (r->attributesonly && (res[i]->elements[j].num_values == 0)) {
412                                         continue;
413                                 }
414                                 ent->attributes[j].num_values = res[i]->elements[j].num_values;
415                                 ent->attributes[j].values = talloc_array_p(ent->attributes,
416                                                                 DATA_BLOB, ent->attributes[j].num_values);
417                                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
418                                 if (ent->attributes[j].num_values == 1) {
419                                         status = convert_values(ent_r,
420                                                         &(res[0]->elements[j]),
421                                                         &(ent->attributes[j]),
422                                                         samdb, &ent->dn, r);
423                                         if (!NT_STATUS_IS_OK(status)) {
424                                                 return status;
425                                         }
426                                 } else {
427                                         for (y=0; y < ent->attributes[j].num_values; y++) {
428                                                 ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
429                                                 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
430                                                                                 res[i]->elements[j].values[y].data);
431                                         }
432                                 }
433                         }
434 queue_reply2:
435                         status = ldapsrv_queue_reply(call, ent_r);
436                         if (!NT_STATUS_IS_OK(status)) {
437                                 return status;
438                         }
439                 }
440         }
441
442         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
443         NT_STATUS_HAVE_NO_MEMORY(done_r);
444
445         if (count > 0) {
446                 DEBUG(10,("hacked_Search: results: [%d]\n",count));
447                 result = LDAP_SUCCESS;
448                 errstr = NULL;
449         } else if (count == 0) {
450                 DEBUG(10,("hacked_Search: no results\n"));
451                 result = LDAP_NO_SUCH_OBJECT;
452                 errstr = ldb_errstring(samdb->ldb);     
453         } else if (count == -1) {
454                 DEBUG(10,("hacked_Search: error\n"));
455                 result = LDAP_OTHER;
456                 errstr = ldb_errstring(samdb->ldb);
457         }
458
459         done = &done_r->msg.r.SearchResultDone;
460         done->dn = NULL;
461         done->resultcode = result;
462         done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);;
463         done->referral = NULL;
464
465         talloc_free(local_ctx);
466
467         return ldapsrv_queue_reply(call, done_r);
468 }
469
470 static NTSTATUS hldb_Search(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
471                                      struct ldap_SearchRequest *r)
472 {
473         NTSTATUS status;
474         void *local_ctx;
475         struct ldb_wrap *samdb;
476 #if 0
477         struct ldap_dn *basedn;
478         struct ldap_Result *done;
479         struct ldap_SearchResEntry *ent;
480         struct ldapsrv_reply *ent_r, *done_r;
481         int result = LDAP_SUCCESS;
482         struct ldb_message **res = NULL;
483         int i, j, y, count = 0;
484         enum ldb_scope scope = LDB_SCOPE_DEFAULT;
485         const char **attrs = NULL;
486         const char *errstr = NULL;
487 #endif
488         local_ctx = talloc_named(call, 0, "hldb_Search local memory context");
489         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
490
491         samdb = samdb_connect(local_ctx);
492         NT_STATUS_HAVE_NO_MEMORY(samdb);
493
494         status = hacked_Search(partition, call, r, samdb);
495         talloc_free(local_ctx);
496         NT_STATUS_IS_OK_RETURN(status);
497         status = hacked_wellknown_Search(partition, call, r);
498         NT_STATUS_IS_OK_RETURN(status);
499         return status;
500 #if 0
501         basedn = ldap_parse_dn(local_ctx, r->basedn);
502         VALID_DN_SYNTAX(basedn,0);
503
504         DEBUG(10, ("hldb_Search: basedn: [%s]\n", basedn->dn));
505         DEBUG(10, ("hldb_Search: filter: [%s]\n", r->filter));
506
507         switch (r->scope) {
508                 case LDAP_SEARCH_SCOPE_BASE:
509                         DEBUG(10,("hldb_Search: scope: [BASE]\n"));
510                         scope = LDB_SCOPE_BASE;
511                         break;
512                 case LDAP_SEARCH_SCOPE_SINGLE:
513                         DEBUG(10,("hldb_Search: scope: [ONE]\n"));
514                         scope = LDB_SCOPE_ONELEVEL;
515                         break;
516                 case LDAP_SEARCH_SCOPE_SUB:
517                         DEBUG(10,("hldb_Search: scope: [SUB]\n"));
518                         scope = LDB_SCOPE_SUBTREE;
519                         break;
520         }
521
522         if (r->num_attributes >= 1) {
523                 attrs = talloc_array_p(samdb, const char *, r->num_attributes+1);
524                 NT_STATUS_HAVE_NO_MEMORY(attrs);
525
526                 for (i=0; i < r->num_attributes; i++) {
527                         DEBUG(10,("hldb_Search: attrs: [%s]\n",r->attributes[i]));
528                         attrs[i] = r->attributes[i];
529                 }
530                 attrs[i] = NULL;
531         }
532
533         count = ldb_search(samdb->ldb, basedn->dn, scope, r->filter, attrs, &res);
534         talloc_steal(samdb, res);
535
536         if (count < 1) {
537                 status = hacked_Search(partition, call, r, samdb);
538                 NT_STATUS_IS_OK_RETURN(status);
539                 status = hacked_wellknown_Search(partition, call, r);
540                 NT_STATUS_IS_OK_RETURN(status);
541         }
542
543         for (i=0; i < count; i++) {
544                 ent_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultEntry);
545                 NT_STATUS_HAVE_NO_MEMORY(ent_r);
546
547                 ent = &ent_r->msg.r.SearchResultEntry;
548                 ent->dn = talloc_steal(ent_r, res[i]->dn);
549                 ent->num_attributes = 0;
550                 ent->attributes = NULL;
551                 if (res[i]->num_elements == 0) {
552                         goto queue_reply;
553                 }
554                 ent->num_attributes = res[i]->num_elements;
555                 ent->attributes = talloc_array_p(ent_r, struct ldap_attribute, ent->num_attributes);
556                 NT_STATUS_HAVE_NO_MEMORY(ent->attributes);
557                 for (j=0; j < ent->num_attributes; j++) {
558                         ent->attributes[j].name = talloc_steal(ent->attributes, res[i]->elements[j].name);
559                         ent->attributes[j].num_values = 0;
560                         ent->attributes[j].values = NULL;
561                         if (r->attributesonly && (res[i]->elements[j].num_values == 0)) {
562                                 continue;
563                         }
564                         ent->attributes[j].num_values = res[i]->elements[j].num_values;
565                         ent->attributes[j].values = talloc_array_p(ent->attributes,
566                                                         DATA_BLOB, ent->attributes[j].num_values);
567                         NT_STATUS_HAVE_NO_MEMORY(ent->attributes[j].values);
568                         for (y=0; y < ent->attributes[j].num_values; y++) {
569                                 ent->attributes[j].values[y].length = res[i]->elements[j].values[y].length;
570                                 ent->attributes[j].values[y].data = talloc_steal(ent->attributes[j].values,
571                                                                         res[i]->elements[j].values[y].data);
572                         }
573                 }
574 queue_reply:
575                 status = ldapsrv_queue_reply(call, ent_r);
576                 if (!NT_STATUS_IS_OK(status)) {
577                         return status;
578                 }
579         }
580
581 reply:
582         done_r = ldapsrv_init_reply(call, LDAP_TAG_SearchResultDone);
583         NT_STATUS_HAVE_NO_MEMORY(done_r);
584
585         if (result == LDAP_SUCCESS) {
586                 if (count > 0) {
587                         DEBUG(10,("hldb_Search: results: [%d]\n",count));
588                         result = LDAP_SUCCESS;
589                         errstr = NULL;
590                 } else if (count == 0) {
591                         DEBUG(10,("hldb_Search: no results\n"));
592                         result = LDAP_NO_SUCH_OBJECT;
593                         errstr = ldb_errstring(samdb->ldb);
594                 } else if (count == -1) {
595                         DEBUG(10,("hldb_Search: error\n"));
596                         result = LDAP_OTHER;
597                         errstr = ldb_errstring(samdb->ldb);
598                 }
599         }
600
601         done = &done_r->msg.r.SearchResultDone;
602         done->dn = NULL;
603         done->resultcode = result;
604         done->errormessage = (errstr?talloc_strdup(done_r,errstr):NULL);
605         done->referral = NULL;
606
607         talloc_free(local_ctx);
608
609         return ldapsrv_queue_reply(call, done_r);
610 #endif
611 }
612
613 static NTSTATUS hldb_Add(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
614                                      struct ldap_AddRequest *r)
615 {
616         void *local_ctx;
617         struct ldap_dn *dn;
618         struct ldap_Result *add_result;
619         struct ldapsrv_reply *add_reply;
620         int ldb_ret;
621         struct ldb_wrap *samdb;
622         struct ldb_message *msg = NULL;
623         int result = LDAP_SUCCESS;
624         const char *errstr = NULL;
625         int i,j;
626
627         local_ctx = talloc_named(call, 0, "hldb_Add local memory context");
628         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
629
630         samdb = samdb_connect(local_ctx);
631         NT_STATUS_HAVE_NO_MEMORY(samdb);
632
633         dn = ldap_parse_dn(local_ctx, r->dn);
634         VALID_DN_SYNTAX(dn,1);
635
636         DEBUG(10, ("hldb_add: dn: [%s]\n", dn->dn));
637
638         msg = talloc_p(local_ctx, struct ldb_message);
639         NT_STATUS_HAVE_NO_MEMORY(msg);
640
641         msg->dn = dn->dn;
642         msg->private_data = NULL;
643         msg->num_elements = 0;
644         msg->elements = NULL;
645
646         if (r->num_attributes > 0) {
647                 msg->num_elements = r->num_attributes;
648                 msg->elements = talloc_array_p(msg, struct ldb_message_element, msg->num_elements);
649                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
650
651                 for (i=0; i < msg->num_elements; i++) {
652                         msg->elements[i].name = discard_const_p(char, r->attributes[i].name);
653                         msg->elements[i].flags = 0;
654                         msg->elements[i].num_values = 0;
655                         msg->elements[i].values = NULL;
656                         
657                         if (r->attributes[i].num_values > 0) {
658                                 msg->elements[i].num_values = r->attributes[i].num_values;
659                                 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
660                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
661
662                                 for (j=0; j < msg->elements[i].num_values; j++) {
663                                         if (!(r->attributes[i].values[j].length > 0)) {
664                                                 result = LDAP_OTHER;
665                                                 errstr = "Empty attribute values are not allowed";
666                                                 goto reply;
667                                         }
668                                         msg->elements[i].values[j].length = r->attributes[i].values[j].length;
669                                         msg->elements[i].values[j].data = r->attributes[i].values[j].data;                      
670                                 }
671                         } else {
672                                 result = LDAP_OTHER;
673                                 errstr = "No attribute values are not allowed";
674                                 goto reply;
675                         }
676                 }
677         } else {
678                 result = LDAP_OTHER;
679                 errstr = "No attributes are not allowed";
680                 goto reply;
681         }
682
683 reply:
684         add_reply = ldapsrv_init_reply(call, LDAP_TAG_AddResponse);
685         NT_STATUS_HAVE_NO_MEMORY(add_reply);
686
687         if (result == LDAP_SUCCESS) {
688                 ldb_ret = ldb_add(samdb->ldb, msg);
689                 if (ldb_ret == 0) {
690                         DEBUG(0,("hldb_Add: added: '%s'\n", msg->dn));
691                         result = LDAP_SUCCESS;
692                         errstr = NULL;
693                 } else {
694                         /* currently we have no way to tell if there was an internal ldb error
695                          * or if the object was not found, return the most probable error
696                          */
697                         result = LDAP_OPERATIONS_ERROR;
698                         errstr = ldb_errstring(samdb->ldb);
699                 }
700         }
701
702         add_result = &add_reply->msg.r.AddResponse;
703         add_result->dn = NULL;
704         add_result->resultcode = result;
705         add_result->errormessage = (errstr?talloc_strdup(add_reply,errstr):NULL);
706         add_result->referral = NULL;
707
708         talloc_free(local_ctx);
709
710         return ldapsrv_queue_reply(call, add_reply);
711 }
712
713 static NTSTATUS hldb_Del(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
714                                      struct ldap_DelRequest *r)
715 {
716         void *local_ctx;
717         struct ldap_dn *dn;
718         struct ldap_Result *del_result;
719         struct ldapsrv_reply *del_reply;
720         int ldb_ret;
721         struct ldb_wrap *samdb;
722         const char *errstr = NULL;
723         int result = LDAP_SUCCESS;
724
725         local_ctx = talloc_named(call, 0, "hldb_Del local memory context");
726         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
727
728         samdb = samdb_connect(local_ctx);
729         NT_STATUS_HAVE_NO_MEMORY(samdb);
730
731         dn = ldap_parse_dn(local_ctx, r->dn);
732         VALID_DN_SYNTAX(dn,1);
733
734         DEBUG(10, ("hldb_Del: dn: [%s]\n", dn->dn));
735
736 reply:
737         del_reply = ldapsrv_init_reply(call, LDAP_TAG_DelResponse);
738         NT_STATUS_HAVE_NO_MEMORY(del_reply);
739
740         if (result == LDAP_SUCCESS) {
741                 ldb_ret = ldb_delete(samdb->ldb, dn->dn);
742                 if (ldb_ret == 0) {
743                         result = LDAP_SUCCESS;
744                         errstr = NULL;
745                 } else {
746                         /* currently we have no way to tell if there was an internal ldb error
747                          * or if the object was not found, return the most probable error
748                          */
749                         result = LDAP_NO_SUCH_OBJECT;
750                         errstr = ldb_errstring(samdb->ldb);
751                 }
752         }
753
754         del_result = &del_reply->msg.r.DelResponse;
755         del_result->dn = NULL;
756         del_result->resultcode = result;
757         del_result->errormessage = (errstr?talloc_strdup(del_reply,errstr):NULL);
758         del_result->referral = NULL;
759
760         talloc_free(local_ctx);
761
762         return ldapsrv_queue_reply(call, del_reply);
763 }
764
765 static NTSTATUS hldb_Modify(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
766                                      struct ldap_ModifyRequest *r)
767 {
768         void *local_ctx;
769         struct ldap_dn *dn;
770         struct ldap_Result *modify_result;
771         struct ldapsrv_reply *modify_reply;
772         int ldb_ret;
773         struct ldb_wrap *samdb;
774         struct ldb_message *msg = NULL;
775         int result = LDAP_SUCCESS;
776         const char *errstr = NULL;
777         int i,j;
778
779         local_ctx = talloc_named(call, 0, "hldb_Modify local memory context");
780         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
781
782         samdb = samdb_connect(local_ctx);
783         NT_STATUS_HAVE_NO_MEMORY(samdb);
784
785         dn = ldap_parse_dn(local_ctx, r->dn);
786         VALID_DN_SYNTAX(dn,1);
787
788         DEBUG(10, ("hldb_modify: dn: [%s]\n", dn->dn));
789
790         msg = talloc_p(local_ctx, struct ldb_message);
791         NT_STATUS_HAVE_NO_MEMORY(msg);
792
793         msg->dn = dn->dn;
794         msg->private_data = NULL;
795         msg->num_elements = 0;
796         msg->elements = NULL;
797
798         if (r->num_mods > 0) {
799                 msg->num_elements = r->num_mods;
800                 msg->elements = talloc_array_p(msg, struct ldb_message_element, r->num_mods);
801                 NT_STATUS_HAVE_NO_MEMORY(msg->elements);
802
803                 for (i=0; i < msg->num_elements; i++) {
804                         msg->elements[i].name = discard_const_p(char, r->mods[i].attrib.name);
805                         msg->elements[i].num_values = 0;
806                         msg->elements[i].values = NULL;
807
808                         switch (r->mods[i].type) {
809                         default:
810                                 result = LDAP_PROTOCOL_ERROR;
811                                 errstr = "Invalid LDAP_MODIFY_* type";
812                                 goto reply;
813                         case LDAP_MODIFY_ADD:
814                                 msg->elements[i].flags = LDB_FLAG_MOD_ADD;
815                                 break;
816                         case LDAP_MODIFY_DELETE:
817                                 msg->elements[i].flags = LDB_FLAG_MOD_DELETE;
818                                 break;
819                         case LDAP_MODIFY_REPLACE:
820                                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
821                                 break;
822                         }
823
824                         msg->elements[i].num_values = r->mods[i].attrib.num_values;
825                         if (msg->elements[i].num_values > 0) {
826                                 msg->elements[i].values = talloc_array_p(msg, struct ldb_val, msg->elements[i].num_values);
827                                 NT_STATUS_HAVE_NO_MEMORY(msg->elements[i].values);
828
829                                 for (j=0; j < msg->elements[i].num_values; j++) {
830                                         if (!(r->mods[i].attrib.values[j].length > 0)) {
831                                                 result = LDAP_OTHER;
832                                                 errstr = "Empty attribute values are not allowed";
833                                                 goto reply;
834                                         }
835                                         msg->elements[i].values[j].length = r->mods[i].attrib.values[j].length;
836                                         msg->elements[i].values[j].data = r->mods[i].attrib.values[j].data;                     
837                                 }
838                         }
839                 }
840         } else {
841                 result = LDAP_OTHER;
842                 errstr = "No mods are not allowed";
843                 goto reply;
844         }
845
846 reply:
847         modify_reply = ldapsrv_init_reply(call, LDAP_TAG_ModifyResponse);
848         NT_STATUS_HAVE_NO_MEMORY(modify_reply);
849
850         if (result == LDAP_SUCCESS) {
851                 ldb_ret = ldb_modify(samdb->ldb, msg);
852                 if (ldb_ret == 0) {
853                         result = LDAP_SUCCESS;
854                         errstr = NULL;
855                 } else {
856                         /* currently we have no way to tell if there was an internal ldb error
857                          * or if the object was not found, return the most probable error
858                          */
859                                 result = LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
860                         result = LDAP_OPERATIONS_ERROR;
861                         errstr = ldb_errstring(samdb->ldb);
862                         if (strcmp("Type or value exists", errstr) ==0){
863                                 result = LDAP_ATTRIBUTE_OR_VALUE_EXISTS;
864                         }
865                         DEBUG(0,("failed to modify: %s - %u - %s\n", msg->dn, result, errstr));
866                 }
867         }
868
869         modify_result = &modify_reply->msg.r.AddResponse;
870         modify_result->dn = NULL;
871         modify_result->resultcode = result;
872         modify_result->errormessage = (errstr?talloc_strdup(modify_reply,errstr):NULL);
873         modify_result->referral = NULL;
874
875         talloc_free(local_ctx);
876
877         return ldapsrv_queue_reply(call, modify_reply);
878 }
879
880 static NTSTATUS hldb_Compare(struct ldapsrv_partition *partition, struct ldapsrv_call *call,
881                                      struct ldap_CompareRequest *r)
882 {
883         void *local_ctx;
884         struct ldap_dn *dn;
885         struct ldap_Result *compare;
886         struct ldapsrv_reply *compare_r;
887         int result = LDAP_SUCCESS;
888         struct ldb_wrap *samdb;
889         struct ldb_message **res = NULL;
890         const char *attrs[1];
891         const char *errstr = NULL;
892         const char *filter = NULL;
893         int count;
894
895         local_ctx = talloc_named(call, 0, "hldb_Compare local_memory_context");
896         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
897
898         samdb = samdb_connect(local_ctx);
899         NT_STATUS_HAVE_NO_MEMORY(samdb);
900
901         dn = ldap_parse_dn(local_ctx, r->dn);
902         VALID_DN_SYNTAX(dn,1);
903
904         DEBUG(10, ("hldb_Compare: dn: [%s]\n", dn->dn));
905         filter = talloc_asprintf(local_ctx, "(%s=%*s)", r->attribute, r->value.length, r->value.data);
906         NT_STATUS_HAVE_NO_MEMORY(filter);
907
908         DEBUGADD(10, ("hldb_Compare: attribute: [%s]\n", filter));
909
910         attrs[0] = NULL;
911
912 reply:
913         compare_r = ldapsrv_init_reply(call, LDAP_TAG_CompareResponse);
914         NT_STATUS_HAVE_NO_MEMORY(compare_r);
915
916         if (result == LDAP_SUCCESS) {
917                 count = ldb_search(samdb->ldb, dn->dn, LDB_SCOPE_BASE, filter, attrs, &res);
918                 talloc_steal(samdb, res);
919                 if (count == 1) {
920                         DEBUG(10,("hldb_Compare: matched\n"));
921                         result = LDAP_COMPARE_TRUE;
922                         errstr = NULL;
923                 } else if (count == 0) {
924                         DEBUG(10,("hldb_Compare: doesn't matched\n"));
925                         result = LDAP_COMPARE_FALSE;
926                         errstr = NULL;
927                 } else if (count > 1) {
928                         result = LDAP_OTHER;
929                         errstr = "too many objects match";
930                         DEBUG(10,("hldb_Compare: %d results: %s\n", count, errstr));
931                 } else if (count == -1) {
932                         result = LDAP_OTHER;
933                         errstr = ldb_errstring(samdb->ldb);
934                         DEBUG(10,("hldb_Compare: error: %s\n", errstr));
935                 }
936         }
937
938         compare = &compare_r->msg.r.CompareResponse;
939         compare->dn = NULL;
940         compare->resultcode = result;
941         compare->errormessage = (errstr?talloc_strdup(compare_r,errstr):NULL);
942         compare->referral = NULL;
943
944         talloc_free(local_ctx);
945
946         return ldapsrv_queue_reply(call, compare_r);
947 }
948
949 static NTSTATUS hldb_ModifyDN(struct ldapsrv_partition *partition, struct ldapsrv_call *call, struct ldap_ModifyDNRequest *r)
950 {
951         void *local_ctx;
952         struct ldap_dn *olddn, *newrdn, *newsuperior;
953         struct ldap_Result *modifydn;
954         struct ldapsrv_reply *modifydn_r;
955         int ldb_ret;
956         struct ldb_wrap *samdb;
957         const char *errstr = NULL;
958         int result = LDAP_SUCCESS;
959         const char *newdn = NULL;
960         char *parentdn = NULL;
961
962         local_ctx = talloc_named(call, 0, "hldb_ModifyDN local memory context");
963         NT_STATUS_HAVE_NO_MEMORY(local_ctx);
964
965         samdb = samdb_connect(local_ctx);
966         NT_STATUS_HAVE_NO_MEMORY(samdb);
967
968         olddn = ldap_parse_dn(local_ctx, r->dn);
969         VALID_DN_SYNTAX(olddn,2);
970
971         newrdn = ldap_parse_dn(local_ctx, r->newrdn);
972         VALID_DN_SYNTAX(newrdn,1);
973
974         DEBUG(10, ("hldb_ModifyDN: olddn: [%s]\n", olddn->dn));
975         DEBUG(10, ("hldb_ModifyDN: newrdn: [%s]\n", newrdn->dn));
976
977         /* we can't handle the rename if we should not remove the old dn */
978         if (!r->deleteolddn) {
979                 result = LDAP_UNWILLING_TO_PERFORM;
980                 errstr = "Old RDN must be deleted";
981                 goto reply;
982         }
983
984         if (newrdn->comp_num > 1) {
985                 result = LDAP_NAMING_VIOLATION;
986                 errstr = "Error new RDN invalid";
987                 goto reply;
988         }
989
990         if (r->newsuperior) {
991                 newsuperior = ldap_parse_dn(local_ctx, r->newsuperior);
992                 VALID_DN_SYNTAX(newsuperior,0);
993                 DEBUG(10, ("hldb_ModifyDN: newsuperior: [%s]\n", newsuperior->dn));
994                 
995                 if (newsuperior->comp_num < 1) {
996                         result = LDAP_AFFECTS_MULTIPLE_DSAS;
997                         errstr = "Error new Superior DN invalid";
998                         goto reply;
999                 }
1000                 parentdn = newsuperior->dn;
1001         }
1002
1003         if (!parentdn) {
1004                 int i;
1005                 parentdn = talloc_strdup(local_ctx, olddn->components[1]->component);
1006                 NT_STATUS_HAVE_NO_MEMORY(parentdn);
1007                 for(i=2; i < olddn->comp_num; i++) {
1008                         char *old = parentdn;
1009                         parentdn = talloc_asprintf(local_ctx, "%s,%s", old, olddn->components[i]->component);
1010                         NT_STATUS_HAVE_NO_MEMORY(parentdn);
1011                         talloc_free(old);
1012                 }
1013         }
1014         newdn = talloc_asprintf(local_ctx, "%s,%s", newrdn->dn, parentdn);
1015         NT_STATUS_HAVE_NO_MEMORY(newdn);
1016
1017 reply:
1018         modifydn_r = ldapsrv_init_reply(call, LDAP_TAG_ModifyDNResponse);
1019         NT_STATUS_HAVE_NO_MEMORY(modifydn_r);
1020
1021         if (result == LDAP_SUCCESS) {
1022                 ldb_ret = ldb_rename(samdb->ldb, olddn->dn, newdn);
1023                 if (ldb_ret == 0) {
1024                         result = LDAP_SUCCESS;
1025                         errstr = NULL;
1026                 } else {
1027                         /* currently we have no way to tell if there was an internal ldb error
1028                          * or if the object was not found, return the most probable error
1029                          */
1030                         result = LDAP_NO_SUCH_OBJECT;
1031                         errstr = ldb_errstring(samdb->ldb);
1032                 }
1033         }
1034
1035         modifydn = &modifydn_r->msg.r.ModifyDNResponse;
1036         modifydn->dn = NULL;
1037         modifydn->resultcode = result;
1038         modifydn->errormessage = (errstr?talloc_strdup(modifydn_r,errstr):NULL);
1039         modifydn->referral = NULL;
1040
1041         talloc_free(local_ctx);
1042
1043         return ldapsrv_queue_reply(call, modifydn_r);
1044 }
1045
1046 static const struct ldapsrv_partition_ops hldb_ops = {
1047         .Search         = hldb_Search,
1048         .Add            = hldb_Add,
1049         .Del            = hldb_Del,
1050         .Modify         = hldb_Modify,
1051         .Compare        = hldb_Compare,
1052         .ModifyDN       = hldb_ModifyDN
1053 };
1054
1055 const struct ldapsrv_partition_ops *ldapsrv_get_hldb_partition_ops(void)
1056 {
1057         return &hldb_ops;
1058 }