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