libds: merge the UF<->ACB flag mapping functions.
[gd/samba-autobuild/.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
470 static int samldb_check_samAccountName_callback(struct ldb_request *req,
471                                                 struct ldb_reply *ares)
472 {
473         struct samldb_ctx *ac;
474         int ret;
475         
476         ac = talloc_get_type(req->context, struct samldb_ctx);
477         
478         if (ares->error != LDB_SUCCESS) {
479                 return ldb_module_done(ac->req, ares->controls,
480                                        ares->response, ares->error);
481         }
482         
483         switch (ares->type) {
484         case LDB_REPLY_ENTRY:           
485                 /* if we get an entry it means this samAccountName
486                  * already exists */
487                 return ldb_module_done(ac->req, NULL, NULL,
488                                        LDB_ERR_ENTRY_ALREADY_EXISTS);
489                 
490         case LDB_REPLY_REFERRAL:
491                 /* this should not happen */
492                 return ldb_module_done(ac->req, NULL, NULL,
493                                        LDB_ERR_OPERATIONS_ERROR);
494                 
495         case LDB_REPLY_DONE:
496                 /* not found, go on */
497                 talloc_free(ares);
498                 ret = samldb_next_step(ac);
499                 break;
500         }
501         
502         if (ret != LDB_SUCCESS) {
503                 return ldb_module_done(ac->req, NULL, NULL, ret);
504         }
505         
506         return LDB_SUCCESS;
507 }
508
509
510 static int samldb_check_samAccountName(struct samldb_ctx *ac)
511 {
512         struct ldb_context *ldb;
513         struct ldb_request *req;
514         const char *name;
515         char *filter;
516         int ret;
517         
518         ldb = ldb_module_get_ctx(ac->module);
519         
520         if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
521                 ret = samldb_generate_samAccountName(ac->msg);
522                 if (ret != LDB_SUCCESS) {
523                         return ret;
524                 }
525         }
526         
527         name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
528         if (name == NULL) {
529                 return LDB_ERR_OPERATIONS_ERROR;
530         }
531         filter = talloc_asprintf(ac, "samAccountName=%s", ldb_binary_encode_string(ac, name));
532         if (filter == NULL) {
533                 return LDB_ERR_OPERATIONS_ERROR;
534         }
535         
536         ret = ldb_build_search_req(&req, ldb, ac,
537                                    ac->domain_dn, LDB_SCOPE_SUBTREE,
538                                    filter, NULL,
539                                    NULL,
540                                    ac, samldb_check_samAccountName_callback,
541                                    ac->req);
542         talloc_free(filter);
543         if (ret != LDB_SUCCESS) {
544                 return ret;
545         }
546         ac->ares = NULL;
547         return ldb_next_request(ac->module, req);
548 }
549
550
551 static int samldb_check_samAccountType(struct samldb_ctx *ac)
552 {
553         struct ldb_context *ldb;
554         unsigned int account_type;
555         unsigned int group_type;
556         unsigned int uac;
557         int ret;
558
559         ldb = ldb_module_get_ctx(ac->module);
560
561         /* make sure sAMAccountType is not specified */
562         if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
563                 ldb_asprintf_errstring(ldb,
564                                         "sAMAccountType must not be specified");
565                 return LDB_ERR_UNWILLING_TO_PERFORM;
566         }
567
568         if (strcmp("user", ac->type) == 0) {
569                 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
570                 if (uac == 0) {
571                         ldb_asprintf_errstring(ldb,
572                                                 "userAccountControl invalid");
573                         return LDB_ERR_UNWILLING_TO_PERFORM;
574                 } else {
575                         account_type = ds_uf2atype(uac);
576                         ret = samdb_msg_add_uint(ldb,
577                                                  ac->msg, ac->msg,
578                                                  "sAMAccountType",
579                                                  account_type);
580                         if (ret != LDB_SUCCESS) {
581                                 return ret;
582                         }
583                 }
584         } else
585         if (strcmp("group", ac->type) == 0) {
586
587                 group_type = samdb_result_uint(ac->msg, "groupType", 0);
588                 if (group_type == 0) {
589                         ldb_asprintf_errstring(ldb,
590                                                 "groupType invalid");
591                         return LDB_ERR_UNWILLING_TO_PERFORM;
592                 } else {
593                         account_type = ds_gtype2atype(group_type);
594                         ret = samdb_msg_add_uint(ldb,
595                                                  ac->msg, ac->msg,
596                                                  "sAMAccountType",
597                                                  account_type);
598                         if (ret != LDB_SUCCESS) {
599                                 return ret;
600                         }
601                 }
602         }
603
604         return samldb_next_step(ac);
605 }
606
607 static int samldb_get_sid_domain_callback(struct ldb_request *req,
608                                           struct ldb_reply *ares)
609 {
610         struct ldb_context *ldb;
611         struct samldb_ctx *ac;
612         const char *nextRid;
613         int ret;
614
615         ac = talloc_get_type(req->context, struct samldb_ctx);
616         ldb = ldb_module_get_ctx(ac->module);
617
618         if (!ares) {
619                 ret = LDB_ERR_OPERATIONS_ERROR;
620                 goto done;
621         }
622         if (ares->error != LDB_SUCCESS) {
623                 return ldb_module_done(ac->req, ares->controls,
624                                         ares->response, ares->error);
625         }
626
627         switch (ares->type) {
628         case LDB_REPLY_ENTRY:
629                 /* save entry */
630                 if (ac->next_rid != 0) {
631                         /* one too many! */
632                         ldb_set_errstring(ldb,
633                                 "Invalid number of results while searching "
634                                 "for domain object");
635                         ret = LDB_ERR_OPERATIONS_ERROR;
636                         break;
637                 }
638
639                 nextRid = ldb_msg_find_attr_as_string(ares->message,
640                                                         "nextRid", NULL);
641                 if (nextRid == NULL) {
642                         ldb_asprintf_errstring(ldb,
643                                 "attribute nextRid not found in %s\n",
644                                 ldb_dn_get_linearized(ares->message->dn));
645                         ret = LDB_ERR_OPERATIONS_ERROR;
646                         break;
647                 }
648
649                 ac->next_rid = strtol(nextRid, NULL, 0);
650
651                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
652
653                 talloc_free(ares);
654                 ret = LDB_SUCCESS;
655                 break;
656
657         case LDB_REPLY_REFERRAL:
658                 /* ignore */
659                 talloc_free(ares);
660                 ret = LDB_SUCCESS;
661                 break;
662
663         case LDB_REPLY_DONE:
664
665                 if (ac->next_rid == 0) {
666                         ldb_asprintf_errstring(ldb,
667                                 "Unable to get nextRid from domain entry\n");
668                         ret = LDB_ERR_OPERATIONS_ERROR;
669                         break;
670                 }
671
672                 /* found, go on */
673                 ret = samldb_next_step(ac);
674                 break;
675         }
676
677 done:
678         if (ret != LDB_SUCCESS) {
679                 return ldb_module_done(ac->req, NULL, NULL, ret);
680         }
681
682         return LDB_SUCCESS;
683 }
684
685 /* Find a domain object in the parents of a particular DN.  */
686 static int samldb_get_sid_domain(struct samldb_ctx *ac)
687 {
688         struct ldb_context *ldb;
689         static const char * const attrs[2] = { "nextRid", NULL };
690         struct ldb_request *req;
691         char *filter;
692         int ret;
693
694         ldb = ldb_module_get_ctx(ac->module);
695
696         if (ac->sid == NULL) {
697                 return LDB_ERR_OPERATIONS_ERROR;
698         }
699
700         ac->domain_sid = dom_sid_dup(ac, ac->sid);
701         if (!ac->domain_sid) {
702                 return LDB_ERR_OPERATIONS_ERROR;
703         }
704         /* get the domain component part of the provided SID */
705         ac->domain_sid->num_auths--;
706
707         filter = talloc_asprintf(ac, "(&(objectSid=%s)"
708                                        "(|(objectClass=domain)"
709                                          "(objectClass=builtinDomain)"
710                                          "(objectClass=samba4LocalDomain)))",
711                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
712         if (filter == NULL) {
713                 return LDB_ERR_OPERATIONS_ERROR;
714         }
715
716         ret = ldb_build_search_req(&req, ldb, ac,
717                                    ldb_get_default_basedn(ldb),
718                                    LDB_SCOPE_SUBTREE,
719                                    filter, attrs,
720                                    NULL,
721                                    ac, samldb_get_sid_domain_callback,
722                                    ac->req);
723
724         if (ret != LDB_SUCCESS) {
725                 return ret;
726         }
727
728         ac->next_rid = 0;
729         return ldb_next_request(ac->module, req);
730 }
731
732 static bool samldb_msg_add_sid(struct ldb_message *msg,
733                                 const char *name,
734                                 const struct dom_sid *sid)
735 {
736         struct ldb_val v;
737         enum ndr_err_code ndr_err;
738
739         ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
740                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
741         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
742                 return false;
743         }
744         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
745 }
746
747 static int samldb_new_sid(struct samldb_ctx *ac)
748 {
749
750         if (ac->domain_sid == NULL || ac->next_rid == 0) {
751                 return LDB_ERR_OPERATIONS_ERROR;
752         }
753
754         ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
755         if (ac->sid == NULL) {
756                 return LDB_ERR_OPERATIONS_ERROR;
757         }
758
759         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
760                 return LDB_ERR_OPERATIONS_ERROR;
761         }
762
763         return samldb_next_step(ac);
764 }
765
766 static int samldb_notice_sid_callback(struct ldb_request *req,
767                                         struct ldb_reply *ares)
768 {
769         struct ldb_context *ldb;
770         struct samldb_ctx *ac;
771         int ret;
772
773         ac = talloc_get_type(req->context, struct samldb_ctx);
774         ldb = ldb_module_get_ctx(ac->module);
775
776         if (!ares) {
777                 ret = LDB_ERR_OPERATIONS_ERROR;
778                 goto done;
779         }
780         if (ares->error != LDB_SUCCESS) {
781                 return ldb_module_done(ac->req, ares->controls,
782                                         ares->response, ares->error);
783         }
784         if (ares->type != LDB_REPLY_DONE) {
785                 ldb_set_errstring(ldb,
786                         "Invalid reply type!\n");
787                 ret = LDB_ERR_OPERATIONS_ERROR;
788                 goto done;
789         }
790
791         ret = samldb_next_step(ac);
792
793 done:
794         if (ret != LDB_SUCCESS) {
795                 return ldb_module_done(ac->req, NULL, NULL, ret);
796         }
797
798         return LDB_SUCCESS;
799 }
800
801 /* If we are adding new users/groups, we need to update the nextRid
802  * attribute to be 'above' the new/incoming RID. Attempt to do it
803  *atomically. */
804 static int samldb_notice_sid(struct samldb_ctx *ac)
805 {
806         struct ldb_context *ldb;
807         uint32_t old_id, new_id;
808         struct ldb_request *req;
809         struct ldb_message *msg;
810         struct ldb_message_element *els;
811         struct ldb_val *vals;
812         int ret;
813
814         ldb = ldb_module_get_ctx(ac->module);
815         old_id = ac->next_rid;
816         new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
817
818         if (old_id >= new_id) {
819                 /* no need to update the domain nextRid attribute */
820                 return samldb_next_step(ac);
821         }
822
823         /* we do a delete and add as a single operation. That prevents
824            a race, in case we are not actually on a transaction db */
825         msg = talloc_zero(ac, struct ldb_message);
826         if (msg == NULL) {
827                 ldb_oom(ldb);
828                 return LDB_ERR_OPERATIONS_ERROR;
829         }
830         els = talloc_array(msg, struct ldb_message_element, 2);
831         if (els == NULL) {
832                 ldb_oom(ldb);
833                 return LDB_ERR_OPERATIONS_ERROR;
834         }
835         vals = talloc_array(msg, struct ldb_val, 2);
836         if (vals == NULL) {
837                 ldb_oom(ldb);
838                 return LDB_ERR_OPERATIONS_ERROR;
839         }
840         msg->dn = ac->domain_dn;
841         msg->num_elements = 2;
842         msg->elements = els;
843
844         els[0].num_values = 1;
845         els[0].values = &vals[0];
846         els[0].flags = LDB_FLAG_MOD_DELETE;
847         els[0].name = talloc_strdup(msg, "nextRid");
848         if (!els[0].name) {
849                 ldb_oom(ldb);
850                 return LDB_ERR_OPERATIONS_ERROR;
851         }
852
853         els[1].num_values = 1;
854         els[1].values = &vals[1];
855         els[1].flags = LDB_FLAG_MOD_ADD;
856         els[1].name = els[0].name;
857
858         vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
859         if (!vals[0].data) {
860                 ldb_oom(ldb);
861                 return LDB_ERR_OPERATIONS_ERROR;
862         }
863         vals[0].length = strlen((char *)vals[0].data);
864
865         vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
866         if (!vals[1].data) {
867                 ldb_oom(ldb);
868                 return LDB_ERR_OPERATIONS_ERROR;
869         }
870         vals[1].length = strlen((char *)vals[1].data);
871
872         ret = ldb_build_mod_req(&req, ldb, ac,
873                                 msg, NULL,
874                                 ac, samldb_notice_sid_callback,
875                                 ac->req);
876         if (ret != LDB_SUCCESS) {
877                 return ret;
878         }
879
880         return ldb_next_request(ac->module, req);
881 }
882
883 static int samldb_add_entry_callback(struct ldb_request *req,
884                                         struct ldb_reply *ares)
885 {
886         struct ldb_context *ldb;
887         struct samldb_ctx *ac;
888
889         ac = talloc_get_type(req->context, struct samldb_ctx);
890         ldb = ldb_module_get_ctx(ac->module);
891
892         if (!ares) {
893                 return ldb_module_done(ac->req, NULL, NULL,
894                                         LDB_ERR_OPERATIONS_ERROR);
895         }
896         if (ares->error != LDB_SUCCESS) {
897                 return ldb_module_done(ac->req, ares->controls,
898                                         ares->response, ares->error);
899         }
900         if (ares->type != LDB_REPLY_DONE) {
901                 ldb_set_errstring(ldb,
902                         "Invalid reply type!\n");
903                 return ldb_module_done(ac->req, NULL, NULL,
904                                         LDB_ERR_OPERATIONS_ERROR);
905         }
906
907         /* we exit the samldb module here */
908         return ldb_module_done(ac->req, ares->controls,
909                                 ares->response, LDB_SUCCESS);
910 }
911
912 static int samldb_add_entry(struct samldb_ctx *ac)
913 {
914         struct ldb_context *ldb;
915         struct ldb_request *req;
916         int ret;
917
918         ldb = ldb_module_get_ctx(ac->module);
919
920         ret = ldb_build_add_req(&req, ldb, ac,
921                                 ac->msg,
922                                 ac->req->controls,
923                                 ac, samldb_add_entry_callback,
924                                 ac->req);
925         if (ret != LDB_SUCCESS) {
926                 return ret;
927         }
928
929         return ldb_next_request(ac->module, req);
930 }
931
932 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
933 {
934         int ret;
935
936         /* first look for the template */
937         ac->type = type;
938         ret = samldb_add_step(ac, samldb_search_template);
939         if (ret != LDB_SUCCESS) return ret;
940
941         /* then apply it */
942         ret = samldb_add_step(ac, samldb_apply_template);
943         if (ret != LDB_SUCCESS) return ret;
944
945         /* search for a parent domain objet */
946         ac->check_dn = ac->req->op.add.message->dn;
947         ret = samldb_add_step(ac, samldb_get_parent_domain);
948         if (ret != LDB_SUCCESS) return ret;
949
950         /* check if we have a valid samAccountName */
951         ret = samldb_add_step(ac, samldb_check_samAccountName);
952         if (ret != LDB_SUCCESS) return ret;
953
954         /* check account_type/group_type */
955         ret = samldb_add_step(ac, samldb_check_samAccountType);
956         if (ret != LDB_SUCCESS) return ret;
957
958         /* check if we have a valid SID */
959         ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
960         if ( ! ac->sid) {
961                 ret = samldb_add_step(ac, samldb_new_sid);
962                 if (ret != LDB_SUCCESS) return ret;
963         } else {
964                 ret = samldb_add_step(ac, samldb_get_sid_domain);
965                 if (ret != LDB_SUCCESS) return ret;
966         }
967
968         ret = samldb_add_step(ac, samldb_notice_sid);
969         if (ret != LDB_SUCCESS) return ret;
970
971         /* finally proceed with adding the entry */
972         ret = samldb_add_step(ac, samldb_add_entry);
973         if (ret != LDB_SUCCESS) return ret;
974
975         return samldb_first_step(ac);
976
977         /* TODO: userAccountControl, badPwdCount, codePage,
978          *       countryCode, badPasswordTime, lastLogoff, lastLogon,
979          *       pwdLastSet, primaryGroupID, accountExpires, logonCount */
980
981 }
982
983 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
984                                                 struct ldb_reply *ares)
985 {
986         struct ldb_context *ldb;
987         struct samldb_ctx *ac;
988         const char *nextRid;
989         const char *name;
990         int ret;
991
992         ac = talloc_get_type(req->context, struct samldb_ctx);
993         ldb = ldb_module_get_ctx(ac->module);
994
995         if (!ares) {
996                 ret = LDB_ERR_OPERATIONS_ERROR;
997                 goto done;
998         }
999         if (ares->error != LDB_SUCCESS) {
1000                 return ldb_module_done(ac->req, ares->controls,
1001                                         ares->response, ares->error);
1002         }
1003
1004         switch (ares->type) {
1005         case LDB_REPLY_ENTRY:
1006                 /* save entry */
1007                 if (ac->next_rid != 0) {
1008                         /* one too many! */
1009                         ldb_set_errstring(ldb,
1010                                 "Invalid number of results while searching "
1011                                 "for domain object");
1012                         ret = LDB_ERR_OPERATIONS_ERROR;
1013                         break;
1014                 }
1015
1016                 nextRid = ldb_msg_find_attr_as_string(ares->message,
1017                                                         "nextRid", NULL);
1018                 if (nextRid == NULL) {
1019                         ldb_asprintf_errstring(ldb,
1020                                 "while looking for forign sid %s attribute nextRid not found in %s\n",
1021                                                dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1022                         ret = LDB_ERR_OPERATIONS_ERROR;
1023                         break;
1024                 }
1025
1026                 ac->next_rid = strtol(nextRid, NULL, 0);
1027
1028                 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1029
1030                 name = samdb_result_string(ares->message, "name", NULL);
1031                 ldb_debug(ldb, LDB_DEBUG_TRACE,
1032                          "NOTE (strange but valid): Adding foreign SID "
1033                          "record with SID %s, but this domain (%s) is "
1034                          "not foreign in the database",
1035                          dom_sid_string(ares, ac->sid), name);
1036
1037                 talloc_free(ares);
1038                 break;
1039
1040         case LDB_REPLY_REFERRAL:
1041                 /* ignore */
1042                 talloc_free(ares);
1043                 break;
1044
1045         case LDB_REPLY_DONE:
1046
1047                 /* if this is a fake foreign SID, notice the SID */
1048                 if (ac->domain_dn) {
1049                         ret = samldb_notice_sid(ac);
1050                         break;
1051                 }
1052
1053                 /* found, go on */
1054                 ret = samldb_next_step(ac);
1055                 break;
1056         }
1057
1058 done:
1059         if (ret != LDB_SUCCESS) {
1060                 return ldb_module_done(ac->req, NULL, NULL, ret);
1061         }
1062
1063         return LDB_SUCCESS;
1064 }
1065
1066 /* Find a domain object in the parents of a particular DN. */
1067 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1068 {
1069         struct ldb_context *ldb;
1070         static const char * const attrs[3] = { "nextRid", "name", NULL };
1071         struct ldb_request *req;
1072         NTSTATUS status;
1073         char *filter;
1074         int ret;
1075
1076         ldb = ldb_module_get_ctx(ac->module);
1077
1078         if (ac->sid == NULL) {
1079                 return LDB_ERR_OPERATIONS_ERROR;
1080         }
1081
1082         status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1083         if (!NT_STATUS_IS_OK(status)) {
1084                 return LDB_ERR_OPERATIONS_ERROR;
1085         }
1086
1087         filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1088                                  ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1089         if (filter == NULL) {
1090                 return LDB_ERR_OPERATIONS_ERROR;
1091         }
1092
1093         ret = ldb_build_search_req(&req, ldb, ac,
1094                                    ldb_get_default_basedn(ldb),
1095                                    LDB_SCOPE_SUBTREE,
1096                                    filter, attrs,
1097                                    NULL,
1098                                    ac, samldb_foreign_notice_sid_callback,
1099                                    ac->req);
1100
1101         if (ret != LDB_SUCCESS) {
1102                 return ret;
1103         }
1104
1105         ac->next_rid = 0;
1106         return ldb_next_request(ac->module, req);
1107 }
1108
1109 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1110 {
1111         struct ldb_context *ldb;
1112         int ret;
1113
1114         ldb = ldb_module_get_ctx(ac->module);
1115
1116         ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1117         if (ac->sid == NULL) {
1118                 ac->sid = dom_sid_parse_talloc(ac->msg,
1119                            (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1120                 if (!ac->sid) {
1121                         ldb_set_errstring(ldb,
1122                                         "No valid found SID in "
1123                                         "ForeignSecurityPrincipal CN!");
1124                         talloc_free(ac);
1125                         return LDB_ERR_CONSTRAINT_VIOLATION;
1126                 }
1127                 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1128                         talloc_free(ac);
1129                         return LDB_ERR_OPERATIONS_ERROR;
1130                 }
1131         }
1132
1133         /* first look for the template */
1134         ac->type = "foreignSecurityPrincipal";
1135         ret = samldb_add_step(ac, samldb_search_template);
1136         if (ret != LDB_SUCCESS) return ret;
1137
1138         /* then apply it */
1139         ret = samldb_add_step(ac, samldb_apply_template);
1140         if (ret != LDB_SUCCESS) return ret;
1141
1142         /* check if we need to notice this SID */
1143         ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1144         if (ret != LDB_SUCCESS) return ret;
1145
1146         /* finally proceed with adding the entry */
1147         ret = samldb_add_step(ac, samldb_add_entry);
1148         if (ret != LDB_SUCCESS) return ret;
1149
1150         return samldb_first_step(ac);
1151 }
1152
1153 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1154 {
1155         struct ldb_context *ldb;
1156         const char *rdn_name;
1157
1158         ldb = ldb_module_get_ctx(module);
1159         rdn_name = ldb_dn_get_rdn_name(dn);
1160
1161         if (strcasecmp(rdn_name, "cn") != 0) {
1162                 ldb_asprintf_errstring(ldb,
1163                                         "Bad RDN (%s=) for samldb object, "
1164                                         "should be CN=!\n", rdn_name);
1165                 return LDB_ERR_CONSTRAINT_VIOLATION;
1166         }
1167
1168         return LDB_SUCCESS;
1169 }
1170
1171 /* add_record */
1172 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1173 {
1174         struct ldb_context *ldb;
1175         struct samldb_ctx *ac;
1176         int ret;
1177
1178         ldb = ldb_module_get_ctx(module);
1179         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1180
1181         /* do not manipulate our control entries */
1182         if (ldb_dn_is_special(req->op.add.message->dn)) {
1183                 return ldb_next_request(module, req);
1184         }
1185
1186         ac = samldb_ctx_init(module, req);
1187         if (ac == NULL) {
1188                 return LDB_ERR_OPERATIONS_ERROR;
1189         }
1190
1191         /* build the new msg */
1192         ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1193         if (!ac->msg) {
1194                 talloc_free(ac);
1195                 ldb_debug(ldb, LDB_DEBUG_FATAL,
1196                           "samldb_add: ldb_msg_copy failed!\n");
1197                 return LDB_ERR_OPERATIONS_ERROR;
1198         }
1199
1200         if (samdb_find_attribute(ldb, ac->msg,
1201                                  "objectclass", "computer") != NULL) {
1202
1203                 /* make sure the computer object also has the 'user'
1204                  * objectclass so it will be handled by the next call */
1205                 ret = samdb_find_or_add_value(ldb, ac->msg,
1206                                                 "objectclass", "user");
1207                 if (ret != LDB_SUCCESS) {
1208                         talloc_free(ac);
1209                         return ret;
1210                 }
1211         }
1212
1213         if (samdb_find_attribute(ldb, ac->msg,
1214                                  "objectclass", "user") != NULL) {
1215
1216                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1217                 if (ret != LDB_SUCCESS) {
1218                         talloc_free(ac);
1219                         return ret;
1220                 }
1221
1222                 return samldb_fill_object(ac, "user");
1223         }
1224
1225         if (samdb_find_attribute(ldb, ac->msg,
1226                                  "objectclass", "group") != NULL) {
1227
1228                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1229                 if (ret != LDB_SUCCESS) {
1230                         talloc_free(ac);
1231                         return ret;
1232                 }
1233
1234                 return samldb_fill_object(ac, "group");
1235         }
1236
1237         /* perhaps a foreignSecurityPrincipal? */
1238         if (samdb_find_attribute(ldb, ac->msg,
1239                                  "objectclass",
1240                                  "foreignSecurityPrincipal") != NULL) {
1241
1242                 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1243                 if (ret != LDB_SUCCESS) {
1244                         talloc_free(ac);
1245                         return ret;
1246                 }
1247
1248                 return samldb_fill_foreignSecurityPrincipal_object(ac);
1249         }
1250
1251         talloc_free(ac);
1252
1253         /* nothing matched, go on */
1254         return ldb_next_request(module, req);
1255 }
1256
1257 /* modify */
1258 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1259 {
1260         struct ldb_context *ldb;
1261         struct ldb_message *msg;
1262         struct ldb_message_element *el, *el2;
1263         int ret;
1264         unsigned int group_type, user_account_control, account_type;
1265         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1266                 return ldb_next_request(module, req);
1267         }
1268
1269         ldb = ldb_module_get_ctx(module);
1270
1271         if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1272                 ldb_asprintf_errstring(ldb, "sAMAccountType must not be specified");
1273                 return LDB_ERR_UNWILLING_TO_PERFORM;
1274         }
1275
1276         /* TODO: do not modify original request, create a new one */
1277
1278         el = ldb_msg_find_element(req->op.mod.message, "groupType");
1279         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1280                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1281
1282                 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1283                 account_type =  ds_gtype2atype(group_type);
1284                 ret = samdb_msg_add_uint(ldb, msg, msg,
1285                                          "sAMAccountType",
1286                                          account_type);
1287                 if (ret != LDB_SUCCESS) {
1288                         return ret;
1289                 }
1290                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1291                 el2->flags = LDB_FLAG_MOD_REPLACE;
1292         }
1293
1294         el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1295         if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1296                 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1297
1298                 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1299                 account_type = ds_uf2atype(user_account_control);
1300                 ret = samdb_msg_add_uint(ldb, msg, msg,
1301                                          "sAMAccountType",
1302                                          account_type);
1303                 if (ret != LDB_SUCCESS) {
1304                         return ret;
1305                 }
1306                 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1307                 el2->flags = LDB_FLAG_MOD_REPLACE;
1308         }
1309         return ldb_next_request(module, req);
1310 }
1311
1312
1313 static int samldb_init(struct ldb_module *module)
1314 {
1315         return ldb_next_init(module);
1316 }
1317
1318 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1319         .name          = "samldb",
1320         .init_context  = samldb_init,
1321         .add           = samldb_add,
1322         .modify        = samldb_modify
1323 };