LDB ASYNC: samba4 modules
[samba.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
7    * NOTICE: this module is NOT released under the GNU LGPL license as
8    * other ldb code. This module is release under the GNU GPL v3 or
9    * later license.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
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 "libcli/ldap/ldap_ndr.h"
37 #include "lib/ldb/include/ldb_errors.h"
38 #include "lib/ldb/include/ldb.h"
39 #include "lib/ldb/include/ldb_private.h"
40 #include "lib/events/events.h"
41 #include "dsdb/samdb/samdb.h"
42 #include "libcli/security/security.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44 #include "util/util_ldb.h"
45 #include "ldb_wrap.h"
46
47 struct samldb_ctx;
48
49 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
50
51 struct samldb_step {
52         struct samldb_step *next;
53         samldb_step_fn_t fn;
54 };
55
56 struct samldb_ctx {
57         struct ldb_module *module;
58         struct ldb_request *req;
59
60         /* the resulting message */
61         struct ldb_message *msg;
62
63         /* used to apply templates */
64         const char *type;
65
66         /* used to find parent domain */
67         struct ldb_dn *check_dn;
68         struct ldb_dn *domain_dn;
69         struct dom_sid *domain_sid;
70         uint32_t next_rid;
71
72         /* generic storage, remember to zero it before use */
73         struct ldb_reply *ares;
74
75         /* holds the entry SID */
76         struct dom_sid *sid;
77
78         /* all the async steps necessary to complete the operation */
79         struct samldb_step *steps;
80         struct samldb_step *curstep;
81 };
82
83 struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
84                                    struct ldb_request *req)
85 {
86         struct samldb_ctx *ac;
87
88         ac = talloc_zero(req, struct samldb_ctx);
89         if (ac == NULL) {
90                 ldb_oom(module->ldb);
91                 return NULL;
92         }
93
94         ac->module = module;
95         ac->req = req;
96
97         return ac;
98 }
99
100 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
101 {
102         struct samldb_step *step;
103
104         step = talloc_zero(ac, struct samldb_step);
105         if (step == NULL) {
106                 return LDB_ERR_OPERATIONS_ERROR;
107         }
108
109         if (ac->steps == NULL) {
110                 ac->steps = step;
111                 ac->curstep = step;
112         } else {
113                 ac->curstep->next = step;
114                 ac->curstep = step;
115         }
116
117         step->fn = fn;
118
119         return LDB_SUCCESS;
120 }
121
122 static int samldb_first_step(struct samldb_ctx *ac)
123 {
124         if (ac->steps == NULL) {
125                 return LDB_ERR_OPERATIONS_ERROR;
126         }
127
128         ac->curstep = ac->steps;
129         return ac->curstep->fn(ac);
130 }
131
132 static int samldb_next_step(struct samldb_ctx *ac)
133 {
134         if (ac->curstep->next) {
135                 ac->curstep = ac->curstep->next;
136                 return ac->curstep->fn(ac);
137         }
138
139         /* it is an error if the last step does not properly
140          * return to the upper module by itself */
141         return LDB_ERR_OPERATIONS_ERROR;
142 }
143
144 static int samldb_search_template_callback(struct ldb_request *req,
145                                            struct ldb_reply *ares)
146 {
147         struct samldb_ctx *ac;
148         int ret;
149
150         ac = talloc_get_type(req->context, struct samldb_ctx);
151
152         if (!ares) {
153                 ret = LDB_ERR_OPERATIONS_ERROR;
154                 goto done;
155         }
156         if (ares->error != LDB_SUCCESS) {
157 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
158                 return ldb_module_done(ac->req, ares->controls,
159                                         ares->response, ares->error);
160 #else
161                 return ldb_request_done(req, ares->error);
162 #endif
163         }
164
165         switch (ares->type) {
166         case LDB_REPLY_ENTRY:
167                 /* save entry */
168                 if (ac->ares != NULL) {
169                         /* one too many! */
170                         ldb_set_errstring(ac->module->ldb,
171                                 "Invalid number of results while searching "
172                                 "for template objects");
173                         ret = LDB_ERR_OPERATIONS_ERROR;
174                         goto done;
175                 }
176
177                 ac->ares = talloc_steal(ac, ares);
178                 ret = LDB_SUCCESS;
179                 break;
180
181         case LDB_REPLY_REFERRAL:
182                 /* ignore */
183                 talloc_free(ares);
184                 ret = LDB_SUCCESS;
185                 break;
186
187         case LDB_REPLY_DONE:
188
189                 talloc_free(ares);
190 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
191                 ret = samldb_next_step(ac);
192 #else
193                 return ldb_request_done(req, LDB_SUCCESS);
194 #endif
195                 break;
196         }
197
198 done:
199         if (ret != LDB_SUCCESS) {
200 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
201                 return ldb_module_done(ac->req, NULL, NULL, ret);
202 #else
203                 return ldb_request_done(req, ret);
204 #endif
205         }
206
207         return LDB_SUCCESS;
208 }
209
210 static int samldb_search_template(struct samldb_ctx *ac)
211 {
212         struct event_context *ev;
213         struct loadparm_context *lparm_ctx;
214         struct ldb_context *templates_ldb;
215         char *templates_ldb_path;
216         struct ldb_request *req;
217         struct ldb_dn *basedn;
218         void *opaque;
219         int ret;
220
221         opaque = ldb_get_opaque(ac->module->ldb, "loadparm");
222         lparm_ctx = talloc_get_type(opaque, struct loadparm_context);
223         if (lparm_ctx == NULL) {
224                 ldb_set_errstring(ac->module->ldb,
225                         "Unable to find loadparm context\n");
226                 return LDB_ERR_OPERATIONS_ERROR;
227         }
228
229         opaque = ldb_get_opaque(ac->module->ldb, "templates_ldb");
230         templates_ldb = talloc_get_type(opaque, struct ldb_context);
231
232         /* make sure we have the templates ldb */
233         if (!templates_ldb) {
234                 templates_ldb_path = samdb_relative_path(ac->module->ldb, ac,
235                                                          "templates.ldb");
236                 if (!templates_ldb_path) {
237                         ldb_set_errstring(ac->module->ldb,
238                                         "samldb_init_template: ERROR: Failed "
239                                         "to contruct path for template db");
240                         return LDB_ERR_OPERATIONS_ERROR;
241                 }
242
243                 /* NOTE: this is a request on a different database!
244                  *
245                  *       Therefore we need to do a bloody sync call
246                  *       otherwise the fake event queue will never call it
247                  *       as it runs on the main ldb context and knows
248                  *       nothing about the templates_ldb one */
249 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
250                 ev = ldb_get_event_context(ac->module->ldb);
251 #else
252                 ev = event_context_init(NULL);
253 #endif
254                 if (!talloc_reference(templates_ldb, ev)) {
255                         return LDB_ERR_OPERATIONS_ERROR;
256                 }
257
258                 templates_ldb = ldb_wrap_connect(ac->module->ldb, ev,
259                                                 lparm_ctx, templates_ldb_path,
260                                                 NULL, NULL, 0, NULL);
261                 talloc_free(templates_ldb_path);
262
263                 if (!templates_ldb) {
264                         return LDB_ERR_OPERATIONS_ERROR;
265                 }
266
267                 ret = ldb_set_opaque(ac->module->ldb,
268                                         "templates_ldb", templates_ldb);
269                 if (ret != LDB_SUCCESS) {
270                         return ret;
271                 }
272         }
273
274         /* search template */
275         basedn = ldb_dn_new_fmt(ac, templates_ldb,
276                             "cn=Template%s,cn=Templates", ac->type);
277         if (basedn == NULL) {
278                 ldb_set_errstring(ac->module->ldb,
279                         "samldb_init_template: ERROR: Failed "
280                         "to contruct DN for template");
281                 return LDB_ERR_OPERATIONS_ERROR;
282         }
283
284         /* pull the template record */
285         ret = ldb_build_search_req(&req, templates_ldb, ac,
286                                    basedn, LDB_SCOPE_BASE,
287                                   "(distinguishedName=*)", NULL,
288                                   NULL,
289                                   ac, samldb_search_template_callback,
290                                   ac->req);
291         if (ret != LDB_SUCCESS) {
292                 return ret;
293         }
294
295         talloc_steal(req, basedn);
296         ac->ares = NULL;
297
298         /* NOTE: this is a request on a different database!
299          *       Therefore we need to do a bloody sync call
300          *       otherwise the fake event queue will never call it
301          *       as it runs on the main ldb context and knows
302          *       nothing about the templates_ldb one */
303 #ifdef REAL_EVENT_SYSTEM_HOOKED_UP
304         return ldb_request(templates_ldb, req);
305 #else
306         ret = ldb_request(templates_ldb, req);
307         if (ret != LDB_SUCCESS) {
308                 return ret;
309         }
310         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
311         if (ret != LDB_SUCCESS) {
312                 return ret;
313         }
314
315         return samldb_next_step(ac);
316 #endif
317 }
318
319 static int samldb_apply_template(struct samldb_ctx *ac)
320 {
321         struct ldb_message_element *el;
322         struct ldb_message *msg;
323         int i, j;
324         int ret;
325
326         msg = ac->ares->message;
327
328         for (i = 0; i < msg->num_elements; i++) {
329                 el = &msg->elements[i];
330                 /* some elements should not be copied */
331                 if (ldb_attr_cmp(el->name, "cn") == 0 ||
332                     ldb_attr_cmp(el->name, "name") == 0 ||
333                     ldb_attr_cmp(el->name, "objectClass") == 0 ||
334                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
335                     ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
336                     ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
337                     ldb_attr_cmp(el->name, "objectGUID") == 0) {
338                         continue;
339                 }
340                 for (j = 0; j < el->num_values; j++) {
341                         ret = samdb_find_or_add_attribute(
342                                         ac->module->ldb, ac->msg, el->name,
343                                         (char *)el->values[j].data);
344                         if (ret != LDB_SUCCESS) {
345                                 ldb_set_errstring(ac->module->ldb,
346                                           "Failed adding template attribute\n");
347                                 return LDB_ERR_OPERATIONS_ERROR;
348                         }
349                 }
350         }
351
352         return samldb_next_step(ac);
353 }
354
355 static int samldb_get_parent_domain(struct samldb_ctx *ac);
356
357 static int samldb_get_parent_domain_callback(struct ldb_request *req,
358                                              struct ldb_reply *ares)
359 {
360         struct samldb_ctx *ac;
361         const char *nextRid;
362         int ret;
363
364         ac = talloc_get_type(req->context, struct samldb_ctx);
365
366         if (!ares) {
367                 ret = LDB_ERR_OPERATIONS_ERROR;
368                 goto done;
369         }
370         if (ares->error != LDB_SUCCESS) {
371                 return ldb_module_done(ac->req, ares->controls,
372                                         ares->response, ares->error);
373         }
374
375         switch (ares->type) {
376         case LDB_REPLY_ENTRY:
377                 /* save entry */
378                 if (ac->domain_dn != NULL) {
379                         /* one too many! */
380                         ldb_set_errstring(ac->module->ldb,
381                                 "Invalid number of results while searching "
382                                 "for domain object");
383                         ret = LDB_ERR_OPERATIONS_ERROR;
384                         break;
385                 }
386
387                 nextRid = ldb_msg_find_attr_as_string(ares->message,
388                                                         "nextRid", NULL);
389                 if (nextRid == NULL) {
390                         ldb_asprintf_errstring(ac->module->ldb,
391                                 "attribute nextRid not found in %s\n",
392                                 ldb_dn_get_linearized(ares->message->dn));
393                         ret = LDB_ERR_OPERATIONS_ERROR;
394                         break;;
395                 }
396
397                 ac->next_rid = strtol(nextRid, NULL, 0);
398
399                 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
400                                                                 "objectSid");
401                 if (ac->domain_sid == NULL) {
402                         ldb_set_errstring(ac->module->ldb,
403                                 "error retrieving parent domain domain sid!\n");
404                         ret = LDB_ERR_CONSTRAINT_VIOLATION;
405                         break;
406                 }
407                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
408
409                 talloc_free(ares);
410                 ret = LDB_SUCCESS;
411                 break;
412
413         case LDB_REPLY_REFERRAL:
414                 /* ignore */
415                 talloc_free(ares);
416                 ret = LDB_SUCCESS;
417                 break;
418
419         case LDB_REPLY_DONE:
420
421                 talloc_free(ares);
422                 if (ac->domain_dn == NULL) {
423                         /* search again */
424                         ret = samldb_get_parent_domain(ac);
425                 } else {
426                         /* found, go on */
427                         ret = samldb_next_step(ac);
428                 }
429                 break;
430         }
431
432 done:
433         if (ret != LDB_SUCCESS) {
434                 return ldb_module_done(ac->req, NULL, NULL, ret);
435         }
436
437         return LDB_SUCCESS;
438 }
439
440 /* Find a domain object in the parents of a particular DN.  */
441 static int samldb_get_parent_domain(struct samldb_ctx *ac)
442 {
443         static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
444         struct ldb_request *req;
445         struct ldb_dn *dn;
446         int ret;
447
448         if (ac->check_dn == NULL) {
449                 return LDB_ERR_OPERATIONS_ERROR;
450         }
451
452         dn = ldb_dn_get_parent(ac, ac->check_dn);
453         if (dn == NULL) {
454                 ldb_set_errstring(ac->module->ldb,
455                         "Unable to find parent domain object");
456                 return LDB_ERR_CONSTRAINT_VIOLATION;
457         }
458
459         ac->check_dn = dn;
460
461         ret = ldb_build_search_req(&req, ac->module->ldb, ac,
462                                    dn, LDB_SCOPE_BASE,
463                                    "(|(objectClass=domain)"
464                                      "(objectClass=builtinDomain)"
465                                      "(objectClass=samba4LocalDomain))",
466                                    attrs,
467                                    NULL,
468                                    ac, samldb_get_parent_domain_callback,
469                                    ac->req);
470
471         if (ret != LDB_SUCCESS) {
472                 return ret;
473         }
474
475         return ldb_next_request(ac->module, req);
476 }
477
478 static int samldb_generate_samAccountName(struct ldb_message *msg)
479 {
480         char *name;
481
482         /* Format: $000000-000000000000 */
483
484         name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
485                                 (unsigned int)generate_random(),
486                                 (unsigned int)generate_random(),
487                                 (unsigned int)generate_random());
488         if (name == NULL) {
489                 return LDB_ERR_OPERATIONS_ERROR;
490         }
491         return ldb_msg_add_steal_string(msg, "samAccountName", name);
492 }
493
494 static int samldb_check_samAccountName_callback(struct ldb_request *req,
495                                                 struct ldb_reply *ares)
496 {
497         struct samldb_ctx *ac;
498         int ret;
499
500         ac = talloc_get_type(req->context, struct samldb_ctx);
501
502         if (!ares) {
503                 ret = LDB_ERR_OPERATIONS_ERROR;
504                 goto done;
505         }
506         if (ares->error != LDB_SUCCESS) {
507                 return ldb_module_done(ac->req, ares->controls,
508                                         ares->response, ares->error);
509         }
510
511         switch (ares->type) {
512         case LDB_REPLY_ENTRY:
513
514                 /* if we get an entry it means this samAccountName
515                  * already exists */
516                 return ldb_module_done(ac->req, NULL, NULL,
517                                         LDB_ERR_ENTRY_ALREADY_EXISTS);
518
519         case LDB_REPLY_REFERRAL:
520                 /* ignore */
521                 talloc_free(ares);
522                 ret = LDB_SUCCESS;
523                 break;
524
525         case LDB_REPLY_DONE:
526
527                 /* not found, go on */
528                 talloc_free(ares);
529                 ret = samldb_next_step(ac);
530                 break;
531         }
532
533 done:
534         if (ret != LDB_SUCCESS) {
535                 return ldb_module_done(ac->req, NULL, NULL, ret);
536         }
537
538         return LDB_SUCCESS;
539 }
540
541 static int samldb_check_samAccountName(struct samldb_ctx *ac)
542 {
543         struct ldb_request *req;
544         const char *name;
545         char *filter;
546         int ret;
547
548         if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
549                 ret = samldb_generate_samAccountName(ac->msg);
550                 if (ret != LDB_SUCCESS) {
551                         return ret;
552                 }
553         }
554
555         name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
556         if (name == NULL) {
557                 return LDB_ERR_OPERATIONS_ERROR;
558         }
559         filter = talloc_asprintf(ac, "samAccountName=%s", name);
560         if (filter == NULL) {
561                 return LDB_ERR_OPERATIONS_ERROR;
562         }
563
564         ret = ldb_build_search_req(&req, ac->module->ldb, ac,
565                                 ac->domain_dn, LDB_SCOPE_SUBTREE,
566                                 filter, NULL,
567                                 NULL,
568                                 ac, samldb_check_samAccountName_callback,
569                                 ac->req);
570         talloc_free(filter);
571         if (ret != LDB_SUCCESS) {
572                 return ret;
573         }
574         ac->ares = NULL;
575         return ldb_next_request(ac->module, req);
576 }
577
578 static int samldb_check_samAccountType(struct samldb_ctx *ac)
579 {
580         unsigned int account_type;
581         unsigned int group_type;
582         unsigned int uac;
583         int ret;
584
585         /* make sure sAMAccountType is not specified */
586         if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
587                 ldb_asprintf_errstring(ac->module->ldb,
588                                         "sAMAccountType must not be specified");
589                 return LDB_ERR_UNWILLING_TO_PERFORM;
590         }
591
592         if (strcmp("user", ac->type) == 0) {
593                 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
594                 if (uac == 0) {
595                         ldb_asprintf_errstring(ac->module->ldb,
596                                                 "userAccountControl invalid");
597                         return LDB_ERR_UNWILLING_TO_PERFORM;
598                 } else {
599                         account_type = samdb_uf2atype(uac);
600                         ret = samdb_msg_add_uint(ac->module->ldb,
601                                                  ac->msg, ac->msg,
602                                                  "sAMAccountType",
603                                                  account_type);
604                         if (ret != LDB_SUCCESS) {
605                                 return ret;
606                         }
607                 }
608         } else
609         if (strcmp("group", ac->type) == 0) {
610
611                 group_type = samdb_result_uint(ac->msg, "groupType", 0);
612                 if (group_type == 0) {
613                         ldb_asprintf_errstring(ac->module->ldb,
614                                                 "groupType invalid");
615                         return LDB_ERR_UNWILLING_TO_PERFORM;
616                 } else {
617                         account_type = samdb_gtype2atype(group_type);
618                         ret = samdb_msg_add_uint(ac->module->ldb,
619                                                  ac->msg, ac->msg,
620                                                  "sAMAccountType",
621                                                  account_type);
622                         if (ret != LDB_SUCCESS) {
623                                 return ret;
624                         }
625                 }
626         }
627
628         return samldb_next_step(ac);
629 }
630
631 static int samldb_get_sid_domain_callback(struct ldb_request *req,
632                                           struct ldb_reply *ares)
633 {
634         struct samldb_ctx *ac;
635         const char *nextRid;
636         int ret;
637
638         ac = talloc_get_type(req->context, struct samldb_ctx);
639
640         if (!ares) {
641                 ret = LDB_ERR_OPERATIONS_ERROR;
642                 goto done;
643         }
644         if (ares->error != LDB_SUCCESS) {
645                 return ldb_module_done(ac->req, ares->controls,
646                                         ares->response, ares->error);
647         }
648
649         switch (ares->type) {
650         case LDB_REPLY_ENTRY:
651                 /* save entry */
652                 if (ac->next_rid != 0) {
653                         /* one too many! */
654                         ldb_set_errstring(ac->module->ldb,
655                                 "Invalid number of results while searching "
656                                 "for domain object");
657                         ret = LDB_ERR_OPERATIONS_ERROR;
658                         break;
659                 }
660
661                 nextRid = ldb_msg_find_attr_as_string(ares->message,
662                                                         "nextRid", NULL);
663                 if (nextRid == NULL) {
664                         ldb_asprintf_errstring(ac->module->ldb,
665                                 "attribute nextRid not found in %s\n",
666                                 ldb_dn_get_linearized(ares->message->dn));
667                         ret = LDB_ERR_OPERATIONS_ERROR;
668                         break;
669                 }
670
671                 ac->next_rid = strtol(nextRid, NULL, 0);
672
673                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
674
675                 talloc_free(ares);
676                 ret = LDB_SUCCESS;
677                 break;
678
679         case LDB_REPLY_REFERRAL:
680                 /* ignore */
681                 talloc_free(ares);
682                 ret = LDB_SUCCESS;
683                 break;
684
685         case LDB_REPLY_DONE:
686
687                 if (ac->next_rid == 0) {
688                         ldb_asprintf_errstring(ac->module->ldb,
689                                 "Unable to get nextRid from domain entry\n");
690                         ret = LDB_ERR_OPERATIONS_ERROR;
691                         break;
692                 }
693
694                 /* found, go on */
695                 ret = samldb_next_step(ac);
696                 break;
697         }
698
699 done:
700         if (ret != LDB_SUCCESS) {
701                 return ldb_module_done(ac->req, NULL, NULL, ret);
702         }
703
704         return LDB_SUCCESS;
705 }
706
707 /* Find a domain object in the parents of a particular DN.  */
708 static int samldb_get_sid_domain(struct samldb_ctx *ac)
709 {
710         static const char * const attrs[2] = { "nextRid", NULL };
711         struct ldb_request *req;
712         char *filter;
713         int ret;
714
715         if (ac->sid == NULL) {
716                 return LDB_ERR_OPERATIONS_ERROR;
717         }
718
719         ac->domain_sid = dom_sid_dup(ac, ac->sid);
720         if (!ac->domain_sid) {
721                 return LDB_ERR_OPERATIONS_ERROR;
722         }
723         /* get the domain component part of the provided SID */
724         ac->domain_sid->num_auths--;
725
726         filter = talloc_asprintf(ac, "(&(objectSid=%s)"
727                                        "(|(objectClass=domain)"
728                                          "(objectClass=builtinDomain)"
729                                          "(objectClass=samba4LocalDomain)))",
730                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
731         if (filter == NULL) {
732                 return LDB_ERR_OPERATIONS_ERROR;
733         }
734
735         ret = ldb_build_search_req(&req, ac->module->ldb, ac,
736                                    ldb_get_default_basedn(ac->module->ldb),
737                                    LDB_SCOPE_SUBTREE,
738                                    filter, attrs,
739                                    NULL,
740                                    ac, samldb_get_sid_domain_callback,
741                                    ac->req);
742
743         if (ret != LDB_SUCCESS) {
744                 return ret;
745         }
746
747         ac->next_rid = 0;
748         return ldb_next_request(ac->module, req);
749 }
750
751 static bool samldb_msg_add_sid(struct ldb_message *msg,
752                                 const char *name,
753                                 const struct dom_sid *sid)
754 {
755         struct ldb_val v;
756         enum ndr_err_code ndr_err;
757
758         ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
759                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
760         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
761                 return false;
762         }
763         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
764 }
765
766 static int samldb_new_sid(struct samldb_ctx *ac)
767 {
768
769         if (ac->domain_sid == NULL || ac->next_rid == 0) {
770                 return LDB_ERR_OPERATIONS_ERROR;
771         }
772
773         ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
774         if (ac->sid == NULL) {
775                 return LDB_ERR_OPERATIONS_ERROR;
776         }
777
778         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
779                 return LDB_ERR_OPERATIONS_ERROR;
780         }
781
782         return samldb_next_step(ac);
783 }
784
785 static int samldb_check_sid_callback(struct ldb_request *req,
786                                      struct ldb_reply *ares)
787 {
788         struct samldb_ctx *ac;
789         int ret;
790
791         ac = talloc_get_type(req->context, struct samldb_ctx);
792
793         if (!ares) {
794                 ret = LDB_ERR_OPERATIONS_ERROR;
795                 goto done;
796         }
797         if (ares->error != LDB_SUCCESS) {
798                 return ldb_module_done(ac->req, ares->controls,
799                                         ares->response, ares->error);
800         }
801
802         switch (ares->type) {
803         case LDB_REPLY_ENTRY:
804
805                 /* if we get an entry it means an object with the
806                  * requested sid exists */
807                 return ldb_module_done(ac->req, NULL, NULL,
808                                         LDB_ERR_CONSTRAINT_VIOLATION);
809
810         case LDB_REPLY_REFERRAL:
811                 /* ignore */
812                 talloc_free(ares);
813                 break;
814
815         case LDB_REPLY_DONE:
816
817                 /* not found, go on */
818                 talloc_free(ares);
819                 ret = samldb_next_step(ac);
820                 break;
821         }
822
823 done:
824         if (ret != LDB_SUCCESS) {
825                 return ldb_module_done(ac->req, NULL, NULL, ret);
826         }
827
828         return LDB_SUCCESS;
829 }
830
831 static int samldb_check_sid(struct samldb_ctx *ac)
832 {
833         const char *const attrs[2] = { "objectSid", NULL };
834         struct ldb_request *req;
835         char *filter;
836         int ret;
837
838         if (ac->sid == NULL) {
839                 return LDB_ERR_OPERATIONS_ERROR;
840         }
841
842         filter = talloc_asprintf(ac, "(objectSid=%s)",
843                                  ldap_encode_ndr_dom_sid(ac, ac->sid));
844         if (filter == NULL) {
845                 return LDB_ERR_OPERATIONS_ERROR;
846         }
847
848         ret = ldb_build_search_req(&req, ac->module->ldb, ac,
849                                    ldb_get_default_basedn(ac->module->ldb),
850                                    LDB_SCOPE_SUBTREE,
851                                    filter, attrs,
852                                    NULL,
853                                    ac, samldb_check_sid_callback,
854                                    ac->req);
855
856         if (ret != LDB_SUCCESS) {
857                 return ret;
858         }
859
860         return ldb_next_request(ac->module, req);
861 }
862
863 static int samldb_notice_sid_callback(struct ldb_request *req,
864                                         struct ldb_reply *ares)
865 {
866         struct samldb_ctx *ac;
867         int ret;
868
869         ac = talloc_get_type(req->context, struct samldb_ctx);
870
871         if (!ares) {
872                 ret = LDB_ERR_OPERATIONS_ERROR;
873                 goto done;
874         }
875         if (ares->error != LDB_SUCCESS) {
876                 return ldb_module_done(ac->req, ares->controls,
877                                         ares->response, ares->error);
878         }
879         if (ares->type != LDB_REPLY_DONE) {
880                 ldb_set_errstring(ac->module->ldb,
881                         "Invalid reply type!\n");
882                 ret = LDB_ERR_OPERATIONS_ERROR;
883                 goto done;
884         }
885
886         ret = samldb_next_step(ac);
887
888 done:
889         if (ret != LDB_SUCCESS) {
890                 return ldb_module_done(ac->req, NULL, NULL, ret);
891         }
892
893         return LDB_SUCCESS;
894 }
895
896 /* If we are adding new users/groups, we need to update the nextRid
897  * attribute to be 'above' the new/incoming RID. Attempt to do it
898  *atomically. */
899 static int samldb_notice_sid(struct samldb_ctx *ac)
900 {
901         uint32_t old_id, new_id;
902         struct ldb_request *req;
903         struct ldb_message *msg;
904         struct ldb_message_element *els;
905         struct ldb_val *vals;
906         int ret;
907
908         old_id = ac->next_rid;
909         new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
910
911         if (old_id >= new_id) {
912                 /* no need to update the domain nextRid attribute */
913                 return samldb_next_step(ac);
914         }
915
916         /* we do a delete and add as a single operation. That prevents
917            a race, in case we are not actually on a transaction db */
918         msg = talloc_zero(ac, struct ldb_message);
919         if (msg == NULL) {
920                 ldb_oom(ac->module->ldb);
921                 return LDB_ERR_OPERATIONS_ERROR;
922         }
923         els = talloc_array(msg, struct ldb_message_element, 2);
924         if (els == NULL) {
925                 ldb_oom(ac->module->ldb);
926                 return LDB_ERR_OPERATIONS_ERROR;
927         }
928         vals = talloc_array(msg, struct ldb_val, 2);
929         if (vals == NULL) {
930                 ldb_oom(ac->module->ldb);
931                 return LDB_ERR_OPERATIONS_ERROR;
932         }
933         msg->dn = ac->domain_dn;
934         msg->num_elements = 2;
935         msg->elements = els;
936
937         els[0].num_values = 1;
938         els[0].values = &vals[0];
939         els[0].flags = LDB_FLAG_MOD_DELETE;
940         els[0].name = talloc_strdup(msg, "nextRid");
941         if (!els[0].name) {
942                 ldb_oom(ac->module->ldb);
943                 return LDB_ERR_OPERATIONS_ERROR;
944         }
945
946         els[1].num_values = 1;
947         els[1].values = &vals[1];
948         els[1].flags = LDB_FLAG_MOD_ADD;
949         els[1].name = els[0].name;
950
951         vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
952         if (!vals[0].data) {
953                 ldb_oom(ac->module->ldb);
954                 return LDB_ERR_OPERATIONS_ERROR;
955         }
956         vals[0].length = strlen((char *)vals[0].data);
957
958         vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
959         if (!vals[1].data) {
960                 ldb_oom(ac->module->ldb);
961                 return LDB_ERR_OPERATIONS_ERROR;
962         }
963         vals[1].length = strlen((char *)vals[1].data);
964
965         ret = ldb_build_mod_req(&req, ac->module->ldb, ac,
966                                 msg, NULL,
967                                 ac, samldb_notice_sid_callback,
968                                 ac->req);
969         if (ret != LDB_SUCCESS) {
970                 return ret;
971         }
972
973         return ldb_next_request(ac->module, req);
974 }
975
976 static int samldb_add_entry_callback(struct ldb_request *req,
977                                         struct ldb_reply *ares)
978 {
979         struct samldb_ctx *ac;
980
981         ac = talloc_get_type(req->context, struct samldb_ctx);
982
983         if (!ares) {
984                 return ldb_module_done(ac->req, NULL, NULL,
985                                         LDB_ERR_OPERATIONS_ERROR);
986         }
987         if (ares->error != LDB_SUCCESS) {
988                 return ldb_module_done(ac->req, ares->controls,
989                                         ares->response, ares->error);
990         }
991         if (ares->type != LDB_REPLY_DONE) {
992                 ldb_set_errstring(ac->module->ldb,
993                         "Invalid reply type!\n");
994                 return ldb_module_done(ac->req, NULL, NULL,
995                                         LDB_ERR_OPERATIONS_ERROR);
996         }
997
998         /* we exit the samldb module here */
999         return ldb_module_done(ac->req, ares->controls,
1000                                 ares->response, LDB_SUCCESS);
1001 }
1002
1003 static int samldb_add_entry(struct samldb_ctx *ac)
1004 {
1005         struct ldb_request *req;
1006         int ret;
1007
1008         ret = ldb_build_add_req(&req, ac->module->ldb, ac,
1009                                 ac->msg,
1010                                 ac->req->controls,
1011                                 ac, samldb_add_entry_callback,
1012                                 ac->req);
1013         if (ret != LDB_SUCCESS) {
1014                 return ret;
1015         }
1016
1017         return ldb_next_request(ac->module, req);
1018 }
1019
1020 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
1021 {
1022         int ret;
1023
1024         /* first look for the template */
1025         ac->type = type;
1026         ret = samldb_add_step(ac, samldb_search_template);
1027         if (ret != LDB_SUCCESS) return ret;
1028
1029         /* then apply it */
1030         ret = samldb_add_step(ac, samldb_apply_template);
1031         if (ret != LDB_SUCCESS) return ret;
1032
1033         /* search for a parent domain objet */
1034         ac->check_dn = ac->req->op.add.message->dn;
1035         ret = samldb_add_step(ac, samldb_get_parent_domain);
1036         if (ret != LDB_SUCCESS) return ret;
1037
1038         /* check if we have a valid samAccountName */
1039         ret = samldb_add_step(ac, samldb_check_samAccountName);
1040         if (ret != LDB_SUCCESS) return ret;
1041
1042         /* check account_type/group_type */
1043         ret = samldb_add_step(ac, samldb_check_samAccountType);
1044         if (ret != LDB_SUCCESS) return ret;
1045
1046         /* check if we have a valid SID */
1047         ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1048         if ( ! ac->sid) {
1049                 ret = samldb_add_step(ac, samldb_new_sid);
1050                 if (ret != LDB_SUCCESS) return ret;
1051         } else {
1052                 ret = samldb_add_step(ac, samldb_get_sid_domain);
1053                 if (ret != LDB_SUCCESS) return ret;
1054         }
1055
1056         ret = samldb_add_step(ac, samldb_check_sid);
1057         if (ret != LDB_SUCCESS) return ret;
1058
1059         ret = samldb_add_step(ac, samldb_notice_sid);
1060         if (ret != LDB_SUCCESS) return ret;
1061
1062         /* finally proceed with adding the entry */
1063         ret = samldb_add_step(ac, samldb_add_entry);
1064         if (ret != LDB_SUCCESS) return ret;
1065
1066         return samldb_first_step(ac);
1067
1068         /* TODO: userAccountControl, badPwdCount, codePage,
1069          *       countryCode, badPasswordTime, lastLogoff, lastLogon,
1070          *       pwdLastSet, primaryGroupID, accountExpires, logonCount */
1071
1072 }
1073
1074 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1075                                                 struct ldb_reply *ares)
1076 {
1077         struct samldb_ctx *ac;
1078         const char *nextRid;
1079         const char *name;
1080         int ret;
1081
1082         ac = talloc_get_type(req->context, struct samldb_ctx);
1083
1084         if (!ares) {
1085                 ret = LDB_ERR_OPERATIONS_ERROR;
1086                 goto done;
1087         }
1088         if (ares->error != LDB_SUCCESS) {
1089                 return ldb_module_done(ac->req, ares->controls,
1090                                         ares->response, ares->error);
1091         }
1092
1093         switch (ares->type) {
1094         case LDB_REPLY_ENTRY:
1095                 /* save entry */
1096                 if (ac->next_rid != 0) {
1097                         /* one too many! */
1098                         ldb_set_errstring(ac->module->ldb,
1099                                 "Invalid number of results while searching "
1100                                 "for domain object");
1101                         ret = LDB_ERR_OPERATIONS_ERROR;
1102                         break;
1103                 }
1104
1105                 nextRid = ldb_msg_find_attr_as_string(ares->message,
1106                                                         "nextRid", NULL);
1107                 if (nextRid == NULL) {
1108                         ldb_asprintf_errstring(ac->module->ldb,
1109                                 "attribute nextRid not found in %s\n",
1110                                 ldb_dn_get_linearized(ares->message->dn));
1111                         ret = LDB_ERR_OPERATIONS_ERROR;
1112                         break;
1113                 }
1114
1115                 ac->next_rid = strtol(nextRid, NULL, 0);
1116
1117                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1118
1119                 name = samdb_result_string(ares->message, "name", NULL);
1120                 ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE,
1121                          "NOTE (strange but valid): Adding foreign SID "
1122                          "record with SID %s, but this domain (%s) is "
1123                          "not foreign in the database",
1124                          dom_sid_string(ares, ac->sid), name);
1125
1126                 talloc_free(ares);
1127                 break;
1128
1129         case LDB_REPLY_REFERRAL:
1130                 /* ignore */
1131                 talloc_free(ares);
1132                 break;
1133
1134         case LDB_REPLY_DONE:
1135
1136                 /* if this is a fake foreign SID, notice the SID */
1137                 if (ac->domain_dn) {
1138                         ret = samldb_notice_sid(ac);
1139                         break;
1140                 }
1141
1142                 /* found, go on */
1143                 ret = samldb_next_step(ac);
1144                 break;
1145         }
1146
1147 done:
1148         if (ret != LDB_SUCCESS) {
1149                 return ldb_module_done(ac->req, NULL, NULL, ret);
1150         }
1151
1152         return LDB_SUCCESS;
1153 }
1154
1155 /* Find a domain object in the parents of a particular DN. */
1156 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1157 {
1158         static const char * const attrs[3] = { "nextRid", "name", NULL };
1159         struct ldb_request *req;
1160         char *filter;
1161         int ret;
1162
1163         if (ac->sid == NULL) {
1164                 return LDB_ERR_OPERATIONS_ERROR;
1165         }
1166
1167         ac->domain_sid = dom_sid_dup(ac, ac->sid);
1168         if (!ac->domain_sid) {
1169                 return LDB_ERR_OPERATIONS_ERROR;
1170         }
1171         /* get the domain component part of the provided SID */
1172         ac->domain_sid->num_auths--;
1173
1174         filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1175                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1176         if (filter == NULL) {
1177                 return LDB_ERR_OPERATIONS_ERROR;
1178         }
1179
1180         ret = ldb_build_search_req(&req, ac->module->ldb, ac,
1181                                    ldb_get_default_basedn(ac->module->ldb),
1182                                    LDB_SCOPE_SUBTREE,
1183                                    filter, attrs,
1184                                    NULL,
1185                                    ac, samldb_foreign_notice_sid_callback,
1186                                    ac->req);
1187
1188         if (ret != LDB_SUCCESS) {
1189                 return ret;
1190         }
1191
1192         ac->next_rid = 0;
1193         return ldb_next_request(ac->module, req);
1194 }
1195
1196 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1197 {
1198         int ret;
1199
1200         ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1201         if (ac->sid == NULL) {
1202                 ac->sid = dom_sid_parse_talloc(ac->msg,
1203                            (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1204                 if (!ac->sid) {
1205                         ldb_set_errstring(ac->module->ldb,
1206                                         "No valid found SID in "
1207                                         "ForeignSecurityPrincipal CN!");
1208                         talloc_free(ac);
1209                         return LDB_ERR_CONSTRAINT_VIOLATION;
1210                 }
1211                 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1212                         talloc_free(ac);
1213                         return LDB_ERR_OPERATIONS_ERROR;
1214                 }
1215         }
1216
1217         /* first look for the template */
1218         ac->type = "foreignSecurityPrincipal";
1219         ret = samldb_add_step(ac, samldb_search_template);
1220         if (ret != LDB_SUCCESS) return ret;
1221
1222         /* then apply it */
1223         ret = samldb_add_step(ac, samldb_apply_template);
1224         if (ret != LDB_SUCCESS) return ret;
1225
1226         /* check we do not already have this SID */
1227         ret = samldb_add_step(ac, samldb_check_sid);
1228         if (ret != LDB_SUCCESS) return ret;
1229
1230         /* check if we need to notice this SID */
1231         ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1232         if (ret != LDB_SUCCESS) return ret;
1233
1234         /* finally proceed with adding the entry */
1235         ret = samldb_add_step(ac, samldb_add_entry);
1236         if (ret != LDB_SUCCESS) return ret;
1237
1238         return samldb_first_step(ac);
1239 }
1240
1241 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1242 {
1243         const char *rdn_name;
1244
1245         rdn_name = ldb_dn_get_rdn_name(dn);
1246
1247         if (strcasecmp(rdn_name, "cn") != 0) {
1248                 ldb_asprintf_errstring(module->ldb,
1249                                         "Bad RDN (%s=) for samldb object, "
1250                                         "should be CN=!\n", rdn_name);
1251                 return LDB_ERR_CONSTRAINT_VIOLATION;
1252         }
1253
1254         return LDB_SUCCESS;
1255 }
1256
1257 /* add_record */
1258 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1259 {
1260         struct samldb_ctx *ac;
1261         int ret;
1262
1263         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1264
1265         /* do not manipulate our control entries */
1266         if (ldb_dn_is_special(req->op.add.message->dn)) {
1267                 return ldb_next_request(module, req);
1268         }
1269
1270         ac = samldb_ctx_init(module, req);
1271         if (ac == NULL) {
1272                 return LDB_ERR_OPERATIONS_ERROR;
1273         }
1274
1275         /* build the new msg */
1276         ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1277         if (!ac->msg) {
1278                 talloc_free(ac);
1279                 ldb_debug(ac->module->ldb, LDB_DEBUG_FATAL,
1280                           "samldb_add: ldb_msg_copy failed!\n");
1281                 return LDB_ERR_OPERATIONS_ERROR;
1282         }
1283
1284         if (samdb_find_attribute(module->ldb, ac->msg,
1285                                  "objectclass", "computer") != NULL) {
1286
1287                 /* make sure the computer object also has the 'user'
1288                  * objectclass so it will be handled by the next call */
1289                 ret = samdb_find_or_add_value(module->ldb, ac->msg,
1290                                                 "objectclass", "user");
1291                 if (ret != LDB_SUCCESS) {
1292                         talloc_free(ac);
1293                         return ret;
1294                 }
1295         }
1296
1297         if (samdb_find_attribute(module->ldb, ac->msg,
1298                                  "objectclass", "user") != NULL) {
1299
1300                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1301                 if (ret != LDB_SUCCESS) {
1302                         talloc_free(ac);
1303                         return ret;
1304                 }
1305
1306                 return samldb_fill_object(ac, "user");
1307         }
1308
1309         if (samdb_find_attribute(module->ldb, ac->msg,
1310                                  "objectclass", "group") != NULL) {
1311
1312                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1313                 if (ret != LDB_SUCCESS) {
1314                         talloc_free(ac);
1315                         return ret;
1316                 }
1317
1318                 return samldb_fill_object(ac, "group");
1319         }
1320
1321         /* perhaps a foreignSecurityPrincipal? */
1322         if (samdb_find_attribute(module->ldb, ac->msg,
1323                                  "objectclass",
1324                                  "foreignSecurityPrincipal") != NULL) {
1325
1326                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1327                 if (ret != LDB_SUCCESS) {
1328                         talloc_free(ac);
1329                         return ret;
1330                 }
1331
1332                 return samldb_fill_foreignSecurityPrincipal_object(ac);
1333         }
1334
1335         talloc_free(ac);
1336
1337         /* nothing matched, go on */
1338         return ldb_next_request(module, req);
1339 }
1340
1341 /* modify */
1342 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1343 {
1344         struct ldb_message *msg;
1345         struct ldb_message_element *el, *el2;
1346         int ret;
1347         unsigned int group_type, user_account_control, account_type;
1348         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1349                 return ldb_next_request(module, req);
1350         }
1351
1352         if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1353                 ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
1354                 return LDB_ERR_UNWILLING_TO_PERFORM;
1355         }
1356
1357         /* TODO: do not modify original request, create a new one */
1358
1359         el = ldb_msg_find_element(req->op.mod.message, "groupType");
1360         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1361                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1362
1363                 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1364                 account_type =  samdb_gtype2atype(group_type);
1365                 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1366                                          "sAMAccountType",
1367                                          account_type);
1368                 if (ret != LDB_SUCCESS) {
1369                         return ret;
1370                 }
1371                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1372                 el2->flags = LDB_FLAG_MOD_REPLACE;
1373         }
1374
1375         el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1376         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1377                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1378
1379                 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1380                 account_type = samdb_uf2atype(user_account_control);
1381                 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1382                                          "sAMAccountType",
1383                                          account_type);
1384                 if (ret != LDB_SUCCESS) {
1385                         return ret;
1386                 }
1387                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1388                 el2->flags = LDB_FLAG_MOD_REPLACE;
1389         }
1390         return ldb_next_request(module, req);
1391 }
1392
1393
1394 static int samldb_init(struct ldb_module *module)
1395 {
1396         return ldb_next_init(module);
1397 }
1398
1399 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1400         .name          = "samldb",
1401         .init_context  = samldb_init,
1402         .add           = samldb_add,
1403         .modify        = samldb_modify
1404 };