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