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, "sAMAccountName") == 0 ||
300 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
301 ldb_attr_cmp(el->name, "objectGUID") == 0) {
304 for (j = 0; j < el->num_values; j++) {
305 ret = samdb_find_or_add_attribute(
306 ldb, ac->msg, el->name,
307 (char *)el->values[j].data);
308 if (ret != LDB_SUCCESS) {
309 ldb_set_errstring(ldb,
310 "Failed adding template attribute\n");
311 return LDB_ERR_OPERATIONS_ERROR;
316 return samldb_next_step(ac);
319 static int samldb_get_parent_domain(struct samldb_ctx *ac);
321 static int samldb_get_parent_domain_callback(struct ldb_request *req,
322 struct ldb_reply *ares)
324 struct ldb_context *ldb;
325 struct samldb_ctx *ac;
329 ac = talloc_get_type(req->context, struct samldb_ctx);
330 ldb = ldb_module_get_ctx(ac->module);
333 ret = LDB_ERR_OPERATIONS_ERROR;
336 if (ares->error != LDB_SUCCESS) {
337 return ldb_module_done(ac->req, ares->controls,
338 ares->response, ares->error);
341 switch (ares->type) {
342 case LDB_REPLY_ENTRY:
344 if (ac->domain_dn != NULL) {
346 ldb_set_errstring(ldb,
347 "Invalid number of results while searching "
348 "for domain object");
349 ret = LDB_ERR_OPERATIONS_ERROR;
353 nextRid = ldb_msg_find_attr_as_string(ares->message,
355 if (nextRid == NULL) {
356 ldb_asprintf_errstring(ldb,
357 "while looking for domain above %s attribute nextRid not found in %s\n",
358 ldb_dn_get_linearized(ac->req->op.add.message->dn),
359 ldb_dn_get_linearized(ares->message->dn));
360 ret = LDB_ERR_OPERATIONS_ERROR;
364 ac->next_rid = strtol(nextRid, NULL, 0);
366 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
368 if (ac->domain_sid == NULL) {
369 ldb_set_errstring(ldb,
370 "error retrieving parent domain domain sid!\n");
371 ret = LDB_ERR_CONSTRAINT_VIOLATION;
374 ac->domain_dn = talloc_steal(ac, ares->message->dn);
378 ldb_reset_err_string(ldb);
381 case LDB_REPLY_REFERRAL:
390 if (ac->domain_dn == NULL) {
392 ret = samldb_get_parent_domain(ac);
395 ret = samldb_next_step(ac);
401 if (ret != LDB_SUCCESS) {
402 return ldb_module_done(ac->req, NULL, NULL, ret);
408 /* Find a domain object in the parents of a particular DN. */
409 static int samldb_get_parent_domain(struct samldb_ctx *ac)
411 struct ldb_context *ldb;
412 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
413 struct ldb_request *req;
417 ldb = ldb_module_get_ctx(ac->module);
419 if (ac->check_dn == NULL) {
420 return LDB_ERR_OPERATIONS_ERROR;
423 dn = ldb_dn_get_parent(ac, ac->check_dn);
425 ldb_set_errstring(ldb,
426 "Unable to find parent domain object");
427 return LDB_ERR_CONSTRAINT_VIOLATION;
432 ret = ldb_build_search_req(&req, ldb, ac,
434 "(|(objectClass=domain)"
435 "(objectClass=builtinDomain)"
436 "(objectClass=samba4LocalDomain))",
439 ac, samldb_get_parent_domain_callback,
442 if (ret != LDB_SUCCESS) {
446 return ldb_next_request(ac->module, req);
449 static int samldb_generate_samAccountName(struct ldb_message *msg)
453 /* Format: $000000-000000000000 */
455 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
456 (unsigned int)generate_random(),
457 (unsigned int)generate_random(),
458 (unsigned int)generate_random());
460 return LDB_ERR_OPERATIONS_ERROR;
462 return ldb_msg_add_steal_string(msg, "samAccountName", name);
466 static int samldb_check_samAccountName_callback(struct ldb_request *req,
467 struct ldb_reply *ares)
469 struct samldb_ctx *ac;
472 ac = talloc_get_type(req->context, struct samldb_ctx);
474 if (ares->error != LDB_SUCCESS) {
475 return ldb_module_done(ac->req, ares->controls,
476 ares->response, ares->error);
479 switch (ares->type) {
480 case LDB_REPLY_ENTRY:
481 /* if we get an entry it means this samAccountName
483 return ldb_module_done(ac->req, NULL, NULL,
484 LDB_ERR_ENTRY_ALREADY_EXISTS);
486 case LDB_REPLY_REFERRAL:
487 /* this should not happen */
488 return ldb_module_done(ac->req, NULL, NULL,
489 LDB_ERR_OPERATIONS_ERROR);
492 /* not found, go on */
494 ret = samldb_next_step(ac);
498 if (ret != LDB_SUCCESS) {
499 return ldb_module_done(ac->req, NULL, NULL, ret);
506 static int samldb_check_samAccountName(struct samldb_ctx *ac)
508 struct ldb_context *ldb;
509 struct ldb_request *req;
514 ldb = ldb_module_get_ctx(ac->module);
516 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
517 ret = samldb_generate_samAccountName(ac->msg);
518 if (ret != LDB_SUCCESS) {
523 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
525 return LDB_ERR_OPERATIONS_ERROR;
527 filter = talloc_asprintf(ac, "samAccountName=%s", ldb_binary_encode_string(ac, name));
528 if (filter == NULL) {
529 return LDB_ERR_OPERATIONS_ERROR;
532 ret = ldb_build_search_req(&req, ldb, ac,
533 ac->domain_dn, LDB_SCOPE_SUBTREE,
536 ac, samldb_check_samAccountName_callback,
539 if (ret != LDB_SUCCESS) {
543 return ldb_next_request(ac->module, req);
547 static int samldb_check_samAccountType(struct samldb_ctx *ac)
549 struct ldb_context *ldb;
550 unsigned int account_type;
551 unsigned int group_type;
555 ldb = ldb_module_get_ctx(ac->module);
557 /* make sure sAMAccountType is not specified */
558 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
559 ldb_asprintf_errstring(ldb,
560 "sAMAccountType must not be specified");
561 return LDB_ERR_UNWILLING_TO_PERFORM;
564 if (strcmp("user", ac->type) == 0) {
565 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
567 ldb_asprintf_errstring(ldb,
568 "userAccountControl invalid");
569 return LDB_ERR_UNWILLING_TO_PERFORM;
571 account_type = ds_uf2atype(uac);
572 ret = samdb_msg_add_uint(ldb,
576 if (ret != LDB_SUCCESS) {
581 if (strcmp("group", ac->type) == 0) {
583 group_type = samdb_result_uint(ac->msg, "groupType", 0);
584 if (group_type == 0) {
585 ldb_asprintf_errstring(ldb,
586 "groupType invalid");
587 return LDB_ERR_UNWILLING_TO_PERFORM;
589 account_type = ds_gtype2atype(group_type);
590 ret = samdb_msg_add_uint(ldb,
594 if (ret != LDB_SUCCESS) {
600 return samldb_next_step(ac);
603 static int samldb_get_sid_domain_callback(struct ldb_request *req,
604 struct ldb_reply *ares)
606 struct ldb_context *ldb;
607 struct samldb_ctx *ac;
611 ac = talloc_get_type(req->context, struct samldb_ctx);
612 ldb = ldb_module_get_ctx(ac->module);
615 ret = LDB_ERR_OPERATIONS_ERROR;
618 if (ares->error != LDB_SUCCESS) {
619 return ldb_module_done(ac->req, ares->controls,
620 ares->response, ares->error);
623 switch (ares->type) {
624 case LDB_REPLY_ENTRY:
626 if (ac->next_rid != 0) {
628 ldb_set_errstring(ldb,
629 "Invalid number of results while searching "
630 "for domain object");
631 ret = LDB_ERR_OPERATIONS_ERROR;
635 nextRid = ldb_msg_find_attr_as_string(ares->message,
637 if (nextRid == NULL) {
638 ldb_asprintf_errstring(ldb,
639 "attribute nextRid not found in %s\n",
640 ldb_dn_get_linearized(ares->message->dn));
641 ret = LDB_ERR_OPERATIONS_ERROR;
645 ac->next_rid = strtol(nextRid, NULL, 0);
647 ac->domain_dn = talloc_steal(ac, ares->message->dn);
653 case LDB_REPLY_REFERRAL:
661 if (ac->next_rid == 0) {
662 ldb_asprintf_errstring(ldb,
663 "Unable to get nextRid from domain entry\n");
664 ret = LDB_ERR_OPERATIONS_ERROR;
669 ret = samldb_next_step(ac);
674 if (ret != LDB_SUCCESS) {
675 return ldb_module_done(ac->req, NULL, NULL, ret);
681 /* Find a domain object in the parents of a particular DN. */
682 static int samldb_get_sid_domain(struct samldb_ctx *ac)
684 struct ldb_context *ldb;
685 static const char * const attrs[2] = { "nextRid", NULL };
686 struct ldb_request *req;
690 ldb = ldb_module_get_ctx(ac->module);
692 if (ac->sid == NULL) {
693 return LDB_ERR_OPERATIONS_ERROR;
696 ac->domain_sid = dom_sid_dup(ac, ac->sid);
697 if (!ac->domain_sid) {
698 return LDB_ERR_OPERATIONS_ERROR;
700 /* get the domain component part of the provided SID */
701 ac->domain_sid->num_auths--;
703 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
704 "(|(objectClass=domain)"
705 "(objectClass=builtinDomain)"
706 "(objectClass=samba4LocalDomain)))",
707 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
708 if (filter == NULL) {
709 return LDB_ERR_OPERATIONS_ERROR;
712 ret = ldb_build_search_req(&req, ldb, ac,
713 ldb_get_default_basedn(ldb),
717 ac, samldb_get_sid_domain_callback,
720 if (ret != LDB_SUCCESS) {
725 return ldb_next_request(ac->module, req);
728 static bool samldb_msg_add_sid(struct ldb_message *msg,
730 const struct dom_sid *sid)
733 enum ndr_err_code ndr_err;
735 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
736 (ndr_push_flags_fn_t)ndr_push_dom_sid);
737 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
740 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
743 static int samldb_new_sid(struct samldb_ctx *ac)
746 if (ac->domain_sid == NULL || ac->next_rid == 0) {
747 return LDB_ERR_OPERATIONS_ERROR;
750 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
751 if (ac->sid == NULL) {
752 return LDB_ERR_OPERATIONS_ERROR;
755 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
756 return LDB_ERR_OPERATIONS_ERROR;
759 return samldb_next_step(ac);
762 static int samldb_notice_sid_callback(struct ldb_request *req,
763 struct ldb_reply *ares)
765 struct ldb_context *ldb;
766 struct samldb_ctx *ac;
769 ac = talloc_get_type(req->context, struct samldb_ctx);
770 ldb = ldb_module_get_ctx(ac->module);
773 ret = LDB_ERR_OPERATIONS_ERROR;
776 if (ares->error != LDB_SUCCESS) {
777 return ldb_module_done(ac->req, ares->controls,
778 ares->response, ares->error);
780 if (ares->type != LDB_REPLY_DONE) {
781 ldb_set_errstring(ldb,
782 "Invalid reply type!\n");
783 ret = LDB_ERR_OPERATIONS_ERROR;
787 ret = samldb_next_step(ac);
790 if (ret != LDB_SUCCESS) {
791 return ldb_module_done(ac->req, NULL, NULL, ret);
797 /* If we are adding new users/groups, we need to update the nextRid
798 * attribute to be 'above' the new/incoming RID. Attempt to do it
800 static int samldb_notice_sid(struct samldb_ctx *ac)
802 struct ldb_context *ldb;
803 uint32_t old_id, new_id;
804 struct ldb_request *req;
805 struct ldb_message *msg;
806 struct ldb_message_element *els;
807 struct ldb_val *vals;
810 ldb = ldb_module_get_ctx(ac->module);
811 old_id = ac->next_rid;
812 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
814 if (old_id >= new_id) {
815 /* no need to update the domain nextRid attribute */
816 return samldb_next_step(ac);
819 /* we do a delete and add as a single operation. That prevents
820 a race, in case we are not actually on a transaction db */
821 msg = talloc_zero(ac, struct ldb_message);
824 return LDB_ERR_OPERATIONS_ERROR;
826 els = talloc_array(msg, struct ldb_message_element, 2);
829 return LDB_ERR_OPERATIONS_ERROR;
831 vals = talloc_array(msg, struct ldb_val, 2);
834 return LDB_ERR_OPERATIONS_ERROR;
836 msg->dn = ac->domain_dn;
837 msg->num_elements = 2;
840 els[0].num_values = 1;
841 els[0].values = &vals[0];
842 els[0].flags = LDB_FLAG_MOD_DELETE;
843 els[0].name = talloc_strdup(msg, "nextRid");
846 return LDB_ERR_OPERATIONS_ERROR;
849 els[1].num_values = 1;
850 els[1].values = &vals[1];
851 els[1].flags = LDB_FLAG_MOD_ADD;
852 els[1].name = els[0].name;
854 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
857 return LDB_ERR_OPERATIONS_ERROR;
859 vals[0].length = strlen((char *)vals[0].data);
861 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
864 return LDB_ERR_OPERATIONS_ERROR;
866 vals[1].length = strlen((char *)vals[1].data);
868 ret = ldb_build_mod_req(&req, ldb, ac,
870 ac, samldb_notice_sid_callback,
872 if (ret != LDB_SUCCESS) {
876 return ldb_next_request(ac->module, req);
879 static int samldb_add_entry_callback(struct ldb_request *req,
880 struct ldb_reply *ares)
882 struct ldb_context *ldb;
883 struct samldb_ctx *ac;
885 ac = talloc_get_type(req->context, struct samldb_ctx);
886 ldb = ldb_module_get_ctx(ac->module);
889 return ldb_module_done(ac->req, NULL, NULL,
890 LDB_ERR_OPERATIONS_ERROR);
892 if (ares->error != LDB_SUCCESS) {
893 return ldb_module_done(ac->req, ares->controls,
894 ares->response, ares->error);
896 if (ares->type != LDB_REPLY_DONE) {
897 ldb_set_errstring(ldb,
898 "Invalid reply type!\n");
899 return ldb_module_done(ac->req, NULL, NULL,
900 LDB_ERR_OPERATIONS_ERROR);
903 /* we exit the samldb module here */
904 return ldb_module_done(ac->req, ares->controls,
905 ares->response, LDB_SUCCESS);
908 static int samldb_add_entry(struct samldb_ctx *ac)
910 struct ldb_context *ldb;
911 struct ldb_request *req;
914 ldb = ldb_module_get_ctx(ac->module);
916 ret = ldb_build_add_req(&req, ldb, ac,
919 ac, samldb_add_entry_callback,
921 if (ret != LDB_SUCCESS) {
925 return ldb_next_request(ac->module, req);
928 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
932 /* first look for the template */
934 ret = samldb_add_step(ac, samldb_search_template);
935 if (ret != LDB_SUCCESS) return ret;
938 ret = samldb_add_step(ac, samldb_apply_template);
939 if (ret != LDB_SUCCESS) return ret;
941 /* search for a parent domain objet */
942 ac->check_dn = ac->req->op.add.message->dn;
943 ret = samldb_add_step(ac, samldb_get_parent_domain);
944 if (ret != LDB_SUCCESS) return ret;
946 /* check if we have a valid samAccountName */
947 ret = samldb_add_step(ac, samldb_check_samAccountName);
948 if (ret != LDB_SUCCESS) return ret;
950 /* check account_type/group_type */
951 ret = samldb_add_step(ac, samldb_check_samAccountType);
952 if (ret != LDB_SUCCESS) return ret;
954 /* check if we have a valid SID */
955 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
957 ret = samldb_add_step(ac, samldb_new_sid);
958 if (ret != LDB_SUCCESS) return ret;
960 ret = samldb_add_step(ac, samldb_get_sid_domain);
961 if (ret != LDB_SUCCESS) return ret;
964 ret = samldb_add_step(ac, samldb_notice_sid);
965 if (ret != LDB_SUCCESS) return ret;
967 /* finally proceed with adding the entry */
968 ret = samldb_add_step(ac, samldb_add_entry);
969 if (ret != LDB_SUCCESS) return ret;
971 return samldb_first_step(ac);
973 /* TODO: userAccountControl, badPwdCount, codePage,
974 * countryCode, badPasswordTime, lastLogoff, lastLogon,
975 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
979 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
980 struct ldb_reply *ares)
982 struct ldb_context *ldb;
983 struct samldb_ctx *ac;
988 ac = talloc_get_type(req->context, struct samldb_ctx);
989 ldb = ldb_module_get_ctx(ac->module);
992 ret = LDB_ERR_OPERATIONS_ERROR;
995 if (ares->error != LDB_SUCCESS) {
996 return ldb_module_done(ac->req, ares->controls,
997 ares->response, ares->error);
1000 switch (ares->type) {
1001 case LDB_REPLY_ENTRY:
1003 if (ac->next_rid != 0) {
1005 ldb_set_errstring(ldb,
1006 "Invalid number of results while searching "
1007 "for domain object");
1008 ret = LDB_ERR_OPERATIONS_ERROR;
1012 nextRid = ldb_msg_find_attr_as_string(ares->message,
1014 if (nextRid == NULL) {
1015 ldb_asprintf_errstring(ldb,
1016 "while looking for forign sid %s attribute nextRid not found in %s\n",
1017 dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1018 ret = LDB_ERR_OPERATIONS_ERROR;
1022 ac->next_rid = strtol(nextRid, NULL, 0);
1024 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1026 name = samdb_result_string(ares->message, "name", NULL);
1027 ldb_debug(ldb, LDB_DEBUG_TRACE,
1028 "NOTE (strange but valid): Adding foreign SID "
1029 "record with SID %s, but this domain (%s) is "
1030 "not foreign in the database",
1031 dom_sid_string(ares, ac->sid), name);
1036 case LDB_REPLY_REFERRAL:
1041 case LDB_REPLY_DONE:
1043 /* if this is a fake foreign SID, notice the SID */
1044 if (ac->domain_dn) {
1045 ret = samldb_notice_sid(ac);
1050 ret = samldb_next_step(ac);
1055 if (ret != LDB_SUCCESS) {
1056 return ldb_module_done(ac->req, NULL, NULL, ret);
1062 /* Find a domain object in the parents of a particular DN. */
1063 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1065 struct ldb_context *ldb;
1066 static const char * const attrs[3] = { "nextRid", "name", NULL };
1067 struct ldb_request *req;
1072 ldb = ldb_module_get_ctx(ac->module);
1074 if (ac->sid == NULL) {
1075 return LDB_ERR_OPERATIONS_ERROR;
1078 status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1079 if (!NT_STATUS_IS_OK(status)) {
1080 return LDB_ERR_OPERATIONS_ERROR;
1083 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1084 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1085 if (filter == NULL) {
1086 return LDB_ERR_OPERATIONS_ERROR;
1089 ret = ldb_build_search_req(&req, ldb, ac,
1090 ldb_get_default_basedn(ldb),
1094 ac, samldb_foreign_notice_sid_callback,
1097 if (ret != LDB_SUCCESS) {
1102 return ldb_next_request(ac->module, req);
1105 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1107 struct ldb_context *ldb;
1110 ldb = ldb_module_get_ctx(ac->module);
1112 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1113 if (ac->sid == NULL) {
1114 ac->sid = dom_sid_parse_talloc(ac->msg,
1115 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1117 ldb_set_errstring(ldb,
1118 "No valid found SID in "
1119 "ForeignSecurityPrincipal CN!");
1121 return LDB_ERR_CONSTRAINT_VIOLATION;
1123 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1125 return LDB_ERR_OPERATIONS_ERROR;
1129 /* first look for the template */
1130 ac->type = "foreignSecurityPrincipal";
1131 ret = samldb_add_step(ac, samldb_search_template);
1132 if (ret != LDB_SUCCESS) return ret;
1135 ret = samldb_add_step(ac, samldb_apply_template);
1136 if (ret != LDB_SUCCESS) return ret;
1138 /* check if we need to notice this SID */
1139 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1140 if (ret != LDB_SUCCESS) return ret;
1142 /* finally proceed with adding the entry */
1143 ret = samldb_add_step(ac, samldb_add_entry);
1144 if (ret != LDB_SUCCESS) return ret;
1146 return samldb_first_step(ac);
1149 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1151 struct ldb_context *ldb;
1152 const char *rdn_name;
1154 ldb = ldb_module_get_ctx(module);
1155 rdn_name = ldb_dn_get_rdn_name(dn);
1157 if (strcasecmp(rdn_name, "cn") != 0) {
1158 ldb_asprintf_errstring(ldb,
1159 "Bad RDN (%s=) for samldb object, "
1160 "should be CN=!\n", rdn_name);
1161 return LDB_ERR_CONSTRAINT_VIOLATION;
1168 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1170 struct ldb_context *ldb;
1171 struct samldb_ctx *ac;
1174 ldb = ldb_module_get_ctx(module);
1175 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1177 /* do not manipulate our control entries */
1178 if (ldb_dn_is_special(req->op.add.message->dn)) {
1179 return ldb_next_request(module, req);
1182 ac = samldb_ctx_init(module, req);
1184 return LDB_ERR_OPERATIONS_ERROR;
1187 /* build the new msg */
1188 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1191 ldb_debug(ldb, LDB_DEBUG_FATAL,
1192 "samldb_add: ldb_msg_copy failed!\n");
1193 return LDB_ERR_OPERATIONS_ERROR;
1196 if (samdb_find_attribute(ldb, ac->msg,
1197 "objectclass", "computer") != NULL) {
1199 /* make sure the computer object also has the 'user'
1200 * objectclass so it will be handled by the next call */
1201 ret = samdb_find_or_add_value(ldb, ac->msg,
1202 "objectclass", "user");
1203 if (ret != LDB_SUCCESS) {
1209 if (samdb_find_attribute(ldb, ac->msg,
1210 "objectclass", "user") != NULL) {
1212 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1213 if (ret != LDB_SUCCESS) {
1218 return samldb_fill_object(ac, "user");
1221 if (samdb_find_attribute(ldb, ac->msg,
1222 "objectclass", "group") != NULL) {
1224 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1225 if (ret != LDB_SUCCESS) {
1230 return samldb_fill_object(ac, "group");
1233 /* perhaps a foreignSecurityPrincipal? */
1234 if (samdb_find_attribute(ldb, ac->msg,
1236 "foreignSecurityPrincipal") != NULL) {
1238 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1239 if (ret != LDB_SUCCESS) {
1244 return samldb_fill_foreignSecurityPrincipal_object(ac);
1249 /* nothing matched, go on */
1250 return ldb_next_request(module, req);
1254 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1256 struct ldb_context *ldb;
1257 struct ldb_message *msg;
1258 struct ldb_message_element *el, *el2;
1260 unsigned int group_type, user_account_control, account_type;
1261 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1262 return ldb_next_request(module, req);
1265 ldb = ldb_module_get_ctx(module);
1267 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1268 ldb_asprintf_errstring(ldb, "sAMAccountType must not be specified");
1269 return LDB_ERR_UNWILLING_TO_PERFORM;
1272 /* TODO: do not modify original request, create a new one */
1274 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1275 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1276 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1278 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1279 account_type = ds_gtype2atype(group_type);
1280 ret = samdb_msg_add_uint(ldb, msg, msg,
1283 if (ret != LDB_SUCCESS) {
1286 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1287 el2->flags = LDB_FLAG_MOD_REPLACE;
1290 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1291 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1292 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1294 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1295 account_type = ds_uf2atype(user_account_control);
1296 ret = samdb_msg_add_uint(ldb, msg, msg,
1299 if (ret != LDB_SUCCESS) {
1302 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1303 el2->flags = LDB_FLAG_MOD_REPLACE;
1305 return ldb_next_request(module, req);
1309 static int samldb_init(struct ldb_module *module)
1311 return ldb_next_init(module);
1314 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1316 .init_context = samldb_init,
1318 .modify = samldb_modify