4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
5 Copyright (C) Simo Sorce 2004-2008
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
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.
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.
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/>.
28 * Component: ldb samldb module
30 * Description: add embedded user/group creation functionality
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"
49 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
52 struct samldb_step *next;
57 struct ldb_module *module;
58 struct ldb_request *req;
60 /* the resulting message */
61 struct ldb_message *msg;
63 /* used to apply templates */
66 /* used to find parent domain */
67 struct ldb_dn *check_dn;
68 struct ldb_dn *domain_dn;
69 struct dom_sid *domain_sid;
72 /* generic storage, remember to zero it before use */
73 struct ldb_reply *ares;
75 /* holds the entry SID */
78 /* all the async steps necessary to complete the operation */
79 struct samldb_step *steps;
80 struct samldb_step *curstep;
83 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
84 struct ldb_request *req)
86 struct samldb_ctx *ac;
88 ac = talloc_zero(req, struct samldb_ctx);
100 static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
102 struct samldb_step *step;
104 step = talloc_zero(ac, struct samldb_step);
106 return LDB_ERR_OPERATIONS_ERROR;
109 if (ac->steps == NULL) {
113 ac->curstep->next = step;
122 static int samldb_first_step(struct samldb_ctx *ac)
124 if (ac->steps == NULL) {
125 return LDB_ERR_OPERATIONS_ERROR;
128 ac->curstep = ac->steps;
129 return ac->curstep->fn(ac);
132 static int samldb_next_step(struct samldb_ctx *ac)
134 if (ac->curstep->next) {
135 ac->curstep = ac->curstep->next;
136 return ac->curstep->fn(ac);
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;
144 static int samldb_search_template_callback(struct ldb_request *req,
145 struct ldb_reply *ares)
147 struct samldb_ctx *ac;
150 ac = talloc_get_type(req->context, struct samldb_ctx);
153 ret = LDB_ERR_OPERATIONS_ERROR;
156 if (ares->error != LDB_SUCCESS) {
157 return ldb_module_done(ac->req, ares->controls,
158 ares->response, ares->error);
161 switch (ares->type) {
162 case LDB_REPLY_ENTRY:
164 if (ac->ares != NULL) {
166 ldb_set_errstring(ac->module->ldb,
167 "Invalid number of results while searching "
168 "for template objects");
169 ret = LDB_ERR_OPERATIONS_ERROR;
173 ac->ares = talloc_steal(ac, ares);
177 case LDB_REPLY_REFERRAL:
186 ret = samldb_next_step(ac);
191 if (ret != LDB_SUCCESS) {
192 return ldb_module_done(ac->req, NULL, NULL, ret);
198 static int samldb_search_template(struct samldb_ctx *ac)
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;
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;
217 opaque = ldb_get_opaque(ac->module->ldb, "templates_ldb");
218 templates_ldb = talloc_get_type(opaque, struct ldb_context);
220 /* make sure we have the templates ldb */
221 if (!templates_ldb) {
222 templates_ldb_path = samdb_relative_path(ac->module->ldb, ac,
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;
231 ev = ldb_get_event_context(ac->module->ldb);
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);
238 if (!templates_ldb) {
239 return LDB_ERR_OPERATIONS_ERROR;
242 if (!talloc_reference(templates_ldb, ev)) {
243 return LDB_ERR_OPERATIONS_ERROR;
246 ret = ldb_set_opaque(ac->module->ldb,
247 "templates_ldb", templates_ldb);
248 if (ret != LDB_SUCCESS) {
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;
263 /* pull the template record */
264 ret = ldb_build_search_req(&req, templates_ldb, ac,
265 basedn, LDB_SCOPE_BASE,
266 "(distinguishedName=*)", NULL,
268 ac, samldb_search_template_callback,
270 if (ret != LDB_SUCCESS) {
274 talloc_steal(req, basedn);
277 return ldb_request(templates_ldb, req);
280 static int samldb_apply_template(struct samldb_ctx *ac)
282 struct ldb_message_element *el;
283 struct ldb_message *msg;
287 msg = ac->ares->message;
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) {
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;
313 return samldb_next_step(ac);
316 static int samldb_get_parent_domain(struct samldb_ctx *ac);
318 static int samldb_get_parent_domain_callback(struct ldb_request *req,
319 struct ldb_reply *ares)
321 struct samldb_ctx *ac;
325 ac = talloc_get_type(req->context, struct samldb_ctx);
328 ret = LDB_ERR_OPERATIONS_ERROR;
331 if (ares->error != LDB_SUCCESS) {
332 return ldb_module_done(ac->req, ares->controls,
333 ares->response, ares->error);
336 switch (ares->type) {
337 case LDB_REPLY_ENTRY:
339 if (ac->domain_dn != NULL) {
341 ldb_set_errstring(ac->module->ldb,
342 "Invalid number of results while searching "
343 "for domain object");
344 ret = LDB_ERR_OPERATIONS_ERROR;
348 nextRid = ldb_msg_find_attr_as_string(ares->message,
350 if (nextRid == NULL) {
351 ldb_asprintf_errstring(ac->module->ldb,
352 "attribute nextRid not found in %s\n",
353 ldb_dn_get_linearized(ares->message->dn));
354 ret = LDB_ERR_OPERATIONS_ERROR;
358 ac->next_rid = strtol(nextRid, NULL, 0);
360 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
362 if (ac->domain_sid == NULL) {
363 ldb_set_errstring(ac->module->ldb,
364 "error retrieving parent domain domain sid!\n");
365 ret = LDB_ERR_CONSTRAINT_VIOLATION;
368 ac->domain_dn = talloc_steal(ac, ares->message->dn);
374 case LDB_REPLY_REFERRAL:
383 if (ac->domain_dn == NULL) {
385 ret = samldb_get_parent_domain(ac);
388 ret = samldb_next_step(ac);
394 if (ret != LDB_SUCCESS) {
395 return ldb_module_done(ac->req, NULL, NULL, ret);
401 /* Find a domain object in the parents of a particular DN. */
402 static int samldb_get_parent_domain(struct samldb_ctx *ac)
404 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
405 struct ldb_request *req;
409 if (ac->check_dn == NULL) {
410 return LDB_ERR_OPERATIONS_ERROR;
413 dn = ldb_dn_get_parent(ac, ac->check_dn);
415 ldb_set_errstring(ac->module->ldb,
416 "Unable to find parent domain object");
417 return LDB_ERR_CONSTRAINT_VIOLATION;
422 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
424 "(|(objectClass=domain)"
425 "(objectClass=builtinDomain)"
426 "(objectClass=samba4LocalDomain))",
429 ac, samldb_get_parent_domain_callback,
432 if (ret != LDB_SUCCESS) {
436 return ldb_next_request(ac->module, req);
439 static int samldb_generate_samAccountName(struct ldb_message *msg)
443 /* Format: $000000-000000000000 */
445 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
446 (unsigned int)generate_random(),
447 (unsigned int)generate_random(),
448 (unsigned int)generate_random());
450 return LDB_ERR_OPERATIONS_ERROR;
452 return ldb_msg_add_steal_string(msg, "samAccountName", name);
455 static int samldb_check_samAccountName_callback(struct ldb_request *req,
456 struct ldb_reply *ares)
458 struct samldb_ctx *ac;
461 ac = talloc_get_type(req->context, struct samldb_ctx);
464 ret = LDB_ERR_OPERATIONS_ERROR;
467 if (ares->error != LDB_SUCCESS) {
468 return ldb_module_done(ac->req, ares->controls,
469 ares->response, ares->error);
472 switch (ares->type) {
473 case LDB_REPLY_ENTRY:
475 /* if we get an entry it means this samAccountName
477 return ldb_module_done(ac->req, NULL, NULL,
478 LDB_ERR_ENTRY_ALREADY_EXISTS);
480 case LDB_REPLY_REFERRAL:
488 /* not found, go on */
490 ret = samldb_next_step(ac);
495 if (ret != LDB_SUCCESS) {
496 return ldb_module_done(ac->req, NULL, NULL, ret);
502 static int samldb_check_samAccountName(struct samldb_ctx *ac)
504 struct ldb_request *req;
509 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
510 ret = samldb_generate_samAccountName(ac->msg);
511 if (ret != LDB_SUCCESS) {
516 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
518 return LDB_ERR_OPERATIONS_ERROR;
520 filter = talloc_asprintf(ac, "samAccountName=%s", name);
521 if (filter == NULL) {
522 return LDB_ERR_OPERATIONS_ERROR;
525 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
526 ac->domain_dn, LDB_SCOPE_SUBTREE,
529 ac, samldb_check_samAccountName_callback,
532 if (ret != LDB_SUCCESS) {
536 return ldb_next_request(ac->module, req);
539 static int samldb_check_samAccountType(struct samldb_ctx *ac)
541 unsigned int account_type;
542 unsigned int group_type;
546 /* make sure sAMAccountType is not specified */
547 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
548 ldb_asprintf_errstring(ac->module->ldb,
549 "sAMAccountType must not be specified");
550 return LDB_ERR_UNWILLING_TO_PERFORM;
553 if (strcmp("user", ac->type) == 0) {
554 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
556 ldb_asprintf_errstring(ac->module->ldb,
557 "userAccountControl invalid");
558 return LDB_ERR_UNWILLING_TO_PERFORM;
560 account_type = samdb_uf2atype(uac);
561 ret = samdb_msg_add_uint(ac->module->ldb,
565 if (ret != LDB_SUCCESS) {
570 if (strcmp("group", ac->type) == 0) {
572 group_type = samdb_result_uint(ac->msg, "groupType", 0);
573 if (group_type == 0) {
574 ldb_asprintf_errstring(ac->module->ldb,
575 "groupType invalid");
576 return LDB_ERR_UNWILLING_TO_PERFORM;
578 account_type = samdb_gtype2atype(group_type);
579 ret = samdb_msg_add_uint(ac->module->ldb,
583 if (ret != LDB_SUCCESS) {
589 return samldb_next_step(ac);
592 static int samldb_get_sid_domain_callback(struct ldb_request *req,
593 struct ldb_reply *ares)
595 struct samldb_ctx *ac;
599 ac = talloc_get_type(req->context, struct samldb_ctx);
602 ret = LDB_ERR_OPERATIONS_ERROR;
605 if (ares->error != LDB_SUCCESS) {
606 return ldb_module_done(ac->req, ares->controls,
607 ares->response, ares->error);
610 switch (ares->type) {
611 case LDB_REPLY_ENTRY:
613 if (ac->next_rid != 0) {
615 ldb_set_errstring(ac->module->ldb,
616 "Invalid number of results while searching "
617 "for domain object");
618 ret = LDB_ERR_OPERATIONS_ERROR;
622 nextRid = ldb_msg_find_attr_as_string(ares->message,
624 if (nextRid == NULL) {
625 ldb_asprintf_errstring(ac->module->ldb,
626 "attribute nextRid not found in %s\n",
627 ldb_dn_get_linearized(ares->message->dn));
628 ret = LDB_ERR_OPERATIONS_ERROR;
632 ac->next_rid = strtol(nextRid, NULL, 0);
634 ac->domain_dn = talloc_steal(ac, ares->message->dn);
640 case LDB_REPLY_REFERRAL:
648 if (ac->next_rid == 0) {
649 ldb_asprintf_errstring(ac->module->ldb,
650 "Unable to get nextRid from domain entry\n");
651 ret = LDB_ERR_OPERATIONS_ERROR;
656 ret = samldb_next_step(ac);
661 if (ret != LDB_SUCCESS) {
662 return ldb_module_done(ac->req, NULL, NULL, ret);
668 /* Find a domain object in the parents of a particular DN. */
669 static int samldb_get_sid_domain(struct samldb_ctx *ac)
671 static const char * const attrs[2] = { "nextRid", NULL };
672 struct ldb_request *req;
676 if (ac->sid == NULL) {
677 return LDB_ERR_OPERATIONS_ERROR;
680 ac->domain_sid = dom_sid_dup(ac, ac->sid);
681 if (!ac->domain_sid) {
682 return LDB_ERR_OPERATIONS_ERROR;
684 /* get the domain component part of the provided SID */
685 ac->domain_sid->num_auths--;
687 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
688 "(|(objectClass=domain)"
689 "(objectClass=builtinDomain)"
690 "(objectClass=samba4LocalDomain)))",
691 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
692 if (filter == NULL) {
693 return LDB_ERR_OPERATIONS_ERROR;
696 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
697 ldb_get_default_basedn(ac->module->ldb),
701 ac, samldb_get_sid_domain_callback,
704 if (ret != LDB_SUCCESS) {
709 return ldb_next_request(ac->module, req);
712 static bool samldb_msg_add_sid(struct ldb_message *msg,
714 const struct dom_sid *sid)
717 enum ndr_err_code ndr_err;
719 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
720 (ndr_push_flags_fn_t)ndr_push_dom_sid);
721 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
724 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
727 static int samldb_new_sid(struct samldb_ctx *ac)
730 if (ac->domain_sid == NULL || ac->next_rid == 0) {
731 return LDB_ERR_OPERATIONS_ERROR;
734 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
735 if (ac->sid == NULL) {
736 return LDB_ERR_OPERATIONS_ERROR;
739 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
740 return LDB_ERR_OPERATIONS_ERROR;
743 return samldb_next_step(ac);
746 static int samldb_check_sid_callback(struct ldb_request *req,
747 struct ldb_reply *ares)
749 struct samldb_ctx *ac;
752 ac = talloc_get_type(req->context, struct samldb_ctx);
755 ret = LDB_ERR_OPERATIONS_ERROR;
758 if (ares->error != LDB_SUCCESS) {
759 return ldb_module_done(ac->req, ares->controls,
760 ares->response, ares->error);
763 switch (ares->type) {
764 case LDB_REPLY_ENTRY:
766 /* if we get an entry it means an object with the
767 * requested sid exists */
768 return ldb_module_done(ac->req, NULL, NULL,
769 LDB_ERR_CONSTRAINT_VIOLATION);
771 case LDB_REPLY_REFERRAL:
778 /* not found, go on */
780 ret = samldb_next_step(ac);
785 if (ret != LDB_SUCCESS) {
786 return ldb_module_done(ac->req, NULL, NULL, ret);
792 static int samldb_check_sid(struct samldb_ctx *ac)
794 const char *const attrs[2] = { "objectSid", NULL };
795 struct ldb_request *req;
799 if (ac->sid == NULL) {
800 return LDB_ERR_OPERATIONS_ERROR;
803 filter = talloc_asprintf(ac, "(objectSid=%s)",
804 ldap_encode_ndr_dom_sid(ac, ac->sid));
805 if (filter == NULL) {
806 return LDB_ERR_OPERATIONS_ERROR;
809 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
810 ldb_get_default_basedn(ac->module->ldb),
814 ac, samldb_check_sid_callback,
817 if (ret != LDB_SUCCESS) {
821 return ldb_next_request(ac->module, req);
824 static int samldb_notice_sid_callback(struct ldb_request *req,
825 struct ldb_reply *ares)
827 struct samldb_ctx *ac;
830 ac = talloc_get_type(req->context, struct samldb_ctx);
833 ret = LDB_ERR_OPERATIONS_ERROR;
836 if (ares->error != LDB_SUCCESS) {
837 return ldb_module_done(ac->req, ares->controls,
838 ares->response, ares->error);
840 if (ares->type != LDB_REPLY_DONE) {
841 ldb_set_errstring(ac->module->ldb,
842 "Invalid reply type!\n");
843 ret = LDB_ERR_OPERATIONS_ERROR;
847 ret = samldb_next_step(ac);
850 if (ret != LDB_SUCCESS) {
851 return ldb_module_done(ac->req, NULL, NULL, ret);
857 /* If we are adding new users/groups, we need to update the nextRid
858 * attribute to be 'above' the new/incoming RID. Attempt to do it
860 static int samldb_notice_sid(struct samldb_ctx *ac)
862 uint32_t old_id, new_id;
863 struct ldb_request *req;
864 struct ldb_message *msg;
865 struct ldb_message_element *els;
866 struct ldb_val *vals;
869 old_id = ac->next_rid;
870 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
872 if (old_id >= new_id) {
873 /* no need to update the domain nextRid attribute */
874 return samldb_next_step(ac);
877 /* we do a delete and add as a single operation. That prevents
878 a race, in case we are not actually on a transaction db */
879 msg = talloc_zero(ac, struct ldb_message);
881 ldb_oom(ac->module->ldb);
882 return LDB_ERR_OPERATIONS_ERROR;
884 els = talloc_array(msg, struct ldb_message_element, 2);
886 ldb_oom(ac->module->ldb);
887 return LDB_ERR_OPERATIONS_ERROR;
889 vals = talloc_array(msg, struct ldb_val, 2);
891 ldb_oom(ac->module->ldb);
892 return LDB_ERR_OPERATIONS_ERROR;
894 msg->dn = ac->domain_dn;
895 msg->num_elements = 2;
898 els[0].num_values = 1;
899 els[0].values = &vals[0];
900 els[0].flags = LDB_FLAG_MOD_DELETE;
901 els[0].name = talloc_strdup(msg, "nextRid");
903 ldb_oom(ac->module->ldb);
904 return LDB_ERR_OPERATIONS_ERROR;
907 els[1].num_values = 1;
908 els[1].values = &vals[1];
909 els[1].flags = LDB_FLAG_MOD_ADD;
910 els[1].name = els[0].name;
912 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
914 ldb_oom(ac->module->ldb);
915 return LDB_ERR_OPERATIONS_ERROR;
917 vals[0].length = strlen((char *)vals[0].data);
919 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
921 ldb_oom(ac->module->ldb);
922 return LDB_ERR_OPERATIONS_ERROR;
924 vals[1].length = strlen((char *)vals[1].data);
926 ret = ldb_build_mod_req(&req, ac->module->ldb, ac,
928 ac, samldb_notice_sid_callback,
930 if (ret != LDB_SUCCESS) {
934 return ldb_next_request(ac->module, req);
937 static int samldb_add_entry_callback(struct ldb_request *req,
938 struct ldb_reply *ares)
940 struct samldb_ctx *ac;
942 ac = talloc_get_type(req->context, struct samldb_ctx);
945 return ldb_module_done(ac->req, NULL, NULL,
946 LDB_ERR_OPERATIONS_ERROR);
948 if (ares->error != LDB_SUCCESS) {
949 return ldb_module_done(ac->req, ares->controls,
950 ares->response, ares->error);
952 if (ares->type != LDB_REPLY_DONE) {
953 ldb_set_errstring(ac->module->ldb,
954 "Invalid reply type!\n");
955 return ldb_module_done(ac->req, NULL, NULL,
956 LDB_ERR_OPERATIONS_ERROR);
959 /* we exit the samldb module here */
960 return ldb_module_done(ac->req, ares->controls,
961 ares->response, LDB_SUCCESS);
964 static int samldb_add_entry(struct samldb_ctx *ac)
966 struct ldb_request *req;
969 ret = ldb_build_add_req(&req, ac->module->ldb, ac,
972 ac, samldb_add_entry_callback,
974 if (ret != LDB_SUCCESS) {
978 return ldb_next_request(ac->module, req);
981 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
985 /* first look for the template */
987 ret = samldb_add_step(ac, samldb_search_template);
988 if (ret != LDB_SUCCESS) return ret;
991 ret = samldb_add_step(ac, samldb_apply_template);
992 if (ret != LDB_SUCCESS) return ret;
994 /* search for a parent domain objet */
995 ac->check_dn = ac->req->op.add.message->dn;
996 ret = samldb_add_step(ac, samldb_get_parent_domain);
997 if (ret != LDB_SUCCESS) return ret;
999 /* check if we have a valid samAccountName */
1000 ret = samldb_add_step(ac, samldb_check_samAccountName);
1001 if (ret != LDB_SUCCESS) return ret;
1003 /* check account_type/group_type */
1004 ret = samldb_add_step(ac, samldb_check_samAccountType);
1005 if (ret != LDB_SUCCESS) return ret;
1007 /* check if we have a valid SID */
1008 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1010 ret = samldb_add_step(ac, samldb_new_sid);
1011 if (ret != LDB_SUCCESS) return ret;
1013 ret = samldb_add_step(ac, samldb_get_sid_domain);
1014 if (ret != LDB_SUCCESS) return ret;
1017 ret = samldb_add_step(ac, samldb_check_sid);
1018 if (ret != LDB_SUCCESS) return ret;
1020 ret = samldb_add_step(ac, samldb_notice_sid);
1021 if (ret != LDB_SUCCESS) return ret;
1023 /* finally proceed with adding the entry */
1024 ret = samldb_add_step(ac, samldb_add_entry);
1025 if (ret != LDB_SUCCESS) return ret;
1027 return samldb_first_step(ac);
1029 /* TODO: userAccountControl, badPwdCount, codePage,
1030 * countryCode, badPasswordTime, lastLogoff, lastLogon,
1031 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
1035 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1036 struct ldb_reply *ares)
1038 struct samldb_ctx *ac;
1039 const char *nextRid;
1043 ac = talloc_get_type(req->context, struct samldb_ctx);
1046 ret = LDB_ERR_OPERATIONS_ERROR;
1049 if (ares->error != LDB_SUCCESS) {
1050 return ldb_module_done(ac->req, ares->controls,
1051 ares->response, ares->error);
1054 switch (ares->type) {
1055 case LDB_REPLY_ENTRY:
1057 if (ac->next_rid != 0) {
1059 ldb_set_errstring(ac->module->ldb,
1060 "Invalid number of results while searching "
1061 "for domain object");
1062 ret = LDB_ERR_OPERATIONS_ERROR;
1066 nextRid = ldb_msg_find_attr_as_string(ares->message,
1068 if (nextRid == NULL) {
1069 ldb_asprintf_errstring(ac->module->ldb,
1070 "attribute nextRid not found in %s\n",
1071 ldb_dn_get_linearized(ares->message->dn));
1072 ret = LDB_ERR_OPERATIONS_ERROR;
1076 ac->next_rid = strtol(nextRid, NULL, 0);
1078 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1080 name = samdb_result_string(ares->message, "name", NULL);
1081 ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE,
1082 "NOTE (strange but valid): Adding foreign SID "
1083 "record with SID %s, but this domain (%s) is "
1084 "not foreign in the database",
1085 dom_sid_string(ares, ac->sid), name);
1090 case LDB_REPLY_REFERRAL:
1095 case LDB_REPLY_DONE:
1097 /* if this is a fake foreign SID, notice the SID */
1098 if (ac->domain_dn) {
1099 ret = samldb_notice_sid(ac);
1104 ret = samldb_next_step(ac);
1109 if (ret != LDB_SUCCESS) {
1110 return ldb_module_done(ac->req, NULL, NULL, ret);
1116 /* Find a domain object in the parents of a particular DN. */
1117 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1119 static const char * const attrs[3] = { "nextRid", "name", NULL };
1120 struct ldb_request *req;
1124 if (ac->sid == NULL) {
1125 return LDB_ERR_OPERATIONS_ERROR;
1128 ac->domain_sid = dom_sid_dup(ac, ac->sid);
1129 if (!ac->domain_sid) {
1130 return LDB_ERR_OPERATIONS_ERROR;
1132 /* get the domain component part of the provided SID */
1133 ac->domain_sid->num_auths--;
1135 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1136 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1137 if (filter == NULL) {
1138 return LDB_ERR_OPERATIONS_ERROR;
1141 ret = ldb_build_search_req(&req, ac->module->ldb, ac,
1142 ldb_get_default_basedn(ac->module->ldb),
1146 ac, samldb_foreign_notice_sid_callback,
1149 if (ret != LDB_SUCCESS) {
1154 return ldb_next_request(ac->module, req);
1157 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1161 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1162 if (ac->sid == NULL) {
1163 ac->sid = dom_sid_parse_talloc(ac->msg,
1164 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1166 ldb_set_errstring(ac->module->ldb,
1167 "No valid found SID in "
1168 "ForeignSecurityPrincipal CN!");
1170 return LDB_ERR_CONSTRAINT_VIOLATION;
1172 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1174 return LDB_ERR_OPERATIONS_ERROR;
1178 /* first look for the template */
1179 ac->type = "foreignSecurityPrincipal";
1180 ret = samldb_add_step(ac, samldb_search_template);
1181 if (ret != LDB_SUCCESS) return ret;
1184 ret = samldb_add_step(ac, samldb_apply_template);
1185 if (ret != LDB_SUCCESS) return ret;
1187 /* check we do not already have this SID */
1188 ret = samldb_add_step(ac, samldb_check_sid);
1189 if (ret != LDB_SUCCESS) return ret;
1191 /* check if we need to notice this SID */
1192 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1193 if (ret != LDB_SUCCESS) return ret;
1195 /* finally proceed with adding the entry */
1196 ret = samldb_add_step(ac, samldb_add_entry);
1197 if (ret != LDB_SUCCESS) return ret;
1199 return samldb_first_step(ac);
1202 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1204 const char *rdn_name;
1206 rdn_name = ldb_dn_get_rdn_name(dn);
1208 if (strcasecmp(rdn_name, "cn") != 0) {
1209 ldb_asprintf_errstring(module->ldb,
1210 "Bad RDN (%s=) for samldb object, "
1211 "should be CN=!\n", rdn_name);
1212 return LDB_ERR_CONSTRAINT_VIOLATION;
1219 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1221 struct samldb_ctx *ac;
1224 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1226 /* do not manipulate our control entries */
1227 if (ldb_dn_is_special(req->op.add.message->dn)) {
1228 return ldb_next_request(module, req);
1231 ac = samldb_ctx_init(module, req);
1233 return LDB_ERR_OPERATIONS_ERROR;
1236 /* build the new msg */
1237 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1240 ldb_debug(ac->module->ldb, LDB_DEBUG_FATAL,
1241 "samldb_add: ldb_msg_copy failed!\n");
1242 return LDB_ERR_OPERATIONS_ERROR;
1245 if (samdb_find_attribute(module->ldb, ac->msg,
1246 "objectclass", "computer") != NULL) {
1248 /* make sure the computer object also has the 'user'
1249 * objectclass so it will be handled by the next call */
1250 ret = samdb_find_or_add_value(module->ldb, ac->msg,
1251 "objectclass", "user");
1252 if (ret != LDB_SUCCESS) {
1258 if (samdb_find_attribute(module->ldb, ac->msg,
1259 "objectclass", "user") != NULL) {
1261 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1262 if (ret != LDB_SUCCESS) {
1267 return samldb_fill_object(ac, "user");
1270 if (samdb_find_attribute(module->ldb, ac->msg,
1271 "objectclass", "group") != NULL) {
1273 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1274 if (ret != LDB_SUCCESS) {
1279 return samldb_fill_object(ac, "group");
1282 /* perhaps a foreignSecurityPrincipal? */
1283 if (samdb_find_attribute(module->ldb, ac->msg,
1285 "foreignSecurityPrincipal") != NULL) {
1287 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1288 if (ret != LDB_SUCCESS) {
1293 return samldb_fill_foreignSecurityPrincipal_object(ac);
1298 /* nothing matched, go on */
1299 return ldb_next_request(module, req);
1303 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1305 struct ldb_message *msg;
1306 struct ldb_message_element *el, *el2;
1308 unsigned int group_type, user_account_control, account_type;
1309 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1310 return ldb_next_request(module, req);
1313 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1314 ldb_asprintf_errstring(module->ldb, "sAMAccountType must not be specified");
1315 return LDB_ERR_UNWILLING_TO_PERFORM;
1318 /* TODO: do not modify original request, create a new one */
1320 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1321 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1322 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1324 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1325 account_type = samdb_gtype2atype(group_type);
1326 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1329 if (ret != LDB_SUCCESS) {
1332 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1333 el2->flags = LDB_FLAG_MOD_REPLACE;
1336 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1337 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1338 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1340 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1341 account_type = samdb_uf2atype(user_account_control);
1342 ret = samdb_msg_add_uint(module->ldb, msg, msg,
1345 if (ret != LDB_SUCCESS) {
1348 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1349 el2->flags = LDB_FLAG_MOD_REPLACE;
1351 return ldb_next_request(module, req);
1355 static int samldb_init(struct ldb_module *module)
1357 return ldb_next_init(module);
1360 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1362 .init_context = samldb_init,
1364 .modify = samldb_modify