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 "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"
46 typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
49 struct samldb_step *next;
54 struct ldb_module *module;
55 struct ldb_request *req;
57 /* the resulting message */
58 struct ldb_message *msg;
60 /* used to apply templates */
63 /* used to find parent domain */
64 struct ldb_dn *check_dn;
65 struct ldb_dn *domain_dn;
66 struct dom_sid *domain_sid;
69 /* generic storage, remember to zero it before use */
70 struct ldb_reply *ares;
72 /* holds the entry SID */
75 /* all the async steps necessary to complete the operation */
76 struct samldb_step *steps;
77 struct samldb_step *curstep;
80 static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
81 struct ldb_request *req)
83 struct ldb_context *ldb;
84 struct samldb_ctx *ac;
86 ldb = ldb_module_get_ctx(module);
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 ldb_context *ldb;
148 struct samldb_ctx *ac;
151 ac = talloc_get_type(req->context, struct samldb_ctx);
152 ldb = ldb_module_get_ctx(ac->module);
155 ret = LDB_ERR_OPERATIONS_ERROR;
158 if (ares->error != LDB_SUCCESS) {
159 return ldb_module_done(ac->req, ares->controls,
160 ares->response, ares->error);
163 switch (ares->type) {
164 case LDB_REPLY_ENTRY:
166 if (ac->ares != NULL) {
168 ldb_set_errstring(ldb,
169 "Invalid number of results while searching "
170 "for template objects");
171 ret = LDB_ERR_OPERATIONS_ERROR;
175 ac->ares = talloc_steal(ac, ares);
179 case LDB_REPLY_REFERRAL:
188 ret = samldb_next_step(ac);
193 if (ret != LDB_SUCCESS) {
194 return ldb_module_done(ac->req, NULL, NULL, ret);
200 static int samldb_search_template(struct samldb_ctx *ac)
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;
212 ldb = ldb_module_get_ctx(ac->module);
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;
222 opaque = ldb_get_opaque(ldb, "templates_ldb");
223 templates_ldb = talloc_get_type(opaque, struct ldb_context);
225 /* make sure we have the templates ldb */
226 if (!templates_ldb) {
227 templates_ldb_path = samdb_relative_path(ldb, ac,
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;
236 ev = ldb_get_event_context(ldb);
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);
243 if (!templates_ldb) {
244 return LDB_ERR_OPERATIONS_ERROR;
247 ret = ldb_set_opaque(ldb,
248 "templates_ldb", templates_ldb);
249 if (ret != LDB_SUCCESS) {
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;
264 /* pull the template record */
265 ret = ldb_build_search_req(&req, templates_ldb, ac,
266 basedn, LDB_SCOPE_BASE,
267 "(distinguishedName=*)", NULL,
269 ac, samldb_search_template_callback,
271 if (ret != LDB_SUCCESS) {
275 talloc_steal(req, basedn);
278 return ldb_request(templates_ldb, req);
281 static int samldb_apply_template(struct samldb_ctx *ac)
283 struct ldb_context *ldb;
284 struct ldb_message_element *el;
285 struct ldb_message *msg;
289 ldb = ldb_module_get_ctx(ac->module);
290 msg = ac->ares->message;
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) {
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;
315 return samldb_next_step(ac);
318 static int samldb_get_parent_domain(struct samldb_ctx *ac);
320 static int samldb_get_parent_domain_callback(struct ldb_request *req,
321 struct ldb_reply *ares)
323 struct ldb_context *ldb;
324 struct samldb_ctx *ac;
328 ac = talloc_get_type(req->context, struct samldb_ctx);
329 ldb = ldb_module_get_ctx(ac->module);
332 ret = LDB_ERR_OPERATIONS_ERROR;
335 if (ares->error != LDB_SUCCESS) {
336 return ldb_module_done(ac->req, ares->controls,
337 ares->response, ares->error);
340 switch (ares->type) {
341 case LDB_REPLY_ENTRY:
343 if (ac->domain_dn != NULL) {
345 ldb_set_errstring(ldb,
346 "Invalid number of results while searching "
347 "for domain object");
348 ret = LDB_ERR_OPERATIONS_ERROR;
352 nextRid = ldb_msg_find_attr_as_string(ares->message,
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;
363 ac->next_rid = strtol(nextRid, NULL, 0);
365 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
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;
373 ac->domain_dn = talloc_steal(ac, ares->message->dn);
377 ldb_reset_err_string(ldb);
380 case LDB_REPLY_REFERRAL:
389 if (ac->domain_dn == NULL) {
391 ret = samldb_get_parent_domain(ac);
394 ret = samldb_next_step(ac);
400 if (ret != LDB_SUCCESS) {
401 return ldb_module_done(ac->req, NULL, NULL, ret);
407 /* Find a domain object in the parents of a particular DN. */
408 static int samldb_get_parent_domain(struct samldb_ctx *ac)
410 struct ldb_context *ldb;
411 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
412 struct ldb_request *req;
416 ldb = ldb_module_get_ctx(ac->module);
418 if (ac->check_dn == NULL) {
419 return LDB_ERR_OPERATIONS_ERROR;
422 dn = ldb_dn_get_parent(ac, ac->check_dn);
424 ldb_set_errstring(ldb,
425 "Unable to find parent domain object");
426 return LDB_ERR_CONSTRAINT_VIOLATION;
431 ret = ldb_build_search_req(&req, ldb, ac,
433 "(|(objectClass=domain)"
434 "(objectClass=builtinDomain)"
435 "(objectClass=samba4LocalDomain))",
438 ac, samldb_get_parent_domain_callback,
441 if (ret != LDB_SUCCESS) {
445 return ldb_next_request(ac->module, req);
448 static int samldb_generate_samAccountName(struct ldb_message *msg)
452 /* Format: $000000-000000000000 */
454 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
455 (unsigned int)generate_random(),
456 (unsigned int)generate_random(),
457 (unsigned int)generate_random());
459 return LDB_ERR_OPERATIONS_ERROR;
461 return ldb_msg_add_steal_string(msg, "samAccountName", name);
465 static int samldb_check_samAccountName_callback(struct ldb_request *req,
466 struct ldb_reply *ares)
468 struct samldb_ctx *ac;
471 ac = talloc_get_type(req->context, struct samldb_ctx);
473 if (ares->error != LDB_SUCCESS) {
474 return ldb_module_done(ac->req, ares->controls,
475 ares->response, ares->error);
478 switch (ares->type) {
479 case LDB_REPLY_ENTRY:
480 /* if we get an entry it means this samAccountName
482 return ldb_module_done(ac->req, NULL, NULL,
483 LDB_ERR_ENTRY_ALREADY_EXISTS);
485 case LDB_REPLY_REFERRAL:
486 /* this should not happen */
487 return ldb_module_done(ac->req, NULL, NULL,
488 LDB_ERR_OPERATIONS_ERROR);
491 /* not found, go on */
493 ret = samldb_next_step(ac);
497 if (ret != LDB_SUCCESS) {
498 return ldb_module_done(ac->req, NULL, NULL, ret);
505 static int samldb_check_samAccountName(struct samldb_ctx *ac)
507 struct ldb_context *ldb;
508 struct ldb_request *req;
513 ldb = ldb_module_get_ctx(ac->module);
515 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
516 ret = samldb_generate_samAccountName(ac->msg);
517 if (ret != LDB_SUCCESS) {
522 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
524 return LDB_ERR_OPERATIONS_ERROR;
526 filter = talloc_asprintf(ac, "samAccountName=%s", ldb_binary_encode_string(ac, name));
527 if (filter == NULL) {
528 return LDB_ERR_OPERATIONS_ERROR;
531 ret = ldb_build_search_req(&req, ldb, ac,
532 ac->domain_dn, LDB_SCOPE_SUBTREE,
535 ac, samldb_check_samAccountName_callback,
538 if (ret != LDB_SUCCESS) {
542 return ldb_next_request(ac->module, req);
546 static int samldb_check_samAccountType(struct samldb_ctx *ac)
548 struct ldb_context *ldb;
549 unsigned int account_type;
550 unsigned int group_type;
554 ldb = ldb_module_get_ctx(ac->module);
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;
563 if (strcmp("user", ac->type) == 0) {
564 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
566 ldb_asprintf_errstring(ldb,
567 "userAccountControl invalid");
568 return LDB_ERR_UNWILLING_TO_PERFORM;
570 account_type = ds_uf2atype(uac);
571 ret = samdb_msg_add_uint(ldb,
575 if (ret != LDB_SUCCESS) {
580 if (strcmp("group", ac->type) == 0) {
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;
588 account_type = ds_gtype2atype(group_type);
589 ret = samdb_msg_add_uint(ldb,
593 if (ret != LDB_SUCCESS) {
599 return samldb_next_step(ac);
602 static int samldb_get_sid_domain_callback(struct ldb_request *req,
603 struct ldb_reply *ares)
605 struct ldb_context *ldb;
606 struct samldb_ctx *ac;
610 ac = talloc_get_type(req->context, struct samldb_ctx);
611 ldb = ldb_module_get_ctx(ac->module);
614 ret = LDB_ERR_OPERATIONS_ERROR;
617 if (ares->error != LDB_SUCCESS) {
618 return ldb_module_done(ac->req, ares->controls,
619 ares->response, ares->error);
622 switch (ares->type) {
623 case LDB_REPLY_ENTRY:
625 if (ac->next_rid != 0) {
627 ldb_set_errstring(ldb,
628 "Invalid number of results while searching "
629 "for domain object");
630 ret = LDB_ERR_OPERATIONS_ERROR;
634 nextRid = ldb_msg_find_attr_as_string(ares->message,
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;
644 ac->next_rid = strtol(nextRid, NULL, 0);
646 ac->domain_dn = talloc_steal(ac, ares->message->dn);
652 case LDB_REPLY_REFERRAL:
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;
668 ret = samldb_next_step(ac);
673 if (ret != LDB_SUCCESS) {
674 return ldb_module_done(ac->req, NULL, NULL, ret);
680 /* Find a domain object in the parents of a particular DN. */
681 static int samldb_get_sid_domain(struct samldb_ctx *ac)
683 struct ldb_context *ldb;
684 static const char * const attrs[2] = { "nextRid", NULL };
685 struct ldb_request *req;
689 ldb = ldb_module_get_ctx(ac->module);
691 if (ac->sid == NULL) {
692 return LDB_ERR_OPERATIONS_ERROR;
695 ac->domain_sid = dom_sid_dup(ac, ac->sid);
696 if (!ac->domain_sid) {
697 return LDB_ERR_OPERATIONS_ERROR;
699 /* get the domain component part of the provided SID */
700 ac->domain_sid->num_auths--;
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;
711 ret = ldb_build_search_req(&req, ldb, ac,
712 ldb_get_default_basedn(ldb),
716 ac, samldb_get_sid_domain_callback,
719 if (ret != LDB_SUCCESS) {
724 return ldb_next_request(ac->module, req);
727 static bool samldb_msg_add_sid(struct ldb_message *msg,
729 const struct dom_sid *sid)
732 enum ndr_err_code ndr_err;
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)) {
739 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
742 static int samldb_new_sid(struct samldb_ctx *ac)
745 if (ac->domain_sid == NULL || ac->next_rid == 0) {
746 return LDB_ERR_OPERATIONS_ERROR;
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;
754 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
755 return LDB_ERR_OPERATIONS_ERROR;
758 return samldb_next_step(ac);
761 static int samldb_notice_sid_callback(struct ldb_request *req,
762 struct ldb_reply *ares)
764 struct ldb_context *ldb;
765 struct samldb_ctx *ac;
768 ac = talloc_get_type(req->context, struct samldb_ctx);
769 ldb = ldb_module_get_ctx(ac->module);
772 ret = LDB_ERR_OPERATIONS_ERROR;
775 if (ares->error != LDB_SUCCESS) {
776 return ldb_module_done(ac->req, ares->controls,
777 ares->response, ares->error);
779 if (ares->type != LDB_REPLY_DONE) {
780 ldb_set_errstring(ldb,
781 "Invalid reply type!\n");
782 ret = LDB_ERR_OPERATIONS_ERROR;
786 ret = samldb_next_step(ac);
789 if (ret != LDB_SUCCESS) {
790 return ldb_module_done(ac->req, NULL, NULL, ret);
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
799 static int samldb_notice_sid(struct samldb_ctx *ac)
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;
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];
813 if (old_id >= new_id) {
814 /* no need to update the domain nextRid attribute */
815 return samldb_next_step(ac);
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);
823 return LDB_ERR_OPERATIONS_ERROR;
825 els = talloc_array(msg, struct ldb_message_element, 2);
828 return LDB_ERR_OPERATIONS_ERROR;
830 vals = talloc_array(msg, struct ldb_val, 2);
833 return LDB_ERR_OPERATIONS_ERROR;
835 msg->dn = ac->domain_dn;
836 msg->num_elements = 2;
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");
845 return LDB_ERR_OPERATIONS_ERROR;
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;
853 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
856 return LDB_ERR_OPERATIONS_ERROR;
858 vals[0].length = strlen((char *)vals[0].data);
860 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
863 return LDB_ERR_OPERATIONS_ERROR;
865 vals[1].length = strlen((char *)vals[1].data);
867 ret = ldb_build_mod_req(&req, ldb, ac,
869 ac, samldb_notice_sid_callback,
871 if (ret != LDB_SUCCESS) {
875 return ldb_next_request(ac->module, req);
878 static int samldb_add_entry_callback(struct ldb_request *req,
879 struct ldb_reply *ares)
881 struct ldb_context *ldb;
882 struct samldb_ctx *ac;
884 ac = talloc_get_type(req->context, struct samldb_ctx);
885 ldb = ldb_module_get_ctx(ac->module);
888 return ldb_module_done(ac->req, NULL, NULL,
889 LDB_ERR_OPERATIONS_ERROR);
891 if (ares->error != LDB_SUCCESS) {
892 return ldb_module_done(ac->req, ares->controls,
893 ares->response, ares->error);
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);
902 /* we exit the samldb module here */
903 return ldb_module_done(ac->req, ares->controls,
904 ares->response, LDB_SUCCESS);
907 static int samldb_add_entry(struct samldb_ctx *ac)
909 struct ldb_context *ldb;
910 struct ldb_request *req;
913 ldb = ldb_module_get_ctx(ac->module);
915 ret = ldb_build_add_req(&req, ldb, ac,
918 ac, samldb_add_entry_callback,
920 if (ret != LDB_SUCCESS) {
924 return ldb_next_request(ac->module, req);
927 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
931 /* first look for the template */
933 ret = samldb_add_step(ac, samldb_search_template);
934 if (ret != LDB_SUCCESS) return ret;
937 ret = samldb_add_step(ac, samldb_apply_template);
938 if (ret != LDB_SUCCESS) return ret;
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;
945 /* check if we have a valid samAccountName */
946 ret = samldb_add_step(ac, samldb_check_samAccountName);
947 if (ret != LDB_SUCCESS) return ret;
949 /* check account_type/group_type */
950 ret = samldb_add_step(ac, samldb_check_samAccountType);
951 if (ret != LDB_SUCCESS) return ret;
953 /* check if we have a valid SID */
954 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
956 ret = samldb_add_step(ac, samldb_new_sid);
957 if (ret != LDB_SUCCESS) return ret;
959 ret = samldb_add_step(ac, samldb_get_sid_domain);
960 if (ret != LDB_SUCCESS) return ret;
963 ret = samldb_add_step(ac, samldb_notice_sid);
964 if (ret != LDB_SUCCESS) return ret;
966 /* finally proceed with adding the entry */
967 ret = samldb_add_step(ac, samldb_add_entry);
968 if (ret != LDB_SUCCESS) return ret;
970 return samldb_first_step(ac);
972 /* TODO: userAccountControl, badPwdCount, codePage,
973 * countryCode, badPasswordTime, lastLogoff, lastLogon,
974 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
978 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
979 struct ldb_reply *ares)
981 struct ldb_context *ldb;
982 struct samldb_ctx *ac;
987 ac = talloc_get_type(req->context, struct samldb_ctx);
988 ldb = ldb_module_get_ctx(ac->module);
991 ret = LDB_ERR_OPERATIONS_ERROR;
994 if (ares->error != LDB_SUCCESS) {
995 return ldb_module_done(ac->req, ares->controls,
996 ares->response, ares->error);
999 switch (ares->type) {
1000 case LDB_REPLY_ENTRY:
1002 if (ac->next_rid != 0) {
1004 ldb_set_errstring(ldb,
1005 "Invalid number of results while searching "
1006 "for domain object");
1007 ret = LDB_ERR_OPERATIONS_ERROR;
1011 nextRid = ldb_msg_find_attr_as_string(ares->message,
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;
1021 ac->next_rid = strtol(nextRid, NULL, 0);
1023 ac->domain_dn = talloc_steal(ac, ares->message->dn);
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);
1035 case LDB_REPLY_REFERRAL:
1040 case LDB_REPLY_DONE:
1042 /* if this is a fake foreign SID, notice the SID */
1043 if (ac->domain_dn) {
1044 ret = samldb_notice_sid(ac);
1049 ret = samldb_next_step(ac);
1054 if (ret != LDB_SUCCESS) {
1055 return ldb_module_done(ac->req, NULL, NULL, ret);
1061 /* Find a domain object in the parents of a particular DN. */
1062 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1064 struct ldb_context *ldb;
1065 static const char * const attrs[3] = { "nextRid", "name", NULL };
1066 struct ldb_request *req;
1071 ldb = ldb_module_get_ctx(ac->module);
1073 if (ac->sid == NULL) {
1074 return LDB_ERR_OPERATIONS_ERROR;
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;
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;
1088 ret = ldb_build_search_req(&req, ldb, ac,
1089 ldb_get_default_basedn(ldb),
1093 ac, samldb_foreign_notice_sid_callback,
1096 if (ret != LDB_SUCCESS) {
1101 return ldb_next_request(ac->module, req);
1104 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1106 struct ldb_context *ldb;
1109 ldb = ldb_module_get_ctx(ac->module);
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);
1116 ldb_set_errstring(ldb,
1117 "No valid found SID in "
1118 "ForeignSecurityPrincipal CN!");
1120 return LDB_ERR_CONSTRAINT_VIOLATION;
1122 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1124 return LDB_ERR_OPERATIONS_ERROR;
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;
1134 ret = samldb_add_step(ac, samldb_apply_template);
1135 if (ret != LDB_SUCCESS) return ret;
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;
1141 /* finally proceed with adding the entry */
1142 ret = samldb_add_step(ac, samldb_add_entry);
1143 if (ret != LDB_SUCCESS) return ret;
1145 return samldb_first_step(ac);
1148 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1150 struct ldb_context *ldb;
1151 const char *rdn_name;
1153 ldb = ldb_module_get_ctx(module);
1154 rdn_name = ldb_dn_get_rdn_name(dn);
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;
1167 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1169 struct ldb_context *ldb;
1170 struct samldb_ctx *ac;
1173 ldb = ldb_module_get_ctx(module);
1174 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
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);
1181 ac = samldb_ctx_init(module, req);
1183 return LDB_ERR_OPERATIONS_ERROR;
1186 /* build the new msg */
1187 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1190 ldb_debug(ldb, LDB_DEBUG_FATAL,
1191 "samldb_add: ldb_msg_copy failed!\n");
1192 return LDB_ERR_OPERATIONS_ERROR;
1195 if (samdb_find_attribute(ldb, ac->msg,
1196 "objectclass", "computer") != NULL) {
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) {
1208 if (samdb_find_attribute(ldb, ac->msg,
1209 "objectclass", "user") != NULL) {
1211 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1212 if (ret != LDB_SUCCESS) {
1217 return samldb_fill_object(ac, "user");
1220 if (samdb_find_attribute(ldb, ac->msg,
1221 "objectclass", "group") != NULL) {
1223 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1224 if (ret != LDB_SUCCESS) {
1229 return samldb_fill_object(ac, "group");
1232 /* perhaps a foreignSecurityPrincipal? */
1233 if (samdb_find_attribute(ldb, ac->msg,
1235 "foreignSecurityPrincipal") != NULL) {
1237 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1238 if (ret != LDB_SUCCESS) {
1243 return samldb_fill_foreignSecurityPrincipal_object(ac);
1248 /* nothing matched, go on */
1249 return ldb_next_request(module, req);
1253 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1255 struct ldb_context *ldb;
1256 struct ldb_message *msg;
1257 struct ldb_message_element *el, *el2;
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);
1264 ldb = ldb_module_get_ctx(module);
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;
1271 /* TODO: do not modify original request, create a new one */
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);
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,
1282 if (ret != LDB_SUCCESS) {
1285 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1286 el2->flags = LDB_FLAG_MOD_REPLACE;
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);
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,
1298 if (ret != LDB_SUCCESS) {
1301 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1302 el2->flags = LDB_FLAG_MOD_REPLACE;
1304 return ldb_next_request(module, req);
1308 static int samldb_init(struct ldb_module *module)
1310 return ldb_next_init(module);
1313 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1315 .init_context = samldb_init,
1317 .modify = samldb_modify