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