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