2a0bb2dfe668f3949f8c23220af76dae1d77b00b
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / samldb.c
1 /*
2    SAM ldb module
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5    Copyright (C) Simo Sorce  2004-2008
6    Copyright (C) Matthias Dieter Wallnöfer 2009
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: ldb samldb module
26  *
27  *  Description: add embedded user/group creation functionality
28  *
29  *  Author: Simo Sorce
30  */
31
32 #include "includes.h"
33 #include "libcli/ldap/ldap_ndr.h"
34 #include "ldb_module.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "libcli/security/security.h"
37 #include "librpc/gen_ndr/ndr_security.h"
38 #include "../lib/util/util_ldb.h"
39 #include "ldb_wrap.h"
40
41 struct samldb_ctx;
42
43 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
44
45 struct samldb_step {
46         struct samldb_step *next;
47         samldb_step_fn_t fn;
48 };
49
50 struct samldb_ctx {
51         struct ldb_module *module;
52         struct ldb_request *req;
53
54         /* used for add operations */
55         const char *type;
56
57         /* the resulting message */
58         struct ldb_message *msg;
59
60         /* used to find parent domain */
61         struct ldb_dn *check_dn;
62         struct ldb_dn *domain_dn;
63         struct dom_sid *domain_sid;
64         uint32_t next_rid;
65
66         /* holds the entry SID */
67         struct dom_sid *sid;
68
69         /* holds a generic dn */
70         struct ldb_dn *dn;
71
72         /* used in conjunction with "sid" in "samldb_dn_from_sid" */
73         struct ldb_dn *res_dn;
74
75         /* used in conjunction with "dn" in "samldb_sid_from_dn" */
76         struct dom_sid *res_sid;
77
78         /* used in "samldb_user_dn_to_prim_group_rid" */
79         uint32_t prim_group_rid;
80
81         /* used in conjunction with "prim_group_rid" in
82          * "samldb_prim_group_rid_to_users_cnt" */
83         unsigned int users_cnt;
84
85         /* used in "samldb_group_add_member" and "samldb_group_del_member" */
86         struct ldb_dn *group_dn;
87         struct ldb_dn *member_dn;
88
89         /* used in "samldb_primary_group_change" */
90         struct ldb_dn *user_dn;
91         struct ldb_dn *old_prim_group_dn, *new_prim_group_dn;
92
93         /* generic counter - used in "samldb_member_check" */
94         unsigned int cnt;
95
96         /* all the async steps necessary to complete the operation */
97         struct samldb_step *steps;
98         struct samldb_step *curstep;
99 };
100
101 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
102                                           struct ldb_request *req)
103 {
104         struct ldb_context *ldb;
105         struct samldb_ctx *ac;
106
107         ldb = ldb_module_get_ctx(module);
108
109         ac = talloc_zero(req, struct samldb_ctx);
110         if (ac == NULL) {
111                 ldb_oom(ldb);
112                 return NULL;
113         }
114
115         ac->module = module;
116         ac->req = req;
117
118         return ac;
119 }
120
121 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
122 {
123         struct samldb_step *step, *stepper;
124
125         step = talloc_zero(ac, struct samldb_step);
126         if (step == NULL) {
127                 return LDB_ERR_OPERATIONS_ERROR;
128         }
129
130         step->fn = fn;
131
132         if (ac->steps == NULL) {
133                 ac->steps = step;
134                 ac->curstep = step;
135         } else {
136                 if (ac->curstep == NULL)
137                         return LDB_ERR_OPERATIONS_ERROR;
138                 for (stepper = ac->curstep; stepper->next != NULL;
139                         stepper = stepper->next);
140                 stepper->next = step;
141         }
142
143         return LDB_SUCCESS;
144 }
145
146 static int samldb_first_step(struct samldb_ctx *ac)
147 {
148         if (ac->steps == NULL) {
149                 return LDB_ERR_OPERATIONS_ERROR;
150         }
151
152         ac->curstep = ac->steps;
153         return ac->curstep->fn(ac);
154 }
155
156 static int samldb_next_step(struct samldb_ctx *ac)
157 {
158         if (ac->curstep->next) {
159                 ac->curstep = ac->curstep->next;
160                 return ac->curstep->fn(ac);
161         }
162
163         /* it is an error if the last step does not properly
164          * return to the upper module by itself */
165         return LDB_ERR_OPERATIONS_ERROR;
166 }
167
168 /*
169  * samldb_get_parent_domain (async)
170  */
171
172 static int samldb_get_parent_domain(struct samldb_ctx *ac);
173
174 static int samldb_get_parent_domain_callback(struct ldb_request *req,
175                                              struct ldb_reply *ares)
176 {
177         struct ldb_context *ldb;
178         struct samldb_ctx *ac;
179         const char *nextRid;
180         int ret;
181
182         ac = talloc_get_type(req->context, struct samldb_ctx);
183         ldb = ldb_module_get_ctx(ac->module);
184
185         if (!ares) {
186                 ret = LDB_ERR_OPERATIONS_ERROR;
187                 goto done;
188         }
189         if (ares->error != LDB_SUCCESS) {
190                 return ldb_module_done(ac->req, ares->controls,
191                                         ares->response, ares->error);
192         }
193
194         switch (ares->type) {
195         case LDB_REPLY_ENTRY:
196                 /* save entry */
197                 if ((ac->domain_dn != NULL) || (ac->domain_sid != NULL)) {
198                         /* one too many! */
199                         ldb_set_errstring(ldb,
200                                 "Invalid number of results while searching "
201                                 "for domain object!");
202                         ret = LDB_ERR_OPERATIONS_ERROR;
203                         break;
204                 }
205
206                 nextRid = ldb_msg_find_attr_as_string(ares->message,
207                                                       "nextRid", NULL);
208                 if (nextRid == NULL) {
209                         ldb_asprintf_errstring(ldb,
210                                 "While looking for domain above %s attribute nextRid not found in %s!\n",
211                                 ldb_dn_get_linearized(
212                                         ac->req->op.add.message->dn),
213                                 ldb_dn_get_linearized(ares->message->dn));
214                         ret = LDB_ERR_OPERATIONS_ERROR;
215                         break;
216                 }
217
218                 ac->next_rid = strtol(nextRid, NULL, 0);
219
220                 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
221                                                                 "objectSid");
222                 if (ac->domain_sid == NULL) {
223                         ldb_set_errstring(ldb,
224                                 "Unable to get the parent domain SID!\n");
225                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
226                         break;
227                 }
228                 ac->domain_dn = ldb_dn_copy(ac, ares->message->dn);
229
230                 talloc_free(ares);
231                 ret = LDB_SUCCESS;
232                 break;
233
234         case LDB_REPLY_REFERRAL:
235                 /* ignore */
236                 talloc_free(ares);
237                 ret = LDB_SUCCESS;
238                 break;
239
240         case LDB_REPLY_DONE:
241                 talloc_free(ares);
242                 if ((ac->domain_dn == NULL) || (ac->domain_sid == NULL)) {
243                         /* not found -> retry */
244                         ret = samldb_get_parent_domain(ac);
245                 } else {
246                         /* found, go on */
247                         ret = samldb_next_step(ac);
248                 }
249                 break;
250         }
251
252 done:
253         if (ret != LDB_SUCCESS) {
254                 return ldb_module_done(ac->req, NULL, NULL, ret);
255         }
256
257         return LDB_SUCCESS;
258 }
259
260 /* Find a domain object in the parents of a particular DN.  */
261 static int samldb_get_parent_domain(struct samldb_ctx *ac)
262 {
263         struct ldb_context *ldb;
264         static const char * const attrs[] = { "objectSid", "nextRid", NULL };
265         struct ldb_request *req;
266         struct ldb_dn *dn;
267         int ret;
268
269         ldb = ldb_module_get_ctx(ac->module);
270
271         if (ac->check_dn == NULL) {
272                 return LDB_ERR_OPERATIONS_ERROR;
273         }
274
275         dn = ldb_dn_get_parent(ac, ac->check_dn);
276         if (dn == NULL) {
277                 ldb_set_errstring(ldb,
278                         "Unable to find parent domain object!");
279                 return LDB_ERR_CONSTRAINT_VIOLATION;
280         }
281
282         ac->check_dn = dn;
283
284         ret = ldb_build_search_req(&req, ldb, ac,
285                                    dn, LDB_SCOPE_BASE,
286                                    "(|(objectClass=domain)"
287                                    "(objectClass=builtinDomain))",
288                                    attrs,
289                                    NULL,
290                                    ac, samldb_get_parent_domain_callback,
291                                    ac->req);
292
293         if (ret != LDB_SUCCESS) {
294                 return ret;
295         }
296
297         return ldb_next_request(ac->module, req);
298 }
299
300
301 static int samldb_generate_samAccountName(struct ldb_message *msg)
302 {
303         char *name;
304
305         /* Format: $000000-000000000000 */
306
307         name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
308                                 (unsigned int)generate_random(),
309                                 (unsigned int)generate_random(),
310                                 (unsigned int)generate_random());
311         if (name == NULL) {
312                 return LDB_ERR_OPERATIONS_ERROR;
313         }
314         return ldb_msg_add_steal_string(msg, "samAccountName", name);
315 }
316
317 /*
318  * samldb_check_samAccountName (async)
319  */
320
321 static int samldb_check_samAccountName_callback(struct ldb_request *req,
322                                                 struct ldb_reply *ares)
323 {
324         struct samldb_ctx *ac;
325         int ret;
326         
327         ac = talloc_get_type(req->context, struct samldb_ctx);
328         
329         if (ares->error != LDB_SUCCESS) {
330                 return ldb_module_done(ac->req, ares->controls,
331                                        ares->response, ares->error);
332         }
333         
334         switch (ares->type) {
335         case LDB_REPLY_ENTRY:           
336                 /* if we get an entry it means this samAccountName
337                  * already exists */
338                 return ldb_module_done(ac->req, NULL, NULL,
339                                        LDB_ERR_ENTRY_ALREADY_EXISTS);
340                 
341         case LDB_REPLY_REFERRAL:
342                 /* this should not happen */
343                 return ldb_module_done(ac->req, NULL, NULL,
344                                        LDB_ERR_OPERATIONS_ERROR);
345                 
346         case LDB_REPLY_DONE:
347                 /* not found, go on */
348                 talloc_free(ares);
349                 ret = samldb_next_step(ac);
350                 break;
351         }
352         
353         if (ret != LDB_SUCCESS) {
354                 return ldb_module_done(ac->req, NULL, NULL, ret);
355         }
356         
357         return LDB_SUCCESS;
358 }
359
360 static int samldb_check_samAccountName(struct samldb_ctx *ac)
361 {
362         struct ldb_context *ldb;
363         struct ldb_request *req;
364         const char *name;
365         char *filter;
366         int ret;
367         
368         ldb = ldb_module_get_ctx(ac->module);
369         
370         if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
371                 ret = samldb_generate_samAccountName(ac->msg);
372                 if (ret != LDB_SUCCESS) {
373                         return ret;
374                 }
375         }
376         
377         name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
378         if (name == NULL) {
379                 return LDB_ERR_OPERATIONS_ERROR;
380         }
381         filter = talloc_asprintf(ac, "samAccountName=%s", ldb_binary_encode_string(ac, name));
382         if (filter == NULL) {
383                 return LDB_ERR_OPERATIONS_ERROR;
384         }
385         
386         ret = ldb_build_search_req(&req, ldb, ac,
387                                    ac->domain_dn, LDB_SCOPE_SUBTREE,
388                                    filter, NULL,
389                                    NULL,
390                                    ac, samldb_check_samAccountName_callback,
391                                    ac->req);
392         talloc_free(filter);
393         if (ret != LDB_SUCCESS) {
394                 return ret;
395         }
396         return ldb_next_request(ac->module, req);
397 }
398
399
400 static int samldb_check_samAccountType(struct samldb_ctx *ac)
401 {
402         struct ldb_context *ldb;
403         unsigned int account_type;
404         unsigned int group_type;
405         unsigned int uac;
406         int ret;
407
408         ldb = ldb_module_get_ctx(ac->module);
409
410         /* make sure sAMAccountType is not specified */
411         if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
412                 ldb_asprintf_errstring(ldb,
413                         "sAMAccountType must not be specified!");
414                 return LDB_ERR_UNWILLING_TO_PERFORM;
415         }
416
417         if (strcmp("user", ac->type) == 0) {
418                 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
419                 if (uac == 0) {
420                         ldb_asprintf_errstring(ldb,
421                                 "userAccountControl invalid!");
422                         return LDB_ERR_UNWILLING_TO_PERFORM;
423                 } else {
424                         account_type = ds_uf2atype(uac);
425                         ret = samdb_msg_add_uint(ldb,
426                                                  ac->msg, ac->msg,
427                                                  "sAMAccountType",
428                                                  account_type);
429                         if (ret != LDB_SUCCESS) {
430                                 return ret;
431                         }
432                 }
433         } else
434         if (strcmp("group", ac->type) == 0) {
435
436                 group_type = samdb_result_uint(ac->msg, "groupType", 0);
437                 if (group_type == 0) {
438                         ldb_asprintf_errstring(ldb,
439                                 "groupType invalid!");
440                         return LDB_ERR_UNWILLING_TO_PERFORM;
441                 } else {
442                         account_type = ds_gtype2atype(group_type);
443                         ret = samdb_msg_add_uint(ldb,
444                                                  ac->msg, ac->msg,
445                                                  "sAMAccountType",
446                                                  account_type);
447                         if (ret != LDB_SUCCESS) {
448                                 return ret;
449                         }
450                 }
451         }
452
453         return samldb_next_step(ac);
454 }
455
456
457 /*
458  * samldb_get_sid_domain (async)
459  */
460
461 static int samldb_get_sid_domain_callback(struct ldb_request *req,
462                                           struct ldb_reply *ares)
463 {
464         struct ldb_context *ldb;
465         struct samldb_ctx *ac;
466         const char *nextRid;
467         int ret;
468
469         ac = talloc_get_type(req->context, struct samldb_ctx);
470         ldb = ldb_module_get_ctx(ac->module);
471
472         if (!ares) {
473                 ret = LDB_ERR_OPERATIONS_ERROR;
474                 goto done;
475         }
476         if (ares->error != LDB_SUCCESS) {
477                 return ldb_module_done(ac->req, ares->controls,
478                                         ares->response, ares->error);
479         }
480
481         switch (ares->type) {
482         case LDB_REPLY_ENTRY:
483                 /* save entry */
484                 if (ac->next_rid != 0) {
485                         /* one too many! */
486                         ldb_set_errstring(ldb,
487                                 "Invalid number of results while searching "
488                                 "for domain object!");
489                         ret = LDB_ERR_OPERATIONS_ERROR;
490                         break;
491                 }
492
493                 nextRid = ldb_msg_find_attr_as_string(ares->message,
494                                                         "nextRid", NULL);
495                 if (nextRid == NULL) {
496                         ldb_asprintf_errstring(ldb,
497                                 "Attribute nextRid not found in %s!\n",
498                                 ldb_dn_get_linearized(ares->message->dn));
499                         ret = LDB_ERR_OPERATIONS_ERROR;
500                         break;
501                 }
502
503                 ac->next_rid = strtol(nextRid, NULL, 0);
504
505                 ac->domain_dn = ldb_dn_copy(ac, ares->message->dn);
506
507                 talloc_free(ares);
508                 ret = LDB_SUCCESS;
509                 break;
510
511         case LDB_REPLY_REFERRAL:
512                 /* ignore */
513                 talloc_free(ares);
514                 ret = LDB_SUCCESS;
515                 break;
516
517         case LDB_REPLY_DONE:
518                 talloc_free(ares);
519                 if (ac->next_rid == 0) {
520                         ldb_asprintf_errstring(ldb,
521                                 "Unable to get nextRid from domain entry!\n");
522                         ret = LDB_ERR_OPERATIONS_ERROR;
523                         break;
524                 }
525
526                 /* found, go on */
527                 ret = samldb_next_step(ac);
528                 break;
529         }
530
531 done:
532         if (ret != LDB_SUCCESS) {
533                 return ldb_module_done(ac->req, NULL, NULL, ret);
534         }
535
536         return LDB_SUCCESS;
537 }
538
539 /* Find a domain object in the parents of a particular DN.  */
540 static int samldb_get_sid_domain(struct samldb_ctx *ac)
541 {
542         struct ldb_context *ldb;
543         static const char * const attrs[2] = { "nextRid", NULL };
544         struct ldb_request *req;
545         char *filter;
546         int ret;
547
548         ldb = ldb_module_get_ctx(ac->module);
549
550         if (ac->sid == NULL) {
551                 return LDB_ERR_OPERATIONS_ERROR;
552         }
553
554         ac->domain_sid = dom_sid_dup(ac, ac->sid);
555         if (!ac->domain_sid) {
556                 return LDB_ERR_OPERATIONS_ERROR;
557         }
558         /* get the domain component part of the provided SID */
559         ac->domain_sid->num_auths--;
560
561         filter = talloc_asprintf(ac, 
562                                  "(&(objectSid=%s)"
563                                  "(|(objectClass=domain)"
564                                  "(objectClass=builtinDomain)))",
565                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
566         if (filter == NULL) {
567                 return LDB_ERR_OPERATIONS_ERROR;
568         }
569
570         ret = ldb_build_search_req(&req, ldb, ac,
571                                    ldb_get_default_basedn(ldb),
572                                    LDB_SCOPE_SUBTREE,
573                                    filter, attrs,
574                                    NULL,
575                                    ac, samldb_get_sid_domain_callback,
576                                    ac->req);
577
578         if (ret != LDB_SUCCESS) {
579                 return ret;
580         }
581
582         ac->next_rid = 0;
583         return ldb_next_request(ac->module, req);
584 }
585
586 /*
587  * samldb_dn_from_sid (async)
588  */
589
590 static int samldb_dn_from_sid(struct samldb_ctx *ac);
591
592 static int samldb_dn_from_sid_callback(struct ldb_request *req,
593         struct ldb_reply *ares)
594 {
595         struct ldb_context *ldb;
596         struct samldb_ctx *ac;
597         int ret;
598
599         ac = talloc_get_type(req->context, struct samldb_ctx);
600         ldb = ldb_module_get_ctx(ac->module);
601
602         if (!ares) {
603                 ret = LDB_ERR_OPERATIONS_ERROR;
604                 goto done;
605         }
606         if (ares->error != LDB_SUCCESS) {
607                 return ldb_module_done(ac->req, ares->controls,
608                                         ares->response, ares->error);
609         }
610
611         switch (ares->type) {
612         case LDB_REPLY_ENTRY:
613                 /* save entry */
614                 if (ac->res_dn != NULL) {
615                         /* one too many! */
616                         ldb_set_errstring(ldb,
617                                 "Invalid number of results while searching "
618                                 "for domain objects!");
619                         ret = LDB_ERR_OPERATIONS_ERROR;
620                         break;
621                 }
622                 ac->res_dn = ldb_dn_copy(ac, ares->message->dn);
623
624                 talloc_free(ares);
625                 ret = LDB_SUCCESS;
626                 break;
627
628         case LDB_REPLY_REFERRAL:
629                 /* ignore */
630                 talloc_free(ares);
631                 ret = LDB_SUCCESS;
632                 break;
633
634         case LDB_REPLY_DONE:
635                 talloc_free(ares);
636
637                 /* found or not found, go on */
638                 ret = samldb_next_step(ac);
639                 break;
640         }
641
642 done:
643         if (ret != LDB_SUCCESS) {
644                 return ldb_module_done(ac->req, NULL, NULL, ret);
645         }
646
647         return LDB_SUCCESS;
648 }
649
650 /* Finds the DN "res_dn" of an object with a given SID "sid" */
651 static int samldb_dn_from_sid(struct samldb_ctx *ac)
652 {
653         struct ldb_context *ldb;
654         static const char * const attrs[] = { NULL };
655         struct ldb_request *req;
656         char *filter;
657         int ret;
658
659         ldb = ldb_module_get_ctx(ac->module);
660
661         if (ac->sid == NULL)
662                 return LDB_ERR_OPERATIONS_ERROR;
663
664         filter = talloc_asprintf(ac, "(objectSid=%s)",
665                 ldap_encode_ndr_dom_sid(ac, ac->sid));
666         if (filter == NULL)
667                 return LDB_ERR_OPERATIONS_ERROR;
668
669         ret = ldb_build_search_req(&req, ldb, ac,
670                                 ldb_get_default_basedn(ldb),
671                                 LDB_SCOPE_SUBTREE,
672                                 filter, attrs,
673                                 NULL,
674                                 ac, samldb_dn_from_sid_callback,
675                                 ac->req);
676         if (ret != LDB_SUCCESS)
677                 return ret;
678
679         return ldb_next_request(ac->module, req);
680 }
681
682
683 static int samldb_check_primaryGroupID_1(struct samldb_ctx *ac)
684 {
685         struct ldb_context *ldb;
686         uint32_t rid;
687
688         ldb = ldb_module_get_ctx(ac->module);
689
690         rid = samdb_result_uint(ac->msg, "primaryGroupID", ~0);
691         ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
692         if (ac->sid == NULL)
693                 return LDB_ERR_OPERATIONS_ERROR;
694         ac->res_dn = NULL;
695
696         return samldb_next_step(ac);
697 }
698
699 static int samldb_check_primaryGroupID_2(struct samldb_ctx *ac)
700 {
701         if (ac->res_dn == NULL) {
702                 struct ldb_context *ldb;
703                 ldb = ldb_module_get_ctx(ac->module);
704                 ldb_asprintf_errstring(ldb,
705                                        "Failed to find group sid %s", 
706                                        dom_sid_string(ac->sid, ac->sid));
707                 return LDB_ERR_UNWILLING_TO_PERFORM;
708         }
709
710         return samldb_next_step(ac);
711 }
712
713
714 static bool samldb_msg_add_sid(struct ldb_message *msg,
715                                 const char *name,
716                                 const struct dom_sid *sid)
717 {
718         struct ldb_val v;
719         enum ndr_err_code ndr_err;
720
721         ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
722                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
723         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
724                 return false;
725         }
726         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
727 }
728
729 static int samldb_new_sid(struct samldb_ctx *ac)
730 {
731
732         if (ac->domain_sid == NULL || ac->next_rid == 0) {
733                 return LDB_ERR_OPERATIONS_ERROR;
734         }
735
736         ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
737         if (ac->sid == NULL) {
738                 return LDB_ERR_OPERATIONS_ERROR;
739         }
740
741         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
742                 return LDB_ERR_OPERATIONS_ERROR;
743         }
744
745         return samldb_next_step(ac);
746 }
747
748 /*
749  * samldb_notice_sid_callback (async)
750  */
751
752 static int samldb_notice_sid_callback(struct ldb_request *req,
753                                         struct ldb_reply *ares)
754 {
755         struct ldb_context *ldb;
756         struct samldb_ctx *ac;
757         int ret;
758
759         ac = talloc_get_type(req->context, struct samldb_ctx);
760         ldb = ldb_module_get_ctx(ac->module);
761
762         if (!ares) {
763                 ret = LDB_ERR_OPERATIONS_ERROR;
764                 goto done;
765         }
766         if (ares->error != LDB_SUCCESS) {
767                 return ldb_module_done(ac->req, ares->controls,
768                                         ares->response, ares->error);
769         }
770         if (ares->type != LDB_REPLY_DONE) {
771                 ldb_set_errstring(ldb,
772                         "Invalid reply type!\n");
773                 ret = LDB_ERR_OPERATIONS_ERROR;
774                 goto done;
775         }
776
777         ret = samldb_next_step(ac);
778
779 done:
780         if (ret != LDB_SUCCESS) {
781                 return ldb_module_done(ac->req, NULL, NULL, ret);
782         }
783
784         return LDB_SUCCESS;
785 }
786
787 /* If we are adding new users/groups, we need to update the nextRid
788  * attribute to be 'above' the new/incoming RID. Attempt to do it
789  * atomically. */
790 static int samldb_notice_sid(struct samldb_ctx *ac)
791 {
792         struct ldb_context *ldb;
793         uint32_t old_id, new_id;
794         struct ldb_request *req;
795         struct ldb_message *msg;
796         struct ldb_message_element *els;
797         struct ldb_val *vals;
798         int ret;
799
800         ldb = ldb_module_get_ctx(ac->module);
801         old_id = ac->next_rid;
802         new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
803
804         if (old_id >= new_id) {
805                 /* no need to update the domain nextRid attribute */
806                 return samldb_next_step(ac);
807         }
808
809         /* we do a delete and add as a single operation. That prevents
810            a race, in case we are not actually on a transaction db */
811         msg = ldb_msg_new(ac);
812         if (msg == NULL) {
813                 ldb_oom(ldb);
814                 return LDB_ERR_OPERATIONS_ERROR;
815         }
816         els = talloc_array(msg, struct ldb_message_element, 2);
817         if (els == NULL) {
818                 ldb_oom(ldb);
819                 return LDB_ERR_OPERATIONS_ERROR;
820         }
821         vals = talloc_array(msg, struct ldb_val, 2);
822         if (vals == NULL) {
823                 ldb_oom(ldb);
824                 return LDB_ERR_OPERATIONS_ERROR;
825         }
826         msg->dn = ac->domain_dn;
827         msg->num_elements = 2;
828         msg->elements = els;
829
830         els[0].num_values = 1;
831         els[0].values = &vals[0];
832         els[0].flags = LDB_FLAG_MOD_DELETE;
833         els[0].name = talloc_strdup(msg, "nextRid");
834         if (!els[0].name) {
835                 ldb_oom(ldb);
836                 return LDB_ERR_OPERATIONS_ERROR;
837         }
838
839         els[1].num_values = 1;
840         els[1].values = &vals[1];
841         els[1].flags = LDB_FLAG_MOD_ADD;
842         els[1].name = els[0].name;
843
844         vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
845         if (!vals[0].data) {
846                 ldb_oom(ldb);
847                 return LDB_ERR_OPERATIONS_ERROR;
848         }
849         vals[0].length = strlen((char *)vals[0].data);
850
851         vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
852         if (!vals[1].data) {
853                 ldb_oom(ldb);
854                 return LDB_ERR_OPERATIONS_ERROR;
855         }
856         vals[1].length = strlen((char *)vals[1].data);
857
858         ret = ldb_build_mod_req(&req, ldb, ac,
859                                 msg, NULL,
860                                 ac, samldb_notice_sid_callback,
861                                 ac->req);
862         if (ret != LDB_SUCCESS) {
863                 return ret;
864         }
865
866         return ldb_next_request(ac->module, req);
867 }
868
869 /*
870  * samldb_add_entry (async)
871  */
872
873 static int samldb_add_entry_callback(struct ldb_request *req,
874                                         struct ldb_reply *ares)
875 {
876         struct ldb_context *ldb;
877         struct samldb_ctx *ac;
878
879         ac = talloc_get_type(req->context, struct samldb_ctx);
880         ldb = ldb_module_get_ctx(ac->module);
881
882         if (!ares) {
883                 return ldb_module_done(ac->req, NULL, NULL,
884                                         LDB_ERR_OPERATIONS_ERROR);
885         }
886         if (ares->error != LDB_SUCCESS) {
887                 return ldb_module_done(ac->req, ares->controls,
888                                         ares->response, ares->error);
889         }
890         if (ares->type != LDB_REPLY_DONE) {
891                 ldb_set_errstring(ldb,
892                         "Invalid reply type!\n");
893                 return ldb_module_done(ac->req, NULL, NULL,
894                                         LDB_ERR_OPERATIONS_ERROR);
895         }
896
897         /* we exit the samldb module here */
898         return ldb_module_done(ac->req, ares->controls,
899                                 ares->response, LDB_SUCCESS);
900 }
901
902 static int samldb_add_entry(struct samldb_ctx *ac)
903 {
904         struct ldb_context *ldb;
905         struct ldb_request *req;
906         int ret;
907
908         ldb = ldb_module_get_ctx(ac->module);
909
910         ret = ldb_build_add_req(&req, ldb, ac,
911                                 ac->msg,
912                                 ac->req->controls,
913                                 ac, samldb_add_entry_callback,
914                                 ac->req);
915         if (ret != LDB_SUCCESS) {
916                 return ret;
917         }
918
919         return ldb_next_request(ac->module, req);
920 }
921
922
923 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
924 {
925         struct ldb_context *ldb;
926         int ret;
927
928         ldb = ldb_module_get_ctx(ac->module);
929
930         /* search for a parent domain objet */
931         ac->check_dn = ac->req->op.add.message->dn;
932         ret = samldb_add_step(ac, samldb_get_parent_domain);
933         if (ret != LDB_SUCCESS) return ret;
934
935         /* Add informations for the different account types */
936         ac->type = type;
937         if (strcmp(ac->type, "user") == 0) {
938                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
939                         "userAccountControl", "546");
940                 if (ret != LDB_SUCCESS) return ret;
941                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
942                         "badPwdCount", "0");
943                 if (ret != LDB_SUCCESS) return ret;
944                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
945                         "codePage", "0");
946                 if (ret != LDB_SUCCESS) return ret;
947                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
948                         "countryCode", "0");
949                 if (ret != LDB_SUCCESS) return ret;
950                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
951                         "badPasswordTime", "0");
952                 if (ret != LDB_SUCCESS) return ret;
953                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
954                         "lastLogoff", "0");
955                 if (ret != LDB_SUCCESS) return ret;
956                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
957                         "lastLogon", "0");
958                 if (ret != LDB_SUCCESS) return ret;
959                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
960                         "pwdLastSet", "0");
961                 if (ret != LDB_SUCCESS) return ret;
962                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
963                         "primaryGroupID", "513");
964                 if (ret != LDB_SUCCESS) return ret;
965                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
966                         "accountExpires", "9223372036854775807");
967                 if (ret != LDB_SUCCESS) return ret;
968                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
969                         "logonCount", "0");
970                 if (ret != LDB_SUCCESS) return ret;
971         } else if (strcmp(ac->type, "group") == 0) {
972                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
973                         "groupType", "-2147483646");
974                 if (ret != LDB_SUCCESS) return ret;
975         } else {
976                 /* we should only have "user" and "group" */
977                 ldb_asprintf_errstring(ldb,
978                         "Invalid entry type!\n");
979                 return LDB_ERR_OPERATIONS_ERROR;
980         }
981
982         /* check if we have a valid samAccountName */
983         ret = samldb_add_step(ac, samldb_check_samAccountName);
984         if (ret != LDB_SUCCESS) return ret;
985
986         /* check account_type/group_type */
987         ret = samldb_add_step(ac, samldb_check_samAccountType);
988         if (ret != LDB_SUCCESS) return ret;
989
990         /* check if we have a valid primary group ID */
991         if (strcmp(ac->type, "user") == 0) {
992                 ret = samldb_add_step(ac, samldb_check_primaryGroupID_1);
993                 if (ret != LDB_SUCCESS) return ret;
994                 ret = samldb_add_step(ac, samldb_dn_from_sid);
995                 if (ret != LDB_SUCCESS) return ret;
996                 ret = samldb_add_step(ac, samldb_check_primaryGroupID_2);
997                 if (ret != LDB_SUCCESS) return ret;
998         }
999
1000         /* check if we have a valid SID */
1001         ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1002         if ( ! ac->sid) {
1003                 ret = samldb_add_step(ac, samldb_new_sid);
1004                 if (ret != LDB_SUCCESS) return ret;
1005         } else {
1006                 ret = samldb_add_step(ac, samldb_get_sid_domain);
1007                 if (ret != LDB_SUCCESS) return ret;
1008         }
1009
1010         ret = samldb_add_step(ac, samldb_notice_sid);
1011         if (ret != LDB_SUCCESS) return ret;
1012
1013         /* finally proceed with adding the entry */
1014         ret = samldb_add_step(ac, samldb_add_entry);
1015         if (ret != LDB_SUCCESS) return ret;
1016
1017         return samldb_first_step(ac);
1018 }
1019
1020 /*
1021  * samldb_foreign_notice_sid (async)
1022  */
1023
1024 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1025                                                 struct ldb_reply *ares)
1026 {
1027         struct ldb_context *ldb;
1028         struct samldb_ctx *ac;
1029         const char *nextRid;
1030         const char *name;
1031         int ret;
1032
1033         ac = talloc_get_type(req->context, struct samldb_ctx);
1034         ldb = ldb_module_get_ctx(ac->module);
1035
1036         if (!ares) {
1037                 ret = LDB_ERR_OPERATIONS_ERROR;
1038                 goto done;
1039         }
1040         if (ares->error != LDB_SUCCESS) {
1041                 return ldb_module_done(ac->req, ares->controls,
1042                                         ares->response, ares->error);
1043         }
1044
1045         switch (ares->type) {
1046         case LDB_REPLY_ENTRY:
1047                 /* save entry */
1048                 if (ac->next_rid != 0) {
1049                         /* one too many! */
1050                         ldb_set_errstring(ldb,
1051                                 "Invalid number of results while searching "
1052                                 "for domain object!");
1053                         ret = LDB_ERR_OPERATIONS_ERROR;
1054                         break;
1055                 }
1056
1057                 nextRid = ldb_msg_find_attr_as_string(ares->message,
1058                                                         "nextRid", NULL);
1059                 if (nextRid == NULL) {
1060                         ldb_asprintf_errstring(ldb,
1061                                 "while looking for forign sid %s attribute nextRid not found in %s\n",
1062                                 dom_sid_string(ares, ac->sid),
1063                                         ldb_dn_get_linearized(ares->message->dn));
1064                         ret = LDB_ERR_OPERATIONS_ERROR;
1065                         break;
1066                 }
1067
1068                 ac->next_rid = strtol(nextRid, NULL, 0);
1069
1070                 ac->domain_dn = ldb_dn_copy(ac, ares->message->dn);
1071
1072                 name = samdb_result_string(ares->message, "name", NULL);
1073                 ldb_debug(ldb, LDB_DEBUG_TRACE,
1074                          "NOTE (strange but valid): Adding foreign SID "
1075                          "record with SID %s, but this domain (%s) is "
1076                          "not foreign in the database",
1077                          dom_sid_string(ares, ac->sid), name);
1078
1079                 talloc_free(ares);
1080                 ret = LDB_SUCCESS;
1081                 break;
1082
1083         case LDB_REPLY_REFERRAL:
1084                 /* ignore */
1085                 talloc_free(ares);
1086                 ret = LDB_SUCCESS;
1087                 break;
1088
1089         case LDB_REPLY_DONE:
1090                 talloc_free(ares);
1091
1092                 /* if this is a fake foreign SID, notice the SID */
1093                 if (ac->domain_dn) {
1094                         ret = samldb_notice_sid(ac);
1095                         break;
1096                 }
1097
1098                 /* found, go on */
1099                 ret = samldb_next_step(ac);
1100                 break;
1101         }
1102
1103 done:
1104         if (ret != LDB_SUCCESS) {
1105                 return ldb_module_done(ac->req, NULL, NULL, ret);
1106         }
1107
1108         return LDB_SUCCESS;
1109 }
1110
1111 /* Find a domain object in the parents of a particular DN. */
1112 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1113 {
1114         struct ldb_context *ldb;
1115         static const char * const attrs[3] = { "nextRid", "name", NULL };
1116         struct ldb_request *req;
1117         NTSTATUS status;
1118         char *filter;
1119         int ret;
1120
1121         ldb = ldb_module_get_ctx(ac->module);
1122
1123         if (ac->sid == NULL) {
1124                 return LDB_ERR_OPERATIONS_ERROR;
1125         }
1126
1127         status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1128         if (!NT_STATUS_IS_OK(status)) {
1129                 return LDB_ERR_OPERATIONS_ERROR;
1130         }
1131
1132         filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1133                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1134         if (filter == NULL) {
1135                 return LDB_ERR_OPERATIONS_ERROR;
1136         }
1137
1138         ret = ldb_build_search_req(&req, ldb, ac,
1139                                    ldb_get_default_basedn(ldb),
1140                                    LDB_SCOPE_SUBTREE,
1141                                    filter, attrs,
1142                                    NULL,
1143                                    ac, samldb_foreign_notice_sid_callback,
1144                                    ac->req);
1145
1146         if (ret != LDB_SUCCESS) {
1147                 return ret;
1148         }
1149
1150         return ldb_next_request(ac->module, req);
1151 }
1152
1153
1154 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1155 {
1156         struct ldb_context *ldb;
1157         int ret;
1158
1159         ldb = ldb_module_get_ctx(ac->module);
1160
1161         ac->next_rid = 0;
1162
1163         ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1164         if (ac->sid == NULL) {
1165                 ac->sid = dom_sid_parse_talloc(ac->msg,
1166                            (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1167                 if (!ac->sid) {
1168                         ldb_set_errstring(ldb,
1169                                         "No valid SID found in "
1170                                         "ForeignSecurityPrincipal CN!");
1171                         talloc_free(ac);
1172                         return LDB_ERR_CONSTRAINT_VIOLATION;
1173                 }
1174                 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1175                         talloc_free(ac);
1176                         return LDB_ERR_OPERATIONS_ERROR;
1177                 }
1178         }
1179
1180         /* check if we need to notice this SID */
1181         ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1182         if (ret != LDB_SUCCESS) return ret;
1183
1184         /* finally proceed with adding the entry */
1185         ret = samldb_add_step(ac, samldb_add_entry);
1186         if (ret != LDB_SUCCESS) return ret;
1187
1188         return samldb_first_step(ac);
1189 }
1190
1191 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1192 {
1193         struct ldb_context *ldb;
1194         const char *rdn_name;
1195
1196         ldb = ldb_module_get_ctx(module);
1197         rdn_name = ldb_dn_get_rdn_name(dn);
1198
1199         if (strcasecmp(rdn_name, "cn") != 0) {
1200                 ldb_asprintf_errstring(ldb,
1201                                         "Bad RDN (%s=) for samldb object, "
1202                                         "should be CN=!\n", rdn_name);
1203                 return LDB_ERR_CONSTRAINT_VIOLATION;
1204         }
1205
1206         return LDB_SUCCESS;
1207 }
1208
1209 /*
1210  * samldb_sid_from_dn (async)
1211  */
1212
1213 static int samldb_sid_from_dn(struct samldb_ctx *ac);
1214
1215 static int samldb_sid_from_dn_callback(struct ldb_request *req,
1216         struct ldb_reply *ares)
1217 {
1218         struct ldb_context *ldb;
1219         struct samldb_ctx *ac;
1220         int ret;
1221
1222         ac = talloc_get_type(req->context, struct samldb_ctx);
1223         ldb = ldb_module_get_ctx(ac->module);
1224
1225         if (!ares) {
1226                 ret = LDB_ERR_OPERATIONS_ERROR;
1227                 goto done;
1228         }
1229         if (ares->error != LDB_SUCCESS) {
1230                 return ldb_module_done(ac->req, ares->controls,
1231                                         ares->response, ares->error);
1232         }
1233
1234         switch (ares->type) {
1235         case LDB_REPLY_ENTRY:
1236                 /* save entry */
1237                 if (ac->res_sid != NULL) {
1238                         /* one too many! */
1239                         ldb_set_errstring(ldb,
1240                                 "Invalid number of results while searching "
1241                                 "for domain objects!");
1242                         ret = LDB_ERR_OPERATIONS_ERROR;
1243                         break;
1244                 }
1245                 ac->res_sid = samdb_result_dom_sid(ac, ares->message,
1246                         "objectSid");
1247
1248                 talloc_free(ares);
1249                 ret = LDB_SUCCESS;
1250                 break;
1251
1252         case LDB_REPLY_REFERRAL:
1253                 /* ignore */
1254                 talloc_free(ares);
1255                 ret = LDB_SUCCESS;
1256                 break;
1257
1258         case LDB_REPLY_DONE:
1259                 talloc_free(ares);
1260
1261                 /* found or not found, go on */
1262                 ret = samldb_next_step(ac);
1263                 break;
1264         }
1265
1266 done:
1267         if (ret != LDB_SUCCESS) {
1268                 return ldb_module_done(ac->req, NULL, NULL, ret);
1269         }
1270
1271         return LDB_SUCCESS;
1272 }
1273
1274 /* Finds the SID "res_sid" of an object with a given DN "dn" */
1275 static int samldb_sid_from_dn(struct samldb_ctx *ac)
1276 {
1277         struct ldb_context *ldb;
1278         static const char * const attrs[] = { "objectSid" };
1279         struct ldb_request *req;
1280         int ret;
1281
1282         ldb = ldb_module_get_ctx(ac->module);
1283
1284         if (ac->dn == NULL)
1285                 return LDB_ERR_OPERATIONS_ERROR;
1286
1287         ret = ldb_build_search_req(&req, ldb, ac,
1288                                 ac->dn,
1289                                 LDB_SCOPE_BASE,
1290                                 NULL, attrs,
1291                                 NULL,
1292                                 ac, samldb_sid_from_dn_callback,
1293                                 ac->req);
1294         if (ret != LDB_SUCCESS)
1295                 return ret;
1296
1297         return ldb_next_request(ac->module, req);
1298 }
1299
1300 /*
1301  * samldb_user_dn_to_prim_group_rid (async)
1302  */
1303
1304 static int samldb_user_dn_to_prim_group_rid(struct samldb_ctx *ac);
1305
1306 static int samldb_user_dn_to_prim_group_rid_callback(struct ldb_request *req,
1307         struct ldb_reply *ares)
1308 {
1309         struct ldb_context *ldb;
1310         struct samldb_ctx *ac;
1311         int ret;
1312
1313         ac = talloc_get_type(req->context, struct samldb_ctx);
1314         ldb = ldb_module_get_ctx(ac->module);
1315
1316         if (!ares) {
1317                 ret = LDB_ERR_OPERATIONS_ERROR;
1318                 goto done;
1319         }
1320         if (ares->error != LDB_SUCCESS) {
1321                 return ldb_module_done(ac->req, ares->controls,
1322                                         ares->response, ares->error);
1323         }
1324
1325         switch (ares->type) {
1326         case LDB_REPLY_ENTRY:
1327                 /* save entry */
1328                 if (ac->prim_group_rid != 0) {
1329                         /* one too many! */
1330                         ldb_set_errstring(ldb,
1331                                 "Invalid number of results while searching "
1332                                 "for domain objects!");
1333                         ret = LDB_ERR_OPERATIONS_ERROR;
1334                         break;
1335                 }
1336                 ac->prim_group_rid = samdb_result_uint(ares->message,
1337                         "primaryGroupID", ~0);
1338
1339                 talloc_free(ares);
1340                 ret = LDB_SUCCESS;
1341                 break;
1342
1343         case LDB_REPLY_REFERRAL:
1344                 /* ignore */
1345                 talloc_free(ares);
1346                 ret = LDB_SUCCESS;
1347                 break;
1348
1349         case LDB_REPLY_DONE:
1350                 talloc_free(ares);
1351                 if (ac->prim_group_rid == 0) {
1352                         ldb_asprintf_errstring(ldb,
1353                                 "Unable to get the primary group RID!\n");
1354                         ret = LDB_ERR_OPERATIONS_ERROR;
1355                         break;
1356                 }
1357
1358                 /* found, go on */
1359                 ret = samldb_next_step(ac);
1360                 break;
1361         }
1362
1363 done:
1364         if (ret != LDB_SUCCESS) {
1365                 return ldb_module_done(ac->req, NULL, NULL, ret);
1366         }
1367
1368         return LDB_SUCCESS;
1369 }
1370
1371 /* Locates the "primaryGroupID" attribute from a certain user specified as
1372  * "user_dn". Saves the result in "prim_group_rid". */
1373 static int samldb_user_dn_to_prim_group_rid(struct samldb_ctx *ac)
1374 {
1375         struct ldb_context *ldb;
1376         static const char * const attrs[] = { "primaryGroupID", NULL };
1377         struct ldb_request *req;
1378         int ret;
1379
1380         ldb = ldb_module_get_ctx(ac->module);
1381
1382         if (ac->user_dn == NULL)
1383                 return LDB_ERR_OPERATIONS_ERROR;
1384
1385         ret = ldb_build_search_req(&req, ldb, ac,
1386                                 ac->user_dn,
1387                                 LDB_SCOPE_BASE,
1388                                 NULL, attrs,
1389                                 NULL,
1390                                 ac, samldb_user_dn_to_prim_group_rid_callback,
1391                                 ac->req);
1392         if (ret != LDB_SUCCESS)
1393                 return ret;
1394
1395         return ldb_next_request(ac->module, req);
1396 }
1397
1398 /*
1399  * samldb_prim_group_rid_to_users_cnt (async)
1400  */
1401
1402 static int samldb_prim_group_rid_to_users_cnt(struct samldb_ctx *ac);
1403
1404 static int samldb_prim_group_rid_to_users_cnt_callback(struct ldb_request *req,
1405         struct ldb_reply *ares)
1406 {
1407         struct ldb_context *ldb;
1408         struct samldb_ctx *ac;
1409         int ret;
1410
1411         ac = talloc_get_type(req->context, struct samldb_ctx);
1412         ldb = ldb_module_get_ctx(ac->module);
1413
1414         if (!ares) {
1415                 ret = LDB_ERR_OPERATIONS_ERROR;
1416                 goto done;
1417         }
1418         if (ares->error != LDB_SUCCESS) {
1419                 return ldb_module_done(ac->req, ares->controls,
1420                                         ares->response, ares->error);
1421         }
1422
1423         switch (ares->type) {
1424         case LDB_REPLY_ENTRY:
1425                 /* save entry */
1426                 ++(ac->users_cnt);
1427
1428                 talloc_free(ares);
1429                 ret = LDB_SUCCESS;
1430                 break;
1431
1432         case LDB_REPLY_REFERRAL:
1433                 /* ignore */
1434                 talloc_free(ares);
1435                 ret = LDB_SUCCESS;
1436                 break;
1437
1438         case LDB_REPLY_DONE:
1439                 talloc_free(ares);
1440
1441                 /* found or not found, go on */
1442                 ret = samldb_next_step(ac);
1443                 break;
1444         }
1445
1446 done:
1447         if (ret != LDB_SUCCESS) {
1448                 return ldb_module_done(ac->req, NULL, NULL, ret);
1449         }
1450
1451         return LDB_SUCCESS;
1452 }
1453
1454 /* Finds the amount of users which have the primary group "prim_group_rid" and
1455  * save the result in "users_cnt" */
1456 static int samldb_prim_group_rid_to_users_cnt(struct samldb_ctx *ac)
1457 {
1458         struct ldb_context *ldb;
1459         static const char * const attrs[] = { NULL };
1460         struct ldb_request *req;
1461         char *filter;
1462         int ret;
1463
1464         ldb = ldb_module_get_ctx(ac->module);
1465
1466         if ((ac->prim_group_rid == 0) || (ac->users_cnt != 0))
1467                 return LDB_ERR_OPERATIONS_ERROR;
1468
1469         filter = talloc_asprintf(ac, "(&(primaryGroupID=%u)(objectclass=user))",
1470                 ac->prim_group_rid);
1471         if (filter == NULL)
1472                 return LDB_ERR_OPERATIONS_ERROR;
1473
1474         ret = ldb_build_search_req(&req, ldb, ac,
1475                                 ldb_get_default_basedn(ldb),
1476                                 LDB_SCOPE_SUBTREE,
1477                                 filter, attrs,
1478                                 NULL,
1479                                 ac,
1480                                 samldb_prim_group_rid_to_users_cnt_callback,
1481                                 ac->req);
1482         if (ret != LDB_SUCCESS)
1483                 return ret;
1484
1485         return ldb_next_request(ac->module, req);
1486 }
1487
1488 /*
1489  * samldb_group_add_member (async)
1490  * samldb_group_del_member (async)
1491  */
1492
1493 static int samldb_group_add_del_member_callback(struct ldb_request *req,
1494         struct ldb_reply *ares)
1495 {
1496         struct ldb_context *ldb;
1497         struct samldb_ctx *ac;
1498         int ret;
1499
1500         ac = talloc_get_type(req->context, struct samldb_ctx);
1501         ldb = ldb_module_get_ctx(ac->module);
1502
1503         if (!ares) {
1504                 ret = LDB_ERR_OPERATIONS_ERROR;
1505                 goto done;
1506         }
1507         if (ares->error != LDB_SUCCESS) {
1508                 if (ares->error == LDB_ERR_NO_SUCH_ATTRIBUTE) {
1509                         /* On error "NO_SUCH_ATTRIBUTE" (delete of an invalid
1510                          * "member" attribute) return "UNWILLING_TO_PERFORM" */
1511                         ares->error = LDB_ERR_UNWILLING_TO_PERFORM;
1512                 }
1513                 return ldb_module_done(ac->req, ares->controls,
1514                                         ares->response, ares->error);
1515         }
1516         if (ares->type != LDB_REPLY_DONE) {
1517                 ldb_set_errstring(ldb,
1518                         "Invalid reply type!\n");
1519                 ret = LDB_ERR_OPERATIONS_ERROR;
1520                 goto done;
1521         }
1522
1523         ret = samldb_next_step(ac);
1524
1525 done:
1526         if (ret != LDB_SUCCESS) {
1527                 return ldb_module_done(ac->req, NULL, NULL, ret);
1528         }
1529
1530         return LDB_SUCCESS;
1531 }
1532
1533 /* Adds a member with DN "member_dn" to a group with DN "group_dn" */
1534 static int samldb_group_add_member(struct samldb_ctx *ac)
1535 {
1536         struct ldb_context *ldb;
1537         struct ldb_request *req;
1538         struct ldb_message *msg;
1539         int ret;
1540
1541         ldb = ldb_module_get_ctx(ac->module);
1542
1543         if ((ac->group_dn == NULL) || (ac->member_dn == NULL))
1544                 return LDB_ERR_OPERATIONS_ERROR;
1545
1546         msg = ldb_msg_new(ac);
1547         msg->dn = ac->group_dn;
1548         samdb_msg_add_addval(ldb, ac, msg, "member",
1549                 ldb_dn_get_linearized(ac->member_dn));
1550
1551         ret = ldb_build_mod_req(&req, ldb, ac,
1552                                 msg, NULL,
1553                                 ac, samldb_group_add_del_member_callback,
1554                                 ac->req);
1555         if (ret != LDB_SUCCESS)
1556                 return ret;
1557
1558         return ldb_next_request(ac->module, req);
1559 }
1560
1561 /* Removes a member with DN "member_dn" from a group with DN "group_dn" */
1562 static int samldb_group_del_member(struct samldb_ctx *ac)
1563 {
1564         struct ldb_context *ldb;
1565         struct ldb_request *req;
1566         struct ldb_message *msg;
1567         int ret;
1568
1569         ldb = ldb_module_get_ctx(ac->module);
1570
1571         if ((ac->group_dn == NULL) || (ac->member_dn == NULL))
1572                 return LDB_ERR_OPERATIONS_ERROR;
1573
1574         msg = ldb_msg_new(ac);
1575         msg->dn = ac->group_dn;
1576         samdb_msg_add_delval(ldb, ac, msg, "member",
1577                 ldb_dn_get_linearized(ac->member_dn));
1578
1579         ret = ldb_build_mod_req(&req, ldb, ac,
1580                                 msg, NULL,
1581                                 ac, samldb_group_add_del_member_callback,
1582                                 ac->req);
1583         if (ret != LDB_SUCCESS)
1584                 return ret;
1585
1586         return ldb_next_request(ac->module, req);
1587 }
1588
1589
1590 static int samldb_prim_group_change_1(struct samldb_ctx *ac)
1591 {
1592         struct ldb_context *ldb;
1593         uint32_t rid;
1594
1595         ldb = ldb_module_get_ctx(ac->module);
1596
1597         ac->user_dn = ac->msg->dn;
1598
1599         rid = samdb_result_uint(ac->msg, "primaryGroupID", ~0);
1600         ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
1601         if (ac->sid == NULL)
1602                 return LDB_ERR_OPERATIONS_ERROR;
1603         ac->res_dn = NULL;
1604
1605         ac->prim_group_rid = 0;
1606
1607         return samldb_next_step(ac);
1608 }
1609
1610 static int samldb_prim_group_change_2(struct samldb_ctx *ac)
1611 {
1612         struct ldb_context *ldb;
1613
1614         ldb = ldb_module_get_ctx(ac->module);
1615
1616         if (ac->res_dn != NULL)
1617                 ac->new_prim_group_dn = ac->res_dn;
1618         else
1619                 return LDB_ERR_UNWILLING_TO_PERFORM;
1620
1621         ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
1622                 ac->prim_group_rid);
1623         if (ac->sid == NULL)
1624                 return LDB_ERR_OPERATIONS_ERROR;
1625         ac->res_dn = NULL;
1626
1627         return samldb_next_step(ac);
1628 }
1629
1630 static int samldb_prim_group_change_4(struct samldb_ctx *ac);
1631 static int samldb_prim_group_change_5(struct samldb_ctx *ac);
1632 static int samldb_prim_group_change_6(struct samldb_ctx *ac);
1633
1634 static int samldb_prim_group_change_3(struct samldb_ctx *ac)
1635 {
1636         int ret;
1637
1638         if (ac->res_dn != NULL)
1639                 ac->old_prim_group_dn = ac->res_dn;
1640         else
1641                 return LDB_ERR_UNWILLING_TO_PERFORM;
1642
1643         /* Only update when the primary group changed */
1644         if (ldb_dn_compare(ac->old_prim_group_dn, ac->new_prim_group_dn) != 0) {
1645                 ac->member_dn = ac->user_dn;
1646                 /* Remove the "member" attribute of the actual (new) primary
1647                  * group */
1648
1649                 ret = samldb_add_step(ac, samldb_prim_group_change_4);
1650                 if (ret != LDB_SUCCESS) return ret;
1651
1652                 ret = samldb_add_step(ac, samldb_group_del_member);
1653                 if (ret != LDB_SUCCESS) return ret;
1654
1655                 /* Add a "member" attribute for the previous primary group */
1656
1657                 ret = samldb_add_step(ac, samldb_prim_group_change_5);
1658                 if (ret != LDB_SUCCESS) return ret;
1659
1660                 ret = samldb_add_step(ac, samldb_group_add_member);
1661                 if (ret != LDB_SUCCESS) return ret;
1662         }
1663
1664         ret = samldb_add_step(ac, samldb_prim_group_change_6);
1665         if (ret != LDB_SUCCESS) return ret;
1666
1667         return samldb_next_step(ac);
1668 }
1669
1670 static int samldb_prim_group_change_4(struct samldb_ctx *ac)
1671 {
1672         ac->group_dn = ac->new_prim_group_dn;
1673
1674         return samldb_next_step(ac);
1675 }
1676
1677 static int samldb_prim_group_change_5(struct samldb_ctx *ac)
1678 {
1679         ac->group_dn = ac->old_prim_group_dn;
1680
1681         return samldb_next_step(ac);
1682 }
1683
1684 static int samldb_prim_group_change_6(struct samldb_ctx *ac)
1685 {
1686         return ldb_next_request(ac->module, ac->req);
1687 }
1688
1689 static int samldb_prim_group_change(struct samldb_ctx *ac)
1690 {
1691         int ret;
1692
1693         /* Finds out the DN of the new primary group */
1694
1695         ret = samldb_add_step(ac, samldb_prim_group_change_1);
1696         if (ret != LDB_SUCCESS) return ret;
1697
1698         ret = samldb_add_step(ac, samldb_dn_from_sid);
1699         if (ret != LDB_SUCCESS) return ret;
1700
1701         ret = samldb_add_step(ac, samldb_user_dn_to_prim_group_rid);
1702         if (ret != LDB_SUCCESS) return ret;
1703
1704         /* Finds out the DN of the old primary group */
1705
1706         ret = samldb_add_step(ac, samldb_prim_group_change_2);
1707         if (ret != LDB_SUCCESS) return ret;
1708
1709         ret = samldb_add_step(ac, samldb_dn_from_sid);
1710         if (ret != LDB_SUCCESS) return ret;
1711
1712         ret = samldb_add_step(ac, samldb_prim_group_change_3);
1713         if (ret != LDB_SUCCESS) return ret;
1714
1715         return samldb_first_step(ac);
1716 }
1717
1718
1719 static int samldb_member_check_1(struct samldb_ctx *ac)
1720 {
1721         struct ldb_context *ldb;
1722         struct ldb_message_element *el;
1723
1724         ldb = ldb_module_get_ctx(ac->module);
1725
1726         el = ldb_msg_find_element(ac->msg, "member");
1727
1728         ac->user_dn = ldb_dn_from_ldb_val(ac, ldb, &el->values[ac->cnt]);
1729         if (!ldb_dn_validate(ac->user_dn))
1730                 return LDB_ERR_OPERATIONS_ERROR;
1731         ac->prim_group_rid = 0;
1732
1733         return samldb_next_step(ac);
1734 }
1735
1736 static int samldb_member_check_2(struct samldb_ctx *ac)
1737 {
1738         struct ldb_context *ldb;
1739
1740         ldb = ldb_module_get_ctx(ac->module);
1741
1742         ac->sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
1743                 ac->prim_group_rid);
1744         if (ac->sid == NULL)
1745                 return LDB_ERR_OPERATIONS_ERROR;
1746         ac->res_dn = NULL;
1747
1748         return samldb_next_step(ac);
1749 }
1750
1751 static int samldb_member_check_3(struct samldb_ctx *ac)
1752 {
1753         if (ldb_dn_compare(ac->res_dn, ac->msg->dn) == 0)
1754                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
1755
1756         ++(ac->cnt);
1757
1758         return samldb_next_step(ac);
1759 }
1760
1761 static int samldb_member_check_4(struct samldb_ctx *ac)
1762 {
1763         return ldb_next_request(ac->module, ac->req);
1764 }
1765
1766 static int samldb_member_check(struct samldb_ctx *ac)
1767 {
1768         struct ldb_message_element *el;
1769         int i, ret;
1770
1771         el = ldb_msg_find_element(ac->msg, "member");
1772         ac->cnt = 0;
1773         for (i = 0; i < el->num_values; i++) {
1774                 /* Denies to add "member"s to groups which are primary ones
1775                  * for them */
1776                 ret = samldb_add_step(ac, samldb_member_check_1);
1777                 if (ret != LDB_SUCCESS) return ret;
1778
1779                 ret = samldb_add_step(ac, samldb_user_dn_to_prim_group_rid);
1780                 if (ret != LDB_SUCCESS) return ret;
1781
1782                 ret = samldb_add_step(ac, samldb_member_check_2);
1783                 if (ret != LDB_SUCCESS) return ret;
1784
1785                 ret = samldb_add_step(ac, samldb_dn_from_sid);
1786                 if (ret != LDB_SUCCESS) return ret;
1787
1788                 ret = samldb_add_step(ac, samldb_member_check_3);
1789                 if (ret != LDB_SUCCESS) return ret;
1790         }
1791
1792         ret = samldb_add_step(ac, samldb_member_check_4);
1793         if (ret != LDB_SUCCESS) return ret;
1794
1795         return samldb_first_step(ac);
1796 }
1797
1798
1799 static int samldb_prim_group_users_check_1(struct samldb_ctx *ac)
1800 {
1801         ac->dn = ac->req->op.del.dn;
1802         ac->res_sid = NULL;
1803
1804         return samldb_next_step(ac);
1805 }
1806
1807 static int samldb_prim_group_users_check_2(struct samldb_ctx *ac)
1808 {
1809         NTSTATUS status;
1810         uint32_t rid;
1811
1812         if (ac->res_sid == NULL) {
1813                 /* No SID - therefore ok here */
1814                 return ldb_next_request(ac->module, ac->req);
1815         }
1816         status = dom_sid_split_rid(ac, ac->res_sid, NULL, &rid);
1817         if (!NT_STATUS_IS_OK(status))
1818                 return LDB_ERR_OPERATIONS_ERROR;
1819
1820         if (rid == 0) {
1821                 /* Special object (security principal?) */
1822                 return ldb_next_request(ac->module, ac->req);
1823         }
1824
1825         ac->prim_group_rid = rid;
1826         ac->users_cnt = 0;
1827
1828         return samldb_next_step(ac);
1829 }
1830
1831 static int samldb_prim_group_users_check_3(struct samldb_ctx *ac)
1832 {
1833         if (ac->users_cnt > 0)
1834                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
1835
1836         return ldb_next_request(ac->module, ac->req);
1837 }
1838
1839 static int samldb_prim_group_users_check(struct samldb_ctx *ac)
1840 {
1841         int ret;
1842
1843         /* Finds out the SID/RID of the domain object */
1844
1845         ret = samldb_add_step(ac, samldb_prim_group_users_check_1);
1846         if (ret != LDB_SUCCESS) return ret;
1847
1848         ret = samldb_add_step(ac, samldb_sid_from_dn);
1849         if (ret != LDB_SUCCESS) return ret;
1850
1851         /* Deny delete requests from groups which are primary ones */
1852
1853         ret = samldb_add_step(ac, samldb_prim_group_users_check_2);
1854         if (ret != LDB_SUCCESS) return ret;
1855
1856         ret = samldb_add_step(ac, samldb_prim_group_rid_to_users_cnt);
1857         if (ret != LDB_SUCCESS) return ret;
1858
1859         ret = samldb_add_step(ac, samldb_prim_group_users_check_3);
1860         if (ret != LDB_SUCCESS) return ret;
1861
1862         return samldb_first_step(ac);
1863 }
1864
1865
1866 /* add */
1867 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1868 {
1869         struct ldb_context *ldb;
1870         struct samldb_ctx *ac;
1871         int ret;
1872
1873         ldb = ldb_module_get_ctx(module);
1874         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
1875
1876         /* do not manipulate our control entries */
1877         if (ldb_dn_is_special(req->op.add.message->dn)) {
1878                 return ldb_next_request(module, req);
1879         }
1880
1881         ac = samldb_ctx_init(module, req);
1882         if (ac == NULL) {
1883                 return LDB_ERR_OPERATIONS_ERROR;
1884         }
1885
1886         /* build the new msg */
1887         ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1888         if (!ac->msg) {
1889                 talloc_free(ac);
1890                 ldb_debug(ldb, LDB_DEBUG_FATAL,
1891                           "samldb_add: ldb_msg_copy failed!\n");
1892                 return LDB_ERR_OPERATIONS_ERROR;
1893         }
1894
1895         if (samdb_find_attribute(ldb, ac->msg,
1896                                  "objectclass", "computer") != NULL) {
1897
1898                 /* make sure the computer object also has the 'user'
1899                  * objectclass so it will be handled by the next call */
1900                 ret = samdb_find_or_add_value(ldb, ac->msg,
1901                                                 "objectclass", "user");
1902                 if (ret != LDB_SUCCESS) {
1903                         talloc_free(ac);
1904                         return ret;
1905                 }
1906         }
1907
1908         if (samdb_find_attribute(ldb, ac->msg,
1909                                  "objectclass", "user") != NULL) {
1910
1911                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1912                 if (ret != LDB_SUCCESS) {
1913                         talloc_free(ac);
1914                         return ret;
1915                 }
1916
1917                 return samldb_fill_object(ac, "user");
1918         }
1919
1920         if (samdb_find_attribute(ldb, ac->msg,
1921                                  "objectclass", "group") != NULL) {
1922
1923                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1924                 if (ret != LDB_SUCCESS) {
1925                         talloc_free(ac);
1926                         return ret;
1927                 }
1928
1929                 return samldb_fill_object(ac, "group");
1930         }
1931
1932         /* perhaps a foreignSecurityPrincipal? */
1933         if (samdb_find_attribute(ldb, ac->msg,
1934                                  "objectclass",
1935                                  "foreignSecurityPrincipal") != NULL) {
1936
1937                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1938                 if (ret != LDB_SUCCESS) {
1939                         talloc_free(ac);
1940                         return ret;
1941                 }
1942
1943                 return samldb_fill_foreignSecurityPrincipal_object(ac);
1944         }
1945
1946         talloc_free(ac);
1947
1948         /* nothing matched, go on */
1949         return ldb_next_request(module, req);
1950 }
1951
1952 /* modify */
1953 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1954 {
1955         struct ldb_context *ldb;
1956         struct ldb_message *msg;
1957         struct ldb_message_element *el, *el2;
1958         int ret;
1959         uint32_t account_type;
1960
1961         if (ldb_dn_is_special(req->op.mod.message->dn)) {
1962                 /* do not manipulate our control entries */
1963                 return ldb_next_request(module, req);
1964         }
1965
1966         ldb = ldb_module_get_ctx(module);
1967
1968         if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1969                 ldb_asprintf_errstring(ldb,
1970                         "sAMAccountType must not be specified!");
1971                 return LDB_ERR_UNWILLING_TO_PERFORM;
1972         }
1973
1974         /* TODO: do not modify original request, create a new one */
1975
1976         el = ldb_msg_find_element(req->op.mod.message, "groupType");
1977         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1978                 uint32_t group_type;
1979
1980                 req->op.mod.message = msg = ldb_msg_copy_shallow(req,
1981                         req->op.mod.message);
1982
1983                 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1984                 account_type =  ds_gtype2atype(group_type);
1985                 ret = samdb_msg_add_uint(ldb, msg, msg,
1986                                          "sAMAccountType",
1987                                          account_type);
1988                 if (ret != LDB_SUCCESS) {
1989                         return ret;
1990                 }
1991                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1992                 el2->flags = LDB_FLAG_MOD_REPLACE;
1993         }
1994
1995         el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1996         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1997                 uint32_t user_account_control;
1998
1999                 req->op.mod.message = msg = ldb_msg_copy_shallow(req,
2000                         req->op.mod.message);
2001
2002                 user_account_control = strtoul((const char *)el->values[0].data,
2003                         NULL, 0);
2004                 account_type = ds_uf2atype(user_account_control);
2005                 ret = samdb_msg_add_uint(ldb, msg, msg,
2006                                          "sAMAccountType",
2007                                          account_type);
2008                 if (ret != LDB_SUCCESS) {
2009                         return ret;
2010                 }
2011                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
2012                 el2->flags = LDB_FLAG_MOD_REPLACE;
2013
2014                 if (user_account_control & UF_SERVER_TRUST_ACCOUNT) {
2015                         ret = samdb_msg_add_string(ldb, msg, msg,
2016                                                    "isCriticalSystemObject", "TRUE");
2017                         if (ret != LDB_SUCCESS) {
2018                                 return ret;
2019                         }
2020                         el2 = ldb_msg_find_element(msg, "isCriticalSystemObject");
2021                         el2->flags = LDB_FLAG_MOD_REPLACE;
2022                 }
2023         }
2024
2025         el = ldb_msg_find_element(req->op.mod.message, "primaryGroupID");
2026         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
2027                 struct samldb_ctx *ac;
2028
2029                 ac = samldb_ctx_init(module, req);
2030                 if (ac == NULL)
2031                         return LDB_ERR_OPERATIONS_ERROR;
2032
2033                 req->op.mod.message = ac->msg = ldb_msg_copy_shallow(req,
2034                         req->op.mod.message);
2035
2036                 return samldb_prim_group_change(ac);
2037         }
2038
2039         el = ldb_msg_find_element(req->op.mod.message, "member");
2040         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
2041                 struct samldb_ctx *ac;
2042
2043                 ac = samldb_ctx_init(module, req);
2044                 if (ac == NULL)
2045                         return LDB_ERR_OPERATIONS_ERROR;
2046
2047                 req->op.mod.message = ac->msg = ldb_msg_copy_shallow(req,
2048                         req->op.mod.message);
2049
2050                 return samldb_member_check(ac);
2051         }
2052
2053         /* nothing matched, go on */
2054         return ldb_next_request(module, req);
2055 }
2056
2057 /* delete */
2058 static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
2059 {
2060         struct samldb_ctx *ac;
2061
2062         if (ldb_dn_is_special(req->op.del.dn)) {
2063                 /* do not manipulate our control entries */
2064                 return ldb_next_request(module, req);
2065         }
2066
2067         ac = samldb_ctx_init(module, req);
2068         if (ac == NULL)
2069                 return LDB_ERR_OPERATIONS_ERROR;
2070
2071         return samldb_prim_group_users_check(ac);
2072 }
2073
2074
2075 static int samldb_init(struct ldb_module *module)
2076 {
2077         return ldb_next_init(module);
2078 }
2079
2080 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
2081         .name          = "samldb",
2082         .init_context  = samldb_init,
2083         .add           = samldb_add,
2084         .modify        = samldb_modify,
2085         .del           = samldb_delete
2086 };