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 if (!talloc_reference(templates_ldb, ev)) {
248 return LDB_ERR_OPERATIONS_ERROR;
251 ret = ldb_set_opaque(ldb,
252 "templates_ldb", templates_ldb);
253 if (ret != LDB_SUCCESS) {
258 /* search template */
259 basedn = ldb_dn_new_fmt(ac, templates_ldb,
260 "cn=Template%s,cn=Templates", ac->type);
261 if (basedn == NULL) {
262 ldb_set_errstring(ldb,
263 "samldb_init_template: ERROR: Failed "
264 "to contruct DN for template");
265 return LDB_ERR_OPERATIONS_ERROR;
268 /* pull the template record */
269 ret = ldb_build_search_req(&req, templates_ldb, ac,
270 basedn, LDB_SCOPE_BASE,
271 "(distinguishedName=*)", NULL,
273 ac, samldb_search_template_callback,
275 if (ret != LDB_SUCCESS) {
279 talloc_steal(req, basedn);
282 return ldb_request(templates_ldb, req);
285 static int samldb_apply_template(struct samldb_ctx *ac)
287 struct ldb_context *ldb;
288 struct ldb_message_element *el;
289 struct ldb_message *msg;
293 ldb = ldb_module_get_ctx(ac->module);
294 msg = ac->ares->message;
296 for (i = 0; i < msg->num_elements; i++) {
297 el = &msg->elements[i];
298 /* some elements should not be copied */
299 if (ldb_attr_cmp(el->name, "cn") == 0 ||
300 ldb_attr_cmp(el->name, "name") == 0 ||
301 ldb_attr_cmp(el->name, "objectClass") == 0 ||
302 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
303 ldb_attr_cmp(el->name, "sAMAccountName") == 0 ||
304 ldb_attr_cmp(el->name, "distinguishedName") == 0 ||
305 ldb_attr_cmp(el->name, "objectGUID") == 0) {
308 for (j = 0; j < el->num_values; j++) {
309 ret = samdb_find_or_add_attribute(
310 ldb, ac->msg, el->name,
311 (char *)el->values[j].data);
312 if (ret != LDB_SUCCESS) {
313 ldb_set_errstring(ldb,
314 "Failed adding template attribute\n");
315 return LDB_ERR_OPERATIONS_ERROR;
320 return samldb_next_step(ac);
323 static int samldb_get_parent_domain(struct samldb_ctx *ac);
325 static int samldb_get_parent_domain_callback(struct ldb_request *req,
326 struct ldb_reply *ares)
328 struct ldb_context *ldb;
329 struct samldb_ctx *ac;
333 ac = talloc_get_type(req->context, struct samldb_ctx);
334 ldb = ldb_module_get_ctx(ac->module);
337 ret = LDB_ERR_OPERATIONS_ERROR;
340 if (ares->error != LDB_SUCCESS) {
341 return ldb_module_done(ac->req, ares->controls,
342 ares->response, ares->error);
345 switch (ares->type) {
346 case LDB_REPLY_ENTRY:
348 if (ac->domain_dn != NULL) {
350 ldb_set_errstring(ldb,
351 "Invalid number of results while searching "
352 "for domain object");
353 ret = LDB_ERR_OPERATIONS_ERROR;
357 nextRid = ldb_msg_find_attr_as_string(ares->message,
359 if (nextRid == NULL) {
360 ldb_asprintf_errstring(ldb,
361 "while looking for domain above %s attribute nextRid not found in %s\n",
362 ldb_dn_get_linearized(ac->req->op.add.message->dn),
363 ldb_dn_get_linearized(ares->message->dn));
364 ret = LDB_ERR_OPERATIONS_ERROR;
368 ac->next_rid = strtol(nextRid, NULL, 0);
370 ac->domain_sid = samdb_result_dom_sid(ac, ares->message,
372 if (ac->domain_sid == NULL) {
373 ldb_set_errstring(ldb,
374 "error retrieving parent domain domain sid!\n");
375 ret = LDB_ERR_CONSTRAINT_VIOLATION;
378 ac->domain_dn = talloc_steal(ac, ares->message->dn);
382 ldb_reset_err_string(ldb);
385 case LDB_REPLY_REFERRAL:
394 if (ac->domain_dn == NULL) {
396 ret = samldb_get_parent_domain(ac);
399 ret = samldb_next_step(ac);
405 if (ret != LDB_SUCCESS) {
406 return ldb_module_done(ac->req, NULL, NULL, ret);
412 /* Find a domain object in the parents of a particular DN. */
413 static int samldb_get_parent_domain(struct samldb_ctx *ac)
415 struct ldb_context *ldb;
416 static const char * const attrs[3] = { "objectSid", "nextRid", NULL };
417 struct ldb_request *req;
421 ldb = ldb_module_get_ctx(ac->module);
423 if (ac->check_dn == NULL) {
424 return LDB_ERR_OPERATIONS_ERROR;
427 dn = ldb_dn_get_parent(ac, ac->check_dn);
429 ldb_set_errstring(ldb,
430 "Unable to find parent domain object");
431 return LDB_ERR_CONSTRAINT_VIOLATION;
436 ret = ldb_build_search_req(&req, ldb, ac,
438 "(|(objectClass=domain)"
439 "(objectClass=builtinDomain)"
440 "(objectClass=samba4LocalDomain))",
443 ac, samldb_get_parent_domain_callback,
446 if (ret != LDB_SUCCESS) {
450 return ldb_next_request(ac->module, req);
453 static int samldb_generate_samAccountName(struct ldb_message *msg)
457 /* Format: $000000-000000000000 */
459 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
460 (unsigned int)generate_random(),
461 (unsigned int)generate_random(),
462 (unsigned int)generate_random());
464 return LDB_ERR_OPERATIONS_ERROR;
466 return ldb_msg_add_steal_string(msg, "samAccountName", name);
469 static int samldb_check_samAccountName_callback(struct ldb_request *req,
470 struct ldb_reply *ares)
472 struct samldb_ctx *ac;
475 ac = talloc_get_type(req->context, struct samldb_ctx);
478 ret = LDB_ERR_OPERATIONS_ERROR;
481 if (ares->error != LDB_SUCCESS) {
482 return ldb_module_done(ac->req, ares->controls,
483 ares->response, ares->error);
486 switch (ares->type) {
487 case LDB_REPLY_ENTRY:
489 /* if we get an entry it means this samAccountName
491 return ldb_module_done(ac->req, NULL, NULL,
492 LDB_ERR_ENTRY_ALREADY_EXISTS);
494 case LDB_REPLY_REFERRAL:
502 /* not found, go on */
504 ret = samldb_next_step(ac);
509 if (ret != LDB_SUCCESS) {
510 return ldb_module_done(ac->req, NULL, NULL, ret);
516 static int samldb_check_samAccountName(struct samldb_ctx *ac)
518 struct ldb_context *ldb;
519 struct ldb_request *req;
524 ldb = ldb_module_get_ctx(ac->module);
526 if (ldb_msg_find_element(ac->msg, "samAccountName") == NULL) {
527 ret = samldb_generate_samAccountName(ac->msg);
528 if (ret != LDB_SUCCESS) {
533 name = ldb_msg_find_attr_as_string(ac->msg, "samAccountName", NULL);
535 return LDB_ERR_OPERATIONS_ERROR;
537 filter = talloc_asprintf(ac, "samAccountName=%s", name);
538 if (filter == NULL) {
539 return LDB_ERR_OPERATIONS_ERROR;
542 ret = ldb_build_search_req(&req, ldb, ac,
543 ac->domain_dn, LDB_SCOPE_SUBTREE,
546 ac, samldb_check_samAccountName_callback,
549 if (ret != LDB_SUCCESS) {
553 return ldb_next_request(ac->module, req);
556 static int samldb_check_samAccountType(struct samldb_ctx *ac)
558 struct ldb_context *ldb;
559 unsigned int account_type;
560 unsigned int group_type;
564 ldb = ldb_module_get_ctx(ac->module);
566 /* make sure sAMAccountType is not specified */
567 if (ldb_msg_find_element(ac->msg, "sAMAccountType") != NULL) {
568 ldb_asprintf_errstring(ldb,
569 "sAMAccountType must not be specified");
570 return LDB_ERR_UNWILLING_TO_PERFORM;
573 if (strcmp("user", ac->type) == 0) {
574 uac = samdb_result_uint(ac->msg, "userAccountControl", 0);
576 ldb_asprintf_errstring(ldb,
577 "userAccountControl invalid");
578 return LDB_ERR_UNWILLING_TO_PERFORM;
580 account_type = samdb_uf2atype(uac);
581 ret = samdb_msg_add_uint(ldb,
585 if (ret != LDB_SUCCESS) {
590 if (strcmp("group", ac->type) == 0) {
592 group_type = samdb_result_uint(ac->msg, "groupType", 0);
593 if (group_type == 0) {
594 ldb_asprintf_errstring(ldb,
595 "groupType invalid");
596 return LDB_ERR_UNWILLING_TO_PERFORM;
598 account_type = samdb_gtype2atype(group_type);
599 ret = samdb_msg_add_uint(ldb,
603 if (ret != LDB_SUCCESS) {
609 return samldb_next_step(ac);
612 static int samldb_get_sid_domain_callback(struct ldb_request *req,
613 struct ldb_reply *ares)
615 struct ldb_context *ldb;
616 struct samldb_ctx *ac;
620 ac = talloc_get_type(req->context, struct samldb_ctx);
621 ldb = ldb_module_get_ctx(ac->module);
624 ret = LDB_ERR_OPERATIONS_ERROR;
627 if (ares->error != LDB_SUCCESS) {
628 return ldb_module_done(ac->req, ares->controls,
629 ares->response, ares->error);
632 switch (ares->type) {
633 case LDB_REPLY_ENTRY:
635 if (ac->next_rid != 0) {
637 ldb_set_errstring(ldb,
638 "Invalid number of results while searching "
639 "for domain object");
640 ret = LDB_ERR_OPERATIONS_ERROR;
644 nextRid = ldb_msg_find_attr_as_string(ares->message,
646 if (nextRid == NULL) {
647 ldb_asprintf_errstring(ldb,
648 "attribute nextRid not found in %s\n",
649 ldb_dn_get_linearized(ares->message->dn));
650 ret = LDB_ERR_OPERATIONS_ERROR;
654 ac->next_rid = strtol(nextRid, NULL, 0);
656 ac->domain_dn = talloc_steal(ac, ares->message->dn);
662 case LDB_REPLY_REFERRAL:
670 if (ac->next_rid == 0) {
671 ldb_asprintf_errstring(ldb,
672 "Unable to get nextRid from domain entry\n");
673 ret = LDB_ERR_OPERATIONS_ERROR;
678 ret = samldb_next_step(ac);
683 if (ret != LDB_SUCCESS) {
684 return ldb_module_done(ac->req, NULL, NULL, ret);
690 /* Find a domain object in the parents of a particular DN. */
691 static int samldb_get_sid_domain(struct samldb_ctx *ac)
693 struct ldb_context *ldb;
694 static const char * const attrs[2] = { "nextRid", NULL };
695 struct ldb_request *req;
699 ldb = ldb_module_get_ctx(ac->module);
701 if (ac->sid == NULL) {
702 return LDB_ERR_OPERATIONS_ERROR;
705 ac->domain_sid = dom_sid_dup(ac, ac->sid);
706 if (!ac->domain_sid) {
707 return LDB_ERR_OPERATIONS_ERROR;
709 /* get the domain component part of the provided SID */
710 ac->domain_sid->num_auths--;
712 filter = talloc_asprintf(ac, "(&(objectSid=%s)"
713 "(|(objectClass=domain)"
714 "(objectClass=builtinDomain)"
715 "(objectClass=samba4LocalDomain)))",
716 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
717 if (filter == NULL) {
718 return LDB_ERR_OPERATIONS_ERROR;
721 ret = ldb_build_search_req(&req, ldb, ac,
722 ldb_get_default_basedn(ldb),
726 ac, samldb_get_sid_domain_callback,
729 if (ret != LDB_SUCCESS) {
734 return ldb_next_request(ac->module, req);
737 static bool samldb_msg_add_sid(struct ldb_message *msg,
739 const struct dom_sid *sid)
742 enum ndr_err_code ndr_err;
744 ndr_err = ndr_push_struct_blob(&v, msg, NULL, sid,
745 (ndr_push_flags_fn_t)ndr_push_dom_sid);
746 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
749 return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
752 static int samldb_new_sid(struct samldb_ctx *ac)
755 if (ac->domain_sid == NULL || ac->next_rid == 0) {
756 return LDB_ERR_OPERATIONS_ERROR;
759 ac->sid = dom_sid_add_rid(ac, ac->domain_sid, ac->next_rid + 1);
760 if (ac->sid == NULL) {
761 return LDB_ERR_OPERATIONS_ERROR;
764 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
765 return LDB_ERR_OPERATIONS_ERROR;
768 return samldb_next_step(ac);
771 static int samldb_check_sid_callback(struct ldb_request *req,
772 struct ldb_reply *ares)
774 struct samldb_ctx *ac;
777 ac = talloc_get_type(req->context, struct samldb_ctx);
780 ret = LDB_ERR_OPERATIONS_ERROR;
783 if (ares->error != LDB_SUCCESS) {
784 return ldb_module_done(ac->req, ares->controls,
785 ares->response, ares->error);
788 switch (ares->type) {
789 case LDB_REPLY_ENTRY:
791 /* if we get an entry it means an object with the
792 * requested sid exists */
793 return ldb_module_done(ac->req, NULL, NULL,
794 LDB_ERR_CONSTRAINT_VIOLATION);
796 case LDB_REPLY_REFERRAL:
803 /* not found, go on */
805 ret = samldb_next_step(ac);
810 if (ret != LDB_SUCCESS) {
811 return ldb_module_done(ac->req, NULL, NULL, ret);
817 static int samldb_check_sid(struct samldb_ctx *ac)
819 struct ldb_context *ldb;
820 const char *const attrs[2] = { "objectSid", NULL };
821 struct ldb_request *req;
825 if (ac->sid == NULL) {
826 return LDB_ERR_OPERATIONS_ERROR;
829 ldb = ldb_module_get_ctx(ac->module);
831 filter = talloc_asprintf(ac, "(objectSid=%s)",
832 ldap_encode_ndr_dom_sid(ac, ac->sid));
833 if (filter == NULL) {
834 return LDB_ERR_OPERATIONS_ERROR;
837 ret = ldb_build_search_req(&req, ldb, ac,
838 ldb_get_default_basedn(ldb),
842 ac, samldb_check_sid_callback,
845 if (ret != LDB_SUCCESS) {
849 return ldb_next_request(ac->module, req);
852 static int samldb_notice_sid_callback(struct ldb_request *req,
853 struct ldb_reply *ares)
855 struct ldb_context *ldb;
856 struct samldb_ctx *ac;
859 ac = talloc_get_type(req->context, struct samldb_ctx);
860 ldb = ldb_module_get_ctx(ac->module);
863 ret = LDB_ERR_OPERATIONS_ERROR;
866 if (ares->error != LDB_SUCCESS) {
867 return ldb_module_done(ac->req, ares->controls,
868 ares->response, ares->error);
870 if (ares->type != LDB_REPLY_DONE) {
871 ldb_set_errstring(ldb,
872 "Invalid reply type!\n");
873 ret = LDB_ERR_OPERATIONS_ERROR;
877 ret = samldb_next_step(ac);
880 if (ret != LDB_SUCCESS) {
881 return ldb_module_done(ac->req, NULL, NULL, ret);
887 /* If we are adding new users/groups, we need to update the nextRid
888 * attribute to be 'above' the new/incoming RID. Attempt to do it
890 static int samldb_notice_sid(struct samldb_ctx *ac)
892 struct ldb_context *ldb;
893 uint32_t old_id, new_id;
894 struct ldb_request *req;
895 struct ldb_message *msg;
896 struct ldb_message_element *els;
897 struct ldb_val *vals;
900 ldb = ldb_module_get_ctx(ac->module);
901 old_id = ac->next_rid;
902 new_id = ac->sid->sub_auths[ac->sid->num_auths - 1];
904 if (old_id >= new_id) {
905 /* no need to update the domain nextRid attribute */
906 return samldb_next_step(ac);
909 /* we do a delete and add as a single operation. That prevents
910 a race, in case we are not actually on a transaction db */
911 msg = talloc_zero(ac, struct ldb_message);
914 return LDB_ERR_OPERATIONS_ERROR;
916 els = talloc_array(msg, struct ldb_message_element, 2);
919 return LDB_ERR_OPERATIONS_ERROR;
921 vals = talloc_array(msg, struct ldb_val, 2);
924 return LDB_ERR_OPERATIONS_ERROR;
926 msg->dn = ac->domain_dn;
927 msg->num_elements = 2;
930 els[0].num_values = 1;
931 els[0].values = &vals[0];
932 els[0].flags = LDB_FLAG_MOD_DELETE;
933 els[0].name = talloc_strdup(msg, "nextRid");
936 return LDB_ERR_OPERATIONS_ERROR;
939 els[1].num_values = 1;
940 els[1].values = &vals[1];
941 els[1].flags = LDB_FLAG_MOD_ADD;
942 els[1].name = els[0].name;
944 vals[0].data = (uint8_t *)talloc_asprintf(vals, "%u", old_id);
947 return LDB_ERR_OPERATIONS_ERROR;
949 vals[0].length = strlen((char *)vals[0].data);
951 vals[1].data = (uint8_t *)talloc_asprintf(vals, "%u", new_id);
954 return LDB_ERR_OPERATIONS_ERROR;
956 vals[1].length = strlen((char *)vals[1].data);
958 ret = ldb_build_mod_req(&req, ldb, ac,
960 ac, samldb_notice_sid_callback,
962 if (ret != LDB_SUCCESS) {
966 return ldb_next_request(ac->module, req);
969 static int samldb_add_entry_callback(struct ldb_request *req,
970 struct ldb_reply *ares)
972 struct ldb_context *ldb;
973 struct samldb_ctx *ac;
975 ac = talloc_get_type(req->context, struct samldb_ctx);
976 ldb = ldb_module_get_ctx(ac->module);
979 return ldb_module_done(ac->req, NULL, NULL,
980 LDB_ERR_OPERATIONS_ERROR);
982 if (ares->error != LDB_SUCCESS) {
983 return ldb_module_done(ac->req, ares->controls,
984 ares->response, ares->error);
986 if (ares->type != LDB_REPLY_DONE) {
987 ldb_set_errstring(ldb,
988 "Invalid reply type!\n");
989 return ldb_module_done(ac->req, NULL, NULL,
990 LDB_ERR_OPERATIONS_ERROR);
993 /* we exit the samldb module here */
994 return ldb_module_done(ac->req, ares->controls,
995 ares->response, LDB_SUCCESS);
998 static int samldb_add_entry(struct samldb_ctx *ac)
1000 struct ldb_context *ldb;
1001 struct ldb_request *req;
1004 ldb = ldb_module_get_ctx(ac->module);
1006 ret = ldb_build_add_req(&req, ldb, ac,
1009 ac, samldb_add_entry_callback,
1011 if (ret != LDB_SUCCESS) {
1015 return ldb_next_request(ac->module, req);
1018 static int samldb_fill_object(struct samldb_ctx *ac, const char *type)
1022 /* first look for the template */
1024 ret = samldb_add_step(ac, samldb_search_template);
1025 if (ret != LDB_SUCCESS) return ret;
1028 ret = samldb_add_step(ac, samldb_apply_template);
1029 if (ret != LDB_SUCCESS) return ret;
1031 /* search for a parent domain objet */
1032 ac->check_dn = ac->req->op.add.message->dn;
1033 ret = samldb_add_step(ac, samldb_get_parent_domain);
1034 if (ret != LDB_SUCCESS) return ret;
1036 /* check if we have a valid samAccountName */
1037 ret = samldb_add_step(ac, samldb_check_samAccountName);
1038 if (ret != LDB_SUCCESS) return ret;
1040 /* check account_type/group_type */
1041 ret = samldb_add_step(ac, samldb_check_samAccountType);
1042 if (ret != LDB_SUCCESS) return ret;
1044 /* check if we have a valid SID */
1045 ac->sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
1047 ret = samldb_add_step(ac, samldb_new_sid);
1048 if (ret != LDB_SUCCESS) return ret;
1050 ret = samldb_add_step(ac, samldb_get_sid_domain);
1051 if (ret != LDB_SUCCESS) return ret;
1054 ret = samldb_add_step(ac, samldb_check_sid);
1055 if (ret != LDB_SUCCESS) return ret;
1057 ret = samldb_add_step(ac, samldb_notice_sid);
1058 if (ret != LDB_SUCCESS) return ret;
1060 /* finally proceed with adding the entry */
1061 ret = samldb_add_step(ac, samldb_add_entry);
1062 if (ret != LDB_SUCCESS) return ret;
1064 return samldb_first_step(ac);
1066 /* TODO: userAccountControl, badPwdCount, codePage,
1067 * countryCode, badPasswordTime, lastLogoff, lastLogon,
1068 * pwdLastSet, primaryGroupID, accountExpires, logonCount */
1072 static int samldb_foreign_notice_sid_callback(struct ldb_request *req,
1073 struct ldb_reply *ares)
1075 struct ldb_context *ldb;
1076 struct samldb_ctx *ac;
1077 const char *nextRid;
1081 ac = talloc_get_type(req->context, struct samldb_ctx);
1082 ldb = ldb_module_get_ctx(ac->module);
1085 ret = LDB_ERR_OPERATIONS_ERROR;
1088 if (ares->error != LDB_SUCCESS) {
1089 return ldb_module_done(ac->req, ares->controls,
1090 ares->response, ares->error);
1093 switch (ares->type) {
1094 case LDB_REPLY_ENTRY:
1096 if (ac->next_rid != 0) {
1098 ldb_set_errstring(ldb,
1099 "Invalid number of results while searching "
1100 "for domain object");
1101 ret = LDB_ERR_OPERATIONS_ERROR;
1105 nextRid = ldb_msg_find_attr_as_string(ares->message,
1107 if (nextRid == NULL) {
1108 ldb_asprintf_errstring(ldb,
1109 "while looking for forign sid %s attribute nextRid not found in %s\n",
1110 dom_sid_string(ares, ac->sid), ldb_dn_get_linearized(ares->message->dn));
1111 ret = LDB_ERR_OPERATIONS_ERROR;
1115 ac->next_rid = strtol(nextRid, NULL, 0);
1117 ac->domain_dn = talloc_steal(ac, ares->message->dn);
1119 name = samdb_result_string(ares->message, "name", NULL);
1120 ldb_debug(ldb, LDB_DEBUG_TRACE,
1121 "NOTE (strange but valid): Adding foreign SID "
1122 "record with SID %s, but this domain (%s) is "
1123 "not foreign in the database",
1124 dom_sid_string(ares, ac->sid), name);
1129 case LDB_REPLY_REFERRAL:
1134 case LDB_REPLY_DONE:
1136 /* if this is a fake foreign SID, notice the SID */
1137 if (ac->domain_dn) {
1138 ret = samldb_notice_sid(ac);
1143 ret = samldb_next_step(ac);
1148 if (ret != LDB_SUCCESS) {
1149 return ldb_module_done(ac->req, NULL, NULL, ret);
1155 /* Find a domain object in the parents of a particular DN. */
1156 static int samldb_foreign_notice_sid(struct samldb_ctx *ac)
1158 struct ldb_context *ldb;
1159 static const char * const attrs[3] = { "nextRid", "name", NULL };
1160 struct ldb_request *req;
1165 ldb = ldb_module_get_ctx(ac->module);
1167 if (ac->sid == NULL) {
1168 return LDB_ERR_OPERATIONS_ERROR;
1171 status = dom_sid_split_rid(ac, ac->sid, &ac->domain_sid, NULL);
1172 if (!NT_STATUS_IS_OK(status)) {
1173 return LDB_ERR_OPERATIONS_ERROR;
1176 filter = talloc_asprintf(ac, "(&(objectSid=%s)(objectclass=domain))",
1177 ldap_encode_ndr_dom_sid(ac, ac->domain_sid));
1178 if (filter == NULL) {
1179 return LDB_ERR_OPERATIONS_ERROR;
1182 ret = ldb_build_search_req(&req, ldb, ac,
1183 ldb_get_default_basedn(ldb),
1187 ac, samldb_foreign_notice_sid_callback,
1190 if (ret != LDB_SUCCESS) {
1195 return ldb_next_request(ac->module, req);
1198 static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
1200 struct ldb_context *ldb;
1203 ldb = ldb_module_get_ctx(ac->module);
1205 ac->sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
1206 if (ac->sid == NULL) {
1207 ac->sid = dom_sid_parse_talloc(ac->msg,
1208 (const char *)ldb_dn_get_rdn_val(ac->msg->dn)->data);
1210 ldb_set_errstring(ldb,
1211 "No valid found SID in "
1212 "ForeignSecurityPrincipal CN!");
1214 return LDB_ERR_CONSTRAINT_VIOLATION;
1216 if ( ! samldb_msg_add_sid(ac->msg, "objectSid", ac->sid)) {
1218 return LDB_ERR_OPERATIONS_ERROR;
1222 /* first look for the template */
1223 ac->type = "foreignSecurityPrincipal";
1224 ret = samldb_add_step(ac, samldb_search_template);
1225 if (ret != LDB_SUCCESS) return ret;
1228 ret = samldb_add_step(ac, samldb_apply_template);
1229 if (ret != LDB_SUCCESS) return ret;
1231 /* check we do not already have this SID */
1232 ret = samldb_add_step(ac, samldb_check_sid);
1233 if (ret != LDB_SUCCESS) return ret;
1235 /* check if we need to notice this SID */
1236 ret = samldb_add_step(ac, samldb_foreign_notice_sid);
1237 if (ret != LDB_SUCCESS) return ret;
1239 /* finally proceed with adding the entry */
1240 ret = samldb_add_step(ac, samldb_add_entry);
1241 if (ret != LDB_SUCCESS) return ret;
1243 return samldb_first_step(ac);
1246 static int samldb_check_rdn(struct ldb_module *module, struct ldb_dn *dn)
1248 struct ldb_context *ldb;
1249 const char *rdn_name;
1251 ldb = ldb_module_get_ctx(module);
1252 rdn_name = ldb_dn_get_rdn_name(dn);
1254 if (strcasecmp(rdn_name, "cn") != 0) {
1255 ldb_asprintf_errstring(ldb,
1256 "Bad RDN (%s=) for samldb object, "
1257 "should be CN=!\n", rdn_name);
1258 return LDB_ERR_CONSTRAINT_VIOLATION;
1265 static int samldb_add(struct ldb_module *module, struct ldb_request *req)
1267 struct ldb_context *ldb;
1268 struct samldb_ctx *ac;
1271 ldb = ldb_module_get_ctx(module);
1272 ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add_record\n");
1274 /* do not manipulate our control entries */
1275 if (ldb_dn_is_special(req->op.add.message->dn)) {
1276 return ldb_next_request(module, req);
1279 ac = samldb_ctx_init(module, req);
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 /* build the new msg */
1285 ac->msg = ldb_msg_copy(ac, ac->req->op.add.message);
1288 ldb_debug(ldb, LDB_DEBUG_FATAL,
1289 "samldb_add: ldb_msg_copy failed!\n");
1290 return LDB_ERR_OPERATIONS_ERROR;
1293 if (samdb_find_attribute(ldb, ac->msg,
1294 "objectclass", "computer") != NULL) {
1296 /* make sure the computer object also has the 'user'
1297 * objectclass so it will be handled by the next call */
1298 ret = samdb_find_or_add_value(ldb, ac->msg,
1299 "objectclass", "user");
1300 if (ret != LDB_SUCCESS) {
1306 if (samdb_find_attribute(ldb, ac->msg,
1307 "objectclass", "user") != NULL) {
1309 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1310 if (ret != LDB_SUCCESS) {
1315 return samldb_fill_object(ac, "user");
1318 if (samdb_find_attribute(ldb, ac->msg,
1319 "objectclass", "group") != NULL) {
1321 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1322 if (ret != LDB_SUCCESS) {
1327 return samldb_fill_object(ac, "group");
1330 /* perhaps a foreignSecurityPrincipal? */
1331 if (samdb_find_attribute(ldb, ac->msg,
1333 "foreignSecurityPrincipal") != NULL) {
1335 ret = samldb_check_rdn(module, ac->req->op.add.message->dn);
1336 if (ret != LDB_SUCCESS) {
1341 return samldb_fill_foreignSecurityPrincipal_object(ac);
1346 /* nothing matched, go on */
1347 return ldb_next_request(module, req);
1351 static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
1353 struct ldb_context *ldb;
1354 struct ldb_message *msg;
1355 struct ldb_message_element *el, *el2;
1357 unsigned int group_type, user_account_control, account_type;
1358 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
1359 return ldb_next_request(module, req);
1362 ldb = ldb_module_get_ctx(module);
1364 if (ldb_msg_find_element(req->op.mod.message, "sAMAccountType") != NULL) {
1365 ldb_asprintf_errstring(ldb, "sAMAccountType must not be specified");
1366 return LDB_ERR_UNWILLING_TO_PERFORM;
1369 /* TODO: do not modify original request, create a new one */
1371 el = ldb_msg_find_element(req->op.mod.message, "groupType");
1372 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1373 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1375 group_type = strtoul((const char *)el->values[0].data, NULL, 0);
1376 account_type = samdb_gtype2atype(group_type);
1377 ret = samdb_msg_add_uint(ldb, msg, msg,
1380 if (ret != LDB_SUCCESS) {
1383 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1384 el2->flags = LDB_FLAG_MOD_REPLACE;
1387 el = ldb_msg_find_element(req->op.mod.message, "userAccountControl");
1388 if (el && el->flags & (LDB_FLAG_MOD_ADD|LDB_FLAG_MOD_REPLACE) && el->num_values == 1) {
1389 req->op.mod.message = msg = ldb_msg_copy_shallow(req, req->op.mod.message);
1391 user_account_control = strtoul((const char *)el->values[0].data, NULL, 0);
1392 account_type = samdb_uf2atype(user_account_control);
1393 ret = samdb_msg_add_uint(ldb, msg, msg,
1396 if (ret != LDB_SUCCESS) {
1399 el2 = ldb_msg_find_element(msg, "sAMAccountType");
1400 el2->flags = LDB_FLAG_MOD_REPLACE;
1402 return ldb_next_request(module, req);
1406 static int samldb_init(struct ldb_module *module)
1408 return ldb_next_init(module);
1411 _PUBLIC_ const struct ldb_module_ops ldb_samldb_module_ops = {
1413 .init_context = samldb_init,
1415 .modify = samldb_modify