9ab683016161596ac658fa02fd2be12e5f3731a4
[samba.git] / source / dsdb / samdb / ldb_modules / samldb.c
1 /* 
2    SAM ldb module
3
4    Copyright (C) Simo Sorce  2004
5
6    * NOTICE: this module is NOT released under the GNU LGPL license as
7    * other ldb code. This module is release under the GNU GPL v2 or
8    * later license.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb samldb module
29  *
30  *  Description: add embedded user/group creation functionality
31  *
32  *  Author: Simo Sorce
33  */
34
35 #include "includes.h"
36 #include "lib/ldb/include/ldb.h"
37 #include "lib/ldb/include/ldb_private.h"
38 #include "system/time.h"
39 #include "librpc/gen_ndr/ndr_security.h"
40
41 #define SAM_ACCOUNT_NAME_BASE "$000000-000000000000"
42
43 struct private_data {
44         const char *error_string;
45 };
46
47 static int samldb_search(struct ldb_module *module, const struct ldb_dn *base,
48                                   enum ldb_scope scope, const char *expression,
49                                   const char * const *attrs, struct ldb_message ***res)
50 {
51         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_search\n");
52         return ldb_next_search(module, base, scope, expression, attrs, res);
53 }
54
55 static int samldb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
56                                 enum ldb_scope scope, struct ldb_parse_tree *tree,
57                                 const char * const *attrs, struct ldb_message ***res)
58 {
59         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_search\n");
60         return ldb_next_search_bytree(module, base, scope, tree, attrs, res);
61 }
62
63 /*
64   allocate a new id, attempting to do it atomically
65   return 0 on failure, the id on success
66 */
67 static int samldb_allocate_next_rid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
68                                    const struct ldb_dn *dn, uint32_t *id)
69 {
70         const char * const attrs[2] = { "nextRid", NULL };
71         struct ldb_message **res = NULL;
72         struct ldb_message msg;
73         int ret;
74         const char *str;
75         struct ldb_val vals[2];
76         struct ldb_message_element els[2];
77
78         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, "nextRid=*", attrs, &res);
79         if (ret != 1) {
80                 if (res) talloc_free(res);
81                 return -1;
82         }
83         str = ldb_msg_find_string(res[0], "nextRid", NULL);
84         if (str == NULL) {
85                 ldb_debug(ldb, LDB_DEBUG_FATAL, "attribute nextRid not found in %s\n", ldb_dn_linearize(res, dn));
86                 talloc_free(res);
87                 return -1;
88         }
89
90         *id = strtol(str, NULL, 0);
91         if ((*id)+1 == 0) {
92                 /* out of IDs ! */
93                 ldb_debug(ldb, LDB_DEBUG_FATAL, "Are we out of valid IDs ?\n");
94                 talloc_free(res);
95                 return -1;
96         }
97         talloc_free(res);
98
99         /* we do a delete and add as a single operation. That prevents
100            a race */
101         ZERO_STRUCT(msg);
102         msg.dn = ldb_dn_copy(mem_ctx, dn);
103         if (!msg.dn) {
104                 return -1;
105         }
106         msg.num_elements = 2;
107         msg.elements = els;
108
109         els[0].num_values = 1;
110         els[0].values = &vals[0];
111         els[0].flags = LDB_FLAG_MOD_DELETE;
112         els[0].name = talloc_strdup(mem_ctx, "nextRid");
113         if (!els[0].name) {
114                 return -1;
115         }
116
117         els[1].num_values = 1;
118         els[1].values = &vals[1];
119         els[1].flags = LDB_FLAG_MOD_ADD;
120         els[1].name = els[0].name;
121
122         vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
123         if (!vals[0].data) {
124                 return -1;
125         }
126         vals[0].length = strlen(vals[0].data);
127
128         vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
129         if (!vals[1].data) {
130                 return -1;
131         }
132         vals[1].length = strlen(vals[1].data);
133
134         ret = ldb_modify(ldb, &msg);
135         if (ret != 0) {
136                 return 1;
137         }
138
139         (*id)++;
140
141         return 0;
142 }
143
144 static struct ldb_dn *samldb_search_domain(struct ldb_module *module, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
145 {
146         TALLOC_CTX *local_ctx;
147         struct ldb_dn *sdn;
148         struct ldb_message **res = NULL;
149         int ret = 0;
150
151         local_ctx = talloc_named(mem_ctx, 0, "samldb_search_domain memory conext");
152         if (local_ctx == NULL) return NULL;
153
154         sdn = ldb_dn_copy(local_ctx, dn);
155         do {
156                 ret = ldb_search(module->ldb, sdn, LDB_SCOPE_BASE, "objectClass=domain", NULL, &res);
157                 talloc_free(res);
158
159                 if (ret == 1)
160                         break;
161
162         } while ((sdn = ldb_dn_get_parent(local_ctx, sdn)));
163
164         if (ret != 1) {
165                 talloc_free(local_ctx);
166                 return NULL;
167         }
168
169         talloc_steal(mem_ctx, sdn);
170         talloc_free(local_ctx);
171
172         return sdn;
173 }
174
175 /* search the domain related to the provided dn
176    allocate a new RID for the domain
177    return the new sid string
178 */
179 static struct dom_sid *samldb_get_new_sid(struct ldb_module *module, 
180                                           TALLOC_CTX *mem_ctx, const struct ldb_dn *obj_dn)
181 {
182         const char * const attrs[2] = { "objectSid", NULL };
183         struct ldb_message **res = NULL;
184         const struct ldb_dn *dom_dn;
185         uint32_t rid;
186         int ret, tries = 10;
187         struct dom_sid *dom_sid, *obj_sid;
188
189         /* get the domain component part of the provided dn */
190
191         /* FIXME: quick search here, I think we should use something like
192            ldap_parse_dn here to be 100% sure we get the right domain dn */
193
194         /* FIXME: "dc=" is probably not utf8 safe either,
195            we need a multibyte safe substring search function here */
196         
197         dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
198         if (dom_dn == NULL) {
199                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Invalid dn (%s) not child of a domain object!\n", ldb_dn_linearize(mem_ctx, obj_dn));
200                 return NULL;
201         }
202
203         /* find the domain sid */
204
205         ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
206         if (ret != 1) {
207                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
208                 talloc_free(res);
209                 return NULL;
210         }
211
212         dom_sid = samdb_result_dom_sid(res, res[0], "objectSid");
213         if (dom_sid == NULL) {
214                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_get_new_sid: error retrieving domain sid!\n");
215                 talloc_free(res);
216                 return NULL;
217         }
218
219         /* allocate a new Rid for the domain */
220
221         /* we need to try multiple times to cope with two account
222            creations at the same time */
223         while (tries--) {
224                 ret = samldb_allocate_next_rid(module->ldb, mem_ctx, dom_dn, &rid);
225                 if (ret != 1) {
226                         break;
227                 }
228         }
229         if (ret != 0) {
230                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s\n", ldb_dn_linearize(mem_ctx, dom_dn));
231                 talloc_free(res);
232                 return NULL;
233         }
234
235         /* return the new object sid */
236         obj_sid = dom_sid_add_rid(mem_ctx, dom_sid, rid);
237
238         talloc_free(res);
239
240         return obj_sid;
241 }
242
243 static char *samldb_generate_samAccountName(const void *mem_ctx) {
244         char *name;
245
246         name = talloc_strdup(mem_ctx, SAM_ACCOUNT_NAME_BASE);
247         /* TODO: randomize name */      
248
249         return name;
250 }
251
252 /* if value is not null also check for attribute to have exactly that value */
253 static struct ldb_message_element *samldb_find_attribute(const struct ldb_message *msg, const char *name, const char *value)
254 {
255         int i, j;
256
257         for (i = 0; i < msg->num_elements; i++) {
258                 if (ldb_attr_cmp(name, msg->elements[i].name) == 0) {
259                         if (!value) {
260                                 return &msg->elements[i];
261                         }
262                         for (j = 0; j < msg->elements[i].num_values; j++) {
263                                 if (strcasecmp(value, msg->elements[i].values[j].data) == 0) {
264                                         return &msg->elements[i];
265                                 }
266                         }
267                 }
268         }
269
270         return NULL;
271 }
272
273 static BOOL samldb_msg_add_string(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value)
274 {
275         char *aname = talloc_strdup(msg, name);
276         char *aval = talloc_strdup(msg, value);
277
278         if (aname == NULL || aval == NULL) {
279                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_msg_add_string: talloc_strdup failed!\n");
280                 return False;
281         }
282
283         if (ldb_msg_add_string(module->ldb, msg, aname, aval) != 0) {
284                 return False;
285         }
286
287         return True;
288 }
289
290 static BOOL samldb_msg_add_sid(struct ldb_module *module, struct ldb_message *msg, const char *name, const struct dom_sid *sid)
291 {
292         struct ldb_val v;
293         NTSTATUS status;
294         status = ndr_push_struct_blob(&v, msg, sid, 
295                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
296         if (!NT_STATUS_IS_OK(status)) {
297                 return -1;
298         }
299         return (ldb_msg_add_value(module->ldb, msg, name, &v) == 0);
300 }
301
302 static BOOL samldb_find_or_add_attribute(struct ldb_module *module, struct ldb_message *msg, const char *name, const char *value, const char *set_value)
303 {
304         if (samldb_find_attribute(msg, name, value) == NULL) {
305                 return samldb_msg_add_string(module, msg, name, set_value);
306         }
307         return True;
308 }
309
310 static int samldb_copy_template(struct ldb_module *module, struct ldb_message *msg, const char *filter)
311 {
312         struct ldb_message **res, *t;
313         int ret, i, j;
314         
315
316         /* pull the template record */
317         ret = ldb_search(module->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
318         if (ret != 1) {
319                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb: ERROR: template '%s' matched %d records\n", filter, ret);
320                 return -1;
321         }
322         t = res[0];
323
324         for (i = 0; i < t->num_elements; i++) {
325                 struct ldb_message_element *el = &t->elements[i];
326                 /* some elements should not be copied from the template */
327                 if (strcasecmp(el->name, "cn") == 0 ||
328                     strcasecmp(el->name, "name") == 0 ||
329                     strcasecmp(el->name, "sAMAccountName") == 0 ||
330                     strcasecmp(el->name, "objectGUID") == 0) {
331                         continue;
332                 }
333                 for (j = 0; j < el->num_values; j++) {
334                         if (strcasecmp(el->name, "objectClass") == 0 &&
335                             (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
336                              strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
337                              strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
338                              strcasecmp((char *)el->values[j].data, "foreignSecurityPrincipalTemplate") == 0 ||
339                              strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
340                              strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
341                              strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
342                                 continue;
343                         }
344                         if ( ! samldb_find_or_add_attribute(module, msg, el->name, 
345                                                             NULL,
346                                                             (char *)el->values[j].data)) {
347                                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Attribute adding failed...\n");
348                                 talloc_free(res);
349                                 return -1;
350                         }
351                 }
352         }
353
354         talloc_free(res);
355
356         return 0;
357 }
358
359 static struct ldb_message *samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg)
360 {
361         struct ldb_message *msg2;
362         struct ldb_message_element *attribute;
363         struct ldb_dn_component *rdn;
364
365         if (samldb_find_attribute(msg, "objectclass", "group") == NULL) {
366                 return NULL;
367         }
368
369         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_group_object\n");
370
371         /* build the new msg */
372         msg2 = ldb_msg_copy(module->ldb, msg);
373         if (!msg2) {
374                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
375                 return NULL;
376         }
377
378         if (samldb_copy_template(module, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))") != 0) {
379                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_group_object: Error copying template!\n");
380                 return NULL;
381         }
382
383         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
384                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad DN (%s)!\n", ldb_dn_linearize(msg2, msg2->dn));
385                 return NULL;
386         }
387         if (strcasecmp(rdn->name, "cn") != 0) {
388                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn->name);
389                 return NULL;
390         }
391
392         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
393                 struct dom_sid *sid = samldb_get_new_sid(module, msg2, msg2->dn);
394                 if (sid == NULL) {
395                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: internal error! Can't generate new sid\n");
396                         return NULL;
397                 }
398
399                 if (!samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
400                         talloc_free(sid);
401                         return NULL;
402                 }
403                 talloc_free(sid);
404         }
405
406         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
407                 return NULL;
408         }
409
410         talloc_steal(msg, msg2);
411
412         return msg2;
413 }
414
415 static struct ldb_message *samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg)
416 {
417         struct ldb_message *msg2;
418         struct ldb_message_element *attribute;
419         struct ldb_dn_component *rdn;
420
421         if ((samldb_find_attribute(msg, "objectclass", "user") == NULL) && 
422             (samldb_find_attribute(msg, "objectclass", "computer") == NULL)) {
423                 return NULL;
424         }
425
426         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_user_or_computer_object\n");
427
428         /* build the new msg */
429         msg2 = ldb_msg_copy(module->ldb, msg);
430         if (!msg2) {
431                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n");
432                 return NULL;
433         }
434
435         if (samldb_find_attribute(msg, "objectclass", "computer") != NULL) {
436                 if (samldb_copy_template(module, msg2, "(&(CN=TemplateMemberServer)(objectclass=userTemplate))") != 0) {
437                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying computer template!\n");
438                         return NULL;
439                 }
440         } else {
441                 if (samldb_copy_template(module, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))") != 0) {
442                         ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_user_or_computer_object: Error copying user template!\n");
443                         return NULL;
444                 }
445         }
446
447         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
448                 return NULL;
449         }
450         if (strcasecmp(rdn->name, "cn") != 0) {
451                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: Bad RDN (%s) for user/computer!\n", rdn->name);
452                 return NULL;
453         }
454
455         /* if the only attribute was: "objectclass: computer", then make sure we also add "user" objectclass */
456         if ( ! samldb_find_or_add_attribute(module, msg2, "objectclass", "user", "user")) {
457                 return NULL;
458         }
459
460         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
461                 struct dom_sid *sid;
462                 sid = samldb_get_new_sid(module, msg2, msg2->dn);
463                 if (sid == NULL) {
464                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_user_or_computer_object: internal error! Can't generate new sid\n");
465                         return NULL;
466                 }
467
468                 if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
469                         talloc_free(sid);
470                         return NULL;
471                 }
472                 talloc_free(sid);
473         }
474
475         if ( ! samldb_find_or_add_attribute(module, msg2, "sAMAccountName", NULL, samldb_generate_samAccountName(msg2))) {
476                 return NULL;
477         }
478
479         /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */
480
481         return msg2;
482 }
483
484 static struct ldb_message *samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg)
485 {
486         struct ldb_message *msg2;
487         struct ldb_message_element *attribute;
488         struct ldb_dn_component *rdn;
489
490         if (samldb_find_attribute(msg, "objectclass", "foreignSecurityPrincipal") == NULL) {
491                 return NULL;
492         }
493
494         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_fill_foreignSecurityPrincipal_object\n");
495
496         /* build the new msg */
497         msg2 = ldb_msg_copy(module->ldb, msg);
498         if (!msg2) {
499                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n");
500                 return NULL;
501         }
502
503         talloc_steal(msg, msg2);
504
505         if (samldb_copy_template(module, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))") != 0) {
506                 ldb_debug(module->ldb, LDB_DEBUG_WARNING, "samldb_fill_foreignSecurityPrincipal_object: Error copying template!\n");
507                 return NULL;
508         }
509
510         if ((rdn = ldb_dn_get_rdn(msg2, msg2->dn)) == NULL) {
511                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: Bad DN (%s)!\n", ldb_dn_linearize(msg2, msg2->dn));
512                 return NULL;
513         }
514         if (strcasecmp(rdn->name, "cn") != 0) {
515                 ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: Bad RDN (%s) for foreignSecurityPrincpal!\n", rdn->name);
516                 return NULL;
517         }
518
519         if ((attribute = samldb_find_attribute(msg2, "objectSid", NULL)) == NULL ) {
520                 struct dom_sid *sid = dom_sid_parse_talloc(msg2, rdn->value.data);
521                 if (sid == NULL) {
522                         ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincipal_object: internal error! Can't parse sid in CN\n");
523                         return NULL;
524                 }
525
526                 if (!samldb_msg_add_sid(module, msg2, "objectSid", sid)) {
527                         talloc_free(sid);
528                         return NULL;
529                 }
530                 talloc_free(sid);
531         }
532
533         return msg2;
534 }
535
536 /* add_record */
537 static int samldb_add_record(struct ldb_module *module, const struct ldb_message *msg)
538 {
539         struct ldb_message *msg2 = NULL;
540         int ret;
541
542         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
543
544         if (strcmp(msg->dn->components[0].name, LDB_SPECIAL) == 0) { /* do not manipulate our control entries */
545                 return ldb_next_add_record(module, msg);
546         }
547
548         /* is user or computer?  add all relevant missing objects */
549         msg2 = samldb_fill_user_or_computer_object(module, msg);
550
551         /* is group? add all relevant missing objects */
552         if ( ! msg2 ) {
553                 msg2 = samldb_fill_group_object(module, msg);
554         }
555
556         /* perhaps a foreignSecurityPrincipal? */
557         if ( ! msg2 ) {
558                 msg2 = samldb_fill_foreignSecurityPrincipal_object(module, msg);
559         }
560
561         if (msg2) {
562                 ret = ldb_next_add_record(module, msg2);
563         } else {
564                 ret = ldb_next_add_record(module, msg);
565         }
566
567         return ret;
568 }
569
570 /* modify_record: change modifyTimestamp as well */
571 static int samldb_modify_record(struct ldb_module *module, const struct ldb_message *msg)
572 {
573         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_modify_record\n");
574         return ldb_next_modify_record(module, msg);
575 }
576
577 static int samldb_delete_record(struct ldb_module *module, const struct ldb_dn *dn)
578 {
579         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_delete_record\n");
580         return ldb_next_delete_record(module, dn);
581 }
582
583 static int samldb_rename_record(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
584 {
585         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_rename_record\n");
586         return ldb_next_rename_record(module, olddn, newdn);
587 }
588
589 static int samldb_lock(struct ldb_module *module, const char *lockname)
590 {
591         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_lock\n");
592         return ldb_next_named_lock(module, lockname);
593 }
594
595 static int samldb_unlock(struct ldb_module *module, const char *lockname)
596 {
597         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_unlock\n");
598         return ldb_next_named_unlock(module, lockname);
599 }
600
601 /* return extended error information */
602 static const char *samldb_errstring(struct ldb_module *module)
603 {
604         struct private_data *data = (struct private_data *)module->private_data;
605
606         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_errstring\n");
607         if (data->error_string) {
608                 const char *error;
609
610                 error = data->error_string;
611                 data->error_string = NULL;
612                 return error;
613         }
614
615         return ldb_next_errstring(module);
616 }
617
618 static int samldb_destructor(void *module_ctx)
619 {
620         /* struct ldb_module *ctx = module_ctx; */
621         /* put your clean-up functions here */
622         return 0;
623 }
624
625 static const struct ldb_module_ops samldb_ops = {
626         .name          = "samldb",
627         .search        = samldb_search,
628         .search_bytree = samldb_search_bytree,
629         .add_record    = samldb_add_record,
630         .modify_record = samldb_modify_record,
631         .delete_record = samldb_delete_record,
632         .rename_record = samldb_rename_record,
633         .named_lock    = samldb_lock,
634         .named_unlock  = samldb_unlock,
635         .errstring     = samldb_errstring
636 };
637
638
639 /* the init function */
640 #ifdef HAVE_DLOPEN_DISABLED
641  struct ldb_module *init_module(struct ldb_context *ldb, const char *options[])
642 #else
643 struct ldb_module *samldb_module_init(struct ldb_context *ldb, const char *options[])
644 #endif
645 {
646         struct ldb_module *ctx;
647         struct private_data *data;
648
649         ctx = talloc(ldb, struct ldb_module);
650         if (!ctx)
651                 return NULL;
652
653         data = talloc(ctx, struct private_data);
654         if (!data) {
655                 talloc_free(ctx);
656                 return NULL;
657         }
658
659         data->error_string = NULL;
660         ctx->private_data = data;
661         ctx->ldb = ldb;
662         ctx->prev = ctx->next = NULL;
663         ctx->ops = &samldb_ops;
664
665         talloc_set_destructor(ctx, samldb_destructor);
666
667         return ctx;
668 }