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