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